Merge branch 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 10 Apr 2014 16:43:56 +0000 (09:43 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 10 Apr 2014 16:43:56 +0000 (09:43 -0700)
Pull x86 platform driver updates from Matthew Garrett:
 "Support for the new keyboard features on the Thinkpad Carbon, a bunch
  of updates for the Sony and Toshiba drivers, a new driver for upcoming
  Alienware hardware and a few misc fixes.  There's a couple of patches
  that got Acked today but aren't invasive, so I'll send a further PR
  for them next week"

* 'for_linus' of git://cavan.codon.org.uk/platform-drivers-x86: (28 commits)
  alienware-wmi: cover some scenarios where memory allocations would fail
  Add WMI driver for controlling AlienFX features on some Alienware products
  fujitsu-tablet: add support for Lifebook T901 and T902
  x86, platform: Make HP_WIRELESS option text more descriptive
  x86, acpi: LLVMLinux: Remove nested functions from Thinkpad ACPI
  save and restore adaptive keyboard mode for suspend and,resume
  support Thinkpad X1 Carbon 2nd generation's adaptive keyboard
  toshiba_acpi: Fix whitespace
  toshiba_acpi: Update version and copyright info
  toshiba_acpi: Add accelerometer support
  toshiba_acpi: Add ECO mode led support
  toshiba_acpi: Add touchpad enable/disable support-
  toshiba_acpi: Add keyboard backlight support
  toshiba_acpi: Adapt Illumination code to use SCI
  toshiba_acpi: Add System Configuration Interface
  thinkpad_acpi: Fix inconsistent mute LED after resume
  sonypi: Simplify dependencies
  Revert "X86 platform: New BayTrail IOSF-SB MBI driver"
  sony-laptop: remove useless sony-laptop versioning
  sony-laptop: add smart connect control function
  ...

1703 files changed:
Documentation/ABI/testing/sysfs-block-zram
Documentation/ABI/testing/sysfs-fs-f2fs
Documentation/ABI/testing/sysfs-module
Documentation/DocBook/Makefile
Documentation/DocBook/drm.tmpl
Documentation/DocBook/kernel-hacking.tmpl
Documentation/arm64/booting.txt
Documentation/arm64/memory.txt
Documentation/blockdev/zram.txt
Documentation/cgroups/memcg_test.txt
Documentation/cgroups/resource_counter.txt
Documentation/cpu-hotplug.txt
Documentation/devicetree/bindings/arm/topology.txt
Documentation/devicetree/bindings/dma/fsl-edma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/qcom_bam_dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/sirfsoc-dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/drm/bridge/ptn3460.txt [new file with mode: 0644]
Documentation/devicetree/bindings/drm/i2c/tda998x.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
Documentation/devicetree/bindings/i2c/i2c-at91.txt
Documentation/devicetree/bindings/i2c/i2c-cadence.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-designware.txt
Documentation/devicetree/bindings/i2c/i2c-efm32.txt [new file with mode: 0644]
Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt
Documentation/devicetree/bindings/i2c/i2c-rcar.txt
Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt [new file with mode: 0644]
Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/leds/leds-gpio.txt
Documentation/devicetree/bindings/mfd/arizona.txt
Documentation/devicetree/bindings/mfd/bcm590xx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/da9055.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/mc13xxx.txt
Documentation/devicetree/bindings/mfd/omap-usb-host.txt
Documentation/devicetree/bindings/mfd/omap-usb-tll.txt
Documentation/devicetree/bindings/mfd/qcom,pm8xxx.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/s2mps11.txt
Documentation/devicetree/bindings/mmc/mmc.txt
Documentation/devicetree/bindings/mmc/sdhci-msm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
Documentation/devicetree/bindings/mmc/ti-omap-hsmmc.txt
Documentation/devicetree/bindings/mtd/nand.txt
Documentation/devicetree/bindings/mtd/st-fsm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/lg,ld070wx3-sl01.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/lg,lh500wx1-sd03.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/lg,lp129qe.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/samsung,ld9040.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt [new file with mode: 0644]
Documentation/devicetree/bindings/regulator/pbias-regulator.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/fsl,ssi.txt
Documentation/devicetree/bindings/video/analog-tv-connector.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/backlight/gpio-backlight.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/dvi-connector.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/exynos_dp.txt
Documentation/devicetree/bindings/video/exynos_dsim.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/exynos_hdmi.txt
Documentation/devicetree/bindings/video/hdmi-connector.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/panel-dsi-cm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/samsung-fimd.txt
Documentation/devicetree/bindings/video/sony,acx565akm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/ti,omap-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/ti,omap2-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/ti,omap3-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/ti,omap4-dss.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/ti,tfp410.txt [new file with mode: 0644]
Documentation/devicetree/bindings/video/ti,tpd12s015.txt [new file with mode: 0644]
Documentation/filesystems/Locking
Documentation/filesystems/affs.txt
Documentation/filesystems/f2fs.txt
Documentation/filesystems/proc.txt
Documentation/i2c/busses/i2c-i801
Documentation/i2c/functionality
Documentation/i2c/i2c-protocol
Documentation/irqflags-tracing.txt
Documentation/kbuild/kconfig-language.txt
Documentation/kernel-parameters.txt
Documentation/module-signing.txt
Documentation/oops-tracing.txt
Documentation/rapidio/sysfs.txt
Documentation/scheduler/sched-arch.txt
Documentation/sysctl/kernel.txt
MAINTAINERS
Makefile
arch/arc/Kconfig
arch/arc/boot/.gitignore
arch/arc/boot/dts/nsimosci.dts
arch/arc/boot/dts/skeleton.dts [deleted file]
arch/arc/configs/nsimosci_defconfig
arch/arc/include/asm/linkage.h
arch/arc/kernel/ctx_sw_asm.S
arch/arc/kernel/entry.S
arch/arc/kernel/head.S
arch/arc/kernel/time.c
arch/arc/lib/memcmp.S
arch/arc/lib/memcpy-700.S
arch/arc/lib/memset.S
arch/arc/lib/strchr-700.S
arch/arc/lib/strcmp.S
arch/arc/lib/strcpy-700.S
arch/arc/lib/strlen.S
arch/arc/mm/cache_arc700.c
arch/arc/mm/init.c
arch/arc/mm/tlbex.S
arch/arc/plat-arcfpga/Kconfig
arch/arc/plat-arcfpga/platform.c
arch/arm/Kconfig
arch/arm/boot/dts/atlas6.dtsi
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/exynos4.dtsi
arch/arm/boot/dts/exynos4210-trats.dts
arch/arm/boot/dts/exynos4210-universal_c210.dts
arch/arm/boot/dts/exynos4412-trats2.dts
arch/arm/boot/dts/omap2.dtsi
arch/arm/boot/dts/omap2430.dtsi
arch/arm/boot/dts/omap3-beagle-xm.dts
arch/arm/boot/dts/omap3-beagle.dts
arch/arm/boot/dts/omap3-igep0020.dts
arch/arm/boot/dts/omap3-ldp.dts
arch/arm/boot/dts/omap3-n900.dts
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap3430es1-clocks.dtsi
arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi
arch/arm/boot/dts/omap36xx-clocks.dtsi
arch/arm/boot/dts/omap36xx.dtsi
arch/arm/boot/dts/omap3xxx-clocks.dtsi
arch/arm/boot/dts/omap4-panda-common.dtsi
arch/arm/boot/dts/omap4-sdp.dts
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/prima2.dtsi
arch/arm/configs/omap2plus_defconfig
arch/arm/kernel/hw_breakpoint.c
arch/arm/kvm/arm.c
arch/arm/mach-omap2/board-generic.c
arch/arm/mach-omap2/cclock3xxx_data.c
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/display.c
arch/arm/mach-omap2/display.h
arch/arm/mach-omap2/dss-common.c
arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
arch/arm/mach-omap2/pdata-quirks.c
arch/arm/mach-picoxcell/Kconfig
arch/arm/mach-prima2/Kconfig
arch/arm/mach-s3c24xx/Kconfig
arch/arm/mach-shmobile/Kconfig
arch/arm/mach-vexpress/Kconfig
arch/arm/plat-samsung/Kconfig
arch/arm64/Kconfig
arch/arm64/Kconfig.debug
arch/arm64/include/asm/Kbuild
arch/arm64/include/asm/fixmap.h [new file with mode: 0644]
arch/arm64/include/asm/io.h
arch/arm64/include/asm/memory.h
arch/arm64/include/asm/mmu.h
arch/arm64/include/asm/pgtable-hwdef.h
arch/arm64/include/asm/virt.h
arch/arm64/kernel/debug-monitors.c
arch/arm64/kernel/early_printk.c
arch/arm64/kernel/head.S
arch/arm64/kernel/hw_breakpoint.c
arch/arm64/kernel/perf_event.c
arch/arm64/kernel/perf_regs.c
arch/arm64/kernel/setup.c
arch/arm64/mm/cache.S
arch/arm64/mm/ioremap.c
arch/arm64/mm/mmu.c
arch/arm64/mm/proc.S
arch/blackfin/include/asm/bfin_twi.h
arch/blackfin/kernel/debug-mmrs.c
arch/cris/Kconfig
arch/cris/kernel/setup.c
arch/hexagon/Kconfig
arch/ia64/Kconfig
arch/ia64/kernel/err_inject.c
arch/ia64/kernel/palinfo.c
arch/ia64/kernel/salinfo.c
arch/ia64/kernel/topology.c
arch/m32r/Kconfig
arch/m68k/Kconfig
arch/metag/Kconfig
arch/mips/Kconfig
arch/openrisc/Kconfig
arch/powerpc/Makefile
arch/powerpc/include/asm/emulated_ops.h
arch/powerpc/include/asm/fadump.h
arch/powerpc/include/asm/opal.h
arch/powerpc/include/asm/rtas.h
arch/powerpc/kernel/align.c
arch/powerpc/kernel/cpu_setup_power.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/rtas.c
arch/powerpc/kernel/rtasd.c
arch/powerpc/kernel/setup-common.c
arch/powerpc/kernel/setup_32.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/tm.S
arch/powerpc/kernel/traps.c
arch/powerpc/math-emu/mtfsf.c
arch/powerpc/mm/gup.c
arch/powerpc/mm/numa.c
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/cell/spu_syscalls.c
arch/powerpc/platforms/powernv/Makefile
arch/powerpc/platforms/powernv/opal-async.c
arch/powerpc/platforms/powernv/opal-dump.c
arch/powerpc/platforms/powernv/opal-elog.c
arch/powerpc/platforms/powernv/opal-msglog.c [new file with mode: 0644]
arch/powerpc/platforms/powernv/opal-sensor.c
arch/powerpc/platforms/powernv/opal-sysparam.c
arch/powerpc/platforms/powernv/opal-wrappers.S
arch/powerpc/platforms/powernv/opal.c
arch/powerpc/platforms/pseries/io_event_irq.c
arch/powerpc/platforms/pseries/nvram.c
arch/powerpc/platforms/pseries/ras.c
arch/powerpc/sysdev/fsl_rio.c
arch/powerpc/sysdev/msi_bitmap.c
arch/s390/Kconfig
arch/s390/include/asm/atomic.h
arch/s390/include/asm/bitops.h
arch/s390/include/asm/futex.h
arch/s390/include/asm/irq.h
arch/s390/include/asm/mmu.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/pgtable.h
arch/s390/include/asm/setup.h
arch/s390/include/asm/switch_to.h
arch/s390/include/asm/thread_info.h
arch/s390/include/asm/tlb.h
arch/s390/include/asm/tlbflush.h
arch/s390/include/asm/uaccess.h
arch/s390/kernel/asm-offsets.c
arch/s390/kernel/cache.c
arch/s390/kernel/early.c
arch/s390/kernel/entry.S
arch/s390/kernel/entry64.S
arch/s390/kernel/irq.c
arch/s390/kernel/perf_cpum_cf.c
arch/s390/kernel/perf_cpum_sf.c
arch/s390/kernel/runtime_instr.c
arch/s390/kernel/sclp.S
arch/s390/kernel/smp.c
arch/s390/kernel/time.c
arch/s390/kvm/diag.c
arch/s390/lib/Makefile
arch/s390/lib/uaccess.c [new file with mode: 0644]
arch/s390/lib/uaccess.h [deleted file]
arch/s390/lib/uaccess_mvcos.c [deleted file]
arch/s390/lib/uaccess_pt.c [deleted file]
arch/s390/mm/fault.c
arch/s390/mm/hugetlbpage.c
arch/s390/mm/init.c
arch/s390/mm/pgtable.c
arch/s390/mm/vmem.c
arch/s390/oprofile/hwsampler.c
arch/sh/Kconfig
arch/sh/boards/Kconfig
arch/sh/include/asm/io.h
arch/sh/include/asm/io_trapped.h
arch/sh/include/asm/machvec.h
arch/sh/kernel/Makefile
arch/sh/kernel/io_trapped.c
arch/sparc/kernel/sysfs.c
arch/tile/Kconfig
arch/um/kernel/process.c
arch/unicore32/Kconfig
arch/unicore32/include/asm/mmu_context.h
arch/x86/Kconfig
arch/x86/include/asm/Kbuild
arch/x86/include/asm/bug.h
arch/x86/include/asm/fixmap.h
arch/x86/include/asm/io.h
arch/x86/include/asm/percpu.h
arch/x86/include/asm/preempt.h
arch/x86/kernel/cpu/intel_cacheinfo.c
arch/x86/kernel/cpu/mcheck/mce.c
arch/x86/kernel/cpu/mcheck/therm_throt.c
arch/x86/kernel/cpu/perf_event_amd_ibs.c
arch/x86/kernel/cpu/perf_event_amd_uncore.c
arch/x86/kernel/cpu/perf_event_intel_rapl.c
arch/x86/kernel/cpu/perf_event_intel_uncore.c
arch/x86/kernel/cpuid.c
arch/x86/kernel/hpet.c
arch/x86/kernel/msr.c
arch/x86/kernel/vsyscall_64.c
arch/x86/kvm/x86.c
arch/x86/mm/ioremap.c
arch/x86/mm/kmemcheck/kmemcheck.c
arch/x86/mm/pgtable_32.c
arch/x86/oprofile/nmi_int.c
arch/x86/pci/amd_bus.c
arch/xtensa/Kconfig
arch/xtensa/configs/iss_defconfig
arch/xtensa/configs/s6105_defconfig
block/blk-core.c
block/blk-mq.c
block/blk-softirq.c
block/blk.h
block/elevator.c
drivers/base/topology.c
drivers/block/loop.c
drivers/block/rbd.c
drivers/block/zram/Kconfig
drivers/block/zram/Makefile
drivers/block/zram/zcomp.c [new file with mode: 0644]
drivers/block/zram/zcomp.h [new file with mode: 0644]
drivers/block/zram/zcomp_lz4.c [new file with mode: 0644]
drivers/block/zram/zcomp_lz4.h [new file with mode: 0644]
drivers/block/zram/zcomp_lzo.c [new file with mode: 0644]
drivers/block/zram/zcomp_lzo.h [new file with mode: 0644]
drivers/block/zram/zram_drv.c
drivers/block/zram/zram_drv.h
drivers/char/tpm/Kconfig
drivers/clk/ti/clk-3xxx.c
drivers/clocksource/dummy_timer.c
drivers/cpufreq/acpi-cpufreq.c
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/acpi-dma.c
drivers/dma/at_hdmac.c
drivers/dma/cppi41.c
drivers/dma/dmaengine.c
drivers/dma/dmatest.c
drivers/dma/dw/core.c
drivers/dma/dw/pci.c
drivers/dma/dw/regs.h
drivers/dma/edma.c
drivers/dma/fsl-edma.c [new file with mode: 0644]
drivers/dma/imx-dma.c
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/omap-dma.c
drivers/dma/pch_dma.c
drivers/dma/qcom_bam_dma.c [new file with mode: 0644]
drivers/dma/s3c24xx-dma.c
drivers/dma/sh/Kconfig
drivers/dma/sh/Makefile
drivers/dma/sh/rcar-audmapp.c [new file with mode: 0644]
drivers/dma/sh/shdma-base.c
drivers/dma/sh/shdma-of.c
drivers/dma/sh/shdmac.c
drivers/dma/sh/sudmac.c
drivers/dma/sirf-dma.c
drivers/gpio/gpio-ich.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/armada/armada_crtc.c
drivers/gpu/drm/ast/ast_mode.c
drivers/gpu/drm/ast/ast_ttm.c
drivers/gpu/drm/bochs/bochs_kms.c
drivers/gpu/drm/bochs/bochs_mm.c
drivers/gpu/drm/bridge/Kconfig [new file with mode: 0644]
drivers/gpu/drm/bridge/Makefile [new file with mode: 0644]
drivers/gpu/drm/bridge/ptn3460.c [new file with mode: 0644]
drivers/gpu/drm/cirrus/cirrus_mode.c
drivers/gpu/drm/cirrus/cirrus_ttm.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_crtc_internal.h [new file with mode: 0644]
drivers/gpu/drm/drm_dp_helper.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fb_helper.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_ioctl.c
drivers/gpu/drm/drm_mipi_dsi.c
drivers/gpu/drm/drm_mm.c
drivers/gpu/drm/drm_modes.c
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_plane_helper.c [new file with mode: 0644]
drivers/gpu/drm/drm_platform.c
drivers/gpu/drm/drm_prime.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_usb.c
drivers/gpu/drm/exynos/Kconfig
drivers/gpu/drm/exynos/Makefile
drivers/gpu/drm/exynos/exynos_dp_core.c [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_dp_core.h [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_dp_reg.c [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_dp_reg.h [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_drm_connector.c
drivers/gpu/drm/exynos/exynos_drm_connector.h
drivers/gpu/drm/exynos/exynos_drm_core.c
drivers/gpu/drm/exynos/exynos_drm_crtc.c
drivers/gpu/drm/exynos/exynos_drm_crtc.h
drivers/gpu/drm/exynos/exynos_drm_dpi.c [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
drivers/gpu/drm/exynos/exynos_drm_dsi.c [new file with mode: 0644]
drivers/gpu/drm/exynos/exynos_drm_encoder.c
drivers/gpu/drm/exynos/exynos_drm_encoder.h
drivers/gpu/drm/exynos/exynos_drm_fb.c
drivers/gpu/drm/exynos/exynos_drm_fbdev.c
drivers/gpu/drm/exynos/exynos_drm_fimd.c
drivers/gpu/drm/exynos/exynos_drm_hdmi.c [deleted file]
drivers/gpu/drm/exynos/exynos_drm_hdmi.h [deleted file]
drivers/gpu/drm/exynos/exynos_drm_plane.c
drivers/gpu/drm/exynos/exynos_drm_plane.h
drivers/gpu/drm/exynos/exynos_drm_vidi.c
drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c
drivers/gpu/drm/exynos/exynos_mixer.h [new file with mode: 0644]
drivers/gpu/drm/gma500/Makefile
drivers/gpu/drm/gma500/blitter.c [new file with mode: 0644]
drivers/gpu/drm/gma500/blitter.h [new file with mode: 0644]
drivers/gpu/drm/gma500/cdv_device.c
drivers/gpu/drm/gma500/cdv_intel_crt.c
drivers/gpu/drm/gma500/cdv_intel_display.c
drivers/gpu/drm/gma500/cdv_intel_dp.c
drivers/gpu/drm/gma500/cdv_intel_hdmi.c
drivers/gpu/drm/gma500/cdv_intel_lvds.c
drivers/gpu/drm/gma500/framebuffer.c
drivers/gpu/drm/gma500/gem.c
drivers/gpu/drm/gma500/gem.h [new file with mode: 0644]
drivers/gpu/drm/gma500/gma_device.c [new file with mode: 0644]
drivers/gpu/drm/gma500/gma_device.h [new file with mode: 0644]
drivers/gpu/drm/gma500/gma_display.c
drivers/gpu/drm/gma500/gma_display.h
drivers/gpu/drm/gma500/gtt.c
drivers/gpu/drm/gma500/gtt.h
drivers/gpu/drm/gma500/mdfld_dsi_output.c
drivers/gpu/drm/gma500/mdfld_intel_display.c
drivers/gpu/drm/gma500/mmu.c
drivers/gpu/drm/gma500/mmu.h [new file with mode: 0644]
drivers/gpu/drm/gma500/oaktrail_crtc.c
drivers/gpu/drm/gma500/oaktrail_hdmi.c
drivers/gpu/drm/gma500/oaktrail_lvds.c
drivers/gpu/drm/gma500/opregion.c
drivers/gpu/drm/gma500/psb_device.c
drivers/gpu/drm/gma500/psb_drv.c
drivers/gpu/drm/gma500/psb_drv.h
drivers/gpu/drm/gma500/psb_intel_display.c
drivers/gpu/drm/gma500/psb_intel_drv.h
drivers/gpu/drm/gma500/psb_intel_lvds.c
drivers/gpu/drm/gma500/psb_intel_sdvo.c
drivers/gpu/drm/gma500/psb_irq.c
drivers/gpu/drm/i2c/tda998x_drv.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/dvo_ch7xxx.c
drivers/gpu/drm/i915/dvo_ivch.c
drivers/gpu/drm/i915/dvo_ns2501.c
drivers/gpu/drm/i915/dvo_sil164.c
drivers/gpu/drm/i915/dvo_tfp410.c
drivers/gpu/drm/i915/i915_cmd_parser.c [new file with mode: 0644]
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_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
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_params.c [new file with mode: 0644]
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/i915_trace.h
drivers/gpu/drm/i915/i915_ums.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_bios.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_dsi.c
drivers/gpu/drm/i915/intel_dvo.c
drivers/gpu/drm/i915/intel_fbdev.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
drivers/gpu/drm/mgag200/mgag200_mode.c
drivers/gpu/drm/mgag200/mgag200_ttm.c
drivers/gpu/drm/msm/Makefile
drivers/gpu/drm/msm/adreno/a3xx_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.c
drivers/gpu/drm/msm/adreno/adreno_gpu.h
drivers/gpu/drm/msm/hdmi/hdmi.c
drivers/gpu/drm/msm/hdmi/hdmi.h
drivers/gpu/drm/msm/hdmi/hdmi_audio.c [new file with mode: 0644]
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
drivers/gpu/drm/msm/mdp/mdp_kms.c
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_gem_submit.c
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/core/namedb.c
drivers/gpu/drm/nouveau/core/core/parent.c
drivers/gpu/drm/nouveau/core/engine/device/base.c
drivers/gpu/drm/nouveau/core/engine/device/gm100.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/device/nv04.c
drivers/gpu/drm/nouveau/core/engine/device/nv10.c
drivers/gpu/drm/nouveau/core/engine/device/nv20.c
drivers/gpu/drm/nouveau/core/engine/device/nv30.c
drivers/gpu/drm/nouveau/core/engine/device/nv40.c
drivers/gpu/drm/nouveau/core/engine/device/nv50.c
drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
drivers/gpu/drm/nouveau/core/engine/device/nve0.c
drivers/gpu/drm/nouveau/core/engine/disp/dport.c
drivers/gpu/drm/nouveau/core/engine/disp/gm107.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
drivers/gpu/drm/nouveau/core/engine/disp/priv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c
drivers/gpu/drm/nouveau/core/engine/falcon.c
drivers/gpu/drm/nouveau/core/engine/fifo/base.c
drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c [deleted file]
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
drivers/gpu/drm/nouveau/core/engine/graph/gm107.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/nv108.c
drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c [deleted file]
drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c
drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c
drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c
drivers/gpu/drm/nouveau/core/engine/graph/nve4.c
drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
drivers/gpu/drm/nouveau/core/engine/xtensa.c
drivers/gpu/drm/nouveau/core/include/core/class.h
drivers/gpu/drm/nouveau/core/include/core/device.h
drivers/gpu/drm/nouveau/core/include/core/namedb.h
drivers/gpu/drm/nouveau/core/include/engine/device.h
drivers/gpu/drm/nouveau/core/include/engine/disp.h
drivers/gpu/drm/nouveau/core/include/engine/graph.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h
drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
drivers/gpu/drm/nouveau/core/include/subdev/fb.h
drivers/gpu/drm/nouveau/core/include/subdev/ltcg.h
drivers/gpu/drm/nouveau/core/include/subdev/mc.h
drivers/gpu/drm/nouveau/core/include/subdev/therm.h
drivers/gpu/drm/nouveau/core/include/subdev/timer.h
drivers/gpu/drm/nouveau/core/os.h
drivers/gpu/drm/nouveau/core/subdev/bar/base.c
drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/base.c
drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
drivers/gpu/drm/nouveau/core/subdev/bios/init.c
drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c
drivers/gpu/drm/nouveau/core/subdev/bios/therm.c
drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h
drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h
drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h
drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c [deleted file]
drivers/gpu/drm/nouveau/core/subdev/mc/base.c
drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
drivers/gpu/drm/nouveau/core/subdev/therm/base.c
drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c
drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c
drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/timer/priv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/dispnv04/crtc.c
drivers/gpu/drm/nouveau/dispnv04/dfp.c
drivers/gpu/drm/nouveau/nouveau_abi16.c
drivers/gpu/drm/nouveau/nouveau_agp.c
drivers/gpu/drm/nouveau/nouveau_bios.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_chan.c
drivers/gpu/drm/nouveau/nouveau_connector.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h
drivers/gpu/drm/nouveau/nouveau_fbcon.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_hwmon.c
drivers/gpu/drm/nouveau/nouveau_sysfs.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/nouveau/nouveau_vga.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/omapdrm/omap_fb.c
drivers/gpu/drm/omapdrm/omap_gem.c
drivers/gpu/drm/panel/Kconfig
drivers/gpu/drm/panel/Makefile
drivers/gpu/drm/panel/panel-ld9040.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-s6e8aa0.c [new file with mode: 0644]
drivers/gpu/drm/panel/panel-simple.c
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_object.c
drivers/gpu/drm/qxl/qxl_release.c
drivers/gpu/drm/qxl/qxl_ttm.c
drivers/gpu/drm/radeon/Makefile
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_encoders.c
drivers/gpu/drm/radeon/btc_dpm.c
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/cypress_dpm.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/evergreen_dma.c
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dma.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r200.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600_dma.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/r600_dpm.h
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_connectors.c
drivers/gpu/drm/radeon/radeon_cs.c
drivers/gpu/drm/radeon/radeon_device.c
drivers/gpu/drm/radeon/radeon_display.c
drivers/gpu/drm/radeon/radeon_drv.c
drivers/gpu/drm/radeon/radeon_fence.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_legacy_crtc.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_object.h
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_sa.c
drivers/gpu/drm/radeon/radeon_semaphore.c
drivers/gpu/drm/radeon/radeon_test.c
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/radeon_vce.c [new file with mode: 0644]
drivers/gpu/drm/radeon/radeon_vm.c [new file with mode: 0644]
drivers/gpu/drm/radeon/rs780_dpm.c
drivers/gpu/drm/radeon/rv6xx_dpm.c
drivers/gpu/drm/radeon/rv770_dpm.c
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dma.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/sumo_dpm.c
drivers/gpu/drm/radeon/trinity_dpm.c
drivers/gpu/drm/radeon/uvd_v1_0.c
drivers/gpu/drm/radeon/vce_v1_0.c [new file with mode: 0644]
drivers/gpu/drm/radeon/vce_v2_0.c [new file with mode: 0644]
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_kms.c
drivers/gpu/drm/shmobile/shmob_drm_crtc.c
drivers/gpu/drm/tegra/Makefile
drivers/gpu/drm/tegra/bus.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/dpaux.c [new file with mode: 0644]
drivers/gpu/drm/tegra/dpaux.h [new file with mode: 0644]
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/dsi.c
drivers/gpu/drm/tegra/dsi.h
drivers/gpu/drm/tegra/gem.c
drivers/gpu/drm/tegra/gem.h
drivers/gpu/drm/tegra/gr2d.c
drivers/gpu/drm/tegra/mipi-phy.c
drivers/gpu/drm/tegra/mipi-phy.h
drivers/gpu/drm/tegra/output.c
drivers/gpu/drm/tegra/sor.c [new file with mode: 0644]
drivers/gpu/drm/tegra/sor.h [new file with mode: 0644]
drivers/gpu/drm/tilcdc/tilcdc_crtc.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_manager.c
drivers/gpu/drm/ttm/ttm_execbuf_util.c
drivers/gpu/drm/ttm/ttm_object.c
drivers/gpu/drm/udl/udl_fb.c
drivers/gpu/drm/udl/udl_gem.c
drivers/gpu/drm/udl/udl_modeset.c
drivers/gpu/drm/vmwgfx/vmwgfx_context.c
drivers/gpu/drm/vmwgfx/vmwgfx_dmabuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.c
drivers/gpu/drm/vmwgfx/vmwgfx_drv.h
drivers/gpu/drm/vmwgfx/vmwgfx_execbuf.c
drivers/gpu/drm/vmwgfx/vmwgfx_fb.c
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_ldu.c
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_scrn.c
drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
drivers/gpu/host1x/syncpt.c
drivers/hwmon/Kconfig
drivers/hwmon/Makefile
drivers/hwmon/coretemp.c
drivers/hwmon/ibmpowernv.c [deleted file]
drivers/hwmon/via-cputemp.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Makefile
drivers/i2c/busses/i2c-ali1535.c
drivers/i2c/busses/i2c-ali1563.c
drivers/i2c/busses/i2c-ali15x3.c
drivers/i2c/busses/i2c-amd756.c
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-at91.c
drivers/i2c/busses/i2c-bcm2835.c
drivers/i2c/busses/i2c-bfin-twi.c
drivers/i2c/busses/i2c-cadence.c [new file with mode: 0644]
drivers/i2c/busses/i2c-davinci.c
drivers/i2c/busses/i2c-designware-core.c
drivers/i2c/busses/i2c-designware-core.h
drivers/i2c/busses/i2c-designware-pcidrv.c
drivers/i2c/busses/i2c-designware-platdrv.c
drivers/i2c/busses/i2c-efm32.c [new file with mode: 0644]
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-exynos5.c
drivers/i2c/busses/i2c-gpio.c
drivers/i2c/busses/i2c-hydra.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ismt.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-mxs.c
drivers/i2c/busses/i2c-nforce2.c
drivers/i2c/busses/i2c-nomadik.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-omap.c
drivers/i2c/busses/i2c-pasemi.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-pxa-pci.c
drivers/i2c/busses/i2c-qup.c [new file with mode: 0644]
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/busses/i2c-s3c2410.c
drivers/i2c/busses/i2c-sirf.c
drivers/i2c/busses/i2c-sis5595.c
drivers/i2c/busses/i2c-sis630.c
drivers/i2c/busses/i2c-sis96x.c
drivers/i2c/busses/i2c-st.c
drivers/i2c/busses/i2c-stu300.c
drivers/i2c/busses/i2c-tegra.c
drivers/i2c/busses/i2c-via.c
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/busses/scx200_acb.c
drivers/i2c/i2c-core.c
drivers/idle/intel_idle.c
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/twl4030-madc.c [new file with mode: 0644]
drivers/isdn/isdnloop/isdnloop.c
drivers/leds/Kconfig
drivers/leds/led-core.c
drivers/leds/led-triggers.c
drivers/leds/leds-88pm860x.c
drivers/leds/leds-adp5520.c
drivers/leds/leds-asic3.c
drivers/leds/leds-blinkm.c
drivers/leds/leds-clevo-mail.c
drivers/leds/leds-cobalt-qube.c
drivers/leds/leds-da903x.c
drivers/leds/leds-da9052.c
drivers/leds/leds-fsg.c
drivers/leds/leds-gpio.c
drivers/leds/leds-hp6xx.c
drivers/leds/leds-lm3533.c
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/leds/leds-lp5562.c
drivers/leds/leds-lt3593.c
drivers/leds/leds-mc13783.c
drivers/leds/leds-netxbig.c
drivers/leds/leds-ns2.c
drivers/leds/leds-ot200.c
drivers/leds/leds-pwm.c
drivers/leds/leds-s3c24xx.c
drivers/leds/leds-ss4200.c
drivers/leds/leds-wm831x-status.c
drivers/leds/leds-wm8350.c
drivers/leds/trigger/ledtrig-cpu.c
drivers/lguest/page_tables.c
drivers/mfd/88pm800.c
drivers/mfd/88pm860x-core.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/adp5520.c
drivers/mfd/as3722.c
drivers/mfd/bcm590xx.c [new file with mode: 0644]
drivers/mfd/cs5535-mfd.c
drivers/mfd/da9052-core.c
drivers/mfd/da9052-i2c.c
drivers/mfd/da9052-spi.c
drivers/mfd/da9055-i2c.c
drivers/mfd/da9063-core.c
drivers/mfd/janz-cmodio.c
drivers/mfd/kempld-core.c
drivers/mfd/lpc_ich.c
drivers/mfd/lpc_sch.c
drivers/mfd/max14577.c
drivers/mfd/max77686.c
drivers/mfd/max77693.c
drivers/mfd/max8925-i2c.c
drivers/mfd/max8997.c
drivers/mfd/max8998.c
drivers/mfd/mc13xxx-spi.c
drivers/mfd/mcp-sa11x0.c
drivers/mfd/omap-usb-host.c
drivers/mfd/omap-usb-tll.c
drivers/mfd/pcf50633-adc.c
drivers/mfd/pm8921-core.c
drivers/mfd/pm8xxx-irq.c [deleted file]
drivers/mfd/rc5t583-irq.c
drivers/mfd/rdc321x-southbridge.c
drivers/mfd/retu-mfd.c
drivers/mfd/rtsx_pcr.c
drivers/mfd/rtsx_usb.c [new file with mode: 0644]
drivers/mfd/sec-core.c
drivers/mfd/smsc-ece1099.c
drivers/mfd/stmpe.c
drivers/mfd/stw481x.c
drivers/mfd/syscon.c
drivers/mfd/tc3589x.c
drivers/mfd/ti-ssp.c [deleted file]
drivers/mfd/ti_am335x_tscadc.c
drivers/mfd/timberdale.c
drivers/mfd/tps65218.c [new file with mode: 0644]
drivers/mfd/tps65910.c
drivers/mfd/tps65912-core.c
drivers/mfd/tps65912-irq.c
drivers/mfd/twl-core.c
drivers/mfd/twl4030-irq.c
drivers/mfd/twl4030-madc.c [deleted file]
drivers/mfd/twl6030-irq.c
drivers/mfd/twl6040.c
drivers/mfd/ucb1x00-core.c
drivers/mfd/vexpress-config.c
drivers/mfd/vexpress-sysreg.c
drivers/mfd/wm5102-tables.c
drivers/mfd/wm5110-tables.c
drivers/mfd/wm8350-core.c
drivers/mfd/wm8350-irq.c
drivers/mfd/wm8400-core.c
drivers/misc/sgi-gru/grukdump.c
drivers/mmc/card/block.c
drivers/mmc/core/Kconfig
drivers/mmc/core/bus.c
drivers/mmc/core/core.c
drivers/mmc/core/host.c
drivers/mmc/core/mmc.c
drivers/mmc/core/mmc_ops.c
drivers/mmc/core/sd.c
drivers/mmc/core/slot-gpio.c
drivers/mmc/host/Kconfig
drivers/mmc/host/Makefile
drivers/mmc/host/davinci_mmc.c
drivers/mmc/host/dw_mmc-k3.c
drivers/mmc/host/dw_mmc-pltfm.c
drivers/mmc/host/dw_mmc-socfpga.c [deleted file]
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h
drivers/mmc/host/mmci.c
drivers/mmc/host/mmci.h
drivers/mmc/host/omap.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/rtsx_pci_sdmmc.c
drivers/mmc/host/sdhci-acpi.c
drivers/mmc/host/sdhci-bcm-kona.c
drivers/mmc/host/sdhci-dove.c
drivers/mmc/host/sdhci-msm.c [new file with mode: 0644]
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci-pxav3.c
drivers/mmc/host/sdhci-s3c.c
drivers/mmc/host/sdhci-spear.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sh_mobile_sdhi.c
drivers/mmc/host/tmio_mmc.c
drivers/mmc/host/tmio_mmc.h
drivers/mmc/host/tmio_mmc_pio.c
drivers/mmc/host/ushc.c
drivers/mmc/host/wmt-sdmmc.c
drivers/mtd/Kconfig
drivers/mtd/bcm47xxpart.c
drivers/mtd/chips/cfi_cmdset_0001.c
drivers/mtd/chips/cfi_cmdset_0002.c
drivers/mtd/chips/cfi_cmdset_0020.c
drivers/mtd/chips/cfi_probe.c
drivers/mtd/chips/cfi_util.c
drivers/mtd/chips/gen_probe.c
drivers/mtd/devices/Kconfig
drivers/mtd/devices/Makefile
drivers/mtd/devices/block2mtd.c
drivers/mtd/devices/elm.c
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/phram.c
drivers/mtd/devices/pmc551.c
drivers/mtd/devices/serial_flash_cmds.h [new file with mode: 0644]
drivers/mtd/devices/spear_smi.c
drivers/mtd/devices/sst25l.c
drivers/mtd/devices/st_spi_fsm.c [new file with mode: 0644]
drivers/mtd/inftlmount.c
drivers/mtd/lpddr/lpddr_cmds.c
drivers/mtd/lpddr/qinfo_probe.c
drivers/mtd/maps/Kconfig
drivers/mtd/maps/bfin-async-flash.c
drivers/mtd/maps/gpio-addr-flash.c
drivers/mtd/maps/intel_vr_nor.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/lantiq-flash.c
drivers/mtd/maps/latch-addr-flash.c
drivers/mtd/maps/pci.c
drivers/mtd/maps/physmap_of.c
drivers/mtd/maps/plat-ram.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/rbtx4939-flash.c
drivers/mtd/maps/scb2_flash.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/mtd_blkdevs.c
drivers/mtd/mtdchar.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/ams-delta.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/denali_dt.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/pasemi_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/onenand/generic.c
drivers/mtd/onenand/omap2.c
drivers/mtd/onenand/onenand_base.c
drivers/mtd/onenand/samsung.c
drivers/mtd/rfd_ftl.c
drivers/mtd/sm_ftl.c
drivers/mtd/tests/mtd_test.c
drivers/mtd/ubi/ubi.h
drivers/net/bonding/bond_main.c
drivers/net/can/sja1000/Kconfig
drivers/net/ethernet/3com/Kconfig
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.h
drivers/net/ethernet/broadcom/genet/bcmgenet.c
drivers/net/ethernet/cadence/at91_ether.c
drivers/net/ethernet/cisco/enic/enic.h
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
drivers/net/ethernet/samsung/Kconfig
drivers/net/ethernet/samsung/sxgbe/Kconfig [deleted file]
drivers/net/ethernet/samsung/sxgbe/sxgbe_dma.c
drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
drivers/net/ethernet/smsc/smc911x.c
drivers/net/ethernet/ti/cpts.c
drivers/net/ieee802154/at86rf230.c
drivers/net/phy/spi_ks8995.c
drivers/net/rionet.c
drivers/net/vxlan.c
drivers/net/xen-netback/common.h
drivers/net/xen-netback/netback.c
drivers/of/of_mtd.c
drivers/oprofile/nmi_timer_int.c
drivers/pci/slot.c
drivers/powercap/intel_rapl.c
drivers/rapidio/devices/tsi721.c
drivers/rapidio/devices/tsi721.h
drivers/rapidio/devices/tsi721_dma.c
drivers/rapidio/rio-driver.c
drivers/rapidio/rio-scan.c
drivers/rapidio/rio-sysfs.c
drivers/rapidio/rio.c
drivers/rapidio/rio.h
drivers/regulator/Kconfig
drivers/regulator/Makefile
drivers/regulator/pbias-regulator.c [new file with mode: 0644]
drivers/s390/block/dasd_diag.c
drivers/s390/char/raw3270.c
drivers/s390/char/sclp.c
drivers/s390/char/sclp.h
drivers/s390/char/sclp_cmd.c
drivers/s390/char/tape_std.c
drivers/s390/crypto/zcrypt_api.c
drivers/s390/crypto/zcrypt_msgtype6.c
drivers/s390/kvm/kvm_virtio.c
drivers/s390/net/lcs.c
drivers/scsi/bnx2fc/bnx2fc_fcoe.c
drivers/scsi/bnx2i/bnx2i_init.c
drivers/scsi/fcoe/fcoe.c
drivers/scsi/scsi_lib.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/imx-drm/ipuv3-crtc.c
drivers/staging/imx-drm/ipuv3-plane.c
drivers/staging/rtl8723au/Kconfig [new file with mode: 0644]
drivers/staging/rtl8723au/Makefile [new file with mode: 0644]
drivers/staging/rtl8723au/TODO [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_ap.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_cmd.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_efuse.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_ieee80211.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_io.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_ioctl_set.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_led.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_mlme.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_mlme_ext.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_p2p.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_pwrctrl.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_recv.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_security.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_sreset.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_sta_mgt.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_wlan_util.c [new file with mode: 0644]
drivers/staging/rtl8723au/core/rtw_xmit.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/Hal8723PwrSeq.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/Hal8723UHWImg_CE.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/HalDMOutSrc8723A_CE.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/HalHWImg8723A_BB.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/HalHWImg8723A_MAC.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/HalHWImg8723A_RF.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/hal_com.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/hal_intf.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/odm.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/odm_HWConfig.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/odm_debug.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/odm_interface.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723a_cmd.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723a_dm.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723a_rxdesc.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723a_sreset.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723a_xmit.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723au_led.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723au_recv.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/rtl8723au_xmit.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/usb_halinit.c [new file with mode: 0644]
drivers/staging/rtl8723au/hal/usb_ops_linux.c [new file with mode: 0644]
drivers/staging/rtl8723au/include/Hal8723APhyCfg.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/Hal8723APhyReg.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/Hal8723PwrSeq.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/Hal8723UHWImg_CE.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/HalDMOutSrc8723A.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/HalHWImg8723A_BB.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/HalHWImg8723A_FW.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/HalHWImg8723A_MAC.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/HalHWImg8723A_RF.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/HalPwrSeqCmd.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/HalVerDef.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/cmd_osdep.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/drv_types.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/ethernet.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/hal_com.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/hal_intf.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/ieee80211.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/ioctl_cfg80211.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/mlme_osdep.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/mp_custom_oid.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm_HWConfig.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm_RegConfig8723A.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm_RegDefine11AC.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm_RegDefine11N.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm_debug.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm_interface.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm_precomp.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm_reg.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/odm_types.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/osdep_intf.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/osdep_service.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/recv_osdep.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_cmd.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_dm.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_hal.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_led.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_pg.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_recv.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_rf.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_spec.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_sreset.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtl8723a_xmit.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_ap.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_cmd.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_debug.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_eeprom.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_efuse.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_event.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_ht.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_io.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_ioctl.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_ioctl_set.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_led.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_mlme.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_mlme_ext.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_p2p.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_pwrctrl.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_qos.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_recv.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_rf.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_security.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_sreset.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_version.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/rtw_xmit.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/sta_info.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/usb_hal.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/usb_ops.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/usb_ops_linux.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/usb_osintf.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/usb_vendor_req.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/wifi.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/wlan_bssdef.h [new file with mode: 0644]
drivers/staging/rtl8723au/include/xmit_osdep.h [new file with mode: 0644]
drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c [new file with mode: 0644]
drivers/staging/rtl8723au/os_dep/mlme_linux.c [new file with mode: 0644]
drivers/staging/rtl8723au/os_dep/os_intfs.c [new file with mode: 0644]
drivers/staging/rtl8723au/os_dep/osdep_service.c [new file with mode: 0644]
drivers/staging/rtl8723au/os_dep/recv_linux.c [new file with mode: 0644]
drivers/staging/rtl8723au/os_dep/usb_intf.c [new file with mode: 0644]
drivers/staging/rtl8723au/os_dep/usb_ops_linux.c [new file with mode: 0644]
drivers/staging/rtl8723au/os_dep/xmit_linux.c [new file with mode: 0644]
drivers/staging/speakup/kobjects.c
drivers/staging/speakup/speakup.h
drivers/staging/speakup/speakup_acntpc.c
drivers/staging/speakup/speakup_acntsa.c
drivers/staging/speakup/speakup_apollo.c
drivers/staging/speakup/speakup_audptr.c
drivers/staging/speakup/speakup_bns.c
drivers/staging/speakup/speakup_decext.c
drivers/staging/speakup/speakup_decpc.c
drivers/staging/speakup/speakup_dectlk.c
drivers/staging/speakup/speakup_dtlk.c
drivers/staging/speakup/speakup_dummy.c
drivers/staging/speakup/speakup_keypc.c
drivers/staging/speakup/speakup_ltlk.c
drivers/staging/speakup/speakup_soft.c
drivers/staging/speakup/speakup_spkout.c
drivers/staging/speakup/speakup_txprt.c
drivers/staging/unisys/Kconfig
drivers/staging/unisys/visorchipset/filexfer.c
drivers/staging/unisys/visorchipset/visorchipset_main.c
drivers/thermal/imx_thermal.c
drivers/thermal/rcar_thermal.c
drivers/thermal/ti-soc-thermal/ti-bandgap.c
drivers/thermal/x86_pkg_temp_thermal.c
drivers/tty/hvc/hvc_opal.c
drivers/video/backlight/backlight.c
drivers/video/backlight/gpio_backlight.c
drivers/video/backlight/lm3639_bl.c
drivers/video/exynos/Kconfig
drivers/video/exynos/Makefile
drivers/video/exynos/exynos_dp_core.c [deleted file]
drivers/video/exynos/exynos_dp_core.h [deleted file]
drivers/video/exynos/exynos_dp_reg.c [deleted file]
drivers/video/exynos/exynos_dp_reg.h [deleted file]
drivers/video/omap2/displays-new/connector-analog-tv.c
drivers/video/omap2/displays-new/connector-dvi.c
drivers/video/omap2/displays-new/connector-hdmi.c
drivers/video/omap2/displays-new/encoder-tfp410.c
drivers/video/omap2/displays-new/encoder-tpd12s015.c
drivers/video/omap2/displays-new/panel-dsi-cm.c
drivers/video/omap2/displays-new/panel-sony-acx565akm.c
drivers/video/omap2/dss/Makefile
drivers/video/omap2/dss/dispc.c
drivers/video/omap2/dss/display.c
drivers/video/omap2/dss/dpi.c
drivers/video/omap2/dss/dsi.c
drivers/video/omap2/dss/dss-of.c [new file with mode: 0644]
drivers/video/omap2/dss/dss.c
drivers/video/omap2/dss/dss.h
drivers/video/omap2/dss/hdmi4.c
drivers/video/omap2/dss/hdmi_wp.c
drivers/video/omap2/dss/sdi.c
drivers/video/omap2/dss/venc.c
drivers/video/omap2/omapfb/omapfb-main.c
drivers/watchdog/iTCO_wdt.c
drivers/watchdog/octeon-wdt-main.c
drivers/xen/balloon.c
drivers/xen/events/events_base.c
fs/9p/vfs_file.c
fs/adfs/super.c
fs/affs/affs.h
fs/affs/amigaffs.c
fs/affs/dir.c
fs/affs/namei.c
fs/affs/super.c
fs/autofs4/dev-ioctl.c
fs/bfs/inode.c
fs/binfmt_elf.c
fs/bio-integrity.c
fs/btrfs/file.c
fs/ceph/cache.c
fs/ceph/cache.h
fs/ceph/caps.c
fs/ceph/debugfs.c
fs/ceph/dir.c
fs/ceph/export.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/ceph/locks.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/strings.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cifs/file.c
fs/dcache.c
fs/exec.c
fs/ext2/acl.c
fs/ext2/ialloc.c
fs/ext2/super.c
fs/ext2/xattr_security.c
fs/ext3/balloc.c
fs/ext3/dir.c
fs/ext3/ialloc.c
fs/ext3/inode.c
fs/ext3/super.c
fs/ext3/xattr_security.c
fs/ext4/file.c
fs/f2fs/acl.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/gc.c
fs/f2fs/inline.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/segment.h
fs/f2fs/super.c
fs/f2fs/xattr.c
fs/fuse/cuse.c
fs/fuse/file.c
fs/gfs2/file.c
fs/isofs/inode.c
fs/jffs2/compr_rtime.c
fs/jffs2/fs.c
fs/jffs2/nodelist.h
fs/jffs2/nodemgmt.c
fs/lockd/svc.c
fs/ncpfs/dir.c
fs/ncpfs/file.c
fs/ncpfs/getopt.c
fs/ncpfs/inode.c
fs/ncpfs/ioctl.c
fs/ncpfs/mmap.c
fs/ncpfs/ncp_fs.h
fs/ncpfs/ncplib_kernel.c
fs/ncpfs/sock.c
fs/ncpfs/symlink.c
fs/nfs/callback_proc.c
fs/nfs/dir.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/internal.h
fs/nfs/nfs3proc.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
fs/nfs/pnfs.c
fs/nfs/proc.c
fs/nfs/unlink.c
fs/nfsd/acl.h
fs/nfsd/nfs4acl.c
fs/nfsd/nfs4callback.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfsctl.c
fs/nfsd/nfsd.h
fs/nfsd/nfsfh.h
fs/nfsd/nfsxdr.c
fs/nfsd/vfs.c
fs/nfsd/xdr4.h
fs/nilfs2/file.c
fs/ntfs/debug.c
fs/ntfs/debug.h
fs/ntfs/super.c
fs/ocfs2/cluster/sys.c
fs/ocfs2/stackglue.c
fs/proc/array.c
fs/proc/base.c
fs/proc/fd.c
fs/proc/inode.c
fs/proc/meminfo.c
fs/proc/task_mmu.c
fs/proc/vmcore.c
fs/quota/Kconfig
fs/reiserfs/dir.c
fs/ubifs/file.c
fs/udf/super.c
fs/ufs/balloc.c
fs/ufs/ialloc.c
fs/ufs/super.c
fs/xfs/xfs_file.c
include/asm-generic/bug.h
include/asm-generic/early_ioremap.h [new file with mode: 0644]
include/asm-generic/io.h
include/asm-generic/iomap.h
include/asm-generic/percpu.h
include/drm/bridge/ptn3460.h [new file with mode: 0644]
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_dp_helper.h
include/drm/drm_fb_helper.h
include/drm/drm_gem_cma_helper.h
include/drm/drm_mipi_dsi.h
include/drm/drm_mm.h
include/drm/drm_modes.h [new file with mode: 0644]
include/drm/drm_plane_helper.h [new file with mode: 0644]
include/drm/drm_vma_manager.h
include/drm/gma_drm.h
include/drm/ttm/ttm_bo_driver.h
include/drm/ttm/ttm_object.h
include/drm/ttm/ttm_placement.h
include/linux/acpi_dma.h
include/linux/binfmts.h
include/linux/bio.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/ceph/ceph_features.h
include/linux/ceph/ceph_fs.h
include/linux/ceph/osd_client.h
include/linux/ceph/osdmap.h
include/linux/ceph/rados.h
include/linux/cpu.h
include/linux/crash_dump.h
include/linux/crush/crush.h
include/linux/dmaengine.h
include/linux/dw_dmac.h
include/linux/f2fs_fs.h
include/linux/hdmi.h
include/linux/host1x.h
include/linux/i2c.h
include/linux/i2c/bfin_twi.h [new file with mode: 0644]
include/linux/i2c/twl.h
include/linux/i2c/twl4030-madc.h
include/linux/idr.h
include/linux/io.h
include/linux/isapnp.h
include/linux/kernel.h
include/linux/lglock.h
include/linux/memcontrol.h
include/linux/mempolicy.h
include/linux/mfd/arizona/registers.h
include/linux/mfd/bcm590xx.h [new file with mode: 0644]
include/linux/mfd/da9052/da9052.h
include/linux/mfd/da9063/core.h
include/linux/mfd/da9063/registers.h
include/linux/mfd/lpc_ich.h
include/linux/mfd/max14577-private.h
include/linux/mfd/max14577.h
include/linux/mfd/mc13xxx.h
include/linux/mfd/pm8xxx/irq.h [deleted file]
include/linux/mfd/pm8xxx/pm8921.h [deleted file]
include/linux/mfd/rtsx_common.h
include/linux/mfd/rtsx_pci.h
include/linux/mfd/rtsx_usb.h [new file with mode: 0644]
include/linux/mfd/tps65218.h [new file with mode: 0644]
include/linux/mm.h
include/linux/mm_types.h
include/linux/mmc/core.h
include/linux/mmc/host.h
include/linux/mmc/sdhci-spear.h
include/linux/mmc/sdhci.h
include/linux/mmc/slot-gpio.h
include/linux/mmdebug.h
include/linux/module.h
include/linux/moduleparam.h
include/linux/mtd/mtd.h
include/linux/mtd/nand.h
include/linux/netdev_features.h
include/linux/netdevice.h
include/linux/nfs_fs.h
include/linux/nfs_xdr.h
include/linux/of_mtd.h
include/linux/percpu.h
include/linux/perf_event.h
include/linux/platform_data/dma-rcar-audmapp.h [new file with mode: 0644]
include/linux/platform_data/elm.h
include/linux/platform_data/i2c-s3c2410.h
include/linux/platform_data/leds-s3c24xx.h
include/linux/platform_data/mmc-msm_sdcc.h
include/linux/platform_data/mmc-mvsdio.h
include/linux/platform_data/mtd-nand-s3c2410.h
include/linux/res_counter.h
include/linux/rio.h
include/linux/sched.h
include/linux/slab.h
include/linux/slub_def.h
include/linux/ssbi.h
include/linux/sunrpc/bc_xprt.h
include/linux/sunrpc/clnt.h
include/linux/sunrpc/svcsock.h
include/linux/sunrpc/xprt.h
include/linux/syscalls.h
include/linux/sysfs.h
include/linux/topology.h
include/linux/vmacache.h [new file with mode: 0644]
include/linux/vmstat.h
include/linux/wait.h
include/linux/writeback.h
include/net/netfilter/nf_conntrack_extend.h
include/scsi/scsi_device.h
include/sound/cs8427.h
include/trace/events/i2c.h [new file with mode: 0644]
include/trace/events/module.h
include/trace/events/task.h
include/uapi/asm-generic/mman-common.h
include/uapi/drm/drm.h
include/uapi/drm/msm_drm.h
include/uapi/drm/radeon_drm.h
include/uapi/drm/tegra_drm.h
include/uapi/drm/vmwgfx_drm.h
include/uapi/linux/prctl.h
include/video/omapdss.h
init/Kconfig
init/initramfs.c
ipc/compat.c
ipc/ipc_sysctl.c
ipc/mqueue.c
ipc/util.c
kernel/cgroup.c
kernel/cpu.c
kernel/debug/debug_core.c
kernel/exit.c
kernel/fork.c
kernel/futex.c
kernel/kallsyms.c
kernel/kexec.c
kernel/ksysfs.c
kernel/locking/Makefile
kernel/module.c
kernel/panic.c
kernel/power/power.h
kernel/power/snapshot.c
kernel/power/suspend.c
kernel/power/swap.c
kernel/profile.c
kernel/res_counter.c
kernel/sched/clock.c
kernel/sched/core.c
kernel/signal.c
kernel/sys.c
kernel/sysctl.c
kernel/time/timekeeping.c
kernel/trace/ring_buffer.c
kernel/trace/trace.h
kernel/tracepoint.c
lib/Kconfig
lib/decompress.c
lib/devres.c
lib/idr.c
lib/iomap.c
lib/percpu_counter.c
lib/smp_processor_id.c
mm/Kconfig
mm/Makefile
mm/compaction.c
mm/early_ioremap.c [new file with mode: 0644]
mm/filemap.c
mm/huge_memory.c
mm/hugetlb.c
mm/internal.h
mm/memblock.c
mm/memcontrol.c
mm/memory.c
mm/mempolicy.c
mm/mempool.c
mm/mlock.c
mm/mmap.c
mm/mprotect.c
mm/nommu.c
mm/page-writeback.c
mm/page_alloc.c
mm/readahead.c
mm/rmap.c
mm/shmem.c
mm/slab.c
mm/slab.h
mm/slab_common.c
mm/slub.c
mm/sparse.c
mm/util.c
mm/vmacache.c [new file with mode: 0644]
mm/vmalloc.c
mm/vmscan.c
mm/vmstat.c
mm/zsmalloc.c
mm/zswap.c
net/bridge/netfilter/ebtables.c
net/ceph/crush/mapper.c
net/ceph/debugfs.c
net/ceph/messenger.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/core/dev.c
net/core/ethtool.c
net/core/filter.c
net/core/flow.c
net/core/pktgen.c
net/ipv4/netfilter/arp_tables.c
net/ipv4/netfilter/ip_tables.c
net/ipv4/route.c
net/ipv6/netfilter/ip6_tables.c
net/iucv/iucv.c
net/mac802154/mib.c
net/netfilter/nf_tables_api.c
net/netfilter/xt_cgroup.c
net/netfilter/xt_connlimit.c
net/netfilter/xt_osf.c
net/packet/af_packet.c
net/sctp/socket.c
net/sunrpc/Kconfig
net/sunrpc/Makefile
net/sunrpc/backchannel_rqst.c
net/sunrpc/clnt.c
net/sunrpc/sched.c
net/sunrpc/svcsock.c
net/sunrpc/xdr.c
net/sunrpc/xprt.c
net/sunrpc/xprtrdma/Makefile
net/sunrpc/xprtrdma/rpc_rdma.c
net/sunrpc/xprtrdma/svc_rdma_recvfrom.c
net/sunrpc/xprtrdma/svc_rdma_sendto.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/transport.c
net/sunrpc/xprtsock.c
net/tipc/net.c
net/tipc/socket.c
scripts/Kbuild.include
scripts/Makefile
scripts/Makefile.lib
scripts/kallsyms.c
scripts/kconfig/confdata.c
scripts/kconfig/expr.h
scripts/kconfig/lkc.h
scripts/kconfig/menu.c
scripts/kconfig/zconf.gperf
scripts/kconfig/zconf.hash.c_shipped
scripts/link-vmlinux.sh
scripts/mod/file2alias.c
sound/i2c/cs8427.c
sound/isa/Kconfig
sound/mips/au1x00.c
sound/oss/ad1848.c
sound/oss/dmasound/dmasound_paula.c
sound/oss/opl3.c
sound/oss/pas2_mixer.c
sound/oss/pas2_pcm.c
sound/oss/sb_common.c
sound/oss/sb_ess.c
sound/oss/sequencer.c
sound/oss/sound_config.h
sound/oss/soundcard.c
sound/oss/uart401.c
sound/pci/Kconfig
sound/pci/hda/hda_controller.c
sound/pci/hda/hda_controller.h
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/pci/ice1712/delta.c
sound/pci/ice1712/ice1712.c
sound/soc/codecs/alc5623.c
sound/soc/codecs/alc5632.c
sound/soc/codecs/cs42l52.c
sound/soc/codecs/cs42l52.h
sound/soc/codecs/cs42xx8.c
sound/soc/codecs/da732x.c
sound/soc/codecs/max98090.c
sound/soc/codecs/rt5640.c
sound/soc/codecs/tlv320aic23-i2c.c
sound/soc/davinci/davinci-mcasp.c
sound/soc/fsl/fsl_sai.c
sound/soc/fsl/fsl_sai.h
sound/soc/samsung/ac97.c
sound/soc/samsung/dma.h
sound/soc/samsung/i2s.c
sound/soc/samsung/pcm.c
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/spdif.c
sound/usb/pcm.c
tools/vm/page-types.c

index 3f0b9ae..70ec992 100644 (file)
@@ -43,6 +43,36 @@ Description:
                The invalid_io file is read-only and specifies the number of
                non-page-size-aligned I/O requests issued to this device.
 
+What:          /sys/block/zram<id>/failed_reads
+Date:          February 2014
+Contact:       Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+               The failed_reads file is read-only and specifies the number of
+               failed reads happened on this device.
+
+What:          /sys/block/zram<id>/failed_writes
+Date:          February 2014
+Contact:       Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+               The failed_writes file is read-only and specifies the number of
+               failed writes happened on this device.
+
+What:          /sys/block/zram<id>/max_comp_streams
+Date:          February 2014
+Contact:       Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+               The max_comp_streams file is read-write and specifies the
+               number of backend's zcomp_strm compression streams (number of
+               concurrent compress operations).
+
+What:          /sys/block/zram<id>/comp_algorithm
+Date:          February 2014
+Contact:       Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
+Description:
+               The comp_algorithm file is read-write and lets to show
+               available and selected compression algorithms, change
+               compression algorithm selection.
+
 What:          /sys/block/zram<id>/notify_free
 Date:          August 2010
 Contact:       Nitin Gupta <ngupta@vflare.org>
@@ -53,15 +83,6 @@ Description:
                is freed. This statistic is applicable only when this disk is
                being used as a swap disk.
 
-What:          /sys/block/zram<id>/discard
-Date:          August 2010
-Contact:       Nitin Gupta <ngupta@vflare.org>
-Description:
-               The discard file is read-only and specifies the number of
-               discard requests received by this device. These requests
-               provide information to block device regarding blocks which are
-               no longer used by filesystem.
-
 What:          /sys/block/zram<id>/zero_pages
 Date:          August 2010
 Contact:       Nitin Gupta <ngupta@vflare.org>
index 32b0809..62dd725 100644 (file)
@@ -55,3 +55,15 @@ Date:                January 2014
 Contact:       "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
 Description:
                 Controls the number of trials to find a victim segment.
+
+What:          /sys/fs/f2fs/<disk>/dir_level
+Date:          March 2014
+Contact:       "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
+Description:
+                Controls the directory level for large directory.
+
+What:          /sys/fs/f2fs/<disk>/ram_thresh
+Date:          March 2014
+Contact:       "Jaegeuk Kim" <jaegeuk.kim@samsung.com>
+Description:
+                Controls the memory footprint used by f2fs.
index 47064c2..0aac02e 100644 (file)
@@ -49,3 +49,4 @@ Description:  Module taint flags:
                        O - out-of-tree module
                        F - force-loaded module
                        C - staging driver module
+                       E - unsigned module
index 8d96ebf..b444f2e 100644 (file)
@@ -16,7 +16,7 @@ DOCBOOKS := z8530book.xml device-drivers.xml \
            alsa-driver-api.xml writing-an-alsa-driver.xml \
            tracepoint.xml drm.xml media_api.xml w1.xml
 
-include $(srctree)/Documentation/DocBook/media/Makefile
+include Documentation/DocBook/media/Makefile
 
 ###
 # The build process is as follows (targets):
@@ -36,6 +36,7 @@ PS_METHOD     = $(prefer-db2x)
 # The targets that may be used.
 PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs
 
+targets += $(DOCBOOKS)
 BOOKS := $(addprefix $(obj)/,$(DOCBOOKS))
 xmldocs: $(BOOKS)
 sgmldocs: xmldocs
@@ -58,14 +59,14 @@ mandocs: $(MAN)
 
 installmandocs: mandocs
        mkdir -p /usr/local/man/man9/
-       install Documentation/DocBook/man/*.9.gz /usr/local/man/man9/
+       install $(obj)/man/*.9.gz /usr/local/man/man9/
 
 ###
 #External programs used
 KERNELDOC = $(srctree)/scripts/kernel-doc
 DOCPROC   = $(objtree)/scripts/docproc
 
-XMLTOFLAGS = -m $(srctree)/Documentation/DocBook/stylesheet.xsl
+XMLTOFLAGS = -m $(srctree)/$(src)/stylesheet.xsl
 XMLTOFLAGS += --skip-validation
 
 ###
@@ -87,21 +88,9 @@ define rule_docproc
         ) > $(dir $@).$(notdir $@).cmd
 endef
 
-%.xml: %.tmpl FORCE
+%.xml: %.tmpl $(KERNELDOC) $(DOCPROC) FORCE
        $(call if_changed_rule,docproc)
 
-###
-#Read in all saved dependency files
-cmd_files := $(wildcard $(foreach f,$(BOOKS),$(dir $(f)).$(notdir $(f)).cmd))
-
-ifneq ($(cmd_files),)
-  include $(cmd_files)
-endif
-
-###
-# Changes in kernel-doc force a rebuild of all documentation
-$(BOOKS): $(KERNELDOC)
-
 # Tell kbuild to always build the programs
 always := $(hostprogs-y)
 
@@ -139,7 +128,7 @@ quiet_cmd_db2pdf = PDF     $@
 
 
 index = index.html
-main_idx = Documentation/DocBook/$(index)
+main_idx = $(obj)/$(index)
 build_main_index = rm -rf $(main_idx); \
                   echo '<h1>Linux Kernel HTML Documentation</h1>' >> $(main_idx) && \
                   echo '<h2>Kernel Version: $(KERNELVERSION)</h2>' >> $(main_idx) && \
@@ -148,7 +137,7 @@ build_main_index = rm -rf $(main_idx); \
 quiet_cmd_db2html = HTML    $@
       cmd_db2html = xmlto html $(XMLTOFLAGS) -o $(patsubst %.html,%,$@) $< && \
                echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/index.html"> \
-        $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
+               $(patsubst %.html,%,$(notdir $@))</a><p>' > $@
 
 %.html:        %.xml
        @(which xmlto > /dev/null 2>&1) || \
index ed1d6d2..702c447 100644 (file)
          </address>
        </affiliation>
       </author>
+      <author>
+       <firstname>Daniel</firstname>
+       <surname>Vetter</surname>
+       <contrib>Contributions all over the place</contrib>
+       <affiliation>
+         <orgname>Intel Corporation</orgname>
+         <address>
+           <email>daniel.vetter@ffwll.ch</email>
+         </address>
+       </affiliation>
+      </author>
     </authorgroup>
 
     <copyright>
       <year>2008-2009</year>
-      <year>2012</year>
+      <year>2013-2014</year>
       <holder>Intel Corporation</holder>
+    </copyright>
+    <copyright>
+      <year>2012</year>
       <holder>Laurent Pinchart</holder>
     </copyright>
 
 
 <toc></toc>
 
-  <!-- Introduction -->
+<part id="drmCore">
+  <title>DRM Core</title>
+  <partintro>
+    <para>
+      This first part of the DRM Developer's Guide documents core DRM code,
+      helper libraries for writting drivers and generic userspace interfaces
+      exposed by DRM drivers.
+    </para>
+  </partintro>
 
   <chapter id="drmIntroduction">
     <title>Introduction</title>
@@ -264,8 +286,8 @@ char *date;</synopsis>
       <para>
         The <methodname>load</methodname> method is the driver and device
         initialization entry point. The method is responsible for allocating and
-        initializing driver private data, specifying supported performance
-        counters, performing resource allocation and mapping (e.g. acquiring
+       initializing driver private data, performing resource allocation and
+       mapping (e.g. acquiring
         clocks, mapping registers or allocating command buffers), initializing
         the memory manager (<xref linkend="drm-memory-management"/>), installing
         the IRQ handler (<xref linkend="drm-irq-registration"/>), setting up
@@ -295,7 +317,7 @@ char *date;</synopsis>
        their <methodname>load</methodname> method called with flags to 0.
       </para>
       <sect3>
-        <title>Driver Private &amp; Performance Counters</title>
+        <title>Driver Private Data</title>
         <para>
           The driver private hangs off the main
           <structname>drm_device</structname> structure and can be used for
@@ -307,14 +329,6 @@ char *date;</synopsis>
           <structname>drm_device</structname>.<structfield>dev_priv</structfield>
           set to NULL when the driver is unloaded.
         </para>
-        <para>
-          DRM supports several counters which were used for rough performance
-          characterization. This stat counter system is deprecated and should not
-          be used. If performance monitoring is desired, the developer should
-          investigate and potentially enhance the kernel perf and tracing
-          infrastructure to export GPU related performance information for
-          consumption by performance monitoring tools and applications.
-        </para>
       </sect3>
       <sect3 id="drm-irq-registration">
         <title>IRQ Registration</title>
@@ -697,55 +711,16 @@ char *date;</synopsis>
           respectively. The conversion is handled by the DRM core without any
           driver-specific support.
         </para>
-        <para>
-          Similar to global names, GEM file descriptors are also used to share GEM
-          objects across processes. They offer additional security: as file
-          descriptors must be explicitly sent over UNIX domain sockets to be shared
-          between applications, they can't be guessed like the globally unique GEM
-          names.
-        </para>
-        <para>
-          Drivers that support GEM file descriptors, also known as the DRM PRIME
-          API, must set the DRIVER_PRIME bit in the struct
-          <structname>drm_driver</structname>
-          <structfield>driver_features</structfield> field, and implement the
-          <methodname>prime_handle_to_fd</methodname> and
-          <methodname>prime_fd_to_handle</methodname> operations.
-        </para>
-        <para>
-          <synopsis>int (*prime_handle_to_fd)(struct drm_device *dev,
-                            struct drm_file *file_priv, uint32_t handle,
-                            uint32_t flags, int *prime_fd);
-  int (*prime_fd_to_handle)(struct drm_device *dev,
-                            struct drm_file *file_priv, int prime_fd,
-                            uint32_t *handle);</synopsis>
-          Those two operations convert a handle to a PRIME file descriptor and
-          vice versa. Drivers must use the kernel dma-buf buffer sharing framework
-          to manage the PRIME file descriptors.
-        </para>
-        <para>
-          While non-GEM drivers must implement the operations themselves, GEM
-          drivers must use the <function>drm_gem_prime_handle_to_fd</function>
-          and <function>drm_gem_prime_fd_to_handle</function> helper functions.
-          Those helpers rely on the driver
-          <methodname>gem_prime_export</methodname> and
-          <methodname>gem_prime_import</methodname> operations to create a dma-buf
-          instance from a GEM object (dma-buf exporter role) and to create a GEM
-          object from a dma-buf instance (dma-buf importer role).
-        </para>
-        <para>
-          <synopsis>struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
-                                       struct drm_gem_object *obj,
-                                       int flags);
-  struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
-                                              struct dma_buf *dma_buf);</synopsis>
-          These two operations are mandatory for GEM drivers that support DRM
-          PRIME.
-        </para>
-        <sect4>
-          <title>DRM PRIME Helper Functions Reference</title>
-!Pdrivers/gpu/drm/drm_prime.c PRIME Helpers
-        </sect4>
+       <para>
+         GEM also supports buffer sharing with dma-buf file descriptors through
+         PRIME. GEM-based drivers must use the provided helpers functions to
+         implement the exporting and importing correctly. See <xref linkend="drm-prime-support" />.
+         Since sharing file descriptors is inherently more secure than the
+         easily guessable and global GEM names it is the preferred buffer
+         sharing mechanism. Sharing buffers through GEM names is only supported
+         for legacy userspace. Furthermore PRIME also allows cross-device
+         buffer sharing since it is based on dma-bufs.
+       </para>
       </sect3>
       <sect3 id="drm-gem-objects-mapping">
         <title>GEM Objects Mapping</title>
@@ -829,62 +804,6 @@ char *date;</synopsis>
           faults can implement their own mmap file operation handler.
         </para>
       </sect3>
-      <sect3>
-        <title>Dumb GEM Objects</title>
-        <para>
-          The GEM API doesn't standardize GEM objects creation and leaves it to
-          driver-specific ioctls. While not an issue for full-fledged graphics
-          stacks that include device-specific userspace components (in libdrm for
-          instance), this limit makes DRM-based early boot graphics unnecessarily
-          complex.
-        </para>
-        <para>
-          Dumb GEM objects partly alleviate the problem by providing a standard
-          API to create dumb buffers suitable for scanout, which can then be used
-          to create KMS frame buffers.
-        </para>
-        <para>
-          To support dumb GEM objects drivers must implement the
-          <methodname>dumb_create</methodname>,
-          <methodname>dumb_destroy</methodname> and
-          <methodname>dumb_map_offset</methodname> operations.
-        </para>
-        <itemizedlist>
-          <listitem>
-            <synopsis>int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev,
-                     struct drm_mode_create_dumb *args);</synopsis>
-            <para>
-              The <methodname>dumb_create</methodname> operation creates a GEM
-              object suitable for scanout based on the width, height and depth
-              from the struct <structname>drm_mode_create_dumb</structname>
-              argument. It fills the argument's <structfield>handle</structfield>,
-              <structfield>pitch</structfield> and <structfield>size</structfield>
-              fields with a handle for the newly created GEM object and its line
-              pitch and size in bytes.
-            </para>
-          </listitem>
-          <listitem>
-            <synopsis>int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev,
-                      uint32_t handle);</synopsis>
-            <para>
-              The <methodname>dumb_destroy</methodname> operation destroys a dumb
-              GEM object created by <methodname>dumb_create</methodname>.
-            </para>
-          </listitem>
-          <listitem>
-            <synopsis>int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev,
-                         uint32_t handle, uint64_t *offset);</synopsis>
-            <para>
-              The <methodname>dumb_map_offset</methodname> operation associates an
-              mmap fake offset with the GEM object given by the handle and returns
-              it. Drivers must use the
-              <function>drm_gem_create_mmap_offset</function> function to
-              associate the fake offset as described in
-              <xref linkend="drm-gem-objects-mapping"/>.
-            </para>
-          </listitem>
-        </itemizedlist>
-      </sect3>
       <sect3>
         <title>Memory Coherency</title>
         <para>
@@ -924,7 +843,99 @@ char *date;</synopsis>
           abstracted from the client in libdrm.
         </para>
       </sect3>
-    </sect2>
+      <sect3>
+        <title>GEM Function Reference</title>
+!Edrivers/gpu/drm/drm_gem.c
+      </sect3>
+      </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>
+      <sect2 id="drm-prime-support">
+       <title>PRIME Buffer Sharing</title>
+       <para>
+         PRIME is the cross device buffer sharing framework in drm, originally
+         created for the OPTIMUS range of multi-gpu platforms. To userspace
+         PRIME buffers are dma-buf based file descriptors.
+       </para>
+       <sect3>
+         <title>Overview and Driver Interface</title>
+         <para>
+           Similar to GEM global names, PRIME file descriptors are
+           also used to share buffer objects across processes. They offer
+           additional security: as file descriptors must be explicitly sent over
+           UNIX domain sockets to be shared between applications, they can't be
+           guessed like the globally unique GEM names.
+         </para>
+         <para>
+           Drivers that support the PRIME
+           API must set the DRIVER_PRIME bit in the struct
+           <structname>drm_driver</structname>
+           <structfield>driver_features</structfield> field, and implement the
+           <methodname>prime_handle_to_fd</methodname> and
+           <methodname>prime_fd_to_handle</methodname> operations.
+         </para>
+         <para>
+           <synopsis>int (*prime_handle_to_fd)(struct drm_device *dev,
+                         struct drm_file *file_priv, uint32_t handle,
+                         uint32_t flags, int *prime_fd);
+int (*prime_fd_to_handle)(struct drm_device *dev,
+                         struct drm_file *file_priv, int prime_fd,
+                         uint32_t *handle);</synopsis>
+           Those two operations convert a handle to a PRIME file descriptor and
+           vice versa. Drivers must use the kernel dma-buf buffer sharing framework
+           to manage the PRIME file descriptors. Similar to the mode setting
+           API PRIME is agnostic to the underlying buffer object manager, as
+           long as handles are 32bit unsinged integers.
+         </para>
+         <para>
+           While non-GEM drivers must implement the operations themselves, GEM
+           drivers must use the <function>drm_gem_prime_handle_to_fd</function>
+           and <function>drm_gem_prime_fd_to_handle</function> helper functions.
+           Those helpers rely on the driver
+           <methodname>gem_prime_export</methodname> and
+           <methodname>gem_prime_import</methodname> operations to create a dma-buf
+           instance from a GEM object (dma-buf exporter role) and to create a GEM
+           object from a dma-buf instance (dma-buf importer role).
+         </para>
+         <para>
+           <synopsis>struct dma_buf * (*gem_prime_export)(struct drm_device *dev,
+                                    struct drm_gem_object *obj,
+                                    int flags);
+struct drm_gem_object * (*gem_prime_import)(struct drm_device *dev,
+                                           struct dma_buf *dma_buf);</synopsis>
+           These two operations are mandatory for GEM drivers that support
+           PRIME.
+         </para>
+       </sect3>
+        <sect3>
+          <title>PRIME Helper Functions</title>
+!Pdrivers/gpu/drm/drm_prime.c PRIME Helpers
+        </sect3>
+      </sect2>
+      <sect2>
+       <title>PRIME Function References</title>
+!Edrivers/gpu/drm/drm_prime.c
+      </sect2>
+      <sect2>
+       <title>DRM MM Range Allocator</title>
+       <sect3>
+         <title>Overview</title>
+!Pdrivers/gpu/drm/drm_mm.c Overview
+       </sect3>
+       <sect3>
+         <title>LRU Scan/Eviction Support</title>
+!Pdrivers/gpu/drm/drm_mm.c lru scan roaster
+       </sect3>
+      </sect2>
+      <sect2>
+       <title>DRM MM Range Allocator Function References</title>
+!Edrivers/gpu/drm/drm_mm.c
+!Iinclude/drm/drm_mm.h
+      </sect2>
   </sect1>
 
   <!-- Internals: mode setting -->
@@ -952,6 +963,11 @@ int max_width, max_height;</synopsis>
        <para>Mode setting functions.</para>
       </listitem>
     </itemizedlist>
+    <sect2>
+      <title>Display Modes Function Reference</title>
+!Iinclude/drm/drm_modes.h
+!Edrivers/gpu/drm/drm_modes.c
+    </sect2>
     <sect2>
       <title>Frame Buffer Creation</title>
       <synopsis>struct drm_framebuffer *(*fb_create)(struct drm_device *dev,
@@ -968,9 +984,11 @@ int max_width, max_height;</synopsis>
         Frame buffers rely on the underneath memory manager for low-level memory
         operations. When creating a frame buffer applications pass a memory
         handle (or a list of memory handles for multi-planar formats) through
-        the <parameter>drm_mode_fb_cmd2</parameter> argument. This document
-        assumes that the driver uses GEM, those handles thus reference GEM
-        objects.
+       the <parameter>drm_mode_fb_cmd2</parameter> argument. For drivers using
+       GEM as their userspace buffer management interface this would be a GEM
+       handle.  Drivers are however free to use their own backing storage object
+       handles, e.g. vmwgfx directly exposes special TTM handles to userspace
+       and so expects TTM handles in the create ioctl and not GEM handles.
       </para>
       <para>
         Drivers must first validate the requested frame buffer parameters passed
@@ -992,7 +1010,7 @@ int max_width, max_height;</synopsis>
       </para>
 
       <para>
-       The initailization of the new framebuffer instance is finalized with a
+       The initialization of the new framebuffer instance is finalized with a
        call to <function>drm_framebuffer_init</function> which takes a pointer
        to DRM frame buffer operations (struct
        <structname>drm_framebuffer_funcs</structname>). Note that this function
@@ -1042,7 +1060,7 @@ int max_width, max_height;</synopsis>
       <para>
        The lifetime of a drm framebuffer is controlled with a reference count,
        drivers can grab additional references with
-       <function>drm_framebuffer_reference</function> </para> and drop them
+       <function>drm_framebuffer_reference</function>and drop them
        again with <function>drm_framebuffer_unreference</function>. For
        driver-private framebuffers for which the last reference is never
        dropped (e.g. for the fbdev framebuffer when the struct
@@ -1050,6 +1068,72 @@ int max_width, max_height;</synopsis>
        helper struct) drivers can manually clean up a framebuffer at module
        unload time with
        <function>drm_framebuffer_unregister_private</function>.
+      </para>
+    </sect2>
+    <sect2>
+      <title>Dumb Buffer Objects</title>
+      <para>
+       The KMS API doesn't standardize backing storage object creation and
+       leaves it to driver-specific ioctls. Furthermore actually creating a
+       buffer object even for GEM-based drivers is done through a
+       driver-specific ioctl - GEM only has a common userspace interface for
+       sharing and destroying objects. While not an issue for full-fledged
+       graphics stacks that include device-specific userspace components (in
+       libdrm for instance), this limit makes DRM-based early boot graphics
+       unnecessarily complex.
+      </para>
+      <para>
+        Dumb objects partly alleviate the problem by providing a standard
+        API to create dumb buffers suitable for scanout, which can then be used
+        to create KMS frame buffers.
+      </para>
+      <para>
+        To support dumb objects drivers must implement the
+        <methodname>dumb_create</methodname>,
+        <methodname>dumb_destroy</methodname> and
+        <methodname>dumb_map_offset</methodname> operations.
+      </para>
+      <itemizedlist>
+        <listitem>
+          <synopsis>int (*dumb_create)(struct drm_file *file_priv, struct drm_device *dev,
+                   struct drm_mode_create_dumb *args);</synopsis>
+          <para>
+            The <methodname>dumb_create</methodname> operation creates a driver
+           object (GEM or TTM handle) suitable for scanout based on the
+           width, height and depth from the struct
+           <structname>drm_mode_create_dumb</structname> argument. It fills the
+           argument's <structfield>handle</structfield>,
+           <structfield>pitch</structfield> and <structfield>size</structfield>
+           fields with a handle for the newly created object and its line
+            pitch and size in bytes.
+          </para>
+        </listitem>
+        <listitem>
+          <synopsis>int (*dumb_destroy)(struct drm_file *file_priv, struct drm_device *dev,
+                    uint32_t handle);</synopsis>
+          <para>
+            The <methodname>dumb_destroy</methodname> operation destroys a dumb
+            object created by <methodname>dumb_create</methodname>.
+          </para>
+        </listitem>
+        <listitem>
+          <synopsis>int (*dumb_map_offset)(struct drm_file *file_priv, struct drm_device *dev,
+                       uint32_t handle, uint64_t *offset);</synopsis>
+          <para>
+            The <methodname>dumb_map_offset</methodname> operation associates an
+            mmap fake offset with the object given by the handle and returns
+            it. Drivers must use the
+            <function>drm_gem_create_mmap_offset</function> function to
+            associate the fake offset as described in
+            <xref linkend="drm-gem-objects-mapping"/>.
+          </para>
+        </listitem>
+      </itemizedlist>
+      <para>
+        Note that dumb objects may not be used for gpu acceleration, as has been
+       attempted on some ARM embedded platforms. Such drivers really must have
+       a hardware-specific ioctl to allocate suitable buffer objects.
+      </para>
     </sect2>
     <sect2>
       <title>Output Polling</title>
@@ -1110,7 +1194,7 @@ int max_width, max_height;</synopsis>
           pointer to CRTC functions.
         </para>
       </sect3>
-      <sect3>
+      <sect3 id="drm-kms-crtcops">
         <title>CRTC Operations</title>
         <sect4>
           <title>Set Configuration</title>
@@ -1130,8 +1214,11 @@ int max_width, max_height;</synopsis>
             This operation is called with the mode config lock held.
           </para>
           <note><para>
-            FIXME: How should set_config interact with DPMS? If the CRTC is
-            suspended, should it be resumed?
+           Note that the drm core has no notion of restoring the mode setting
+           state after resume, since all resume handling is in the full
+           responsibility of the driver. The common mode setting helper library
+           though provides a helper which can be used for this:
+           <function>drm_helper_resume_force_mode</function>.
           </para></note>
         </sect4>
         <sect4>
@@ -1248,15 +1335,47 @@ int max_width, max_height;</synopsis>
        optionally scale it to a destination size. The result is then blended
        with or overlayed on top of a CRTC.
       </para>
+      <para>
+      The DRM core recognizes three types of planes:
+      <itemizedlist>
+        <listitem>
+        DRM_PLANE_TYPE_PRIMARY represents a "main" plane for a CRTC.  Primary
+        planes are the planes operated upon by by CRTC modesetting and flipping
+        operations described in <xref linkend="drm-kms-crtcops"/>.
+        </listitem>
+        <listitem>
+        DRM_PLANE_TYPE_CURSOR represents a "cursor" plane for a CRTC.  Cursor
+        planes are the planes operated upon by the DRM_IOCTL_MODE_CURSOR and
+        DRM_IOCTL_MODE_CURSOR2 ioctls.
+        </listitem>
+        <listitem>
+        DRM_PLANE_TYPE_OVERLAY represents all non-primary, non-cursor planes.
+        Some drivers refer to these types of planes as "sprites" internally.
+        </listitem>
+      </itemizedlist>
+      For compatibility with legacy userspace, only overlay planes are made
+      available to userspace by default.  Userspace clients may set the
+      DRM_CLIENT_CAP_UNIVERSAL_PLANES client capability bit to indicate that
+      they wish to receive a universal plane list containing all plane types.
+      </para>
       <sect3>
         <title>Plane Initialization</title>
         <para>
-          Planes are optional. To create a plane, a KMS drivers allocates and
+          To create a plane, a KMS drivers allocates and
           zeroes an instances of struct <structname>drm_plane</structname>
           (possibly as part of a larger structure) and registers it with a call
-          to <function>drm_plane_init</function>. The function takes a bitmask
+          to <function>drm_universal_plane_init</function>. The function takes a bitmask
           of the CRTCs that can be associated with the plane, a pointer to the
-          plane functions and a list of format supported formats.
+          plane functions, a list of format supported formats, and the type of
+          plane (primary, cursor, or overlay) being initialized.
+        </para>
+        <para>
+          Cursor and overlay planes are optional.  All drivers should provide
+          one primary plane per CRTC (although this requirement may change in
+          the future); drivers that do not wish to provide special handling for
+          primary planes may make use of the helper functions described in
+          <xref linkend="drm-kms-planehelpers"/> to create and register a
+          primary plane with standard capabilities.
         </para>
       </sect3>
       <sect3>
@@ -1687,7 +1806,7 @@ void intel_crt_init(struct drm_device *dev)
   <sect1>
     <title>Mode Setting Helper Functions</title>
     <para>
-      The CRTC, encoder and connector functions provided by the drivers
+      The plane, CRTC, encoder and connector functions provided by the drivers
       implement the DRM API. They're called by the DRM core and ioctl handlers
       to handle device state changes and configuration request. As implementing
       those functions often requires logic not specific to drivers, mid-layer
@@ -1695,8 +1814,8 @@ void intel_crt_init(struct drm_device *dev)
     </para>
     <para>
       The DRM core contains one mid-layer implementation. The mid-layer provides
-      implementations of several CRTC, encoder and connector functions (called
-      from the top of the mid-layer) that pre-process requests and call
+      implementations of several plane, CRTC, encoder and connector functions
+      (called from the top of the mid-layer) that pre-process requests and call
       lower-level functions provided by the driver (at the bottom of the
       mid-layer). For instance, the
       <function>drm_crtc_helper_set_config</function> function can be used to
@@ -2134,7 +2253,7 @@ void intel_crt_init(struct drm_device *dev)
             set the <structfield>display_info</structfield>
             <structfield>width_mm</structfield> and
             <structfield>height_mm</structfield> fields if they haven't been set
-            already (for instance at initilization time when a fixed-size panel is
+            already (for instance at initialization time when a fixed-size panel is
             attached to the connector). The mode <structfield>width_mm</structfield>
             and <structfield>height_mm</structfield> fields are only used internally
             during EDID parsing and should not be set when creating modes manually.
@@ -2196,10 +2315,19 @@ void intel_crt_init(struct drm_device *dev)
 !Edrivers/gpu/drm/drm_flip_work.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
+      <title>HDMI Infoframes Helper Reference</title>
+      <para>
+       Strictly speaking this is not a DRM helper library but generally useable
+       by any driver interfacing with HDMI outputs like v4l or alsa drivers.
+       But it nicely fits into the overall topic of mode setting helper
+       libraries and hence is also included here.
+      </para>
+!Iinclude/linux/hdmi.h
+!Edrivers/video/hdmi.c
+    </sect2>
+    <sect2>
+      <title id="drm-kms-planehelpers">Plane Helper Reference</title>
+!Edrivers/gpu/drm/drm_plane_helper.c Plane Helpers
     </sect2>
   </sect1>
 
@@ -2561,42 +2689,44 @@ int num_ioctls;</synopsis>
       </para>
     </sect2>
   </sect1>
-
   <sect1>
-    <title>Command submission &amp; fencing</title>
+    <title>Legacy Support Code</title>
     <para>
-      This should cover a few device-specific command submission
-      implementations.
+      The section very brievely covers some of the old legacy support code which
+      is only used by old DRM drivers which have done a so-called shadow-attach
+      to the underlying device instead of registering as a real driver. This
+      also includes some of the old generic buffer mangement and command
+      submission code. Do not use any of this in new and modern drivers.
     </para>
-  </sect1>
-
-  <!-- Internals: suspend/resume -->
 
-  <sect1>
-    <title>Suspend/Resume</title>
-    <para>
-      The DRM core provides some suspend/resume code, but drivers wanting full
-      suspend/resume support should provide save() and restore() functions.
-      These are called at suspend, hibernate, or resume time, and should perform
-      any state save or restore required by your device across suspend or
-      hibernate states.
-    </para>
-    <synopsis>int (*suspend) (struct drm_device *, pm_message_t state);
-int (*resume) (struct drm_device *);</synopsis>
-    <para>
-      Those are legacy suspend and resume methods. New driver should use the
-      power management interface provided by their bus type (usually through
-      the struct <structname>device_driver</structname> dev_pm_ops) and set
-      these methods to NULL.
-    </para>
-  </sect1>
+    <sect2>
+      <title>Legacy Suspend/Resume</title>
+      <para>
+       The DRM core provides some suspend/resume code, but drivers wanting full
+       suspend/resume support should provide save() and restore() functions.
+       These are called at suspend, hibernate, or resume time, and should perform
+       any state save or restore required by your device across suspend or
+       hibernate states.
+      </para>
+      <synopsis>int (*suspend) (struct drm_device *, pm_message_t state);
+  int (*resume) (struct drm_device *);</synopsis>
+      <para>
+       Those are legacy suspend and resume methods which
+       <emphasis>only</emphasis> work with the legacy shadow-attach driver
+       registration functions. New driver should use the power management
+       interface provided by their bus type (usually through
+       the struct <structname>device_driver</structname> dev_pm_ops) and set
+       these methods to NULL.
+      </para>
+    </sect2>
 
-  <sect1>
-    <title>DMA services</title>
-    <para>
-      This should cover how DMA mapping etc. is supported by the core.
-      These functions are deprecated and should not be used.
-    </para>
+    <sect2>
+      <title>Legacy DMA Services</title>
+      <para>
+       This should cover how DMA mapping etc. is supported by the core.
+       These functions are deprecated and should not be used.
+      </para>
+    </sect2>
   </sect1>
   </chapter>
 
@@ -2658,8 +2788,8 @@ int (*resume) (struct drm_device *);</synopsis>
         DRM core provides multiple character-devices for user-space to use.
         Depending on which device is opened, user-space can perform a different
         set of operations (mainly ioctls). The primary node is always created
-        and called <term>card&lt;num&gt;</term>. Additionally, a currently
-        unused control node, called <term>controlD&lt;num&gt;</term> is also
+        and called card&lt;num&gt;. Additionally, a currently
+        unused control node, called controlD&lt;num&gt; is also
         created. The primary node provides all legacy operations and
         historically was the only interface used by userspace. With KMS, the
         control node was introduced. However, the planned KMS control interface
@@ -2674,21 +2804,21 @@ int (*resume) (struct drm_device *);</synopsis>
         nodes were introduced. Render nodes solely serve render clients, that
         is, no modesetting or privileged ioctls can be issued on render nodes.
         Only non-global rendering commands are allowed. If a driver supports
-        render nodes, it must advertise it via the <term>DRIVER_RENDER</term>
+        render nodes, it must advertise it via the DRIVER_RENDER
         DRM driver capability. If not supported, the primary node must be used
         for render clients together with the legacy drmAuth authentication
         procedure.
       </para>
       <para>
         If a driver advertises render node support, DRM core will create a
-        separate render node called <term>renderD&lt;num&gt;</term>. There will
+        separate render node called renderD&lt;num&gt;. There will
         be one render node per device. No ioctls except  PRIME-related ioctls
-        will be allowed on this node. Especially <term>GEM_OPEN</term> will be
+        will be allowed on this node. Especially GEM_OPEN will be
         explicitly prohibited. Render nodes are designed to avoid the
         buffer-leaks, which occur if clients guess the flink names or mmap
         offsets on the legacy interface. Additionally to this basic interface,
         drivers must mark their driver-dependent render-only ioctls as
-        <term>DRM_RENDER_ALLOW</term> so render clients can use them. Driver
+        DRM_RENDER_ALLOW so render clients can use them. Driver
         authors must be careful not to allow any privileged ioctls on render
         nodes.
       </para>
@@ -2749,15 +2879,73 @@ int (*resume) (struct drm_device *);</synopsis>
     </sect1>
 
   </chapter>
+</part>
+<part id="drmDrivers">
+  <title>DRM Drivers</title>
 
-  <!-- API reference -->
+  <partintro>
+    <para>
+      This second part of the DRM Developer's Guide documents driver code,
+      implementation details and also all the driver-specific userspace
+      interfaces. Especially since all hardware-acceleration interfaces to
+      userspace are driver specific for efficiency and other reasons these
+      interfaces can be rather substantial. Hence every driver has its own
+      chapter.
+    </para>
+  </partintro>
 
-  <appendix id="drmDriverApi">
-    <title>DRM Driver API</title>
+  <chapter id="drmI915">
+    <title>drm/i915 Intel GFX Driver</title>
     <para>
-      Include auto-generated API reference here (need to reference it
-      from paragraphs above too).
+      The drm/i915 driver supports all (with the exception of some very early
+      models) integrated GFX chipsets with both Intel display and rendering
+      blocks. This excludes a set of SoC platforms with an SGX rendering unit,
+      those have basic support through the gma500 drm driver.
     </para>
-  </appendix>
+    <sect1>
+      <title>Display Hardware Handling</title>
+      <para>
+        This section covers everything related to the display hardware including
+        the mode setting infrastructure, plane, sprite and cursor handling and
+        display, output probing and related topics.
+      </para>
+      <sect2>
+        <title>Mode Setting Infrastructure</title>
+        <para>
+          The i915 driver is thus far the only DRM driver which doesn't use the
+          common DRM helper code to implement mode setting sequences. Thus it
+          has its own tailor-made infrastructure for executing a display
+          configuration change.
+        </para>
+      </sect2>
+      <sect2>
+        <title>Plane Configuration</title>
+        <para>
+         This section covers plane configuration and composition with the
+         primary plane, sprites, cursors and overlays. This includes the
+         infrastructure to do atomic vsync'ed updates of all this state and
+         also tightly coupled topics like watermark setup and computation,
+         framebuffer compression and panel self refresh.
+        </para>
+      </sect2>
+      <sect2>
+        <title>Output Probing</title>
+        <para>
+         This section covers output probing and related infrastructure like the
+         hotplug interrupt storm detection and mitigation code. Note that the
+         i915 driver still uses most of the common DRM helper code for output
+         probing, so those sections fully apply.
+        </para>
+      </sect2>
+    </sect1>
 
+    <sect1>
+      <title>Memory Management and Command Submission</title>
+      <para>
+       This sections covers all things related to the GEM implementation in the
+       i915 driver.
+      </para>
+    </sect1>
+  </chapter>
+</part>
 </book>
index d0758b2..e84f094 100644 (file)
@@ -671,7 +671,7 @@ printk(KERN_INFO "my ip: %pI4\n", &amp;ipaddress);
 
   <sect1 id="routines-local-irqs">
    <title><function>local_irq_save()</function>/<function>local_irq_restore()</function>
-    <filename class="headerfile">include/asm/system.h</filename>
+    <filename class="headerfile">include/linux/irqflags.h</filename>
    </title>
 
    <para>
@@ -850,16 +850,6 @@ printk(KERN_INFO "my ip: %pI4\n", &amp;ipaddress);
     <returnvalue>-ERESTARTSYS</returnvalue> if a signal is received.
     The <function>wait_event()</function> version ignores signals.
    </para>
-   <para>
-   Do not use the <function>sleep_on()</function> function family -
-   it is very easy to accidentally introduce races; almost certainly
-   one of the <function>wait_event()</function> family will do, or a
-   loop around <function>schedule_timeout()</function>. If you choose
-   to loop around <function>schedule_timeout()</function> remember
-   you must set the task state (with 
-   <function>set_current_state()</function>) on each iteration to avoid
-   busy-looping.
-   </para>
  
   </sect1>
 
index a9691cc..beb754e 100644 (file)
@@ -111,8 +111,14 @@ Before jumping into the kernel, the following conditions must be met:
 - Caches, MMUs
   The MMU must be off.
   Instruction cache may be on or off.
-  Data cache must be off and invalidated.
-  External caches (if present) must be configured and disabled.
+  The address range corresponding to the loaded kernel image must be
+  cleaned to the PoC. In the presence of a system cache or other
+  coherent masters with caches enabled, this will typically require
+  cache maintenance by VA rather than set/way operations.
+  System caches which respect the architected cache maintenance by VA
+  operations must be configured and may be enabled.
+  System caches which do not respect architected cache maintenance by VA
+  operations (not recommended) must be configured and disabled.
 
 - Architected timers
   CNTFRQ must be programmed with the timer frequency and CNTVOFF must
index 85e24c4..d50fa61 100644 (file)
@@ -39,7 +39,7 @@ ffffffbffa000000      ffffffbffaffffff          16MB          PCI I/O space
 
 ffffffbffb000000       ffffffbffbbfffff          12MB          [guard]
 
-ffffffbffbc00000       ffffffbffbdfffff           2MB          earlyprintk device
+ffffffbffbc00000       ffffffbffbdfffff           2MB          fixed mappings
 
 ffffffbffbe00000       ffffffbffbffffff           2MB          [guard]
 
@@ -66,7 +66,7 @@ fffffdfffa000000      fffffdfffaffffff          16MB          PCI I/O space
 
 fffffdfffb000000       fffffdfffbbfffff          12MB          [guard]
 
-fffffdfffbc00000       fffffdfffbdfffff           2MB          earlyprintk device
+fffffdfffbc00000       fffffdfffbdfffff           2MB          fixed mappings
 
 fffffdfffbe00000       fffffdfffbffffff           2MB          [guard]
 
index 2eccddf..0595c3f 100644 (file)
@@ -21,7 +21,43 @@ Following shows a typical sequence of steps for using zram.
        This creates 4 devices: /dev/zram{0,1,2,3}
        (num_devices parameter is optional. Default: 1)
 
-2) Set Disksize
+2) Set max number of compression streams
+       Compression backend may use up to max_comp_streams compression streams,
+       thus allowing up to max_comp_streams concurrent compression operations.
+       By default, compression backend uses single compression stream.
+
+       Examples:
+       #show max compression streams number
+       cat /sys/block/zram0/max_comp_streams
+
+       #set max compression streams number to 3
+       echo 3 > /sys/block/zram0/max_comp_streams
+
+Note:
+In order to enable compression backend's multi stream support max_comp_streams
+must be initially set to desired concurrency level before ZRAM device
+initialisation. Once the device initialised as a single stream compression
+backend (max_comp_streams equals to 1), you will see error if you try to change
+the value of max_comp_streams because single stream compression backend
+implemented as a special case by lock overhead issue and does not support
+dynamic max_comp_streams. Only multi stream backend supports dynamic
+max_comp_streams adjustment.
+
+3) Select compression algorithm
+       Using comp_algorithm device attribute one can see available and
+       currently selected (shown in square brackets) compression algortithms,
+       change selected compression algorithm (once the device is initialised
+       there is no way to change compression algorithm).
+
+       Examples:
+       #show supported compression algorithms
+       cat /sys/block/zram0/comp_algorithm
+       lzo [lz4]
+
+       #select lzo compression algorithm
+       echo lzo > /sys/block/zram0/comp_algorithm
+
+4) Set Disksize
         Set disk size by writing the value to sysfs node 'disksize'.
         The value can be either in bytes or you can use mem suffixes.
         Examples:
@@ -33,32 +69,38 @@ Following shows a typical sequence of steps for using zram.
             echo 512M > /sys/block/zram0/disksize
             echo 1G > /sys/block/zram0/disksize
 
-3) Activate:
+Note:
+There is little point creating a zram of greater than twice the size of memory
+since we expect a 2:1 compression ratio. Note that zram uses about 0.1% of the
+size of the disk when not in use so a huge zram is wasteful.
+
+5) Activate:
        mkswap /dev/zram0
        swapon /dev/zram0
 
        mkfs.ext4 /dev/zram1
        mount /dev/zram1 /tmp
 
-4) Stats:
+6) Stats:
        Per-device statistics are exported as various nodes under
        /sys/block/zram<id>/
                disksize
                num_reads
                num_writes
+               failed_reads
+               failed_writes
                invalid_io
                notify_free
-               discard
                zero_pages
                orig_data_size
                compr_data_size
                mem_used_total
 
-5) Deactivate:
+7) Deactivate:
        swapoff /dev/zram0
        umount /dev/zram1
 
-6) Reset:
+8) Reset:
        Write any positive value to 'reset' sysfs node
        echo 1 > /sys/block/zram0/reset
        echo 1 > /sys/block/zram1/reset
index ce94a83..80ac454 100644 (file)
@@ -24,7 +24,7 @@ Please note that implementation details can be changed.
 
    a page/swp_entry may be charged (usage += PAGE_SIZE) at
 
-       mem_cgroup_newpage_charge()
+       mem_cgroup_charge_anon()
          Called at new page fault and Copy-On-Write.
 
        mem_cgroup_try_charge_swapin()
@@ -32,7 +32,7 @@ Please note that implementation details can be changed.
          Followed by charge-commit-cancel protocol. (With swap accounting)
          At commit, a charge recorded in swap_cgroup is removed.
 
-       mem_cgroup_cache_charge()
+       mem_cgroup_charge_file()
          Called at add_to_page_cache()
 
        mem_cgroup_cache_charge_swapin()
index 5108afb..762ca54 100644 (file)
@@ -76,15 +76,7 @@ to work with it.
        limit_fail_at parameter is set to the particular res_counter element
        where the charging failed.
 
- d. int res_counter_charge_locked
-                       (struct res_counter *rc, unsigned long val, bool force)
-
-       The same as res_counter_charge(), but it must not acquire/release the
-       res_counter->lock internally (it must be called with res_counter->lock
-       held). The force parameter indicates whether we can bypass the limit.
-
- e. u64 res_counter_uncharge[_locked]
-                       (struct res_counter *rc, unsigned long val)
+ d. u64 res_counter_uncharge(struct res_counter *rc, unsigned long val)
 
        When a resource is released (freed) it should be de-accounted
        from the resource counter it was accounted to.  This is called
@@ -93,7 +85,7 @@ to work with it.
 
        The _locked routines imply that the res_counter->lock is taken.
 
f. u64 res_counter_uncharge_until
e. u64 res_counter_uncharge_until
                (struct res_counter *rc, struct res_counter *top,
                 unsigned long val)
 
index be675d2..a0b005d 100644 (file)
@@ -312,12 +312,57 @@ things will happen if a notifier in path sent a BAD notify code.
 Q: I don't see my action being called for all CPUs already up and running?
 A: Yes, CPU notifiers are called only when new CPUs are on-lined or offlined.
    If you need to perform some action for each cpu already in the system, then
+   do this:
 
        for_each_online_cpu(i) {
                foobar_cpu_callback(&foobar_cpu_notifier, CPU_UP_PREPARE, i);
                foobar_cpu_callback(&foobar_cpu_notifier, CPU_ONLINE, i);
        }
 
+   However, if you want to register a hotplug callback, as well as perform
+   some initialization for CPUs that are already online, then do this:
+
+   Version 1: (Correct)
+   ---------
+
+       cpu_notifier_register_begin();
+
+               for_each_online_cpu(i) {
+                       foobar_cpu_callback(&foobar_cpu_notifier,
+                                           CPU_UP_PREPARE, i);
+                       foobar_cpu_callback(&foobar_cpu_notifier,
+                                           CPU_ONLINE, i);
+               }
+
+       /* Note the use of the double underscored version of the API */
+       __register_cpu_notifier(&foobar_cpu_notifier);
+
+       cpu_notifier_register_done();
+
+   Note that the following code is *NOT* the right way to achieve this,
+   because it is prone to an ABBA deadlock between the cpu_add_remove_lock
+   and the cpu_hotplug.lock.
+
+   Version 2: (Wrong!)
+   ---------
+
+       get_online_cpus();
+
+               for_each_online_cpu(i) {
+                       foobar_cpu_callback(&foobar_cpu_notifier,
+                                           CPU_UP_PREPARE, i);
+                       foobar_cpu_callback(&foobar_cpu_notifier,
+                                           CPU_ONLINE, i);
+               }
+
+       register_cpu_notifier(&foobar_cpu_notifier);
+
+       put_online_cpus();
+
+    So always use the first version shown above when you want to register
+    callbacks as well as initialize the already online CPUs.
+
+
 Q: If i would like to develop cpu hotplug support for a new architecture,
    what do i need at a minimum?
 A: The following are what is required for CPU hotplug infrastructure to work
index 4aa20e7..1061faf 100644 (file)
@@ -75,9 +75,10 @@ The cpu-map node can only contain three types of child nodes:
 
 whose bindings are described in paragraph 3.
 
-The nodes describing the CPU topology (cluster/core/thread) can only be
-defined within the cpu-map node.
-Any other configuration is consider invalid and therefore must be ignored.
+The nodes describing the CPU topology (cluster/core/thread) can only
+be defined within the cpu-map node and every core/thread in the system
+must be defined within the topology.  Any other configuration is
+invalid and therefore must be ignored.
 
 ===========================================
 2.1 - cpu-map child nodes naming convention
diff --git a/Documentation/devicetree/bindings/dma/fsl-edma.txt b/Documentation/devicetree/bindings/dma/fsl-edma.txt
new file mode 100644 (file)
index 0000000..191d7bd
--- /dev/null
@@ -0,0 +1,76 @@
+* Freescale enhanced Direct Memory Access(eDMA) Controller
+
+  The eDMA channels have multiplex capability by programmble memory-mapped
+registers. channels are split into two groups, called DMAMUX0 and DMAMUX1,
+specific DMA request source can only be multiplexed by any channel of certain
+group, DMAMUX0 or DMAMUX1, but not both.
+
+* eDMA Controller
+Required properties:
+- compatible :
+       - "fsl,vf610-edma" for eDMA used similar to that on Vybrid vf610 SoC
+- reg : Specifies base physical address(s) and size of the eDMA registers.
+       The 1st region is eDMA control register's address and size.
+       The 2nd and the 3rd regions are programmable channel multiplexing
+       control register's address and size.
+- interrupts : A list of interrupt-specifiers, one for each entry in
+       interrupt-names.
+- interrupt-names : Should contain:
+       "edma-tx" - the transmission interrupt
+       "edma-err" - the error interrupt
+- #dma-cells : Must be <2>.
+       The 1st cell specifies the DMAMUX(0 for DMAMUX0 and 1 for DMAMUX1).
+       Specific request source can only be multiplexed by specific channels
+       group called DMAMUX.
+       The 2nd cell specifies the request source(slot) ID.
+       See the SoC's reference manual for all the supported request sources.
+- dma-channels : Number of channels supported by the controller
+- clock-names : A list of channel group clock names. Should contain:
+       "dmamux0" - clock name of mux0 group
+       "dmamux1" - clock name of mux1 group
+- clocks : A list of phandle and clock-specifier pairs, one for each entry in
+       clock-names.
+
+Optional properties:
+- big-endian: If present registers and hardware scatter/gather descriptors
+       of the eDMA are implemented in big endian mode, otherwise in little
+       mode.
+
+
+Examples:
+
+edma0: dma-controller@40018000 {
+       #dma-cells = <2>;
+       compatible = "fsl,vf610-edma";
+       reg = <0x40018000 0x2000>,
+               <0x40024000 0x1000>,
+               <0x40025000 0x1000>;
+       interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
+               <0 9 IRQ_TYPE_LEVEL_HIGH>;
+       interrupt-names = "edma-tx", "edma-err";
+       dma-channels = <32>;
+       clock-names = "dmamux0", "dmamux1";
+       clocks = <&clks VF610_CLK_DMAMUX0>,
+               <&clks VF610_CLK_DMAMUX1>;
+};
+
+
+* DMA clients
+DMA client drivers that uses the DMA function must use the format described
+in the dma.txt file, using a two-cell specifier for each channel: the 1st
+specifies the channel group(DMAMUX) in which this request can be multiplexed,
+and the 2nd specifies the request source.
+
+Examples:
+
+sai2: sai@40031000 {
+       compatible = "fsl,vf610-sai";
+       reg = <0x40031000 0x1000>;
+       interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>;
+       clock-names = "sai";
+       clocks = <&clks VF610_CLK_SAI2>;
+       dma-names = "tx", "rx";
+       dmas = <&edma0 0 21>,
+               <&edma0 0 20>;
+       status = "disabled";
+};
diff --git a/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt b/Documentation/devicetree/bindings/dma/qcom_bam_dma.txt
new file mode 100644 (file)
index 0000000..d75a9d7
--- /dev/null
@@ -0,0 +1,41 @@
+QCOM BAM DMA controller
+
+Required properties:
+- compatible: must contain "qcom,bam-v1.4.0" for MSM8974
+- reg: Address range for DMA registers
+- interrupts: Should contain the one interrupt shared by all channels
+- #dma-cells: must be <1>, the cell in the dmas property of the client device
+  represents the channel number
+- clocks: required clock
+- clock-names: must contain "bam_clk" entry
+- qcom,ee : indicates the active Execution Environment identifier (0-7) used in
+  the secure world.
+
+Example:
+
+       uart-bam: dma@f9984000 = {
+               compatible = "qcom,bam-v1.4.0";
+               reg = <0xf9984000 0x15000>;
+               interrupts = <0 94 0>;
+               clocks = <&gcc GCC_BAM_DMA_AHB_CLK>;
+               clock-names = "bam_clk";
+               #dma-cells = <1>;
+               qcom,ee = <0>;
+       };
+
+DMA clients must use the format described in the dma.txt file, using a two cell
+specifier for each channel.
+
+Example:
+       serial@f991e000 {
+               compatible = "qcom,msm-uart";
+               reg = <0xf991e000 0x1000>
+                       <0xf9944000 0x19000>;
+               interrupts = <0 108 0>;
+               clocks = <&gcc GCC_BLSP1_UART2_APPS_CLK>,
+                       <&gcc GCC_BLSP1_AHB_CLK>;
+               clock-names = "core", "iface";
+
+               dmas = <&uart-bam 0>, <&uart-bam 1>;
+               dma-names = "rx", "tx";
+       };
diff --git a/Documentation/devicetree/bindings/dma/sirfsoc-dma.txt b/Documentation/devicetree/bindings/dma/sirfsoc-dma.txt
new file mode 100644 (file)
index 0000000..ecbc96a
--- /dev/null
@@ -0,0 +1,43 @@
+* CSR SiRFSoC DMA controller
+
+See dma.txt first
+
+Required properties:
+- compatible: Should be "sirf,prima2-dmac" or "sirf,marco-dmac"
+- reg: Should contain DMA registers location and length.
+- interrupts: Should contain one interrupt shared by all channel
+- #dma-cells: must be <1>. used to represent the number of integer
+    cells in the dmas property of client device.
+- clocks: clock required
+
+Example:
+
+Controller:
+dmac0: dma-controller@b00b0000 {
+       compatible = "sirf,prima2-dmac";
+       reg = <0xb00b0000 0x10000>;
+       interrupts = <12>;
+       clocks = <&clks 24>;
+       #dma-cells = <1>;
+};
+
+
+Client:
+Fill the specific dma request line in dmas. In the below example, spi0 read
+channel request line is 9 of the 2nd dma controller, while write channel uses
+4 of the 2nd dma controller; spi1 read channel request line is 12 of the 1st
+dma controller, while write channel uses 13 of the 1st dma controller:
+
+spi0: spi@b00d0000 {
+       compatible = "sirf,prima2-spi";
+       dmas = <&dmac1 9>,
+               <&dmac1 4>;
+       dma-names = "rx", "tx";
+};
+
+spi1: spi@b0170000 {
+       compatible = "sirf,prima2-spi";
+       dmas = <&dmac0 12>,
+               <&dmac0 13>;
+       dma-names = "rx", "tx";
+};
diff --git a/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt b/Documentation/devicetree/bindings/drm/bridge/ptn3460.txt
new file mode 100644 (file)
index 0000000..52b93b2
--- /dev/null
@@ -0,0 +1,27 @@
+ptn3460 bridge bindings
+
+Required properties:
+       - compatible: "nxp,ptn3460"
+       - reg: i2c address of the bridge
+       - powerdown-gpio: OF device-tree gpio specification
+       - reset-gpio: OF device-tree gpio specification
+       - edid-emulation: The EDID emulation entry to use
+               +-------+------------+------------------+
+               | Value | Resolution | Description      |
+               |   0   |  1024x768  | NXP Generic      |
+               |   1   |  1920x1080 | NXP Generic      |
+               |   2   |  1920x1080 | NXP Generic      |
+               |   3   |  1600x900  | Samsung LTM200KT |
+               |   4   |  1920x1080 | Samsung LTM230HT |
+               |   5   |  1366x768  | NXP Generic      |
+               |   6   |  1600x900  | ChiMei M215HGE   |
+               +-------+------------+------------------+
+
+Example:
+       lvds-bridge@20 {
+               compatible = "nxp,ptn3460";
+               reg = <0x20>;
+               powerdown-gpio = <&gpy2 5 1 0 0>;
+               reset-gpio = <&gpx1 5 1 0 0>;
+               edid-emulation = <5>;
+       };
diff --git a/Documentation/devicetree/bindings/drm/i2c/tda998x.txt b/Documentation/devicetree/bindings/drm/i2c/tda998x.txt
new file mode 100644 (file)
index 0000000..d7df01c
--- /dev/null
@@ -0,0 +1,27 @@
+Device-Tree bindings for the NXP TDA998x HDMI transmitter
+
+Required properties;
+  - compatible: must be "nxp,tda998x"
+
+Optional properties:
+  - interrupts: interrupt number and trigger type
+       default: polling
+
+  - pinctrl-0: pin control group to be used for
+       screen plug/unplug interrupt.
+
+  - pinctrl-names: must contain a "default" entry.
+
+  - video-ports: 24 bits value which defines how the video controller
+       output is wired to the TDA998x input - default: <0x230145>
+
+Example:
+
+       tda998x: hdmi-encoder {
+               compatible = "nxp,tda998x";
+               reg = <0x70>;
+               interrupt-parent = <&gpio0>;
+               interrupts = <27 2>;            /* falling edge */
+               pinctrl-0 = <&pmx_camera>;
+               pinctrl-names = "default";
+       };
index efaeec8..efa8b84 100644 (file)
@@ -190,6 +190,48 @@ of the following host1x client modules:
   - nvidia,edid: supplies a binary EDID blob
   - nvidia,panel: phandle of a display panel
 
+- sor: serial output resource
+
+  Required properties:
+  - compatible: "nvidia,tegra124-sor"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain an entry for each entry in clock-names.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: Must include the following entries:
+    - sor: clock input for the SOR hardware
+    - parent: input for the pixel clock
+    - dp: reference clock for the SOR clock
+    - safe: safe reference for the SOR clock during power up
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - sor
+
+  Optional properties:
+  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
+  - nvidia,edid: supplies a binary EDID blob
+  - nvidia,panel: phandle of a display panel
+
+  Optional properties when driving an eDP output:
+  - nvidia,dpaux: phandle to a DispayPort AUX interface
+
+- dpaux: DisplayPort AUX interface
+  - compatible: "nvidia,tegra124-dpaux"
+  - reg: Physical base address and length of the controller's registers.
+  - interrupts: The interrupt outputs from the controller.
+  - clocks: Must contain an entry for each entry in clock-names.
+    See ../clocks/clock-bindings.txt for details.
+  - clock-names: Must include the following entries:
+    - dpaux: clock input for the DPAUX hardware
+    - parent: reference clock
+  - resets: Must contain an entry for each entry in reset-names.
+    See ../reset/reset.txt for details.
+  - reset-names: Must include the following entries:
+    - dpaux
+  - vdd-supply: phandle of a supply that powers the DisplayPort link
+
 Example:
 
 / {
index 4fade84..388f0a2 100644 (file)
@@ -12,6 +12,7 @@ Required properties :
 - clocks: phandles to input clocks.
 
 Optional properties:
+- clock-frequency: Desired I2C bus frequency in Hz, otherwise defaults to 100000
 - Child nodes conforming to i2c bus binding
 
 Examples :
@@ -23,6 +24,7 @@ i2c0: i2c@fff84000 {
        #address-cells = <1>;
        #size-cells = <0>;
        clocks = <&twi0_clk>;
+       clock-frequency = <400000>;
 
        24c512@50 {
                compatible = "24c512";
diff --git a/Documentation/devicetree/bindings/i2c/i2c-cadence.txt b/Documentation/devicetree/bindings/i2c/i2c-cadence.txt
new file mode 100644 (file)
index 0000000..7cb0b56
--- /dev/null
@@ -0,0 +1,24 @@
+Binding for the Cadence I2C controller
+
+Required properties:
+  - reg: Physical base address and size of the controller's register area.
+  - compatible: Compatibility string. Must be 'cdns,i2c-r1p10'.
+  - clocks: Input clock specifier. Refer to common clock bindings.
+  - interrupts: Interrupt specifier. Refer to interrupt bindings.
+  - #address-cells: Should be 1.
+  - #size-cells: Should be 0.
+
+Optional properties:
+  - clock-frequency: Desired operating frequency, in Hz, of the bus.
+  - clock-names: Input clock name, should be 'pclk'.
+
+Example:
+       i2c@e0004000 {
+               compatible = "cdns,i2c-r1p10";
+               clocks = <&clkc 38>;
+               interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+               reg = <0xe0004000 0x1000>;
+               clock-frequency = <400000>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
index 7fd7fa2..5199b0c 100644 (file)
@@ -14,6 +14,12 @@ Optional properties :
  - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds.
    This option is only supported in hardware blocks version 1.11a or newer.
 
+ - i2c-scl-falling-time : should contain the SCL falling time in nanoseconds.
+   This value which is by default 300ns is used to compute the tLOW period.
+
+ - i2c-sda-falling-time : should contain the SDA falling time in nanoseconds.
+   This value which is by default 300ns is used to compute the tHIGH period.
+
 Example :
 
        i2c@f0000 {
@@ -34,4 +40,6 @@ Example :
                interrupts = <12 1>;
                clock-frequency = <400000>;
                i2c-sda-hold-time-ns = <300>;
+               i2c-sda-falling-time-ns = <300>;
+               i2c-scl-falling-time-ns = <300>;
        };
diff --git a/Documentation/devicetree/bindings/i2c/i2c-efm32.txt b/Documentation/devicetree/bindings/i2c/i2c-efm32.txt
new file mode 100644 (file)
index 0000000..fc15ac5
--- /dev/null
@@ -0,0 +1,34 @@
+* Energymicro efm32 i2c controller
+
+Required properties :
+
+ - reg : Offset and length of the register set for the device
+ - compatible : should be "energymicro,efm32-i2c"
+ - interrupts : the interrupt number
+ - clocks : reference to the module clock
+
+Recommended properties :
+
+ - clock-frequency : maximal I2C bus clock frequency in Hz.
+ - efm32,location : Decides the location of the USART I/O pins.
+   Allowed range : [0 .. 6]
+
+Example:
+       i2c0: i2c@4000a000 {
+               #address-cells = <1>;
+               #size-cells = <0>;
+               compatible = "energymicro,efm32-i2c";
+               reg = <0x4000a000 0x400>;
+               interrupts = <9>;
+               clocks = <&cmu clk_HFPERCLKI2C0>;
+               clock-frequency = <100000>;
+               status = "ok";
+               efm32,location = <3>;
+
+               eeprom@50 {
+                       compatible = "microchip,24c02";
+                       reg = <0x50>;
+                       pagesize = <16>;
+               };
+       };
+
index 582b465..befd4fb 100644 (file)
@@ -4,12 +4,16 @@
 Required properties :
 
  - reg             : Offset and length of the register set for the device
- - compatible      : Should be "marvell,mv64xxx-i2c" or "allwinner,sun4i-i2c"
-                     or "marvell,mv78230-i2c" or "marvell,mv78230-a0-i2c"
-                     Note: Only use "marvell,mv78230-a0-i2c" for a very rare,
-                     initial version of the SoC which had broken offload
-                     support.  Linux auto-detects this and sets it
-                     appropriately.
+ - compatible      : Should be either:
+                     - "allwinner,sun4i-i2c"
+                     - "allwinner,sun6i-a31-i2c"
+                     - "marvell,mv64xxx-i2c"
+                     - "marvell,mv78230-i2c"
+                     - "marvell,mv78230-a0-i2c"
+                       * Note: Only use "marvell,mv78230-a0-i2c" for a
+                         very rare, initial version of the SoC which
+                         had broken offload support.  Linux
+                         auto-detects this and sets it appropriately.
  - interrupts      : The interrupt number
 
 Optional properties :
@@ -17,6 +21,10 @@ Optional properties :
  - clock-frequency : Desired I2C bus clock frequency in Hz. If not set the
 default frequency is 100kHz
 
+ - resets          : phandle to the parent reset controller. Mandatory
+                     whenever you're using the "allwinner,sun6i-a31-i2c"
+                     compatible.
+
 Examples:
 
        i2c@11000 {
index 897cfcd..dd8b2dd 100644 (file)
@@ -6,6 +6,7 @@ Required properties:
        "renesas,i2c-r8a7778"
        "renesas,i2c-r8a7779"
        "renesas,i2c-r8a7790"
+       "renesas,i2c-r8a7791"
 - reg: physical base address of the controller and length of memory mapped
   region.
 - interrupts: interrupt specifier.
@@ -13,11 +14,16 @@ Required properties:
 Optional properties:
 - clock-frequency: desired I2C bus clock frequency in Hz. The absence of this
   propoerty indicates the default frequency 100 kHz.
+- clocks: clock specifier.
 
 Examples :
 
-i2c0: i2c@e6500000 {
-       compatible = "renesas,i2c-rcar-h2";
-       reg = <0 0xe6500000 0 0x428>;
-       interrupts = <0 174 0x4>;
+i2c0: i2c@e6508000 {
+       #address-cells = <1>;
+       #size-cells = <0>;
+       compatible = "renesas,i2c-r8a7791";
+       reg = <0 0xe6508000 0 0x40>;
+       interrupts = <0 287 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&mstp9_clks R8A7791_CLK_I2C0>;
+       clock-frequency = <400000>;
 };
diff --git a/Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt b/Documentation/devicetree/bindings/i2c/qcom,i2c-qup.txt
new file mode 100644 (file)
index 0000000..dc71754
--- /dev/null
@@ -0,0 +1,40 @@
+Qualcomm Universal Peripheral (QUP) I2C controller
+
+Required properties:
+ - compatible: Should be:
+   * "qcom,i2c-qup-v1.1.1" for 8660, 8960 and 8064.
+   * "qcom,i2c-qup-v2.1.1" for 8974 v1.
+   * "qcom,i2c-qup-v2.2.1" for 8974 v2 and later.
+ - reg: Should contain QUP register address and length.
+ - interrupts: Should contain I2C interrupt.
+
+ - clocks: A list of phandles + clock-specifiers, one for each entry in
+   clock-names.
+ - clock-names: Should contain:
+   * "core" for the core clock
+   * "iface" for the AHB clock
+
+ - #address-cells: Should be <1> Address cells for i2c device address
+ - #size-cells: Should be <0> as i2c addresses have no size component
+
+Optional properties:
+ - clock-frequency: Should specify the desired i2c bus clock frequency in Hz,
+                    defaults to 100kHz if omitted.
+
+Child nodes should conform to i2c bus binding.
+
+Example:
+
+ i2c@f9924000 {
+       compatible = "qcom,i2c-qup-v2.2.1";
+       reg = <0xf9924000 0x1000>;
+       interrupts = <0 96 0>;
+
+       clocks = <&gcc GCC_BLSP1_QUP2_I2C_APPS_CLK>, <&gcc GCC_BLSP1_AHB_CLK>;
+       clock-names = "core", "iface";
+
+       clock-frequency = <355000>;
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt b/Documentation/devicetree/bindings/iio/adc/twl4030-madc.txt
new file mode 100644 (file)
index 0000000..6bdd214
--- /dev/null
@@ -0,0 +1,24 @@
+* TWL4030 Monitoring Analog to Digital Converter (MADC)
+
+The MADC subsystem in the TWL4030 consists of a 10-bit ADC
+combined with a 16-input analog multiplexer.
+
+Required properties:
+  - compatible: Should contain "ti,twl4030-madc".
+  - interrupts: IRQ line for the MADC submodule.
+  - #io-channel-cells: Should be set to <1>.
+
+Optional properties:
+  - ti,system-uses-second-madc-irq: boolean, set if the second madc irq register
+                                   should be used, which is intended to be used
+                                   by Co-Processors (e.g. a modem).
+
+Example:
+
+&twl {
+       madc {
+               compatible = "ti,twl4030-madc";
+               interrupts = <3>;
+               #io-channel-cells = <1>;
+       };
+};
index df1b308..f77148f 100644 (file)
@@ -21,6 +21,8 @@ LED sub-node properties:
   on).  The "keep" setting will keep the LED at whatever its current
   state is, without producing a glitch.  The default is off if this
   property is not present.
+- retain-state-suspended: (optional) The suspend state can be retained.Such
+  as charge-led gpio.
 
 Examples:
 
@@ -50,3 +52,13 @@ run-control {
                default-state = "on";
        };
 };
+
+leds {
+       compatible = "gpio-leds";
+
+       charger-led {
+               gpios = <&gpio1 2 0>;
+               linux,default-trigger = "max8903-charger-charging";
+               retain-state-suspended;
+       };
+};
index 0e295c9..36a0c3d 100644 (file)
@@ -5,9 +5,10 @@ of analogue I/O.
 
 Required properties:
 
-  - compatible : one of the following chip-specific strings:
-       "wlf,wm5102"
-       "wlf,wm5110"
+  - compatible : One of the following chip-specific strings:
+        "wlf,wm5102"
+        "wlf,wm5110"
+        "wlf,wm8997"
   - reg : I2C slave address when connected using I2C, chip select number when
     using SPI.
 
@@ -25,8 +26,9 @@ Required properties:
   - #gpio-cells : Must be 2. The first cell is the pin number and the
     second cell is used to specify optional parameters (currently unused).
 
-  - AVDD1-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply, CPVDD-supply,
-    SPKVDDL-supply, SPKVDDR-supply : power supplies for the device, as covered
+  - AVDD-supply, DBVDD1-supply, DBVDD2-supply, DBVDD3-supply (wm5102, wm5110),
+    CPVDD-supply, SPKVDDL-supply (wm5102, wm5110), SPKVDDR-supply (wm5102,
+    wm5110), SPKVDD-supply (wm8997) : Power supplies for the device, as covered
     in Documentation/devicetree/bindings/regulator/regulator.txt
 
 Optional properties:
@@ -46,6 +48,7 @@ codec: wm5102@1a {
        compatible = "wlf,wm5102";
        reg = <0x1a>;
        interrupts = <347>;
+       interrupt-controller;
        #interrupt-cells = <2>;
         interrupt-parent = <&gic>;
 
@@ -53,10 +56,10 @@ codec: wm5102@1a {
        #gpio-cells = <2>;
 
        wlf,gpio-defaults = <
-               0x00000000, /* AIF1TXLRCLK */
-               0xffffffff,
-               0xffffffff,
-               0xffffffff,
-               0xffffffff,
+               0x00000000 /* AIF1TXLRCLK */
+               0xffffffff
+               0xffffffff
+               0xffffffff
+               0xffffffff
        >;
 };
diff --git a/Documentation/devicetree/bindings/mfd/bcm590xx.txt b/Documentation/devicetree/bindings/mfd/bcm590xx.txt
new file mode 100644 (file)
index 0000000..1fe30e2
--- /dev/null
@@ -0,0 +1,37 @@
+-------------------------------
+BCM590xx Power Management Units
+-------------------------------
+
+Required properties:
+- compatible: "brcm,bcm59056"
+- reg: I2C slave address
+- interrupts: interrupt for the PMU. Generic interrupt client node bindings
+  are described in interrupt-controller/interrupts.txt
+
+------------------
+Voltage Regulators
+------------------
+
+Optional child nodes:
+- regulators: container node for regulators following the generic
+  regulator binding in regulator/regulator.txt
+
+  The valid regulator node names for BCM59056 are:
+       rfldo, camldo1, camldo2, simldo1, simldo2, sdldo, sdxldo,
+       mmcldo1, mmcldo2, audldo, micldo, usbldo, vibldo,
+       csr, iosr1, iosr2, msr, sdsr1, sdsr2, vsr
+
+Example:
+       pmu: bcm59056@8 {
+               compatible = "brcm,bcm59056";
+               reg = <0x08>;
+               interrupts = <GIC_SPI 215 IRQ_TYPE_LEVEL_HIGH>;
+               regulators {
+                       rfldo_reg: rfldo {
+                               regulator-min-microvolt = <1200000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+
+                       ...
+               };
+       };
diff --git a/Documentation/devicetree/bindings/mfd/da9055.txt b/Documentation/devicetree/bindings/mfd/da9055.txt
new file mode 100644 (file)
index 0000000..6dab34d
--- /dev/null
@@ -0,0 +1,72 @@
+* Dialog DA9055 Power Management Integrated Circuit (PMIC)
+
+DA9055 consists of a large and varied group of sub-devices (I2C Only):
+
+Device                  Supply Names    Description
+------                  ------------    -----------
+da9055-gpio            :               : GPIOs
+da9055-regulator       :               : Regulators
+da9055-onkey           :               : On key
+da9055-rtc             :               : RTC
+da9055-hwmon           :               : ADC
+da9055-watchdog                :               : Watchdog
+
+The CODEC device in DA9055 has a separate, configurable I2C address and so
+is instantiated separately from the PMIC.
+
+For details on accompanying CODEC I2C device, see the following:
+Documentation/devicetree/bindings/sound/da9055.txt
+
+======
+
+Required properties:
+- compatible : Should be "dlg,da9055-pmic"
+- reg: Specifies the I2C slave address (defaults to 0x5a but can be modified)
+- interrupt-parent: Specifies the phandle of the interrupt controller to which
+  the IRQs from da9055 are delivered to.
+- interrupts: IRQ line info for da9055 chip.
+- interrupt-controller: da9055 has internal IRQs (has own IRQ domain).
+- #interrupt-cells: Should be 1, is the local IRQ number for da9055.
+
+Sub-nodes:
+- regulators : Contain the regulator nodes. The DA9055 regulators are
+  bound using their names as listed below:
+
+    buck1     : regulator BUCK1
+    buck2     : regulator BUCK2
+    ldo1      : regulator LDO1
+    ldo2      : regulator LDO2
+    ldo3      : regulator LDO3
+    ldo4      : regulator LDO4
+    ldo5      : regulator LDO5
+    ldo6      : regulator LDO6
+
+  The bindings details of individual regulator device can be found in:
+  Documentation/devicetree/bindings/regulator/regulator.txt
+
+
+Example:
+
+       pmic: da9055-pmic@5a {
+               compatible = "dlg,da9055-pmic";
+               reg = <0x5a>;
+               interrupt-parent = <&intc>;
+               interrupts = <5 IRQ_TYPE_LEVEL_LOW>;
+               interrupt-controller;
+               #interrupt-cells = <1>;
+
+               regulators {
+                       buck1: BUCK1 {
+                               regulator-min-microvolt = <725000>;
+                               regulator-max-microvolt = <2075000>;
+                       };
+                       buck2: BUCK2 {
+                               regulator-min-microvolt = <925000>;
+                               regulator-max-microvolt = <2500000>;
+                       };
+                       ldo1: LDO1 {
+                               regulator-min-microvolt = <900000>;
+                               regulator-max-microvolt = <3300000>;
+                       };
+               };
+       };
index abd9e3c..1413f39 100644 (file)
@@ -10,9 +10,44 @@ Optional properties:
 - fsl,mc13xxx-uses-touch : Indicate the touchscreen controller is being used
 
 Sub-nodes:
+- leds : Contain the led nodes and initial register values in property
+  "led-control". Number of register depends of used IC, for MC13783 is 6,
+  for MC13892 is 4, for MC34708 is 1. See datasheet for bits definitions of
+  these registers.
+  - #address-cells: Must be 1.
+  - #size-cells: Must be 0.
+  Each led node should contain "reg", which used as LED ID (described below).
+  Optional properties "label" and "linux,default-trigger" is described in
+  Documentation/devicetree/bindings/leds/common.txt.
 - regulators : Contain the regulator nodes. The regulators are bound using
   their names as listed below with their registers and bits for enabling.
 
+MC13783 LED IDs:
+    0  : Main display
+    1  : AUX display
+    2  : Keypad
+    3  : Red 1
+    4  : Green 1
+    5  : Blue 1
+    6  : Red 2
+    7  : Green 2
+    8  : Blue 2
+    9  : Red 3
+    10 : Green 3
+    11 : Blue 3
+
+MC13892 LED IDs:
+    0  : Main display
+    1  : AUX display
+    2  : Keypad
+    3  : Red
+    4  : Green
+    5  : Blue
+
+MC34708 LED IDs:
+    0  : Charger Red
+    1  : Charger Green
+
 MC13783 regulators:
     sw1a      : regulator SW1A      (register 24, bit 0)
     sw1b      : regulator SW1B      (register 25, bit 0)
@@ -89,6 +124,18 @@ ecspi@70010000 { /* ECSPI1 */
                interrupt-parent = <&gpio0>;
                interrupts = <8>;
 
+               leds {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+                       led-control = <0x000 0x000 0x0e0 0x000>;
+
+                       sysled {
+                               reg = <3>;
+                               label = "system:red:live";
+                               linux,default-trigger = "heartbeat";
+                       };
+               };
+
                regulators {
                        sw1_reg: mc13892__sw1 {
                                regulator-min-microvolt = <600000>;
index b381fa6..4721b2d 100644 (file)
@@ -32,6 +32,29 @@ Optional properties:
 - single-ulpi-bypass: Must be present if the controller contains a single
   ULPI bypass control bit. e.g. OMAP3 silicon <= ES2.1
 
+- clocks: a list of phandles and clock-specifier pairs, one for each entry in
+  clock-names.
+
+- clock-names: should include:
+  For OMAP3
+  * "usbhost_120m_fck" - 120MHz Functional clock.
+
+  For OMAP4+
+  * "refclk_60m_int" - 60MHz internal reference clock for UTMI clock mux
+  * "refclk_60m_ext_p1" - 60MHz external ref. clock for Port 1's UTMI clock mux.
+  * "refclk_60m_ext_p2" - 60MHz external ref. clock for Port 2's UTMI clock mux
+  * "utmi_p1_gfclk" - Port 1 UTMI clock mux.
+  * "utmi_p2_gfclk" - Port 2 UTMI clock mux.
+  * "usb_host_hs_utmi_p1_clk" - Port 1 UTMI clock gate.
+  * "usb_host_hs_utmi_p2_clk" - Port 2 UTMI clock gate.
+  * "usb_host_hs_utmi_p3_clk" - Port 3 UTMI clock gate.
+  * "usb_host_hs_hsic480m_p1_clk" - Port 1 480MHz HSIC clock gate.
+  * "usb_host_hs_hsic480m_p2_clk" - Port 2 480MHz HSIC clock gate.
+  * "usb_host_hs_hsic480m_p3_clk" - Port 3 480MHz HSIC clock gate.
+  * "usb_host_hs_hsic60m_p1_clk" - Port 1 60MHz HSIC clock gate.
+  * "usb_host_hs_hsic60m_p2_clk" - Port 2 60MHz HSIC clock gate.
+  * "usb_host_hs_hsic60m_p3_clk" - Port 3 60MHz HSIC clock gate.
+
 Required properties if child node exists:
 
 - #address-cells: Must be 1
index 62fe697..c58d704 100644 (file)
@@ -7,6 +7,16 @@ Required properties:
 - interrupts : should contain the TLL module's interrupt
 - ti,hwmod : must contain "usb_tll_hs"
 
+Optional properties:
+
+- clocks: a list of phandles and clock-specifier pairs, one for each entry in
+  clock-names.
+
+- clock-names: should include:
+  * "usb_tll_hs_usb_ch0_clk" - USB TLL channel 0 clock
+  * "usb_tll_hs_usb_ch1_clk" - USB TLL channel 1 clock
+  * "usb_tll_hs_usb_ch2_clk" - USB TLL channel 2 clock
+
 Example:
 
        usbhstll: usbhstll@4a062000 {
diff --git a/Documentation/devicetree/bindings/mfd/qcom,pm8xxx.txt b/Documentation/devicetree/bindings/mfd/qcom,pm8xxx.txt
new file mode 100644 (file)
index 0000000..03518dc
--- /dev/null
@@ -0,0 +1,96 @@
+Qualcomm PM8xxx PMIC multi-function devices
+
+The PM8xxx family of Power Management ICs are used to provide regulated
+voltages and other various functionality to Qualcomm SoCs.
+
+= PROPERTIES
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be one of:
+                   "qcom,pm8058"
+                   "qcom,pm8921"
+
+- #address-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 1
+
+- #size-cells:
+       Usage: required
+       Value type: <u32>
+       Definition: must be 0
+
+- interrupts:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: specifies the interrupt that indicates a subdevice
+                   has generated an interrupt (summary interrupt). The
+                   format of the specifier is defined by the binding document
+                   describing the node's interrupt parent.
+
+- #interrupt-cells:
+       Usage: required
+       Value type : <u32>
+       Definition: must be 2. Specifies the number of cells needed to encode
+                   an interrupt source. The 1st cell contains the interrupt
+                   number. The 2nd cell is the trigger type and level flags
+                   encoded as follows:
+
+                       1 = low-to-high edge triggered
+                       2 = high-to-low edge triggered
+                       4 = active high level-sensitive
+                       8 = active low level-sensitive
+
+- interrupt-controller:
+       Usage: required
+       Value type: <empty>
+       Definition: identifies this node as an interrupt controller
+
+= SUBCOMPONENTS
+
+The PMIC contains multiple independent functions, each described in a subnode.
+The below bindings specify the set of valid subnodes.
+
+== Real-Time Clock
+
+- compatible:
+       Usage: required
+       Value type: <string>
+       Definition: must be one of:
+                   "qcom,pm8058-rtc"
+                   "qcom,pm8921-rtc"
+
+- reg:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: single entry specifying the base address of the RTC registers
+
+- interrupts:
+       Usage: required
+       Value type: <prop-encoded-array>
+       Definition: single entry specifying the RTC's alarm interrupt
+
+- allow-set-time:
+       Usage: optional
+       Value type: <empty>
+       Definition: indicates that the setting of RTC time is allowed by
+                   the host CPU
+
+= EXAMPLE
+
+       pmicintc: pmic@0 {
+               compatible = "qcom,pm8921";
+               interrupts = <104 8>;
+               #interrupt-cells = <2>;
+               interrupt-controller;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               rtc@11d {
+                       compatible = "qcom,pm8921-rtc";
+                       reg = <0x11d>;
+                       interrupts = <0x27 0>;
+               };
+       };
index f69bec2..802e839 100644 (file)
@@ -16,20 +16,25 @@ Optional properties:
 - interrupts: Interrupt specifiers for interrupt sources.
 
 Optional nodes:
-- clocks: s2mps11 provides three(AP/CP/BT) buffered 32.768 KHz outputs, so to
-  register these as clocks with common clock framework instantiate a sub-node
-  named "clocks". It uses the common clock binding documented in :
+- clocks: s2mps11 and s5m8767 provide three(AP/CP/BT) buffered 32.768 KHz
+  outputs, so to register these as clocks with common clock framework
+  instantiate a sub-node named "clocks". It uses the common clock binding
+  documented in :
   [Documentation/devicetree/bindings/clock/clock-bindings.txt]
+  The s2mps14 provides two (AP/BT) buffered 32.768 KHz outputs.
   - #clock-cells: should be 1.
 
   - The following is the list of clocks generated by the controller. Each clock
     is assigned an identifier and client nodes use this identifier to specify
     the clock which they consume.
-    Clock               ID
-    ----------------------
-    32KhzAP            0
-    32KhzCP            1
-    32KhzBT            2
+    Clock               ID           Devices
+    ----------------------------------------------------------
+    32KhzAP            0            S2MPS11, S2MPS14, S5M8767
+    32KhzCP            1            S2MPS11, S5M8767
+    32KhzBT            2            S2MPS11, S2MPS14, S5M8767
+
+  - compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps14-clk",
+               "samsung,s5m8767-clk"
 
 - regulators: The regulators of s2mps11 that have to be instantiated should be
 included in a sub-node named 'regulators'. Regulator nodes included in this
@@ -75,7 +80,8 @@ Example:
                compatible = "samsung,s2mps11-pmic";
                reg = <0x66>;
 
-               s2m_osc: clocks{
+               s2m_osc: clocks {
+                       compatible = "samsung,s2mps11-clk";
                        #clock-cells = 1;
                        clock-output-names = "xx", "yy", "zz";
                };
index 458b57f..9dce540 100644 (file)
@@ -26,9 +26,18 @@ Optional properties:
   this system, even if the controller claims it is.
 - cap-sd-highspeed: SD high-speed timing is supported
 - cap-mmc-highspeed: MMC high-speed timing is supported
+- sd-uhs-sdr12: SD UHS SDR12 speed is supported
+- sd-uhs-sdr25: SD UHS SDR25 speed is supported
+- sd-uhs-sdr50: SD UHS SDR50 speed is supported
+- sd-uhs-sdr104: SD UHS SDR104 speed is supported
+- sd-uhs-ddr50: SD UHS DDR50 speed is supported
 - cap-power-off-card: powering off the card is safe
 - cap-sdio-irq: enable SDIO IRQ signalling on this interface
 - full-pwr-cycle: full power cycle of the card is supported
+- mmc-highspeed-ddr-1_8v: eMMC high-speed DDR mode(1.8V I/O) is supported
+- mmc-highspeed-ddr-1_2v: eMMC high-speed DDR mode(1.2V I/O) is supported
+- mmc-hs200-1_8v: eMMC HS200 mode(1.8V I/O) is supported
+- mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 
 *NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
 polarity properties, we have to fix the meaning of the "normal" and "inverted"
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-msm.txt b/Documentation/devicetree/bindings/mmc/sdhci-msm.txt
new file mode 100644 (file)
index 0000000..81b33b5
--- /dev/null
@@ -0,0 +1,55 @@
+* Qualcomm SDHCI controller (sdhci-msm)
+
+This file documents differences between the core properties in mmc.txt
+and the properties used by the sdhci-msm driver.
+
+Required properties:
+- compatible: Should contain "qcom,sdhci-msm-v4".
+- reg: Base address and length of the register in the following order:
+       - Host controller register map (required)
+       - SD Core register map (required)
+- interrupts: Should contain an interrupt-specifiers for the interrupts:
+       - Host controller interrupt (required)
+- pinctrl-names: Should contain only one value - "default".
+- pinctrl-0: Should specify pin control groups used for this controller.
+- clocks: A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
+- clock-names: Should contain the following:
+       "iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required)
+       "core"  - SDC MMC clock (MCLK) (required)
+       "bus"   - SDCC bus voter clock (optional)
+
+Example:
+
+       sdhc_1: sdhci@f9824900 {
+               compatible = "qcom,sdhci-msm-v4";
+               reg = <0xf9824900 0x11c>, <0xf9824000 0x800>;
+               interrupts = <0 123 0>;
+               bus-width = <8>;
+               non-removable;
+
+               vmmc = <&pm8941_l20>;
+               vqmmc = <&pm8941_s3>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&sdc1_clk &sdc1_cmd &sdc1_data>;
+
+               clocks = <&gcc GCC_SDCC1_APPS_CLK>, <&gcc GCC_SDCC1_AHB_CLK>;
+               clock-names = "core", "iface";
+       };
+
+       sdhc_2: sdhci@f98a4900 {
+               compatible = "qcom,sdhci-msm-v4";
+               reg = <0xf98a4900 0x11c>, <0xf98a4000 0x800>;
+               interrupts = <0 125 0>;
+               bus-width = <4>;
+               cd-gpios = <&msmgpio 62 0x1>;
+
+               vmmc = <&pm8941_l21>;
+               vqmmc = <&pm8941_l13>;
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&sdc2_clk &sdc2_cmd &sdc2_data>;
+
+               clocks = <&gcc GCC_SDCC2_APPS_CLK>, <&gcc GCC_SDCC2_AHB_CLK>;
+               clock-names = "core", "iface";
+       };
index dbe98a3..86223c3 100644 (file)
@@ -4,7 +4,14 @@ This file documents differences between the core properties in mmc.txt
 and the properties used by the sdhci-pxav2 and sdhci-pxav3 drivers.
 
 Required properties:
-- compatible: Should be "mrvl,pxav2-mmc" or "mrvl,pxav3-mmc".
+- compatible: Should be "mrvl,pxav2-mmc", "mrvl,pxav3-mmc" or
+  "marvell,armada-380-sdhci".
+- reg:
+  * for "mrvl,pxav2-mmc" and "mrvl,pxav3-mmc", one register area for
+    the SDHCI registers.
+  * for "marvell,armada-380-sdhci", two register areas. The first one
+    for the SDHCI registers themselves, and the second one for the
+    AXI/Mbus bridge registers of the SDHCI unit.
 
 Optional properties:
 - mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
@@ -19,3 +26,11 @@ sdhci@d4280800 {
        non-removable;
        mrvl,clk-delay-cycles = <31>;
 };
+
+sdhci@d8000 {
+       compatible = "marvell,armada-380-sdhci";
+       reg = <0xd8000 0x1000>, <0xdc000 0x100>;
+       interrupts = <0 25 0x4>;
+       clocks = <&gateclk 17>;
+       mrvl,clk-delay-cycles = <0x1F>;
+};
index 8c8908a..ce80561 100644 (file)
@@ -10,6 +10,7 @@ Required properties:
 - compatible:
  Should be "ti,omap2-hsmmc", for OMAP2 controllers
  Should be "ti,omap3-hsmmc", for OMAP3 controllers
+ Should be "ti,omap3-pre-es3-hsmmc" for OMAP3 controllers pre ES3.0
  Should be "ti,omap4-hsmmc", for OMAP4 controllers
 - ti,hwmods: Must be "mmc<n>", n is controller instance starting 1
 
index 03855c8..b53f92e 100644 (file)
@@ -5,3 +5,17 @@
   "soft_bch".
 - nand-bus-width : 8 or 16 bus width if not present 8
 - nand-on-flash-bbt: boolean to enable on flash bbt option if not present false
+
+- nand-ecc-strength: integer representing the number of bits to correct
+                    per ECC step.
+
+- nand-ecc-step-size: integer representing the number of data bytes
+                     that are covered by a single ECC step.
+
+The ECC strength and ECC step size properties define the correction capability
+of a controller. Together, they say a controller can correct "{strength} bit
+errors per {size} bytes".
+
+The interpretation of these parameters is implementation-defined, so not all
+implementations must support all possible combinations. However, implementations
+are encouraged to further specify the value(s) they support.
diff --git a/Documentation/devicetree/bindings/mtd/st-fsm.txt b/Documentation/devicetree/bindings/mtd/st-fsm.txt
new file mode 100644 (file)
index 0000000..c248939
--- /dev/null
@@ -0,0 +1,26 @@
+* ST-Microelectronics SPI FSM Serial (NOR) Flash Controller
+
+Required properties:
+  - compatible : Should be "st,spi-fsm"
+  - reg        : Contains register's location and length.
+  - reg-names  : Should contain the reg names "spi-fsm"
+  - interrupts : The interrupt number
+  - pinctrl-0  : Standard Pinctrl phandle (see: pinctrl/pinctrl-bindings.txt)
+
+Optional properties:
+  - st,syscfg          : Phandle to boot-device system configuration registers
+  - st,boot-device-reg : Address of the aforementioned boot-device register(s)
+  - st,boot-device-spi : Expected boot-device value if booted via this device
+
+Example:
+       spifsm: spifsm@fe902000{
+               compatible         = "st,spi-fsm";
+               reg                =  <0xfe902000 0x1000>;
+               reg-names          = "spi-fsm";
+               pinctrl-0          = <&pinctrl_fsm>;
+               st,syscfg          = <&syscfg_rear>;
+               st,boot-device-reg = <0x958>;
+               st,boot-device-spi = <0x1a>;
+               status = "okay";
+       };
+
diff --git a/Documentation/devicetree/bindings/panel/lg,ld070wx3-sl01.txt b/Documentation/devicetree/bindings/panel/lg,ld070wx3-sl01.txt
new file mode 100644 (file)
index 0000000..5e649cb
--- /dev/null
@@ -0,0 +1,7 @@
+LG Corporation 7" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "lg,ld070wx3-sl01"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/lg,lh500wx1-sd03.txt b/Documentation/devicetree/bindings/panel/lg,lh500wx1-sd03.txt
new file mode 100644 (file)
index 0000000..a04fd2b
--- /dev/null
@@ -0,0 +1,7 @@
+LG Corporation 5" HD TFT LCD panel
+
+Required properties:
+- compatible: should be "lg,lh500wx1-sd03"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/lg,lp129qe.txt b/Documentation/devicetree/bindings/panel/lg,lp129qe.txt
new file mode 100644 (file)
index 0000000..9f262e0
--- /dev/null
@@ -0,0 +1,7 @@
+LG 12.9" (2560x1700 pixels) TFT LCD panel
+
+Required properties:
+- compatible: should be "lg,lp129qe"
+
+This binding is compatible with the simple-panel binding, which is specified
+in simple-panel.txt in this directory.
diff --git a/Documentation/devicetree/bindings/panel/samsung,ld9040.txt b/Documentation/devicetree/bindings/panel/samsung,ld9040.txt
new file mode 100644 (file)
index 0000000..07c36c3
--- /dev/null
@@ -0,0 +1,66 @@
+Samsung LD9040 AMOLED LCD parallel RGB panel with SPI control bus
+
+Required properties:
+  - compatible: "samsung,ld9040"
+  - reg: address of the panel on SPI bus
+  - vdd3-supply: core voltage supply
+  - vci-supply: voltage supply for analog circuits
+  - reset-gpios: a GPIO spec for the reset pin
+  - display-timings: timings for the connected panel according to [1]
+
+The panel must obey rules for SPI slave device specified in document [2].
+
+Optional properties:
+  - power-on-delay: delay after turning regulators on [ms]
+  - reset-delay: delay after reset sequence [ms]
+  - panel-width-mm: physical panel width [mm]
+  - panel-height-mm: physical panel height [mm]
+
+The device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in [3]. This
+node should describe panel's video bus.
+
+[1]: Documentation/devicetree/bindings/video/display-timing.txt
+[2]: Documentation/devicetree/bindings/spi/spi-bus.txt
+[3]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+       lcd@0 {
+               compatible = "samsung,ld9040";
+               reg = <0>;
+               vdd3-supply = <&ldo7_reg>;
+               vci-supply = <&ldo17_reg>;
+               reset-gpios = <&gpy4 5 0>;
+               spi-max-frequency = <1200000>;
+               spi-cpol;
+               spi-cpha;
+               power-on-delay = <10>;
+               reset-delay = <10>;
+               panel-width-mm = <90>;
+               panel-height-mm = <154>;
+
+               display-timings {
+                       timing {
+                               clock-frequency = <23492370>;
+                               hactive = <480>;
+                               vactive = <800>;
+                               hback-porch = <16>;
+                               hfront-porch = <16>;
+                               vback-porch = <2>;
+                               vfront-porch = <28>;
+                               hsync-len = <2>;
+                               vsync-len = <1>;
+                               hsync-active = <0>;
+                               vsync-active = <0>;
+                               de-active = <0>;
+                               pixelclk-active = <0>;
+                       };
+               };
+
+               port {
+                       lcd_ep: endpoint {
+                               remote-endpoint = <&fimd_dpi_ep>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt b/Documentation/devicetree/bindings/panel/samsung,s6e8aa0.txt
new file mode 100644 (file)
index 0000000..e7ee988
--- /dev/null
@@ -0,0 +1,56 @@
+Samsung S6E8AA0 AMOLED LCD 5.3 inch panel
+
+Required properties:
+  - compatible: "samsung,s6e8aa0"
+  - reg: the virtual channel number of a DSI peripheral
+  - vdd3-supply: core voltage supply
+  - vci-supply: voltage supply for analog circuits
+  - reset-gpios: a GPIO spec for the reset pin
+  - display-timings: timings for the connected panel as described by [1]
+
+Optional properties:
+  - power-on-delay: delay after turning regulators on [ms]
+  - reset-delay: delay after reset sequence [ms]
+  - init-delay: delay after initialization sequence [ms]
+  - panel-width-mm: physical panel width [mm]
+  - panel-height-mm: physical panel height [mm]
+  - flip-horizontal: boolean to flip image horizontally
+  - flip-vertical: boolean to flip image vertically
+
+The device node can contain one 'port' child node with one child
+'endpoint' node, according to the bindings defined in [2]. This
+node should describe panel's video bus.
+
+[1]: Documentation/devicetree/bindings/video/display-timing.txt
+[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+       panel {
+               compatible = "samsung,s6e8aa0";
+               reg = <0>;
+               vdd3-supply = <&vcclcd_reg>;
+               vci-supply = <&vlcd_reg>;
+               reset-gpios = <&gpy4 5 0>;
+               power-on-delay= <50>;
+               reset-delay = <100>;
+               init-delay = <100>;
+               panel-width-mm = <58>;
+               panel-height-mm = <103>;
+               flip-horizontal;
+               flip-vertical;
+
+               display-timings {
+                       timing0: timing-0 {
+                               clock-frequency = <57153600>;
+                               hactive = <720>;
+                               vactive = <1280>;
+                               hfront-porch = <5>;
+                               hback-porch = <5>;
+                               hsync-len = <5>;
+                               vfront-porch = <13>;
+                               vback-porch = <1>;
+                               vsync-len = <2>;
+                       };
+               };
+       };
diff --git a/Documentation/devicetree/bindings/regulator/pbias-regulator.txt b/Documentation/devicetree/bindings/regulator/pbias-regulator.txt
new file mode 100644 (file)
index 0000000..32aa26f
--- /dev/null
@@ -0,0 +1,27 @@
+PBIAS internal regulator for SD card dual voltage i/o pads on OMAP SoCs.
+
+Required properties:
+- compatible:
+  - "ti,pbias-omap" for OMAP2, OMAP3, OMAP4, OMAP5, DRA7.
+- reg: pbias register offset from syscon base and size of pbias register.
+- syscon : phandle of the system control module
+- regulator-name : should be
+                       pbias_mmc_omap2430 for OMAP2430, OMAP3 SoCs
+                       pbias_sim_omap3 for OMAP3 SoCs
+                       pbias_mmc_omap4 for OMAP4 SoCs
+                       pbias_mmc_omap5 for OMAP5 and DRA7 SoC
+
+Optional properties:
+- Any optional property defined in bindings/regulator/regulator.txt
+
+Example:
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0 0x4>;
+                       syscon = <&omap5_padconf_global>;
+                       pbias_mmc_reg: pbias_mmc_omap5 {
+                               regulator-name = "pbias_mmc_omap5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
index b93e9a9..3aa4a8f 100644 (file)
@@ -20,15 +20,6 @@ Required properties:
                     have.
 - interrupt-parent: The phandle for the interrupt controller that
                     services interrupts for this device.
-- fsl,mode:         The operating mode for the SSI interface.
-                    "i2s-slave" - I2S mode, SSI is clock slave
-                    "i2s-master" - I2S mode, SSI is clock master
-                    "lj-slave" - left-justified mode, SSI is clock slave
-                    "lj-master" - l.j. mode, SSI is clock master
-                    "rj-slave" - right-justified mode, SSI is clock slave
-                    "rj-master" - r.j., SSI is clock master
-                    "ac97-slave" - AC97 mode, SSI is clock slave
-                    "ac97-master" - AC97 mode, SSI is clock master
 - fsl,playback-dma: Phandle to a node for the DMA channel to use for
                     playback of audio.  This is typically dictated by SOC
                     design.  See the notes below.
@@ -47,6 +38,9 @@ Required properties:
                     be connected together, and SRFS and STFS be connected
                     together.  This would still allow different sample sizes,
                     but not different sample rates.
+ - clocks:          "ipg" - Required clock for the SSI unit
+                    "baud" - Required clock for SSI master mode. Otherwise this
+                     clock is not used
 
 Required are also ac97 link bindings if ac97 is used. See
 Documentation/devicetree/bindings/sound/soc-ac97link.txt for the necessary
@@ -64,6 +58,15 @@ Optional properties:
                    Documentation/devicetree/bindings/dma/dma.txt.
 - dma-names:       Two dmas have to be defined, "tx" and "rx", if fsl,imx-fiq
                    is not defined.
+- fsl,mode:         The operating mode for the SSI interface.
+                    "i2s-slave" - I2S mode, SSI is clock slave
+                    "i2s-master" - I2S mode, SSI is clock master
+                    "lj-slave" - left-justified mode, SSI is clock slave
+                    "lj-master" - l.j. mode, SSI is clock master
+                    "rj-slave" - right-justified mode, SSI is clock slave
+                    "rj-master" - r.j., SSI is clock master
+                    "ac97-slave" - AC97 mode, SSI is clock slave
+                    "ac97-master" - AC97 mode, SSI is clock master
 
 Child 'codec' node required properties:
 - compatible:       Compatible list, contains the name of the codec
diff --git a/Documentation/devicetree/bindings/video/analog-tv-connector.txt b/Documentation/devicetree/bindings/video/analog-tv-connector.txt
new file mode 100644 (file)
index 0000000..0218fcd
--- /dev/null
@@ -0,0 +1,25 @@
+Analog TV Connector
+===================
+
+Required properties:
+- compatible: "composite-connector" or "svideo-connector"
+
+Optional properties:
+- label: a symbolic name for the connector
+
+Required nodes:
+- Video port for TV input
+
+Example
+-------
+
+tv: connector {
+       compatible = "composite-connector";
+       label = "tv";
+
+       port {
+               tv_connector_in: endpoint {
+                       remote-endpoint = <&venc_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/video/backlight/gpio-backlight.txt b/Documentation/devicetree/bindings/video/backlight/gpio-backlight.txt
new file mode 100644 (file)
index 0000000..321be66
--- /dev/null
@@ -0,0 +1,16 @@
+gpio-backlight bindings
+
+Required properties:
+  - compatible: "gpio-backlight"
+  - gpios: describes the gpio that is used for enabling/disabling the backlight.
+    refer to bindings/gpio/gpio.txt for more details.
+
+Optional properties:
+  - default-on: enable the backlight at boot.
+
+Example:
+       backlight {
+               compatible = "gpio-backlight";
+               gpios = <&gpio3 4 GPIO_ACTIVE_HIGH>;
+               default-on;
+       };
diff --git a/Documentation/devicetree/bindings/video/dvi-connector.txt b/Documentation/devicetree/bindings/video/dvi-connector.txt
new file mode 100644 (file)
index 0000000..fc53f7c
--- /dev/null
@@ -0,0 +1,35 @@
+DVI Connector
+==============
+
+Required properties:
+- compatible: "dvi-connector"
+
+Optional properties:
+- label: a symbolic name for the connector
+- ddc-i2c-bus: phandle to the i2c bus that is connected to DVI DDC
+- analog: the connector has DVI analog pins
+- digital: the connector has DVI digital pins
+- dual-link: the connector has pins for DVI dual-link
+
+Required nodes:
+- Video port for DVI input
+
+Note: One (or both) of 'analog' or 'digital' must be set.
+
+Example
+-------
+
+dvi0: connector@0 {
+       compatible = "dvi-connector";
+       label = "dvi";
+
+       digital;
+
+       ddc-i2c-bus = <&i2c3>;
+
+       port {
+               dvi_connector_in: endpoint {
+                       remote-endpoint = <&tfp410_out>;
+               };
+       };
+};
index 3289d76..57ccdde 100644 (file)
@@ -49,6 +49,8 @@ Required properties for dp-controller:
        -samsung,lane-count:
                number of lanes supported by the panel.
                        LANE_COUNT1 = 1, LANE_COUNT2 = 2, LANE_COUNT4 = 4
+       - display-timings: timings for the connected panel as described by
+               Documentation/devicetree/bindings/video/display-timing.txt
 
 Optional properties for dp-controller:
        -interlaced:
@@ -84,4 +86,19 @@ Board Specific portion:
                samsung,color-depth = <1>;
                samsung,link-rate = <0x0a>;
                samsung,lane-count = <4>;
+
+               display-timings {
+                       native-mode = <&lcd_timing>;
+                       lcd_timing: 1366x768 {
+                               clock-frequency = <70589280>;
+                               hactive = <1366>;
+                               vactive = <768>;
+                               hfront-porch = <40>;
+                               hback-porch = <40>;
+                               hsync-len = <32>;
+                               vback-porch = <10>;
+                               vfront-porch = <12>;
+                               vsync-len = <6>;
+                       };
+               };
        };
diff --git a/Documentation/devicetree/bindings/video/exynos_dsim.txt b/Documentation/devicetree/bindings/video/exynos_dsim.txt
new file mode 100644 (file)
index 0000000..33b5730
--- /dev/null
@@ -0,0 +1,80 @@
+Exynos MIPI DSI Master
+
+Required properties:
+  - compatible: "samsung,exynos4210-mipi-dsi"
+  - reg: physical base address and length of the registers set for the device
+  - interrupts: should contain DSI interrupt
+  - clocks: list of clock specifiers, must contain an entry for each required
+    entry in clock-names
+  - clock-names: should include "bus_clk"and "pll_clk" entries
+  - phys: list of phy specifiers, must contain an entry for each required
+    entry in phy-names
+  - phy-names: should include "dsim" entry
+  - vddcore-supply: MIPI DSIM Core voltage supply (e.g. 1.1V)
+  - vddio-supply: MIPI DSIM I/O and PLL voltage supply (e.g. 1.8V)
+  - samsung,pll-clock-frequency: specifies frequency of the "pll_clk" clock
+  - #address-cells, #size-cells: should be set respectively to <1> and <0>
+    according to DSI host bindings (see MIPI DSI bindings [1])
+
+Optional properties:
+  - samsung,power-domain: a phandle to DSIM power domain node
+
+Child nodes:
+  Should contain DSI peripheral nodes (see MIPI DSI bindings [1]).
+
+Video interfaces:
+  Device node can contain video interface port nodes according to [2].
+  The following are properties specific to those nodes:
+
+  port node:
+    - reg: (required) can be 0 for input RGB/I80 port or 1 for DSI port;
+
+  endpoint node of DSI port (reg = 1):
+    - samsung,burst-clock-frequency: specifies DSI frequency in high-speed burst
+      mode
+    - samsung,esc-clock-frequency: specifies DSI frequency in escape mode
+
+[1]: Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt
+[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
+
+Example:
+
+       dsi@11C80000 {
+               compatible = "samsung,exynos4210-mipi-dsi";
+               reg = <0x11C80000 0x10000>;
+               interrupts = <0 79 0>;
+               clocks = <&clock 286>, <&clock 143>;
+               clock-names = "bus_clk", "pll_clk";
+               phys = <&mipi_phy 1>;
+               phy-names = "dsim";
+               vddcore-supply = <&vusb_reg>;
+               vddio-supply = <&vmipi_reg>;
+               samsung,power-domain = <&pd_lcd0>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               samsung,pll-clock-frequency = <24000000>;
+
+               panel@1 {
+                       reg = <0>;
+                       ...
+                       port {
+                               panel_ep: endpoint {
+                                       remote-endpoint = <&dsi_ep>;
+                               };
+                       };
+               };
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@1 {
+                               dsi_ep: endpoint {
+                                       reg = <0>;
+                                       samsung,burst-clock-frequency = <500000000>;
+                                       samsung,esc-clock-frequency = <20000000>;
+                                       remote-endpoint = <&panel_ep>;
+                               };
+                       };
+               };
+       };
index 50decf8..f9187a2 100644 (file)
@@ -25,6 +25,9 @@ Required properties:
                sclk_pixel.
 - clock-names: aliases as per driver requirements for above clock IDs:
        "hdmi", "sclk_hdmi", "sclk_pixel", "sclk_hdmiphy" and "mout_hdmi".
+- ddc: phandle to the hdmi ddc node
+- phy: phandle to the hdmi phy node
+
 Example:
 
        hdmi {
@@ -32,4 +35,6 @@ Example:
                reg = <0x14530000 0x100000>;
                interrupts = <0 95 0>;
                hpd-gpio = <&gpx3 7 1>;
+               ddc = <&hdmi_ddc_node>;
+               phy = <&hdmi_phy_node>;
        };
diff --git a/Documentation/devicetree/bindings/video/hdmi-connector.txt b/Documentation/devicetree/bindings/video/hdmi-connector.txt
new file mode 100644 (file)
index 0000000..ccccc19
--- /dev/null
@@ -0,0 +1,28 @@
+HDMI Connector
+==============
+
+Required properties:
+- compatible: "hdmi-connector"
+- type: the HDMI connector type: "a", "b", "c", "d" or "e"
+
+Optional properties:
+- label: a symbolic name for the connector
+
+Required nodes:
+- Video port for HDMI input
+
+Example
+-------
+
+hdmi0: connector@1 {
+       compatible = "hdmi-connector";
+       label = "hdmi";
+
+       type = "a";
+
+       port {
+               hdmi_connector_in: endpoint {
+                       remote-endpoint = <&tpd12s015_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/video/panel-dsi-cm.txt b/Documentation/devicetree/bindings/video/panel-dsi-cm.txt
new file mode 100644 (file)
index 0000000..dce48eb
--- /dev/null
@@ -0,0 +1,29 @@
+Generic MIPI DSI Command Mode Panel
+===================================
+
+Required properties:
+- compatible: "panel-dsi-cm"
+
+Optional properties:
+- label: a symbolic name for the panel
+- reset-gpios: panel reset gpio
+- te-gpios: panel TE gpio
+
+Required nodes:
+- Video port for DSI input
+
+Example
+-------
+
+lcd0: display {
+       compatible = "tpo,taal", "panel-dsi-cm";
+       label = "lcd0";
+
+       reset-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>;
+
+       port {
+               lcd0_in: endpoint {
+                       remote-endpoint = <&dsi1_out_ep>;
+               };
+       };
+};
index 778838a..2dad41b 100644 (file)
@@ -39,6 +39,23 @@ Required properties:
 
 Optional Properties:
 - samsung,power-domain: a phandle to FIMD power domain node.
+- samsung,invert-vden: video enable signal is inverted
+- samsung,invert-vclk: video clock signal is inverted
+- display-timings: timing settings for FIMD, as described in document [1].
+               Can be used in case timings cannot be provided otherwise
+               or to override timings provided by the panel.
+
+The device node can contain 'port' child nodes according to the bindings defined
+in [2]. The following are properties specific to those nodes:
+- reg: (required) port index, can be:
+               0 - for CAMIF0 input,
+               1 - for CAMIF1 input,
+               2 - for CAMIF2 input,
+               3 - for parallel output,
+               4 - for write-back interface
+
+[1]: Documentation/devicetree/bindings/video/display-timing.txt
+[2]: Documentation/devicetree/bindings/media/video-interfaces.txt
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/video/sony,acx565akm.txt b/Documentation/devicetree/bindings/video/sony,acx565akm.txt
new file mode 100644 (file)
index 0000000..e123332
--- /dev/null
@@ -0,0 +1,30 @@
+Sony ACX565AKM SDI Panel
+========================
+
+Required properties:
+- compatible: "sony,acx565akm"
+
+Optional properties:
+- label: a symbolic name for the panel
+- reset-gpios: panel reset gpio
+
+Required nodes:
+- Video port for SDI input
+
+Example
+-------
+
+acx565akm@2 {
+       compatible = "sony,acx565akm";
+       spi-max-frequency = <6000000>;
+       reg = <2>;
+
+       label = "lcd";
+       reset-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; /* 90 */
+
+       port {
+               lcd_in: endpoint {
+                       remote-endpoint = <&sdi_out>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/video/ti,omap-dss.txt b/Documentation/devicetree/bindings/video/ti,omap-dss.txt
new file mode 100644 (file)
index 0000000..d5f1a3f
--- /dev/null
@@ -0,0 +1,211 @@
+Texas Instruments OMAP Display Subsystem
+========================================
+
+Generic Description
+-------------------
+
+This document is a generic description of the OMAP Display Subsystem bindings.
+Binding details for each OMAP SoC version are described in respective binding
+documentation.
+
+The OMAP Display Subsystem (DSS) hardware consists of DSS Core, DISPC module and
+a number of encoder modules. All DSS versions contain DSS Core and DISPC, but
+the encoder modules vary.
+
+The DSS Core is the parent of the other DSS modules, and manages clock routing,
+integration to the SoC, etc.
+
+DISPC is the display controller, which reads pixels from the memory and outputs
+a RGB pixel stream to encoders.
+
+The encoder modules encode the received RGB pixel stream to a video output like
+HDMI, MIPI DPI, etc.
+
+Video Ports
+-----------
+
+The DSS Core and the encoders have video port outputs. The structure of the
+video ports is described in Documentation/devicetree/bindings/video/video-
+ports.txt, and the properties for the ports and endpoints for each encoder are
+described in the SoC's DSS binding documentation.
+
+The video ports are used to describe the connections to external hardware, like
+panels or external encoders.
+
+Aliases
+-------
+
+The board dts file may define aliases for displays to assign "displayX" style
+name for each display. If no aliases are defined, a semi-random number is used
+for the display.
+
+Example
+-------
+
+A shortened example of the DSS description for OMAP4, with non-relevant parts
+removed, defined in omap4.dtsi:
+
+dss: dss@58000000 {
+       compatible = "ti,omap4-dss";
+       reg = <0x58000000 0x80>;
+       status = "disabled";
+       ti,hwmods = "dss_core";
+       clocks = <&dss_dss_clk>;
+       clock-names = "fck";
+       #address-cells = <1>;
+       #size-cells = <1>;
+       ranges;
+
+       dispc@58001000 {
+               compatible = "ti,omap4-dispc";
+               reg = <0x58001000 0x1000>;
+               interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+               ti,hwmods = "dss_dispc";
+               clocks = <&dss_dss_clk>;
+               clock-names = "fck";
+       };
+
+       hdmi: encoder@58006000 {
+               compatible = "ti,omap4-hdmi";
+               reg = <0x58006000 0x200>,
+                     <0x58006200 0x100>,
+                     <0x58006300 0x100>,
+                     <0x58006400 0x1000>;
+               reg-names = "wp", "pll", "phy", "core";
+               interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+               status = "disabled";
+               ti,hwmods = "dss_hdmi";
+               clocks = <&dss_48mhz_clk>, <&dss_sys_clk>;
+               clock-names = "fck", "sys_clk";
+       };
+};
+
+A shortened example of the board description for OMAP4 Panda board, defined in
+omap4-panda.dts.
+
+The Panda board has a DVI and a HDMI connector, and the board contains a TFP410
+chip (MIPI DPI to DVI encoder) and a TPD12S015 chip (HDMI ESD protection & level
+shifter). The video pipelines for the connectors are formed as follows:
+
+DSS Core --(MIPI DPI)--> TFP410 --(DVI)--> DVI Connector
+OMAP HDMI --(HDMI)--> TPD12S015 --(HDMI)--> HDMI Connector
+
+/ {
+       aliases {
+               display0 = &dvi0;
+               display1 = &hdmi0;
+       };
+
+       tfp410: encoder@0 {
+               compatible = "ti,tfp410";
+               gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;     /* 0, power-down */
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&tfp410_pins>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tfp410_in: endpoint@0 {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tfp410_out: endpoint@0 {
+                                       remote-endpoint = <&dvi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       dvi0: connector@0 {
+               compatible = "dvi-connector";
+               label = "dvi";
+
+               i2c-bus = <&i2c3>;
+
+               port {
+                       dvi_connector_in: endpoint {
+                               remote-endpoint = <&tfp410_out>;
+                       };
+               };
+       };
+
+       tpd12s015: encoder@1 {
+               compatible = "ti,tpd12s015";
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&tpd12s015_pins>;
+
+               gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,   /* 60, CT CP HPD */
+                       <&gpio2 9 GPIO_ACTIVE_HIGH>,    /* 41, LS OE */
+                       <&gpio2 31 GPIO_ACTIVE_HIGH>;   /* 63, HPD */
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tpd12s015_in: endpoint@0 {
+                                       remote-endpoint = <&hdmi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tpd12s015_out: endpoint@0 {
+                                       remote-endpoint = <&hdmi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       hdmi0: connector@1 {
+               compatible = "hdmi-connector";
+               label = "hdmi";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&tpd12s015_out>;
+                       };
+               };
+       };
+};
+
+&dss {
+       status = "ok";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&dss_dpi_pins>;
+
+       port {
+               dpi_out: endpoint {
+                       remote-endpoint = <&tfp410_in>;
+                       data-lines = <24>;
+               };
+       };
+};
+
+&hdmi {
+       status = "ok";
+       vdda-supply = <&vdac>;
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&dss_hdmi_pins>;
+
+       port {
+               hdmi_out: endpoint {
+                       remote-endpoint = <&tpd12s015_in>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/video/ti,omap2-dss.txt b/Documentation/devicetree/bindings/video/ti,omap2-dss.txt
new file mode 100644 (file)
index 0000000..fa8bb2e
--- /dev/null
@@ -0,0 +1,54 @@
+Texas Instruments OMAP2 Display Subsystem
+=========================================
+
+See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
+description about OMAP Display Subsystem bindings.
+
+DSS Core
+--------
+
+Required properties:
+- compatible: "ti,omap2-dss"
+- reg: address and length of the register space
+- ti,hwmods: "dss_core"
+
+Optional nodes:
+- Video port for DPI output
+
+DPI Endpoint required properties:
+- data-lines: number of lines used
+
+
+DISPC
+-----
+
+Required properties:
+- compatible: "ti,omap2-dispc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_dispc"
+- interrupts: the DISPC interrupt
+
+
+RFBI
+----
+
+Required properties:
+- compatible: "ti,omap2-rfbi"
+- reg: address and length of the register space
+- ti,hwmods: "dss_rfbi"
+
+
+VENC
+----
+
+Required properties:
+- compatible: "ti,omap2-venc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_venc"
+- vdda-supply: power supply for DAC
+
+VENC Endpoint required properties:
+
+Required properties:
+- ti,invert-polarity: invert the polarity of the video signal
+- ti,channels: 1 for composite, 2 for s-video
diff --git a/Documentation/devicetree/bindings/video/ti,omap3-dss.txt b/Documentation/devicetree/bindings/video/ti,omap3-dss.txt
new file mode 100644 (file)
index 0000000..0023fa4
--- /dev/null
@@ -0,0 +1,83 @@
+Texas Instruments OMAP3 Display Subsystem
+=========================================
+
+See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
+description about OMAP Display Subsystem bindings.
+
+DSS Core
+--------
+
+Required properties:
+- compatible: "ti,omap3-dss"
+- reg: address and length of the register space
+- ti,hwmods: "dss_core"
+- clocks: handle to fclk
+- clock-names: "fck"
+
+Optional nodes:
+- Video ports:
+       - Port 0: DPI output
+       - Port 1: SDI output
+
+DPI Endpoint required properties:
+- data-lines: number of lines used
+
+SDI Endpoint required properties:
+- datapairs: number of datapairs used
+
+
+DISPC
+-----
+
+Required properties:
+- compatible: "ti,omap3-dispc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_dispc"
+- interrupts: the DISPC interrupt
+- clocks: handle to fclk
+- clock-names: "fck"
+
+
+RFBI
+----
+
+Required properties:
+- compatible: "ti,omap3-rfbi"
+- reg: address and length of the register space
+- ti,hwmods: "dss_rfbi"
+- clocks: handles to fclk and iclk
+- clock-names: "fck", "ick"
+
+
+VENC
+----
+
+Required properties:
+- compatible: "ti,omap3-venc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_venc"
+- vdda-supply: power supply for DAC
+- clocks: handle to fclk
+- clock-names: "fck"
+
+VENC Endpoint required properties:
+- ti,invert-polarity: invert the polarity of the video signal
+- ti,channels: 1 for composite, 2 for s-video
+
+
+DSI
+---
+
+Required properties:
+- compatible: "ti,omap3-dsi"
+- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll'
+- reg-names: "proto", "phy", "pll"
+- interrupts: the DSI interrupt line
+- ti,hwmods: "dss_dsi1"
+- vdd-supply: power supply for DSI
+- clocks: handles to fclk and pll clock
+- clock-names: "fck", "sys_clk"
+
+DSI Endpoint required properties:
+- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-,
+  DATA1+, DATA1-, ...
diff --git a/Documentation/devicetree/bindings/video/ti,omap4-dss.txt b/Documentation/devicetree/bindings/video/ti,omap4-dss.txt
new file mode 100644 (file)
index 0000000..f85d6fc
--- /dev/null
@@ -0,0 +1,111 @@
+Texas Instruments OMAP4 Display Subsystem
+=========================================
+
+See Documentation/devicetree/bindings/video/ti,omap-dss.txt for generic
+description about OMAP Display Subsystem bindings.
+
+DSS Core
+--------
+
+Required properties:
+- compatible: "ti,omap4-dss"
+- reg: address and length of the register space
+- ti,hwmods: "dss_core"
+- clocks: handle to fclk
+- clock-names: "fck"
+
+Required nodes:
+- DISPC
+
+Optional nodes:
+- DSS Submodules: RFBI, VENC, DSI, HDMI
+- Video port for DPI output
+
+DPI Endpoint required properties:
+- data-lines: number of lines used
+
+
+DISPC
+-----
+
+Required properties:
+- compatible: "ti,omap4-dispc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_dispc"
+- interrupts: the DISPC interrupt
+- clocks: handle to fclk
+- clock-names: "fck"
+
+
+RFBI
+----
+
+Required properties:
+- compatible: "ti,omap4-rfbi"
+- reg: address and length of the register space
+- ti,hwmods: "dss_rfbi"
+- clocks: handles to fclk and iclk
+- clock-names: "fck", "ick"
+
+Optional nodes:
+- Video port for RFBI output
+- RFBI controlled peripherals
+
+
+VENC
+----
+
+Required properties:
+- compatible: "ti,omap4-venc"
+- reg: address and length of the register space
+- ti,hwmods: "dss_venc"
+- vdda-supply: power supply for DAC
+- clocks: handle to fclk
+- clock-names: "fck"
+
+Optional nodes:
+- Video port for VENC output
+
+VENC Endpoint required properties:
+- ti,invert-polarity: invert the polarity of the video signal
+- ti,channels: 1 for composite, 2 for s-video
+
+
+DSI
+---
+
+Required properties:
+- compatible: "ti,omap4-dsi"
+- reg: addresses and lengths of the register spaces for 'proto', 'phy' and 'pll'
+- reg-names: "proto", "phy", "pll"
+- interrupts: the DSI interrupt line
+- ti,hwmods: "dss_dsi1" or "dss_dsi2"
+- vdd-supply: power supply for DSI
+- clocks: handles to fclk and pll clock
+- clock-names: "fck", "sys_clk"
+
+Optional nodes:
+- Video port for DSI output
+- DSI controlled peripherals
+
+DSI Endpoint required properties:
+- lanes: list of pin numbers for the DSI lanes: CLK+, CLK-, DATA0+, DATA0-,
+  DATA1+, DATA1-, ...
+
+
+HDMI
+----
+
+Required properties:
+- compatible: "ti,omap4-hdmi"
+- reg: addresses and lengths of the register spaces for 'wp', 'pll', 'phy',
+       'core'
+- reg-names: "wp", "pll", "phy", "core"
+- interrupts: the HDMI interrupt line
+- ti,hwmods: "dss_hdmi"
+- vdda-supply: vdda power supply
+- clocks: handles to fclk and pll clock
+- clock-names: "fck", "sys_clk"
+
+Optional nodes:
+- Video port for HDMI output
diff --git a/Documentation/devicetree/bindings/video/ti,tfp410.txt b/Documentation/devicetree/bindings/video/ti,tfp410.txt
new file mode 100644 (file)
index 0000000..2cbe32a
--- /dev/null
@@ -0,0 +1,41 @@
+TFP410 DPI to DVI encoder
+=========================
+
+Required properties:
+- compatible: "ti,tfp410"
+
+Optional properties:
+- powerdown-gpios: power-down gpio
+
+Required nodes:
+- Video port 0 for DPI input
+- Video port 1 for DVI output
+
+Example
+-------
+
+tfp410: encoder@0 {
+       compatible = "ti,tfp410";
+       powerdown-gpios = <&twl_gpio 2 GPIO_ACTIVE_LOW>;
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+
+                       tfp410_in: endpoint@0 {
+                               remote-endpoint = <&dpi_out>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       tfp410_out: endpoint@0 {
+                               remote-endpoint = <&dvi_connector_in>;
+                       };
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/video/ti,tpd12s015.txt b/Documentation/devicetree/bindings/video/ti,tpd12s015.txt
new file mode 100644 (file)
index 0000000..26e6d32
--- /dev/null
@@ -0,0 +1,44 @@
+TPD12S015 HDMI level shifter and ESD protection chip
+====================================================
+
+Required properties:
+- compatible: "ti,tpd12s015"
+
+Optional properties:
+- gpios: CT CP HPD, LS OE and HPD gpios
+
+Required nodes:
+- Video port 0 for HDMI input
+- Video port 1 for HDMI output
+
+Example
+-------
+
+tpd12s015: encoder@1 {
+       compatible = "ti,tpd12s015";
+
+       gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,   /* 60, CT CP HPD */
+               <&gpio2 9 GPIO_ACTIVE_HIGH>,    /* 41, LS OE */
+               <&gpio2 31 GPIO_ACTIVE_HIGH>;   /* 63, HPD */
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@0 {
+                       reg = <0>;
+
+                       tpd12s015_in: endpoint@0 {
+                               remote-endpoint = <&hdmi_out>;
+                       };
+               };
+
+               port@1 {
+                       reg = <1>;
+
+                       tpd12s015_out: endpoint@0 {
+                               remote-endpoint = <&hdmi_connector_in>;
+                       };
+               };
+       };
+};
index f424e0e..efca5c1 100644 (file)
@@ -529,6 +529,7 @@ locking rules:
 open:          yes
 close:         yes
 fault:         yes             can return with page locked
+map_pages:     yes
 page_mkwrite:  yes             can return with page locked
 access:                yes
 
@@ -540,6 +541,15 @@ the page, then ensure it is not already truncated (the page lock will block
 subsequent truncate), and then return with VM_FAULT_LOCKED, and the page
 locked. The VM will unlock the page.
 
+       ->map_pages() is called when VM asks to map easy accessible pages.
+Filesystem should find and map pages associated with offsets from "pgoff"
+till "max_pgoff". ->map_pages() is called with page table locked and must
+not block.  If it's not possible to reach a page without blocking,
+filesystem should skip it. Filesystem should use do_set_pte() to setup
+page table entry. Pointer to entry associated with offset "pgoff" is
+passed in "pte" field in vm_fault structure. Pointers to entries for other
+offsets should be calculated relative to "pte".
+
        ->page_mkwrite() is called when a previously read-only pte is
 about to become writeable. The filesystem again must ensure that there are
 no truncate/invalidate races, and then return with the page locked. If
index 81ac488..71b63c2 100644 (file)
@@ -49,6 +49,10 @@ mode=mode    Sets the mode flags to the given (octal) value, regardless
                This is useful since most of the plain AmigaOS files
                will map to 600.
 
+nofilenametruncate
+               The file system will return an error when filename exceeds
+               standard maximum filename length (30 characters).
+
 reserved=num   Sets the number of reserved blocks at the start of the
                partition to num. You should never need this option.
                Default is 2.
@@ -181,9 +185,8 @@ tested, though several hundred MB have been read and written using
 this fs. For a most up-to-date list of bugs please consult
 fs/affs/Changes.
 
-Filenames are truncated to 30 characters without warning (this
-can be changed by setting the compile-time option AFFS_NO_TRUNCATE
-in include/linux/amigaffs.h).
+By default, filenames are truncated to 30 characters without warning.
+'nofilenametruncate' mount option can change that behavior.
 
 Case is ignored by the affs in filename matching, but Linux shells
 do care about the case. Example (with /wb being an affs mounted fs):
index b8d2849..25311e1 100644 (file)
@@ -122,6 +122,10 @@ disable_ext_identify   Disable the extension list configured by mkfs, so f2fs
 inline_xattr           Enable the inline xattrs feature.
 inline_data            Enable the inline data feature: New created small(<~3.4k)
                        files can be written into inode block.
+flush_merge           Merge concurrent cache_flush commands as much as possible
+                       to eliminate redundant command issues. If the underlying
+                      device handles the cache_flush command relatively slowly,
+                      recommend to enable this option.
 
 ================================================================================
 DEBUGFS ENTRIES
@@ -169,9 +173,11 @@ Files in /sys/fs/f2fs/<devname>
 
  reclaim_segments             This parameter controls the number of prefree
                               segments to be reclaimed. If the number of prefree
-                             segments is larger than this number, f2fs tries to
-                             conduct checkpoint to reclaim the prefree segments
-                             to free segments. By default, 100 segments, 200MB.
+                             segments is larger than the number of segments
+                             in the proportion to the percentage over total
+                             volume size, f2fs tries to conduct checkpoint to
+                             reclaim the prefree segments to free segments.
+                             By default, 5% over total # of segments.
 
  max_small_discards          This parameter controls the number of discard
                              commands that consist small blocks less than 2MB.
@@ -195,6 +201,17 @@ Files in /sys/fs/f2fs/<devname>
                              cleaning operations. The default value is 4096
                              which covers 8GB block address range.
 
+ dir_level                    This parameter controls the directory level to
+                             support large directory. If a directory has a
+                             number of files, it can reduce the file lookup
+                             latency by increasing this dir_level value.
+                             Otherwise, it needs to decrease this value to
+                             reduce the space overhead. The default value is 0.
+
+ ram_thresh                   This parameter controls the memory footprint used
+                             by free nids and cached nat entries. By default,
+                             10 is set, which indicates 10 MB / 1 GB RAM.
+
 ================================================================================
 USAGE
 ================================================================================
@@ -444,9 +461,11 @@ The number of blocks and buckets are determined by,
   # of blocks in level #n = |
                             `- 4, Otherwise
 
-                             ,- 2^n, if n < MAX_DIR_HASH_DEPTH / 2,
+                             ,- 2^ (n + dir_level),
+                            |            if n < MAX_DIR_HASH_DEPTH / 2,
   # of buckets in level #n = |
-                             `- 2^((MAX_DIR_HASH_DEPTH / 2) - 1), Otherwise
+                             `- 2^((MAX_DIR_HASH_DEPTH / 2 + dir_level) - 1),
+                                         Otherwise
 
 When F2FS finds a file name in a directory, at first a hash value of the file
 name is calculated. Then, F2FS scans the hash table in level #0 to find the
index f00bee1..8b9cd8e 100644 (file)
@@ -1648,18 +1648,21 @@ pids, so one need to either stop or freeze processes being inspected
 if precise results are needed.
 
 
-3.7    /proc/<pid>/fdinfo/<fd> - Information about opened file
+3.8    /proc/<pid>/fdinfo/<fd> - Information about opened file
 ---------------------------------------------------------------
 This file provides information associated with an opened file. The regular
-files have at least two fields -- 'pos' and 'flags'. The 'pos' represents
-the current offset of the opened file in decimal form [see lseek(2) for
-details] and 'flags' denotes the octal O_xxx mask the file has been
-created with [see open(2) for details].
+files have at least three fields -- 'pos', 'flags' and mnt_id. The 'pos'
+represents the current offset of the opened file in decimal form [see lseek(2)
+for details], 'flags' denotes the octal O_xxx mask the file has been
+created with [see open(2) for details] and 'mnt_id' represents mount ID of
+the file system containing the opened file [see 3.5 /proc/<pid>/mountinfo
+for details].
 
 A typical output is
 
        pos:    0
        flags:  0100002
+       mnt_id: 19
 
 The files such as eventfd, fsnotify, signalfd, epoll among the regular pos/flags
 pair provide additional information particular to the objects they represent.
@@ -1668,6 +1671,7 @@ pair provide additional information particular to the objects they represent.
        ~~~~~~~~~~~~~
        pos:    0
        flags:  04002
+       mnt_id: 9
        eventfd-count:  5a
 
        where 'eventfd-count' is hex value of a counter.
@@ -1676,6 +1680,7 @@ pair provide additional information particular to the objects they represent.
        ~~~~~~~~~~~~~~
        pos:    0
        flags:  04002
+       mnt_id: 9
        sigmask:        0000000000000200
 
        where 'sigmask' is hex value of the signal mask associated
@@ -1685,6 +1690,7 @@ pair provide additional information particular to the objects they represent.
        ~~~~~~~~~~~
        pos:    0
        flags:  02
+       mnt_id: 9
        tfd:        5 events:       1d data: ffffffffffffffff
 
        where 'tfd' is a target file descriptor number in decimal form,
@@ -1718,6 +1724,7 @@ pair provide additional information particular to the objects they represent.
 
        pos:    0
        flags:  02
+       mnt_id: 9
        fanotify flags:10 event-flags:0
        fanotify mnt_id:12 mflags:40 mask:38 ignored_mask:40000003
        fanotify ino:4f969 sdev:800013 mflags:0 mask:3b ignored_mask:40000000 fhandle-bytes:8 fhandle-type:1 f_handle:69f90400c275b5b4
index aaaf069..adf5e33 100644 (file)
@@ -26,6 +26,7 @@ Supported adapters:
   * Intel Wellsburg (PCH)
   * Intel Coleto Creek (PCH)
   * Intel Wildcat Point-LP (PCH)
+  * Intel BayTrail (SOC)
    Datasheets: Publicly available at the Intel website
 
 On Intel Patsburg and later chipsets, both the normal host SMBus controller
index b0ff2ab..4556a3e 100644 (file)
@@ -46,7 +46,7 @@ A few combinations of the above flags are also defined for your convenience:
                                   and write_block_data commands
   I2C_FUNC_SMBUS_I2C_BLOCK        Handles the SMBus read_i2c_block_data
                                   and write_i2c_block_data commands
-  I2C_FUNC_SMBUS_EMUL             Handles all SMBus commands than can be
+  I2C_FUNC_SMBUS_EMUL             Handles all SMBus commands that can be
                                   emulated by a real I2C adapter (using
                                   the transparent emulation layer)
 
index 0b3e62d..ff6d6ce 100644 (file)
@@ -6,8 +6,8 @@ Key to symbols
 S     (1 bit) : Start bit
 P     (1 bit) : Stop bit
 Rd/Wr (1 bit) : Read/Write bit. Rd equals 1, Wr equals 0.
-A, NA (1 bit) : Accept and reverse accept bit. 
-Addr  (7 bits): I2C 7 bit address. Note that this can be expanded as usual to 
+A, NA (1 bit) : Accept and reverse accept bit.
+Addr  (7 bits): I2C 7 bit address. Note that this can be expanded as usual to
                 get a 10 bit I2C address.
 Comm  (8 bits): Command byte, a data byte which often selects a register on
                 the device.
@@ -49,11 +49,20 @@ a byte read, followed by a byte write:
 Modified transactions
 =====================
 
-The following modifications to the I2C protocol can also be generated,
-with the exception of I2C_M_NOSTART these are usually only needed to
-work around device issues:
+The following modifications to the I2C protocol can also be generated by
+setting these flags for i2c messages. With the exception of I2C_M_NOSTART, they
+are usually only needed to work around device issues:
 
-  Flag I2C_M_NOSTART: 
+I2C_M_IGNORE_NAK:
+    Normally message is interrupted immediately if there is [NA] from the
+    client. Setting this flag treats any [NA] as [A], and all of
+    message is sent.
+    These messages may still fail to SCL lo->hi timeout.
+
+I2C_M_NO_RD_ACK:
+    In a read message, master A/NA bit is skipped.
+
+I2C_M_NOSTART:
     In a combined transaction, no 'S Addr Wr/Rd [A]' is generated at some
     point. For example, setting I2C_M_NOSTART on the second partial message
     generates something like:
@@ -67,17 +76,13 @@ work around device issues:
     I2C device but may also be used between direction changes by some
     rare devices.
 
-  Flags I2C_M_REV_DIR_ADDR
+I2C_M_REV_DIR_ADDR:
     This toggles the Rd/Wr flag. That is, if you want to do a write, but
     need to emit an Rd instead of a Wr, or vice versa, you set this
     flag. For example:
       S Addr Rd [A] Data [A] Data [A] ... [A] Data [A] P
 
-  Flags I2C_M_IGNORE_NAK
-    Normally message is interrupted immediately if there is [NA] from the
-    client. Setting this flag treats any [NA] as [A], and all of
-    message is sent.
-    These messages may still fail to SCL lo->hi timeout.
-
-  Flags I2C_M_NO_RD_ACK
-    In a read message, master A/NA bit is skipped.
+I2C_M_STOP:
+    Force a stop condition (P) after the message. Some I2C related protocols
+    like SCCB require that. Normally, you really don't want to get interrupted
+    between the messages of one transfer.
index 67aa71e..f6da056 100644 (file)
@@ -22,13 +22,6 @@ rather straightforward and risk-free manner.
 Architectures that want to support this need to do a couple of
 code-organizational changes first:
 
-- move their irq-flags manipulation code from their asm/system.h header
-  to asm/irqflags.h
-
-- rename local_irq_disable()/etc to raw_local_irq_disable()/etc. so that
-  the linux/irqflags.h code can inject callbacks and can construct the
-  real local_irq_disable()/etc APIs.
-
 - add and enable TRACE_IRQFLAGS_SUPPORT in their arch level Kconfig file
 
 and then a couple of functional changes are needed as well to implement
index c420676..350f733 100644 (file)
@@ -157,6 +157,10 @@ applicable everywhere (see syntax).
     to the build environment (if this is desired, it can be done via
     another symbol).
 
+  - "allnoconfig_y"
+    This declares the symbol as one that should have the value y when
+    using "allnoconfig". Used for symbols that hide other symbols.
+
 Menu dependencies
 -----------------
 
index bc34785..b6c67d5 100644 (file)
@@ -884,6 +884,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        Enable debug messages at boot time.  See
                        Documentation/dynamic-debug-howto.txt for details.
 
+       early_ioremap_debug [KNL]
+                       Enable debug messages in early_ioremap support. This
+                       is useful for tracking down temporary early mappings
+                       which are not unmapped.
+
        earlycon=       [KNL] Output early console device and options.
                uart[8250],io,<addr>[,options]
                uart[8250],mmio,<addr>[,options]
index 09b583e..09c2382 100644 (file)
@@ -53,7 +53,8 @@ This has a number of options available:
 
      If this is off (ie. "permissive"), then modules for which the key is not
      available and modules that are unsigned are permitted, but the kernel will
-     be marked as being tainted.
+     be marked as being tainted, and the concerned modules will be marked as
+     tainted, shown with the character 'E'.
 
      If this is on (ie. "restrictive"), only modules that have a valid
      signature that can be verified by a public key in the kernel's possession
index 13032c0..e315599 100644 (file)
@@ -265,6 +265,9 @@ characters, each representing a particular tainted value.
 
  13: 'O' if an externally-built ("out-of-tree") module has been loaded.
 
+ 14: 'E' if an unsigned module has been loaded in a kernel supporting
+     module signature.
+
 The primary reason for the 'Tainted: ' string is to tell kernel
 debuggers if this is a clean kernel or if anything unusual has
 occurred.  Tainting is permanent: even if an offending module is
index 271438c..47ce9a5 100644 (file)
@@ -2,8 +2,8 @@
 
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
-1. Device Subdirectories
-------------------------
+1. RapidIO Device Subdirectories
+--------------------------------
 
 For each RapidIO device, the RapidIO subsystem creates files in an individual
 subdirectory with the following name, /sys/bus/rapidio/devices/<device_name>.
@@ -25,8 +25,8 @@ seen by the enumerating host (destID = 1):
 NOTE: An enumerating or discovering endpoint does not create a sysfs entry for
 itself, this is why an endpoint with destID=1 is not shown in the list.
 
-2. Attributes Common for All Devices
-------------------------------------
+2. Attributes Common for All RapidIO Devices
+--------------------------------------------
 
 Each device subdirectory contains the following informational read-only files:
 
@@ -52,16 +52,16 @@ This attribute is similar in behavior to the "config" attribute of PCI devices
 and provides an access to the RapidIO device registers using standard file read
 and write operations.
 
-3. Endpoint Device Attributes
------------------------------
+3. RapidIO Endpoint Device Attributes
+-------------------------------------
 
 Currently Linux RapidIO subsystem does not create any endpoint specific sysfs
 attributes. It is possible that RapidIO master port drivers and endpoint device
 drivers will add their device-specific sysfs attributes but such attributes are
 outside the scope of this document.
 
-4. Switch Device Attributes
----------------------------
+4. RapidIO Switch Device Attributes
+-----------------------------------
 
 RapidIO switches have additional attributes in sysfs. RapidIO subsystem supports
 common and device-specific sysfs attributes for switches. Because switches are
@@ -106,3 +106,53 @@ attribute:
         for that controller always will be 0.
         To initiate RapidIO enumeration/discovery on all available mports
         a user must write '-1' (or RIO_MPORT_ANY) into this attribute file.
+
+
+6. RapidIO Bus Controllers/Ports
+--------------------------------
+
+On-chip RapidIO controllers and PCIe-to-RapidIO bridges (referenced as
+"Master Port" or "mport") are presented in sysfs as the special class of
+devices: "rapidio_port".
+
+The /sys/class/rapidio_port subdirectory contains individual subdirectories
+named as "rapidioN" where N = mport ID registered with RapidIO subsystem.
+
+NOTE: An mport ID is not a RapidIO destination ID assigned to a given local
+mport device.
+
+Each mport device subdirectory in addition to standard entries contains the
+following device-specific attributes:
+
+   port_destid - reports RapidIO destination ID assigned to the given RapidIO
+                 mport device. If value 0xFFFFFFFF is returned this means that
+                 no valid destination ID have been assigned to the mport (yet).
+                 Normally, before enumeration/discovery have been executed only
+                 fabric enumerating mports have a valid destination ID assigned
+                 to them using "hdid=..." rapidio module parameter.
+      sys_size - reports RapidIO common transport system size:
+                   0 = small (8-bit destination ID, max. 256 devices),
+                   1 = large (16-bit destination ID, max. 65536 devices).
+
+After enumeration or discovery was performed for a given mport device,
+the corresponding subdirectory will also contain subdirectories for each
+child RapidIO device connected to the mport. Naming conventions for RapidIO
+devices are described in Section 1 above.
+
+The example below shows mport device subdirectory with several child RapidIO
+devices attached to it.
+
+[rio@rapidio ~]$ ls /sys/class/rapidio_port/rapidio0/ -l
+total 0
+drwxr-xr-x 3 root root    0 Feb 11 15:10 00:e:0001
+drwxr-xr-x 3 root root    0 Feb 11 15:10 00:e:0004
+drwxr-xr-x 3 root root    0 Feb 11 15:10 00:e:0007
+drwxr-xr-x 3 root root    0 Feb 11 15:10 00:s:0002
+drwxr-xr-x 3 root root    0 Feb 11 15:10 00:s:0003
+drwxr-xr-x 3 root root    0 Feb 11 15:10 00:s:0005
+lrwxrwxrwx 1 root root    0 Feb 11 15:11 device -> ../../../0000:01:00.0
+-r--r--r-- 1 root root 4096 Feb 11 15:11 port_destid
+drwxr-xr-x 2 root root    0 Feb 11 15:11 power
+lrwxrwxrwx 1 root root    0 Feb 11 15:04 subsystem -> ../../../../../../class/rapidio_port
+-r--r--r-- 1 root root 4096 Feb 11 15:11 sys_size
+-rw-r--r-- 1 root root 4096 Feb 11 15:04 uevent
index 9290de7..a2f27bb 100644 (file)
@@ -8,7 +8,7 @@ Context switch
 By default, the switch_to arch function is called with the runqueue
 locked. This is usually not a problem unless switch_to may need to
 take the runqueue lock. This is usually due to a wake up operation in
-the context switch. See arch/ia64/include/asm/system.h for an example.
+the context switch. See arch/ia64/include/asm/switch_to.h for an example.
 
 To request the scheduler call switch_to with the runqueue unlocked,
 you must `#define __ARCH_WANT_UNLOCKED_CTXSW` in a header file
index ec8be46..9886c3d 100644 (file)
@@ -317,6 +317,7 @@ for more than this value report a warning.
 This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
 
 0: means infinite timeout - no checking done.
+Possible values to set are in range {0..LONG_MAX/HZ}.
 
 ==============================================================
 
@@ -785,6 +786,8 @@ can be ORed together:
 1024 - A module from drivers/staging was loaded.
 2048 - The system is working around a severe firmware bug.
 4096 - An out-of-tree module has been loaded.
+8192 - An unsigned module has been loaded in a kernel supporting module
+       signature.
 
 ==============================================================
 
index bfff896..beaa87a 100644 (file)
@@ -1427,6 +1427,7 @@ F:        drivers/cpuidle/cpuidle-zynq.c
 N:     zynq
 N:     xilinx
 F:     drivers/clocksource/cadence_ttc_timer.c
+F:     drivers/i2c/busses/i2c-cadence.c
 F:     drivers/mmc/host/sdhci-of-arasan.c
 
 ARM SMMU DRIVER
@@ -2945,6 +2946,16 @@ F:       drivers/gpu/drm/radeon/
 F:     include/drm/radeon*
 F:     include/uapi/drm/radeon*
 
+DRM PANEL DRIVERS
+M:     Thierry Reding <thierry.reding@gmail.com>
+L:     dri-devel@lists.freedesktop.org
+T:     git git://anongit.freedesktop.org/tegra/linux.git
+S:     Maintained
+F:     drivers/gpu/drm/drm_panel.c
+F:     drivers/gpu/drm/panel/
+F:     include/drm/drm_panel.h
+F:     Documentation/devicetree/bindings/panel/
+
 INTEL DRM DRIVERS (excluding Poulsbo, Moorestown and derivative chipsets)
 M:     Daniel Vetter <daniel.vetter@ffwll.ch>
 M:     Jani Nikula <jani.nikula@linux.intel.com>
@@ -3474,12 +3485,6 @@ S:       Maintained
 F:     drivers/extcon/
 F:     Documentation/extcon/
 
-EXYNOS DP DRIVER
-M:     Jingoo Han <jg1.han@samsung.com>
-L:     linux-fbdev@vger.kernel.org
-S:     Maintained
-F:     drivers/video/exynos/exynos_dp*
-
 EXYNOS MIPI DISPLAY DRIVERS
 M:     Inki Dae <inki.dae@samsung.com>
 M:     Donghwa Lee <dh09.lee@samsung.com>
@@ -4304,7 +4309,8 @@ F:        drivers/i2c/i2c-stub.c
 I2C SUBSYSTEM
 M:     Wolfram Sang <wsa@the-dreams.de>
 L:     linux-i2c@vger.kernel.org
-W:     http://i2c.wiki.kernel.org/
+W:     https://i2c.wiki.kernel.org/
+Q:     https://patchwork.ozlabs.org/project/linux-i2c/list/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux.git
 S:     Maintained
 F:     Documentation/i2c/
@@ -4542,8 +4548,7 @@ K:        \b(ABS|SYN)_MT_
 
 INTEL C600 SERIES SAS CONTROLLER DRIVER
 M:     Intel SCU Linux support <intel-linux-scu@intel.com>
-M:     Lukasz Dorau <lukasz.dorau@intel.com>
-M:     Maciej Patelczyk <maciej.patelczyk@intel.com>
+M:     Artur Paszkiewicz <artur.paszkiewicz@intel.com>
 M:     Dave Jiang <dave.jiang@intel.com>
 L:     linux-scsi@vger.kernel.org
 T:     git git://git.code.sf.net/p/intel-sas/isci
@@ -5927,6 +5932,7 @@ F:        include/linux/mfd/
 
 MULTIMEDIA CARD (MMC), SECURE DIGITAL (SD) AND SDIO SUBSYSTEM
 M:     Chris Ball <chris@printf.net>
+M:     Ulf Hansson <ulf.hansson@linaro.org>
 L:     linux-mmc@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc.git
 S:     Maintained
index 00a933b..cf3e075 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -120,9 +120,10 @@ ifneq ($(KBUILD_OUTPUT),)
 # Invoke a second make in the output directory, passing relevant variables
 # check that the output directory actually exists
 saved-output := $(KBUILD_OUTPUT)
-KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT) && /bin/pwd)
+KBUILD_OUTPUT := $(shell mkdir -p $(KBUILD_OUTPUT) && cd $(KBUILD_OUTPUT) \
+                                                               && /bin/pwd)
 $(if $(KBUILD_OUTPUT),, \
-     $(error output directory "$(saved-output)" does not exist))
+     $(error failed to create output directory "$(saved-output)"))
 
 PHONY += $(MAKECMDGOALS) sub-make
 
@@ -1079,7 +1080,7 @@ MRPROPER_FILES += .config .config.old .version .old_version $(version_h) \
                  Module.symvers tags TAGS cscope* GPATH GTAGS GRTAGS GSYMS \
                  signing_key.priv signing_key.x509 x509.genkey         \
                  extra_certificates signing_key.x509.keyid             \
-                 signing_key.x509.signer
+                 signing_key.x509.signer include/linux/version.h
 
 # clean - Delete most, but leave enough to build external modules
 #
@@ -1118,8 +1119,7 @@ distclean: mrproper
        @find $(srctree) $(RCS_FIND_IGNORE) \
                \( -name '*.orig' -o -name '*.rej' -o -name '*~' \
                -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \
-               -o -name '.*.rej' \
-               -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \
+               -o -name '.*.rej' -o -name '*%'  -o -name 'core' \) \
                -type f -print | xargs rm -f
 
 
index 75de197..9596b0a 100644 (file)
@@ -57,7 +57,7 @@ config ARCH_FLATMEM_ENABLE
 config MMU
        def_bool y
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool y
 
 config GENERIC_CALIBRATE_DELAY
index ea16d78..4f31b2e 100644 (file)
 
 / {
        compatible = "snps,nsimosci";
-       clock-frequency = <80000000>;   /* 80 MHZ */
+       clock-frequency = <20000000>;   /* 20 MHZ */
        #address-cells = <1>;
        #size-cells = <1>;
        interrupt-parent = <&intc>;
 
        chosen {
-               bootargs = "console=tty0 consoleblank=0";
+               /* this is for console on PGU */
+               /* bootargs = "console=tty0 consoleblank=0"; */
+               /* this is for console on serial */
+               bootargs = "earlycon=uart8250,mmio32,0xc0000000,115200n8 console=ttyS0,115200n8 consoleblank=0 debug";
        };
 
        aliases {
                };
 
                uart0: serial@c0000000 {
-                       compatible = "snps,dw-apb-uart";
+                       compatible = "ns8250";
                        reg = <0xc0000000 0x2000>;
                        interrupts = <11>;
-                       #clock-frequency = <80000000>;
                        clock-frequency = <3686400>;
                        baud = <115200>;
                        reg-shift = <2>;
                        reg-io-width = <4>;
-                       status = "okay";
+                       no-loopback-test = <1>;
                };
 
                pgu0: pgu@c9000000 {
diff --git a/arch/arc/boot/dts/skeleton.dts b/arch/arc/boot/dts/skeleton.dts
deleted file mode 100644 (file)
index 25a84fb..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-/dts-v1/;
-
-/include/ "skeleton.dtsi"
index 451af30..c01ba35 100644 (file)
@@ -54,6 +54,7 @@ CONFIG_SERIO_ARC_PS2=y
 CONFIG_SERIAL_8250=y
 CONFIG_SERIAL_8250_CONSOLE=y
 CONFIG_SERIAL_8250_DW=y
+CONFIG_SERIAL_OF_PLATFORM=y
 CONFIG_SERIAL_ARC=y
 CONFIG_SERIAL_ARC_CONSOLE=y
 # CONFIG_HW_RANDOM is not set
index 66ee552..5faad17 100644 (file)
 
 #define ASM_NL          `      /* use '`' to mark new line in macro */
 
-/* Can't use the ENTRY macro in linux/linkage.h
- * gas considers ';' as comment vs. newline
- */
-.macro ARC_ENTRY name
-       .global \name
-       .align 4
-       \name:
-.endm
-
-.macro ARC_EXIT name
-#define ASM_PREV_SYM_ADDR(name)  .-##name
-       .size \ name, ASM_PREV_SYM_ADDR(\name)
-.endm
-
 /* annotation for data we want in DCCM - if enabled in .config */
 .macro ARCFP_DATA nm
 #ifdef CONFIG_ARC_HAS_DCCM
index 65690e7..2ff0347 100644 (file)
@@ -62,4 +62,4 @@ __switch_to:
        ld.ab   blink, [sp, 4]
        j       [blink]
 
-ARC_EXIT __switch_to
+END(__switch_to)
index 47d09d0..819dd5f 100644 (file)
@@ -141,7 +141,7 @@ VECTOR   EV_Extension            ; 0x130, Extn Intruction Excp  (0x26)
 VECTOR   reserved                ; Reserved Exceptions
 .endr
 
-#include <linux/linkage.h>   /* ARC_{EXTRY,EXIT} */
+#include <linux/linkage.h>   /* {EXTRY,EXIT} */
 #include <asm/entry.h>       /* SAVE_ALL_{INT1,INT2,SYS...} */
 #include <asm/errno.h>
 #include <asm/arcregs.h>
@@ -184,7 +184,7 @@ reserved:           ; processor restart
 ; ---------------------------------------------
 ;  Level 2 ISR: Can interrupt a Level 1 ISR
 ; ---------------------------------------------
-ARC_ENTRY handle_interrupt_level2
+ENTRY(handle_interrupt_level2)
 
        ; TODO-vineetg for SMP this wont work
        ; free up r9 as scratchpad
@@ -225,14 +225,14 @@ ARC_ENTRY handle_interrupt_level2
 
        b   ret_from_exception
 
-ARC_EXIT handle_interrupt_level2
+END(handle_interrupt_level2)
 
 #endif
 
 ; ---------------------------------------------
 ;  Level 1 ISR
 ; ---------------------------------------------
-ARC_ENTRY handle_interrupt_level1
+ENTRY(handle_interrupt_level1)
 
        /* free up r9 as scratchpad */
 #ifdef CONFIG_SMP
@@ -265,7 +265,7 @@ ARC_ENTRY handle_interrupt_level1
        sr r8, [AUX_IRQ_LV12]       ; clear bit in Sticky Status Reg
 
        b   ret_from_exception
-ARC_EXIT handle_interrupt_level1
+END(handle_interrupt_level1)
 
 ;################### Non TLB Exception Handling #############################
 
@@ -273,7 +273,7 @@ ARC_EXIT handle_interrupt_level1
 ; Instruction Error Exception Handler
 ; ---------------------------------------------
 
-ARC_ENTRY instr_service
+ENTRY(instr_service)
 
        EXCEPTION_PROLOGUE
 
@@ -284,13 +284,13 @@ ARC_ENTRY instr_service
 
        bl  do_insterror_or_kprobe
        b   ret_from_exception
-ARC_EXIT instr_service
+END(instr_service)
 
 ; ---------------------------------------------
 ; Memory Error Exception Handler
 ; ---------------------------------------------
 
-ARC_ENTRY mem_service
+ENTRY(mem_service)
 
        EXCEPTION_PROLOGUE
 
@@ -301,13 +301,13 @@ ARC_ENTRY mem_service
 
        bl  do_memory_error
        b   ret_from_exception
-ARC_EXIT mem_service
+END(mem_service)
 
 ; ---------------------------------------------
 ; Machine Check Exception Handler
 ; ---------------------------------------------
 
-ARC_ENTRY EV_MachineCheck
+ENTRY(EV_MachineCheck)
 
        EXCEPTION_PROLOGUE
 
@@ -331,13 +331,13 @@ ARC_ENTRY EV_MachineCheck
 
        j  do_machine_check_fault
 
-ARC_EXIT EV_MachineCheck
+END(EV_MachineCheck)
 
 ; ---------------------------------------------
 ; Protection Violation Exception Handler
 ; ---------------------------------------------
 
-ARC_ENTRY EV_TLBProtV
+ENTRY(EV_TLBProtV)
 
        EXCEPTION_PROLOGUE
 
@@ -385,12 +385,12 @@ ARC_ENTRY EV_TLBProtV
 
        b   ret_from_exception
 
-ARC_EXIT EV_TLBProtV
+END(EV_TLBProtV)
 
 ; ---------------------------------------------
 ; Privilege Violation Exception Handler
 ; ---------------------------------------------
-ARC_ENTRY EV_PrivilegeV
+ENTRY(EV_PrivilegeV)
 
        EXCEPTION_PROLOGUE
 
@@ -401,12 +401,12 @@ ARC_ENTRY EV_PrivilegeV
 
        bl  do_privilege_fault
        b   ret_from_exception
-ARC_EXIT EV_PrivilegeV
+END(EV_PrivilegeV)
 
 ; ---------------------------------------------
 ; Extension Instruction Exception Handler
 ; ---------------------------------------------
-ARC_ENTRY EV_Extension
+ENTRY(EV_Extension)
 
        EXCEPTION_PROLOGUE
 
@@ -417,7 +417,7 @@ ARC_ENTRY EV_Extension
 
        bl  do_extension_fault
        b   ret_from_exception
-ARC_EXIT EV_Extension
+END(EV_Extension)
 
 ;######################### System Call Tracing #########################
 
@@ -504,7 +504,7 @@ trap_with_param:
 ;   (2) Break Points
 ;------------------------------------------------------------------
 
-ARC_ENTRY EV_Trap
+ENTRY(EV_Trap)
 
        EXCEPTION_PROLOGUE
 
@@ -534,9 +534,9 @@ ARC_ENTRY EV_Trap
        jl      [r9]        ; Entry into Sys Call Handler
 
        ; fall through to ret_from_system_call
-ARC_EXIT EV_Trap
+END(EV_Trap)
 
-ARC_ENTRY ret_from_system_call
+ENTRY(ret_from_system_call)
 
        st  r0, [sp, PT_r0]     ; sys call return value in pt_regs
 
@@ -546,7 +546,7 @@ ARC_ENTRY ret_from_system_call
 ;
 ; If ret to user mode do we need to handle signals, schedule() et al.
 
-ARC_ENTRY ret_from_exception
+ENTRY(ret_from_exception)
 
        ; Pre-{IRQ,Trap,Exception} K/U mode from pt_regs->status32
        ld  r8, [sp, PT_status32]   ; returning to User/Kernel Mode
@@ -726,9 +726,9 @@ not_level1_interrupt:
 debug_marker_syscall:
        rtie
 
-ARC_EXIT ret_from_exception
+END(ret_from_exception)
 
-ARC_ENTRY ret_from_fork
+ENTRY(ret_from_fork)
        ; when the forked child comes here from the __switch_to function
        ; r0 has the last task pointer.
        ; put last task in scheduler queue
@@ -745,11 +745,11 @@ ARC_ENTRY ret_from_fork
        ; special case of kernel_thread entry point returning back due to
        ; kernel_execve() - pretend return from syscall to ret to userland
        b    ret_from_exception
-ARC_EXIT ret_from_fork
+END(ret_from_fork)
 
 ;################### Special Sys Call Wrappers ##########################
 
-ARC_ENTRY sys_clone_wrapper
+ENTRY(sys_clone_wrapper)
        SAVE_CALLEE_SAVED_USER
        bl  @sys_clone
        DISCARD_CALLEE_SAVED_USER
@@ -759,7 +759,7 @@ ARC_ENTRY sys_clone_wrapper
        bnz  tracesys_exit
 
        b ret_from_system_call
-ARC_EXIT sys_clone_wrapper
+END(sys_clone_wrapper)
 
 #ifdef CONFIG_ARC_DW2_UNWIND
 ; Workaround for bug 94179 (STAR ):
index 9919972..4ad0491 100644 (file)
        .globl stext
 stext:
        ;-------------------------------------------------------------------
-       ; Don't clobber r0-r4 yet. It might have bootloader provided info
+       ; Don't clobber r0-r2 yet. It might have bootloader provided info
        ;-------------------------------------------------------------------
 
        sr      @_int_vec_base_lds, [AUX_INTR_VEC_BASE]
 
 #ifdef CONFIG_SMP
-       ; Only Boot (Master) proceeds. Others wait in platform dependent way
+       ; Ensure Boot (Master) proceeds. Others wait in platform dependent way
        ;       IDENTITY Reg [ 3  2  1  0 ]
        ;       (cpu-id)             ^^^        => Zero for UP ARC700
        ;                                       => #Core-ID if SMP (Master 0)
@@ -39,7 +39,8 @@ stext:
        ; need to make sure only boot cpu takes this path.
        GET_CPU_ID  r5
        cmp     r5, 0
-       jnz     arc_platform_smp_wait_to_boot
+       mov.ne  r0, r5
+       jne     arc_platform_smp_wait_to_boot
 #endif
        ; Clear BSS before updating any globals
        ; XXX: use ZOL here
index e5f3a83..71c4252 100644 (file)
@@ -155,22 +155,6 @@ static void arc_timer_event_setup(unsigned int limit)
        write_aux_reg(ARC_REG_TIMER0_CTRL, TIMER_CTRL_IE | TIMER_CTRL_NH);
 }
 
-/*
- * Acknowledge the interrupt (oneshot) and optionally re-arm it (periodic)
- * -Any write to CTRL Reg will ack the intr (NH bit: Count when not halted)
- * -Rearming is done by setting the IE bit
- *
- * Small optimisation: Normal code would have been
- *   if (irq_reenable)
- *     CTRL_REG = (IE | NH);
- *   else
- *     CTRL_REG = NH;
- * However since IE is BIT0 we can fold the branch
- */
-static void arc_timer_event_ack(unsigned int irq_reenable)
-{
-       write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH);
-}
 
 static int arc_clkevent_set_next_event(unsigned long delta,
                                       struct clock_event_device *dev)
@@ -207,10 +191,22 @@ static DEFINE_PER_CPU(struct clock_event_device, arc_clockevent_device) = {
 
 static irqreturn_t timer_irq_handler(int irq, void *dev_id)
 {
-       struct clock_event_device *clk = this_cpu_ptr(&arc_clockevent_device);
+       /*
+        * Note that generic IRQ core could have passed @evt for @dev_id if
+        * irq_set_chip_and_handler() asked for handle_percpu_devid_irq()
+        */
+       struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
+       int irq_reenable = evt->mode == CLOCK_EVT_MODE_PERIODIC;
+
+       /*
+        * Any write to CTRL reg ACks the interrupt, we rewrite the
+        * Count when [N]ot [H]alted bit.
+        * And re-arm it if perioid by [I]nterrupt [E]nable bit
+        */
+       write_aux_reg(ARC_REG_TIMER0_CTRL, irq_reenable | TIMER_CTRL_NH);
+
+       evt->event_handler(evt);
 
-       arc_timer_event_ack(clk->mode == CLOCK_EVT_MODE_PERIODIC);
-       clk->event_handler(clk);
        return IRQ_HANDLED;
 }
 
@@ -222,9 +218,8 @@ static struct irqaction arc_timer_irq = {
 
 /*
  * Setup the local event timer for @cpu
- * N.B. weak so that some exotic ARC SoCs can completely override it
  */
-void __weak arc_local_timer_setup(unsigned int cpu)
+void arc_local_timer_setup(unsigned int cpu)
 {
        struct clock_event_device *clk = &per_cpu(arc_clockevent_device, cpu);
 
index bc813d5..978bf83 100644 (file)
@@ -6,7 +6,7 @@
  * published by the Free Software Foundation.
  */
 
-#include <asm/linkage.h>
+#include <linux/linkage.h>
 
 #ifdef __LITTLE_ENDIAN__
 #define WORD2 r2
@@ -16,7 +16,7 @@
 #define SHIFT r2
 #endif
 
-ARC_ENTRY memcmp
+ENTRY(memcmp)
        or      r12,r0,r1
        asl_s   r12,r12,30
        sub     r3,r2,1
@@ -121,4 +121,4 @@ ARC_ENTRY memcmp
 .Lnil:
        j_s.d   [blink]
        mov     r0,0
-ARC_EXIT memcmp
+END(memcmp)
index b64cc10..3222573 100644 (file)
@@ -6,9 +6,9 @@
  * published by the Free Software Foundation.
  */
 
-#include <asm/linkage.h>
+#include <linux/linkage.h>
 
-ARC_ENTRY memcpy
+ENTRY(memcpy)
        or      r3,r0,r1
        asl_s   r3,r3,30
        mov_s   r5,r0
@@ -63,4 +63,4 @@ ARC_ENTRY memcpy
 .Lendbloop:
        j_s.d   [blink]
        stb     r12,[r5,0]
-ARC_EXIT memcpy
+END(memcpy)
index 9b2d88d..d36bd43 100644 (file)
@@ -6,11 +6,11 @@
  * published by the Free Software Foundation.
  */
 
-#include <asm/linkage.h>
+#include <linux/linkage.h>
 
 #define SMALL  7 /* Must be at least 6 to deal with alignment/loop issues.  */
 
-ARC_ENTRY memset
+ENTRY(memset)
        mov_s   r4,r0
        or      r12,r0,r2
        bmsk.f  r12,r12,1
@@ -46,14 +46,14 @@ ARC_ENTRY memset
        stb.ab  r1,[r4,1]
 .Ltiny_end:
        j_s     [blink]
-ARC_EXIT memset
+END(memset)
 
 ; memzero: @r0 = mem, @r1 = size_t
 ; memset:  @r0 = mem, @r1 = char, @r2 = size_t
 
-ARC_ENTRY memzero
+ENTRY(memzero)
     ; adjust bzero args to memset args
     mov r2, r1
     mov r1, 0
     b  memset    ;tail call so need to tinker with blink
-ARC_EXIT memzero
+END(memzero)
index 9c548c7..b725d58 100644 (file)
@@ -11,9 +11,9 @@
    presence of the norm instruction makes it easier to operate on whole
    words branch-free.  */
 
-#include <asm/linkage.h>
+#include <linux/linkage.h>
 
-ARC_ENTRY strchr
+ENTRY(strchr)
        extb_s  r1,r1
        asl     r5,r1,8
        bmsk    r2,r0,1
@@ -130,4 +130,4 @@ ARC_ENTRY strchr
        j_s.d   [blink]
        mov.mi  r0,0
 #endif /* ENDIAN */
-ARC_EXIT strchr
+END(strchr)
index 5dc802b..3544600 100644 (file)
@@ -13,9 +13,9 @@
    source 1; however, that would increase the overhead for loop setup / finish,
    and strcmp might often terminate early.  */
 
-#include <asm/linkage.h>
+#include <linux/linkage.h>
 
-ARC_ENTRY strcmp
+ENTRY(strcmp)
        or      r2,r0,r1
        bmsk_s  r2,r2,1
        brne    r2,0,.Lcharloop
@@ -93,4 +93,4 @@ ARC_ENTRY strcmp
 .Lcmpend:
        j_s.d   [blink]
        sub     r0,r2,r3
-ARC_EXIT strcmp
+END(strcmp)
index b7ca4ae..8422f38 100644 (file)
@@ -16,9 +16,9 @@
    there, but the it is not likely to be taken often, and it
    would also be likey to cost an unaligned mispredict at the next call.  */
 
-#include <asm/linkage.h>
+#include <linux/linkage.h>
 
-ARC_ENTRY strcpy
+ENTRY(strcpy)
        or      r2,r0,r1
        bmsk_s  r2,r2,1
        brne.d  r2,0,charloop
@@ -67,4 +67,4 @@ charloop:
        brne.d  r3,0,charloop
        stb.ab  r3,[r10,1]
        j       [blink]
-ARC_EXIT strcpy
+END(strcpy)
index 39759e0..53cfd56 100644 (file)
@@ -6,9 +6,9 @@
  * published by the Free Software Foundation.
  */
 
-#include <asm/linkage.h>
+#include <linux/linkage.h>
 
-ARC_ENTRY strlen
+ENTRY(strlen)
        or      r3,r0,7
        ld      r2,[r3,-7]
        ld.a    r6,[r3,-3]
@@ -80,4 +80,4 @@ ARC_ENTRY strlen
 .Learly_end:
        b.d     .Lend
        sub_s.ne r1,r1,r1
-ARC_EXIT strlen
+END(strlen)
index 400c663..89edf79 100644 (file)
 #define DC_CTRL_INV_MODE_FLUSH  0x40
 #define DC_CTRL_FLUSH_STATUS    0x100
 
-char *arc_cache_mumbojumbo(int cpu_id, char *buf, int len)
+char *arc_cache_mumbojumbo(int c, char *buf, int len)
 {
        int n = 0;
-       unsigned int c = smp_processor_id();
 
 #define PR_CACHE(p, enb, str)                                          \
 {                                                                      \
index 55e0a85..5234123 100644 (file)
@@ -10,6 +10,9 @@
 #include <linux/mm.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
+#ifdef CONFIG_BLK_DEV_INITRD
+#include <linux/initrd.h>
+#endif
 #include <linux/swap.h>
 #include <linux/module.h>
 #include <asm/page.h>
@@ -42,6 +45,24 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        pr_info("Memory size set via devicetree %ldM\n", TO_MB(arc_mem_sz));
 }
 
+#ifdef CONFIG_BLK_DEV_INITRD
+static int __init early_initrd(char *p)
+{
+       unsigned long start, size;
+       char *endp;
+
+       start = memparse(p, &endp);
+       if (*endp == ',') {
+               size = memparse(endp + 1, NULL);
+
+               initrd_start = (unsigned long)__va(start);
+               initrd_end = (unsigned long)__va(start + size);
+       }
+       return 0;
+}
+early_param("initrd", early_initrd);
+#endif
+
 /*
  * First memory setup routine called from setup_arch()
  * 1. setup swapper's mm @init_mm
@@ -80,6 +101,12 @@ void __init setup_arch_memory(void)
        memblock_reserve(CONFIG_LINUX_LINK_BASE,
                         __pa(_end) - CONFIG_LINUX_LINK_BASE);
 
+#ifdef CONFIG_BLK_DEV_INITRD
+       /*------------- reserve initrd image -----------------------*/
+       if (initrd_start)
+               memblock_reserve(__pa(initrd_start), initrd_end - initrd_start);
+#endif
+
        memblock_dump_all();
 
        /*-------------- node setup --------------------------------*/
index 3fcfdb3..79bfc81 100644 (file)
@@ -260,7 +260,7 @@ ARCFP_CODE  ;Fast Path Code, candidate for ICCM
 ; I-TLB Miss Exception Handler
 ;-----------------------------------------------------------------------------
 
-ARC_ENTRY EV_TLBMissI
+ENTRY(EV_TLBMissI)
 
        TLBMISS_FREEUP_REGS
 
@@ -293,13 +293,13 @@ ARC_ENTRY EV_TLBMissI
        TLBMISS_RESTORE_REGS
        rtie
 
-ARC_EXIT EV_TLBMissI
+END(EV_TLBMissI)
 
 ;-----------------------------------------------------------------------------
 ; D-TLB Miss Exception Handler
 ;-----------------------------------------------------------------------------
 
-ARC_ENTRY EV_TLBMissD
+ENTRY(EV_TLBMissD)
 
        TLBMISS_FREEUP_REGS
 
@@ -381,6 +381,4 @@ do_slow_path_pf:
        bl  do_page_fault
        b   ret_from_exception
 
-ARC_EXIT EV_TLBMissD
-
-ARC_ENTRY EV_TLBMissB   ; Bogus entry to measure sz of DTLBMiss hdlr
+END(EV_TLBMissD)
index 295cefe..33058aa 100644 (file)
@@ -33,7 +33,6 @@ config ISS_SMP_EXTN
        bool "ARC SMP Extensions (ISS Models only)"
        default n
        depends on SMP
-       select ARC_HAS_COH_RTSC
        help
          SMP Extensions to ARC700, in a "simulation only" Model, supported in
          ARC ISS (Instruction Set Simulator).
index d71f3c3..19b76b6 100644 (file)
@@ -201,7 +201,7 @@ static void __init plat_fpga_populate_dev(void)
  * callback set, by matching the DT compatible name.
  */
 
-static const char *aa4_compat[] __initdata = {
+static const char *aa4_compat[] __initconst = {
        "snps,arc-angel4",
        NULL,
 };
@@ -216,7 +216,7 @@ MACHINE_START(ANGEL4, "angel4")
 #endif
 MACHINE_END
 
-static const char *ml509_compat[] __initdata = {
+static const char *ml509_compat[] __initconst = {
        "snps,arc-ml509",
        NULL,
 };
@@ -231,7 +231,7 @@ MACHINE_START(ML509, "ml509")
 #endif
 MACHINE_END
 
-static const char *nsimosci_compat[] __initdata = {
+static const char *nsimosci_compat[] __initconst = {
        "snps,nsimosci",
        NULL,
 };
index d7a71e3..5db05f6 100644 (file)
@@ -126,7 +126,7 @@ config HAVE_TCM
 config HAVE_PROC_CPU
        bool
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        bool
 
 config EISA
@@ -410,7 +410,7 @@ config ARCH_EBSA110
        select ISA
        select NEED_MACH_IO_H
        select NEED_MACH_MEMORY_H
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        help
          This is an evaluation board for the StrongARM processor available
          from Digital. It has limited hardware on-board, including an
@@ -428,7 +428,7 @@ config ARCH_EFM32
        select CPU_V7M
        select GENERIC_CLOCKEVENTS
        select NO_DMA
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select SPARSE_IRQ
        select USE_OF
        help
@@ -677,7 +677,7 @@ config ARCH_SHMOBILE_LEGACY
        select HAVE_SMP
        select MIGHT_HAVE_CACHE_L2X0
        select MULTI_IRQ_HANDLER
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select PINCTRL
        select PM_GENERIC_DOMAINS if PM
        select SPARSE_IRQ
@@ -699,7 +699,7 @@ config ARCH_RPC
        select ISA_DMA_API
        select NEED_MACH_IO_H
        select NEED_MACH_MEMORY_H
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select VIRT_TO_BUS
        help
          On the Acorn Risc-PC, Linux can support the internal IDE disk and
@@ -760,7 +760,7 @@ config ARCH_S3C64XX
        select HAVE_S3C2410_I2C if I2C
        select HAVE_S3C2410_WATCHDOG if WATCHDOG
        select HAVE_TCM
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select PLAT_SAMSUNG
        select PM_GENERIC_DOMAINS if PM
        select S3C_DEV_NAND
index 55d3f79..9d72674 100644 (file)
                                reg = <0xb00b0000 0x10000>;
                                interrupts = <12>;
                                clocks = <&clks 24>;
+                               #dma-cells = <1>;
                        };
 
                        dmac1: dma-controller@b0160000 {
                                reg = <0xb0160000 0x10000>;
                                interrupts = <13>;
                                clocks = <&clks 25>;
+                               #dma-cells = <1>;
                        };
 
                        vip@b00C0000 {
index 9e3caf3..1c0f8e1 100644 (file)
                        ti,hwmods = "counter_32k";
                };
 
+               dra7_ctrl_general: tisyscon@4a002e00 {
+                       compatible = "syscon";
+                       reg = <0x4a002e00 0x7c>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0 0x4>;
+                       syscon = <&dra7_ctrl_general>;
+                       pbias_mmc_reg: pbias_mmc_omap5 {
+                               regulator-name = "pbias_mmc_omap5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                dra7_pmx_core: pinmux@4a003400 {
                        compatible = "pinctrl-single";
                        reg = <0x4a003400 0x0464>;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
                        status = "disabled";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
index 0401f4d..2f8bcd0 100644 (file)
                reg = <0x10010000 0x400>;
        };
 
+       dsi_0: dsi@11C80000 {
+               compatible = "samsung,exynos4210-mipi-dsi";
+               reg = <0x11C80000 0x10000>;
+               interrupts = <0 79 0>;
+               samsung,power-domain = <&pd_lcd0>;
+               phys = <&mipi_phy 1>;
+               phy-names = "dsim";
+               clocks = <&clock 286>, <&clock 143>;
+               clock-names = "bus_clk", "pll_clk";
+               status = "disabled";
+               #address-cells = <1>;
+               #size-cells = <0>;
+       };
+
        camera {
                compatible = "samsung,fimc", "simple-bus";
                status = "disabled";
index 361cb58..63aa2bb 100644 (file)
                };
        };
 
+       dsi_0: dsi@11C80000 {
+               vddcore-supply = <&vusb_reg>;
+               vddio-supply = <&vmipi_reg>;
+               samsung,pll-clock-frequency = <24000000>;
+               status = "okay";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@1 {
+                               reg = <1>;
+
+                               dsi_out: endpoint {
+                                       remote-endpoint = <&dsi_in>;
+                                       samsung,burst-clock-frequency = <500000000>;
+                                       samsung,esc-clock-frequency = <20000000>;
+                               };
+                       };
+               };
+
+               panel@0 {
+                       reg = <0>;
+                       compatible = "samsung,s6e8aa0";
+                       vdd3-supply = <&vcclcd_reg>;
+                       vci-supply = <&vlcd_reg>;
+                       reset-gpios = <&gpy4 5 0>;
+                       power-on-delay= <50>;
+                       reset-delay = <100>;
+                       init-delay = <100>;
+                       flip-horizontal;
+                       flip-vertical;
+                       panel-width-mm = <58>;
+                       panel-height-mm = <103>;
+
+                       display-timings {
+                               timing-0 {
+                                       clock-frequency = <57153600>;
+                                       hactive = <720>;
+                                       vactive = <1280>;
+                                       hfront-porch = <5>;
+                                       hback-porch = <5>;
+                                       hsync-len = <5>;
+                                       vfront-porch = <13>;
+                                       vback-porch = <1>;
+                                       vsync-len = <2>;
+                               };
+                       };
+
+                       port {
+                               dsi_in: endpoint {
+                                       remote-endpoint = <&dsi_out>;
+                               };
+                       };
+               };
+       };
+
+       fimd@11c00000 {
+               status = "okay";
+       };
+
        camera {
                pinctrl-names = "default";
                pinctrl-0 = <>;
index 27d3b70..63e34b2 100644 (file)
                };
        };
 
+       spi-lcd {
+               compatible = "spi-gpio";
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               gpio-sck = <&gpy3 1 0>;
+               gpio-mosi = <&gpy3 3 0>;
+               num-chipselects = <1>;
+               cs-gpios = <&gpy4 3 0>;
+
+               lcd@0 {
+                       compatible = "samsung,ld9040";
+                       reg = <0>;
+                       vdd3-supply = <&ldo7_reg>;
+                       vci-supply = <&ldo17_reg>;
+                       reset-gpios = <&gpy4 5 0>;
+                       spi-max-frequency = <1200000>;
+                       spi-cpol;
+                       spi-cpha;
+                       power-on-delay = <10>;
+                       reset-delay = <10>;
+                       panel-width-mm = <90>;
+                       panel-height-mm = <154>;
+                       display-timings {
+                               timing {
+                                       clock-frequency = <23492370>;
+                                       hactive = <480>;
+                                       vactive = <800>;
+                                       hback-porch = <16>;
+                                       hfront-porch = <16>;
+                                       vback-porch = <2>;
+                                       vfront-porch = <28>;
+                                       hsync-len = <2>;
+                                       vsync-len = <1>;
+                                       hsync-active = <0>;
+                                       vsync-active = <0>;
+                                       de-active = <0>;
+                                       pixelclk-active = <0>;
+                               };
+                       };
+                       port {
+                               lcd_ep: endpoint {
+                                       remote-endpoint = <&fimd_dpi_ep>;
+                               };
+                       };
+               };
+       };
+
+       fimd: fimd@11c00000 {
+               pinctrl-0 = <&lcd_clk>, <&lcd_data24>;
+               pinctrl-names = "default";
+               status = "okay";
+               samsung,invert-vden;
+               samsung,invert-vclk;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               port@3 {
+                       reg = <3>;
+                       fimd_dpi_ep: endpoint {
+                               remote-endpoint = <&lcd_ep>;
+                       };
+               };
+       };
+
        pwm@139D0000 {
                compatible = "samsung,s5p6440-pwm";
                status = "okay";
index c16b315..9583563 100644 (file)
                        enable-active-high;
                };
 
+               lcd_vdd3_reg: voltage-regulator-2 {
+                       compatible = "regulator-fixed";
+                       regulator-name = "LCD_VDD_2.2V";
+                       regulator-min-microvolt = <2200000>;
+                       regulator-max-microvolt = <2200000>;
+                       gpio = <&gpc0 1 0>;
+                       enable-active-high;
+               };
+
                /* More to come */
        };
 
                };
        };
 
+       dsi_0: dsi@11C80000 {
+               vddcore-supply = <&ldo8_reg>;
+               vddio-supply = <&ldo10_reg>;
+               samsung,pll-clock-frequency = <24000000>;
+               status = "okay";
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@1 {
+                               reg = <1>;
+
+                               dsi_out: endpoint {
+                                       remote-endpoint = <&dsi_in>;
+                                       samsung,burst-clock-frequency = <500000000>;
+                                       samsung,esc-clock-frequency = <20000000>;
+                               };
+                       };
+               };
+
+               panel@0 {
+                       compatible = "samsung,s6e8aa0";
+                       reg = <0>;
+                       vdd3-supply = <&lcd_vdd3_reg>;
+                       vci-supply = <&ldo25_reg>;
+                       reset-gpios = <&gpy4 5 0>;
+                       power-on-delay= <50>;
+                       reset-delay = <100>;
+                       init-delay = <100>;
+                       flip-horizontal;
+                       flip-vertical;
+                       panel-width-mm = <58>;
+                       panel-height-mm = <103>;
+
+                       display-timings {
+                               timing-0 {
+                                       clock-frequency = <0>;
+                                       hactive = <720>;
+                                       vactive = <1280>;
+                                       hfront-porch = <5>;
+                                       hback-porch = <5>;
+                                       hsync-len = <5>;
+                                       vfront-porch = <13>;
+                                       vback-porch = <1>;
+                                       vsync-len = <2>;
+                               };
+                       };
+
+                       port {
+                               dsi_in: endpoint {
+                                       remote-endpoint = <&dsi_out>;
+                               };
+                       };
+               };
+       };
+
+       fimd@11c00000 {
+               status = "okay";
+       };
+
        camera {
                pinctrl-0 = <&cam_port_b_clk_active>;
                pinctrl-names = "default";
index 5377ddf..22f35ea 100644 (file)
                        ti,hwmods = "timer12";
                        ti,timer-pwm;
                };
+
+               dss: dss@48050000 {
+                       compatible = "ti,omap2-dss";
+                       reg = <0x48050000 0x400>;
+                       status = "disabled";
+                       ti,hwmods = "dss_core";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       dispc@48050400 {
+                               compatible = "ti,omap2-dispc";
+                               reg = <0x48050400 0x400>;
+                               interrupts = <25>;
+                               ti,hwmods = "dss_dispc";
+                       };
+
+                       rfbi: encoder@48050800 {
+                               compatible = "ti,omap2-rfbi";
+                               reg = <0x48050800 0x400>;
+                               status = "disabled";
+                               ti,hwmods = "dss_rfbi";
+                       };
+
+                       venc: encoder@48050c00 {
+                               compatible = "ti,omap2-venc";
+                               reg = <0x48050c00 0x400>;
+                               status = "disabled";
+                               ti,hwmods = "dss_venc";
+                       };
+               };
        };
 };
index 9d2f028..d09697d 100644 (file)
                        pinctrl-single,function-mask = <0x3f>;
                };
 
+               omap2_scm_general: tisyscon@49002270 {
+                       compatible = "syscon";
+                       reg = <0x49002270 0x240>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0x230 0x4>;
+                       syscon = <&omap2_scm_general>;
+                       pbias_mmc_reg: pbias_mmc_omap2430 {
+                               regulator-name = "pbias_mmc_omap2430";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                gpio1: gpio@4900c000 {
                        compatible = "ti,omap2-gpio";
                        reg = <0x4900c000 0x200>;
                        ti,dual-volt;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
index cba3570..cf0be66 100644 (file)
                reg = <0x80000000 0x20000000>; /* 512 MB */
        };
 
+       aliases {
+               display0 = &dvi0;
+               display1 = &tv0;
+       };
+
        leds {
                compatible = "gpio-leds";
 
                reset-gpios = <&gpio5 19 GPIO_ACTIVE_LOW>; /* gpio_147 */
                vcc-supply = <&hsusb2_power>;
        };
+
+       tfp410: encoder@0 {
+               compatible = "ti,tfp410";
+               powerdown-gpios = <&twl_gpio 2 GPIO_ACTIVE_LOW>;
+
+               /* XXX pinctrl from twl */
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tfp410_in: endpoint@0 {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tfp410_out: endpoint@0 {
+                                       remote-endpoint = <&dvi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       dvi0: connector@0 {
+               compatible = "dvi-connector";
+               label = "dvi";
+
+               digital;
+
+               ddc-i2c-bus = <&i2c3>;
+
+               port {
+                       dvi_connector_in: endpoint {
+                               remote-endpoint = <&tfp410_out>;
+                       };
+               };
+       };
+
+       tv0: connector@1 {
+               compatible = "svideo-connector";
+               label = "tv";
+
+               port {
+                       tv_connector_in: endpoint {
+                               remote-endpoint = <&venc_out>;
+                       };
+               };
+       };
 };
 
 &omap3_pmx_wkup {
                        0x0e (PIN_INPUT | PIN_OFF_WAKEUPENABLE | MUX_MODE4) /* sys_boot2.gpio_4 */
                >;
        };
+
+       dss_dpi_pins2: pinmux_dss_dpi_pins1 {
+               pinctrl-single,pins = <
+                       0x0a (PIN_OUTPUT | MUX_MODE3)   /* sys_boot0.dss_data18 */
+                       0x0c (PIN_OUTPUT | MUX_MODE3)   /* sys_boot1.dss_data19 */
+                       0x10 (PIN_OUTPUT | MUX_MODE3)   /* sys_boot3.dss_data20 */
+                       0x12 (PIN_OUTPUT | MUX_MODE3)   /* sys_boot4.dss_data21 */
+                       0x14 (PIN_OUTPUT | MUX_MODE3)   /* sys_boot5.dss_data22 */
+                       0x16 (PIN_OUTPUT | MUX_MODE3)   /* sys_boot6.dss_data23 */
+               >;
+       };
 };
 
 &omap3_pmx_core {
                        OMAP3_CORE1_IOPAD(0x21de, PIN_INPUT_PULLDOWN | MUX_MODE3)       /* mcspi2_cs1.hsusb2_data3 */
                >;
        };
+
+       dss_dpi_pins1: pinmux_dss_dpi_pins2 {
+               pinctrl-single,pins = <
+                       OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT | MUX_MODE0)   /* dss_pclk.dss_pclk */
+                       OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT | MUX_MODE0)   /* dss_hsync.dss_hsync */
+                       OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT | MUX_MODE0)   /* dss_vsync.dss_vsync */
+                       OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT | MUX_MODE0)   /* dss_acbias.dss_acbias */
+
+                       OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT | MUX_MODE0)   /* dss_data6.dss_data6 */
+                       OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT | MUX_MODE0)   /* dss_data7.dss_data7 */
+                       OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT | MUX_MODE0)   /* dss_data8.dss_data8 */
+                       OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT | MUX_MODE0)   /* dss_data9.dss_data9 */
+                       OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT | MUX_MODE0)   /* dss_data10.dss_data10 */
+                       OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT | MUX_MODE0)   /* dss_data11.dss_data11 */
+                       OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT | MUX_MODE0)   /* dss_data12.dss_data12 */
+                       OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT | MUX_MODE0)   /* dss_data13.dss_data13 */
+                       OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT | MUX_MODE0)   /* dss_data14.dss_data14 */
+                       OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT | MUX_MODE0)   /* dss_data15.dss_data15 */
+                       OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT | MUX_MODE0)   /* dss_data16.dss_data16 */
+                       OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE0)   /* dss_data17.dss_data17 */
+
+                       OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT | MUX_MODE3)   /* dss_data18.dss_data0 */
+                       OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT | MUX_MODE3)   /* dss_data19.dss_data1 */
+                       OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT | MUX_MODE3)   /* dss_data20.dss_data2 */
+                       OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT | MUX_MODE3)   /* dss_data21.dss_data3 */
+                       OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE3)   /* dss_data22.dss_data4 */
+                       OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE3)   /* dss_data23.dss_data5 */
+               >;
+       };
 };
 
 &omap3_pmx_core2 {
 
 &i2c3 {
        clock-frequency = <100000>;
-
-       /*
-        * Display monitor features are burnt in the EEPROM
-        * as EDID data.
-        */
-       eeprom@50 {
-               compatible = "ti,eeprom";
-               reg = <0x50>;
-       };
 };
 
 &mmc1 {
 &mcbsp2 {
        status = "okay";
 };
+
+&dss {
+       status = "ok";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <
+               &dss_dpi_pins1
+               &dss_dpi_pins2
+       >;
+
+       port {
+               dpi_out: endpoint {
+                       remote-endpoint = <&tfp410_in>;
+                       data-lines = <24>;
+               };
+       };
+};
+
+&venc {
+       status = "ok";
+
+       vdda-supply = <&vdac>;
+
+       port {
+               venc_out: endpoint {
+                       remote-endpoint = <&tv_connector_in>;
+                       ti,channels = <2>;
+               };
+       };
+};
index d01e9a7..3c3e6da 100644 (file)
                reg = <0x80000000 0x10000000>; /* 256 MB */
        };
 
+       aliases {
+               display0 = &dvi0;
+               display1 = &tv0;
+       };
+
        leds {
                compatible = "gpio-leds";
                pmu_stat {
                };
 
        };
+
+       tfp410: encoder@0 {
+               compatible = "ti,tfp410";
+               powerdown-gpios = <&gpio6 10 GPIO_ACTIVE_LOW>;  /* gpio_170 */
+
+               pinctrl-names = "default";
+               pinctrl-0 = <&tfp410_pins>;
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tfp410_in: endpoint@0 {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tfp410_out: endpoint@0 {
+                                       remote-endpoint = <&dvi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       dvi0: connector@0 {
+               compatible = "dvi-connector";
+               label = "dvi";
+
+               digital;
+
+               ddc-i2c-bus = <&i2c3>;
+
+               port {
+                       dvi_connector_in: endpoint {
+                               remote-endpoint = <&tfp410_out>;
+                       };
+               };
+       };
+
+       tv0: connector@1 {
+               compatible = "svideo-connector";
+               label = "tv";
+
+               port {
+                       tv_connector_in: endpoint {
+                               remote-endpoint = <&venc_out>;
+                       };
+               };
+       };
 };
 
 &omap3_pmx_wkup {
                        0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx_irtx.uart3_tx_irtx */
                >;
        };
+
+       tfp410_pins: pinmux_tfp410_pins {
+               pinctrl-single,pins = <
+                       0x194 (PIN_OUTPUT | MUX_MODE4)  /* hdq_sio.gpio_170 */
+               >;
+       };
+
+       dss_dpi_pins: pinmux_dss_dpi_pins {
+               pinctrl-single,pins = <
+                       0x0a4 (PIN_OUTPUT | MUX_MODE0)   /* dss_pclk.dss_pclk */
+                       0x0a6 (PIN_OUTPUT | MUX_MODE0)   /* dss_hsync.dss_hsync */
+                       0x0a8 (PIN_OUTPUT | MUX_MODE0)   /* dss_vsync.dss_vsync */
+                       0x0aa (PIN_OUTPUT | MUX_MODE0)   /* dss_acbias.dss_acbias */
+                       0x0ac (PIN_OUTPUT | MUX_MODE0)   /* dss_data0.dss_data0 */
+                       0x0ae (PIN_OUTPUT | MUX_MODE0)   /* dss_data1.dss_data1 */
+                       0x0b0 (PIN_OUTPUT | MUX_MODE0)   /* dss_data2.dss_data2 */
+                       0x0b2 (PIN_OUTPUT | MUX_MODE0)   /* dss_data3.dss_data3 */
+                       0x0b4 (PIN_OUTPUT | MUX_MODE0)   /* dss_data4.dss_data4 */
+                       0x0b6 (PIN_OUTPUT | MUX_MODE0)   /* dss_data5.dss_data5 */
+                       0x0b8 (PIN_OUTPUT | MUX_MODE0)   /* dss_data6.dss_data6 */
+                       0x0ba (PIN_OUTPUT | MUX_MODE0)   /* dss_data7.dss_data7 */
+                       0x0bc (PIN_OUTPUT | MUX_MODE0)   /* dss_data8.dss_data8 */
+                       0x0be (PIN_OUTPUT | MUX_MODE0)   /* dss_data9.dss_data9 */
+                       0x0c0 (PIN_OUTPUT | MUX_MODE0)   /* dss_data10.dss_data10 */
+                       0x0c2 (PIN_OUTPUT | MUX_MODE0)   /* dss_data11.dss_data11 */
+                       0x0c4 (PIN_OUTPUT | MUX_MODE0)   /* dss_data12.dss_data12 */
+                       0x0c6 (PIN_OUTPUT | MUX_MODE0)   /* dss_data13.dss_data13 */
+                       0x0c8 (PIN_OUTPUT | MUX_MODE0)   /* dss_data14.dss_data14 */
+                       0x0ca (PIN_OUTPUT | MUX_MODE0)   /* dss_data15.dss_data15 */
+                       0x0cc (PIN_OUTPUT | MUX_MODE0)   /* dss_data16.dss_data16 */
+                       0x0ce (PIN_OUTPUT | MUX_MODE0)   /* dss_data17.dss_data17 */
+                       0x0d0 (PIN_OUTPUT | MUX_MODE0)   /* dss_data18.dss_data18 */
+                       0x0d2 (PIN_OUTPUT | MUX_MODE0)   /* dss_data19.dss_data19 */
+                       0x0d4 (PIN_OUTPUT | MUX_MODE0)   /* dss_data20.dss_data20 */
+                       0x0d6 (PIN_OUTPUT | MUX_MODE0)   /* dss_data21.dss_data21 */
+                       0x0d8 (PIN_OUTPUT | MUX_MODE0)   /* dss_data22.dss_data22 */
+                       0x0da (PIN_OUTPUT | MUX_MODE0)   /* dss_data23.dss_data23 */
+               >;
+       };
 };
 
 &omap3_pmx_core2 {
 #include "twl4030.dtsi"
 #include "twl4030_omap3.dtsi"
 
+&i2c3 {
+       clock-frequency = <100000>;
+};
+
 &mmc1 {
        vmmc-supply = <&vmmc1>;
        vmmc_aux-supply = <&vsim>;
 &mcbsp2 {
        status = "okay";
 };
+
+/* Needed to power the DPI pins */
+&vpll2 {
+       regulator-always-on;
+};
+
+&dss {
+       status = "ok";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&dss_dpi_pins>;
+
+       port {
+               dpi_out: endpoint {
+                       remote-endpoint = <&tfp410_in>;
+                       data-lines = <24>;
+               };
+       };
+};
+
+&venc {
+       status = "ok";
+
+       vdda-supply = <&vdac>;
+
+       port {
+               venc_out: endpoint {
+                       remote-endpoint = <&tv_connector_in>;
+                       ti,channels = <2>;
+               };
+       };
+};
index f2779ac..7abd64f 100644 (file)
                reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>; /* gpio_24 */
                vcc-supply = <&hsusb1_power>;
        };
+
+       tfp410: encoder@0 {
+               compatible = "ti,tfp410";
+               powerdown-gpios = <&gpio6 10 GPIO_ACTIVE_LOW>; /* gpio_170 */
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tfp410_in: endpoint@0 {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tfp410_out: endpoint@0 {
+                                       remote-endpoint = <&dvi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       dvi0: connector@0 {
+               compatible = "dvi-connector";
+               label = "dvi";
+
+               digital;
+
+               ddc-i2c-bus = <&i2c3>;
+
+               port {
+                       dvi_connector_in: endpoint {
+                               remote-endpoint = <&tfp410_out>;
+                       };
+               };
+       };
 };
 
 &omap3_pmx_core {
        pinctrl-names = "default";
        pinctrl-0 = <
                &tfp410_pins
-               &dss_pins
+               &dss_dpi_pins
        >;
 
-       tfp410_pins: tfp410_dvi_pins {
+       tfp410_pins: pinmux_tfp410_pins {
                pinctrl-single,pins = <
                        0x196 (PIN_OUTPUT | MUX_MODE4)   /* hdq_sio.gpio_170 */
                >;
        };
 
-       dss_pins: pinmux_dss_dvi_pins {
+       dss_dpi_pins: pinmux_dss_dpi_pins {
                pinctrl-single,pins = <
                        0x0a4 (PIN_OUTPUT | MUX_MODE0)   /* dss_pclk.dss_pclk */
                        0x0a6 (PIN_OUTPUT | MUX_MODE0)   /* dss_hsync.dss_hsync */
         /* Needed for DSS */
         regulator-name = "vdds_dsi";
 };
+
+&dss {
+       status = "ok";
+
+       port {
+               dpi_out: endpoint {
+                       remote-endpoint = <&tfp410_in>;
+                       data-lines = <24>;
+               };
+       };
+};
index ddce0d8..0abe986 100644 (file)
 };
 
 &mmc1 {
+       /* See 35xx errata 2.1.1.128 in SPRZ278F */
+       compatible = "ti,omap3-pre-es3-hsmmc";
        vmmc-supply = <&vmmc1>;
        bus-width = <4>;
+       pinctrl-names = "default";
+       pinctrl-0 = <&mmc1_pins>;
+};
+
+&mmc2 {
+       status="disabled";
+};
+
+&mmc3 {
+       status="disabled";
 };
 
 &omap3_pmx_core {
                        0x174 (PIN_OUTPUT | MUX_MODE0)  /* hsusb0_stp.hsusb0_stp */
                >;
        };
+
+       mmc1_pins: pinmux_mmc1_pins {
+               pinctrl-single,pins = <
+                       OMAP3_CORE1_IOPAD(0x2144, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.mmc1_clk */
+                       OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.mmc1_cmd */
+                       OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.mmc1_dat0 */
+                       OMAP3_CORE1_IOPAD(0x214A, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.mmc1_dat1 */
+                       OMAP3_CORE1_IOPAD(0x214C, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.mmc1_dat2 */
+                       OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.mmc1_dat3 */
+               >;
+       };
 };
 
 &usb_otg_hs {
index d1c3d99..1a57b61 100644 (file)
                nxp,enable-gpio = <&gpio3 3 GPIO_ACTIVE_HIGH>;
                usb-phy = <&usb2_phy>;
        };
+
+       tv: connector {
+               compatible = "composite-connector";
+               label = "tv";
+
+               port {
+                       tv_connector_in: endpoint {
+                               remote-endpoint = <&venc_out>;
+                       };
+               };
+       };
 };
 
 &omap3_pmx_core {
                >;
        };
 
-       display_pins: pinmux_display_pins {
+       acx565akm_pins: pinmux_acx565akm_pins {
                pinctrl-single,pins = <
                        0x0d4 (PIN_OUTPUT | MUX_MODE4)          /* RX51_LCD_RESET_GPIO */
                >;
        };
+
+       dss_sdi_pins: pinmux_dss_sdi_pins {
+               pinctrl-single,pins = <
+                       0x0c0 (PIN_OUTPUT | MUX_MODE1)   /* dss_data10.sdi_dat1n */
+                       0x0c2 (PIN_OUTPUT | MUX_MODE1)   /* dss_data11.sdi_dat1p */
+                       0x0c4 (PIN_OUTPUT | MUX_MODE1)   /* dss_data12.sdi_dat2n */
+                       0x0c6 (PIN_OUTPUT | MUX_MODE1)   /* dss_data13.sdi_dat2p */
+
+                       0x0d8 (PIN_OUTPUT | MUX_MODE1)   /* dss_data22.sdi_clkp */
+                       0x0da (PIN_OUTPUT | MUX_MODE1)   /* dss_data23.sdi_clkn */
+               >;
+       };
 };
 
 &i2c1 {
                spi-max-frequency = <6000000>;
                reg = <0>;
        };
-       mipid@2 {
-               compatible = "acx565akm";
+
+       acx565akm@2 {
+               compatible = "sony,acx565akm";
                spi-max-frequency = <6000000>;
                reg = <2>;
 
                pinctrl-names = "default";
-               pinctrl-0 = <&display_pins>;
+               pinctrl-0 = <&acx565akm_pins>;
+
+               label = "lcd";
+               reset-gpios = <&gpio3 26 GPIO_ACTIVE_HIGH>; /* 90 */
+
+               port {
+                       lcd_in: endpoint {
+                               remote-endpoint = <&sdi_out>;
+                       };
+               };
        };
 };
 
        pinctrl-names = "default";
        pinctrl-0 = <&uart3_pins>;
 };
+
+&dss {
+       status = "ok";
+
+       pinctrl-names = "default";
+       pinctrl-0 = <&dss_sdi_pins>;
+
+       vdds_sdi-supply = <&vaux1>;
+
+       ports {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               port@1 {
+                       reg = <1>;
+
+                       sdi_out: endpoint {
+                               remote-endpoint = <&lcd_in>;
+                               datapairs = <2>;
+                       };
+               };
+       };
+};
+
+&venc {
+       status = "ok";
+
+       vdda-supply = <&vdac>;
+
+       port {
+               venc_out: endpoint {
+                       remote-endpoint = <&tv_connector_in>;
+                       ti,channels = <1>;
+               };
+       };
+};
index a089e6e..5e5790f 100644 (file)
                        pinctrl-single,function-mask = <0xff1f>;
                };
 
+               omap3_scm_general: tisyscon@48002270 {
+                       compatible = "syscon";
+                       reg = <0x48002270 0x2f0>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0x2b0 0x4>;
+                       syscon = <&omap3_scm_general>;
+                       pbias_mmc_reg: pbias_mmc_omap2430 {
+                               regulator-name = "pbias_mmc_omap2430";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                gpio1: gpio@48310000 {
                        compatible = "ti,omap3-gpio";
                        reg = <0x48310000 0x200>;
                        ti,dual-volt;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
                        num-eps = <16>;
                        ram-bits = <12>;
                };
+
+               dss: dss@48050000 {
+                       compatible = "ti,omap3-dss";
+                       reg = <0x48050000 0x200>;
+                       status = "disabled";
+                       ti,hwmods = "dss_core";
+                       clocks = <&dss1_alwon_fck>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       dispc@48050400 {
+                               compatible = "ti,omap3-dispc";
+                               reg = <0x48050400 0x400>;
+                               interrupts = <25>;
+                               ti,hwmods = "dss_dispc";
+                               clocks = <&dss1_alwon_fck>;
+                               clock-names = "fck";
+                       };
+
+                       dsi: encoder@4804fc00 {
+                               compatible = "ti,omap3-dsi";
+                               reg = <0x4804fc00 0x200>,
+                                     <0x4804fe00 0x40>,
+                                     <0x4804ff00 0x20>;
+                               reg-names = "proto", "phy", "pll";
+                               interrupts = <25>;
+                               status = "disabled";
+                               ti,hwmods = "dss_dsi1";
+                               clocks = <&dss1_alwon_fck>, <&dss2_alwon_fck>;
+                               clock-names = "fck", "sys_clk";
+                       };
+
+                       rfbi: encoder@48050800 {
+                               compatible = "ti,omap3-rfbi";
+                               reg = <0x48050800 0x100>;
+                               status = "disabled";
+                               ti,hwmods = "dss_rfbi";
+                               clocks = <&dss1_alwon_fck>, <&dss_ick>;
+                               clock-names = "fck", "ick";
+                       };
+
+                       venc: encoder@48050c00 {
+                               compatible = "ti,omap3-venc";
+                               reg = <0x48050c00 0x100>;
+                               status = "disabled";
+                               ti,hwmods = "dss_venc";
+                               clocks = <&dss_tv_fck>;
+                               clock-names = "fck";
+                       };
+               };
        };
 };
 
index 6f31954..4c22f3a 100644 (file)
                clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>;
        };
 
-       dss1_alwon_fck_3430es1: dss1_alwon_fck_3430es1 {
+       dss1_alwon_fck: dss1_alwon_fck_3430es1 {
                #clock-cells = <0>;
                compatible = "ti,gate-clock";
                clocks = <&dpll4_m4x2_ck>;
                ti,set-rate-parent;
        };
 
-       dss_ick_3430es1: dss_ick_3430es1 {
+       dss_ick: dss_ick_3430es1 {
                #clock-cells = <0>;
                compatible = "ti,omap3-no-wait-interface-clock";
                clocks = <&l4_ick>;
        dss_clkdm: dss_clkdm {
                compatible = "ti,clockdomain";
                clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>,
-                        <&dss1_alwon_fck_3430es1>, <&dss_ick_3430es1>;
+                        <&dss1_alwon_fck>, <&dss_ick>;
        };
 
        d2d_clkdm: d2d_clkdm {
index af9ae53..080fb3f 100644 (file)
                ti,bit-shift = <30>;
        };
 
-       dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2 {
+       dss1_alwon_fck: dss1_alwon_fck_3430es2 {
                #clock-cells = <0>;
                compatible = "ti,dss-gate-clock";
                clocks = <&dpll4_m4x2_ck>;
                ti,set-rate-parent;
        };
 
-       dss_ick_3430es2: dss_ick_3430es2 {
+       dss_ick: dss_ick_3430es2 {
                #clock-cells = <0>;
                compatible = "ti,omap3-dss-interface-clock";
                clocks = <&l4_ick>;
        dss_clkdm: dss_clkdm {
                compatible = "ti,clockdomain";
                clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>,
-                        <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>;
+                        <&dss1_alwon_fck>, <&dss_ick>;
        };
 
        core_l4_clkdm: core_l4_clkdm {
index 2fcf253..6b5280d 100644 (file)
        };
 };
 
+&dpll4_m2x2_mul_ck {
+       clock-mult = <1>;
+};
+
+&dpll4_m3x2_mul_ck {
+       clock-mult = <1>;
+};
+
+&dpll4_m4x2_mul_ck {
+       ti,clock-mult = <1>;
+};
+
+&dpll4_m5x2_mul_ck {
+       clock-mult = <1>;
+};
+
+&dpll4_m6x2_mul_ck {
+       clock-mult = <1>;
+};
+
 &cm_clockdomains {
        dpll4_clkdm: dpll4_clkdm {
                compatible = "ti,clockdomain";
index ba077cd..22cf464 100644 (file)
        };
 };
 
-/include/ "omap36xx-clocks.dtsi"
+/* OMAP3630 needs dss_96m_fck for VENC */
+&venc {
+       clocks = <&dss_tv_fck>, <&dss_96m_fck>;
+       clock-names = "fck", "tv_dac_clk";
+};
+
 /include/ "omap34xx-omap36xx-clocks.dtsi"
 /include/ "omap36xx-omap3430es2plus-clocks.dtsi"
 /include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi"
+/include/ "omap36xx-clocks.dtsi"
index cb04d4b..12be2b3 100644 (file)
 
        dpll4_m4x2_mul_ck: dpll4_m4x2_mul_ck {
                #clock-cells = <0>;
-               compatible = "fixed-factor-clock";
+               compatible = "ti,fixed-factor-clock";
                clocks = <&dpll4_m4_ck>;
-               clock-mult = <2>;
-               clock-div = <1>;
+               ti,clock-mult = <2>;
+               ti,clock-div = <1>;
+               ti,set-rate-parent;
        };
 
        dpll4_m4x2_ck: dpll4_m4x2_ck {
                ti,bit-shift = <0x1d>;
                reg = <0x0d00>;
                ti,set-bit-to-disable;
+               ti,set-rate-parent;
        };
 
        dpll4_m5_ck: dpll4_m5_ck {
index cbc45cf..d2c45bf 100644 (file)
                reg = <0x80000000 0x40000000>; /* 1 GB */
        };
 
+       aliases {
+               display0 = &dvi0;
+               display1 = &hdmi0;
+       };
+
        leds: leds {
                compatible = "gpio-leds";
                pinctrl-names = "default";
                startup-delay-us = <70000>;
                enable-active-high;
        };
+
+       tfp410: encoder@0 {
+               compatible = "ti,tfp410";
+               powerdown-gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;   /* gpio_0 */
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tfp410_in: endpoint@0 {
+                                       remote-endpoint = <&dpi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tfp410_out: endpoint@0 {
+                                       remote-endpoint = <&dvi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       dvi0: connector@0 {
+               compatible = "dvi-connector";
+               label = "dvi";
+
+               digital;
+
+               ddc-i2c-bus = <&i2c3>;
+
+               port {
+                       dvi_connector_in: endpoint {
+                               remote-endpoint = <&tfp410_out>;
+                       };
+               };
+       };
+
+       tpd12s015: encoder@1 {
+               compatible = "ti,tpd12s015";
+
+               gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,   /* 60, CT CP HPD */
+                       <&gpio2 9 GPIO_ACTIVE_HIGH>,    /* 41, LS OE */
+                       <&gpio2 31 GPIO_ACTIVE_HIGH>;   /* 63, HPD */
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tpd12s015_in: endpoint@0 {
+                                       remote-endpoint = <&hdmi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tpd12s015_out: endpoint@0 {
+                                       remote-endpoint = <&hdmi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       hdmi0: connector@1 {
+               compatible = "hdmi-connector";
+               label = "hdmi";
+
+               type = "a";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&tpd12s015_out>;
+                       };
+               };
+       };
 };
 
 &omap4_pmx_core {
 &usbhsehci {
        phys = <&hsusb1_phy>;
 };
+
+&dss {
+       status = "ok";
+
+       port {
+               dpi_out: endpoint {
+                       remote-endpoint = <&tfp410_in>;
+                       data-lines = <24>;
+               };
+       };
+};
+
+&dsi2 {
+       status = "ok";
+       vdd-supply = <&vcxio>;
+};
+
+&hdmi {
+       status = "ok";
+       vdda-supply = <&vdac>;
+
+       port {
+               hdmi_out: endpoint {
+                       remote-endpoint = <&tpd12s015_in>;
+               };
+       };
+};
index 9bbbbec..48983c8 100644 (file)
                reg = <0x80000000 0x40000000>; /* 1 GB */
        };
 
+       aliases {
+               display0 = &lcd0;
+               display1 = &lcd1;
+               display2 = &hdmi0;
+       };
+
        vdd_eth: fixedregulator-vdd-eth {
                compatible = "regulator-fixed";
                regulator-name = "VDD_ETH";
                startup-delay-us = <70000>;
                enable-active-high;
        };
+
+       tpd12s015: encoder@0 {
+               compatible = "ti,tpd12s015";
+
+               gpios = <&gpio2 28 GPIO_ACTIVE_HIGH>,   /* 60, CT CP HPD */
+                       <&gpio2 9 GPIO_ACTIVE_HIGH>,    /* 41, LS OE */
+                       <&gpio2 31 GPIO_ACTIVE_HIGH>;   /* 63, HPD */
+
+               ports {
+                       #address-cells = <1>;
+                       #size-cells = <0>;
+
+                       port@0 {
+                               reg = <0>;
+
+                               tpd12s015_in: endpoint@0 {
+                                       remote-endpoint = <&hdmi_out>;
+                               };
+                       };
+
+                       port@1 {
+                               reg = <1>;
+
+                               tpd12s015_out: endpoint@0 {
+                                       remote-endpoint = <&hdmi_connector_in>;
+                               };
+                       };
+               };
+       };
+
+       hdmi0: connector@0 {
+               compatible = "hdmi-connector";
+               label = "hdmi";
+
+               type = "c";
+
+               port {
+                       hdmi_connector_in: endpoint {
+                               remote-endpoint = <&tpd12s015_out>;
+                       };
+               };
+       };
 };
 
 &omap4_pmx_core {
        mode = <3>;
        power = <50>;
 };
+
+&dss {
+       status = "ok";
+};
+
+&dsi1 {
+       status = "ok";
+       vdd-supply = <&vcxio>;
+
+       port {
+               dsi1_out_ep: endpoint {
+                       remote-endpoint = <&lcd0_in>;
+                       lanes = <0 1 2 3 4 5>;
+               };
+       };
+
+       lcd0: display {
+               compatible = "tpo,taal", "panel-dsi-cm";
+               label = "lcd0";
+
+               reset-gpios = <&gpio4 6 GPIO_ACTIVE_HIGH>;      /* 102 */
+
+               port {
+                       lcd0_in: endpoint {
+                               remote-endpoint = <&dsi1_out_ep>;
+                       };
+               };
+       };
+};
+
+&dsi2 {
+       status = "ok";
+       vdd-supply = <&vcxio>;
+
+       port {
+               dsi2_out_ep: endpoint {
+                       remote-endpoint = <&lcd1_in>;
+                       lanes = <0 1 2 3 4 5>;
+               };
+       };
+
+       lcd1: display {
+               compatible = "tpo,taal", "panel-dsi-cm";
+               label = "lcd1";
+
+               reset-gpios = <&gpio4 8 GPIO_ACTIVE_HIGH>;      /* 104 */
+
+               port {
+                       lcd1_in: endpoint {
+                               remote-endpoint = <&dsi2_out_ep>;
+                       };
+               };
+       };
+};
+
+&hdmi {
+       status = "ok";
+       vdda-supply = <&vdac>;
+
+       port {
+               hdmi_out: endpoint {
+                       remote-endpoint = <&tpd12s015_in>;
+               };
+       };
+};
index fe61976..27fcac8 100644 (file)
                        pinctrl-single,function-mask = <0x7fff>;
                };
 
+               omap4_padconf_global: tisyscon@4a1005a0 {
+                       compatible = "syscon";
+                       reg = <0x4a1005a0 0x170>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0x60 0x4>;
+                       syscon = <&omap4_padconf_global>;
+                       pbias_mmc_reg: pbias_mmc_omap4 {
+                               regulator-name = "pbias_mmc_omap4";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                sdma: dma-controller@4a056000 {
                        compatible = "ti,omap4430-sdma";
                        reg = <0x4a056000 0x1000>;
                        ti,needs-special-reset;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
                        ranges;
+                       clocks = <&init_60m_fclk>,
+                                <&xclk60mhsp1_ck>,
+                                <&xclk60mhsp2_ck>;
+                       clock-names = "refclk_60m_int",
+                                     "refclk_60m_ext_p1",
+                                     "refclk_60m_ext_p2";
 
                        usbhsohci: ohci@4a064800 {
                                compatible = "ti,ohci-omap3";
 
                        status = "disabled";
                };
+
+               dss: dss@58000000 {
+                       compatible = "ti,omap4-dss";
+                       reg = <0x58000000 0x80>;
+                       status = "disabled";
+                       ti,hwmods = "dss_core";
+                       clocks = <&dss_dss_clk>;
+                       clock-names = "fck";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       ranges;
+
+                       dispc@58001000 {
+                               compatible = "ti,omap4-dispc";
+                               reg = <0x58001000 0x1000>;
+                               interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
+                               ti,hwmods = "dss_dispc";
+                               clocks = <&dss_dss_clk>;
+                               clock-names = "fck";
+                       };
+
+                       rfbi: encoder@58002000  {
+                               compatible = "ti,omap4-rfbi";
+                               reg = <0x58002000 0x1000>;
+                               status = "disabled";
+                               ti,hwmods = "dss_rfbi";
+                               clocks = <&dss_dss_clk>, <&dss_fck>;
+                               clock-names = "fck", "ick";
+                       };
+
+                       venc: encoder@58003000 {
+                               compatible = "ti,omap4-venc";
+                               reg = <0x58003000 0x1000>;
+                               status = "disabled";
+                               ti,hwmods = "dss_venc";
+                               clocks = <&dss_tv_clk>;
+                               clock-names = "fck";
+                       };
+
+                       dsi1: encoder@58004000 {
+                               compatible = "ti,omap4-dsi";
+                               reg = <0x58004000 0x200>,
+                                     <0x58004200 0x40>,
+                                     <0x58004300 0x20>;
+                               reg-names = "proto", "phy", "pll";
+                               interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                               ti,hwmods = "dss_dsi1";
+                               clocks = <&dss_dss_clk>, <&dss_sys_clk>;
+                               clock-names = "fck", "sys_clk";
+                       };
+
+                       dsi2: encoder@58005000 {
+                               compatible = "ti,omap4-dsi";
+                               reg = <0x58005000 0x200>,
+                                     <0x58005200 0x40>,
+                                     <0x58005300 0x20>;
+                               reg-names = "proto", "phy", "pll";
+                               interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                               ti,hwmods = "dss_dsi2";
+                               clocks = <&dss_dss_clk>, <&dss_sys_clk>;
+                               clock-names = "fck", "sys_clk";
+                       };
+
+                       hdmi: encoder@58006000 {
+                               compatible = "ti,omap4-hdmi";
+                               reg = <0x58006000 0x200>,
+                                     <0x58006200 0x100>,
+                                     <0x58006300 0x100>,
+                                     <0x58006400 0x1000>;
+                               reg-names = "wp", "pll", "phy", "core";
+                               interrupts = <GIC_SPI 101 IRQ_TYPE_LEVEL_HIGH>;
+                               status = "disabled";
+                               ti,hwmods = "dss_hdmi";
+                               clocks = <&dss_48mhz_clk>, <&dss_sys_clk>;
+                               clock-names = "fck", "sys_clk";
+                       };
+               };
        };
 };
 
index 8292ad0..6f3de22 100644 (file)
                        pinctrl-single,function-mask = <0x7fff>;
                };
 
+               omap5_padconf_global: tisyscon@4a002da0 {
+                       compatible = "syscon";
+                       reg = <0x4A002da0 0xec>;
+               };
+
+               pbias_regulator: pbias_regulator {
+                       compatible = "ti,pbias-omap";
+                       reg = <0x60 0x4>;
+                       syscon = <&omap5_padconf_global>;
+                       pbias_mmc_reg: pbias_mmc_omap5 {
+                               regulator-name = "pbias_mmc_omap5";
+                               regulator-min-microvolt = <1800000>;
+                               regulator-max-microvolt = <3000000>;
+                       };
+               };
+
                sdma: dma-controller@4a056000 {
                        compatible = "ti,omap4430-sdma";
                        reg = <0x4a056000 0x1000>;
                        ti,needs-special-reset;
                        dmas = <&sdma 61>, <&sdma 62>;
                        dma-names = "tx", "rx";
+                       pbias-supply = <&pbias_mmc_reg>;
                };
 
                mmc2: mmc@480b4000 {
                        #address-cells = <1>;
                        #size-cells = <1>;
                        ranges;
+                       clocks = <&l3init_60m_fclk>,
+                                <&xclk60mhsp1_ck>,
+                                <&xclk60mhsp2_ck>;
+                       clock-names = "refclk_60m_int",
+                                     "refclk_60m_ext_p1",
+                                     "refclk_60m_ext_p2";
 
                        usbhsohci: ohci@4a064800 {
                                compatible = "ti,ohci-omap3";
index 2014552..1e82571 100644 (file)
                                reg = <0xb00b0000 0x10000>;
                                interrupts = <12>;
                                clocks = <&clks 24>;
+                               #dma-cells = <1>;
                        };
 
                        dmac1: dma-controller@b0160000 {
                                reg = <0xb0160000 0x10000>;
                                interrupts = <13>;
                                clocks = <&clks 25>;
+                               #dma-cells = <1>;
                        };
 
                        vip@b00C0000 {
index 364ba38..a966795 100644 (file)
@@ -170,6 +170,7 @@ CONFIG_DRA752_THERMAL=y
 CONFIG_WATCHDOG=y
 CONFIG_OMAP_WATCHDOG=y
 CONFIG_TWL4030_WATCHDOG=y
+CONFIG_MFD_SYSCON=y
 CONFIG_MFD_PALMAS=y
 CONFIG_MFD_TPS65217=y
 CONFIG_MFD_TPS65910=y
@@ -181,6 +182,7 @@ CONFIG_REGULATOR_TPS6507X=y
 CONFIG_REGULATOR_TPS65217=y
 CONFIG_REGULATOR_TPS65910=y
 CONFIG_REGULATOR_TWL4030=y
+CONFIG_REGULATOR_PBIAS=y
 CONFIG_FB=y
 CONFIG_FIRMWARE_EDID=y
 CONFIG_FB_MODE_HELPERS=y
index 9da35c6..4d963fb 100644 (file)
@@ -1073,6 +1073,8 @@ static int __init arch_hw_breakpoint_init(void)
        core_num_brps = get_num_brps();
        core_num_wrps = get_num_wrps();
 
+       cpu_notifier_register_begin();
+
        /*
         * We need to tread carefully here because DBGSWENABLE may be
         * driven low on this core and there isn't an architected way to
@@ -1089,6 +1091,7 @@ static int __init arch_hw_breakpoint_init(void)
        if (!cpumask_empty(&debug_err_mask)) {
                core_num_brps = 0;
                core_num_wrps = 0;
+               cpu_notifier_register_done();
                return 0;
        }
 
@@ -1108,7 +1111,10 @@ static int __init arch_hw_breakpoint_init(void)
                        TRAP_HWBKPT, "breakpoint debug exception");
 
        /* Register hotplug and PM notifiers. */
-       register_cpu_notifier(&dbg_reset_nb);
+       __register_cpu_notifier(&dbg_reset_nb);
+
+       cpu_notifier_register_done();
+
        pm_init();
        return 0;
 }
index bd18bb8..f0e50a0 100644 (file)
@@ -1051,21 +1051,26 @@ int kvm_arch_init(void *opaque)
                }
        }
 
+       cpu_notifier_register_begin();
+
        err = init_hyp_mode();
        if (err)
                goto out_err;
 
-       err = register_cpu_notifier(&hyp_init_cpu_nb);
+       err = __register_cpu_notifier(&hyp_init_cpu_nb);
        if (err) {
                kvm_err("Cannot register HYP init CPU notifier (%d)\n", err);
                goto out_err;
        }
 
+       cpu_notifier_register_done();
+
        hyp_cpu_pm_init();
 
        kvm_coproc_table_init();
        return 0;
 out_err:
+       cpu_notifier_register_done();
        return err;
 }
 
index bc6013f..b8920b6 100644 (file)
@@ -35,7 +35,11 @@ static struct of_device_id omap_dt_match_table[] __initdata = {
 
 static void __init omap_generic_init(void)
 {
+       omapdss_early_init_of();
+
        pdata_quirks_init(omap_dt_match_table);
+
+       omapdss_init_of();
 }
 
 #ifdef CONFIG_SOC_OMAP2420
index 11ed915..8f5121b 100644 (file)
@@ -3497,10 +3497,6 @@ static struct omap_clk omap3xxx_clks[] = {
        CLK(NULL,       "dss_tv_fck",   &dss_tv_fck),
        CLK(NULL,       "dss_96m_fck",  &dss_96m_fck),
        CLK(NULL,       "dss2_alwon_fck",       &dss2_alwon_fck),
-       CLK(NULL,       "utmi_p1_gfclk",        &dummy_ck),
-       CLK(NULL,       "utmi_p2_gfclk",        &dummy_ck),
-       CLK(NULL,       "xclk60mhsp1_ck",       &dummy_ck),
-       CLK(NULL,       "xclk60mhsp2_ck",       &dummy_ck),
        CLK(NULL,       "init_60m_fclk",        &dummy_ck),
        CLK(NULL,       "gpt1_fck",     &gpt1_fck),
        CLK(NULL,       "aes2_ick",     &aes2_ick),
index a6aae30..d88aff7 100644 (file)
@@ -315,5 +315,8 @@ extern int omap_dss_reset(struct omap_hwmod *);
 /* SoC specific clock initializer */
 int omap_clk_init(void);
 
+int __init omapdss_init_of(void);
+void __init omapdss_early_init_of(void);
+
 #endif /* __ASSEMBLER__ */
 #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
index 93ebb40..16d33d8 100644 (file)
@@ -23,6 +23,9 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
 
 #include <video/omapdss.h>
 #include "omap_hwmod.h"
@@ -551,3 +554,166 @@ int omap_dss_reset(struct omap_hwmod *oh)
 
        return r;
 }
+
+/* list of 'compatible' nodes to convert to omapdss specific */
+static const char * const dss_compat_conv_list[] __initconst = {
+       "composite-connector",
+       "dvi-connector",
+       "hdmi-connector",
+       "panel-dpi",
+       "panel-dsi-cm",
+       "sony,acx565akm",
+       "svideo-connector",
+       "ti,tfp410",
+       "ti,tpd12s015",
+};
+
+/* prepend compatible string with "omapdss," */
+static __init void omapdss_omapify_node(struct device_node *node,
+       const char *compat)
+{
+       char *new_compat;
+       struct property *prop;
+
+       new_compat = kasprintf(GFP_KERNEL, "omapdss,%s", compat);
+
+       prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+
+       if (!prop) {
+               pr_err("omapdss_omapify_node: kzalloc failed\n");
+               return;
+       }
+
+       prop->name = "compatible";
+       prop->value = new_compat;
+       prop->length = strlen(new_compat) + 1;
+
+       of_update_property(node, prop);
+}
+
+/*
+ * As omapdss panel drivers are omapdss specific, but we want to define the
+ * DT-data in generic manner, we convert the compatible strings of the panel
+ * nodes from "panel-foo" to "omapdss,panel-foo". This way we can have both
+ * correct DT data and omapdss specific drivers.
+ *
+ * When we get generic panel drivers to the kernel, this will be removed.
+ */
+void __init omapdss_early_init_of(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(dss_compat_conv_list); ++i) {
+               const char *compat = dss_compat_conv_list[i];
+               struct device_node *node = NULL;
+
+               while ((node = of_find_compatible_node(node, NULL, compat))) {
+                       if (!of_device_is_available(node))
+                               continue;
+
+                       omapdss_omapify_node(node, compat);
+               }
+       }
+}
+
+struct device_node * __init omapdss_find_dss_of_node(void)
+{
+       struct device_node *node;
+
+       node = of_find_compatible_node(NULL, NULL, "ti,omap2-dss");
+       if (node)
+               return node;
+
+       node = of_find_compatible_node(NULL, NULL, "ti,omap3-dss");
+       if (node)
+               return node;
+
+       node = of_find_compatible_node(NULL, NULL, "ti,omap4-dss");
+       if (node)
+               return node;
+
+       return NULL;
+}
+
+int __init omapdss_init_of(void)
+{
+       int r;
+       enum omapdss_version ver;
+       struct device_node *node;
+       struct platform_device *pdev;
+
+       static struct omap_dss_board_info board_data = {
+               .dsi_enable_pads = omap_dsi_enable_pads,
+               .dsi_disable_pads = omap_dsi_disable_pads,
+               .set_min_bus_tput = omap_dss_set_min_bus_tput,
+       };
+
+       /* only create dss helper devices if dss is enabled in the .dts */
+
+       node = omapdss_find_dss_of_node();
+       if (!node)
+               return 0;
+
+       if (!of_device_is_available(node))
+               return 0;
+
+       ver = omap_display_get_version();
+
+       if (ver == OMAPDSS_VER_UNKNOWN) {
+               pr_err("DSS not supported on this SoC\n");
+               return -ENODEV;
+       }
+
+       pdev = of_find_device_by_node(node);
+
+       if (!pdev) {
+               pr_err("Unable to find DSS platform device\n");
+               return -ENODEV;
+       }
+
+       r = of_platform_populate(node, NULL, NULL, &pdev->dev);
+       if (r) {
+               pr_err("Unable to populate DSS submodule devices\n");
+               return r;
+       }
+
+       board_data.version = ver;
+
+       omap_display_device.dev.platform_data = &board_data;
+
+       r = platform_device_register(&omap_display_device);
+       if (r < 0) {
+               pr_err("Unable to register omapdss device\n");
+               return r;
+       }
+
+       /* create DRM device */
+       r = omap_init_drm();
+       if (r < 0) {
+               pr_err("Unable to register omapdrm device\n");
+               return r;
+       }
+
+       /* create vrfb device */
+       r = omap_init_vrfb();
+       if (r < 0) {
+               pr_err("Unable to register omapvrfb device\n");
+               return r;
+       }
+
+       /* create FB device */
+       r = omap_init_fb();
+       if (r < 0) {
+               pr_err("Unable to register omapfb device\n");
+               return r;
+       }
+
+       /* create V4L2 display device */
+       r = omap_init_vout();
+       if (r < 0) {
+               pr_err("Unable to register omap_vout device\n");
+               return r;
+       }
+
+       return 0;
+}
index f3d2ce4..7375854 100644 (file)
@@ -30,4 +30,7 @@ int omap_init_drm(void);
 int omap_init_vrfb(void);
 int omap_init_fb(void);
 int omap_init_vout(void);
+
+struct device_node * __init omapdss_find_dss_of_node(void);
+
 #endif
index dadccc9..ea2be0f 100644 (file)
 #include "soc.h"
 #include "dss-common.h"
 #include "mux.h"
+#include "display.h"
 
-#define HDMI_GPIO_CT_CP_HPD 60 /* HPD mode enable/disable */
-#define HDMI_GPIO_LS_OE 41 /* Level shifter for HDMI */
-#define HDMI_GPIO_HPD  63 /* Hotplug detect */
-
-#define PANDA_DVI_TFP410_POWER_DOWN_GPIO       0
-
-/* DVI Connector */
-static struct connector_dvi_platform_data omap4_panda_dvi_connector_pdata = {
-       .name                   = "dvi",
-       .source                 = "tfp410.0",
-       .i2c_bus_num            = 2,
-};
-
-static struct platform_device omap4_panda_dvi_connector_device = {
-       .name                   = "connector-dvi",
-       .id                     = 0,
-       .dev.platform_data      = &omap4_panda_dvi_connector_pdata,
-};
-
-/* TFP410 DPI-to-DVI chip */
-static struct encoder_tfp410_platform_data omap4_panda_tfp410_pdata = {
-       .name                   = "tfp410.0",
-       .source                 = "dpi.0",
-       .data_lines             = 24,
-       .power_down_gpio        = PANDA_DVI_TFP410_POWER_DOWN_GPIO,
-};
-
-static struct platform_device omap4_panda_tfp410_device = {
-       .name                   = "tfp410",
-       .id                     = 0,
-       .dev.platform_data      = &omap4_panda_tfp410_pdata,
-};
-
-/* HDMI Connector */
-static struct connector_hdmi_platform_data omap4_panda_hdmi_connector_pdata = {
-       .name                   = "hdmi",
-       .source                 = "tpd12s015.0",
-};
-
-static struct platform_device omap4_panda_hdmi_connector_device = {
-       .name                   = "connector-hdmi",
-       .id                     = 0,
-       .dev.platform_data      = &omap4_panda_hdmi_connector_pdata,
-};
-
-/* TPD12S015 HDMI ESD protection & level shifter chip */
-static struct encoder_tpd12s015_platform_data omap4_panda_tpd_pdata = {
-       .name                   = "tpd12s015.0",
-       .source                 = "hdmi.0",
-
-       .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD,
-       .ls_oe_gpio = HDMI_GPIO_LS_OE,
-       .hpd_gpio = HDMI_GPIO_HPD,
-};
-
-static struct platform_device omap4_panda_tpd_device = {
-       .name                   = "tpd12s015",
-       .id                     = 0,
-       .dev.platform_data      = &omap4_panda_tpd_pdata,
-};
-
-static struct omap_dss_board_info omap4_panda_dss_data = {
-       .default_display_name = "dvi",
-};
-
-void __init omap4_panda_display_init_of(void)
-{
-       omap_display_init(&omap4_panda_dss_data);
-
-       platform_device_register(&omap4_panda_tfp410_device);
-       platform_device_register(&omap4_panda_dvi_connector_device);
-
-       platform_device_register(&omap4_panda_tpd_device);
-       platform_device_register(&omap4_panda_hdmi_connector_device);
-}
-
-
-/* OMAP4 Blaze display data */
-
-#define DISPLAY_SEL_GPIO       59      /* LCD2/PicoDLP switch */
-#define DLP_POWER_ON_GPIO      40
-
-static struct panel_dsicm_platform_data dsi1_panel = {
-       .name           = "lcd",
-       .source         = "dsi.0",
-       .reset_gpio     = 102,
-       .use_ext_te     = false,
-       .ext_te_gpio    = 101,
-       .pin_config = {
-               .num_pins       = 6,
-               .pins           = { 0, 1, 2, 3, 4, 5 },
-       },
-};
-
-static struct platform_device sdp4430_lcd_device = {
-       .name                   = "panel-dsi-cm",
-       .id                     = 0,
-       .dev.platform_data      = &dsi1_panel,
-};
-
-static struct panel_dsicm_platform_data dsi2_panel = {
-       .name           = "lcd2",
-       .source         = "dsi.1",
-       .reset_gpio     = 104,
-       .use_ext_te     = false,
-       .ext_te_gpio    = 103,
-       .pin_config = {
-               .num_pins       = 6,
-               .pins           = { 0, 1, 2, 3, 4, 5 },
-       },
-};
-
-static struct platform_device sdp4430_lcd2_device = {
-       .name                   = "panel-dsi-cm",
-       .id                     = 1,
-       .dev.platform_data      = &dsi2_panel,
-};
-
-/* HDMI Connector */
-static struct connector_hdmi_platform_data sdp4430_hdmi_connector_pdata = {
-       .name                   = "hdmi",
-       .source                 = "tpd12s015.0",
-};
-
-static struct platform_device sdp4430_hdmi_connector_device = {
-       .name                   = "connector-hdmi",
-       .id                     = 0,
-       .dev.platform_data      = &sdp4430_hdmi_connector_pdata,
-};
-
-/* TPD12S015 HDMI ESD protection & level shifter chip */
-static struct encoder_tpd12s015_platform_data sdp4430_tpd_pdata = {
-       .name                   = "tpd12s015.0",
-       .source                 = "hdmi.0",
-
-       .ct_cp_hpd_gpio = HDMI_GPIO_CT_CP_HPD,
-       .ls_oe_gpio = HDMI_GPIO_LS_OE,
-       .hpd_gpio = HDMI_GPIO_HPD,
-};
-
-static struct platform_device sdp4430_tpd_device = {
-       .name                   = "tpd12s015",
-       .id                     = 0,
-       .dev.platform_data      = &sdp4430_tpd_pdata,
-};
-
-
-static struct omap_dss_board_info sdp4430_dss_data = {
-       .default_display_name = "lcd",
-};
-
-/*
- * we select LCD2 by default (instead of Pico DLP) by setting DISPLAY_SEL_GPIO.
- * Setting DLP_POWER_ON gpio enables the VDLP_2V5 VDLP_1V8 and VDLP_1V0 rails
- * used by picodlp on the 4430sdp platform. Keep this gpio disabled as LCD2 is
- * selected by default
- */
-void __init omap_4430sdp_display_init_of(void)
-{
-       int r;
-
-       r = gpio_request_one(DISPLAY_SEL_GPIO, GPIOF_OUT_INIT_HIGH,
-                       "display_sel");
-       if (r)
-               pr_err("%s: Could not get display_sel GPIO\n", __func__);
-
-       r = gpio_request_one(DLP_POWER_ON_GPIO, GPIOF_OUT_INIT_LOW,
-               "DLP POWER ON");
-       if (r)
-               pr_err("%s: Could not get DLP POWER ON GPIO\n", __func__);
-
-       omap_display_init(&sdp4430_dss_data);
-
-       platform_device_register(&sdp4430_lcd_device);
-       platform_device_register(&sdp4430_lcd2_device);
-
-       platform_device_register(&sdp4430_tpd_device);
-       platform_device_register(&sdp4430_hdmi_connector_device);
-}
-
-
-/* OMAP3 IGEPv2 data */
-
-#define IGEP2_DVI_TFP410_POWER_DOWN_GPIO       170
-
-/* DVI Connector */
-static struct connector_dvi_platform_data omap3_igep2_dvi_connector_pdata = {
-       .name                   = "dvi",
-       .source                 = "tfp410.0",
-       .i2c_bus_num            = 2,
-};
-
-static struct platform_device omap3_igep2_dvi_connector_device = {
-       .name                   = "connector-dvi",
-       .id                     = 0,
-       .dev.platform_data      = &omap3_igep2_dvi_connector_pdata,
-};
-
-/* TFP410 DPI-to-DVI chip */
-static struct encoder_tfp410_platform_data omap3_igep2_tfp410_pdata = {
-       .name                   = "tfp410.0",
-       .source                 = "dpi.0",
-       .data_lines             = 24,
-       .power_down_gpio        = IGEP2_DVI_TFP410_POWER_DOWN_GPIO,
-};
-
-static struct platform_device omap3_igep2_tfp410_device = {
-       .name                   = "tfp410",
-       .id                     = 0,
-       .dev.platform_data      = &omap3_igep2_tfp410_pdata,
-};
-
-static struct omap_dss_board_info igep2_dss_data = {
-       .default_display_name = "dvi",
-};
-
-void __init omap3_igep2_display_init_of(void)
-{
-       omap_display_init(&igep2_dss_data);
-
-       platform_device_register(&omap3_igep2_tfp410_device);
-       platform_device_register(&omap3_igep2_dvi_connector_device);
-}
index 9c7e23a..a123ff0 100644 (file)
@@ -1955,10 +1955,6 @@ static struct omap_hwmod_class omap3xxx_usb_host_hs_hwmod_class = {
        .sysc = &omap3xxx_usb_host_hs_sysc,
 };
 
-static struct omap_hwmod_opt_clk omap3xxx_usb_host_hs_opt_clks[] = {
-         { .role = "ehci_logic_fck", .clk = "usbhost_120m_fck", },
-};
-
 static struct omap_hwmod_irq_info omap3xxx_usb_host_hs_irqs[] = {
        { .name = "ohci-irq", .irq = 76 + OMAP_INTC_START, },
        { .name = "ehci-irq", .irq = 77 + OMAP_INTC_START, },
@@ -1981,8 +1977,6 @@ static struct omap_hwmod omap3xxx_usb_host_hs_hwmod = {
                        .idlest_stdby_bit = OMAP3430ES2_ST_USBHOST_STDBY_SHIFT,
                },
        },
-       .opt_clks       = omap3xxx_usb_host_hs_opt_clks,
-       .opt_clks_cnt   = ARRAY_SIZE(omap3xxx_usb_host_hs_opt_clks),
 
        /*
         * Errata: USBHOST Configured In Smart-Idle Can Lead To a Deadlock
index b04c5f0..c3b7335 100644 (file)
@@ -141,7 +141,6 @@ static void __init omap3_sbc_t3530_legacy_init(void)
 
 static void __init omap3_igep0020_legacy_init(void)
 {
-       omap3_igep2_display_init_of();
 }
 
 static void __init omap3_evm_legacy_init(void)
@@ -247,14 +246,12 @@ static void __init nokia_n900_legacy_init(void)
 #ifdef CONFIG_ARCH_OMAP4
 static void __init omap4_sdp_legacy_init(void)
 {
-       omap_4430sdp_display_init_of();
        legacy_init_wl12xx(WL12XX_REFCLOCK_26,
                           WL12XX_TCXOCLOCK_26, 53);
 }
 
 static void __init omap4_panda_legacy_init(void)
 {
-       omap4_panda_display_init_of();
        legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 53);
 }
 #endif
index eca9eb1..62240f6 100644 (file)
@@ -4,4 +4,4 @@ config ARCH_PICOXCELL
        select ARM_VIC
        select DW_APB_TIMER_OF
        select HAVE_TCM
-       select NO_IOPORT
+       select NO_IOPORT_MAP
index 3e81891..e4e505f 100644 (file)
@@ -3,7 +3,7 @@ config ARCH_SIRF
        select ARCH_HAS_RESET_CONTROLLER
        select ARCH_REQUIRE_GPIOLIB
        select GENERIC_IRQ_CHIP
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select PINCTRL
        select PINCTRL_SIRF
        help
index ba1cc62..40cf50b 100644 (file)
@@ -12,7 +12,7 @@ if ARCH_S3C24XX
 config PLAT_S3C24XX
        def_bool y
        select ARCH_REQUIRE_GPIOLIB
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select S3C_DEV_NAND
        select IRQ_DOMAIN
        help
index a182008..0f92ba8 100644 (file)
@@ -10,7 +10,7 @@ config ARCH_SHMOBILE_MULTI
        select ARM_GIC
        select MIGHT_HAVE_PCI
        select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select PINCTRL
        select ARCH_REQUIRE_GPIOLIB
 
index 80b4be3..657d52d 100644 (file)
@@ -10,7 +10,7 @@ config ARCH_VEXPRESS
        select HAVE_ARM_TWD if SMP
        select HAVE_PATA_PLATFORM
        select ICST
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select PLAT_VERSATILE
        select PLAT_VERSATILE_CLCD
        select POWER_RESET
index b57e922..243dfcb 100644 (file)
@@ -9,7 +9,7 @@ config PLAT_SAMSUNG
        depends on PLAT_S3C24XX || ARCH_S3C64XX || PLAT_S5P || ARCH_EXYNOS
        default y
        select GENERIC_IRQ_CHIP
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        help
          Base platform code for all Samsung SoC based systems
 
@@ -19,7 +19,7 @@ config PLAT_S5P
        default y
        select ARCH_REQUIRE_GPIOLIB
        select ARM_VIC
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select PLAT_SAMSUNG
        select S3C_GPIO_TRACK
        select S5P_GPIO_DRVSTR
index 9711a5f..e6e4d37 100644 (file)
@@ -17,6 +17,7 @@ config ARM64
        select GENERIC_CLOCKEVENTS
        select GENERIC_CLOCKEVENTS_BROADCAST if SMP
        select GENERIC_CPU_AUTOPROBE
+       select GENERIC_EARLY_IOREMAP
        select GENERIC_IOMAP
        select GENERIC_IRQ_PROBE
        select GENERIC_IRQ_SHOW
@@ -66,7 +67,7 @@ config ARCH_PHYS_ADDR_T_64BIT
 config MMU
        def_bool y
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool y
 
 config STACKTRACE_SUPPORT
index 835c559..d10ec33 100644 (file)
@@ -6,6 +6,20 @@ config FRAME_POINTER
        bool
        default y
 
+config STRICT_DEVMEM
+       bool "Filter access to /dev/mem"
+       depends on MMU
+       help
+         If this option is disabled, you allow userspace (root) access to all
+         of memory, including kernel and userspace memory. Accidental
+         access to this is obviously disastrous, but specific access can
+         be used by people debugging the kernel.
+
+         If this option is switched on, the /dev/mem file only allows
+         userspace access to memory mapped peripherals.
+
+         If in doubt, say Y.
+
 config EARLY_PRINTK
        bool "Early printk support"
        default y
index 4bca492..83f71b3 100644 (file)
@@ -10,6 +10,7 @@ generic-y += delay.h
 generic-y += div64.h
 generic-y += dma.h
 generic-y += emergency-restart.h
+generic-y += early_ioremap.h
 generic-y += errno.h
 generic-y += ftrace.h
 generic-y += hash.h
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
new file mode 100644 (file)
index 0000000..5f7bfe6
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * fixmap.h: compile-time virtual memory allocation
+ *
+ * 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.
+ *
+ * Copyright (C) 1998 Ingo Molnar
+ * Copyright (C) 2013 Mark Salter <msalter@redhat.com>
+ *
+ * Adapted from arch/x86_64 version.
+ *
+ */
+
+#ifndef _ASM_ARM64_FIXMAP_H
+#define _ASM_ARM64_FIXMAP_H
+
+#ifndef __ASSEMBLY__
+#include <linux/kernel.h>
+#include <asm/page.h>
+
+/*
+ * Here we define all the compile-time 'special' virtual
+ * addresses. The point is to have a constant address at
+ * compile time, but to set the physical address only
+ * in the boot process.
+ *
+ * These 'compile-time allocated' memory buffers are
+ * page-sized. Use set_fixmap(idx,phys) to associate
+ * physical memory with fixmap indices.
+ *
+ */
+enum fixed_addresses {
+       FIX_EARLYCON_MEM_BASE,
+       __end_of_permanent_fixed_addresses,
+
+       /*
+        * Temporary boot-time mappings, used by early_ioremap(),
+        * before ioremap() is functional.
+        */
+#ifdef CONFIG_ARM64_64K_PAGES
+#define NR_FIX_BTMAPS          4
+#else
+#define NR_FIX_BTMAPS          64
+#endif
+#define FIX_BTMAPS_SLOTS       7
+#define TOTAL_FIX_BTMAPS       (NR_FIX_BTMAPS * FIX_BTMAPS_SLOTS)
+
+       FIX_BTMAP_END = __end_of_permanent_fixed_addresses,
+       FIX_BTMAP_BEGIN = FIX_BTMAP_END + TOTAL_FIX_BTMAPS - 1,
+       __end_of_fixed_addresses
+};
+
+#define FIXADDR_SIZE   (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
+#define FIXADDR_START  (FIXADDR_TOP - FIXADDR_SIZE)
+
+#define FIXMAP_PAGE_IO     __pgprot(PROT_DEVICE_nGnRE)
+
+extern void __early_set_fixmap(enum fixed_addresses idx,
+                              phys_addr_t phys, pgprot_t flags);
+
+#define __set_fixmap __early_set_fixmap
+
+#include <asm-generic/fixmap.h>
+
+#endif /* !__ASSEMBLY__ */
+#endif /* _ASM_ARM64_FIXMAP_H */
index 7846a6b..a1bef78 100644 (file)
@@ -27,6 +27,7 @@
 #include <asm/byteorder.h>
 #include <asm/barrier.h>
 #include <asm/pgtable.h>
+#include <asm/early_ioremap.h>
 
 #include <xen/xen.h>
 
index 9dc5dc3..e94f945 100644 (file)
@@ -49,7 +49,7 @@
 #define PAGE_OFFSET            (UL(0xffffffffffffffff) << (VA_BITS - 1))
 #define MODULES_END            (PAGE_OFFSET)
 #define MODULES_VADDR          (MODULES_END - SZ_64M)
-#define EARLYCON_IOBASE                (MODULES_VADDR - SZ_4M)
+#define FIXADDR_TOP            (MODULES_VADDR - SZ_2M - PAGE_SIZE)
 #define TASK_SIZE_64           (UL(1) << VA_BITS)
 
 #ifdef CONFIG_COMPAT
index 2494fc0..f600d40 100644 (file)
@@ -27,5 +27,6 @@ typedef struct {
 extern void paging_init(void);
 extern void setup_mm_for_reboot(void);
 extern void __iomem *early_io_map(phys_addr_t phys, unsigned long virt);
+extern void init_mem_pgprot(void);
 
 #endif
index f7af66b..5fc8a66 100644 (file)
 #define TCR_ORGN_WBnWA         ((UL(3) << 10) | (UL(3) << 26))
 #define TCR_ORGN_MASK          ((UL(3) << 10) | (UL(3) << 26))
 #define TCR_SHARED             ((UL(3) << 12) | (UL(3) << 28))
+#define TCR_TG0_4K             (UL(0) << 14)
 #define TCR_TG0_64K            (UL(1) << 14)
-#define TCR_TG1_64K            (UL(1) << 30)
+#define TCR_TG0_16K            (UL(2) << 14)
+#define TCR_TG1_16K            (UL(1) << 30)
+#define TCR_TG1_4K             (UL(2) << 30)
+#define TCR_TG1_64K            (UL(3) << 30)
 #define TCR_ASID16             (UL(1) << 36)
 #define TCR_TBI0               (UL(1) << 37)
 
index 130e2be..215ad46 100644 (file)
@@ -22,7 +22,6 @@
 #define BOOT_CPU_MODE_EL2      (0xe12)
 
 #ifndef __ASSEMBLY__
-#include <asm/cacheflush.h>
 
 /*
  * __boot_cpu_mode records what mode CPUs were booted in.
@@ -38,20 +37,9 @@ extern u32 __boot_cpu_mode[2];
 void __hyp_set_vectors(phys_addr_t phys_vector_base);
 phys_addr_t __hyp_get_vectors(void);
 
-static inline void sync_boot_mode(void)
-{
-       /*
-        * As secondaries write to __boot_cpu_mode with caches disabled, we
-        * must flush the corresponding cache entries to ensure the visibility
-        * of their writes.
-        */
-       __flush_dcache_area(__boot_cpu_mode, sizeof(__boot_cpu_mode));
-}
-
 /* Reports the availability of HYP mode */
 static inline bool is_hyp_mode_available(void)
 {
-       sync_boot_mode();
        return (__boot_cpu_mode[0] == BOOT_CPU_MODE_EL2 &&
                __boot_cpu_mode[1] == BOOT_CPU_MODE_EL2);
 }
@@ -59,7 +47,6 @@ static inline bool is_hyp_mode_available(void)
 /* Check if the bootloader has booted CPUs in different modes */
 static inline bool is_hyp_mode_mismatched(void)
 {
-       sync_boot_mode();
        return __boot_cpu_mode[0] != __boot_cpu_mode[1];
 }
 
index 14ba23c..ed3955a 100644 (file)
@@ -154,13 +154,17 @@ static struct notifier_block os_lock_nb = {
 
 static int debug_monitors_init(void)
 {
+       cpu_notifier_register_begin();
+
        /* Clear the OS lock. */
        on_each_cpu(clear_os_lock, NULL, 1);
        isb();
        local_dbg_enable();
 
        /* Register hotplug handler. */
-       register_cpu_notifier(&os_lock_nb);
+       __register_cpu_notifier(&os_lock_nb);
+
+       cpu_notifier_register_done();
        return 0;
 }
 postcore_initcall(debug_monitors_init);
index fbb6e18..ffbbdde 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/amba/serial.h>
 #include <linux/serial_reg.h>
 
+#include <asm/fixmap.h>
+
 static void __iomem *early_base;
 static void (*printch)(char ch);
 
@@ -141,8 +143,10 @@ static int __init setup_early_printk(char *buf)
        }
        /* no options parsing yet */
 
-       if (paddr)
-               early_base = early_io_map(paddr, EARLYCON_IOBASE);
+       if (paddr) {
+               set_fixmap_io(FIX_EARLYCON_MEM_BASE, paddr);
+               early_base = (void __iomem *)fix_to_virt(FIX_EARLYCON_MEM_BASE);
+       }
 
        printch = match->printch;
        early_console = &early_console_dev;
index 61035d6..0fd5650 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/assembler.h>
 #include <asm/ptrace.h>
 #include <asm/asm-offsets.h>
+#include <asm/cache.h>
 #include <asm/cputype.h>
 #include <asm/memory.h>
 #include <asm/thread_info.h>
@@ -229,7 +230,11 @@ ENTRY(set_cpu_boot_mode_flag)
        cmp     w20, #BOOT_CPU_MODE_EL2
        b.ne    1f
        add     x1, x1, #4
-1:     str     w20, [x1]                       // This CPU has booted in EL1
+1:     dc      cvac, x1                        // Clean potentially dirty cache line
+       dsb     sy
+       str     w20, [x1]                       // This CPU has booted in EL1
+       dc      civac, x1                       // Clean&invalidate potentially stale cache line
+       dsb     sy
        ret
 ENDPROC(set_cpu_boot_mode_flag)
 
@@ -240,8 +245,9 @@ ENDPROC(set_cpu_boot_mode_flag)
  * This is not in .bss, because we set it sufficiently early that the boot-time
  * zeroing of .bss would clobber it.
  */
-       .pushsection    .data
+       .pushsection    .data..cacheline_aligned
 ENTRY(__boot_cpu_mode)
+       .align  L1_CACHE_SHIFT
        .long   BOOT_CPU_MODE_EL2
        .long   0
        .popsection
@@ -404,10 +410,19 @@ ENDPROC(__calc_phys_offset)
  *   - identity mapping to enable the MMU (low address, TTBR0)
  *   - first few MB of the kernel linear mapping to jump to once the MMU has
  *     been enabled, including the FDT blob (TTBR1)
- *   - UART mapping if CONFIG_EARLY_PRINTK is enabled (TTBR1)
+ *   - pgd entry for fixed mappings (TTBR1)
  */
 __create_page_tables:
        pgtbl   x25, x26, x24                   // idmap_pg_dir and swapper_pg_dir addresses
+       mov     x27, lr
+
+       /*
+        * Invalidate the idmap and swapper page tables to avoid potential
+        * dirty cache lines being evicted.
+        */
+       mov     x0, x25
+       add     x1, x26, #SWAPPER_DIR_SIZE
+       bl      __inval_cache_range
 
        /*
         * Clear the idmap and swapper page tables.
@@ -461,15 +476,23 @@ __create_page_tables:
        sub     x6, x6, #1                      // inclusive range
        create_block_map x0, x7, x3, x5, x6
 1:
-#ifdef CONFIG_EARLY_PRINTK
        /*
-        * Create the pgd entry for the UART mapping. The full mapping is done
-        * later based earlyprintk kernel parameter.
+        * Create the pgd entry for the fixed mappings.
         */
-       ldr     x5, =EARLYCON_IOBASE            // UART virtual address
+       ldr     x5, =FIXADDR_TOP                // Fixed mapping virtual address
        add     x0, x26, #2 * PAGE_SIZE         // section table address
        create_pgd_entry x26, x0, x5, x6, x7
-#endif
+
+       /*
+        * Since the page tables have been populated with non-cacheable
+        * accesses (MMU disabled), invalidate the idmap and swapper page
+        * tables again to remove any speculatively loaded cache lines.
+        */
+       mov     x0, x25
+       add     x1, x26, #SWAPPER_DIR_SIZE
+       bl      __inval_cache_range
+
+       mov     lr, x27
        ret
 ENDPROC(__create_page_tables)
        .ltorg
index f17f581..bee7897 100644 (file)
@@ -913,6 +913,8 @@ static int __init arch_hw_breakpoint_init(void)
        pr_info("found %d breakpoint and %d watchpoint registers.\n",
                core_num_brps, core_num_wrps);
 
+       cpu_notifier_register_begin();
+
        /*
         * Reset the breakpoint resources. We assume that a halting
         * debugger will leave the world in a nice state for us.
@@ -927,7 +929,10 @@ static int __init arch_hw_breakpoint_init(void)
                              TRAP_HWBKPT, "hw-watchpoint handler");
 
        /* Register hotplug notifier. */
-       register_cpu_notifier(&hw_breakpoint_reset_nb);
+       __register_cpu_notifier(&hw_breakpoint_reset_nb);
+
+       cpu_notifier_register_done();
+
        /* Register cpu_suspend hw breakpoint restore hook */
        cpu_suspend_set_dbg_restorer(hw_breakpoint_reset);
 
index e868c72..baf5afb 100644 (file)
@@ -1386,6 +1386,7 @@ user_backtrace(struct frame_tail __user *tail,
        return buftail.fp;
 }
 
+#ifdef CONFIG_COMPAT
 /*
  * The registers we're interested in are at the end of the variable
  * length saved register structure. The fp points at the end of this
@@ -1430,6 +1431,7 @@ compat_user_backtrace(struct compat_frame_tail __user *tail,
 
        return (struct compat_frame_tail __user *)compat_ptr(buftail.fp) - 1;
 }
+#endif /* CONFIG_COMPAT */
 
 void perf_callchain_user(struct perf_callchain_entry *entry,
                         struct pt_regs *regs)
@@ -1451,6 +1453,7 @@ void perf_callchain_user(struct perf_callchain_entry *entry,
                       tail && !((unsigned long)tail & 0xf))
                        tail = user_backtrace(tail, entry);
        } else {
+#ifdef CONFIG_COMPAT
                /* AARCH32 compat mode */
                struct compat_frame_tail __user *tail;
 
@@ -1459,6 +1462,7 @@ void perf_callchain_user(struct perf_callchain_entry *entry,
                while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
                        tail && !((unsigned long)tail & 0x3))
                        tail = compat_user_backtrace(tail, entry);
+#endif
        }
 }
 
index f2d6f0a..422ebd6 100644 (file)
@@ -2,6 +2,8 @@
 #include <linux/kernel.h>
 #include <linux/perf_event.h>
 #include <linux/bug.h>
+
+#include <asm/compat.h>
 #include <asm/perf_regs.h>
 #include <asm/ptrace.h>
 
index 67da307..720853f 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/of_fdt.h>
 #include <linux/of_platform.h>
 
+#include <asm/fixmap.h>
 #include <asm/cputype.h>
 #include <asm/elf.h>
 #include <asm/cputable.h>
@@ -360,6 +361,9 @@ void __init setup_arch(char **cmdline_p)
 
        *cmdline_p = boot_command_line;
 
+       init_mem_pgprot();
+       early_ioremap_init();
+
        parse_early_param();
 
        arm64_memblock_init();
index c46f48b..fda7568 100644 (file)
@@ -167,6 +167,14 @@ ENTRY(__flush_dcache_area)
        ret
 ENDPROC(__flush_dcache_area)
 
+/*
+ *     __inval_cache_range(start, end)
+ *     - start   - start address of region
+ *     - end     - end address of region
+ */
+ENTRY(__inval_cache_range)
+       /* FALLTHROUGH */
+
 /*
  *     __dma_inv_range(start, end)
  *     - start   - virtual start address of region
@@ -175,14 +183,22 @@ ENDPROC(__flush_dcache_area)
 __dma_inv_range:
        dcache_line_size x2, x3
        sub     x3, x2, #1
-       bic     x0, x0, x3
+       tst     x1, x3                          // end cache line aligned?
        bic     x1, x1, x3
-1:     dc      ivac, x0                        // invalidate D / U line
-       add     x0, x0, x2
+       b.eq    1f
+       dc      civac, x1                       // clean & invalidate D / U line
+1:     tst     x0, x3                          // start cache line aligned?
+       bic     x0, x0, x3
+       b.eq    2f
+       dc      civac, x0                       // clean & invalidate D / U line
+       b       3f
+2:     dc      ivac, x0                        // invalidate D / U line
+3:     add     x0, x0, x2
        cmp     x0, x1
-       b.lo    1b
+       b.lo    2b
        dsb     sy
        ret
+ENDPROC(__inval_cache_range)
 ENDPROC(__dma_inv_range)
 
 /*
index 2bb1d58..7ec3283 100644 (file)
 #include <linux/vmalloc.h>
 #include <linux/io.h>
 
+#include <asm/fixmap.h>
+#include <asm/tlbflush.h>
+#include <asm/pgalloc.h>
+
 static void __iomem *__ioremap_caller(phys_addr_t phys_addr, size_t size,
                                      pgprot_t prot, void *caller)
 {
@@ -98,3 +102,84 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
                                __builtin_return_address(0));
 }
 EXPORT_SYMBOL(ioremap_cache);
+
+#ifndef CONFIG_ARM64_64K_PAGES
+static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
+#endif
+
+static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
+{
+       pgd_t *pgd;
+       pud_t *pud;
+
+       pgd = pgd_offset_k(addr);
+       BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
+
+       pud = pud_offset(pgd, addr);
+       BUG_ON(pud_none(*pud) || pud_bad(*pud));
+
+       return pmd_offset(pud, addr);
+}
+
+static inline pte_t * __init early_ioremap_pte(unsigned long addr)
+{
+       pmd_t *pmd = early_ioremap_pmd(addr);
+
+       BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
+
+       return pte_offset_kernel(pmd, addr);
+}
+
+void __init early_ioremap_init(void)
+{
+       pmd_t *pmd;
+
+       pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
+#ifndef CONFIG_ARM64_64K_PAGES
+       /* need to populate pmd for 4k pagesize only */
+       pmd_populate_kernel(&init_mm, pmd, bm_pte);
+#endif
+       /*
+        * The boot-ioremap range spans multiple pmds, for which
+        * we are not prepared:
+        */
+       BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
+                    != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
+
+       if (pmd != early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))) {
+               WARN_ON(1);
+               pr_warn("pmd %p != %p\n",
+                       pmd, early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END)));
+               pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
+                       fix_to_virt(FIX_BTMAP_BEGIN));
+               pr_warn("fix_to_virt(FIX_BTMAP_END):   %08lx\n",
+                       fix_to_virt(FIX_BTMAP_END));
+
+               pr_warn("FIX_BTMAP_END:       %d\n", FIX_BTMAP_END);
+               pr_warn("FIX_BTMAP_BEGIN:     %d\n",
+                       FIX_BTMAP_BEGIN);
+       }
+
+       early_ioremap_setup();
+}
+
+void __init __early_set_fixmap(enum fixed_addresses idx,
+                              phys_addr_t phys, pgprot_t flags)
+{
+       unsigned long addr = __fix_to_virt(idx);
+       pte_t *pte;
+
+       if (idx >= __end_of_fixed_addresses) {
+               BUG();
+               return;
+       }
+
+       pte = early_ioremap_pte(addr);
+
+       if (pgprot_val(flags))
+               set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
+       else {
+               pte_clear(&init_mm, addr, pte);
+               flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
+       }
+}
index f8dc7e8..6b7e895 100644 (file)
@@ -125,7 +125,7 @@ early_param("cachepolicy", early_cachepolicy);
 /*
  * Adjust the PMD section entries according to the CPU in use.
  */
-static void __init init_mem_pgprot(void)
+void __init init_mem_pgprot(void)
 {
        pteval_t default_pgprot;
        int i;
@@ -260,47 +260,6 @@ static void __init create_mapping(phys_addr_t phys, unsigned long virt,
        } while (pgd++, addr = next, addr != end);
 }
 
-#ifdef CONFIG_EARLY_PRINTK
-/*
- * Create an early I/O mapping using the pgd/pmd entries already populated
- * in head.S as this function is called too early to allocated any memory. The
- * mapping size is 2MB with 4KB pages or 64KB or 64KB pages.
- */
-void __iomem * __init early_io_map(phys_addr_t phys, unsigned long virt)
-{
-       unsigned long size, mask;
-       bool page64k = IS_ENABLED(CONFIG_ARM64_64K_PAGES);
-       pgd_t *pgd;
-       pud_t *pud;
-       pmd_t *pmd;
-       pte_t *pte;
-
-       /*
-        * No early pte entries with !ARM64_64K_PAGES configuration, so using
-        * sections (pmd).
-        */
-       size = page64k ? PAGE_SIZE : SECTION_SIZE;
-       mask = ~(size - 1);
-
-       pgd = pgd_offset_k(virt);
-       pud = pud_offset(pgd, virt);
-       if (pud_none(*pud))
-               return NULL;
-       pmd = pmd_offset(pud, virt);
-
-       if (page64k) {
-               if (pmd_none(*pmd))
-                       return NULL;
-               pte = pte_offset_kernel(pmd, virt);
-               set_pte(pte, __pte((phys & mask) | PROT_DEVICE_nGnRE));
-       } else {
-               set_pmd(pmd, __pmd((phys & mask) | PROT_SECT_DEVICE_nGnRE));
-       }
-
-       return (void __iomem *)((virt & mask) + (phys & ~mask));
-}
-#endif
-
 static void __init map_mem(void)
 {
        struct memblock_region *reg;
@@ -357,7 +316,6 @@ void __init paging_init(void)
 {
        void *zero_page;
 
-       init_mem_pgprot();
        map_mem();
 
        /*
index e085ee6..9042aff 100644 (file)
 
 #include "proc-macros.S"
 
-#ifndef CONFIG_SMP
-/* PTWs cacheable, inner/outer WBWA not shareable */
-#define TCR_FLAGS      TCR_IRGN_WBWA | TCR_ORGN_WBWA
+#ifdef CONFIG_ARM64_64K_PAGES
+#define TCR_TG_FLAGS   TCR_TG0_64K | TCR_TG1_64K
+#else
+#define TCR_TG_FLAGS   TCR_TG0_4K | TCR_TG1_4K
+#endif
+
+#ifdef CONFIG_SMP
+#define TCR_SMP_FLAGS  TCR_SHARED
 #else
-/* PTWs cacheable, inner/outer WBWA shareable */
-#define TCR_FLAGS      TCR_IRGN_WBWA | TCR_ORGN_WBWA | TCR_SHARED
+#define TCR_SMP_FLAGS  0
 #endif
 
+/* PTWs cacheable, inner/outer WBWA */
+#define TCR_CACHE_FLAGS        TCR_IRGN_WBWA | TCR_ORGN_WBWA
+
 #define MAIR(attr, mt) ((attr) << ((mt) * 8))
 
 /*
@@ -209,18 +216,14 @@ ENTRY(__cpu_setup)
         * Set/prepare TCR and TTBR. We use 512GB (39-bit) address range for
         * both user and kernel.
         */
-       ldr     x10, =TCR_TxSZ(VA_BITS) | TCR_FLAGS | \
-                     TCR_ASID16 | TCR_TBI0 | (1 << 31)
+       ldr     x10, =TCR_TxSZ(VA_BITS) | TCR_CACHE_FLAGS | TCR_SMP_FLAGS | \
+                       TCR_TG_FLAGS | TCR_ASID16 | TCR_TBI0
        /*
         * Read the PARange bits from ID_AA64MMFR0_EL1 and set the IPS bits in
         * TCR_EL1.
         */
        mrs     x9, ID_AA64MMFR0_EL1
        bfi     x10, x9, #32, #3
-#ifdef CONFIG_ARM64_64K_PAGES
-       orr     x10, x10, TCR_TG0_64K
-       orr     x10, x10, TCR_TG1_64K
-#endif
        msr     tcr_el1, x10
        ret                                     // return to head.S
 ENDPROC(__cpu_setup)
index 90c3c00..aaa0834 100644 (file)
@@ -9,60 +9,7 @@
 #ifndef __ASM_BFIN_TWI_H__
 #define __ASM_BFIN_TWI_H__
 
-#include <linux/types.h>
-#include <linux/i2c.h>
-
-/*
- * All Blackfin system MMRs are padded to 32bits even if the register
- * itself is only 16bits.  So use a helper macro to streamline this.
- */
-#define __BFP(m) u16 m; u16 __pad_##m
-
-/*
- * bfin twi registers layout
- */
-struct bfin_twi_regs {
-       __BFP(clkdiv);
-       __BFP(control);
-       __BFP(slave_ctl);
-       __BFP(slave_stat);
-       __BFP(slave_addr);
-       __BFP(master_ctl);
-       __BFP(master_stat);
-       __BFP(master_addr);
-       __BFP(int_stat);
-       __BFP(int_mask);
-       __BFP(fifo_ctl);
-       __BFP(fifo_stat);
-       u32 __pad[20];
-       __BFP(xmt_data8);
-       __BFP(xmt_data16);
-       __BFP(rcv_data8);
-       __BFP(rcv_data16);
-};
-
-#undef __BFP
-
-struct bfin_twi_iface {
-       int                     irq;
-       spinlock_t              lock;
-       char                    read_write;
-       u8                      command;
-       u8                      *transPtr;
-       int                     readNum;
-       int                     writeNum;
-       int                     cur_mode;
-       int                     manual_stop;
-       int                     result;
-       struct i2c_adapter      adap;
-       struct completion       complete;
-       struct i2c_msg          *pmsg;
-       int                     msg_num;
-       int                     cur_msg;
-       u16                     saved_clkdiv;
-       u16                     saved_control;
-       struct bfin_twi_regs __iomem *regs_base;
-};
+#include <asm/blackfin.h>
 
 #define DEFINE_TWI_REG(reg_name, reg) \
 static inline u16 read_##reg_name(struct bfin_twi_iface *iface) \
@@ -71,7 +18,6 @@ static inline void write_##reg_name(struct bfin_twi_iface *iface, u16 v) \
        { bfin_write16(&iface->regs_base->reg, v); }
 
 DEFINE_TWI_REG(CLKDIV, clkdiv)
-DEFINE_TWI_REG(CONTROL, control)
 DEFINE_TWI_REG(SLAVE_CTL, slave_ctl)
 DEFINE_TWI_REG(SLAVE_STAT, slave_stat)
 DEFINE_TWI_REG(SLAVE_ADDR, slave_addr)
@@ -80,7 +26,6 @@ DEFINE_TWI_REG(MASTER_STAT, master_stat)
 DEFINE_TWI_REG(MASTER_ADDR, master_addr)
 DEFINE_TWI_REG(INT_STAT, int_stat)
 DEFINE_TWI_REG(INT_MASK, int_mask)
-DEFINE_TWI_REG(FIFO_CTL, fifo_ctl)
 DEFINE_TWI_REG(FIFO_STAT, fifo_stat)
 DEFINE_TWI_REG(XMT_DATA8, xmt_data8)
 DEFINE_TWI_REG(XMT_DATA16, xmt_data16)
@@ -113,75 +58,25 @@ static inline u16 read_RCV_DATA16(struct bfin_twi_iface *iface)
 }
 #endif
 
+static inline u16 read_FIFO_CTL(struct bfin_twi_iface *iface)
+{
+       return bfin_read16(&iface->regs_base->fifo_ctl);
+}
 
-/*  ********************  TWO-WIRE INTERFACE (TWI) MASKS  ***********************/
-/* TWI_CLKDIV Macros (Use: *pTWI_CLKDIV = CLKLOW(x)|CLKHI(y);  )                               */
-#define        CLKLOW(x)       ((x) & 0xFF)    /* Periods Clock Is Held Low                    */
-#define CLKHI(y)       (((y)&0xFF)<<0x8)       /* Periods Before New Clock Low                 */
-
-/* TWI_PRESCALE Masks                                                                                                                  */
-#define        PRESCALE        0x007F  /* SCLKs Per Internal Time Reference (10MHz)    */
-#define        TWI_ENA         0x0080  /* TWI Enable                                                                   */
-#define        SCCB            0x0200  /* SCCB Compatibility Enable                                    */
-
-/* TWI_SLAVE_CTL Masks                                                                                                                 */
-#define        SEN                     0x0001  /* Slave Enable                                                                 */
-#define        SADD_LEN        0x0002  /* Slave Address Length                                                 */
-#define        STDVAL          0x0004  /* Slave Transmit Data Valid                                    */
-#define        NAK                     0x0008  /* NAK/ACK* Generated At Conclusion Of Transfer */
-#define        GEN                     0x0010  /* General Call Address Matching Enabled                */
-
-/* TWI_SLAVE_STAT Masks                                                                                                                        */
-#define        SDIR            0x0001  /* Slave Transfer Direction (Transmit/Receive*) */
-#define GCALL          0x0002  /* General Call Indicator                                               */
-
-/* TWI_MASTER_CTL Masks                                                                                                        */
-#define        MEN                     0x0001  /* Master Mode Enable                                           */
-#define        MADD_LEN        0x0002  /* Master Address Length                                        */
-#define        MDIR            0x0004  /* Master Transmit Direction (RX/TX*)           */
-#define        FAST            0x0008  /* Use Fast Mode Timing Specs                           */
-#define        STOP            0x0010  /* Issue Stop Condition                                         */
-#define        RSTART          0x0020  /* Repeat Start or Stop* At End Of Transfer     */
-#define        DCNT            0x3FC0  /* Data Bytes To Transfer                                       */
-#define        SDAOVR          0x4000  /* Serial Data Override                                         */
-#define        SCLOVR          0x8000  /* Serial Clock Override                                        */
-
-/* TWI_MASTER_STAT Masks                                                                                                               */
-#define        MPROG           0x0001  /* Master Transfer In Progress                                  */
-#define        LOSTARB         0x0002  /* Lost Arbitration Indicator (Xfer Aborted)    */
-#define        ANAK            0x0004  /* Address Not Acknowledged                                             */
-#define        DNAK            0x0008  /* Data Not Acknowledged                                                */
-#define        BUFRDERR        0x0010  /* Buffer Read Error                                                    */
-#define        BUFWRERR        0x0020  /* Buffer Write Error                                                   */
-#define        SDASEN          0x0040  /* Serial Data Sense                                                    */
-#define        SCLSEN          0x0080  /* Serial Clock Sense                                                   */
-#define        BUSBUSY         0x0100  /* Bus Busy Indicator                                                   */
-
-/* TWI_INT_SRC and TWI_INT_ENABLE Masks                                                */
-#define        SINIT           0x0001  /* Slave Transfer Initiated     */
-#define        SCOMP           0x0002  /* Slave Transfer Complete      */
-#define        SERR            0x0004  /* Slave Transfer Error         */
-#define        SOVF            0x0008  /* Slave Overflow                       */
-#define        MCOMP           0x0010  /* Master Transfer Complete     */
-#define        MERR            0x0020  /* Master Transfer Error        */
-#define        XMTSERV         0x0040  /* Transmit FIFO Service        */
-#define        RCVSERV         0x0080  /* Receive FIFO Service         */
-
-/* TWI_FIFO_CTRL Masks                                                                                         */
-#define        XMTFLUSH        0x0001  /* Transmit Buffer Flush                        */
-#define        RCVFLUSH        0x0002  /* Receive Buffer Flush                         */
-#define        XMTINTLEN       0x0004  /* Transmit Buffer Interrupt Length     */
-#define        RCVINTLEN       0x0008  /* Receive Buffer Interrupt Length      */
-
-/* TWI_FIFO_STAT Masks                                                                                                                 */
-#define        XMTSTAT         0x0003  /* Transmit FIFO Status                                                 */
-#define        XMT_EMPTY       0x0000  /*              Transmit FIFO Empty                                             */
-#define        XMT_HALF        0x0001  /*              Transmit FIFO Has 1 Byte To Write               */
-#define        XMT_FULL        0x0003  /*              Transmit FIFO Full (2 Bytes To Write)   */
+static inline void write_FIFO_CTL(struct bfin_twi_iface *iface, u16 v)
+{
+       bfin_write16(&iface->regs_base->fifo_ctl, v);
+       SSYNC();
+}
 
-#define        RCVSTAT         0x000C  /* Receive FIFO Status                                                  */
-#define        RCV_EMPTY       0x0000  /*              Receive FIFO Empty                                              */
-#define        RCV_HALF        0x0004  /*              Receive FIFO Has 1 Byte To Read                 */
-#define        RCV_FULL        0x000C  /*              Receive FIFO Full (2 Bytes To Read)             */
+static inline u16 read_CONTROL(struct bfin_twi_iface *iface)
+{
+       return bfin_read16(&iface->regs_base->control);
+}
 
+static inline void write_CONTROL(struct bfin_twi_iface *iface, u16 v)
+{
+       SSYNC();
+       bfin_write16(&iface->regs_base->control, v);
+}
 #endif
index 01232a1..947ad08 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/i2c/bfin_twi.h>
 
 #include <asm/blackfin.h>
 #include <asm/gpio.h>
index ed0fcdf..52731e2 100644 (file)
@@ -29,7 +29,7 @@ config GENERIC_CALIBRATE_DELAY
        bool
        default y
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool y
 
 config FORCE_MAX_ZONEORDER
@@ -138,6 +138,7 @@ config ETRAX_ARCH_V10
        bool
        default y if ETRAX100LX || ETRAX100LX_V2
        default n if !(ETRAX100LX || ETRAX100LX_V2)
+       select TTY
 
 config ETRAX_ARCH_V32
        bool
index 32c3d24..905b70e 100644 (file)
@@ -165,6 +165,7 @@ void __init setup_arch(char **cmdline_p)
        strcpy(init_utsname()->machine, cris_machine_name);
 }
 
+#ifdef CONFIG_PROC_FS
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
        return *pos < nr_cpu_ids ? (void *)(int)(*pos + 1) : NULL;
@@ -188,6 +189,7 @@ const struct seq_operations cpuinfo_op = {
        .stop  = c_stop,
        .show  = show_cpuinfo,
 };
+#endif /* CONFIG_PROC_FS */
 
 static int __init topology_init(void)
 {
index fbc5c78..0fd6138 100644 (file)
@@ -19,7 +19,7 @@ config HEXAGON
        select GENERIC_IRQ_SHOW
        select HAVE_ARCH_KGDB
        select HAVE_ARCH_TRACEHOOK
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select GENERIC_IOMAP
        select GENERIC_SMP_IDLE_THREAD
        select STACKTRACE_SUPPORT
index 0c8e553..1325c3b 100644 (file)
@@ -21,6 +21,7 @@ config IA64
        select HAVE_FUNCTION_TRACER
        select HAVE_DMA_ATTRS
        select HAVE_KVM
+       select TTY
        select HAVE_ARCH_TRACEHOOK
        select HAVE_DMA_API_DEBUG
        select HAVE_MEMBLOCK
index f59c0b8..0c161ed 100644 (file)
@@ -269,12 +269,17 @@ err_inject_init(void)
 #ifdef ERR_INJ_DEBUG
        printk(KERN_INFO "Enter error injection driver.\n");
 #endif
+
+       cpu_notifier_register_begin();
+
        for_each_online_cpu(i) {
                err_inject_cpu_callback(&err_inject_cpu_notifier, CPU_ONLINE,
                                (void *)(long)i);
        }
 
-       register_hotcpu_notifier(&err_inject_cpu_notifier);
+       __register_hotcpu_notifier(&err_inject_cpu_notifier);
+
+       cpu_notifier_register_done();
 
        return 0;
 }
@@ -288,11 +293,17 @@ err_inject_exit(void)
 #ifdef ERR_INJ_DEBUG
        printk(KERN_INFO "Exit error injection driver.\n");
 #endif
+
+       cpu_notifier_register_begin();
+
        for_each_online_cpu(i) {
                sys_dev = get_cpu_device(i);
                sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
        }
-       unregister_hotcpu_notifier(&err_inject_cpu_notifier);
+
+       __unregister_hotcpu_notifier(&err_inject_cpu_notifier);
+
+       cpu_notifier_register_done();
 }
 
 module_init(err_inject_init);
index ab33328..c39c3cd 100644 (file)
@@ -996,13 +996,17 @@ palinfo_init(void)
        if (!palinfo_dir)
                return -ENOMEM;
 
+       cpu_notifier_register_begin();
+
        /* Create palinfo dirs in /proc for all online cpus */
        for_each_online_cpu(i) {
                create_palinfo_proc_entries(i);
        }
 
        /* Register for future delivery via notify registration */
-       register_hotcpu_notifier(&palinfo_cpu_notifier);
+       __register_hotcpu_notifier(&palinfo_cpu_notifier);
+
+       cpu_notifier_register_done();
 
        return 0;
 }
index 960a396..ee9719e 100644 (file)
@@ -635,6 +635,8 @@ salinfo_init(void)
                                           (void *)salinfo_entries[i].feature);
        }
 
+       cpu_notifier_register_begin();
+
        for (i = 0; i < ARRAY_SIZE(salinfo_log_name); i++) {
                data = salinfo_data + i;
                data->type = i;
@@ -669,7 +671,9 @@ salinfo_init(void)
        salinfo_timer.function = &salinfo_timeout;
        add_timer(&salinfo_timer);
 
-       register_hotcpu_notifier(&salinfo_cpu_notifier);
+       __register_hotcpu_notifier(&salinfo_cpu_notifier);
+
+       cpu_notifier_register_done();
 
        return 0;
 }
index ca69a5a..f295f9a 100644 (file)
@@ -454,12 +454,16 @@ static int __init cache_sysfs_init(void)
 {
        int i;
 
+       cpu_notifier_register_begin();
+
        for_each_online_cpu(i) {
                struct device *sys_dev = get_cpu_device((unsigned int)i);
                cache_add_dev(sys_dev);
        }
 
-       register_hotcpu_notifier(&cache_cpu_notifier);
+       __register_hotcpu_notifier(&cache_cpu_notifier);
+
+       cpu_notifier_register_done();
 
        return 0;
 }
index ca45044..9e44bbd 100644 (file)
@@ -28,7 +28,7 @@ config ZONE_DMA
        bool
        default y
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool y
 
 config NO_DMA
index b2e3229..87b7c75 100644 (file)
@@ -52,7 +52,7 @@ config TIME_LOW_RES
        bool
        default y
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool y
 
 config NO_DMA
index b1d3c9c..499b761 100644 (file)
@@ -52,7 +52,7 @@ config GENERIC_HWEIGHT
 config GENERIC_CALIBRATE_DELAY
        def_bool y
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool y
 
 source "init/Kconfig"
index 16d5ab1..5cd695f 100644 (file)
@@ -175,7 +175,7 @@ config MACH_DECSTATION
        select CPU_R4000_WORKAROUNDS if 64BIT
        select CPU_R4400_WORKAROUNDS if 64BIT
        select DMA_NONCOHERENT
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select IRQ_CPU
        select SYS_HAS_CPU_R3000
        select SYS_HAS_CPU_R4X00
@@ -947,7 +947,7 @@ config SYNC_R4K
 config MIPS_MACHINE
        def_bool n
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool n
 
 config GENERIC_ISA_DMA
index 9488209..e71d712 100644 (file)
@@ -41,7 +41,7 @@ config RWSEM_XCHGADD_ALGORITHM
 config GENERIC_HWEIGHT
        def_bool y
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool y
 
 config TRACE_IRQFLAGS_SUPPORT
index 0f4344e..4c0cedf 100644 (file)
@@ -74,6 +74,7 @@ override CROSS32AS += -mlittle-endian
 LDEMULATION    := lppc
 GNUTARGET      := powerpcle
 MULTIPLEWORD   := -mno-multiple
+KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-save-toc-indirect)
 else
 ifeq ($(call cc-option-yn,-mbig-endian),y)
 override CC    += -mbig-endian
index 4358e30..f00e10e 100644 (file)
@@ -54,6 +54,7 @@ extern struct ppc_emulated {
 #ifdef CONFIG_PPC64
        struct ppc_emulated_entry mfdscr;
        struct ppc_emulated_entry mtdscr;
+       struct ppc_emulated_entry lq_stq;
 #endif
 } ppc_emulated;
 
index 88dbf96..a677456 100644 (file)
@@ -210,7 +210,6 @@ extern int is_fadump_active(void);
 extern void crash_fadump(struct pt_regs *, const char *);
 extern void fadump_cleanup(void);
 
-extern void vmcore_cleanup(void);
 #else  /* CONFIG_FA_DUMP */
 static inline int is_fadump_active(void) { return 0; }
 static inline void crash_fadump(struct pt_regs *regs, const char *str) { }
index fe2aa0b..a2efdaa 100644 (file)
@@ -87,6 +87,7 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #define OPAL_ASYNC_COMPLETION  -15
 
 /* API Tokens (in r0) */
+#define OPAL_INVALID_CALL                      -1
 #define OPAL_CONSOLE_WRITE                     1
 #define OPAL_CONSOLE_READ                      2
 #define OPAL_RTC_READ                          3
@@ -177,6 +178,8 @@ extern int opal_enter_rtas(struct rtas_args *args,
 
 #ifndef __ASSEMBLY__
 
+#include <linux/notifier.h>
+
 /* Other enums */
 enum OpalVendorApiTokens {
        OPAL_START_VENDOR_API_RANGE = 1000, OPAL_END_VENDOR_API_RANGE = 1999
@@ -422,9 +425,9 @@ enum OpalSysparamPerm {
 };
 
 struct opal_msg {
-       uint32_t msg_type;
-       uint32_t reserved;
-       uint64_t params[8];
+       __be32 msg_type;
+       __be32 reserved;
+       __be64 params[8];
 };
 
 struct opal_machine_check_event {
@@ -730,7 +733,11 @@ typedef struct oppanel_line {
 /* /sys/firmware/opal */
 extern struct kobject *opal_kobj;
 
+/* /ibm,opal */
+extern struct device_node *opal_node;
+
 /* API functions */
+int64_t opal_invalid_call(void);
 int64_t opal_console_write(int64_t term_number, __be64 *length,
                           const uint8_t *buffer);
 int64_t opal_console_read(int64_t term_number, __be64 *length,
@@ -874,8 +881,7 @@ int64_t opal_get_param(uint64_t token, uint32_t param_id, uint64_t buffer,
                size_t length);
 int64_t opal_set_param(uint64_t token, uint32_t param_id, uint64_t buffer,
                size_t length);
-int64_t opal_sensor_read(uint32_t sensor_hndl, int token,
-               uint32_t *sensor_data);
+int64_t opal_sensor_read(uint32_t sensor_hndl, int token, __be32 *sensor_data);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
@@ -892,6 +898,8 @@ extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
                                   int depth, void *data);
 
 extern int opal_notifier_register(struct notifier_block *nb);
+extern int opal_notifier_unregister(struct notifier_block *nb);
+
 extern int opal_message_notifier_register(enum OpalMessageType msg_type,
                                                struct notifier_block *nb);
 extern void opal_notifier_enable(void);
@@ -919,6 +927,7 @@ extern void opal_flash_init(void);
 extern int opal_elog_init(void);
 extern void opal_platform_dump_init(void);
 extern void opal_sys_param_init(void);
+extern void opal_msglog_init(void);
 
 extern int opal_machine_check(struct pt_regs *regs);
 extern bool opal_mce_check_early_recovery(struct pt_regs *regs);
index a0e1add..b390f55 100644 (file)
@@ -150,19 +150,53 @@ struct rtas_suspend_me_data {
 #define RTAS_VECTOR_EXTERNAL_INTERRUPT 0x500
 
 struct rtas_error_log {
-       unsigned long version:8;                /* Architectural version */
-       unsigned long severity:3;               /* Severity level of error */
-       unsigned long disposition:2;            /* Degree of recovery */
-       unsigned long extended:1;               /* extended log present? */
-       unsigned long /* reserved */ :2;        /* Reserved for future use */
-       unsigned long initiator:4;              /* Initiator of event */
-       unsigned long target:4;                 /* Target of failed operation */
-       unsigned long type:8;                   /* General event or error*/
-       unsigned long extended_log_length:32;   /* length in bytes */
-       unsigned char buffer[1];                /* Start of extended log */
+       /* Byte 0 */
+       uint8_t         byte0;                  /* Architectural version */
+
+       /* Byte 1 */
+       uint8_t         byte1;
+       /* XXXXXXXX
+        * XXX          3: Severity level of error
+        *    XX        2: Degree of recovery
+        *      X       1: Extended log present?
+        *       XX     2: Reserved
+        */
+
+       /* Byte 2 */
+       uint8_t         byte2;
+       /* XXXXXXXX
+        * XXXX         4: Initiator of event
+        *     XXXX     4: Target of failed operation
+        */
+       uint8_t         byte3;                  /* General event or error*/
+       __be32          extended_log_length;    /* length in bytes */
+       unsigned char   buffer[1];              /* Start of extended log */
                                                /* Variable length.      */
 };
 
+static inline uint8_t rtas_error_severity(const struct rtas_error_log *elog)
+{
+       return (elog->byte1 & 0xE0) >> 5;
+}
+
+static inline uint8_t rtas_error_disposition(const struct rtas_error_log *elog)
+{
+       return (elog->byte1 & 0x18) >> 3;
+}
+
+static inline uint8_t rtas_error_extended(const struct rtas_error_log *elog)
+{
+       return (elog->byte1 & 0x04) >> 2;
+}
+
+#define rtas_error_type(x)     ((x)->byte3)
+
+static inline
+uint32_t rtas_error_extended_log_length(const struct rtas_error_log *elog)
+{
+       return be32_to_cpu(elog->extended_log_length);
+}
+
 #define RTAS_V6EXT_LOG_FORMAT_EVENT_LOG        14
 
 #define RTAS_V6EXT_COMPANY_ID_IBM      (('I' << 24) | ('B' << 16) | ('M' << 8))
@@ -172,32 +206,35 @@ struct rtas_error_log {
  */
 struct rtas_ext_event_log_v6 {
        /* Byte 0 */
-       uint32_t log_valid:1;           /* 1:Log valid */
-       uint32_t unrecoverable_error:1; /* 1:Unrecoverable error */
-       uint32_t recoverable_error:1;   /* 1:recoverable (correctable   */
-                                       /*   or successfully retried)   */
-       uint32_t degraded_operation:1;  /* 1:Unrecoverable err, bypassed*/
-                                       /*   - degraded operation (e.g. */
-                                       /*   CPU or mem taken off-line) */
-       uint32_t predictive_error:1;
-       uint32_t new_log:1;             /* 1:"New" log (Always 1 for    */
-                                       /*   data returned from RTAS    */
-       uint32_t big_endian:1;          /* 1: Big endian */
-       uint32_t :1;                    /* reserved */
+       uint8_t byte0;
+       /* XXXXXXXX
+        * X            1: Log valid
+        *  X           1: Unrecoverable error
+        *   X          1: Recoverable (correctable or successfully retried)
+        *    X         1: Bypassed unrecoverable error (degraded operation)
+        *     X        1: Predictive error
+        *      X       1: "New" log (always 1 for data returned from RTAS)
+        *       X      1: Big Endian
+        *        X     1: Reserved
+        */
+
        /* Byte 1 */
-       uint32_t :8;                    /* reserved */
+       uint8_t byte1;                  /* reserved */
+
        /* Byte 2 */
-       uint32_t powerpc_format:1;      /* Set to 1 (indicating log is  */
-                                       /* in PowerPC format            */
-       uint32_t :3;                    /* reserved */
-       uint32_t log_format:4;          /* Log format indicator. Define */
-                                       /* format used for byte 12-2047 */
+       uint8_t byte2;
+       /* XXXXXXXX
+        * X            1: Set to 1 (indicating log is in PowerPC format)
+        *  XXX         3: Reserved
+        *     XXXX     4: Log format used for bytes 12-2047
+        */
+
        /* Byte 3 */
-       uint32_t :8;                    /* reserved */
+       uint8_t byte3;                  /* reserved */
        /* Byte 4-11 */
        uint8_t reserved[8];            /* reserved */
        /* Byte 12-15 */
-       uint32_t company_id;            /* Company ID of the company    */
+       __be32  company_id;             /* Company ID of the company    */
                                        /* that defines the format for  */
                                        /* the vendor specific log type */
        /* Byte 16-end of log */
@@ -205,6 +242,18 @@ struct rtas_ext_event_log_v6 {
                                        /* Variable length.             */
 };
 
+static
+inline uint8_t rtas_ext_event_log_format(struct rtas_ext_event_log_v6 *ext_log)
+{
+       return ext_log->byte2 & 0x0F;
+}
+
+static
+inline uint32_t rtas_ext_event_company_id(struct rtas_ext_event_log_v6 *ext_log)
+{
+       return be32_to_cpu(ext_log->company_id);
+}
+
 /* pSeries event log format */
 
 /* Two bytes ASCII section IDs */
@@ -227,14 +276,26 @@ struct rtas_ext_event_log_v6 {
 
 /* Vendor specific Platform Event Log Format, Version 6, section header */
 struct pseries_errorlog {
-       uint16_t id;                    /* 0x00 2-byte ASCII section ID */
-       uint16_t length;                /* 0x02 Section length in bytes */
+       __be16 id;                      /* 0x00 2-byte ASCII section ID */
+       __be16 length;                  /* 0x02 Section length in bytes */
        uint8_t version;                /* 0x04 Section version         */
        uint8_t subtype;                /* 0x05 Section subtype         */
-       uint16_t creator_component;     /* 0x06 Creator component ID    */
+       __be16 creator_component;       /* 0x06 Creator component ID    */
        uint8_t data[];                 /* 0x08 Start of section data   */
 };
 
+static
+inline uint16_t pseries_errorlog_id(struct pseries_errorlog *sect)
+{
+       return be16_to_cpu(sect->id);
+}
+
+static
+inline uint16_t pseries_errorlog_length(struct pseries_errorlog *sect)
+{
+       return be16_to_cpu(sect->length);
+}
+
 struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
                                              uint16_t section_id);
 
index de91f3a..94908af 100644 (file)
@@ -73,7 +73,7 @@ static struct aligninfo aligninfo[128] = {
        { 8, LD+F },            /* 00 0 1001: lfd */
        { 4, ST+F+S },          /* 00 0 1010: stfs */
        { 8, ST+F },            /* 00 0 1011: stfd */
-       INVALID,                /* 00 0 1100 */
+       { 16, LD },             /* 00 0 1100: lq */
        { 8, LD },              /* 00 0 1101: ld/ldu/lwa */
        INVALID,                /* 00 0 1110 */
        { 8, ST },              /* 00 0 1111: std/stdu */
@@ -140,7 +140,7 @@ static struct aligninfo aligninfo[128] = {
        { 2, LD+SW },           /* 10 0 1100: lhbrx */
        { 4, LD+SE },           /* 10 0 1101  lwa */
        { 2, ST+SW },           /* 10 0 1110: sthbrx */
-       INVALID,                /* 10 0 1111 */
+       { 16, ST },             /* 10 0 1111: stq */
        INVALID,                /* 10 1 0000 */
        INVALID,                /* 10 1 0001 */
        INVALID,                /* 10 1 0010 */
@@ -385,8 +385,6 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
        char *ptr1 = (char *) &current->thread.TS_FPR(reg+1);
        int i, ret, sw = 0;
 
-       if (!(flags & F))
-               return 0;
        if (reg & 1)
                return 0;       /* invalid form: FRS/FRT must be even */
        if (flags & SW)
@@ -406,6 +404,34 @@ static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
        return 1;       /* exception handled and fixed up */
 }
 
+#ifdef CONFIG_PPC64
+static int emulate_lq_stq(struct pt_regs *regs, unsigned char __user *addr,
+                         unsigned int reg, unsigned int flags)
+{
+       char *ptr0 = (char *)&regs->gpr[reg];
+       char *ptr1 = (char *)&regs->gpr[reg+1];
+       int i, ret, sw = 0;
+
+       if (reg & 1)
+               return 0;       /* invalid form: GPR must be even */
+       if (flags & SW)
+               sw = 7;
+       ret = 0;
+       for (i = 0; i < 8; ++i) {
+               if (!(flags & ST)) {
+                       ret |= __get_user(ptr0[i^sw], addr + i);
+                       ret |= __get_user(ptr1[i^sw], addr + i + 8);
+               } else {
+                       ret |= __put_user(ptr0[i^sw], addr + i);
+                       ret |= __put_user(ptr1[i^sw], addr + i + 8);
+               }
+       }
+       if (ret)
+               return -EFAULT;
+       return 1;       /* exception handled and fixed up */
+}
+#endif /* CONFIG_PPC64 */
+
 #ifdef CONFIG_SPE
 
 static struct aligninfo spe_aligninfo[32] = {
@@ -914,10 +940,20 @@ int fix_alignment(struct pt_regs *regs)
                flush_fp_to_thread(current);
        }
 
-       /* Special case for 16-byte FP loads and stores */
-       if (nb == 16) {
-               PPC_WARN_ALIGNMENT(fp_pair, regs);
-               return emulate_fp_pair(addr, reg, flags);
+       if ((nb == 16)) {
+               if (flags & F) {
+                       /* Special case for 16-byte FP loads and stores */
+                       PPC_WARN_ALIGNMENT(fp_pair, regs);
+                       return emulate_fp_pair(addr, reg, flags);
+               } else {
+#ifdef CONFIG_PPC64
+                       /* Special case for 16-byte loads and stores */
+                       PPC_WARN_ALIGNMENT(lq_stq, regs);
+                       return emulate_lq_stq(regs, addr, reg, flags);
+#else
+                       return 0;
+#endif
+               }
        }
 
        PPC_WARN_ALIGNMENT(unaligned, regs);
index 37d1bb0..1557e7c 100644 (file)
@@ -56,7 +56,6 @@ _GLOBAL(__setup_cpu_power8)
        li      r0,0
        mtspr   SPRN_LPID,r0
        mfspr   r3,SPRN_LPCR
-       oris    r3, r3, LPCR_AIL_3@h
        bl      __init_LPCR
        bl      __init_HFSCR
        bl      __init_tlb_power8
@@ -75,7 +74,6 @@ _GLOBAL(__restore_cpu_power8)
        li      r0,0
        mtspr   SPRN_LPID,r0
        mfspr   r3,SPRN_LPCR
-       oris    r3, r3, LPCR_AIL_3@h
        bl      __init_LPCR
        bl      __init_HFSCR
        bl      __init_tlb_power8
index d9c650e..3afd391 100644 (file)
@@ -54,14 +54,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_REAL_LE)                               \
        xori    r12,r12,MSR_LE ;                                \
        mtspr   SPRN_SRR1,r12 ;                                 \
        rfid ;          /* return to userspace */               \
-       b       . ;                                             \
-2:     mfspr   r12,SPRN_SRR1 ;                                 \
-       andi.   r12,r12,MSR_PR ;                                \
-       bne     0b ;                                            \
-       mtspr   SPRN_SRR0,r3 ;                                  \
-       mtspr   SPRN_SRR1,r4 ;                                  \
-       mtspr   SPRN_SDR1,r5 ;                                  \
-       rfid ;                                                  \
        b       . ;     /* prevent speculative execution */
 
 #if defined(CONFIG_RELOCATABLE)
index bf0aada..ad302f8 100644 (file)
@@ -152,7 +152,8 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
        new_paca->paca_index = cpu;
        new_paca->kernel_toc = kernel_toc;
        new_paca->kernelbase = (unsigned long) _stext;
-       new_paca->kernel_msr = MSR_KERNEL;
+       /* Only set MSR:IR/DR when MMU is initialized */
+       new_paca->kernel_msr = MSR_KERNEL & ~(MSR_IR | MSR_DR);
        new_paca->hw_cpu_id = 0xffff;
        new_paca->kexec_state = KEXEC_STATE_NONE;
        new_paca->__current = &init_task;
index af064d2..31d0215 100644 (file)
@@ -610,6 +610,31 @@ out_and_saveregs:
        tm_save_sprs(thr);
 }
 
+extern void __tm_recheckpoint(struct thread_struct *thread,
+                             unsigned long orig_msr);
+
+void tm_recheckpoint(struct thread_struct *thread,
+                    unsigned long orig_msr)
+{
+       unsigned long flags;
+
+       /* We really can't be interrupted here as the TEXASR registers can't
+        * change and later in the trecheckpoint code, we have a userspace R1.
+        * So let's hard disable over this region.
+        */
+       local_irq_save(flags);
+       hard_irq_disable();
+
+       /* The TM SPRs are restored here, so that TEXASR.FS can be set
+        * before the trecheckpoint and no explosion occurs.
+        */
+       tm_restore_sprs(thread);
+
+       __tm_recheckpoint(thread, orig_msr);
+
+       local_irq_restore(flags);
+}
+
 static inline void tm_recheckpoint_new_task(struct task_struct *new)
 {
        unsigned long msr;
@@ -628,13 +653,10 @@ static inline void tm_recheckpoint_new_task(struct task_struct *new)
        if (!new->thread.regs)
                return;
 
-       /* The TM SPRs are restored here, so that TEXASR.FS can be set
-        * before the trecheckpoint and no explosion occurs.
-        */
-       tm_restore_sprs(&new->thread);
-
-       if (!MSR_TM_ACTIVE(new->thread.regs->msr))
+       if (!MSR_TM_ACTIVE(new->thread.regs->msr)){
+               tm_restore_sprs(&new->thread);
                return;
+       }
        msr = new->thread.tm_orig_msr;
        /* Recheckpoint to restore original checkpointed register state. */
        TM_DEBUG("*** tm_recheckpoint of pid %d "
index dd72beb..668aa47 100644 (file)
@@ -347,45 +347,45 @@ static int __init early_init_dt_scan_cpus(unsigned long node,
 #endif
        }
 
-       if (found >= 0) {
-               DBG("boot cpu: logical %d physical %d\n", found,
-                       be32_to_cpu(intserv[found_thread]));
-               boot_cpuid = found;
-               set_hard_smp_processor_id(found,
-                       be32_to_cpu(intserv[found_thread]));
+       /* Not the boot CPU */
+       if (found < 0)
+               return 0;
 
-               /*
-                * PAPR defines "logical" PVR values for cpus that
-                * meet various levels of the architecture:
-                * 0x0f000001   Architecture version 2.04
-                * 0x0f000002   Architecture version 2.05
-                * If the cpu-version property in the cpu node contains
-                * such a value, we call identify_cpu again with the
-                * logical PVR value in order to use the cpu feature
-                * bits appropriate for the architecture level.
-                *
-                * A POWER6 partition in "POWER6 architected" mode
-                * uses the 0x0f000002 PVR value; in POWER5+ mode
-                * it uses 0x0f000001.
-                */
-               prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
-               if (prop && (be32_to_cpup(prop) & 0xff000000) == 0x0f000000)
-                       identify_cpu(0, be32_to_cpup(prop));
+       DBG("boot cpu: logical %d physical %d\n", found,
+           be32_to_cpu(intserv[found_thread]));
+       boot_cpuid = found;
+       set_hard_smp_processor_id(found, be32_to_cpu(intserv[found_thread]));
 
-               identical_pvr_fixup(node);
-       }
+       /*
+        * PAPR defines "logical" PVR values for cpus that
+        * meet various levels of the architecture:
+        * 0x0f000001   Architecture version 2.04
+        * 0x0f000002   Architecture version 2.05
+        * If the cpu-version property in the cpu node contains
+        * such a value, we call identify_cpu again with the
+        * logical PVR value in order to use the cpu feature
+        * bits appropriate for the architecture level.
+        *
+        * A POWER6 partition in "POWER6 architected" mode
+        * uses the 0x0f000002 PVR value; in POWER5+ mode
+        * it uses 0x0f000001.
+        */
+       prop = of_get_flat_dt_prop(node, "cpu-version", NULL);
+       if (prop && (be32_to_cpup(prop) & 0xff000000) == 0x0f000000)
+               identify_cpu(0, be32_to_cpup(prop));
+
+       identical_pvr_fixup(node);
 
        check_cpu_feature_properties(node);
        check_cpu_pa_features(node);
        check_cpu_slb_size(node);
 
-#ifdef CONFIG_PPC_PSERIES
+#ifdef CONFIG_PPC64
        if (nthreads > 1)
                cur_cpu_spec->cpu_features |= CPU_FTR_SMT;
        else
                cur_cpu_spec->cpu_features &= ~CPU_FTR_SMT;
 #endif
-
        return 0;
 }
 
@@ -747,6 +747,10 @@ void __init early_init_devtree(void *params)
         * (altivec support, boot CPU ID, ...)
         */
        of_scan_flat_dt(early_init_dt_scan_cpus, NULL);
+       if (boot_cpuid < 0) {
+               printk("Failed to indentify boot CPU !\n");
+               BUG();
+       }
 
 #if defined(CONFIG_SMP) && defined(CONFIG_PPC64)
        /* We'll later wait for secondaries to check in; there are
index f386296..8cd5ed0 100644 (file)
@@ -993,21 +993,24 @@ struct pseries_errorlog *get_pseries_errorlog(struct rtas_error_log *log,
                (struct rtas_ext_event_log_v6 *)log->buffer;
        struct pseries_errorlog *sect;
        unsigned char *p, *log_end;
+       uint32_t ext_log_length = rtas_error_extended_log_length(log);
+       uint8_t log_format = rtas_ext_event_log_format(ext_log);
+       uint32_t company_id = rtas_ext_event_company_id(ext_log);
 
        /* Check that we understand the format */
-       if (log->extended_log_length < sizeof(struct rtas_ext_event_log_v6) ||
-           ext_log->log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
-           ext_log->company_id != RTAS_V6EXT_COMPANY_ID_IBM)
+       if (ext_log_length < sizeof(struct rtas_ext_event_log_v6) ||
+           log_format != RTAS_V6EXT_LOG_FORMAT_EVENT_LOG ||
+           company_id != RTAS_V6EXT_COMPANY_ID_IBM)
                return NULL;
 
-       log_end = log->buffer + log->extended_log_length;
+       log_end = log->buffer + ext_log_length;
        p = ext_log->vendor_log;
 
        while (p < log_end) {
                sect = (struct pseries_errorlog *)p;
-               if (sect->id == section_id)
+               if (pseries_errorlog_id(sect) == section_id)
                        return sect;
-               p += sect->length;
+               p += pseries_errorlog_length(sect);
        }
 
        return NULL;
index 1130c53..e736387 100644 (file)
@@ -150,8 +150,8 @@ static void printk_log_rtas(char *buf, int len)
                struct rtas_error_log *errlog = (struct rtas_error_log *)buf;
 
                printk(RTAS_DEBUG "event: %d, Type: %s, Severity: %d\n",
-                      error_log_cnt, rtas_event_type(errlog->type),
-                      errlog->severity);
+                      error_log_cnt, rtas_event_type(rtas_error_type(errlog)),
+                      rtas_error_severity(errlog));
        }
 }
 
@@ -159,14 +159,16 @@ static int log_rtas_len(char * buf)
 {
        int len;
        struct rtas_error_log *err;
+       uint32_t extended_log_length;
 
        /* rtas fixed header */
        len = 8;
        err = (struct rtas_error_log *)buf;
-       if (err->extended && err->extended_log_length) {
+       extended_log_length = rtas_error_extended_log_length(err);
+       if (rtas_error_extended(err) && extended_log_length) {
 
                /* extended header */
-               len += err->extended_log_length;
+               len += extended_log_length;
        }
 
        if (rtas_error_log_max == 0)
@@ -293,15 +295,13 @@ void prrn_schedule_update(u32 scope)
 
 static void handle_rtas_event(const struct rtas_error_log *log)
 {
-       if (log->type == RTAS_TYPE_PRRN) {
-               /* For PRRN Events the extended log length is used to denote
-                * the scope for calling rtas update-nodes.
-                */
-               if (prrn_is_enabled())
-                       prrn_schedule_update(log->extended_log_length);
-       }
+       if (rtas_error_type(log) != RTAS_TYPE_PRRN || !prrn_is_enabled())
+               return;
 
-       return;
+       /* For PRRN Events the extended log length is used to denote
+        * the scope for calling rtas update-nodes.
+        */
+       prrn_schedule_update(rtas_error_extended_log_length(log));
 }
 
 #else
index bc76cc6..79b7612 100644 (file)
@@ -76,6 +76,9 @@ EXPORT_SYMBOL(ppc_md);
 struct machdep_calls *machine_id;
 EXPORT_SYMBOL(machine_id);
 
+int boot_cpuid = -1;
+EXPORT_SYMBOL_GPL(boot_cpuid);
+
 unsigned long klimit = (unsigned long) _end;
 
 char cmd_line[COMMAND_LINE_SIZE];
index 04cc4fc..ea4fda6 100644 (file)
@@ -44,8 +44,6 @@
 
 extern void bootx_init(unsigned long r4, unsigned long phys);
 
-int boot_cpuid = -1;
-EXPORT_SYMBOL_GPL(boot_cpuid);
 int boot_cpuid_phys;
 EXPORT_SYMBOL_GPL(boot_cpuid_phys);
 
index 4933909..3d7a50a 100644 (file)
@@ -74,7 +74,6 @@
 #define DBG(fmt...)
 #endif
 
-int boot_cpuid = 0;
 int spinning_secondaries;
 u64 ppc64_pft_size;
 
@@ -196,6 +195,18 @@ static void fixup_boot_paca(void)
        get_paca()->data_offset = 0;
 }
 
+static void cpu_ready_for_interrupts(void)
+{
+       /* Set IR and DR in PACA MSR */
+       get_paca()->kernel_msr = MSR_KERNEL;
+
+       /* Enable AIL if supported */
+       if (cpu_has_feature(CPU_FTR_ARCH_207S)) {
+               unsigned long lpcr = mfspr(SPRN_LPCR);
+               mtspr(SPRN_LPCR, lpcr | LPCR_AIL_3);
+       }
+}
+
 /*
  * Early initialization entry point. This is called by head.S
  * with MMU translation disabled. We rely on the "feature" of
@@ -262,6 +273,14 @@ void __init early_setup(unsigned long dt_ptr)
        /* Initialize the hash table or TLB handling */
        early_init_mmu();
 
+       /*
+        * At this point, we can let interrupts switch to virtual mode
+        * (the MMU has been setup), so adjust the MSR in the PACA to
+        * have IR and DR set and enable AIL if it exists
+        */
+       cpu_ready_for_interrupts();
+
+       /* Reserve large chunks of memory for use by CMA for KVM */
        kvm_cma_reserve();
 
        /*
@@ -294,6 +313,13 @@ void early_setup_secondary(void)
 
        /* Initialize the hash table or TLB handling */
        early_init_mmu_secondary();
+
+       /*
+        * At this point, we can let interrupts switch to virtual mode
+        * (the MMU has been setup), so adjust the MSR in the PACA to
+        * have IR and DR set.
+        */
+       cpu_ready_for_interrupts();
 }
 
 #endif /* CONFIG_SMP */
index a67e00a..4e47db6 100644 (file)
@@ -881,6 +881,8 @@ static long restore_tm_user_regs(struct pt_regs *regs,
         * transactional versions should be loaded.
         */
        tm_enable();
+       /* Make sure the transaction is marked as failed */
+       current->thread.tm_texasr |= TEXASR_FS;
        /* This loads the checkpointed FP/VEC state, if used */
        tm_recheckpoint(&current->thread, msr);
        /* Get the top half of the MSR */
index 8d253c2..d501dc4 100644 (file)
@@ -527,6 +527,8 @@ static long restore_tm_sigcontexts(struct pt_regs *regs,
        }
 #endif
        tm_enable();
+       /* Make sure the transaction is marked as failed */
+       current->thread.tm_texasr |= TEXASR_FS;
        /* This loads the checkpointed FP/VEC state, if used */
        tm_recheckpoint(&current->thread, msr);
 
index 97e1dc9..d90d4b7 100644 (file)
@@ -975,7 +975,8 @@ static int __init topology_init(void)
        int cpu;
 
        register_nodes();
-       register_cpu_notifier(&sysfs_cpu_nb);
+
+       cpu_notifier_register_begin();
 
        for_each_possible_cpu(cpu) {
                struct cpu *c = &per_cpu(cpu_devices, cpu);
@@ -999,6 +1000,11 @@ static int __init topology_init(void)
                if (cpu_online(cpu))
                        register_cpu_online(cpu);
        }
+
+       __register_cpu_notifier(&sysfs_cpu_nb);
+
+       cpu_notifier_register_done();
+
 #ifdef CONFIG_PPC64
        sysfs_create_dscr_default();
 #endif /* CONFIG_PPC64 */
index ef47bcb..03567c0 100644 (file)
@@ -307,7 +307,7 @@ dont_backup_fp:
         *      Call with IRQs off, stacks get all out of sync for
         *      some periods in here!
         */
-_GLOBAL(tm_recheckpoint)
+_GLOBAL(__tm_recheckpoint)
        mfcr    r5
        mflr    r0
        stw     r5, 8(r1)
index df86f0c..1bd7ca2 100644 (file)
@@ -1868,6 +1868,7 @@ struct ppc_emulated ppc_emulated = {
 #ifdef CONFIG_PPC64
        WARN_EMULATED_SETUP(mfdscr),
        WARN_EMULATED_SETUP(mtdscr),
+       WARN_EMULATED_SETUP(lq_stq),
 #endif
 };
 
index dbce92e..44b0fc8 100644 (file)
@@ -11,48 +11,36 @@ mtfsf(unsigned int FM, u32 *frB)
        u32 mask;
        u32 fpscr;
 
-       if (FM == 0)
-               return 0;
-
-       if (FM == 0xff)
-               mask = 0x9fffffff;
+       if (likely(FM == 1))
+               mask = 0x0f;
+       else if (likely(FM == 0xff))
+               mask = ~0;
        else {
-               mask = 0;
-               if (FM & (1 << 0))
-                       mask |= 0x90000000;
-               if (FM & (1 << 1))
-                       mask |= 0x0f000000;
-               if (FM & (1 << 2))
-                       mask |= 0x00f00000;
-               if (FM & (1 << 3))
-                       mask |= 0x000f0000;
-               if (FM & (1 << 4))
-                       mask |= 0x0000f000;
-               if (FM & (1 << 5))
-                       mask |= 0x00000f00;
-               if (FM & (1 << 6))
-                       mask |= 0x000000f0;
-               if (FM & (1 << 7))
-                       mask |= 0x0000000f;
+               mask = ((FM & 1) |
+                               ((FM << 3) & 0x10) |
+                               ((FM << 6) & 0x100) |
+                               ((FM << 9) & 0x1000) |
+                               ((FM << 12) & 0x10000) |
+                               ((FM << 15) & 0x100000) |
+                               ((FM << 18) & 0x1000000) |
+                               ((FM << 21) & 0x10000000)) * 15;
        }
 
-       __FPU_FPSCR &= ~(mask);
-       __FPU_FPSCR |= (frB[1] & mask);
+       fpscr = ((__FPU_FPSCR & ~mask) | (frB[1] & mask)) &
+               ~(FPSCR_VX | FPSCR_FEX | 0x800);
 
-       __FPU_FPSCR &= ~(FPSCR_VX);
-       if (__FPU_FPSCR & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
+       if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
                     FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
                     FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
-               __FPU_FPSCR |= FPSCR_VX;
-
-       fpscr = __FPU_FPSCR;
-       fpscr &= ~(FPSCR_FEX);
-       if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) ||
-           ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) ||
-           ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) ||
-           ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) ||
-           ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE)))
+               fpscr |= FPSCR_VX;
+
+       /* The bit order of exception enables and exception status
+        * is the same. Simply shift and mask to check for enabled
+        * exceptions.
+        */
+       if (fpscr & (fpscr >> 22) &  0xf8)
                fpscr |= FPSCR_FEX;
+
        __FPU_FPSCR = fpscr;
 
 #ifdef DEBUG
index c5f734e..d874668 100644 (file)
@@ -36,6 +36,11 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
        do {
                pte_t pte = ACCESS_ONCE(*ptep);
                struct page *page;
+               /*
+                * Similar to the PMD case, NUMA hinting must take slow path
+                */
+               if (pte_numa(pte))
+                       return 0;
 
                if ((pte_val(pte) & mask) != result)
                        return 0;
@@ -75,6 +80,14 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
                if (pmd_none(pmd) || pmd_trans_splitting(pmd))
                        return 0;
                if (pmd_huge(pmd) || pmd_large(pmd)) {
+                       /*
+                        * NUMA hinting faults need to be handled in the GUP
+                        * slowpath for accounting purposes and so that they
+                        * can be serialised against THP migration.
+                        */
+                       if (pmd_numa(pmd))
+                               return 0;
+
                        if (!gup_hugepte((pte_t *)pmdp, PMD_SIZE, addr, next,
                                         write, pages, nr))
                                return 0;
index 30a42e2..4ebbb9e 100644 (file)
@@ -1591,6 +1591,20 @@ int arch_update_cpu_topology(void)
                cpu = cpu_last_thread_sibling(cpu);
        }
 
+       /*
+        * In cases where we have nothing to update (because the updates list
+        * is too short or because the new topology is same as the old one),
+        * skip invoking update_cpu_topology() via stop-machine(). This is
+        * necessary (and not just a fast-path optimization) since stop-machine
+        * can end up electing a random CPU to run update_cpu_topology(), and
+        * thus trick us into setting up incorrect cpu-node mappings (since
+        * 'updates' is kzalloc()'ed).
+        *
+        * And for the similar reason, we will skip all the following updating.
+        */
+       if (!cpumask_weight(&updated_cpus))
+               goto out;
+
        stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
 
        /*
@@ -1612,6 +1626,7 @@ int arch_update_cpu_topology(void)
                changed = 1;
        }
 
+out:
        kfree(updates);
        return changed;
 }
index 434fda3..d9e2b19 100644 (file)
@@ -73,6 +73,7 @@ config PPC_BOOK3S_64
        select SYS_SUPPORTS_HUGETLBFS
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE if PPC_64K_PAGES
        select ARCH_SUPPORTS_NUMA_BALANCING
+       select IRQ_WORK
 
 config PPC_BOOK3E_64
        bool "Embedded processors"
index 3844f13..38e0a1a 100644 (file)
@@ -170,7 +170,7 @@ EXPORT_SYMBOL_GPL(register_spu_syscalls);
 void unregister_spu_syscalls(struct spufs_calls *calls)
 {
        BUG_ON(spufs_calls->owner != calls->owner);
-       rcu_assign_pointer(spufs_calls, NULL);
+       RCU_INIT_POINTER(spufs_calls, NULL);
        synchronize_rcu();
 }
 EXPORT_SYMBOL_GPL(unregister_spu_syscalls);
index f324ea0..63cebb9 100644 (file)
@@ -1,6 +1,7 @@
 obj-y                  += setup.o opal-takeover.o opal-wrappers.o opal.o opal-async.o
 obj-y                  += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y                  += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
+obj-y                  += opal-msglog.o
 
 obj-$(CONFIG_SMP)      += smp.o
 obj-$(CONFIG_PCI)      += pci.o pci-p5ioc2.o pci-ioda.o
index cd0c135..32e2adf 100644 (file)
@@ -125,14 +125,15 @@ static int opal_async_comp_event(struct notifier_block *nb,
 {
        struct opal_msg *comp_msg = msg;
        unsigned long flags;
+       uint64_t token;
 
        if (msg_type != OPAL_MSG_ASYNC_COMP)
                return 0;
 
-       memcpy(&opal_async_responses[comp_msg->params[0]], comp_msg,
-                       sizeof(*comp_msg));
+       token = be64_to_cpu(comp_msg->params[0]);
+       memcpy(&opal_async_responses[token], comp_msg, sizeof(*comp_msg));
        spin_lock_irqsave(&opal_async_comp_lock, flags);
-       __set_bit(comp_msg->params[0], opal_async_complete_map);
+       __set_bit(token, opal_async_complete_map);
        spin_unlock_irqrestore(&opal_async_comp_lock, flags);
 
        wake_up(&opal_async_wait);
index 0c767c5..b9827b0 100644 (file)
@@ -86,19 +86,14 @@ static int64_t dump_send_ack(uint32_t dump_id)
        return rc;
 }
 
-static void delay_release_kobj(void *kobj)
-{
-       kobject_put((struct kobject *)kobj);
-}
-
 static ssize_t dump_ack_store(struct dump_obj *dump_obj,
                              struct dump_attribute *attr,
                              const char *buf,
                              size_t count)
 {
        dump_send_ack(dump_obj->id);
-       sysfs_schedule_callback(&dump_obj->kobj, delay_release_kobj,
-                               &dump_obj->kobj, THIS_MODULE);
+       sysfs_remove_file_self(&dump_obj->kobj, &attr->attr);
+       kobject_put(&dump_obj->kobj);
        return count;
 }
 
index 1d7355b..ef7bc2a 100644 (file)
@@ -70,19 +70,14 @@ static ssize_t elog_ack_show(struct elog_obj *elog_obj,
        return sprintf(buf, "ack - acknowledge log message\n");
 }
 
-static void delay_release_kobj(void *kobj)
-{
-       kobject_put((struct kobject *)kobj);
-}
-
 static ssize_t elog_ack_store(struct elog_obj *elog_obj,
                              struct elog_attribute *attr,
                              const char *buf,
                              size_t count)
 {
        opal_send_ack_elog(elog_obj->id);
-       sysfs_schedule_callback(&elog_obj->kobj, delay_release_kobj,
-                               &elog_obj->kobj, THIS_MODULE);
+       sysfs_remove_file_self(&elog_obj->kobj, &attr->attr);
+       kobject_put(&elog_obj->kobj);
        return count;
 }
 
diff --git a/arch/powerpc/platforms/powernv/opal-msglog.c b/arch/powerpc/platforms/powernv/opal-msglog.c
new file mode 100644 (file)
index 0000000..1bb25b9
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * PowerNV OPAL in-memory console interface
+ *
+ * Copyright 2014 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <asm/io.h>
+#include <asm/opal.h>
+#include <linux/debugfs.h>
+#include <linux/of.h>
+#include <linux/types.h>
+#include <asm/barrier.h>
+
+/* OPAL in-memory console. Defined in OPAL source at core/console.c */
+struct memcons {
+       __be64 magic;
+#define MEMCONS_MAGIC  0x6630696567726173L
+       __be64 obuf_phys;
+       __be64 ibuf_phys;
+       __be32 obuf_size;
+       __be32 ibuf_size;
+       __be32 out_pos;
+#define MEMCONS_OUT_POS_WRAP   0x80000000u
+#define MEMCONS_OUT_POS_MASK   0x00ffffffu
+       __be32 in_prod;
+       __be32 in_cons;
+};
+
+static ssize_t opal_msglog_read(struct file *file, struct kobject *kobj,
+                               struct bin_attribute *bin_attr, char *to,
+                               loff_t pos, size_t count)
+{
+       struct memcons *mc = bin_attr->private;
+       const char *conbuf;
+       size_t ret, first_read = 0;
+       uint32_t out_pos, avail;
+
+       if (!mc)
+               return -ENODEV;
+
+       out_pos = be32_to_cpu(ACCESS_ONCE(mc->out_pos));
+
+       /* Now we've read out_pos, put a barrier in before reading the new
+        * data it points to in conbuf. */
+       smp_rmb();
+
+       conbuf = phys_to_virt(be64_to_cpu(mc->obuf_phys));
+
+       /* When the buffer has wrapped, read from the out_pos marker to the end
+        * of the buffer, and then read the remaining data as in the un-wrapped
+        * case. */
+       if (out_pos & MEMCONS_OUT_POS_WRAP) {
+
+               out_pos &= MEMCONS_OUT_POS_MASK;
+               avail = be32_to_cpu(mc->obuf_size) - out_pos;
+
+               ret = memory_read_from_buffer(to, count, &pos,
+                               conbuf + out_pos, avail);
+
+               if (ret < 0)
+                       goto out;
+
+               first_read = ret;
+               to += first_read;
+               count -= first_read;
+               pos -= avail;
+       }
+
+       /* Sanity check. The firmware should not do this to us. */
+       if (out_pos > be32_to_cpu(mc->obuf_size)) {
+               pr_err("OPAL: memory console corruption. Aborting read.\n");
+               return -EINVAL;
+       }
+
+       ret = memory_read_from_buffer(to, count, &pos, conbuf, out_pos);
+
+       if (ret < 0)
+               goto out;
+
+       ret += first_read;
+out:
+       return ret;
+}
+
+static struct bin_attribute opal_msglog_attr = {
+       .attr = {.name = "msglog", .mode = 0444},
+       .read = opal_msglog_read
+};
+
+void __init opal_msglog_init(void)
+{
+       u64 mcaddr;
+       struct memcons *mc;
+
+       if (of_property_read_u64(opal_node, "ibm,opal-memcons", &mcaddr)) {
+               pr_warn("OPAL: Property ibm,opal-memcons not found, no message log\n");
+               return;
+       }
+
+       mc = phys_to_virt(mcaddr);
+       if (!mc) {
+               pr_warn("OPAL: memory console address is invalid\n");
+               return;
+       }
+
+       if (be64_to_cpu(mc->magic) != MEMCONS_MAGIC) {
+               pr_warn("OPAL: memory console version is invalid\n");
+               return;
+       }
+
+       opal_msglog_attr.private = mc;
+
+       if (sysfs_create_bin_file(opal_kobj, &opal_msglog_attr) != 0)
+               pr_warn("OPAL: sysfs file creation failed\n");
+}
index 663cc9c..10271ad 100644 (file)
@@ -33,6 +33,7 @@ int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data)
 {
        int ret, token;
        struct opal_msg msg;
+       __be32 data;
 
        token = opal_async_get_token_interruptible();
        if (token < 0) {
@@ -42,7 +43,7 @@ int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data)
        }
 
        mutex_lock(&opal_sensor_mutex);
-       ret = opal_sensor_read(sensor_hndl, token, sensor_data);
+       ret = opal_sensor_read(sensor_hndl, token, &data);
        if (ret != OPAL_ASYNC_COMPLETION)
                goto out_token;
 
@@ -53,7 +54,8 @@ int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data)
                goto out_token;
        }
 
-       ret = msg.params[1];
+       *sensor_data = be32_to_cpu(data);
+       ret = be64_to_cpu(msg.params[1]);
 
 out_token:
        mutex_unlock(&opal_sensor_mutex);
index 0bd249a..6b61472 100644 (file)
@@ -64,7 +64,7 @@ static int opal_get_sys_param(u32 param_id, u32 length, void *buffer)
                goto out_token;
        }
 
-       ret = msg.params[1];
+       ret = be64_to_cpu(msg.params[1]);
 
 out_token:
        opal_async_release_token(token);
@@ -98,7 +98,7 @@ static int opal_set_sys_param(u32 param_id, u32 length, void *buffer)
                goto out_token;
        }
 
-       ret = msg.params[1];
+       ret = be64_to_cpu(msg.params[1]);
 
 out_token:
        opal_async_release_token(token);
index bb90f9a..f531ffe 100644 (file)
@@ -61,6 +61,7 @@ _STATIC(opal_return)
        mtcr    r4;
        rfid
 
+OPAL_CALL(opal_invalid_call,                   OPAL_INVALID_CALL);
 OPAL_CALL(opal_console_write,                  OPAL_CONSOLE_WRITE);
 OPAL_CALL(opal_console_read,                   OPAL_CONSOLE_READ);
 OPAL_CALL(opal_console_write_buffer_space,     OPAL_CONSOLE_WRITE_BUFFER_SPACE);
index e92f2f6..49d2f00 100644 (file)
@@ -46,7 +46,7 @@ struct mcheck_recoverable_range {
 static struct mcheck_recoverable_range *mc_recoverable_range;
 static int mc_recoverable_range_len;
 
-static struct device_node *opal_node;
+struct device_node *opal_node;
 static DEFINE_SPINLOCK(opal_write_lock);
 extern u64 opal_mc_secondary_handler[];
 static unsigned int *opal_irqs;
@@ -102,19 +102,36 @@ int __init early_init_dt_scan_opal(unsigned long node,
 int __init early_init_dt_scan_recoverable_ranges(unsigned long node,
                                   const char *uname, int depth, void *data)
 {
-       unsigned long i, size;
+       unsigned long i, psize, size;
        const __be32 *prop;
 
        if (depth != 1 || strcmp(uname, "ibm,opal") != 0)
                return 0;
 
-       prop = of_get_flat_dt_prop(node, "mcheck-recoverable-ranges", &size);
+       prop = of_get_flat_dt_prop(node, "mcheck-recoverable-ranges", &psize);
 
        if (!prop)
                return 1;
 
        pr_debug("Found machine check recoverable ranges.\n");
 
+       /*
+        * Calculate number of available entries.
+        *
+        * Each recoverable address range entry is (start address, len,
+        * recovery address), 2 cells each for start and recovery address,
+        * 1 cell for len, totalling 5 cells per entry.
+        */
+       mc_recoverable_range_len = psize / (sizeof(*prop) * 5);
+
+       /* Sanity check */
+       if (!mc_recoverable_range_len)
+               return 1;
+
+       /* Size required to hold all the entries. */
+       size = mc_recoverable_range_len *
+                       sizeof(struct mcheck_recoverable_range);
+
        /*
         * Allocate a buffer to hold the MC recoverable ranges. We would be
         * accessing them in real mode, hence it needs to be within
@@ -124,11 +141,7 @@ int __init early_init_dt_scan_recoverable_ranges(unsigned long node,
                                                        ppc64_rma_size));
        memset(mc_recoverable_range, 0, size);
 
-       /*
-        * Each recoverable address entry is an (start address,len,
-        * recover address) pair, * 2 cells each, totalling 4 cells per entry.
-        */
-       for (i = 0; i < size / (sizeof(*prop) * 5); i++) {
+       for (i = 0; i < mc_recoverable_range_len; i++) {
                mc_recoverable_range[i].start_addr =
                                        of_read_number(prop + (i * 5) + 0, 2);
                mc_recoverable_range[i].end_addr =
@@ -142,7 +155,6 @@ int __init early_init_dt_scan_recoverable_ranges(unsigned long node,
                                mc_recoverable_range[i].end_addr,
                                mc_recoverable_range[i].recover_addr);
        }
-       mc_recoverable_range_len = i;
        return 1;
 }
 
@@ -180,6 +192,20 @@ int opal_notifier_register(struct notifier_block *nb)
        atomic_notifier_chain_register(&opal_notifier_head, nb);
        return 0;
 }
+EXPORT_SYMBOL_GPL(opal_notifier_register);
+
+int opal_notifier_unregister(struct notifier_block *nb)
+{
+       if (!nb) {
+               pr_warning("%s: Invalid argument (%p)\n",
+                          __func__, nb);
+               return -EINVAL;
+       }
+
+       atomic_notifier_chain_unregister(&opal_notifier_head, nb);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(opal_notifier_unregister);
 
 static void opal_do_notifier(uint64_t events)
 {
@@ -267,6 +293,7 @@ static void opal_handle_message(void)
         * value in /proc/device-tree.
         */
        static struct opal_msg msg;
+       u32 type;
 
        ret = opal_get_msg(__pa(&msg), sizeof(msg));
        /* No opal message pending. */
@@ -280,13 +307,14 @@ static void opal_handle_message(void)
                return;
        }
 
+       type = be32_to_cpu(msg.msg_type);
+
        /* Sanity check */
-       if (msg.msg_type > OPAL_MSG_TYPE_MAX) {
-               pr_warning("%s: Unknown message type: %u\n",
-                               __func__, msg.msg_type);
+       if (type > OPAL_MSG_TYPE_MAX) {
+               pr_warning("%s: Unknown message type: %u\n", __func__, type);
                return;
        }
-       opal_message_do_notify(msg.msg_type, (void *)&msg);
+       opal_message_do_notify(type, (void *)&msg);
 }
 
 static int opal_message_notify(struct notifier_block *nb,
@@ -574,6 +602,8 @@ static int __init opal_init(void)
                opal_platform_dump_init();
                /* Setup system parameters interface */
                opal_sys_param_init();
+               /* Setup message log interface. */
+               opal_msglog_init();
        }
 
        return 0;
@@ -605,3 +635,6 @@ void opal_shutdown(void)
                        mdelay(10);
        }
 }
+
+/* Export this so that test modules can use it */
+EXPORT_SYMBOL_GPL(opal_invalid_call);
index 5ea88d1..0240c4f 100644 (file)
@@ -82,9 +82,9 @@ static struct pseries_io_event * ioei_find_event(struct rtas_error_log *elog)
         * RTAS_TYPE_IO only exists in extended event log version 6 or later.
         * No need to check event log version.
         */
-       if (unlikely(elog->type != RTAS_TYPE_IO)) {
-               printk_once(KERN_WARNING "io_event_irq: Unexpected event type %d",
-                           elog->type);
+       if (unlikely(rtas_error_type(elog) != RTAS_TYPE_IO)) {
+               printk_once(KERN_WARNING"io_event_irq: Unexpected event type %d",
+                           rtas_error_type(elog));
                return NULL;
        }
 
index d7096f2..0cc240b 100644 (file)
@@ -298,13 +298,13 @@ int nvram_write_os_partition(struct nvram_os_partition *part, char * buff,
 
        rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
        if (rc <= 0) {
-               pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);
+               pr_err("%s: Failed nvram_write (%d)\n", __func__, rc);
                return rc;
        }
 
        rc = ppc_md.nvram_write(buff, length, &tmp_index);
        if (rc <= 0) {
-               pr_err("%s: Failed nvram_write (%d)\n", __FUNCTION__, rc);
+               pr_err("%s: Failed nvram_write (%d)\n", __func__, rc);
                return rc;
        }
        
@@ -351,15 +351,14 @@ int nvram_read_partition(struct nvram_os_partition *part, char *buff,
                                        sizeof(struct err_log_info),
                                        &tmp_index);
                if (rc <= 0) {
-                       pr_err("%s: Failed nvram_read (%d)\n", __FUNCTION__,
-                                                                       rc);
+                       pr_err("%s: Failed nvram_read (%d)\n", __func__, rc);
                        return rc;
                }
        }
 
        rc = ppc_md.nvram_read(buff, length, &tmp_index);
        if (rc <= 0) {
-               pr_err("%s: Failed nvram_read (%d)\n", __FUNCTION__, rc);
+               pr_err("%s: Failed nvram_read (%d)\n", __func__, rc);
                return rc;
        }
 
@@ -869,7 +868,7 @@ static void oops_to_nvram(struct kmsg_dumper *dumper,
                break;
        default:
                pr_err("%s: ignoring unrecognized KMSG_DUMP_* reason %d\n",
-                                               __FUNCTION__, (int) reason);
+                      __func__, (int) reason);
                return;
        }
 
index 721c058..9c5778e 100644 (file)
@@ -236,7 +236,8 @@ static irqreturn_t ras_error_interrupt(int irq, void *dev_id)
 
        rtas_elog = (struct rtas_error_log *)ras_log_buf;
 
-       if ((status == 0) && (rtas_elog->severity >= RTAS_SEVERITY_ERROR_SYNC))
+       if (status == 0 &&
+           rtas_error_severity(rtas_elog) >= RTAS_SEVERITY_ERROR_SYNC)
                fatal = 1;
        else
                fatal = 0;
@@ -300,13 +301,14 @@ static struct rtas_error_log *fwnmi_get_errinfo(struct pt_regs *regs)
 
        /* If it isn't an extended log we can use the per cpu 64bit buffer */
        h = (struct rtas_error_log *)&savep[1];
-       if (!h->extended) {
+       if (!rtas_error_extended(h)) {
                memcpy(&__get_cpu_var(mce_data_buf), h, sizeof(__u64));
                errhdr = (struct rtas_error_log *)&__get_cpu_var(mce_data_buf);
        } else {
-               int len;
+               int len, error_log_length;
 
-               len = max_t(int, 8+h->extended_log_length, RTAS_ERROR_LOG_MAX);
+               error_log_length = 8 + rtas_error_extended_log_length(h);
+               len = max_t(int, error_log_length, RTAS_ERROR_LOG_MAX);
                memset(global_mce_data_buf, 0, RTAS_ERROR_LOG_MAX);
                memcpy(global_mce_data_buf, h, len);
                errhdr = (struct rtas_error_log *)global_mce_data_buf;
@@ -350,23 +352,24 @@ int pSeries_system_reset_exception(struct pt_regs *regs)
 static int recover_mce(struct pt_regs *regs, struct rtas_error_log *err)
 {
        int recovered = 0;
+       int disposition = rtas_error_disposition(err);
 
        if (!(regs->msr & MSR_RI)) {
                /* If MSR_RI isn't set, we cannot recover */
                recovered = 0;
 
-       } else if (err->disposition == RTAS_DISP_FULLY_RECOVERED) {
+       } else if (disposition == RTAS_DISP_FULLY_RECOVERED) {
                /* Platform corrected itself */
                recovered = 1;
 
-       } else if (err->disposition == RTAS_DISP_LIMITED_RECOVERY) {
+       } else if (disposition == RTAS_DISP_LIMITED_RECOVERY) {
                /* Platform corrected itself but could be degraded */
                printk(KERN_ERR "MCE: limited recovery, system may "
                       "be degraded\n");
                recovered = 1;
 
        } else if (user_mode(regs) && !is_global_init(current) &&
-                  err->severity == RTAS_SEVERITY_ERROR_SYNC) {
+                  rtas_error_severity(err) == RTAS_SEVERITY_ERROR_SYNC) {
 
                /*
                 * If we received a synchronous error when in userspace
index 95dd892..cf2b084 100644 (file)
@@ -531,6 +531,7 @@ int fsl_rio_setup(struct platform_device *dev)
                sprintf(port->name, "RIO mport %d", i);
 
                priv->dev = &dev->dev;
+               port->dev.parent = &dev->dev;
                port->ops = ops;
                port->priv = priv;
                port->phys_efptr = 0x100;
index 8ba6042..2ff6302 100644 (file)
@@ -202,7 +202,7 @@ void __init test_of_node(void)
 
        /* There should really be a struct device_node allocator */
        memset(&of_node, 0, sizeof(of_node));
-       kref_init(&of_node.kobj.kref);
+       of_node_init(&of_node);
        of_node.full_name = node_name;
 
        check(0 == msi_bitmap_alloc(&bmp, size, &of_node));
index 953f17c..346d216 100644 (file)
@@ -52,7 +52,7 @@ config KEXEC
 config AUDIT_ARCH
        def_bool y
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool y
 
 config PCI_QUIRKS
index fa9aaf7..1d47061 100644 (file)
 
 #include <linux/compiler.h>
 #include <linux/types.h>
+#include <asm/barrier.h>
 #include <asm/cmpxchg.h>
 
 #define ATOMIC_INIT(i)  { (i) }
 
+#define __ATOMIC_NO_BARRIER    "\n"
+
 #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
 
 #define __ATOMIC_OR    "lao"
 #define __ATOMIC_AND   "lan"
 #define __ATOMIC_ADD   "laa"
+#define __ATOMIC_BARRIER "bcr  14,0\n"
 
-#define __ATOMIC_LOOP(ptr, op_val, op_string)                          \
+#define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier)               \
 ({                                                                     \
        int old_val;                                                    \
                                                                        \
        typecheck(atomic_t *, ptr);                                     \
        asm volatile(                                                   \
+               __barrier                                               \
                op_string "     %0,%2,%1\n"                             \
+               __barrier                                               \
                : "=d" (old_val), "+Q" ((ptr)->counter)                 \
                : "d" (op_val)                                          \
                : "cc", "memory");                                      \
@@ -43,8 +49,9 @@
 #define __ATOMIC_OR    "or"
 #define __ATOMIC_AND   "nr"
 #define __ATOMIC_ADD   "ar"
+#define __ATOMIC_BARRIER "\n"
 
-#define __ATOMIC_LOOP(ptr, op_val, op_string)                          \
+#define __ATOMIC_LOOP(ptr, op_val, op_string, __barrier)               \
 ({                                                                     \
        int old_val, new_val;                                           \
                                                                        \
@@ -82,7 +89,7 @@ static inline void atomic_set(atomic_t *v, int i)
 
 static inline int atomic_add_return(int i, atomic_t *v)
 {
-       return __ATOMIC_LOOP(v, i, __ATOMIC_ADD) + i;
+       return __ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_BARRIER) + i;
 }
 
 static inline void atomic_add(int i, atomic_t *v)
@@ -94,12 +101,10 @@ static inline void atomic_add(int i, atomic_t *v)
                        : "+Q" (v->counter)
                        : "i" (i)
                        : "cc", "memory");
-       } else {
-               atomic_add_return(i, v);
+               return;
        }
-#else
-       atomic_add_return(i, v);
 #endif
+       __ATOMIC_LOOP(v, i, __ATOMIC_ADD, __ATOMIC_NO_BARRIER);
 }
 
 #define atomic_add_negative(_i, _v)    (atomic_add_return(_i, _v) < 0)
@@ -115,12 +120,12 @@ static inline void atomic_add(int i, atomic_t *v)
 
 static inline void atomic_clear_mask(unsigned int mask, atomic_t *v)
 {
-       __ATOMIC_LOOP(v, ~mask, __ATOMIC_AND);
+       __ATOMIC_LOOP(v, ~mask, __ATOMIC_AND, __ATOMIC_NO_BARRIER);
 }
 
 static inline void atomic_set_mask(unsigned int mask, atomic_t *v)
 {
-       __ATOMIC_LOOP(v, mask, __ATOMIC_OR);
+       __ATOMIC_LOOP(v, mask, __ATOMIC_OR, __ATOMIC_NO_BARRIER);
 }
 
 #define atomic_xchg(v, new) (xchg(&((v)->counter), new))
@@ -157,19 +162,24 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
 
 #ifdef CONFIG_64BIT
 
+#define __ATOMIC64_NO_BARRIER  "\n"
+
 #ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
 
 #define __ATOMIC64_OR  "laog"
 #define __ATOMIC64_AND "lang"
 #define __ATOMIC64_ADD "laag"
+#define __ATOMIC64_BARRIER "bcr        14,0\n"
 
-#define __ATOMIC64_LOOP(ptr, op_val, op_string)                                \
+#define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier)             \
 ({                                                                     \
        long long old_val;                                              \
                                                                        \
        typecheck(atomic64_t *, ptr);                                   \
        asm volatile(                                                   \
+               __barrier                                               \
                op_string "     %0,%2,%1\n"                             \
+               __barrier                                               \
                : "=d" (old_val), "+Q" ((ptr)->counter)                 \
                : "d" (op_val)                                          \
                : "cc", "memory");                                      \
@@ -181,8 +191,9 @@ static inline int __atomic_add_unless(atomic_t *v, int a, int u)
 #define __ATOMIC64_OR  "ogr"
 #define __ATOMIC64_AND "ngr"
 #define __ATOMIC64_ADD "agr"
+#define __ATOMIC64_BARRIER "\n"
 
-#define __ATOMIC64_LOOP(ptr, op_val, op_string)                                \
+#define __ATOMIC64_LOOP(ptr, op_val, op_string, __barrier)             \
 ({                                                                     \
        long long old_val, new_val;                                     \
                                                                        \
@@ -220,17 +231,32 @@ static inline void atomic64_set(atomic64_t *v, long long i)
 
 static inline long long atomic64_add_return(long long i, atomic64_t *v)
 {
-       return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD) + i;
+       return __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_BARRIER) + i;
+}
+
+static inline void atomic64_add(long long i, atomic64_t *v)
+{
+#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
+       if (__builtin_constant_p(i) && (i > -129) && (i < 128)) {
+               asm volatile(
+                       "agsi   %0,%1\n"
+                       : "+Q" (v->counter)
+                       : "i" (i)
+                       : "cc", "memory");
+               return;
+       }
+#endif
+       __ATOMIC64_LOOP(v, i, __ATOMIC64_ADD, __ATOMIC64_NO_BARRIER);
 }
 
 static inline void atomic64_clear_mask(unsigned long mask, atomic64_t *v)
 {
-       __ATOMIC64_LOOP(v, ~mask, __ATOMIC64_AND);
+       __ATOMIC64_LOOP(v, ~mask, __ATOMIC64_AND, __ATOMIC64_NO_BARRIER);
 }
 
 static inline void atomic64_set_mask(unsigned long mask, atomic64_t *v)
 {
-       __ATOMIC64_LOOP(v, mask, __ATOMIC64_OR);
+       __ATOMIC64_LOOP(v, mask, __ATOMIC64_OR, __ATOMIC64_NO_BARRIER);
 }
 
 #define atomic64_xchg(v, new) (xchg(&((v)->counter), new))
@@ -334,25 +360,13 @@ static inline void atomic64_clear_mask(unsigned long long mask, atomic64_t *v)
        } while (atomic64_cmpxchg(v, old, new) != old);
 }
 
-#endif /* CONFIG_64BIT */
-
 static inline void atomic64_add(long long i, atomic64_t *v)
 {
-#ifdef CONFIG_HAVE_MARCH_Z196_FEATURES
-       if (__builtin_constant_p(i) && (i > -129) && (i < 128)) {
-               asm volatile(
-                       "agsi   %0,%1\n"
-                       : "+Q" (v->counter)
-                       : "i" (i)
-                       : "cc", "memory");
-       } else {
-               atomic64_add_return(i, v);
-       }
-#else
        atomic64_add_return(i, v);
-#endif
 }
 
+#endif /* CONFIG_64BIT */
+
 static inline int atomic64_add_unless(atomic64_t *v, long long i, long long u)
 {
        long long c, old;
index ec5ef89..5205424 100644 (file)
 
 #include <linux/typecheck.h>
 #include <linux/compiler.h>
+#include <asm/barrier.h>
+
+#define __BITOPS_NO_BARRIER    "\n"
 
 #ifndef CONFIG_64BIT
 
 #define __BITOPS_OR            "or"
 #define __BITOPS_AND           "nr"
 #define __BITOPS_XOR           "xr"
+#define __BITOPS_BARRIER       "\n"
 
-#define __BITOPS_LOOP(__addr, __val, __op_string)              \
+#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier)   \
 ({                                                             \
        unsigned long __old, __new;                             \
                                                                \
@@ -67,7 +71,7 @@
                "       jl      0b"                             \
                : "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\
                : "d" (__val)                                   \
-               : "cc");                                        \
+               : "cc", "memory");                              \
        __old;                                                  \
 })
 
 #define __BITOPS_OR            "laog"
 #define __BITOPS_AND           "lang"
 #define __BITOPS_XOR           "laxg"
+#define __BITOPS_BARRIER       "bcr    14,0\n"
 
-#define __BITOPS_LOOP(__addr, __val, __op_string)              \
+#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier)   \
 ({                                                             \
        unsigned long __old;                                    \
                                                                \
        typecheck(unsigned long *, (__addr));                   \
        asm volatile(                                           \
+               __barrier                                       \
                __op_string "   %0,%2,%1\n"                     \
+               __barrier                                       \
                : "=d" (__old), "+Q" (*(__addr))                \
                : "d" (__val)                                   \
-               : "cc");                                        \
+               : "cc", "memory");                              \
        __old;                                                  \
 })
 
 #define __BITOPS_OR            "ogr"
 #define __BITOPS_AND           "ngr"
 #define __BITOPS_XOR           "xgr"
+#define __BITOPS_BARRIER       "\n"
 
-#define __BITOPS_LOOP(__addr, __val, __op_string)              \
+#define __BITOPS_LOOP(__addr, __val, __op_string, __barrier)   \
 ({                                                             \
        unsigned long __old, __new;                             \
                                                                \
                "       jl      0b"                             \
                : "=&d" (__old), "=&d" (__new), "+Q" (*(__addr))\
                : "d" (__val)                                   \
-               : "cc");                                        \
+               : "cc", "memory");                              \
        __old;                                                  \
 })
 
@@ -149,12 +157,12 @@ static inline void set_bit(unsigned long nr, volatile unsigned long *ptr)
                        "oi     %0,%b1\n"
                        : "+Q" (*caddr)
                        : "i" (1 << (nr & 7))
-                       : "cc");
+                       : "cc", "memory");
                return;
        }
 #endif
        mask = 1UL << (nr & (BITS_PER_LONG - 1));
-       __BITOPS_LOOP(addr, mask, __BITOPS_OR);
+       __BITOPS_LOOP(addr, mask, __BITOPS_OR, __BITOPS_NO_BARRIER);
 }
 
 static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
@@ -170,12 +178,12 @@ static inline void clear_bit(unsigned long nr, volatile unsigned long *ptr)
                        "ni     %0,%b1\n"
                        : "+Q" (*caddr)
                        : "i" (~(1 << (nr & 7)))
-                       : "cc");
+                       : "cc", "memory");
                return;
        }
 #endif
        mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
-       __BITOPS_LOOP(addr, mask, __BITOPS_AND);
+       __BITOPS_LOOP(addr, mask, __BITOPS_AND, __BITOPS_NO_BARRIER);
 }
 
 static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
@@ -191,12 +199,12 @@ static inline void change_bit(unsigned long nr, volatile unsigned long *ptr)
                        "xi     %0,%b1\n"
                        : "+Q" (*caddr)
                        : "i" (1 << (nr & 7))
-                       : "cc");
+                       : "cc", "memory");
                return;
        }
 #endif
        mask = 1UL << (nr & (BITS_PER_LONG - 1));
-       __BITOPS_LOOP(addr, mask, __BITOPS_XOR);
+       __BITOPS_LOOP(addr, mask, __BITOPS_XOR, __BITOPS_NO_BARRIER);
 }
 
 static inline int
@@ -206,8 +214,7 @@ test_and_set_bit(unsigned long nr, volatile unsigned long *ptr)
        unsigned long old, mask;
 
        mask = 1UL << (nr & (BITS_PER_LONG - 1));
-       old = __BITOPS_LOOP(addr, mask, __BITOPS_OR);
-       barrier();
+       old = __BITOPS_LOOP(addr, mask, __BITOPS_OR, __BITOPS_BARRIER);
        return (old & mask) != 0;
 }
 
@@ -218,8 +225,7 @@ test_and_clear_bit(unsigned long nr, volatile unsigned long *ptr)
        unsigned long old, mask;
 
        mask = ~(1UL << (nr & (BITS_PER_LONG - 1)));
-       old = __BITOPS_LOOP(addr, mask, __BITOPS_AND);
-       barrier();
+       old = __BITOPS_LOOP(addr, mask, __BITOPS_AND, __BITOPS_BARRIER);
        return (old & ~mask) != 0;
 }
 
@@ -230,8 +236,7 @@ test_and_change_bit(unsigned long nr, volatile unsigned long *ptr)
        unsigned long old, mask;
 
        mask = 1UL << (nr & (BITS_PER_LONG - 1));
-       old = __BITOPS_LOOP(addr, mask, __BITOPS_XOR);
-       barrier();
+       old = __BITOPS_LOOP(addr, mask, __BITOPS_XOR, __BITOPS_BARRIER);
        return (old & mask) != 0;
 }
 
index fda46bd..69cf5b5 100644 (file)
@@ -1,12 +1,25 @@
 #ifndef _ASM_S390_FUTEX_H
 #define _ASM_S390_FUTEX_H
 
-#include <linux/futex.h>
 #include <linux/uaccess.h>
+#include <linux/futex.h>
+#include <asm/mmu_context.h>
 #include <asm/errno.h>
 
-int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval);
-int __futex_atomic_op_inuser(int op, u32 __user *uaddr, int oparg, int *old);
+#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg)     \
+       asm volatile(                                                   \
+               "   sacf  256\n"                                        \
+               "0: l     %1,0(%6)\n"                                   \
+               "1:"insn                                                \
+               "2: cs    %1,%2,0(%6)\n"                                \
+               "3: jl    1b\n"                                         \
+               "   lhi   %0,0\n"                                       \
+               "4: sacf  768\n"                                        \
+               EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b)         \
+               : "=d" (ret), "=&d" (oldval), "=&d" (newval),           \
+                 "=m" (*uaddr)                                         \
+               : "0" (-EFAULT), "d" (oparg), "a" (uaddr),              \
+                 "m" (*uaddr) : "cc");
 
 static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 {
@@ -14,13 +27,37 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
        int cmp = (encoded_op >> 24) & 15;
        int oparg = (encoded_op << 8) >> 20;
        int cmparg = (encoded_op << 20) >> 20;
-       int oldval, ret;
+       int oldval = 0, newval, ret;
 
+       update_primary_asce(current);
        if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
                oparg = 1 << oparg;
 
        pagefault_disable();
-       ret = __futex_atomic_op_inuser(op, uaddr, oparg, &oldval);
+       switch (op) {
+       case FUTEX_OP_SET:
+               __futex_atomic_op("lr %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ADD:
+               __futex_atomic_op("lr %2,%1\nar %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       case FUTEX_OP_OR:
+               __futex_atomic_op("lr %2,%1\nor %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       case FUTEX_OP_ANDN:
+               __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       case FUTEX_OP_XOR:
+               __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
+                                 ret, oldval, newval, uaddr, oparg);
+               break;
+       default:
+               ret = -ENOSYS;
+       }
        pagefault_enable();
 
        if (!ret) {
@@ -37,4 +74,23 @@ static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
        return ret;
 }
 
+static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+                                               u32 oldval, u32 newval)
+{
+       int ret;
+
+       update_primary_asce(current);
+       asm volatile(
+               "   sacf 256\n"
+               "0: cs   %1,%4,0(%5)\n"
+               "1: la   %0,0\n"
+               "2: sacf 768\n"
+               EX_TABLE(0b,2b) EX_TABLE(1b,2b)
+               : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
+               : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
+               : "cc", "memory");
+       *uval = oldval;
+       return ret;
+}
+
 #endif /* _ASM_S390_FUTEX_H */
index 35f0faa..c4dd400 100644 (file)
 /* This number is used when no interrupt has been assigned */
 #define NO_IRQ         0
 
+/* External interruption codes */
+#define EXT_IRQ_INTERRUPT_KEY  0x0040
+#define EXT_IRQ_CLK_COMP       0x1004
+#define EXT_IRQ_CPU_TIMER      0x1005
+#define EXT_IRQ_WARNING_TRACK  0x1007
+#define EXT_IRQ_MALFUNC_ALERT  0x1200
+#define EXT_IRQ_EMERGENCY_SIG  0x1201
+#define EXT_IRQ_EXTERNAL_CALL  0x1202
+#define EXT_IRQ_TIMING_ALERT   0x1406
+#define EXT_IRQ_MEASURE_ALERT  0x1407
+#define EXT_IRQ_SERVICE_SIG    0x2401
+#define EXT_IRQ_CP_SERVICE     0x2603
+#define EXT_IRQ_IUCV           0x4000
+
 #ifndef __ASSEMBLY__
 
 #include <linux/hardirq.h>
@@ -77,8 +91,8 @@ struct ext_code {
 
 typedef void (*ext_int_handler_t)(struct ext_code, unsigned int, unsigned long);
 
-int register_external_interrupt(u16 code, ext_int_handler_t handler);
-int unregister_external_interrupt(u16 code, ext_int_handler_t handler);
+int register_external_irq(u16 code, ext_int_handler_t handler);
+int unregister_external_irq(u16 code, ext_int_handler_t handler);
 
 enum irq_subclass {
        IRQ_SUBCLASS_MEASUREMENT_ALERT = 5,
index ff132ac..f77695a 100644 (file)
@@ -1,9 +1,11 @@
 #ifndef __MMU_H
 #define __MMU_H
 
+#include <linux/cpumask.h>
 #include <linux/errno.h>
 
 typedef struct {
+       cpumask_t cpu_attach_mask;
        atomic_t attach_count;
        unsigned int flush_mm;
        spinlock_t list_lock;
index 38149b6..71be346 100644 (file)
@@ -15,6 +15,7 @@
 static inline int init_new_context(struct task_struct *tsk,
                                   struct mm_struct *mm)
 {
+       cpumask_clear(&mm->context.cpu_attach_mask);
        atomic_set(&mm->context.attach_count, 0);
        mm->context.flush_mm = 0;
        mm->context.asce_bits = _ASCE_TABLE_LENGTH | _ASCE_USER_BITS;
@@ -29,41 +30,61 @@ static inline int init_new_context(struct task_struct *tsk,
 
 #define destroy_context(mm)             do { } while (0)
 
-#ifndef CONFIG_64BIT
-#define LCTL_OPCODE "lctl"
-#else
-#define LCTL_OPCODE "lctlg"
-#endif
-
-static inline void update_mm(struct mm_struct *mm, struct task_struct *tsk)
+static inline void update_user_asce(struct mm_struct *mm, int load_primary)
 {
        pgd_t *pgd = mm->pgd;
 
        S390_lowcore.user_asce = mm->context.asce_bits | __pa(pgd);
-       /* Load primary space page table origin. */
-       asm volatile(LCTL_OPCODE" 1,1,%0\n" : : "m" (S390_lowcore.user_asce));
+       if (load_primary)
+               __ctl_load(S390_lowcore.user_asce, 1, 1);
        set_fs(current->thread.mm_segment);
 }
 
+static inline void clear_user_asce(struct mm_struct *mm, int load_primary)
+{
+       S390_lowcore.user_asce = S390_lowcore.kernel_asce;
+
+       if (load_primary)
+               __ctl_load(S390_lowcore.user_asce, 1, 1);
+       __ctl_load(S390_lowcore.user_asce, 7, 7);
+}
+
+static inline void update_primary_asce(struct task_struct *tsk)
+{
+       unsigned long asce;
+
+       __ctl_store(asce, 1, 1);
+       if (asce != S390_lowcore.kernel_asce)
+               __ctl_load(S390_lowcore.kernel_asce, 1, 1);
+       set_tsk_thread_flag(tsk, TIF_ASCE);
+}
+
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
                             struct task_struct *tsk)
 {
        int cpu = smp_processor_id();
 
+       update_primary_asce(tsk);
        if (prev == next)
                return;
+       if (MACHINE_HAS_TLB_LC)
+               cpumask_set_cpu(cpu, &next->context.cpu_attach_mask);
        if (atomic_inc_return(&next->context.attach_count) >> 16) {
-               /* Delay update_mm until all TLB flushes are done. */
+               /* Delay update_user_asce until all TLB flushes are done. */
                set_tsk_thread_flag(tsk, TIF_TLB_WAIT);
+               /* Clear old ASCE by loading the kernel ASCE. */
+               clear_user_asce(next, 0);
        } else {
                cpumask_set_cpu(cpu, mm_cpumask(next));
-               update_mm(next, tsk);
+               update_user_asce(next, 0);
                if (next->context.flush_mm)
                        /* Flush pending TLBs */
                        __tlb_flush_mm(next);
        }
        atomic_dec(&prev->context.attach_count);
        WARN_ON(atomic_read(&prev->context.attach_count) < 0);
+       if (MACHINE_HAS_TLB_LC)
+               cpumask_clear_cpu(cpu, &prev->context.cpu_attach_mask);
 }
 
 #define finish_arch_post_lock_switch finish_arch_post_lock_switch
@@ -80,7 +101,7 @@ static inline void finish_arch_post_lock_switch(void)
                cpu_relax();
 
        cpumask_set_cpu(smp_processor_id(), mm_cpumask(mm));
-       update_mm(mm, tsk);
+       update_user_asce(mm, 0);
        if (mm->context.flush_mm)
                __tlb_flush_mm(mm);
        preempt_enable();
index 50a75d9..12f7531 100644 (file)
@@ -1070,12 +1070,35 @@ static inline void __ptep_ipte(unsigned long address, pte_t *ptep)
                : "=m" (*ptep) : "m" (*ptep), "a" (pto), "a" (address));
 }
 
+static inline void __ptep_ipte_local(unsigned long address, pte_t *ptep)
+{
+       unsigned long pto = (unsigned long) ptep;
+
+#ifndef CONFIG_64BIT
+       /* pto in ESA mode must point to the start of the segment table */
+       pto &= 0x7ffffc00;
+#endif
+       /* Invalidation + local TLB flush for the pte */
+       asm volatile(
+               "       .insn rrf,0xb2210000,%2,%3,0,1"
+               : "=m" (*ptep) : "m" (*ptep), "a" (pto), "a" (address));
+}
+
 static inline void ptep_flush_direct(struct mm_struct *mm,
                                     unsigned long address, pte_t *ptep)
 {
+       int active, count;
+
        if (pte_val(*ptep) & _PAGE_INVALID)
                return;
-       __ptep_ipte(address, ptep);
+       active = (mm == current->active_mm) ? 1 : 0;
+       count = atomic_add_return(0x10000, &mm->context.attach_count);
+       if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active &&
+           cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
+               __ptep_ipte_local(address, ptep);
+       else
+               __ptep_ipte(address, ptep);
+       atomic_sub(0x10000, &mm->context.attach_count);
 }
 
 static inline void ptep_flush_lazy(struct mm_struct *mm,
@@ -1384,35 +1407,6 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long address)
 #define pte_offset_map(pmd, address) pte_offset_kernel(pmd, address)
 #define pte_unmap(pte) do { } while (0)
 
-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_INVALID)) {
-               asm volatile(
-                       "       .insn   rrf,0xb98e0000,%2,%3,0,0"
-                       : "=m" (*pmdp)
-                       : "m" (*pmdp), "a" (sto),
-                         "a" ((address & HPAGE_MASK))
-                       : "cc"
-               );
-       }
-}
-
-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)
 {
@@ -1481,18 +1475,80 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE || CONFIG_HUGETLB_PAGE */
 
+static inline void __pmdp_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");
+}
+
+static inline void __pmdp_idte(unsigned long address, pmd_t *pmdp)
+{
+       unsigned long sto;
+
+       sto = (unsigned long) pmdp - pmd_index(address) * sizeof(pmd_t);
+       asm volatile(
+               "       .insn   rrf,0xb98e0000,%2,%3,0,0"
+               : "=m" (*pmdp)
+               : "m" (*pmdp), "a" (sto), "a" ((address & HPAGE_MASK))
+               : "cc" );
+}
+
+static inline void __pmdp_idte_local(unsigned long address, pmd_t *pmdp)
+{
+       unsigned long sto;
+
+       sto = (unsigned long) pmdp - pmd_index(address) * sizeof(pmd_t);
+       asm volatile(
+               "       .insn   rrf,0xb98e0000,%2,%3,0,1"
+               : "=m" (*pmdp)
+               : "m" (*pmdp), "a" (sto), "a" ((address & HPAGE_MASK))
+               : "cc" );
+}
+
+static inline void pmdp_flush_direct(struct mm_struct *mm,
+                                    unsigned long address, pmd_t *pmdp)
+{
+       int active, count;
+
+       if (pmd_val(*pmdp) & _SEGMENT_ENTRY_INVALID)
+               return;
+       if (!MACHINE_HAS_IDTE) {
+               __pmdp_csp(pmdp);
+               return;
+       }
+       active = (mm == current->active_mm) ? 1 : 0;
+       count = atomic_add_return(0x10000, &mm->context.attach_count);
+       if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active &&
+           cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id())))
+               __pmdp_idte_local(address, pmdp);
+       else
+               __pmdp_idte(address, pmdp);
+       atomic_sub(0x10000, &mm->context.attach_count);
+}
+
 static inline void pmdp_flush_lazy(struct mm_struct *mm,
                                   unsigned long address, pmd_t *pmdp)
 {
        int active, count;
 
+       if (pmd_val(*pmdp) & _SEGMENT_ENTRY_INVALID)
+               return;
        active = (mm == current->active_mm) ? 1 : 0;
        count = atomic_add_return(0x10000, &mm->context.attach_count);
        if ((count & 0xffff) <= active) {
                pmd_val(*pmdp) |= _SEGMENT_ENTRY_INVALID;
                mm->context.flush_mm = 1;
-       } else
-               __pmd_idte(address, pmdp);
+       } else if (MACHINE_HAS_IDTE)
+               __pmdp_idte(address, pmdp);
+       else
+               __pmdp_csp(pmdp);
        atomic_sub(0x10000, &mm->context.attach_count);
 }
 
@@ -1545,7 +1601,7 @@ static inline int pmdp_test_and_clear_young(struct vm_area_struct *vma,
        pmd_t pmd;
 
        pmd = *pmdp;
-       __pmd_idte(address, pmdp);
+       pmdp_flush_direct(vma->vm_mm, address, pmdp);
        *pmdp = pmd_mkold(pmd);
        return pmd_young(pmd);
 }
@@ -1556,7 +1612,7 @@ static inline pmd_t pmdp_get_and_clear(struct mm_struct *mm,
 {
        pmd_t pmd = *pmdp;
 
-       __pmd_idte(address, pmdp);
+       pmdp_flush_direct(mm, address, pmdp);
        pmd_clear(pmdp);
        return pmd;
 }
@@ -1572,7 +1628,7 @@ static inline pmd_t pmdp_clear_flush(struct vm_area_struct *vma,
 static inline void pmdp_invalidate(struct vm_area_struct *vma,
                                   unsigned long address, pmd_t *pmdp)
 {
-       __pmd_idte(address, pmdp);
+       pmdp_flush_direct(vma->vm_mm, address, pmdp);
 }
 
 #define __HAVE_ARCH_PMDP_SET_WRPROTECT
@@ -1582,7 +1638,7 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
        pmd_t pmd = *pmdp;
 
        if (pmd_write(pmd)) {
-               __pmd_idte(address, pmdp);
+               pmdp_flush_direct(mm, address, pmdp);
                set_pmd_at(mm, address, pmdp, pmd_wrprotect(pmd));
        }
 }
index 406f3a1..b31b22d 100644 (file)
@@ -68,6 +68,7 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
 #define MACHINE_FLAG_TOPOLOGY  (1UL << 14)
 #define MACHINE_FLAG_TE                (1UL << 15)
 #define MACHINE_FLAG_RRBM      (1UL << 16)
+#define MACHINE_FLAG_TLB_LC    (1UL << 17)
 
 #define MACHINE_IS_VM          (S390_lowcore.machine_flags & MACHINE_FLAG_VM)
 #define MACHINE_IS_KVM         (S390_lowcore.machine_flags & MACHINE_FLAG_KVM)
@@ -90,6 +91,7 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
 #define MACHINE_HAS_TOPOLOGY   (0)
 #define MACHINE_HAS_TE         (0)
 #define MACHINE_HAS_RRBM       (0)
+#define MACHINE_HAS_TLB_LC     (0)
 #else /* CONFIG_64BIT */
 #define MACHINE_HAS_IEEE       (1)
 #define MACHINE_HAS_CSP                (1)
@@ -102,6 +104,7 @@ void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
 #define MACHINE_HAS_TOPOLOGY   (S390_lowcore.machine_flags & MACHINE_FLAG_TOPOLOGY)
 #define MACHINE_HAS_TE         (S390_lowcore.machine_flags & MACHINE_FLAG_TE)
 #define MACHINE_HAS_RRBM       (S390_lowcore.machine_flags & MACHINE_FLAG_RRBM)
+#define MACHINE_HAS_TLB_LC     (S390_lowcore.machine_flags & MACHINE_FLAG_TLB_LC)
 #endif /* CONFIG_64BIT */
 
 /*
index 29c81f8..e759181 100644 (file)
@@ -132,6 +132,7 @@ static inline void restore_access_regs(unsigned int *acrs)
                update_cr_regs(next);                                   \
        }                                                               \
        prev = __switch_to(prev,next);                                  \
+       update_primary_asce(current);                                   \
 } while (0)
 
 #define finish_arch_switch(prev) do {                                       \
index 3ccd71b..50630e6 100644 (file)
@@ -82,6 +82,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_SIGPENDING         2       /* signal pending */
 #define TIF_NEED_RESCHED       3       /* rescheduling necessary */
 #define TIF_TLB_WAIT           4       /* wait for TLB flush completion */
+#define TIF_ASCE               5       /* primary asce needs fixup / uaccess */
 #define TIF_PER_TRAP           6       /* deliver sigtrap on return to user */
 #define TIF_MCCK_PENDING       7       /* machine check handling is pending */
 #define TIF_SYSCALL_TRACE      8       /* syscall trace active */
@@ -99,6 +100,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_TLB_WAIT          (1<<TIF_TLB_WAIT)
+#define _TIF_ASCE              (1<<TIF_ASCE)
 #define _TIF_PER_TRAP          (1<<TIF_PER_TRAP)
 #define _TIF_MCCK_PENDING      (1<<TIF_MCCK_PENDING)
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
index 2cb846c..c544b6f 100644 (file)
@@ -57,8 +57,6 @@ static inline void tlb_gather_mmu(struct mmu_gather *tlb,
        tlb->end = end;
        tlb->fullmm = !(start | (end+1));
        tlb->batch = NULL;
-       if (tlb->fullmm)
-               __tlb_flush_mm(mm);
 }
 
 static inline void tlb_flush_mmu(struct mmu_gather *tlb)
@@ -96,9 +94,7 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
 static inline void pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
                                unsigned long address)
 {
-       if (!tlb->fullmm)
-               return page_table_free_rcu(tlb, (unsigned long *) pte);
-       page_table_free(tlb->mm, (unsigned long *) pte);
+       page_table_free_rcu(tlb, (unsigned long *) pte);
 }
 
 /*
@@ -114,9 +110,7 @@ static inline void pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmd,
 #ifdef CONFIG_64BIT
        if (tlb->mm->context.asce_limit <= (1UL << 31))
                return;
-       if (!tlb->fullmm)
-               return tlb_remove_table(tlb, pmd);
-       crst_table_free(tlb->mm, (unsigned long *) pmd);
+       tlb_remove_table(tlb, pmd);
 #endif
 }
 
@@ -133,9 +127,7 @@ static inline void pud_free_tlb(struct mmu_gather *tlb, pud_t *pud,
 #ifdef CONFIG_64BIT
        if (tlb->mm->context.asce_limit <= (1UL << 42))
                return;
-       if (!tlb->fullmm)
-               return tlb_remove_table(tlb, pud);
-       crst_table_free(tlb->mm, (unsigned long *) pud);
+       tlb_remove_table(tlb, pud);
 #endif
 }
 
index f9fef04..16c9c88 100644 (file)
@@ -7,19 +7,41 @@
 #include <asm/pgalloc.h>
 
 /*
- * Flush all tlb entries on the local cpu.
+ * Flush all TLB entries on the local CPU.
  */
 static inline void __tlb_flush_local(void)
 {
        asm volatile("ptlb" : : : "memory");
 }
 
-#ifdef CONFIG_SMP
 /*
- * Flush all tlb entries on all cpus.
+ * Flush TLB entries for a specific ASCE on all CPUs
  */
+static inline void __tlb_flush_idte(unsigned long asce)
+{
+       /* Global TLB flush for the mm */
+       asm volatile(
+               "       .insn   rrf,0xb98e0000,0,%0,%1,0"
+               : : "a" (2048), "a" (asce) : "cc");
+}
+
+/*
+ * Flush TLB entries for a specific ASCE on the local CPU
+ */
+static inline void __tlb_flush_idte_local(unsigned long asce)
+{
+       /* Local TLB flush for the mm */
+       asm volatile(
+               "       .insn   rrf,0xb98e0000,0,%0,%1,1"
+               : : "a" (2048), "a" (asce) : "cc");
+}
+
+#ifdef CONFIG_SMP
 void smp_ptlb_all(void);
 
+/*
+ * Flush all TLB entries on all CPUs.
+ */
 static inline void __tlb_flush_global(void)
 {
        register unsigned long reg2 asm("2");
@@ -42,36 +64,89 @@ static inline void __tlb_flush_global(void)
                : : "d" (reg2), "d" (reg3), "d" (reg4), "m" (dummy) : "cc" );
 }
 
+/*
+ * Flush TLB entries for a specific mm on all CPUs (in case gmap is used
+ * this implicates multiple ASCEs!).
+ */
 static inline void __tlb_flush_full(struct mm_struct *mm)
 {
-       cpumask_t local_cpumask;
-
        preempt_disable();
-       /*
-        * If the process only ran on the local cpu, do a local flush.
-        */
-       cpumask_copy(&local_cpumask, cpumask_of(smp_processor_id()));
-       if (cpumask_equal(mm_cpumask(mm), &local_cpumask))
+       atomic_add(0x10000, &mm->context.attach_count);
+       if (cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+               /* Local TLB flush */
                __tlb_flush_local();
-       else
+       } else {
+               /* Global TLB flush */
                __tlb_flush_global();
+               /* Reset TLB flush mask */
+               if (MACHINE_HAS_TLB_LC)
+                       cpumask_copy(mm_cpumask(mm),
+                                    &mm->context.cpu_attach_mask);
+       }
+       atomic_sub(0x10000, &mm->context.attach_count);
        preempt_enable();
 }
+
+/*
+ * Flush TLB entries for a specific ASCE on all CPUs.
+ */
+static inline void __tlb_flush_asce(struct mm_struct *mm, unsigned long asce)
+{
+       int active, count;
+
+       preempt_disable();
+       active = (mm == current->active_mm) ? 1 : 0;
+       count = atomic_add_return(0x10000, &mm->context.attach_count);
+       if (MACHINE_HAS_TLB_LC && (count & 0xffff) <= active &&
+           cpumask_equal(mm_cpumask(mm), cpumask_of(smp_processor_id()))) {
+               __tlb_flush_idte_local(asce);
+       } else {
+               if (MACHINE_HAS_IDTE)
+                       __tlb_flush_idte(asce);
+               else
+                       __tlb_flush_global();
+               /* Reset TLB flush mask */
+               if (MACHINE_HAS_TLB_LC)
+                       cpumask_copy(mm_cpumask(mm),
+                                    &mm->context.cpu_attach_mask);
+       }
+       atomic_sub(0x10000, &mm->context.attach_count);
+       preempt_enable();
+}
+
+static inline void __tlb_flush_kernel(void)
+{
+       if (MACHINE_HAS_IDTE)
+               __tlb_flush_idte((unsigned long) init_mm.pgd |
+                                init_mm.context.asce_bits);
+       else
+               __tlb_flush_global();
+}
 #else
-#define __tlb_flush_full(mm)   __tlb_flush_local()
 #define __tlb_flush_global()   __tlb_flush_local()
-#endif
+#define __tlb_flush_full(mm)   __tlb_flush_local()
 
 /*
- * Flush all tlb entries of a page table on all cpus.
+ * Flush TLB entries for a specific ASCE on all CPUs.
  */
-static inline void __tlb_flush_idte(unsigned long asce)
+static inline void __tlb_flush_asce(struct mm_struct *mm, unsigned long asce)
 {
-       asm volatile(
-               "       .insn   rrf,0xb98e0000,0,%0,%1,0"
-               : : "a" (2048), "a" (asce) : "cc" );
+       if (MACHINE_HAS_TLB_LC)
+               __tlb_flush_idte_local(asce);
+       else
+               __tlb_flush_local();
 }
 
+static inline void __tlb_flush_kernel(void)
+{
+       if (MACHINE_HAS_TLB_LC)
+               __tlb_flush_idte_local((unsigned long) init_mm.pgd |
+                                      init_mm.context.asce_bits);
+       else
+               __tlb_flush_local();
+}
+#endif
+
 static inline void __tlb_flush_mm(struct mm_struct * mm)
 {
        /*
@@ -80,7 +155,7 @@ static inline void __tlb_flush_mm(struct mm_struct * mm)
         * only ran on the local cpu.
         */
        if (MACHINE_HAS_IDTE && list_empty(&mm->context.gmap_list))
-               __tlb_flush_idte((unsigned long) mm->pgd |
+               __tlb_flush_asce(mm, (unsigned long) mm->pgd |
                                 mm->context.asce_bits);
        else
                __tlb_flush_full(mm);
@@ -130,7 +205,7 @@ static inline void flush_tlb_range(struct vm_area_struct *vma,
 static inline void flush_tlb_kernel_range(unsigned long start,
                                          unsigned long end)
 {
-       __tlb_flush_mm(&init_mm);
+       __tlb_flush_kernel();
 }
 
 #endif /* _S390_TLBFLUSH_H */
index 4133b3f..1be64a1 100644 (file)
@@ -92,8 +92,6 @@ static inline unsigned long extable_fixup(const struct exception_table_entry *x)
 #define ARCH_HAS_SORT_EXTABLE
 #define ARCH_HAS_SEARCH_EXTABLE
 
-int __handle_fault(unsigned long, unsigned long, int);
-
 /**
  * __copy_from_user: - Copy a block of data from user space, with less checking.
  * @to:   Destination address, in kernel space.
index e4c99a1..cc10cdd 100644 (file)
@@ -136,6 +136,7 @@ int main(void)
        DEFINE(__LC_RESTART_FN, offsetof(struct _lowcore, restart_fn));
        DEFINE(__LC_RESTART_DATA, offsetof(struct _lowcore, restart_data));
        DEFINE(__LC_RESTART_SOURCE, offsetof(struct _lowcore, restart_source));
+       DEFINE(__LC_KERNEL_ASCE, offsetof(struct _lowcore, kernel_asce));
        DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce));
        DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock));
        DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock));
index 3a414c0..c0b03c2 100644 (file)
@@ -378,9 +378,12 @@ static int __init cache_init(void)
        if (!test_facility(34))
                return 0;
        cache_build_info();
+
+       cpu_notifier_register_begin();
        for_each_online_cpu(cpu)
                cache_add_cpu(cpu);
-       hotcpu_notifier(cache_hotplug, 0);
+       __hotcpu_notifier(cache_hotplug, 0);
+       cpu_notifier_register_done();
        return 0;
 }
 device_initcall(cache_init);
index 6b59443..a734f35 100644 (file)
@@ -386,6 +386,8 @@ static __init void detect_machine_facilities(void)
                S390_lowcore.machine_flags |= MACHINE_FLAG_TE;
        if (test_facility(66))
                S390_lowcore.machine_flags |= MACHINE_FLAG_RRBM;
+       if (test_facility(51))
+               S390_lowcore.machine_flags |= MACHINE_FLAG_TLB_LC;
 #endif
 }
 
index 526d373..1662038 100644 (file)
@@ -38,9 +38,9 @@ __PT_R14     =        __PT_GPRS + 56
 __PT_R15     = __PT_GPRS + 60
 
 _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
-                _TIF_MCCK_PENDING | _TIF_PER_TRAP )
+                _TIF_MCCK_PENDING | _TIF_PER_TRAP | _TIF_ASCE)
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
-                _TIF_MCCK_PENDING)
+                _TIF_MCCK_PENDING | _TIF_ASCE)
 _TIF_TRACE    = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
                 _TIF_SYSCALL_TRACEPOINT)
 _TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
@@ -241,6 +241,8 @@ sysc_work:
        jo      sysc_sigpending
        tm      __TI_flags+3(%r12),_TIF_NOTIFY_RESUME
        jo      sysc_notify_resume
+       tm      __TI_flags+3(%r12),_TIF_ASCE
+       jo      sysc_uaccess
        j       sysc_return             # beware of critical section cleanup
 
 #
@@ -259,6 +261,14 @@ sysc_mcck_pending:
        la      %r14,BASED(sysc_return)
        br      %r1                     # TIF bit will be cleared by handler
 
+#
+# _TIF_ASCE is set, load user space asce
+#
+sysc_uaccess:
+       ni      __TI_flags+3(%r12),255-_TIF_ASCE
+       lctl    %c1,%c1,__LC_USER_ASCE  # load primary asce
+       j       sysc_return
+
 #
 # _TIF_SIGPENDING is set, call do_signal
 #
@@ -522,6 +532,8 @@ io_work_tif:
        jo      io_sigpending
        tm      __TI_flags+3(%r12),_TIF_NOTIFY_RESUME
        jo      io_notify_resume
+       tm      __TI_flags+3(%r12),_TIF_ASCE
+       jo      io_uaccess
        j       io_return               # beware of critical section cleanup
 
 #
@@ -534,6 +546,14 @@ io_mcck_pending:
        TRACE_IRQS_OFF
        j       io_return
 
+#
+# _TIF_ASCE is set, load user space asce
+#
+io_uaccess:
+       ni      __TI_flags+3(%r12),255-_TIF_ASCE
+       lctl    %c1,%c1,__LC_USER_ASCE  # load primary asce
+       j       io_return
+
 #
 # _TIF_NEED_RESCHED is set, call schedule
 #
index e09dbe5..5963e43 100644 (file)
@@ -43,9 +43,9 @@ STACK_SIZE  = 1 << STACK_SHIFT
 STACK_INIT = STACK_SIZE - STACK_FRAME_OVERHEAD - __PT_SIZE
 
 _TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
-                _TIF_MCCK_PENDING | _TIF_PER_TRAP )
+                _TIF_MCCK_PENDING | _TIF_PER_TRAP | _TIF_ASCE)
 _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED | \
-                _TIF_MCCK_PENDING)
+                _TIF_MCCK_PENDING | _TIF_ASCE)
 _TIF_TRACE    = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
                 _TIF_SYSCALL_TRACEPOINT)
 _TIF_TRANSFER = (_TIF_MCCK_PENDING | _TIF_TLB_WAIT)
@@ -275,6 +275,8 @@ sysc_work:
        jo      sysc_sigpending
        tm      __TI_flags+7(%r12),_TIF_NOTIFY_RESUME
        jo      sysc_notify_resume
+       tm      __TI_flags+7(%r12),_TIF_ASCE
+       jo      sysc_uaccess
        j       sysc_return             # beware of critical section cleanup
 
 #
@@ -291,6 +293,14 @@ sysc_mcck_pending:
        larl    %r14,sysc_return
        jg      s390_handle_mcck        # TIF bit will be cleared by handler
 
+#
+# _TIF_ASCE is set, load user space asce
+#
+sysc_uaccess:
+       ni      __TI_flags+7(%r12),255-_TIF_ASCE
+       lctlg   %c1,%c1,__LC_USER_ASCE          # load primary asce
+       j       sysc_return
+
 #
 # _TIF_SIGPENDING is set, call do_signal
 #
@@ -559,6 +569,8 @@ io_work_tif:
        jo      io_sigpending
        tm      __TI_flags+7(%r12),_TIF_NOTIFY_RESUME
        jo      io_notify_resume
+       tm      __TI_flags+7(%r12),_TIF_ASCE
+       jo      io_uaccess
        j       io_return               # beware of critical section cleanup
 
 #
@@ -570,6 +582,14 @@ io_mcck_pending:
        TRACE_IRQS_OFF
        j       io_return
 
+#
+# _TIF_ASCE is set, load user space asce
+#
+io_uaccess:
+       ni      __TI_flags+7(%r12),255-_TIF_ASCE
+       lctlg   %c1,%c1,__LC_USER_ASCE          # load primary asce
+       j       io_return
+
 #
 # _TIF_NEED_RESCHED is set, call schedule
 #
index d42b14c..c7463aa 100644 (file)
@@ -207,7 +207,7 @@ static inline int ext_hash(u16 code)
        return (code + (code >> 9)) & (ARRAY_SIZE(ext_int_hash) - 1);
 }
 
-int register_external_interrupt(u16 code, ext_int_handler_t handler)
+int register_external_irq(u16 code, ext_int_handler_t handler)
 {
        struct ext_int_info *p;
        unsigned long flags;
@@ -225,9 +225,9 @@ int register_external_interrupt(u16 code, ext_int_handler_t handler)
        spin_unlock_irqrestore(&ext_int_hash_lock, flags);
        return 0;
 }
-EXPORT_SYMBOL(register_external_interrupt);
+EXPORT_SYMBOL(register_external_irq);
 
-int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
+int unregister_external_irq(u16 code, ext_int_handler_t handler)
 {
        struct ext_int_info *p;
        unsigned long flags;
@@ -243,7 +243,7 @@ int unregister_external_interrupt(u16 code, ext_int_handler_t handler)
        spin_unlock_irqrestore(&ext_int_hash_lock, flags);
        return 0;
 }
-EXPORT_SYMBOL(unregister_external_interrupt);
+EXPORT_SYMBOL(unregister_external_irq);
 
 static irqreturn_t do_ext_interrupt(int irq, void *dummy)
 {
@@ -253,7 +253,7 @@ static irqreturn_t do_ext_interrupt(int irq, void *dummy)
        int index;
 
        ext_code = *(struct ext_code *) &regs->int_code;
-       if (ext_code.code != 0x1004)
+       if (ext_code.code != EXT_IRQ_CLK_COMP)
                __get_cpu_var(s390_idle).nohz_delay = 1;
 
        index = ext_hash(ext_code.code);
index f51214c..ea75d01 100644 (file)
@@ -673,7 +673,8 @@ static int __init cpumf_pmu_init(void)
        ctl_clear_bit(0, 48);
 
        /* register handler for measurement-alert interruptions */
-       rc = register_external_interrupt(0x1407, cpumf_measurement_alert);
+       rc = register_external_irq(EXT_IRQ_MEASURE_ALERT,
+                                  cpumf_measurement_alert);
        if (rc) {
                pr_err("Registering for CPU-measurement alerts "
                       "failed with rc=%i\n", rc);
@@ -684,7 +685,8 @@ static int __init cpumf_pmu_init(void)
        rc = perf_pmu_register(&cpumf_pmu, "cpum_cf", PERF_TYPE_RAW);
        if (rc) {
                pr_err("Registering the cpum_cf PMU failed with rc=%i\n", rc);
-               unregister_external_interrupt(0x1407, cpumf_measurement_alert);
+               unregister_external_irq(EXT_IRQ_MEASURE_ALERT,
+                                       cpumf_measurement_alert);
                goto out;
        }
        perf_cpu_notifier(cpumf_pmu_notifier);
index 6c0d298..ea0c7b2 100644 (file)
@@ -1621,7 +1621,8 @@ static int __init init_cpum_sampling_pmu(void)
                pr_err("Registering for s390dbf failed\n");
        debug_register_view(sfdbg, &debug_sprintf_view);
 
-       err = register_external_interrupt(0x1407, cpumf_measurement_alert);
+       err = register_external_irq(EXT_IRQ_MEASURE_ALERT,
+                                   cpumf_measurement_alert);
        if (err) {
                pr_cpumsf_err(RS_INIT_FAILURE_ALRT);
                goto out;
@@ -1630,7 +1631,8 @@ static int __init init_cpum_sampling_pmu(void)
        err = perf_pmu_register(&cpumf_sampling, "cpum_sf", PERF_TYPE_RAW);
        if (err) {
                pr_cpumsf_err(RS_INIT_FAILURE_PERF);
-               unregister_external_interrupt(0x1407, cpumf_measurement_alert);
+               unregister_external_irq(EXT_IRQ_MEASURE_ALERT,
+                                       cpumf_measurement_alert);
                goto out;
        }
        perf_cpu_notifier(cpumf_pmu_notifier);
index d817cce..26b4ae9 100644 (file)
@@ -138,7 +138,8 @@ static int __init runtime_instr_init(void)
                return 0;
 
        irq_subclass_register(IRQ_SUBCLASS_MEASUREMENT_ALERT);
-       rc = register_external_interrupt(0x1407, runtime_instr_int_handler);
+       rc = register_external_irq(EXT_IRQ_MEASURE_ALERT,
+                                  runtime_instr_int_handler);
        if (rc)
                irq_subclass_unregister(IRQ_SUBCLASS_MEASUREMENT_ALERT);
        else
index 29bd7be..a41f2c9 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/linkage.h>
+#include <asm/irq.h>
 
 LC_EXT_NEW_PSW         = 0x58                  # addr of ext int handler
 LC_EXT_NEW_PSW_64      = 0x1b0                 # addr of ext int handler 64 bit
@@ -73,9 +74,9 @@ _sclp_wait_int:
        lpsw    .LwaitpswS1-.LbaseS1(%r13)      # wait until interrupt
 .LwaitS1:
        lh      %r7,LC_EXT_INT_CODE
-       chi     %r7,0x1004                      # timeout?
+       chi     %r7,EXT_IRQ_CLK_COMP            # timeout?
        je      .LtimeoutS1
-       chi     %r7,0x2401                      # service int?
+       chi     %r7,EXT_IRQ_SERVICE_SIG         # service int?
        jne     .LloopS1
        sr      %r2,%r2
        l       %r3,LC_EXT_INT_PARAM
index 8827883..512ce1c 100644 (file)
@@ -236,6 +236,9 @@ static void pcpu_prepare_secondary(struct pcpu *pcpu, int cpu)
 {
        struct _lowcore *lc = pcpu->lowcore;
 
+       if (MACHINE_HAS_TLB_LC)
+               cpumask_set_cpu(cpu, &init_mm.context.cpu_attach_mask);
+       cpumask_set_cpu(cpu, mm_cpumask(&init_mm));
        atomic_inc(&init_mm.context.attach_count);
        lc->cpu_nr = cpu;
        lc->percpu_offset = __per_cpu_offset[cpu];
@@ -760,6 +763,9 @@ void __cpu_die(unsigned int cpu)
                cpu_relax();
        pcpu_free_lowcore(pcpu);
        atomic_dec(&init_mm.context.attach_count);
+       cpumask_clear_cpu(cpu, mm_cpumask(&init_mm));
+       if (MACHINE_HAS_TLB_LC)
+               cpumask_clear_cpu(cpu, &init_mm.context.cpu_attach_mask);
 }
 
 void __noreturn cpu_die(void)
@@ -785,10 +791,10 @@ void __init smp_fill_possible_mask(void)
 void __init smp_prepare_cpus(unsigned int max_cpus)
 {
        /* request the 0x1201 emergency signal external interrupt */
-       if (register_external_interrupt(0x1201, do_ext_call_interrupt) != 0)
+       if (register_external_irq(EXT_IRQ_EMERGENCY_SIG, do_ext_call_interrupt))
                panic("Couldn't request external interrupt 0x1201");
        /* request the 0x1202 external call external interrupt */
-       if (register_external_interrupt(0x1202, do_ext_call_interrupt) != 0)
+       if (register_external_irq(EXT_IRQ_EXTERNAL_CALL, do_ext_call_interrupt))
                panic("Couldn't request external interrupt 0x1202");
        smp_detect_cpus();
 }
@@ -1057,19 +1063,24 @@ static DEVICE_ATTR(rescan, 0200, NULL, rescan_store);
 
 static int __init s390_smp_init(void)
 {
-       int cpu, rc;
+       int cpu, rc = 0;
 
-       hotcpu_notifier(smp_cpu_notify, 0);
 #ifdef CONFIG_HOTPLUG_CPU
        rc = device_create_file(cpu_subsys.dev_root, &dev_attr_rescan);
        if (rc)
                return rc;
 #endif
+       cpu_notifier_register_begin();
        for_each_present_cpu(cpu) {
                rc = smp_add_present_cpu(cpu);
                if (rc)
-                       return rc;
+                       goto out;
        }
-       return 0;
+
+       __hotcpu_notifier(smp_cpu_notify, 0);
+
+out:
+       cpu_notifier_register_done();
+       return rc;
 }
 subsys_initcall(s390_smp_init);
index dd95f16..386d37a 100644 (file)
@@ -262,11 +262,11 @@ void __init time_init(void)
        stp_reset();
 
        /* request the clock comparator external interrupt */
-       if (register_external_interrupt(0x1004, clock_comparator_interrupt))
-                panic("Couldn't request external interrupt 0x1004");
+       if (register_external_irq(EXT_IRQ_CLK_COMP, clock_comparator_interrupt))
+               panic("Couldn't request external interrupt 0x1004");
 
        /* request the timing alert external interrupt */
-       if (register_external_interrupt(0x1406, timing_alert_interrupt))
+       if (register_external_irq(EXT_IRQ_TIMING_ALERT, timing_alert_interrupt))
                panic("Couldn't request external interrupt 0x1406");
 
        if (clocksource_register(&clocksource_tod) != 0)
index 03a05ff..08dfc83 100644 (file)
@@ -167,6 +167,10 @@ static int __diag_ipl_functions(struct kvm_vcpu *vcpu)
 
        VCPU_EVENT(vcpu, 5, "diag ipl functions, subcode %lx", subcode);
        switch (subcode) {
+       case 0:
+       case 1:
+               page_table_reset_pgste(current->mm, 0, TASK_SIZE);
+               return -EOPNOTSUPP;
        case 3:
                vcpu->run->s390_reset_flags = KVM_S390_RESET_CLEAR;
                page_table_reset_pgste(current->mm, 0, TASK_SIZE);
index e3fffe1..c6d752e 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for s390-specific library files..
 #
 
-lib-y += delay.o string.o uaccess_pt.o uaccess_mvcos.o find.o
+lib-y += delay.o string.o uaccess.o find.o
 obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o
 obj-$(CONFIG_64BIT) += mem64.o
 lib-$(CONFIG_SMP) += spinlock.o
diff --git a/arch/s390/lib/uaccess.c b/arch/s390/lib/uaccess.c
new file mode 100644 (file)
index 0000000..23f866b
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ *  Standard user space access functions based on mvcp/mvcs and doing
+ *  interesting things in the secondary space mode.
+ *
+ *    Copyright IBM Corp. 2006,2014
+ *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
+ *              Gerald Schaefer (gerald.schaefer@de.ibm.com)
+ */
+
+#include <linux/jump_label.h>
+#include <linux/uaccess.h>
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/mm.h>
+#include <asm/mmu_context.h>
+#include <asm/facility.h>
+
+#ifndef CONFIG_64BIT
+#define AHI    "ahi"
+#define ALR    "alr"
+#define CLR    "clr"
+#define LHI    "lhi"
+#define SLR    "slr"
+#else
+#define AHI    "aghi"
+#define ALR    "algr"
+#define CLR    "clgr"
+#define LHI    "lghi"
+#define SLR    "slgr"
+#endif
+
+static struct static_key have_mvcos = STATIC_KEY_INIT_FALSE;
+
+static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr,
+                                                unsigned long size)
+{
+       register unsigned long reg0 asm("0") = 0x81UL;
+       unsigned long tmp1, tmp2;
+
+       tmp1 = -4096UL;
+       asm volatile(
+               "0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n"
+               "9: jz    7f\n"
+               "1:"ALR"  %0,%3\n"
+               "  "SLR"  %1,%3\n"
+               "  "SLR"  %2,%3\n"
+               "   j     0b\n"
+               "2: la    %4,4095(%1)\n"/* %4 = ptr + 4095 */
+               "   nr    %4,%3\n"      /* %4 = (ptr + 4095) & -4096 */
+               "  "SLR"  %4,%1\n"
+               "  "CLR"  %0,%4\n"      /* copy crosses next page boundary? */
+               "   jnh   4f\n"
+               "3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n"
+               "10:"SLR"  %0,%4\n"
+               "  "ALR"  %2,%4\n"
+               "4:"LHI"  %4,-1\n"
+               "  "ALR"  %4,%0\n"      /* copy remaining size, subtract 1 */
+               "   bras  %3,6f\n"      /* memset loop */
+               "   xc    0(1,%2),0(%2)\n"
+               "5: xc    0(256,%2),0(%2)\n"
+               "   la    %2,256(%2)\n"
+               "6:"AHI"  %4,-256\n"
+               "   jnm   5b\n"
+               "   ex    %4,0(%3)\n"
+               "   j     8f\n"
+               "7:"SLR"  %0,%0\n"
+               "8:\n"
+               EX_TABLE(0b,2b) EX_TABLE(3b,4b) EX_TABLE(9b,2b) EX_TABLE(10b,4b)
+               : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
+               : "d" (reg0) : "cc", "memory");
+       return size;
+}
+
+static inline unsigned long copy_from_user_mvcp(void *x, const void __user *ptr,
+                                               unsigned long size)
+{
+       unsigned long tmp1, tmp2;
+
+       update_primary_asce(current);
+       tmp1 = -256UL;
+       asm volatile(
+               "   sacf  0\n"
+               "0: mvcp  0(%0,%2),0(%1),%3\n"
+               "10:jz    8f\n"
+               "1:"ALR"  %0,%3\n"
+               "   la    %1,256(%1)\n"
+               "   la    %2,256(%2)\n"
+               "2: mvcp  0(%0,%2),0(%1),%3\n"
+               "11:jnz   1b\n"
+               "   j     8f\n"
+               "3: la    %4,255(%1)\n" /* %4 = ptr + 255 */
+               "  "LHI"  %3,-4096\n"
+               "   nr    %4,%3\n"      /* %4 = (ptr + 255) & -4096 */
+               "  "SLR"  %4,%1\n"
+               "  "CLR"  %0,%4\n"      /* copy crosses next page boundary? */
+               "   jnh   5f\n"
+               "4: mvcp  0(%4,%2),0(%1),%3\n"
+               "12:"SLR"  %0,%4\n"
+               "  "ALR"  %2,%4\n"
+               "5:"LHI"  %4,-1\n"
+               "  "ALR"  %4,%0\n"      /* copy remaining size, subtract 1 */
+               "   bras  %3,7f\n"      /* memset loop */
+               "   xc    0(1,%2),0(%2)\n"
+               "6: xc    0(256,%2),0(%2)\n"
+               "   la    %2,256(%2)\n"
+               "7:"AHI"  %4,-256\n"
+               "   jnm   6b\n"
+               "   ex    %4,0(%3)\n"
+               "   j     9f\n"
+               "8:"SLR"  %0,%0\n"
+               "9: sacf  768\n"
+               EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,5b)
+               EX_TABLE(10b,3b) EX_TABLE(11b,3b) EX_TABLE(12b,5b)
+               : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
+               : : "cc", "memory");
+       return size;
+}
+
+unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
+{
+       if (static_key_false(&have_mvcos))
+               return copy_from_user_mvcos(to, from, n);
+       return copy_from_user_mvcp(to, from, n);
+}
+EXPORT_SYMBOL(__copy_from_user);
+
+static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x,
+                                              unsigned long size)
+{
+       register unsigned long reg0 asm("0") = 0x810000UL;
+       unsigned long tmp1, tmp2;
+
+       tmp1 = -4096UL;
+       asm volatile(
+               "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
+               "6: jz    4f\n"
+               "1:"ALR"  %0,%3\n"
+               "  "SLR"  %1,%3\n"
+               "  "SLR"  %2,%3\n"
+               "   j     0b\n"
+               "2: la    %4,4095(%1)\n"/* %4 = ptr + 4095 */
+               "   nr    %4,%3\n"      /* %4 = (ptr + 4095) & -4096 */
+               "  "SLR"  %4,%1\n"
+               "  "CLR"  %0,%4\n"      /* copy crosses next page boundary? */
+               "   jnh   5f\n"
+               "3: .insn ss,0xc80000000000,0(%4,%1),0(%2),0\n"
+               "7:"SLR"  %0,%4\n"
+               "   j     5f\n"
+               "4:"SLR"  %0,%0\n"
+               "5:\n"
+               EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b)
+               : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
+               : "d" (reg0) : "cc", "memory");
+       return size;
+}
+
+static inline unsigned long copy_to_user_mvcs(void __user *ptr, const void *x,
+                                             unsigned long size)
+{
+       unsigned long tmp1, tmp2;
+
+       update_primary_asce(current);
+       tmp1 = -256UL;
+       asm volatile(
+               "   sacf  0\n"
+               "0: mvcs  0(%0,%1),0(%2),%3\n"
+               "7: jz    5f\n"
+               "1:"ALR"  %0,%3\n"
+               "   la    %1,256(%1)\n"
+               "   la    %2,256(%2)\n"
+               "2: mvcs  0(%0,%1),0(%2),%3\n"
+               "8: jnz   1b\n"
+               "   j     5f\n"
+               "3: la    %4,255(%1)\n" /* %4 = ptr + 255 */
+               "  "LHI"  %3,-4096\n"
+               "   nr    %4,%3\n"      /* %4 = (ptr + 255) & -4096 */
+               "  "SLR"  %4,%1\n"
+               "  "CLR"  %0,%4\n"      /* copy crosses next page boundary? */
+               "   jnh   6f\n"
+               "4: mvcs  0(%4,%1),0(%2),%3\n"
+               "9:"SLR"  %0,%4\n"
+               "   j     6f\n"
+               "5:"SLR"  %0,%0\n"
+               "6: sacf  768\n"
+               EX_TABLE(0b,3b) EX_TABLE(2b,3b) EX_TABLE(4b,6b)
+               EX_TABLE(7b,3b) EX_TABLE(8b,3b) EX_TABLE(9b,6b)
+               : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
+               : : "cc", "memory");
+       return size;
+}
+
+unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
+{
+       if (static_key_false(&have_mvcos))
+               return copy_to_user_mvcos(to, from, n);
+       return copy_to_user_mvcs(to, from, n);
+}
+EXPORT_SYMBOL(__copy_to_user);
+
+static inline unsigned long copy_in_user_mvcos(void __user *to, const void __user *from,
+                                              unsigned long size)
+{
+       register unsigned long reg0 asm("0") = 0x810081UL;
+       unsigned long tmp1, tmp2;
+
+       tmp1 = -4096UL;
+       /* FIXME: copy with reduced length. */
+       asm volatile(
+               "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
+               "   jz    2f\n"
+               "1:"ALR"  %0,%3\n"
+               "  "SLR"  %1,%3\n"
+               "  "SLR"  %2,%3\n"
+               "   j     0b\n"
+               "2:"SLR"  %0,%0\n"
+               "3: \n"
+               EX_TABLE(0b,3b)
+               : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2)
+               : "d" (reg0) : "cc", "memory");
+       return size;
+}
+
+static inline unsigned long copy_in_user_mvc(void __user *to, const void __user *from,
+                                            unsigned long size)
+{
+       unsigned long tmp1;
+
+       update_primary_asce(current);
+       asm volatile(
+               "   sacf  256\n"
+               "  "AHI"  %0,-1\n"
+               "   jo    5f\n"
+               "   bras  %3,3f\n"
+               "0:"AHI"  %0,257\n"
+               "1: mvc   0(1,%1),0(%2)\n"
+               "   la    %1,1(%1)\n"
+               "   la    %2,1(%2)\n"
+               "  "AHI"  %0,-1\n"
+               "   jnz   1b\n"
+               "   j     5f\n"
+               "2: mvc   0(256,%1),0(%2)\n"
+               "   la    %1,256(%1)\n"
+               "   la    %2,256(%2)\n"
+               "3:"AHI"  %0,-256\n"
+               "   jnm   2b\n"
+               "4: ex    %0,1b-0b(%3)\n"
+               "5: "SLR"  %0,%0\n"
+               "6: sacf  768\n"
+               EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
+               : "+a" (size), "+a" (to), "+a" (from), "=a" (tmp1)
+               : : "cc", "memory");
+       return size;
+}
+
+unsigned long __copy_in_user(void __user *to, const void __user *from, unsigned long n)
+{
+       if (static_key_false(&have_mvcos))
+               return copy_in_user_mvcos(to, from, n);
+       return copy_in_user_mvc(to, from, n);
+}
+EXPORT_SYMBOL(__copy_in_user);
+
+static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size)
+{
+       register unsigned long reg0 asm("0") = 0x810000UL;
+       unsigned long tmp1, tmp2;
+
+       tmp1 = -4096UL;
+       asm volatile(
+               "0: .insn ss,0xc80000000000,0(%0,%1),0(%4),0\n"
+               "   jz    4f\n"
+               "1:"ALR"  %0,%2\n"
+               "  "SLR"  %1,%2\n"
+               "   j     0b\n"
+               "2: la    %3,4095(%1)\n"/* %4 = to + 4095 */
+               "   nr    %3,%2\n"      /* %4 = (to + 4095) & -4096 */
+               "  "SLR"  %3,%1\n"
+               "  "CLR"  %0,%3\n"      /* copy crosses next page boundary? */
+               "   jnh   5f\n"
+               "3: .insn ss,0xc80000000000,0(%3,%1),0(%4),0\n"
+               "  "SLR"  %0,%3\n"
+               "   j     5f\n"
+               "4:"SLR"  %0,%0\n"
+               "5:\n"
+               EX_TABLE(0b,2b) EX_TABLE(3b,5b)
+               : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
+               : "a" (empty_zero_page), "d" (reg0) : "cc", "memory");
+       return size;
+}
+
+static inline unsigned long clear_user_xc(void __user *to, unsigned long size)
+{
+       unsigned long tmp1, tmp2;
+
+       update_primary_asce(current);
+       asm volatile(
+               "   sacf  256\n"
+               "  "AHI"  %0,-1\n"
+               "   jo    5f\n"
+               "   bras  %3,3f\n"
+               "   xc    0(1,%1),0(%1)\n"
+               "0:"AHI"  %0,257\n"
+               "   la    %2,255(%1)\n" /* %2 = ptr + 255 */
+               "   srl   %2,12\n"
+               "   sll   %2,12\n"      /* %2 = (ptr + 255) & -4096 */
+               "  "SLR"  %2,%1\n"
+               "  "CLR"  %0,%2\n"      /* clear crosses next page boundary? */
+               "   jnh   5f\n"
+               "  "AHI"  %2,-1\n"
+               "1: ex    %2,0(%3)\n"
+               "  "AHI"  %2,1\n"
+               "  "SLR"  %0,%2\n"
+               "   j     5f\n"
+               "2: xc    0(256,%1),0(%1)\n"
+               "   la    %1,256(%1)\n"
+               "3:"AHI"  %0,-256\n"
+               "   jnm   2b\n"
+               "4: ex    %0,0(%3)\n"
+               "5: "SLR"  %0,%0\n"
+               "6: sacf  768\n"
+               EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
+               : "+a" (size), "+a" (to), "=a" (tmp1), "=a" (tmp2)
+               : : "cc", "memory");
+       return size;
+}
+
+unsigned long __clear_user(void __user *to, unsigned long size)
+{
+       if (static_key_false(&have_mvcos))
+                       return clear_user_mvcos(to, size);
+       return clear_user_xc(to, size);
+}
+EXPORT_SYMBOL(__clear_user);
+
+static inline unsigned long strnlen_user_srst(const char __user *src,
+                                             unsigned long size)
+{
+       register unsigned long reg0 asm("0") = 0;
+       unsigned long tmp1, tmp2;
+
+       if (unlikely(!size))
+               return 0;
+       update_primary_asce(current);
+       asm volatile(
+               "   la    %2,0(%1)\n"
+               "   la    %3,0(%0,%1)\n"
+               "  "SLR"  %0,%0\n"
+               "   sacf  256\n"
+               "0: srst  %3,%2\n"
+               "   jo    0b\n"
+               "   la    %0,1(%3)\n"   /* strnlen_user results includes \0 */
+               "  "SLR"  %0,%1\n"
+               "1: sacf  768\n"
+               EX_TABLE(0b,1b)
+               : "+a" (size), "+a" (src), "=a" (tmp1), "=a" (tmp2)
+               : "d" (reg0) : "cc", "memory");
+       return size;
+}
+
+unsigned long __strnlen_user(const char __user *src, unsigned long size)
+{
+       update_primary_asce(current);
+       return strnlen_user_srst(src, size);
+}
+EXPORT_SYMBOL(__strnlen_user);
+
+long __strncpy_from_user(char *dst, const char __user *src, long size)
+{
+       size_t done, len, offset, len_str;
+
+       if (unlikely(size <= 0))
+               return 0;
+       done = 0;
+       do {
+               offset = (size_t)src & ~PAGE_MASK;
+               len = min(size - done, PAGE_SIZE - offset);
+               if (copy_from_user(dst, src, len))
+                       return -EFAULT;
+               len_str = strnlen(dst, len);
+               done += len_str;
+               src += len_str;
+               dst += len_str;
+       } while ((len_str == len) && (done < size));
+       return done;
+}
+EXPORT_SYMBOL(__strncpy_from_user);
+
+/*
+ * The "old" uaccess variant without mvcos can be enforced with the
+ * uaccess_primary kernel parameter. This is mainly for debugging purposes.
+ */
+static int uaccess_primary __initdata;
+
+static int __init parse_uaccess_pt(char *__unused)
+{
+       uaccess_primary = 1;
+       return 0;
+}
+early_param("uaccess_primary", parse_uaccess_pt);
+
+static int __init uaccess_init(void)
+{
+       if (IS_ENABLED(CONFIG_64BIT) && !uaccess_primary && test_facility(27))
+               static_key_slow_inc(&have_mvcos);
+       return 0;
+}
+early_initcall(uaccess_init);
diff --git a/arch/s390/lib/uaccess.h b/arch/s390/lib/uaccess.h
deleted file mode 100644 (file)
index c7e0e81..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- *    Copyright IBM Corp. 2007
- *
- */
-
-#ifndef __ARCH_S390_LIB_UACCESS_H
-#define __ARCH_S390_LIB_UACCESS_H
-
-unsigned long copy_from_user_pt(void *to, const void __user *from, unsigned long n);
-unsigned long copy_to_user_pt(void __user *to, const void *from, unsigned long n);
-unsigned long copy_in_user_pt(void __user *to, const void __user *from, unsigned long n);
-unsigned long clear_user_pt(void __user *to, unsigned long n);
-unsigned long strnlen_user_pt(const char __user *src, unsigned long count);
-long strncpy_from_user_pt(char *dst, const char __user *src, long count);
-
-#endif /* __ARCH_S390_LIB_UACCESS_H */
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c
deleted file mode 100644 (file)
index ae97b8d..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- *  Optimized user space space access functions based on mvcos.
- *
- *    Copyright IBM Corp. 2006
- *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
- *              Gerald Schaefer (gerald.schaefer@de.ibm.com)
- */
-
-#include <linux/jump_label.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <asm/facility.h>
-#include <asm/uaccess.h>
-#include <asm/futex.h>
-#include "uaccess.h"
-
-#ifndef CONFIG_64BIT
-#define AHI    "ahi"
-#define ALR    "alr"
-#define CLR    "clr"
-#define LHI    "lhi"
-#define SLR    "slr"
-#else
-#define AHI    "aghi"
-#define ALR    "algr"
-#define CLR    "clgr"
-#define LHI    "lghi"
-#define SLR    "slgr"
-#endif
-
-static struct static_key have_mvcos = STATIC_KEY_INIT_TRUE;
-
-static inline unsigned long copy_from_user_mvcos(void *x, const void __user *ptr,
-                                                unsigned long size)
-{
-       register unsigned long reg0 asm("0") = 0x81UL;
-       unsigned long tmp1, tmp2;
-
-       tmp1 = -4096UL;
-       asm volatile(
-               "0: .insn ss,0xc80000000000,0(%0,%2),0(%1),0\n"
-               "9: jz    7f\n"
-               "1:"ALR"  %0,%3\n"
-               "  "SLR"  %1,%3\n"
-               "  "SLR"  %2,%3\n"
-               "   j     0b\n"
-               "2: la    %4,4095(%1)\n"/* %4 = ptr + 4095 */
-               "   nr    %4,%3\n"      /* %4 = (ptr + 4095) & -4096 */
-               "  "SLR"  %4,%1\n"
-               "  "CLR"  %0,%4\n"      /* copy crosses next page boundary? */
-               "   jnh   4f\n"
-               "3: .insn ss,0xc80000000000,0(%4,%2),0(%1),0\n"
-               "10:"SLR"  %0,%4\n"
-               "  "ALR"  %2,%4\n"
-               "4:"LHI"  %4,-1\n"
-               "  "ALR"  %4,%0\n"      /* copy remaining size, subtract 1 */
-               "   bras  %3,6f\n"      /* memset loop */
-               "   xc    0(1,%2),0(%2)\n"
-               "5: xc    0(256,%2),0(%2)\n"
-               "   la    %2,256(%2)\n"
-               "6:"AHI"  %4,-256\n"
-               "   jnm   5b\n"
-               "   ex    %4,0(%3)\n"
-               "   j     8f\n"
-               "7:"SLR"  %0,%0\n"
-               "8: \n"
-               EX_TABLE(0b,2b) EX_TABLE(3b,4b) EX_TABLE(9b,2b) EX_TABLE(10b,4b)
-               : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
-               : "d" (reg0) : "cc", "memory");
-       return size;
-}
-
-unsigned long __copy_from_user(void *to, const void __user *from, unsigned long n)
-{
-       if (static_key_true(&have_mvcos))
-               return copy_from_user_mvcos(to, from, n);
-       return copy_from_user_pt(to, from, n);
-}
-EXPORT_SYMBOL(__copy_from_user);
-
-static inline unsigned long copy_to_user_mvcos(void __user *ptr, const void *x,
-                                              unsigned long size)
-{
-       register unsigned long reg0 asm("0") = 0x810000UL;
-       unsigned long tmp1, tmp2;
-
-       tmp1 = -4096UL;
-       asm volatile(
-               "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
-               "6: jz    4f\n"
-               "1:"ALR"  %0,%3\n"
-               "  "SLR"  %1,%3\n"
-               "  "SLR"  %2,%3\n"
-               "   j     0b\n"
-               "2: la    %4,4095(%1)\n"/* %4 = ptr + 4095 */
-               "   nr    %4,%3\n"      /* %4 = (ptr + 4095) & -4096 */
-               "  "SLR"  %4,%1\n"
-               "  "CLR"  %0,%4\n"      /* copy crosses next page boundary? */
-               "   jnh   5f\n"
-               "3: .insn ss,0xc80000000000,0(%4,%1),0(%2),0\n"
-               "7:"SLR"  %0,%4\n"
-               "   j     5f\n"
-               "4:"SLR"  %0,%0\n"
-               "5: \n"
-               EX_TABLE(0b,2b) EX_TABLE(3b,5b) EX_TABLE(6b,2b) EX_TABLE(7b,5b)
-               : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2)
-               : "d" (reg0) : "cc", "memory");
-       return size;
-}
-
-unsigned long __copy_to_user(void __user *to, const void *from, unsigned long n)
-{
-       if (static_key_true(&have_mvcos))
-               return copy_to_user_mvcos(to, from, n);
-       return copy_to_user_pt(to, from, n);
-}
-EXPORT_SYMBOL(__copy_to_user);
-
-static inline unsigned long copy_in_user_mvcos(void __user *to, const void __user *from,
-                                              unsigned long size)
-{
-       register unsigned long reg0 asm("0") = 0x810081UL;
-       unsigned long tmp1, tmp2;
-
-       tmp1 = -4096UL;
-       /* FIXME: copy with reduced length. */
-       asm volatile(
-               "0: .insn ss,0xc80000000000,0(%0,%1),0(%2),0\n"
-               "   jz    2f\n"
-               "1:"ALR"  %0,%3\n"
-               "  "SLR"  %1,%3\n"
-               "  "SLR"  %2,%3\n"
-               "   j     0b\n"
-               "2:"SLR"  %0,%0\n"
-               "3: \n"
-               EX_TABLE(0b,3b)
-               : "+a" (size), "+a" (to), "+a" (from), "+a" (tmp1), "=a" (tmp2)
-               : "d" (reg0) : "cc", "memory");
-       return size;
-}
-
-unsigned long __copy_in_user(void __user *to, const void __user *from, unsigned long n)
-{
-       if (static_key_true(&have_mvcos))
-               return copy_in_user_mvcos(to, from, n);
-       return copy_in_user_pt(to, from, n);
-}
-EXPORT_SYMBOL(__copy_in_user);
-
-static inline unsigned long clear_user_mvcos(void __user *to, unsigned long size)
-{
-       register unsigned long reg0 asm("0") = 0x810000UL;
-       unsigned long tmp1, tmp2;
-
-       tmp1 = -4096UL;
-       asm volatile(
-               "0: .insn ss,0xc80000000000,0(%0,%1),0(%4),0\n"
-               "   jz    4f\n"
-               "1:"ALR"  %0,%2\n"
-               "  "SLR"  %1,%2\n"
-               "   j     0b\n"
-               "2: la    %3,4095(%1)\n"/* %4 = to + 4095 */
-               "   nr    %3,%2\n"      /* %4 = (to + 4095) & -4096 */
-               "  "SLR"  %3,%1\n"
-               "  "CLR"  %0,%3\n"      /* copy crosses next page boundary? */
-               "   jnh   5f\n"
-               "3: .insn ss,0xc80000000000,0(%3,%1),0(%4),0\n"
-               "  "SLR"  %0,%3\n"
-               "   j     5f\n"
-               "4:"SLR"  %0,%0\n"
-               "5: \n"
-               EX_TABLE(0b,2b) EX_TABLE(3b,5b)
-               : "+a" (size), "+a" (to), "+a" (tmp1), "=a" (tmp2)
-               : "a" (empty_zero_page), "d" (reg0) : "cc", "memory");
-       return size;
-}
-
-unsigned long __clear_user(void __user *to, unsigned long size)
-{
-       if (static_key_true(&have_mvcos))
-               return clear_user_mvcos(to, size);
-       return clear_user_pt(to, size);
-}
-EXPORT_SYMBOL(__clear_user);
-
-static inline unsigned long strnlen_user_mvcos(const char __user *src,
-                                              unsigned long count)
-{
-       unsigned long done, len, offset, len_str;
-       char buf[256];
-
-       done = 0;
-       do {
-               offset = (unsigned long)src & ~PAGE_MASK;
-               len = min(256UL, PAGE_SIZE - offset);
-               len = min(count - done, len);
-               if (copy_from_user_mvcos(buf, src, len))
-                       return 0;
-               len_str = strnlen(buf, len);
-               done += len_str;
-               src += len_str;
-       } while ((len_str == len) && (done < count));
-       return done + 1;
-}
-
-unsigned long __strnlen_user(const char __user *src, unsigned long count)
-{
-       if (static_key_true(&have_mvcos))
-               return strnlen_user_mvcos(src, count);
-       return strnlen_user_pt(src, count);
-}
-EXPORT_SYMBOL(__strnlen_user);
-
-static inline long strncpy_from_user_mvcos(char *dst, const char __user *src,
-                                          long count)
-{
-       unsigned long done, len, offset, len_str;
-
-       if (unlikely(count <= 0))
-               return 0;
-       done = 0;
-       do {
-               offset = (unsigned long)src & ~PAGE_MASK;
-               len = min(count - done, PAGE_SIZE - offset);
-               if (copy_from_user_mvcos(dst, src, len))
-                       return -EFAULT;
-               len_str = strnlen(dst, len);
-               done += len_str;
-               src += len_str;
-               dst += len_str;
-       } while ((len_str == len) && (done < count));
-       return done;
-}
-
-long __strncpy_from_user(char *dst, const char __user *src, long count)
-{
-       if (static_key_true(&have_mvcos))
-               return strncpy_from_user_mvcos(dst, src, count);
-       return strncpy_from_user_pt(dst, src, count);
-}
-EXPORT_SYMBOL(__strncpy_from_user);
-
-/*
- * The uaccess page tabe walk variant can be enforced with the "uaccesspt"
- * kernel parameter. This is mainly for debugging purposes.
- */
-static int force_uaccess_pt __initdata;
-
-static int __init parse_uaccess_pt(char *__unused)
-{
-       force_uaccess_pt = 1;
-       return 0;
-}
-early_param("uaccesspt", parse_uaccess_pt);
-
-static int __init uaccess_init(void)
-{
-       if (IS_ENABLED(CONFIG_32BIT) || force_uaccess_pt || !test_facility(27))
-               static_key_slow_dec(&have_mvcos);
-       return 0;
-}
-early_initcall(uaccess_init);
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
deleted file mode 100644 (file)
index 8d39760..0000000
+++ /dev/null
@@ -1,471 +0,0 @@
-/*
- *  User access functions based on page table walks for enhanced
- *  system layout without hardware support.
- *
- *    Copyright IBM Corp. 2006, 2012
- *    Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com)
- */
-
-#include <linux/errno.h>
-#include <linux/hardirq.h>
-#include <linux/mm.h>
-#include <linux/hugetlb.h>
-#include <asm/uaccess.h>
-#include <asm/futex.h>
-#include "uaccess.h"
-
-#ifndef CONFIG_64BIT
-#define AHI    "ahi"
-#define SLR    "slr"
-#else
-#define AHI    "aghi"
-#define SLR    "slgr"
-#endif
-
-static unsigned long strnlen_kernel(const char __user *src, unsigned long count)
-{
-       register unsigned long reg0 asm("0") = 0UL;
-       unsigned long tmp1, tmp2;
-
-       asm volatile(
-               "   la    %2,0(%1)\n"
-               "   la    %3,0(%0,%1)\n"
-               "  "SLR"  %0,%0\n"
-               "0: srst  %3,%2\n"
-               "   jo    0b\n"
-               "   la    %0,1(%3)\n"   /* strnlen_kernel results includes \0 */
-               "  "SLR"  %0,%1\n"
-               "1:\n"
-               EX_TABLE(0b,1b)
-               : "+a" (count), "+a" (src), "=a" (tmp1), "=a" (tmp2)
-               : "d" (reg0) : "cc", "memory");
-       return count;
-}
-
-static unsigned long copy_in_kernel(void __user *to, const void __user *from,
-                                   unsigned long count)
-{
-       unsigned long tmp1;
-
-       asm volatile(
-               "  "AHI"  %0,-1\n"
-               "   jo    5f\n"
-               "   bras  %3,3f\n"
-               "0:"AHI"  %0,257\n"
-               "1: mvc   0(1,%1),0(%2)\n"
-               "   la    %1,1(%1)\n"
-               "   la    %2,1(%2)\n"
-               "  "AHI"  %0,-1\n"
-               "   jnz   1b\n"
-               "   j     5f\n"
-               "2: mvc   0(256,%1),0(%2)\n"
-               "   la    %1,256(%1)\n"
-               "   la    %2,256(%2)\n"
-               "3:"AHI"  %0,-256\n"
-               "   jnm   2b\n"
-               "4: ex    %0,1b-0b(%3)\n"
-               "5:"SLR"  %0,%0\n"
-               "6:\n"
-               EX_TABLE(1b,6b) EX_TABLE(2b,0b) EX_TABLE(4b,0b)
-               : "+a" (count), "+a" (to), "+a" (from), "=a" (tmp1)
-               : : "cc", "memory");
-       return count;
-}
-
-/*
- * Returns kernel address for user virtual address. If the returned address is
- * >= -4095 (IS_ERR_VALUE(x) returns true), a fault has occurred and the
- * address contains the (negative) exception code.
- */
-#ifdef CONFIG_64BIT
-
-static unsigned long follow_table(struct mm_struct *mm,
-                                 unsigned long address, int write)
-{
-       unsigned long *table = (unsigned long *)__pa(mm->pgd);
-
-       if (unlikely(address > mm->context.asce_limit - 1))
-               return -0x38UL;
-       switch (mm->context.asce_bits & _ASCE_TYPE_MASK) {
-       case _ASCE_TYPE_REGION1:
-               table = table + ((address >> 53) & 0x7ff);
-               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_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_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_INVALID))
-                       return -0x10UL;
-               if (unlikely(*table & _SEGMENT_ENTRY_LARGE)) {
-                       if (write && (*table & _SEGMENT_ENTRY_PROTECT))
-                               return -0x04UL;
-                       return (*table & _SEGMENT_ENTRY_ORIGIN_LARGE) +
-                               (address & ~_SEGMENT_ENTRY_ORIGIN_LARGE);
-               }
-               table = (unsigned long *)(*table & _SEGMENT_ENTRY_ORIGIN);
-       }
-       table = table + ((address >> 12) & 0xff);
-       if (unlikely(*table & _PAGE_INVALID))
-               return -0x11UL;
-       if (write && (*table & _PAGE_PROTECT))
-               return -0x04UL;
-       return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
-}
-
-#else /* CONFIG_64BIT */
-
-static unsigned long follow_table(struct mm_struct *mm,
-                                 unsigned long address, int write)
-{
-       unsigned long *table = (unsigned long *)__pa(mm->pgd);
-
-       table = table + ((address >> 20) & 0x7ff);
-       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_PROTECT))
-               return -0x04UL;
-       return (*table & PAGE_MASK) + (address & ~PAGE_MASK);
-}
-
-#endif /* CONFIG_64BIT */
-
-static inline unsigned long __user_copy_pt(unsigned long uaddr, void *kptr,
-                                          unsigned long n, int write_user)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long offset, done, size, kaddr;
-       void *from, *to;
-
-       if (!mm)
-               return n;
-       done = 0;
-retry:
-       spin_lock(&mm->page_table_lock);
-       do {
-               kaddr = follow_table(mm, uaddr, write_user);
-               if (IS_ERR_VALUE(kaddr))
-                       goto fault;
-
-               offset = uaddr & ~PAGE_MASK;
-               size = min(n - done, PAGE_SIZE - offset);
-               if (write_user) {
-                       to = (void *) kaddr;
-                       from = kptr + done;
-               } else {
-                       from = (void *) kaddr;
-                       to = kptr + done;
-               }
-               memcpy(to, from, size);
-               done += size;
-               uaddr += size;
-       } while (done < n);
-       spin_unlock(&mm->page_table_lock);
-       return n - done;
-fault:
-       spin_unlock(&mm->page_table_lock);
-       if (__handle_fault(uaddr, -kaddr, write_user))
-               return n - done;
-       goto retry;
-}
-
-/*
- * Do DAT for user address by page table walk, return kernel address.
- * This function needs to be called with current->mm->page_table_lock held.
- */
-static inline unsigned long __dat_user_addr(unsigned long uaddr, int write)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long kaddr;
-       int rc;
-
-retry:
-       kaddr = follow_table(mm, uaddr, write);
-       if (IS_ERR_VALUE(kaddr))
-               goto fault;
-
-       return kaddr;
-fault:
-       spin_unlock(&mm->page_table_lock);
-       rc = __handle_fault(uaddr, -kaddr, write);
-       spin_lock(&mm->page_table_lock);
-       if (!rc)
-               goto retry;
-       return 0;
-}
-
-unsigned long copy_from_user_pt(void *to, const void __user *from, unsigned long n)
-{
-       unsigned long rc;
-
-       if (segment_eq(get_fs(), KERNEL_DS))
-               return copy_in_kernel((void __user *) to, from, n);
-       rc = __user_copy_pt((unsigned long) from, to, n, 0);
-       if (unlikely(rc))
-               memset(to + n - rc, 0, rc);
-       return rc;
-}
-
-unsigned long copy_to_user_pt(void __user *to, const void *from, unsigned long n)
-{
-       if (segment_eq(get_fs(), KERNEL_DS))
-               return copy_in_kernel(to, (void __user *) from, n);
-       return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
-}
-
-unsigned long clear_user_pt(void __user *to, unsigned long n)
-{
-       void *zpage = (void *) empty_zero_page;
-       unsigned long done, size, ret;
-
-       done = 0;
-       do {
-               if (n - done > PAGE_SIZE)
-                       size = PAGE_SIZE;
-               else
-                       size = n - done;
-               if (segment_eq(get_fs(), KERNEL_DS))
-                       ret = copy_in_kernel(to, (void __user *) zpage, n);
-               else
-                       ret = __user_copy_pt((unsigned long) to, zpage, size, 1);
-               done += size;
-               to += size;
-               if (ret)
-                       return ret + n - done;
-       } while (done < n);
-       return 0;
-}
-
-unsigned long strnlen_user_pt(const char __user *src, unsigned long count)
-{
-       unsigned long uaddr = (unsigned long) src;
-       struct mm_struct *mm = current->mm;
-       unsigned long offset, done, len, kaddr;
-       unsigned long len_str;
-
-       if (unlikely(!count))
-               return 0;
-       if (segment_eq(get_fs(), KERNEL_DS))
-               return strnlen_kernel(src, count);
-       if (!mm)
-               return 0;
-       done = 0;
-retry:
-       spin_lock(&mm->page_table_lock);
-       do {
-               kaddr = follow_table(mm, uaddr, 0);
-               if (IS_ERR_VALUE(kaddr))
-                       goto fault;
-
-               offset = uaddr & ~PAGE_MASK;
-               len = min(count - done, PAGE_SIZE - offset);
-               len_str = strnlen((char *) kaddr, len);
-               done += len_str;
-               uaddr += len_str;
-       } while ((len_str == len) && (done < count));
-       spin_unlock(&mm->page_table_lock);
-       return done + 1;
-fault:
-       spin_unlock(&mm->page_table_lock);
-       if (__handle_fault(uaddr, -kaddr, 0))
-               return 0;
-       goto retry;
-}
-
-long strncpy_from_user_pt(char *dst, const char __user *src, long count)
-{
-       unsigned long done, len, offset, len_str;
-
-       if (unlikely(count <= 0))
-               return 0;
-       done = 0;
-       do {
-               offset = (unsigned long)src & ~PAGE_MASK;
-               len = min(count - done, PAGE_SIZE - offset);
-               if (segment_eq(get_fs(), KERNEL_DS)) {
-                       if (copy_in_kernel((void __user *) dst, src, len))
-                               return -EFAULT;
-               } else {
-                       if (__user_copy_pt((unsigned long) src, dst, len, 0))
-                               return -EFAULT;
-               }
-               len_str = strnlen(dst, len);
-               done += len_str;
-               src += len_str;
-               dst += len_str;
-       } while ((len_str == len) && (done < count));
-       return done;
-}
-
-unsigned long copy_in_user_pt(void __user *to, const void __user *from,
-                             unsigned long n)
-{
-       struct mm_struct *mm = current->mm;
-       unsigned long offset_max, uaddr, done, size, error_code;
-       unsigned long uaddr_from = (unsigned long) from;
-       unsigned long uaddr_to = (unsigned long) to;
-       unsigned long kaddr_to, kaddr_from;
-       int write_user;
-
-       if (segment_eq(get_fs(), KERNEL_DS))
-               return copy_in_kernel(to, from, n);
-       if (!mm)
-               return n;
-       done = 0;
-retry:
-       spin_lock(&mm->page_table_lock);
-       do {
-               write_user = 0;
-               uaddr = uaddr_from;
-               kaddr_from = follow_table(mm, uaddr_from, 0);
-               error_code = kaddr_from;
-               if (IS_ERR_VALUE(error_code))
-                       goto fault;
-
-               write_user = 1;
-               uaddr = uaddr_to;
-               kaddr_to = follow_table(mm, uaddr_to, 1);
-               error_code = (unsigned long) kaddr_to;
-               if (IS_ERR_VALUE(error_code))
-                       goto fault;
-
-               offset_max = max(uaddr_from & ~PAGE_MASK,
-                                uaddr_to & ~PAGE_MASK);
-               size = min(n - done, PAGE_SIZE - offset_max);
-
-               memcpy((void *) kaddr_to, (void *) kaddr_from, size);
-               done += size;
-               uaddr_from += size;
-               uaddr_to += size;
-       } while (done < n);
-       spin_unlock(&mm->page_table_lock);
-       return n - done;
-fault:
-       spin_unlock(&mm->page_table_lock);
-       if (__handle_fault(uaddr, -error_code, write_user))
-               return n - done;
-       goto retry;
-}
-
-#define __futex_atomic_op(insn, ret, oldval, newval, uaddr, oparg)     \
-       asm volatile("0: l   %1,0(%6)\n"                                \
-                    "1: " insn                                         \
-                    "2: cs  %1,%2,0(%6)\n"                             \
-                    "3: jl  1b\n"                                      \
-                    "   lhi %0,0\n"                                    \
-                    "4:\n"                                             \
-                    EX_TABLE(0b,4b) EX_TABLE(2b,4b) EX_TABLE(3b,4b)    \
-                    : "=d" (ret), "=&d" (oldval), "=&d" (newval),      \
-                      "=m" (*uaddr)                                    \
-                    : "0" (-EFAULT), "d" (oparg), "a" (uaddr),         \
-                      "m" (*uaddr) : "cc" );
-
-static int __futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
-{
-       int oldval = 0, newval, ret;
-
-       switch (op) {
-       case FUTEX_OP_SET:
-               __futex_atomic_op("lr %2,%5\n",
-                                 ret, oldval, newval, uaddr, oparg);
-               break;
-       case FUTEX_OP_ADD:
-               __futex_atomic_op("lr %2,%1\nar %2,%5\n",
-                                 ret, oldval, newval, uaddr, oparg);
-               break;
-       case FUTEX_OP_OR:
-               __futex_atomic_op("lr %2,%1\nor %2,%5\n",
-                                 ret, oldval, newval, uaddr, oparg);
-               break;
-       case FUTEX_OP_ANDN:
-               __futex_atomic_op("lr %2,%1\nnr %2,%5\n",
-                                 ret, oldval, newval, uaddr, oparg);
-               break;
-       case FUTEX_OP_XOR:
-               __futex_atomic_op("lr %2,%1\nxr %2,%5\n",
-                                 ret, oldval, newval, uaddr, oparg);
-               break;
-       default:
-               ret = -ENOSYS;
-       }
-       if (ret == 0)
-               *old = oldval;
-       return ret;
-}
-
-int __futex_atomic_op_inuser(int op, u32 __user *uaddr, int oparg, int *old)
-{
-       int ret;
-
-       if (segment_eq(get_fs(), KERNEL_DS))
-               return __futex_atomic_op_pt(op, uaddr, oparg, old);
-       if (unlikely(!current->mm))
-               return -EFAULT;
-       spin_lock(&current->mm->page_table_lock);
-       uaddr = (u32 __force __user *)
-               __dat_user_addr((__force unsigned long) uaddr, 1);
-       if (!uaddr) {
-               spin_unlock(&current->mm->page_table_lock);
-               return -EFAULT;
-       }
-       get_page(virt_to_page(uaddr));
-       spin_unlock(&current->mm->page_table_lock);
-       ret = __futex_atomic_op_pt(op, uaddr, oparg, old);
-       put_page(virt_to_page(uaddr));
-       return ret;
-}
-
-static int __futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
-                                    u32 oldval, u32 newval)
-{
-       int ret;
-
-       asm volatile("0: cs   %1,%4,0(%5)\n"
-                    "1: la   %0,0\n"
-                    "2:\n"
-                    EX_TABLE(0b,2b) EX_TABLE(1b,2b)
-                    : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
-                    : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
-                    : "cc", "memory" );
-       *uval = oldval;
-       return ret;
-}
-
-int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
-                                 u32 oldval, u32 newval)
-{
-       int ret;
-
-       if (segment_eq(get_fs(), KERNEL_DS))
-               return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
-       if (unlikely(!current->mm))
-               return -EFAULT;
-       spin_lock(&current->mm->page_table_lock);
-       uaddr = (u32 __force __user *)
-               __dat_user_addr((__force unsigned long) uaddr, 1);
-       if (!uaddr) {
-               spin_unlock(&current->mm->page_table_lock);
-               return -EFAULT;
-       }
-       get_page(virt_to_page(uaddr));
-       spin_unlock(&current->mm->page_table_lock);
-       ret = __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
-       put_page(virt_to_page(uaddr));
-       return ret;
-}
index 88cef50..19f623f 100644 (file)
@@ -106,21 +106,24 @@ void bust_spinlocks(int yes)
  * Returns the address space associated with the fault.
  * Returns 0 for kernel space and 1 for user space.
  */
-static inline int user_space_fault(unsigned long trans_exc_code)
+static inline int user_space_fault(struct pt_regs *regs)
 {
+       unsigned long trans_exc_code;
+
        /*
         * The lowest two bits of the translation exception
         * identification indicate which paging table was used.
         */
-       trans_exc_code &= 3;
-       if (trans_exc_code == 2)
-               /* Access via secondary space, set_fs setting decides */
+       trans_exc_code = regs->int_parm_long & 3;
+       if (trans_exc_code == 3) /* home space -> kernel */
+               return 0;
+       if (user_mode(regs))
+               return 1;
+       if (trans_exc_code == 2) /* secondary space -> set_fs */
                return current->thread.mm_segment.ar4;
-       /*
-        * Access via primary space or access register is from user space
-        * and access via home space is from the kernel.
-        */
-       return trans_exc_code != 3;
+       if (current->flags & PF_VCPU)
+               return 1;
+       return 0;
 }
 
 static inline void report_user_fault(struct pt_regs *regs, long signr)
@@ -172,7 +175,7 @@ static noinline void do_no_context(struct pt_regs *regs)
         * terminate things with extreme prejudice.
         */
        address = regs->int_parm_long & __FAIL_ADDR_MASK;
-       if (!user_space_fault(regs->int_parm_long))
+       if (!user_space_fault(regs))
                printk(KERN_ALERT "Unable to handle kernel pointer dereference"
                       " at virtual kernel address %p\n", (void *)address);
        else
@@ -296,7 +299,7 @@ static inline int do_exception(struct pt_regs *regs, int access)
         * user context.
         */
        fault = VM_FAULT_BADCONTEXT;
-       if (unlikely(!user_space_fault(trans_exc_code) || in_atomic() || !mm))
+       if (unlikely(!user_space_fault(regs) || in_atomic() || !mm))
                goto out;
 
        address = trans_exc_code & __FAIL_ADDR_MASK;
@@ -441,30 +444,6 @@ void __kprobes do_dat_exception(struct pt_regs *regs)
                do_fault_error(regs, fault);
 }
 
-int __handle_fault(unsigned long uaddr, unsigned long pgm_int_code, int write)
-{
-       struct pt_regs regs;
-       int access, fault;
-
-       /* Emulate a uaccess fault from kernel mode. */
-       regs.psw.mask = PSW_KERNEL_BITS | PSW_MASK_DAT | PSW_MASK_MCHECK;
-       if (!irqs_disabled())
-               regs.psw.mask |= PSW_MASK_IO | PSW_MASK_EXT;
-       regs.psw.addr = (unsigned long) __builtin_return_address(0);
-       regs.psw.addr |= PSW_ADDR_AMODE;
-       regs.int_code = pgm_int_code;
-       regs.int_parm_long = (uaddr & PAGE_MASK) | 2;
-       access = write ? VM_WRITE : VM_READ;
-       fault = do_exception(&regs, access);
-       /*
-        * Since the fault happened in kernel mode while performing a uaccess
-        * all we need to do now is emulating a fixup in case "fault" is not
-        * zero.
-        * For the calling uaccess functions this results always in -EFAULT.
-        */
-       return fault ? -EFAULT : 0;
-}
-
 #ifdef CONFIG_PFAULT 
 /*
  * 'pfault' pseudo page faults routines.
@@ -645,7 +624,7 @@ static int __init pfault_irq_init(void)
 {
        int rc;
 
-       rc = register_external_interrupt(0x2603, pfault_interrupt);
+       rc = register_external_irq(EXT_IRQ_CP_SERVICE, pfault_interrupt);
        if (rc)
                goto out_extint;
        rc = pfault_init() == 0 ? 0 : -EOPNOTSUPP;
@@ -656,7 +635,7 @@ static int __init pfault_irq_init(void)
        return 0;
 
 out_pfault:
-       unregister_external_interrupt(0x2603, pfault_interrupt);
+       unregister_external_irq(EXT_IRQ_CP_SERVICE, pfault_interrupt);
 out_extint:
        pfault_disable = 1;
        return rc;
index d261c62..0727a55 100644 (file)
@@ -123,10 +123,7 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm,
        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);
+       pmdp_flush_direct(mm, addr, pmdp);
        pmd_val(*pmdp) = _SEGMENT_ENTRY_EMPTY;
        return pte;
 }
index ad446b0..0c1073e 100644 (file)
@@ -124,8 +124,6 @@ void __init paging_init(void)
        __ctl_load(S390_lowcore.kernel_asce, 13, 13);
        arch_local_irq_restore(4UL << (BITS_PER_LONG - 8));
 
-       atomic_set(&init_mm.context.attach_count, 1);
-
        sparse_memory_present_with_active_regions(MAX_NUMNODES);
        sparse_init();
        memset(max_zone_pfns, 0, sizeof(max_zone_pfns));
@@ -136,6 +134,11 @@ void __init paging_init(void)
 
 void __init mem_init(void)
 {
+       if (MACHINE_HAS_TLB_LC)
+               cpumask_set_cpu(0, &init_mm.context.cpu_attach_mask);
+       cpumask_set_cpu(0, mm_cpumask(&init_mm));
+       atomic_set(&init_mm.context.attach_count, 1);
+
         max_mapnr = max_low_pfn;
         high_memory = (void *) __va(max_low_pfn * PAGE_SIZE);
 
index 796c932..d7cfd57 100644 (file)
@@ -54,7 +54,7 @@ static void __crst_table_upgrade(void *arg)
        struct mm_struct *mm = arg;
 
        if (current->active_mm == mm)
-               update_mm(mm, current);
+               update_user_asce(mm, 1);
        __tlb_flush_local();
 }
 
@@ -107,8 +107,10 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
 {
        pgd_t *pgd;
 
-       if (current->active_mm == mm)
+       if (current->active_mm == mm) {
+               clear_user_asce(mm, 1);
                __tlb_flush_mm(mm);
+       }
        while (mm->context.asce_limit > limit) {
                pgd = mm->pgd;
                switch (pgd_val(*pgd) & _REGION_ENTRY_TYPE_MASK) {
@@ -132,7 +134,7 @@ void crst_table_downgrade(struct mm_struct *mm, unsigned long limit)
                crst_table_free(mm, (unsigned long *) pgd);
        }
        if (current->active_mm == mm)
-               update_mm(mm, current);
+               update_user_asce(mm, 1);
 }
 #endif
 
@@ -198,7 +200,7 @@ static int gmap_unlink_segment(struct gmap *gmap, unsigned long *table)
 static void gmap_flush_tlb(struct gmap *gmap)
 {
        if (MACHINE_HAS_IDTE)
-               __tlb_flush_idte((unsigned long) gmap->table |
+               __tlb_flush_asce(gmap->mm, (unsigned long) gmap->table |
                                 _ASCE_TYPE_REGION1);
        else
                __tlb_flush_global();
@@ -217,7 +219,7 @@ void gmap_free(struct gmap *gmap)
 
        /* Flush tlb. */
        if (MACHINE_HAS_IDTE)
-               __tlb_flush_idte((unsigned long) gmap->table |
+               __tlb_flush_asce(gmap->mm, (unsigned long) gmap->table |
                                 _ASCE_TYPE_REGION1);
        else
                __tlb_flush_global();
@@ -505,6 +507,9 @@ static int gmap_connect_pgtable(unsigned long address, unsigned long segment,
        if (!pmd_present(*pmd) &&
            __pte_alloc(mm, vma, pmd, vmaddr))
                return -ENOMEM;
+       /* large pmds cannot yet be handled */
+       if (pmd_large(*pmd))
+               return -EFAULT;
        /* pmd now points to a valid segment table entry. */
        rmap = kmalloc(sizeof(*rmap), GFP_KERNEL|__GFP_REPEAT);
        if (!rmap)
index bcfb70b..72b04de 100644 (file)
@@ -138,7 +138,6 @@ static int vmem_add_mem(unsigned long start, unsigned long size, int ro)
        }
        ret = 0;
 out:
-       flush_tlb_kernel_range(start, end);
        return ret;
 }
 
@@ -265,7 +264,6 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
        memset((void *)start, 0, end - start);
        ret = 0;
 out:
-       flush_tlb_kernel_range(start, end);
        return ret;
 }
 
index a32c967..276f2e2 100644 (file)
@@ -1033,7 +1033,7 @@ int hwsampler_setup(void)
                                max_sampler_rate = cb->qsi.max_sampl_rate;
                }
        }
-       register_external_interrupt(0x1407, hws_ext_handler);
+       register_external_irq(EXT_IRQ_MEASURE_ALERT, hws_ext_handler);
 
        hws_state = HWS_DEALLOCATED;
        rc = 0;
@@ -1068,7 +1068,7 @@ int hwsampler_shutdown(void)
                        hws_wq = NULL;
                }
 
-               unregister_external_interrupt(0x1407, hws_ext_handler);
+               unregister_external_irq(EXT_IRQ_MEASURE_ALERT, hws_ext_handler);
                hws_state = HWS_INIT;
                rc = 0;
        }
index 1399383..ba55e93 100644 (file)
@@ -3,7 +3,7 @@ config SUPERH
        select ARCH_MIGHT_HAVE_PC_PARPORT
        select EXPERT
        select CLKDEV_LOOKUP
-       select HAVE_IDE if HAS_IOPORT
+       select HAVE_IDE if HAS_IOPORT_MAP
        select HAVE_MEMBLOCK
        select HAVE_MEMBLOCK_NODE_MAP
        select ARCH_DISCARD_MEMBLOCK
@@ -138,7 +138,7 @@ config ARCH_HAS_ILOG2_U32
 config ARCH_HAS_ILOG2_U64
        def_bool n
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool !PCI
        depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN && \
                   !SH_HP6XX && !SH_SOLUTION_ENGINE
index eb1cf84..e331e53 100644 (file)
@@ -158,7 +158,7 @@ config SH_SDK7786
        bool "SDK7786"
        depends on CPU_SUBTYPE_SH7786
        select SYS_SUPPORTS_PCI
-       select NO_IOPORT if !PCI
+       select NO_IOPORT_MAP if !PCI
        select ARCH_WANT_OPTIONAL_GPIOLIB
        select HAVE_SRAM_POOL
        select REGULATOR_FIXED_VOLTAGE if REGULATOR
@@ -204,7 +204,7 @@ config SH_URQUELL
        depends on CPU_SUBTYPE_SH7786
        select ARCH_REQUIRE_GPIOLIB
        select SYS_SUPPORTS_PCI
-       select NO_IOPORT if !PCI
+       select NO_IOPORT_MAP if !PCI
 
 config SH_MIGOR
        bool "Migo-R"
@@ -306,7 +306,7 @@ config SH_LBOX_RE2
 config SH_X3PROTO
        bool "SH-X3 Prototype board"
        depends on CPU_SUBTYPE_SHX3
-       select NO_IOPORT if !PCI
+       select NO_IOPORT_MAP if !PCI
        select IRQ_DOMAIN
 
 config SH_MAGIC_PANEL_R2
@@ -333,7 +333,7 @@ config SH_POLARIS
 
 config SH_SH2007
        bool "SH-2007 board"
-       select NO_IOPORT
+       select NO_IOPORT_MAP
        select REGULATOR_FIXED_VOLTAGE if REGULATOR
        depends on CPU_SUBTYPE_SH7780
        help
index 629db2a..728c4c5 100644 (file)
@@ -122,7 +122,7 @@ __BUILD_MEMORY_STRING(__raw_, l, u32)
 
 __BUILD_MEMORY_STRING(__raw_, q, u64)
 
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
 
 /*
  * Slowdown I/O port space accesses for antique hardware.
@@ -218,7 +218,7 @@ __BUILD_IOPORT_STRING(w, u16)
 __BUILD_IOPORT_STRING(l, u32)
 __BUILD_IOPORT_STRING(q, u64)
 
-#else /* !CONFIG_HAS_IOPORT */
+#else /* !CONFIG_HAS_IOPORT_MAP */
 
 #include <asm/io_noioport.h>
 
index f1251d4..4ab94ef 100644 (file)
@@ -36,7 +36,7 @@ __ioremap_trapped(unsigned long offset, unsigned long size)
 #define __ioremap_trapped(offset, size) NULL
 #endif
 
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
 extern struct list_head trapped_io;
 
 static inline void __iomem *
index eb9c20d..d3324e4 100644 (file)
@@ -21,7 +21,7 @@ struct sh_machine_vector {
        int (*mv_irq_demux)(int irq);
        void (*mv_init_irq)(void);
 
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
        void __iomem *(*mv_ioport_map)(unsigned long port, unsigned int size);
        void (*mv_ioport_unmap)(void __iomem *);
 #endif
index 261c8bf..2ccf36c 100644 (file)
@@ -22,7 +22,7 @@ obj-y := debugtraps.o dma-nommu.o dumpstack.o                 \
 
 ifndef CONFIG_GENERIC_IOMAP
 obj-y                          += iomap.o
-obj-$(CONFIG_HAS_IOPORT)       += ioport.o
+obj-$(CONFIG_HAS_IOPORT_MAP)   += ioport.o
 endif
 
 obj-$(CONFIG_SUPERH32)         += sys_sh32.o
index c0a9761..f8ce362 100644 (file)
@@ -22,7 +22,7 @@
 
 #define TRAPPED_PAGES_MAX 16
 
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
 LIST_HEAD(trapped_io);
 EXPORT_SYMBOL_GPL(trapped_io);
 #endif
@@ -90,7 +90,7 @@ int register_trapped_io(struct trapped_io *tiop)
        tiop->magic = IO_TRAPPED_MAGIC;
        INIT_LIST_HEAD(&tiop->list);
        spin_lock_irq(&trapped_lock);
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
        if (flags & IORESOURCE_IO)
                list_add(&tiop->list, &trapped_io);
 #endif
index c21c673..a364000 100644 (file)
@@ -300,7 +300,7 @@ static int __init topology_init(void)
 
        check_mmu_stats();
 
-       register_cpu_notifier(&sysfs_cpu_nb);
+       cpu_notifier_register_begin();
 
        for_each_possible_cpu(cpu) {
                struct cpu *c = &per_cpu(cpu_devices, cpu);
@@ -310,6 +310,10 @@ static int __init topology_init(void)
                        register_cpu_online(cpu);
        }
 
+       __register_cpu_notifier(&sysfs_cpu_nb);
+
+       cpu_notifier_register_done();
+
        return 0;
 }
 
index 31c8c62..85258ca 100644 (file)
@@ -411,7 +411,7 @@ config PCI_DOMAINS
 config NO_IOMEM
        def_bool !PCI
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool !PCI
 
 config TILE_PCI_IO
index eecc414..f17bca8 100644 (file)
@@ -359,7 +359,7 @@ int singlestepping(void * t)
 /*
  * Only x86 and x86_64 have an arch_align_stack().
  * All other arches have "#define arch_align_stack(x) (x)"
- * in their asm/system.h
+ * in their asm/exec.h
  * As this is included in UML from asm-um/system-generic.h,
  * we can use it to behave as the subarch does.
  */
index 25c0dba..aafad6f 100644 (file)
@@ -27,7 +27,7 @@ config UNICORE32
 config GENERIC_CSUM
        def_bool y
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        bool
 
 config STACKTRACE_SUPPORT
index fb5e4c6..ef470a7 100644 (file)
@@ -14,6 +14,8 @@
 
 #include <linux/compiler.h>
 #include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmacache.h>
 #include <linux/io.h>
 
 #include <asm/cacheflush.h>
@@ -73,7 +75,7 @@ do { \
                else \
                        mm->mmap = NULL; \
                rb_erase(&high_vma->vm_rb, &mm->mm_rb); \
-               mm->mmap_cache = NULL; \
+               vmacache_invalidate(mm); \
                mm->map_count--; \
                remove_vma(high_vma); \
        } \
index f730717..5b8ec0f 100644 (file)
@@ -43,6 +43,7 @@ config X86
        select HAVE_DMA_ATTRS
        select HAVE_DMA_CONTIGUOUS if !SWIOTLB
        select HAVE_KRETPROBES
+       select GENERIC_EARLY_IOREMAP
        select HAVE_OPTPROBES
        select HAVE_KPROBES_ON_FTRACE
        select HAVE_FTRACE_MCOUNT_RECORD
index 4acddc4..3ca9762 100644 (file)
@@ -5,5 +5,6 @@ genhdr-y += unistd_64.h
 genhdr-y += unistd_x32.h
 
 generic-y += clkdev.h
+generic-y += early_ioremap.h
 generic-y += cputime.h
 generic-y += mcs_spinlock.h
index 2f03ff0..ba38ebb 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef _ASM_X86_BUG_H
 #define _ASM_X86_BUG_H
 
-#ifdef CONFIG_BUG
 #define HAVE_ARCH_BUG
 
 #ifdef CONFIG_DEBUG_BUGVERBOSE
@@ -33,8 +32,6 @@ do {                                                          \
 } while (0)
 #endif
 
-#endif /* !CONFIG_BUG */
-
 #include <asm-generic/bug.h>
 
 #endif /* _ASM_X86_BUG_H */
index 8dcd35c..43f482a 100644 (file)
@@ -163,5 +163,11 @@ static inline void __set_fixmap(enum fixed_addresses idx,
 
 #include <asm-generic/fixmap.h>
 
+#define __late_set_fixmap(idx, phys, flags) __set_fixmap(idx, phys, flags)
+#define __late_clear_fixmap(idx) __set_fixmap(idx, 0, __pgprot(0))
+
+void __early_set_fixmap(enum fixed_addresses idx,
+                       phys_addr_t phys, pgprot_t flags);
+
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASM_X86_FIXMAP_H */
index 91d9c69..b8237d8 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/string.h>
 #include <linux/compiler.h>
 #include <asm/page.h>
+#include <asm/early_ioremap.h>
 
 #define build_mmio_read(name, size, type, reg, barrier) \
 static inline type name(const volatile void __iomem *addr) \
@@ -316,19 +317,6 @@ extern int ioremap_change_attr(unsigned long vaddr, unsigned long size,
                                unsigned long prot_val);
 extern void __iomem *ioremap_wc(resource_size_t offset, unsigned long size);
 
-/*
- * early_ioremap() and early_iounmap() are for temporary early boot-time
- * mappings, before the real ioremap() is functional.
- * A boot-time mapping is currently limited to at most 16 pages.
- */
-extern void early_ioremap_init(void);
-extern void early_ioremap_reset(void);
-extern void __iomem *early_ioremap(resource_size_t phys_addr,
-                                  unsigned long size);
-extern void __iomem *early_memremap(resource_size_t phys_addr,
-                                   unsigned long size);
-extern void early_iounmap(void __iomem *addr, unsigned long size);
-extern void fixup_early_ioremap(void);
 extern bool is_early_ioremap_ptep(pte_t *ptep);
 
 #ifdef CONFIG_XEN
index 94220d1..851bcdc 100644 (file)
@@ -52,7 +52,7 @@
  * Compared to the generic __my_cpu_offset version, the following
  * saves one instruction and avoids clobbering a temp register.
  */
-#define __this_cpu_ptr(ptr)                            \
+#define raw_cpu_ptr(ptr)                               \
 ({                                                     \
        unsigned long tcp_ptr__;                        \
        __verify_pcpu_ptr(ptr);                         \
@@ -362,25 +362,25 @@ do {                                                                      \
  */
 #define this_cpu_read_stable(var)      percpu_from_op("mov", var, "p" (&(var)))
 
-#define __this_cpu_read_1(pcp)         percpu_from_op("mov", (pcp), "m"(pcp))
-#define __this_cpu_read_2(pcp)         percpu_from_op("mov", (pcp), "m"(pcp))
-#define __this_cpu_read_4(pcp)         percpu_from_op("mov", (pcp), "m"(pcp))
-
-#define __this_cpu_write_1(pcp, val)   percpu_to_op("mov", (pcp), val)
-#define __this_cpu_write_2(pcp, val)   percpu_to_op("mov", (pcp), val)
-#define __this_cpu_write_4(pcp, val)   percpu_to_op("mov", (pcp), val)
-#define __this_cpu_add_1(pcp, val)     percpu_add_op((pcp), val)
-#define __this_cpu_add_2(pcp, val)     percpu_add_op((pcp), val)
-#define __this_cpu_add_4(pcp, val)     percpu_add_op((pcp), val)
-#define __this_cpu_and_1(pcp, val)     percpu_to_op("and", (pcp), val)
-#define __this_cpu_and_2(pcp, val)     percpu_to_op("and", (pcp), val)
-#define __this_cpu_and_4(pcp, val)     percpu_to_op("and", (pcp), val)
-#define __this_cpu_or_1(pcp, val)      percpu_to_op("or", (pcp), val)
-#define __this_cpu_or_2(pcp, val)      percpu_to_op("or", (pcp), val)
-#define __this_cpu_or_4(pcp, val)      percpu_to_op("or", (pcp), val)
-#define __this_cpu_xchg_1(pcp, val)    percpu_xchg_op(pcp, val)
-#define __this_cpu_xchg_2(pcp, val)    percpu_xchg_op(pcp, val)
-#define __this_cpu_xchg_4(pcp, val)    percpu_xchg_op(pcp, val)
+#define raw_cpu_read_1(pcp)            percpu_from_op("mov", (pcp), "m"(pcp))
+#define raw_cpu_read_2(pcp)            percpu_from_op("mov", (pcp), "m"(pcp))
+#define raw_cpu_read_4(pcp)            percpu_from_op("mov", (pcp), "m"(pcp))
+
+#define raw_cpu_write_1(pcp, val)      percpu_to_op("mov", (pcp), val)
+#define raw_cpu_write_2(pcp, val)      percpu_to_op("mov", (pcp), val)
+#define raw_cpu_write_4(pcp, val)      percpu_to_op("mov", (pcp), val)
+#define raw_cpu_add_1(pcp, val)                percpu_add_op((pcp), val)
+#define raw_cpu_add_2(pcp, val)                percpu_add_op((pcp), val)
+#define raw_cpu_add_4(pcp, val)                percpu_add_op((pcp), val)
+#define raw_cpu_and_1(pcp, val)                percpu_to_op("and", (pcp), val)
+#define raw_cpu_and_2(pcp, val)                percpu_to_op("and", (pcp), val)
+#define raw_cpu_and_4(pcp, val)                percpu_to_op("and", (pcp), val)
+#define raw_cpu_or_1(pcp, val)         percpu_to_op("or", (pcp), val)
+#define raw_cpu_or_2(pcp, val)         percpu_to_op("or", (pcp), val)
+#define raw_cpu_or_4(pcp, val)         percpu_to_op("or", (pcp), val)
+#define raw_cpu_xchg_1(pcp, val)       percpu_xchg_op(pcp, val)
+#define raw_cpu_xchg_2(pcp, val)       percpu_xchg_op(pcp, val)
+#define raw_cpu_xchg_4(pcp, val)       percpu_xchg_op(pcp, val)
 
 #define this_cpu_read_1(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
 #define this_cpu_read_2(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
@@ -401,16 +401,16 @@ do {                                                                      \
 #define this_cpu_xchg_2(pcp, nval)     percpu_xchg_op(pcp, nval)
 #define this_cpu_xchg_4(pcp, nval)     percpu_xchg_op(pcp, nval)
 
-#define __this_cpu_add_return_1(pcp, val) percpu_add_return_op(pcp, val)
-#define __this_cpu_add_return_2(pcp, val) percpu_add_return_op(pcp, val)
-#define __this_cpu_add_return_4(pcp, val) percpu_add_return_op(pcp, val)
-#define __this_cpu_cmpxchg_1(pcp, oval, nval)  percpu_cmpxchg_op(pcp, oval, nval)
-#define __this_cpu_cmpxchg_2(pcp, oval, nval)  percpu_cmpxchg_op(pcp, oval, nval)
-#define __this_cpu_cmpxchg_4(pcp, oval, nval)  percpu_cmpxchg_op(pcp, oval, nval)
+#define raw_cpu_add_return_1(pcp, val)         percpu_add_return_op(pcp, val)
+#define raw_cpu_add_return_2(pcp, val)         percpu_add_return_op(pcp, val)
+#define raw_cpu_add_return_4(pcp, val)         percpu_add_return_op(pcp, val)
+#define raw_cpu_cmpxchg_1(pcp, oval, nval)     percpu_cmpxchg_op(pcp, oval, nval)
+#define raw_cpu_cmpxchg_2(pcp, oval, nval)     percpu_cmpxchg_op(pcp, oval, nval)
+#define raw_cpu_cmpxchg_4(pcp, oval, nval)     percpu_cmpxchg_op(pcp, oval, nval)
 
-#define this_cpu_add_return_1(pcp, val)        percpu_add_return_op(pcp, val)
-#define this_cpu_add_return_2(pcp, val)        percpu_add_return_op(pcp, val)
-#define this_cpu_add_return_4(pcp, val)        percpu_add_return_op(pcp, val)
+#define this_cpu_add_return_1(pcp, val)                percpu_add_return_op(pcp, val)
+#define this_cpu_add_return_2(pcp, val)                percpu_add_return_op(pcp, val)
+#define this_cpu_add_return_4(pcp, val)                percpu_add_return_op(pcp, val)
 #define this_cpu_cmpxchg_1(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
 #define this_cpu_cmpxchg_2(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
 #define this_cpu_cmpxchg_4(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
@@ -427,7 +427,7 @@ do {                                                                        \
        __ret;                                                          \
 })
 
-#define __this_cpu_cmpxchg_double_4    percpu_cmpxchg8b_double
+#define raw_cpu_cmpxchg_double_4       percpu_cmpxchg8b_double
 #define this_cpu_cmpxchg_double_4      percpu_cmpxchg8b_double
 #endif /* CONFIG_X86_CMPXCHG64 */
 
@@ -436,22 +436,22 @@ do {                                                                      \
  * 32 bit must fall back to generic operations.
  */
 #ifdef CONFIG_X86_64
-#define __this_cpu_read_8(pcp)         percpu_from_op("mov", (pcp), "m"(pcp))
-#define __this_cpu_write_8(pcp, val)   percpu_to_op("mov", (pcp), val)
-#define __this_cpu_add_8(pcp, val)     percpu_add_op((pcp), val)
-#define __this_cpu_and_8(pcp, val)     percpu_to_op("and", (pcp), val)
-#define __this_cpu_or_8(pcp, val)      percpu_to_op("or", (pcp), val)
-#define __this_cpu_add_return_8(pcp, val) percpu_add_return_op(pcp, val)
-#define __this_cpu_xchg_8(pcp, nval)   percpu_xchg_op(pcp, nval)
-#define __this_cpu_cmpxchg_8(pcp, oval, nval)  percpu_cmpxchg_op(pcp, oval, nval)
-
-#define this_cpu_read_8(pcp)           percpu_from_op("mov", (pcp), "m"(pcp))
-#define this_cpu_write_8(pcp, val)     percpu_to_op("mov", (pcp), val)
-#define this_cpu_add_8(pcp, val)       percpu_add_op((pcp), val)
-#define this_cpu_and_8(pcp, val)       percpu_to_op("and", (pcp), val)
-#define this_cpu_or_8(pcp, val)                percpu_to_op("or", (pcp), val)
-#define this_cpu_add_return_8(pcp, val)        percpu_add_return_op(pcp, val)
-#define this_cpu_xchg_8(pcp, nval)     percpu_xchg_op(pcp, nval)
+#define raw_cpu_read_8(pcp)                    percpu_from_op("mov", (pcp), "m"(pcp))
+#define raw_cpu_write_8(pcp, val)              percpu_to_op("mov", (pcp), val)
+#define raw_cpu_add_8(pcp, val)                        percpu_add_op((pcp), val)
+#define raw_cpu_and_8(pcp, val)                        percpu_to_op("and", (pcp), val)
+#define raw_cpu_or_8(pcp, val)                 percpu_to_op("or", (pcp), val)
+#define raw_cpu_add_return_8(pcp, val)         percpu_add_return_op(pcp, val)
+#define raw_cpu_xchg_8(pcp, nval)              percpu_xchg_op(pcp, nval)
+#define raw_cpu_cmpxchg_8(pcp, oval, nval)     percpu_cmpxchg_op(pcp, oval, nval)
+
+#define this_cpu_read_8(pcp)                   percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_write_8(pcp, val)             percpu_to_op("mov", (pcp), val)
+#define this_cpu_add_8(pcp, val)               percpu_add_op((pcp), val)
+#define this_cpu_and_8(pcp, val)               percpu_to_op("and", (pcp), val)
+#define this_cpu_or_8(pcp, val)                        percpu_to_op("or", (pcp), val)
+#define this_cpu_add_return_8(pcp, val)                percpu_add_return_op(pcp, val)
+#define this_cpu_xchg_8(pcp, nval)             percpu_xchg_op(pcp, nval)
 #define this_cpu_cmpxchg_8(pcp, oval, nval)    percpu_cmpxchg_op(pcp, oval, nval)
 
 /*
@@ -474,7 +474,7 @@ do {                                                                        \
        __ret;                                                          \
 })
 
-#define __this_cpu_cmpxchg_double_8    percpu_cmpxchg16b_double
+#define raw_cpu_cmpxchg_double_8       percpu_cmpxchg16b_double
 #define this_cpu_cmpxchg_double_8      percpu_cmpxchg16b_double
 
 #endif
@@ -495,9 +495,9 @@ static __always_inline int x86_this_cpu_constant_test_bit(unsigned int nr,
        unsigned long __percpu *a = (unsigned long *)addr + nr / BITS_PER_LONG;
 
 #ifdef CONFIG_X86_64
-       return ((1UL << (nr % BITS_PER_LONG)) & __this_cpu_read_8(*a)) != 0;
+       return ((1UL << (nr % BITS_PER_LONG)) & raw_cpu_read_8(*a)) != 0;
 #else
-       return ((1UL << (nr % BITS_PER_LONG)) & __this_cpu_read_4(*a)) != 0;
+       return ((1UL << (nr % BITS_PER_LONG)) & raw_cpu_read_4(*a)) != 0;
 #endif
 }
 
index c8b0519..7024c12 100644 (file)
@@ -19,12 +19,12 @@ DECLARE_PER_CPU(int, __preempt_count);
  */
 static __always_inline int preempt_count(void)
 {
-       return __this_cpu_read_4(__preempt_count) & ~PREEMPT_NEED_RESCHED;
+       return raw_cpu_read_4(__preempt_count) & ~PREEMPT_NEED_RESCHED;
 }
 
 static __always_inline void preempt_count_set(int pc)
 {
-       __this_cpu_write_4(__preempt_count, pc);
+       raw_cpu_write_4(__preempt_count, pc);
 }
 
 /*
@@ -53,17 +53,17 @@ static __always_inline void preempt_count_set(int pc)
 
 static __always_inline void set_preempt_need_resched(void)
 {
-       __this_cpu_and_4(__preempt_count, ~PREEMPT_NEED_RESCHED);
+       raw_cpu_and_4(__preempt_count, ~PREEMPT_NEED_RESCHED);
 }
 
 static __always_inline void clear_preempt_need_resched(void)
 {
-       __this_cpu_or_4(__preempt_count, PREEMPT_NEED_RESCHED);
+       raw_cpu_or_4(__preempt_count, PREEMPT_NEED_RESCHED);
 }
 
 static __always_inline bool test_preempt_need_resched(void)
 {
-       return !(__this_cpu_read_4(__preempt_count) & PREEMPT_NEED_RESCHED);
+       return !(raw_cpu_read_4(__preempt_count) & PREEMPT_NEED_RESCHED);
 }
 
 /*
@@ -72,12 +72,12 @@ static __always_inline bool test_preempt_need_resched(void)
 
 static __always_inline void __preempt_count_add(int val)
 {
-       __this_cpu_add_4(__preempt_count, val);
+       raw_cpu_add_4(__preempt_count, val);
 }
 
 static __always_inline void __preempt_count_sub(int val)
 {
-       __this_cpu_add_4(__preempt_count, -val);
+       raw_cpu_add_4(__preempt_count, -val);
 }
 
 /*
@@ -95,7 +95,7 @@ static __always_inline bool __preempt_count_dec_and_test(void)
  */
 static __always_inline bool should_resched(void)
 {
-       return unlikely(!__this_cpu_read_4(__preempt_count));
+       return unlikely(!raw_cpu_read_4(__preempt_count));
 }
 
 #ifdef CONFIG_PREEMPT
index 0641113..a952e9c 100644 (file)
@@ -1225,21 +1225,24 @@ static struct notifier_block cacheinfo_cpu_notifier = {
 
 static int __init cache_sysfs_init(void)
 {
-       int i;
+       int i, err = 0;
 
        if (num_cache_leaves == 0)
                return 0;
 
+       cpu_notifier_register_begin();
        for_each_online_cpu(i) {
-               int err;
                struct device *dev = get_cpu_device(i);
 
                err = cache_add_dev(dev);
                if (err)
-                       return err;
+                       goto out;
        }
-       register_hotcpu_notifier(&cacheinfo_cpu_notifier);
-       return 0;
+       __register_hotcpu_notifier(&cacheinfo_cpu_notifier);
+
+out:
+       cpu_notifier_register_done();
+       return err;
 }
 
 device_initcall(cache_sysfs_init);
index 4d5419b..9b7734b 100644 (file)
@@ -2434,14 +2434,18 @@ static __init int mcheck_init_device(void)
        if (err)
                return err;
 
+       cpu_notifier_register_begin();
        for_each_online_cpu(i) {
                err = mce_device_create(i);
-               if (err)
+               if (err) {
+                       cpu_notifier_register_done();
                        return err;
+               }
        }
 
        register_syscore_ops(&mce_syscore_ops);
-       register_hotcpu_notifier(&mce_cpu_notifier);
+       __register_hotcpu_notifier(&mce_cpu_notifier);
+       cpu_notifier_register_done();
 
        /* register character device /dev/mcelog */
        misc_register(&mce_chrdev_device);
index 3eec7de..d921b7e 100644 (file)
@@ -271,9 +271,6 @@ static void thermal_throttle_remove_dev(struct device *dev)
        sysfs_remove_group(&dev->kobj, &thermal_attr_group);
 }
 
-/* Mutex protecting device creation against CPU hotplug: */
-static DEFINE_MUTEX(therm_cpu_lock);
-
 /* Get notified when a cpu comes on/off. Be hotplug friendly. */
 static int
 thermal_throttle_cpu_callback(struct notifier_block *nfb,
@@ -289,18 +286,14 @@ thermal_throttle_cpu_callback(struct notifier_block *nfb,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               mutex_lock(&therm_cpu_lock);
                err = thermal_throttle_add_dev(dev, cpu);
-               mutex_unlock(&therm_cpu_lock);
                WARN_ON(err);
                break;
        case CPU_UP_CANCELED:
        case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               mutex_lock(&therm_cpu_lock);
                thermal_throttle_remove_dev(dev);
-               mutex_unlock(&therm_cpu_lock);
                break;
        }
        return notifier_from_errno(err);
@@ -319,19 +312,16 @@ static __init int thermal_throttle_init_device(void)
        if (!atomic_read(&therm_throt_en))
                return 0;
 
-       register_hotcpu_notifier(&thermal_throttle_cpu_notifier);
+       cpu_notifier_register_begin();
 
-#ifdef CONFIG_HOTPLUG_CPU
-       mutex_lock(&therm_cpu_lock);
-#endif
        /* connect live CPUs to sysfs */
        for_each_online_cpu(cpu) {
                err = thermal_throttle_add_dev(get_cpu_device(cpu), cpu);
                WARN_ON(err);
        }
-#ifdef CONFIG_HOTPLUG_CPU
-       mutex_unlock(&therm_cpu_lock);
-#endif
+
+       __register_hotcpu_notifier(&thermal_throttle_cpu_notifier);
+       cpu_notifier_register_done();
 
        return 0;
 }
index 4b8e4d3..4c36bbe 100644 (file)
@@ -926,13 +926,13 @@ static __init int amd_ibs_init(void)
                goto out;
 
        perf_ibs_pm_init();
-       get_online_cpus();
+       cpu_notifier_register_begin();
        ibs_caps = caps;
        /* make ibs_caps visible to other cpus: */
        smp_mb();
-       perf_cpu_notifier(perf_ibs_cpu_notifier);
        smp_call_function(setup_APIC_ibs, NULL, 1);
-       put_online_cpus();
+       __perf_cpu_notifier(perf_ibs_cpu_notifier);
+       cpu_notifier_register_done();
 
        ret = perf_event_ibs_init();
 out:
index 754291a..3bbdf4c 100644 (file)
@@ -531,15 +531,16 @@ static int __init amd_uncore_init(void)
        if (ret)
                return -ENODEV;
 
-       get_online_cpus();
+       cpu_notifier_register_begin();
+
        /* init cpus already online before registering for hotplug notifier */
        for_each_online_cpu(cpu) {
                amd_uncore_cpu_up_prepare(cpu);
                smp_call_function_single(cpu, init_cpu_already_online, NULL, 1);
        }
 
-       register_cpu_notifier(&amd_uncore_cpu_notifier_block);
-       put_online_cpus();
+       __register_cpu_notifier(&amd_uncore_cpu_notifier_block);
+       cpu_notifier_register_done();
 
        return 0;
 }
index 5ad35ad..059218e 100644 (file)
@@ -646,19 +646,20 @@ static int __init rapl_pmu_init(void)
                /* unsupported */
                return 0;
        }
-       get_online_cpus();
+
+       cpu_notifier_register_begin();
 
        for_each_online_cpu(cpu) {
                rapl_cpu_prepare(cpu);
                rapl_cpu_init(cpu);
        }
 
-       perf_cpu_notifier(rapl_cpu_notifier);
+       __perf_cpu_notifier(rapl_cpu_notifier);
 
        ret = perf_pmu_register(&rapl_pmu_class, "power", -1);
        if (WARN_ON(ret)) {
                pr_info("RAPL PMU detected, registration failed (%d), RAPL PMU disabled\n", ret);
-               put_online_cpus();
+               cpu_notifier_register_done();
                return -1;
        }
 
@@ -672,7 +673,7 @@ static int __init rapl_pmu_init(void)
                hweight32(rapl_cntr_mask),
                ktime_to_ms(pmu->timer_interval));
 
-       put_online_cpus();
+       cpu_notifier_register_done();
 
        return 0;
 }
index bd2253d..65bbbea 100644 (file)
@@ -4244,7 +4244,7 @@ static void __init uncore_cpumask_init(void)
        if (!cpumask_empty(&uncore_cpu_mask))
                return;
 
-       get_online_cpus();
+       cpu_notifier_register_begin();
 
        for_each_online_cpu(cpu) {
                int i, phys_id = topology_physical_package_id(cpu);
@@ -4263,9 +4263,9 @@ static void __init uncore_cpumask_init(void)
        }
        on_each_cpu(uncore_cpu_setup, NULL, 1);
 
-       register_cpu_notifier(&uncore_cpu_nb);
+       __register_cpu_notifier(&uncore_cpu_nb);
 
-       put_online_cpus();
+       cpu_notifier_register_done();
 }
 
 
index 7d9481c..3225ae6 100644 (file)
@@ -198,14 +198,15 @@ static int __init cpuid_init(void)
                goto out_chrdev;
        }
        cpuid_class->devnode = cpuid_devnode;
-       get_online_cpus();
+
+       cpu_notifier_register_begin();
        for_each_online_cpu(i) {
                err = cpuid_device_create(i);
                if (err != 0)
                        goto out_class;
        }
-       register_hotcpu_notifier(&cpuid_class_cpu_notifier);
-       put_online_cpus();
+       __register_hotcpu_notifier(&cpuid_class_cpu_notifier);
+       cpu_notifier_register_done();
 
        err = 0;
        goto out;
@@ -215,7 +216,7 @@ out_class:
        for_each_online_cpu(i) {
                cpuid_device_destroy(i);
        }
-       put_online_cpus();
+       cpu_notifier_register_done();
        class_destroy(cpuid_class);
 out_chrdev:
        __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
@@ -227,13 +228,13 @@ static void __exit cpuid_exit(void)
 {
        int cpu = 0;
 
-       get_online_cpus();
+       cpu_notifier_register_begin();
        for_each_online_cpu(cpu)
                cpuid_device_destroy(cpu);
        class_destroy(cpuid_class);
        __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
-       unregister_hotcpu_notifier(&cpuid_class_cpu_notifier);
-       put_online_cpus();
+       __unregister_hotcpu_notifier(&cpuid_class_cpu_notifier);
+       cpu_notifier_register_done();
 }
 
 module_init(cpuid_init);
index 93eed15..8d80ae0 100644 (file)
@@ -941,12 +941,14 @@ static __init int hpet_late_init(void)
        if (boot_cpu_has(X86_FEATURE_ARAT))
                return 0;
 
+       cpu_notifier_register_begin();
        for_each_online_cpu(cpu) {
                hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu);
        }
 
        /* This notifier should be called after workqueue is ready */
-       hotcpu_notifier(hpet_cpuhp_notify, -20);
+       __hotcpu_notifier(hpet_cpuhp_notify, -20);
+       cpu_notifier_register_done();
 
        return 0;
 }
index 05266b5..c9603ac 100644 (file)
@@ -259,14 +259,15 @@ static int __init msr_init(void)
                goto out_chrdev;
        }
        msr_class->devnode = msr_devnode;
-       get_online_cpus();
+
+       cpu_notifier_register_begin();
        for_each_online_cpu(i) {
                err = msr_device_create(i);
                if (err != 0)
                        goto out_class;
        }
-       register_hotcpu_notifier(&msr_class_cpu_notifier);
-       put_online_cpus();
+       __register_hotcpu_notifier(&msr_class_cpu_notifier);
+       cpu_notifier_register_done();
 
        err = 0;
        goto out;
@@ -275,7 +276,7 @@ out_class:
        i = 0;
        for_each_online_cpu(i)
                msr_device_destroy(i);
-       put_online_cpus();
+       cpu_notifier_register_done();
        class_destroy(msr_class);
 out_chrdev:
        __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
@@ -286,13 +287,14 @@ out:
 static void __exit msr_exit(void)
 {
        int cpu = 0;
-       get_online_cpus();
+
+       cpu_notifier_register_begin();
        for_each_online_cpu(cpu)
                msr_device_destroy(cpu);
        class_destroy(msr_class);
        __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
-       unregister_hotcpu_notifier(&msr_class_cpu_notifier);
-       put_online_cpus();
+       __unregister_hotcpu_notifier(&msr_class_cpu_notifier);
+       cpu_notifier_register_done();
 }
 
 module_init(msr_init);
index 9ea2876..8b3b3eb 100644 (file)
@@ -348,9 +348,13 @@ static int __init vsyscall_init(void)
 {
        BUG_ON(VSYSCALL_ADDR(0) != __fix_to_virt(VSYSCALL_FIRST_PAGE));
 
+       cpu_notifier_register_begin();
+
        on_each_cpu(cpu_vsyscall_init, NULL, 1);
        /* notifier priority > KVM */
-       hotcpu_notifier(cpu_vsyscall_notifier, 30);
+       __hotcpu_notifier(cpu_vsyscall_notifier, 30);
+
+       cpu_notifier_register_done();
 
        return 0;
 }
index d1c55f8..9d1b5cd 100644 (file)
@@ -5422,7 +5422,8 @@ static void kvm_timer_init(void)
        int cpu;
 
        max_tsc_khz = tsc_khz;
-       register_hotcpu_notifier(&kvmclock_cpu_notifier_block);
+
+       cpu_notifier_register_begin();
        if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
 #ifdef CONFIG_CPU_FREQ
                struct cpufreq_policy policy;
@@ -5439,6 +5440,10 @@ static void kvm_timer_init(void)
        pr_debug("kvm: max_tsc_khz = %ld\n", max_tsc_khz);
        for_each_online_cpu(cpu)
                smp_call_function_single(cpu, tsc_khz_changed, NULL, 1);
+
+       __register_hotcpu_notifier(&kvmclock_cpu_notifier_block);
+       cpu_notifier_register_done();
+
 }
 
 static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu);
index 799580c..597ac15 100644 (file)
@@ -328,17 +328,6 @@ void unxlate_dev_mem_ptr(unsigned long phys, void *addr)
        return;
 }
 
-static int __initdata early_ioremap_debug;
-
-static int __init early_ioremap_debug_setup(char *str)
-{
-       early_ioremap_debug = 1;
-
-       return 0;
-}
-early_param("early_ioremap_debug", early_ioremap_debug_setup);
-
-static __initdata int after_paging_init;
 static pte_t bm_pte[PAGE_SIZE/sizeof(pte_t)] __page_aligned_bss;
 
 static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
@@ -362,18 +351,11 @@ bool __init is_early_ioremap_ptep(pte_t *ptep)
        return ptep >= &bm_pte[0] && ptep < &bm_pte[PAGE_SIZE/sizeof(pte_t)];
 }
 
-static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata;
-
 void __init early_ioremap_init(void)
 {
        pmd_t *pmd;
-       int i;
 
-       if (early_ioremap_debug)
-               printk(KERN_INFO "early_ioremap_init()\n");
-
-       for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
-               slot_virt[i] = __fix_to_virt(FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*i);
+       early_ioremap_setup();
 
        pmd = early_ioremap_pmd(fix_to_virt(FIX_BTMAP_BEGIN));
        memset(bm_pte, 0, sizeof(bm_pte));
@@ -402,13 +384,8 @@ void __init early_ioremap_init(void)
        }
 }
 
-void __init early_ioremap_reset(void)
-{
-       after_paging_init = 1;
-}
-
-static void __init __early_set_fixmap(enum fixed_addresses idx,
-                                     phys_addr_t phys, pgprot_t flags)
+void __init __early_set_fixmap(enum fixed_addresses idx,
+                              phys_addr_t phys, pgprot_t flags)
 {
        unsigned long addr = __fix_to_virt(idx);
        pte_t *pte;
@@ -425,198 +402,3 @@ static void __init __early_set_fixmap(enum fixed_addresses idx,
                pte_clear(&init_mm, addr, pte);
        __flush_tlb_one(addr);
 }
-
-static inline void __init early_set_fixmap(enum fixed_addresses idx,
-                                          phys_addr_t phys, pgprot_t prot)
-{
-       if (after_paging_init)
-               __set_fixmap(idx, phys, prot);
-       else
-               __early_set_fixmap(idx, phys, prot);
-}
-
-static inline void __init early_clear_fixmap(enum fixed_addresses idx)
-{
-       if (after_paging_init)
-               clear_fixmap(idx);
-       else
-               __early_set_fixmap(idx, 0, __pgprot(0));
-}
-
-static void __iomem *prev_map[FIX_BTMAPS_SLOTS] __initdata;
-static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata;
-
-void __init fixup_early_ioremap(void)
-{
-       int i;
-
-       for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
-               if (prev_map[i]) {
-                       WARN_ON(1);
-                       break;
-               }
-       }
-
-       early_ioremap_init();
-}
-
-static int __init check_early_ioremap_leak(void)
-{
-       int count = 0;
-       int i;
-
-       for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
-               if (prev_map[i])
-                       count++;
-
-       if (!count)
-               return 0;
-       WARN(1, KERN_WARNING
-              "Debug warning: early ioremap leak of %d areas detected.\n",
-               count);
-       printk(KERN_WARNING
-               "please boot with early_ioremap_debug and report the dmesg.\n");
-
-       return 1;
-}
-late_initcall(check_early_ioremap_leak);
-
-static void __init __iomem *
-__early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot)
-{
-       unsigned long offset;
-       resource_size_t last_addr;
-       unsigned int nrpages;
-       enum fixed_addresses idx;
-       int i, slot;
-
-       WARN_ON(system_state != SYSTEM_BOOTING);
-
-       slot = -1;
-       for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
-               if (!prev_map[i]) {
-                       slot = i;
-                       break;
-               }
-       }
-
-       if (slot < 0) {
-               printk(KERN_INFO "%s(%08llx, %08lx) not found slot\n",
-                      __func__, (u64)phys_addr, size);
-               WARN_ON(1);
-               return NULL;
-       }
-
-       if (early_ioremap_debug) {
-               printk(KERN_INFO "%s(%08llx, %08lx) [%d] => ",
-                      __func__, (u64)phys_addr, size, slot);
-               dump_stack();
-       }
-
-       /* Don't allow wraparound or zero size */
-       last_addr = phys_addr + size - 1;
-       if (!size || last_addr < phys_addr) {
-               WARN_ON(1);
-               return NULL;
-       }
-
-       prev_size[slot] = size;
-       /*
-        * Mappings have to be page-aligned
-        */
-       offset = phys_addr & ~PAGE_MASK;
-       phys_addr &= PAGE_MASK;
-       size = PAGE_ALIGN(last_addr + 1) - phys_addr;
-
-       /*
-        * Mappings have to fit in the FIX_BTMAP area.
-        */
-       nrpages = size >> PAGE_SHIFT;
-       if (nrpages > NR_FIX_BTMAPS) {
-               WARN_ON(1);
-               return NULL;
-       }
-
-       /*
-        * Ok, go for it..
-        */
-       idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
-       while (nrpages > 0) {
-               early_set_fixmap(idx, phys_addr, prot);
-               phys_addr += PAGE_SIZE;
-               --idx;
-               --nrpages;
-       }
-       if (early_ioremap_debug)
-               printk(KERN_CONT "%08lx + %08lx\n", offset, slot_virt[slot]);
-
-       prev_map[slot] = (void __iomem *)(offset + slot_virt[slot]);
-       return prev_map[slot];
-}
-
-/* Remap an IO device */
-void __init __iomem *
-early_ioremap(resource_size_t phys_addr, unsigned long size)
-{
-       return __early_ioremap(phys_addr, size, PAGE_KERNEL_IO);
-}
-
-/* Remap memory */
-void __init __iomem *
-early_memremap(resource_size_t phys_addr, unsigned long size)
-{
-       return __early_ioremap(phys_addr, size, PAGE_KERNEL);
-}
-
-void __init early_iounmap(void __iomem *addr, unsigned long size)
-{
-       unsigned long virt_addr;
-       unsigned long offset;
-       unsigned int nrpages;
-       enum fixed_addresses idx;
-       int i, slot;
-
-       slot = -1;
-       for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
-               if (prev_map[i] == addr) {
-                       slot = i;
-                       break;
-               }
-       }
-
-       if (slot < 0) {
-               printk(KERN_INFO "early_iounmap(%p, %08lx) not found slot\n",
-                        addr, size);
-               WARN_ON(1);
-               return;
-       }
-
-       if (prev_size[slot] != size) {
-               printk(KERN_INFO "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n",
-                        addr, size, slot, prev_size[slot]);
-               WARN_ON(1);
-               return;
-       }
-
-       if (early_ioremap_debug) {
-               printk(KERN_INFO "early_iounmap(%p, %08lx) [%d]\n", addr,
-                      size, slot);
-               dump_stack();
-       }
-
-       virt_addr = (unsigned long)addr;
-       if (virt_addr < fix_to_virt(FIX_BTMAP_BEGIN)) {
-               WARN_ON(1);
-               return;
-       }
-       offset = virt_addr & ~PAGE_MASK;
-       nrpages = PAGE_ALIGN(offset + size) >> PAGE_SHIFT;
-
-       idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
-       while (nrpages > 0) {
-               early_clear_fixmap(idx);
-               --idx;
-               --nrpages;
-       }
-       prev_map[slot] = NULL;
-}
index d87dd6d..dd89a13 100644 (file)
@@ -78,10 +78,16 @@ early_initcall(kmemcheck_init);
  */
 static int __init param_kmemcheck(char *str)
 {
+       int val;
+       int ret;
+
        if (!str)
                return -EINVAL;
 
-       sscanf(str, "%d", &kmemcheck_enabled);
+       ret = kstrtoint(str, 0, &val);
+       if (ret)
+               return ret;
+       kmemcheck_enabled = val;
        return 0;
 }
 
index a69bcb8..4dd8cf6 100644 (file)
@@ -127,7 +127,7 @@ static int __init parse_reservetop(char *arg)
 
        address = memparse(arg, &arg);
        reserve_top_address(address);
-       fixup_early_ioremap();
+       early_ioremap_init();
        return 0;
 }
 early_param("reservetop", parse_reservetop);
index 6890d84..379e8bd 100644 (file)
@@ -494,14 +494,19 @@ static int nmi_setup(void)
        if (err)
                goto fail;
 
+       cpu_notifier_register_begin();
+
+       /* Use get/put_online_cpus() to protect 'nmi_enabled' */
        get_online_cpus();
-       register_cpu_notifier(&oprofile_cpu_nb);
        nmi_enabled = 1;
        /* make nmi_enabled visible to the nmi handler: */
        smp_mb();
        on_each_cpu(nmi_cpu_setup, NULL, 1);
+       __register_cpu_notifier(&oprofile_cpu_nb);
        put_online_cpus();
 
+       cpu_notifier_register_done();
+
        return 0;
 fail:
        free_msrs();
@@ -512,12 +517,18 @@ static void nmi_shutdown(void)
 {
        struct op_msrs *msrs;
 
+       cpu_notifier_register_begin();
+
+       /* Use get/put_online_cpus() to protect 'nmi_enabled' & 'ctr_running' */
        get_online_cpus();
-       unregister_cpu_notifier(&oprofile_cpu_nb);
        on_each_cpu(nmi_cpu_shutdown, NULL, 1);
        nmi_enabled = 0;
        ctr_running = 0;
+       __unregister_cpu_notifier(&oprofile_cpu_nb);
        put_online_cpus();
+
+       cpu_notifier_register_done();
+
        /* make variables visible to the nmi handler: */
        smp_mb();
        unregister_nmi_handler(NMI_LOCAL, "oprofile");
index a313a7f..e88f4c5 100644 (file)
@@ -370,10 +370,13 @@ static int __init pci_io_ecs_init(void)
        if (early_pci_allowed())
                pci_enable_pci_io_ecs();
 
-       register_cpu_notifier(&amd_cpu_notifier);
+       cpu_notifier_register_begin();
        for_each_online_cpu(cpu)
                amd_cpu_notify(&amd_cpu_notifier, (unsigned long)CPU_ONLINE,
                               (void *)(long)cpu);
+       __register_cpu_notifier(&amd_cpu_notifier);
+       cpu_notifier_register_done();
+
        pci_probe |= PCI_HAS_IO_ECS;
 
        return 0;
index c87ae7c..02d6d29 100644 (file)
@@ -41,7 +41,7 @@ config ARCH_HAS_ILOG2_U32
 config ARCH_HAS_ILOG2_U64
        def_bool n
 
-config NO_IOPORT
+config NO_IOPORT_MAP
        def_bool n
 
 config HZ
@@ -239,7 +239,7 @@ config XTENSA_PLATFORM_XT2000
 config XTENSA_PLATFORM_S6105
        bool "S6105"
        select SERIAL_CONSOLE
-       select NO_IOPORT
+       select NO_IOPORT_MAP
 
 config XTENSA_PLATFORM_XTFPGA
        bool "XTFPGA"
index 4f23320..d57d917 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_NO_IOPORT=y
+CONFIG_NO_IOPORT_MAP=y
 CONFIG_HZ=100
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 CONFIG_CONSTRUCTORS=y
index d929f77..583c2b0 100644 (file)
@@ -11,7 +11,7 @@ CONFIG_GENERIC_FIND_NEXT_BIT=y
 CONFIG_GENERIC_HWEIGHT=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
-CONFIG_NO_IOPORT=y
+CONFIG_NO_IOPORT_MAP=y
 CONFIG_HZ=100
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
index 34d7c19..a0e3096 100644 (file)
@@ -1307,7 +1307,7 @@ void __blk_put_request(struct request_queue *q, struct request *req)
                struct request_list *rl = blk_rq_rl(req);
 
                BUG_ON(!list_empty(&req->queuelist));
-               BUG_ON(!hlist_unhashed(&req->hash));
+               BUG_ON(ELV_ON_HASH(req));
 
                blk_free_request(rl, req);
                freed_request(rl, flags);
index b1bcc61..1d2a9bd 100644 (file)
@@ -956,6 +956,7 @@ static void blk_mq_hctx_notify(void *data, unsigned long action,
                               unsigned int cpu)
 {
        struct blk_mq_hw_ctx *hctx = data;
+       struct request_queue *q = hctx->queue;
        struct blk_mq_ctx *ctx;
        LIST_HEAD(tmp);
 
@@ -965,7 +966,7 @@ static void blk_mq_hctx_notify(void *data, unsigned long action,
        /*
         * Move ctx entries to new CPU, if this one is going away.
         */
-       ctx = __blk_mq_get_ctx(hctx->queue, cpu);
+       ctx = __blk_mq_get_ctx(q, cpu);
 
        spin_lock(&ctx->lock);
        if (!list_empty(&ctx->rq_list)) {
@@ -977,7 +978,7 @@ static void blk_mq_hctx_notify(void *data, unsigned long action,
        if (list_empty(&tmp))
                return;
 
-       ctx = blk_mq_get_ctx(hctx->queue);
+       ctx = blk_mq_get_ctx(q);
        spin_lock(&ctx->lock);
 
        while (!list_empty(&tmp)) {
@@ -988,10 +989,13 @@ static void blk_mq_hctx_notify(void *data, unsigned long action,
                list_move_tail(&rq->queuelist, &ctx->rq_list);
        }
 
+       hctx = q->mq_ops->map_queue(q, ctx->cpu);
        blk_mq_hctx_mark_pending(hctx, ctx);
 
        spin_unlock(&ctx->lock);
        blk_mq_put_ctx(ctx);
+
+       blk_mq_run_hw_queue(hctx, true);
 }
 
 static int blk_mq_init_hw_commands(struct blk_mq_hw_ctx *hctx,
index ebd6b6f..53b1737 100644 (file)
@@ -30,8 +30,8 @@ static void blk_done_softirq(struct softirq_action *h)
        while (!list_empty(&local_list)) {
                struct request *rq;
 
-               rq = list_entry(local_list.next, struct request, queuelist);
-               list_del_init(&rq->queuelist);
+               rq = list_entry(local_list.next, struct request, ipi_list);
+               list_del_init(&rq->ipi_list);
                rq->q->softirq_done_fn(rq);
        }
 }
@@ -45,14 +45,9 @@ static void trigger_softirq(void *data)
 
        local_irq_save(flags);
        list = this_cpu_ptr(&blk_cpu_done);
-       /*
-        * We reuse queuelist for a list of requests to process. Since the
-        * queuelist is used by the block layer only for requests waiting to be
-        * submitted to the device it is unused now.
-        */
-       list_add_tail(&rq->queuelist, list);
+       list_add_tail(&rq->ipi_list, list);
 
-       if (list->next == &rq->queuelist)
+       if (list->next == &rq->ipi_list)
                raise_softirq_irqoff(BLOCK_SOFTIRQ);
 
        local_irq_restore(flags);
@@ -141,7 +136,7 @@ void __blk_complete_request(struct request *req)
                struct list_head *list;
 do_local:
                list = this_cpu_ptr(&blk_cpu_done);
-               list_add_tail(&req->queuelist, list);
+               list_add_tail(&req->ipi_list, list);
 
                /*
                 * if the list only contains our just added request,
@@ -149,7 +144,7 @@ do_local:
                 * entries there, someone already raised the irq but it
                 * hasn't run yet.
                 */
-               if (list->next == &req->queuelist)
+               if (list->next == &req->ipi_list)
                        raise_softirq_irqoff(BLOCK_SOFTIRQ);
        } else if (raise_blk_irq(ccpu, req))
                goto do_local;
index d23b415..1d880f1 100644 (file)
@@ -78,7 +78,7 @@ static inline void blk_clear_rq_complete(struct request *rq)
 /*
  * Internal elevator interface
  */
-#define ELV_ON_HASH(rq) hash_hashed(&(rq)->hash)
+#define ELV_ON_HASH(rq) ((rq)->cmd_flags & REQ_HASHED)
 
 void blk_insert_flush(struct request *rq);
 void blk_abort_flushes(struct request_queue *q);
index 42c45a7..1e01b66 100644 (file)
@@ -247,6 +247,7 @@ EXPORT_SYMBOL(elevator_exit);
 static inline void __elv_rqhash_del(struct request *rq)
 {
        hash_del(&rq->hash);
+       rq->cmd_flags &= ~REQ_HASHED;
 }
 
 static void elv_rqhash_del(struct request_queue *q, struct request *rq)
@@ -261,6 +262,7 @@ static void elv_rqhash_add(struct request_queue *q, struct request *rq)
 
        BUG_ON(ELV_ON_HASH(rq));
        hash_add(e->hash, &rq->hash, rq_hash_key(rq));
+       rq->cmd_flags |= REQ_HASHED;
 }
 
 static void elv_rqhash_reposition(struct request_queue *q, struct request *rq)
index ad9d177..bbcbd3c 100644 (file)
@@ -160,16 +160,20 @@ static int topology_cpu_callback(struct notifier_block *nfb,
 static int topology_sysfs_init(void)
 {
        int cpu;
-       int rc;
+       int rc = 0;
+
+       cpu_notifier_register_begin();
 
        for_each_online_cpu(cpu) {
                rc = topology_add_dev(cpu);
                if (rc)
-                       return rc;
+                       goto out;
        }
-       hotcpu_notifier(topology_cpu_callback, 0);
+       __hotcpu_notifier(topology_cpu_callback, 0);
 
-       return 0;
+out:
+       cpu_notifier_register_done();
+       return rc;
 }
 
 device_initcall(topology_sysfs_init);
index 66e8c3b..f70a230 100644 (file)
@@ -237,7 +237,7 @@ static int __do_lo_send_write(struct file *file,
        file_end_write(file);
        if (likely(bw == len))
                return 0;
-       printk(KERN_ERR "loop: Write error at byte offset %llu, length %i.\n",
+       printk_ratelimited(KERN_ERR "loop: Write error at byte offset %llu, length %i.\n",
                        (unsigned long long)pos, len);
        if (bw >= 0)
                bw = -EIO;
@@ -277,7 +277,7 @@ static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec,
                return __do_lo_send_write(lo->lo_backing_file,
                                page_address(page), bvec->bv_len,
                                pos);
-       printk(KERN_ERR "loop: Transfer error at byte offset %llu, "
+       printk_ratelimited(KERN_ERR "loop: Transfer error at byte offset %llu, "
                        "length %i.\n", (unsigned long long)pos, bvec->bv_len);
        if (ret > 0)
                ret = -EIO;
@@ -316,7 +316,7 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos)
 out:
        return ret;
 fail:
-       printk(KERN_ERR "loop: Failed to allocate temporary page for write.\n");
+       printk_ratelimited(KERN_ERR "loop: Failed to allocate temporary page for write.\n");
        ret = -ENOMEM;
        goto out;
 }
@@ -345,7 +345,7 @@ lo_splice_actor(struct pipe_inode_info *pipe, struct pipe_buffer *buf,
                size = p->bsize;
 
        if (lo_do_transfer(lo, READ, page, buf->offset, p->page, p->offset, size, IV)) {
-               printk(KERN_ERR "loop: transfer error block %ld\n",
+               printk_ratelimited(KERN_ERR "loop: transfer error block %ld\n",
                       page->index);
                size = -EINVAL;
        }
index 34898d5..4c95b50 100644 (file)
@@ -1654,7 +1654,7 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
        if (osd_req->r_result < 0)
                obj_request->result = osd_req->r_result;
 
-       BUG_ON(osd_req->r_num_ops > 2);
+       rbd_assert(osd_req->r_num_ops <= CEPH_OSD_MAX_OP);
 
        /*
         * We support a 64-bit length, but ultimately it has to be
@@ -1662,11 +1662,15 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
         */
        obj_request->xferred = osd_req->r_reply_op_len[0];
        rbd_assert(obj_request->xferred < (u64)UINT_MAX);
+
        opcode = osd_req->r_ops[0].op;
        switch (opcode) {
        case CEPH_OSD_OP_READ:
                rbd_osd_read_callback(obj_request);
                break;
+       case CEPH_OSD_OP_SETALLOCHINT:
+               rbd_assert(osd_req->r_ops[1].op == CEPH_OSD_OP_WRITE);
+               /* fall through */
        case CEPH_OSD_OP_WRITE:
                rbd_osd_write_callback(obj_request);
                break;
@@ -1715,9 +1719,16 @@ static void rbd_osd_req_format_write(struct rbd_obj_request *obj_request)
                        snapc, CEPH_NOSNAP, &mtime);
 }
 
+/*
+ * Create an osd request.  A read request has one osd op (read).
+ * A write request has either one (watch) or two (hint+write) osd ops.
+ * (All rbd data writes are prefixed with an allocation hint op, but
+ * technically osd watch is a write request, hence this distinction.)
+ */
 static struct ceph_osd_request *rbd_osd_req_create(
                                        struct rbd_device *rbd_dev,
                                        bool write_request,
+                                       unsigned int num_ops,
                                        struct rbd_obj_request *obj_request)
 {
        struct ceph_snap_context *snapc = NULL;
@@ -1733,10 +1744,13 @@ static struct ceph_osd_request *rbd_osd_req_create(
                        snapc = img_request->snapc;
        }
 
-       /* Allocate and initialize the request, for the single op */
+       rbd_assert(num_ops == 1 || (write_request && num_ops == 2));
+
+       /* Allocate and initialize the request, for the num_ops ops */
 
        osdc = &rbd_dev->rbd_client->client->osdc;
-       osd_req = ceph_osdc_alloc_request(osdc, snapc, 1, false, GFP_ATOMIC);
+       osd_req = ceph_osdc_alloc_request(osdc, snapc, num_ops, false,
+                                         GFP_ATOMIC);
        if (!osd_req)
                return NULL;    /* ENOMEM */
 
@@ -1756,8 +1770,8 @@ static struct ceph_osd_request *rbd_osd_req_create(
 
 /*
  * Create a copyup osd request based on the information in the
- * object request supplied.  A copyup request has two osd ops,
- * a copyup method call, and a "normal" write request.
+ * object request supplied.  A copyup request has three osd ops,
+ * a copyup method call, a hint op, and a write op.
  */
 static struct ceph_osd_request *
 rbd_osd_req_create_copyup(struct rbd_obj_request *obj_request)
@@ -1773,12 +1787,12 @@ rbd_osd_req_create_copyup(struct rbd_obj_request *obj_request)
        rbd_assert(img_request);
        rbd_assert(img_request_write_test(img_request));
 
-       /* Allocate and initialize the request, for the two ops */
+       /* Allocate and initialize the request, for the three ops */
 
        snapc = img_request->snapc;
        rbd_dev = img_request->rbd_dev;
        osdc = &rbd_dev->rbd_client->client->osdc;
-       osd_req = ceph_osdc_alloc_request(osdc, snapc, 2, false, GFP_ATOMIC);
+       osd_req = ceph_osdc_alloc_request(osdc, snapc, 3, false, GFP_ATOMIC);
        if (!osd_req)
                return NULL;    /* ENOMEM */
 
@@ -2178,6 +2192,7 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
                const char *object_name;
                u64 offset;
                u64 length;
+               unsigned int which = 0;
 
                object_name = rbd_segment_name(rbd_dev, img_offset);
                if (!object_name)
@@ -2190,6 +2205,7 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
                rbd_segment_name_free(object_name);
                if (!obj_request)
                        goto out_unwind;
+
                /*
                 * set obj_request->img_request before creating the
                 * osd_request so that it gets the right snapc
@@ -2207,7 +2223,7 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
                                                                clone_size,
                                                                GFP_ATOMIC);
                        if (!obj_request->bio_list)
-                               goto out_partial;
+                               goto out_unwind;
                } else {
                        unsigned int page_count;
 
@@ -2220,19 +2236,27 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
                }
 
                osd_req = rbd_osd_req_create(rbd_dev, write_request,
-                                               obj_request);
+                                            (write_request ? 2 : 1),
+                                            obj_request);
                if (!osd_req)
-                       goto out_partial;
+                       goto out_unwind;
                obj_request->osd_req = osd_req;
                obj_request->callback = rbd_img_obj_callback;
 
-               osd_req_op_extent_init(osd_req, 0, opcode, offset, length,
-                                               0, 0);
+               if (write_request) {
+                       osd_req_op_alloc_hint_init(osd_req, which,
+                                            rbd_obj_bytes(&rbd_dev->header),
+                                            rbd_obj_bytes(&rbd_dev->header));
+                       which++;
+               }
+
+               osd_req_op_extent_init(osd_req, which, opcode, offset, length,
+                                      0, 0);
                if (type == OBJ_REQUEST_BIO)
-                       osd_req_op_extent_osd_data_bio(osd_req, 0,
+                       osd_req_op_extent_osd_data_bio(osd_req, which,
                                        obj_request->bio_list, length);
                else
-                       osd_req_op_extent_osd_data_pages(osd_req, 0,
+                       osd_req_op_extent_osd_data_pages(osd_req, which,
                                        obj_request->pages, length,
                                        offset & ~PAGE_MASK, false, false);
 
@@ -2249,11 +2273,9 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
 
        return 0;
 
-out_partial:
-       rbd_obj_request_put(obj_request);
 out_unwind:
        for_each_obj_request_safe(img_request, obj_request, next_obj_request)
-               rbd_obj_request_put(obj_request);
+               rbd_img_obj_request_del(img_request, obj_request);
 
        return -ENOMEM;
 }
@@ -2353,7 +2375,7 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
 
        /*
         * The original osd request is of no use to use any more.
-        * We need a new one that can hold the two ops in a copyup
+        * We need a new one that can hold the three ops in a copyup
         * request.  Allocate the new copyup osd request for the
         * original request, and release the old one.
         */
@@ -2372,17 +2394,22 @@ rbd_img_obj_parent_read_full_callback(struct rbd_img_request *img_request)
        osd_req_op_cls_request_data_pages(osd_req, 0, pages, parent_length, 0,
                                                false, false);
 
-       /* Then the original write request op */
+       /* Then the hint op */
+
+       osd_req_op_alloc_hint_init(osd_req, 1, rbd_obj_bytes(&rbd_dev->header),
+                                  rbd_obj_bytes(&rbd_dev->header));
+
+       /* And the original write request op */
 
        offset = orig_request->offset;
        length = orig_request->length;
-       osd_req_op_extent_init(osd_req, 1, CEPH_OSD_OP_WRITE,
+       osd_req_op_extent_init(osd_req, 2, CEPH_OSD_OP_WRITE,
                                        offset, length, 0, 0);
        if (orig_request->type == OBJ_REQUEST_BIO)
-               osd_req_op_extent_osd_data_bio(osd_req, 1,
+               osd_req_op_extent_osd_data_bio(osd_req, 2,
                                        orig_request->bio_list, length);
        else
-               osd_req_op_extent_osd_data_pages(osd_req, 1,
+               osd_req_op_extent_osd_data_pages(osd_req, 2,
                                        orig_request->pages, length,
                                        offset & ~PAGE_MASK, false, false);
 
@@ -2603,8 +2630,8 @@ static int rbd_img_obj_exists_submit(struct rbd_obj_request *obj_request)
 
        rbd_assert(obj_request->img_request);
        rbd_dev = obj_request->img_request->rbd_dev;
-       stat_request->osd_req = rbd_osd_req_create(rbd_dev, false,
-                                               stat_request);
+       stat_request->osd_req = rbd_osd_req_create(rbd_dev, false, 1,
+                                                  stat_request);
        if (!stat_request->osd_req)
                goto out;
        stat_request->callback = rbd_img_obj_exists_callback;
@@ -2807,7 +2834,8 @@ static int rbd_obj_notify_ack_sync(struct rbd_device *rbd_dev, u64 notify_id)
                return -ENOMEM;
 
        ret = -ENOMEM;
-       obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, obj_request);
+       obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, 1,
+                                                 obj_request);
        if (!obj_request->osd_req)
                goto out;
 
@@ -2870,7 +2898,8 @@ static int __rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start)
        if (!obj_request)
                goto out_cancel;
 
-       obj_request->osd_req = rbd_osd_req_create(rbd_dev, true, obj_request);
+       obj_request->osd_req = rbd_osd_req_create(rbd_dev, true, 1,
+                                                 obj_request);
        if (!obj_request->osd_req)
                goto out_cancel;
 
@@ -2978,7 +3007,8 @@ static int rbd_obj_method_sync(struct rbd_device *rbd_dev,
        obj_request->pages = pages;
        obj_request->page_count = page_count;
 
-       obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, obj_request);
+       obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, 1,
+                                                 obj_request);
        if (!obj_request->osd_req)
                goto out;
 
@@ -3211,7 +3241,8 @@ static int rbd_obj_read_sync(struct rbd_device *rbd_dev,
        obj_request->pages = pages;
        obj_request->page_count = page_count;
 
-       obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, obj_request);
+       obj_request->osd_req = rbd_osd_req_create(rbd_dev, false, 1,
+                                                 obj_request);
        if (!obj_request->osd_req)
                goto out;
 
index 3450be8..6489c0f 100644 (file)
@@ -15,6 +15,16 @@ config ZRAM
 
          See zram.txt for more information.
 
+config ZRAM_LZ4_COMPRESS
+       bool "Enable LZ4 algorithm support"
+       depends on ZRAM
+       select LZ4_COMPRESS
+       select LZ4_DECOMPRESS
+       default n
+       help
+         This option enables LZ4 compression algorithm support. Compression
+         algorithm can be changed using `comp_algorithm' device attribute.
+
 config ZRAM_DEBUG
        bool "Compressed RAM block device debug support"
        depends on ZRAM
index cb0f9ce..be0763f 100644 (file)
@@ -1,3 +1,5 @@
-zram-y :=      zram_drv.o
+zram-y :=      zcomp_lzo.o zcomp.o zram_drv.o
+
+zram-$(CONFIG_ZRAM_LZ4_COMPRESS) += zcomp_lz4.o
 
 obj-$(CONFIG_ZRAM)     +=      zram.o
diff --git a/drivers/block/zram/zcomp.c b/drivers/block/zram/zcomp.c
new file mode 100644 (file)
index 0000000..f1ff39a
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+
+#include "zcomp.h"
+#include "zcomp_lzo.h"
+#ifdef CONFIG_ZRAM_LZ4_COMPRESS
+#include "zcomp_lz4.h"
+#endif
+
+/*
+ * single zcomp_strm backend
+ */
+struct zcomp_strm_single {
+       struct mutex strm_lock;
+       struct zcomp_strm *zstrm;
+};
+
+/*
+ * multi zcomp_strm backend
+ */
+struct zcomp_strm_multi {
+       /* protect strm list */
+       spinlock_t strm_lock;
+       /* max possible number of zstrm streams */
+       int max_strm;
+       /* number of available zstrm streams */
+       int avail_strm;
+       /* list of available strms */
+       struct list_head idle_strm;
+       wait_queue_head_t strm_wait;
+};
+
+static struct zcomp_backend *backends[] = {
+       &zcomp_lzo,
+#ifdef CONFIG_ZRAM_LZ4_COMPRESS
+       &zcomp_lz4,
+#endif
+       NULL
+};
+
+static struct zcomp_backend *find_backend(const char *compress)
+{
+       int i = 0;
+       while (backends[i]) {
+               if (sysfs_streq(compress, backends[i]->name))
+                       break;
+               i++;
+       }
+       return backends[i];
+}
+
+static void zcomp_strm_free(struct zcomp *comp, struct zcomp_strm *zstrm)
+{
+       if (zstrm->private)
+               comp->backend->destroy(zstrm->private);
+       free_pages((unsigned long)zstrm->buffer, 1);
+       kfree(zstrm);
+}
+
+/*
+ * allocate new zcomp_strm structure with ->private initialized by
+ * backend, return NULL on error
+ */
+static struct zcomp_strm *zcomp_strm_alloc(struct zcomp *comp)
+{
+       struct zcomp_strm *zstrm = kmalloc(sizeof(*zstrm), GFP_KERNEL);
+       if (!zstrm)
+               return NULL;
+
+       zstrm->private = comp->backend->create();
+       /*
+        * allocate 2 pages. 1 for compressed data, plus 1 extra for the
+        * case when compressed size is larger than the original one
+        */
+       zstrm->buffer = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
+       if (!zstrm->private || !zstrm->buffer) {
+               zcomp_strm_free(comp, zstrm);
+               zstrm = NULL;
+       }
+       return zstrm;
+}
+
+/*
+ * get idle zcomp_strm or wait until other process release
+ * (zcomp_strm_release()) one for us
+ */
+static struct zcomp_strm *zcomp_strm_multi_find(struct zcomp *comp)
+{
+       struct zcomp_strm_multi *zs = comp->stream;
+       struct zcomp_strm *zstrm;
+
+       while (1) {
+               spin_lock(&zs->strm_lock);
+               if (!list_empty(&zs->idle_strm)) {
+                       zstrm = list_entry(zs->idle_strm.next,
+                                       struct zcomp_strm, list);
+                       list_del(&zstrm->list);
+                       spin_unlock(&zs->strm_lock);
+                       return zstrm;
+               }
+               /* zstrm streams limit reached, wait for idle stream */
+               if (zs->avail_strm >= zs->max_strm) {
+                       spin_unlock(&zs->strm_lock);
+                       wait_event(zs->strm_wait, !list_empty(&zs->idle_strm));
+                       continue;
+               }
+               /* allocate new zstrm stream */
+               zs->avail_strm++;
+               spin_unlock(&zs->strm_lock);
+
+               zstrm = zcomp_strm_alloc(comp);
+               if (!zstrm) {
+                       spin_lock(&zs->strm_lock);
+                       zs->avail_strm--;
+                       spin_unlock(&zs->strm_lock);
+                       wait_event(zs->strm_wait, !list_empty(&zs->idle_strm));
+                       continue;
+               }
+               break;
+       }
+       return zstrm;
+}
+
+/* add stream back to idle list and wake up waiter or free the stream */
+static void zcomp_strm_multi_release(struct zcomp *comp, struct zcomp_strm *zstrm)
+{
+       struct zcomp_strm_multi *zs = comp->stream;
+
+       spin_lock(&zs->strm_lock);
+       if (zs->avail_strm <= zs->max_strm) {
+               list_add(&zstrm->list, &zs->idle_strm);
+               spin_unlock(&zs->strm_lock);
+               wake_up(&zs->strm_wait);
+               return;
+       }
+
+       zs->avail_strm--;
+       spin_unlock(&zs->strm_lock);
+       zcomp_strm_free(comp, zstrm);
+}
+
+/* change max_strm limit */
+static bool zcomp_strm_multi_set_max_streams(struct zcomp *comp, int num_strm)
+{
+       struct zcomp_strm_multi *zs = comp->stream;
+       struct zcomp_strm *zstrm;
+
+       spin_lock(&zs->strm_lock);
+       zs->max_strm = num_strm;
+       /*
+        * if user has lowered the limit and there are idle streams,
+        * immediately free as much streams (and memory) as we can.
+        */
+       while (zs->avail_strm > num_strm && !list_empty(&zs->idle_strm)) {
+               zstrm = list_entry(zs->idle_strm.next,
+                               struct zcomp_strm, list);
+               list_del(&zstrm->list);
+               zcomp_strm_free(comp, zstrm);
+               zs->avail_strm--;
+       }
+       spin_unlock(&zs->strm_lock);
+       return true;
+}
+
+static void zcomp_strm_multi_destroy(struct zcomp *comp)
+{
+       struct zcomp_strm_multi *zs = comp->stream;
+       struct zcomp_strm *zstrm;
+
+       while (!list_empty(&zs->idle_strm)) {
+               zstrm = list_entry(zs->idle_strm.next,
+                               struct zcomp_strm, list);
+               list_del(&zstrm->list);
+               zcomp_strm_free(comp, zstrm);
+       }
+       kfree(zs);
+}
+
+static int zcomp_strm_multi_create(struct zcomp *comp, int max_strm)
+{
+       struct zcomp_strm *zstrm;
+       struct zcomp_strm_multi *zs;
+
+       comp->destroy = zcomp_strm_multi_destroy;
+       comp->strm_find = zcomp_strm_multi_find;
+       comp->strm_release = zcomp_strm_multi_release;
+       comp->set_max_streams = zcomp_strm_multi_set_max_streams;
+       zs = kmalloc(sizeof(struct zcomp_strm_multi), GFP_KERNEL);
+       if (!zs)
+               return -ENOMEM;
+
+       comp->stream = zs;
+       spin_lock_init(&zs->strm_lock);
+       INIT_LIST_HEAD(&zs->idle_strm);
+       init_waitqueue_head(&zs->strm_wait);
+       zs->max_strm = max_strm;
+       zs->avail_strm = 1;
+
+       zstrm = zcomp_strm_alloc(comp);
+       if (!zstrm) {
+               kfree(zs);
+               return -ENOMEM;
+       }
+       list_add(&zstrm->list, &zs->idle_strm);
+       return 0;
+}
+
+static struct zcomp_strm *zcomp_strm_single_find(struct zcomp *comp)
+{
+       struct zcomp_strm_single *zs = comp->stream;
+       mutex_lock(&zs->strm_lock);
+       return zs->zstrm;
+}
+
+static void zcomp_strm_single_release(struct zcomp *comp,
+               struct zcomp_strm *zstrm)
+{
+       struct zcomp_strm_single *zs = comp->stream;
+       mutex_unlock(&zs->strm_lock);
+}
+
+static bool zcomp_strm_single_set_max_streams(struct zcomp *comp, int num_strm)
+{
+       /* zcomp_strm_single support only max_comp_streams == 1 */
+       return false;
+}
+
+static void zcomp_strm_single_destroy(struct zcomp *comp)
+{
+       struct zcomp_strm_single *zs = comp->stream;
+       zcomp_strm_free(comp, zs->zstrm);
+       kfree(zs);
+}
+
+static int zcomp_strm_single_create(struct zcomp *comp)
+{
+       struct zcomp_strm_single *zs;
+
+       comp->destroy = zcomp_strm_single_destroy;
+       comp->strm_find = zcomp_strm_single_find;
+       comp->strm_release = zcomp_strm_single_release;
+       comp->set_max_streams = zcomp_strm_single_set_max_streams;
+       zs = kmalloc(sizeof(struct zcomp_strm_single), GFP_KERNEL);
+       if (!zs)
+               return -ENOMEM;
+
+       comp->stream = zs;
+       mutex_init(&zs->strm_lock);
+       zs->zstrm = zcomp_strm_alloc(comp);
+       if (!zs->zstrm) {
+               kfree(zs);
+               return -ENOMEM;
+       }
+       return 0;
+}
+
+/* show available compressors */
+ssize_t zcomp_available_show(const char *comp, char *buf)
+{
+       ssize_t sz = 0;
+       int i = 0;
+
+       while (backends[i]) {
+               if (sysfs_streq(comp, backends[i]->name))
+                       sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
+                                       "[%s] ", backends[i]->name);
+               else
+                       sz += scnprintf(buf + sz, PAGE_SIZE - sz - 2,
+                                       "%s ", backends[i]->name);
+               i++;
+       }
+       sz += scnprintf(buf + sz, PAGE_SIZE - sz, "\n");
+       return sz;
+}
+
+bool zcomp_set_max_streams(struct zcomp *comp, int num_strm)
+{
+       return comp->set_max_streams(comp, num_strm);
+}
+
+struct zcomp_strm *zcomp_strm_find(struct zcomp *comp)
+{
+       return comp->strm_find(comp);
+}
+
+void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm)
+{
+       comp->strm_release(comp, zstrm);
+}
+
+int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
+               const unsigned char *src, size_t *dst_len)
+{
+       return comp->backend->compress(src, zstrm->buffer, dst_len,
+                       zstrm->private);
+}
+
+int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
+               size_t src_len, unsigned char *dst)
+{
+       return comp->backend->decompress(src, src_len, dst);
+}
+
+void zcomp_destroy(struct zcomp *comp)
+{
+       comp->destroy(comp);
+       kfree(comp);
+}
+
+/*
+ * search available compressors for requested algorithm.
+ * allocate new zcomp and initialize it. return compressing
+ * backend pointer or ERR_PTR if things went bad. ERR_PTR(-EINVAL)
+ * if requested algorithm is not supported, ERR_PTR(-ENOMEM) in
+ * case of allocation error.
+ */
+struct zcomp *zcomp_create(const char *compress, int max_strm)
+{
+       struct zcomp *comp;
+       struct zcomp_backend *backend;
+
+       backend = find_backend(compress);
+       if (!backend)
+               return ERR_PTR(-EINVAL);
+
+       comp = kzalloc(sizeof(struct zcomp), GFP_KERNEL);
+       if (!comp)
+               return ERR_PTR(-ENOMEM);
+
+       comp->backend = backend;
+       if (max_strm > 1)
+               zcomp_strm_multi_create(comp, max_strm);
+       else
+               zcomp_strm_single_create(comp);
+       if (!comp->stream) {
+               kfree(comp);
+               return ERR_PTR(-ENOMEM);
+       }
+       return comp;
+}
diff --git a/drivers/block/zram/zcomp.h b/drivers/block/zram/zcomp.h
new file mode 100644 (file)
index 0000000..c59d1fc
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * 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.
+ */
+
+#ifndef _ZCOMP_H_
+#define _ZCOMP_H_
+
+#include <linux/mutex.h>
+
+struct zcomp_strm {
+       /* compression/decompression buffer */
+       void *buffer;
+       /*
+        * The private data of the compression stream, only compression
+        * stream backend can touch this (e.g. compression algorithm
+        * working memory)
+        */
+       void *private;
+       /* used in multi stream backend, protected by backend strm_lock */
+       struct list_head list;
+};
+
+/* static compression backend */
+struct zcomp_backend {
+       int (*compress)(const unsigned char *src, unsigned char *dst,
+                       size_t *dst_len, void *private);
+
+       int (*decompress)(const unsigned char *src, size_t src_len,
+                       unsigned char *dst);
+
+       void *(*create)(void);
+       void (*destroy)(void *private);
+
+       const char *name;
+};
+
+/* dynamic per-device compression frontend */
+struct zcomp {
+       void *stream;
+       struct zcomp_backend *backend;
+
+       struct zcomp_strm *(*strm_find)(struct zcomp *comp);
+       void (*strm_release)(struct zcomp *comp, struct zcomp_strm *zstrm);
+       bool (*set_max_streams)(struct zcomp *comp, int num_strm);
+       void (*destroy)(struct zcomp *comp);
+};
+
+ssize_t zcomp_available_show(const char *comp, char *buf);
+
+struct zcomp *zcomp_create(const char *comp, int max_strm);
+void zcomp_destroy(struct zcomp *comp);
+
+struct zcomp_strm *zcomp_strm_find(struct zcomp *comp);
+void zcomp_strm_release(struct zcomp *comp, struct zcomp_strm *zstrm);
+
+int zcomp_compress(struct zcomp *comp, struct zcomp_strm *zstrm,
+               const unsigned char *src, size_t *dst_len);
+
+int zcomp_decompress(struct zcomp *comp, const unsigned char *src,
+               size_t src_len, unsigned char *dst);
+
+bool zcomp_set_max_streams(struct zcomp *comp, int num_strm);
+#endif /* _ZCOMP_H_ */
diff --git a/drivers/block/zram/zcomp_lz4.c b/drivers/block/zram/zcomp_lz4.c
new file mode 100644 (file)
index 0000000..f2afb7e
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/lz4.h>
+
+#include "zcomp_lz4.h"
+
+static void *zcomp_lz4_create(void)
+{
+       return kzalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
+}
+
+static void zcomp_lz4_destroy(void *private)
+{
+       kfree(private);
+}
+
+static int zcomp_lz4_compress(const unsigned char *src, unsigned char *dst,
+               size_t *dst_len, void *private)
+{
+       /* return  : Success if return 0 */
+       return lz4_compress(src, PAGE_SIZE, dst, dst_len, private);
+}
+
+static int zcomp_lz4_decompress(const unsigned char *src, size_t src_len,
+               unsigned char *dst)
+{
+       size_t dst_len = PAGE_SIZE;
+       /* return  : Success if return 0 */
+       return lz4_decompress_unknownoutputsize(src, src_len, dst, &dst_len);
+}
+
+struct zcomp_backend zcomp_lz4 = {
+       .compress = zcomp_lz4_compress,
+       .decompress = zcomp_lz4_decompress,
+       .create = zcomp_lz4_create,
+       .destroy = zcomp_lz4_destroy,
+       .name = "lz4",
+};
diff --git a/drivers/block/zram/zcomp_lz4.h b/drivers/block/zram/zcomp_lz4.h
new file mode 100644 (file)
index 0000000..60613fb
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * 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.
+ */
+
+#ifndef _ZCOMP_LZ4_H_
+#define _ZCOMP_LZ4_H_
+
+#include "zcomp.h"
+
+extern struct zcomp_backend zcomp_lz4;
+
+#endif /* _ZCOMP_LZ4_H_ */
diff --git a/drivers/block/zram/zcomp_lzo.c b/drivers/block/zram/zcomp_lzo.c
new file mode 100644 (file)
index 0000000..da1bc47
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/lzo.h>
+
+#include "zcomp_lzo.h"
+
+static void *lzo_create(void)
+{
+       return kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
+}
+
+static void lzo_destroy(void *private)
+{
+       kfree(private);
+}
+
+static int lzo_compress(const unsigned char *src, unsigned char *dst,
+               size_t *dst_len, void *private)
+{
+       int ret = lzo1x_1_compress(src, PAGE_SIZE, dst, dst_len, private);
+       return ret == LZO_E_OK ? 0 : ret;
+}
+
+static int lzo_decompress(const unsigned char *src, size_t src_len,
+               unsigned char *dst)
+{
+       size_t dst_len = PAGE_SIZE;
+       int ret = lzo1x_decompress_safe(src, src_len, dst, &dst_len);
+       return ret == LZO_E_OK ? 0 : ret;
+}
+
+struct zcomp_backend zcomp_lzo = {
+       .compress = lzo_compress,
+       .decompress = lzo_decompress,
+       .create = lzo_create,
+       .destroy = lzo_destroy,
+       .name = "lzo",
+};
diff --git a/drivers/block/zram/zcomp_lzo.h b/drivers/block/zram/zcomp_lzo.h
new file mode 100644 (file)
index 0000000..128c580
--- /dev/null
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2014 Sergey Senozhatsky.
+ *
+ * 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.
+ */
+
+#ifndef _ZCOMP_LZO_H_
+#define _ZCOMP_LZO_H_
+
+#include "zcomp.h"
+
+extern struct zcomp_backend zcomp_lzo;
+
+#endif /* _ZCOMP_LZO_H_ */
index 51c557c..9849b52 100644 (file)
 #include <linux/genhd.h>
 #include <linux/highmem.h>
 #include <linux/slab.h>
-#include <linux/lzo.h>
 #include <linux/string.h>
 #include <linux/vmalloc.h>
+#include <linux/err.h>
 
 #include "zram_drv.h"
 
 /* Globals */
 static int zram_major;
 static struct zram *zram_devices;
+static const char *default_compressor = "lzo";
 
 /* Module params (documentation at end) */
 static unsigned int num_devices = 1;
 
+#define ZRAM_ATTR_RO(name)                                             \
+static ssize_t zram_attr_##name##_show(struct device *d,               \
+                               struct device_attribute *attr, char *b) \
+{                                                                      \
+       struct zram *zram = dev_to_zram(d);                             \
+       return scnprintf(b, PAGE_SIZE, "%llu\n",                        \
+               (u64)atomic64_read(&zram->stats.name));                 \
+}                                                                      \
+static struct device_attribute dev_attr_##name =                       \
+       __ATTR(name, S_IRUGO, zram_attr_##name##_show, NULL);
+
+static inline int init_done(struct zram *zram)
+{
+       return zram->meta != NULL;
+}
+
 static inline struct zram *dev_to_zram(struct device *dev)
 {
        return (struct zram *)dev_to_disk(dev)->private_data;
@@ -52,92 +69,114 @@ static ssize_t disksize_show(struct device *dev,
 {
        struct zram *zram = dev_to_zram(dev);
 
-       return sprintf(buf, "%llu\n", zram->disksize);
+       return scnprintf(buf, PAGE_SIZE, "%llu\n", zram->disksize);
 }
 
 static ssize_t initstate_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
+       u32 val;
        struct zram *zram = dev_to_zram(dev);
 
-       return sprintf(buf, "%u\n", zram->init_done);
-}
-
-static ssize_t num_reads_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct zram *zram = dev_to_zram(dev);
+       down_read(&zram->init_lock);
+       val = init_done(zram);
+       up_read(&zram->init_lock);
 
-       return sprintf(buf, "%llu\n",
-                       (u64)atomic64_read(&zram->stats.num_reads));
+       return scnprintf(buf, PAGE_SIZE, "%u\n", val);
 }
 
-static ssize_t num_writes_show(struct device *dev,
+static ssize_t orig_data_size_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct zram *zram = dev_to_zram(dev);
 
-       return sprintf(buf, "%llu\n",
-                       (u64)atomic64_read(&zram->stats.num_writes));
+       return scnprintf(buf, PAGE_SIZE, "%llu\n",
+               (u64)(atomic64_read(&zram->stats.pages_stored)) << PAGE_SHIFT);
 }
 
-static ssize_t invalid_io_show(struct device *dev,
+static ssize_t mem_used_total_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
+       u64 val = 0;
        struct zram *zram = dev_to_zram(dev);
+       struct zram_meta *meta = zram->meta;
 
-       return sprintf(buf, "%llu\n",
-                       (u64)atomic64_read(&zram->stats.invalid_io));
-}
-
-static ssize_t notify_free_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct zram *zram = dev_to_zram(dev);
+       down_read(&zram->init_lock);
+       if (init_done(zram))
+               val = zs_get_total_size_bytes(meta->mem_pool);
+       up_read(&zram->init_lock);
 
-       return sprintf(buf, "%llu\n",
-                       (u64)atomic64_read(&zram->stats.notify_free));
+       return scnprintf(buf, PAGE_SIZE, "%llu\n", val);
 }
 
-static ssize_t zero_pages_show(struct device *dev,
+static ssize_t max_comp_streams_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
+       int val;
        struct zram *zram = dev_to_zram(dev);
 
-       return sprintf(buf, "%u\n", atomic_read(&zram->stats.pages_zero));
+       down_read(&zram->init_lock);
+       val = zram->max_comp_streams;
+       up_read(&zram->init_lock);
+
+       return scnprintf(buf, PAGE_SIZE, "%d\n", val);
 }
 
-static ssize_t orig_data_size_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
+static ssize_t max_comp_streams_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
 {
+       int num;
        struct zram *zram = dev_to_zram(dev);
+       int ret;
 
-       return sprintf(buf, "%llu\n",
-               (u64)(atomic_read(&zram->stats.pages_stored)) << PAGE_SHIFT);
-}
+       ret = kstrtoint(buf, 0, &num);
+       if (ret < 0)
+               return ret;
+       if (num < 1)
+               return -EINVAL;
 
-static ssize_t compr_data_size_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       struct zram *zram = dev_to_zram(dev);
+       down_write(&zram->init_lock);
+       if (init_done(zram)) {
+               if (!zcomp_set_max_streams(zram->comp, num)) {
+                       pr_info("Cannot change max compression streams\n");
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
 
-       return sprintf(buf, "%llu\n",
-                       (u64)atomic64_read(&zram->stats.compr_size));
+       zram->max_comp_streams = num;
+       ret = len;
+out:
+       up_write(&zram->init_lock);
+       return ret;
 }
 
-static ssize_t mem_used_total_show(struct device *dev,
+static ssize_t comp_algorithm_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       u64 val = 0;
+       size_t sz;
        struct zram *zram = dev_to_zram(dev);
-       struct zram_meta *meta = zram->meta;
 
        down_read(&zram->init_lock);
-       if (zram->init_done)
-               val = zs_get_total_size_bytes(meta->mem_pool);
+       sz = zcomp_available_show(zram->compressor, buf);
        up_read(&zram->init_lock);
 
-       return sprintf(buf, "%llu\n", val);
+       return sz;
+}
+
+static ssize_t comp_algorithm_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t len)
+{
+       struct zram *zram = dev_to_zram(dev);
+       down_write(&zram->init_lock);
+       if (init_done(zram)) {
+               up_write(&zram->init_lock);
+               pr_info("Can't change algorithm for initialized device\n");
+               return -EBUSY;
+       }
+       strlcpy(zram->compressor, buf, sizeof(zram->compressor));
+       up_write(&zram->init_lock);
+       return len;
 }
 
 /* flag operations needs meta->tb_lock */
@@ -192,8 +231,6 @@ static inline int valid_io_request(struct zram *zram, struct bio *bio)
 static void zram_meta_free(struct zram_meta *meta)
 {
        zs_destroy_pool(meta->mem_pool);
-       kfree(meta->compress_workmem);
-       free_pages((unsigned long)meta->compress_buffer, 1);
        vfree(meta->table);
        kfree(meta);
 }
@@ -205,22 +242,11 @@ static struct zram_meta *zram_meta_alloc(u64 disksize)
        if (!meta)
                goto out;
 
-       meta->compress_workmem = kzalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
-       if (!meta->compress_workmem)
-               goto free_meta;
-
-       meta->compress_buffer =
-               (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, 1);
-       if (!meta->compress_buffer) {
-               pr_err("Error allocating compressor buffer space\n");
-               goto free_workmem;
-       }
-
        num_pages = disksize >> PAGE_SHIFT;
        meta->table = vzalloc(num_pages * sizeof(*meta->table));
        if (!meta->table) {
                pr_err("Error allocating zram address table\n");
-               goto free_buffer;
+               goto free_meta;
        }
 
        meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM);
@@ -230,15 +256,10 @@ static struct zram_meta *zram_meta_alloc(u64 disksize)
        }
 
        rwlock_init(&meta->tb_lock);
-       mutex_init(&meta->buffer_lock);
        return meta;
 
 free_table:
        vfree(meta->table);
-free_buffer:
-       free_pages((unsigned long)meta->compress_buffer, 1);
-free_workmem:
-       kfree(meta->compress_workmem);
 free_meta:
        kfree(meta);
        meta = NULL;
@@ -288,7 +309,6 @@ static void zram_free_page(struct zram *zram, size_t index)
 {
        struct zram_meta *meta = zram->meta;
        unsigned long handle = meta->table[index].handle;
-       u16 size = meta->table[index].size;
 
        if (unlikely(!handle)) {
                /*
@@ -297,21 +317,15 @@ static void zram_free_page(struct zram *zram, size_t index)
                 */
                if (zram_test_flag(meta, index, ZRAM_ZERO)) {
                        zram_clear_flag(meta, index, ZRAM_ZERO);
-                       atomic_dec(&zram->stats.pages_zero);
+                       atomic64_dec(&zram->stats.zero_pages);
                }
                return;
        }
 
-       if (unlikely(size > max_zpage_size))
-               atomic_dec(&zram->stats.bad_compress);
-
        zs_free(meta->mem_pool, handle);
 
-       if (size <= PAGE_SIZE / 2)
-               atomic_dec(&zram->stats.good_compress);
-
-       atomic64_sub(meta->table[index].size, &zram->stats.compr_size);
-       atomic_dec(&zram->stats.pages_stored);
+       atomic64_sub(meta->table[index].size, &zram->stats.compr_data_size);
+       atomic64_dec(&zram->stats.pages_stored);
 
        meta->table[index].handle = 0;
        meta->table[index].size = 0;
@@ -319,8 +333,7 @@ static void zram_free_page(struct zram *zram, size_t index)
 
 static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
 {
-       int ret = LZO_E_OK;
-       size_t clen = PAGE_SIZE;
+       int ret = 0;
        unsigned char *cmem;
        struct zram_meta *meta = zram->meta;
        unsigned long handle;
@@ -340,12 +353,12 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
        if (size == PAGE_SIZE)
                copy_page(mem, cmem);
        else
-               ret = lzo1x_decompress_safe(cmem, size, mem, &clen);
+               ret = zcomp_decompress(zram->comp, cmem, size, mem);
        zs_unmap_object(meta->mem_pool, handle);
        read_unlock(&meta->tb_lock);
 
        /* Should NEVER happen. Return bio error if it does. */
-       if (unlikely(ret != LZO_E_OK)) {
+       if (unlikely(ret)) {
                pr_err("Decompression failed! err=%d, page=%u\n", ret, index);
                atomic64_inc(&zram->stats.failed_reads);
                return ret;
@@ -388,7 +401,7 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
 
        ret = zram_decompress_page(zram, uncmem, index);
        /* Should NEVER happen. Return bio error if it does. */
-       if (unlikely(ret != LZO_E_OK))
+       if (unlikely(ret))
                goto out_cleanup;
 
        if (is_partial_io(bvec))
@@ -413,11 +426,10 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
        struct page *page;
        unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
        struct zram_meta *meta = zram->meta;
+       struct zcomp_strm *zstrm;
        bool locked = false;
 
        page = bvec->bv_page;
-       src = meta->compress_buffer;
-
        if (is_partial_io(bvec)) {
                /*
                 * This is a partial IO. We need to read the full page
@@ -433,7 +445,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
                        goto out;
        }
 
-       mutex_lock(&meta->buffer_lock);
+       zstrm = zcomp_strm_find(zram->comp);
        locked = true;
        user_mem = kmap_atomic(page);
 
@@ -454,28 +466,25 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
                zram_set_flag(meta, index, ZRAM_ZERO);
                write_unlock(&zram->meta->tb_lock);
 
-               atomic_inc(&zram->stats.pages_zero);
+               atomic64_inc(&zram->stats.zero_pages);
                ret = 0;
                goto out;
        }
 
-       ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
-                              meta->compress_workmem);
+       ret = zcomp_compress(zram->comp, zstrm, uncmem, &clen);
        if (!is_partial_io(bvec)) {
                kunmap_atomic(user_mem);
                user_mem = NULL;
                uncmem = NULL;
        }
 
-       if (unlikely(ret != LZO_E_OK)) {
+       if (unlikely(ret)) {
                pr_err("Compression failed! err=%d\n", ret);
                goto out;
        }
-
+       src = zstrm->buffer;
        if (unlikely(clen > max_zpage_size)) {
-               atomic_inc(&zram->stats.bad_compress);
                clen = PAGE_SIZE;
-               src = NULL;
                if (is_partial_io(bvec))
                        src = uncmem;
        }
@@ -497,6 +506,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
                memcpy(cmem, src, clen);
        }
 
+       zcomp_strm_release(zram->comp, zstrm);
+       locked = false;
        zs_unmap_object(meta->mem_pool, handle);
 
        /*
@@ -511,49 +522,88 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
        write_unlock(&zram->meta->tb_lock);
 
        /* Update stats */
-       atomic64_add(clen, &zram->stats.compr_size);
-       atomic_inc(&zram->stats.pages_stored);
-       if (clen <= PAGE_SIZE / 2)
-               atomic_inc(&zram->stats.good_compress);
-
+       atomic64_add(clen, &zram->stats.compr_data_size);
+       atomic64_inc(&zram->stats.pages_stored);
 out:
        if (locked)
-               mutex_unlock(&meta->buffer_lock);
+               zcomp_strm_release(zram->comp, zstrm);
        if (is_partial_io(bvec))
                kfree(uncmem);
-
        if (ret)
                atomic64_inc(&zram->stats.failed_writes);
        return ret;
 }
 
 static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
-                       int offset, struct bio *bio, int rw)
+                       int offset, struct bio *bio)
 {
        int ret;
+       int rw = bio_data_dir(bio);
 
-       if (rw == READ)
+       if (rw == READ) {
+               atomic64_inc(&zram->stats.num_reads);
                ret = zram_bvec_read(zram, bvec, index, offset, bio);
-       else
+       } else {
+               atomic64_inc(&zram->stats.num_writes);
                ret = zram_bvec_write(zram, bvec, index, offset);
+       }
 
        return ret;
 }
 
+/*
+ * zram_bio_discard - handler on discard request
+ * @index: physical block index in PAGE_SIZE units
+ * @offset: byte offset within physical block
+ */
+static void zram_bio_discard(struct zram *zram, u32 index,
+                            int offset, struct bio *bio)
+{
+       size_t n = bio->bi_iter.bi_size;
+
+       /*
+        * zram manages data in physical block size units. Because logical block
+        * size isn't identical with physical block size on some arch, we
+        * could get a discard request pointing to a specific offset within a
+        * certain physical block.  Although we can handle this request by
+        * reading that physiclal block and decompressing and partially zeroing
+        * and re-compressing and then re-storing it, this isn't reasonable
+        * because our intent with a discard request is to save memory.  So
+        * skipping this logical block is appropriate here.
+        */
+       if (offset) {
+               if (n < offset)
+                       return;
+
+               n -= offset;
+               index++;
+       }
+
+       while (n >= PAGE_SIZE) {
+               /*
+                * Discard request can be large so the lock hold times could be
+                * lengthy.  So take the lock once per page.
+                */
+               write_lock(&zram->meta->tb_lock);
+               zram_free_page(zram, index);
+               write_unlock(&zram->meta->tb_lock);
+               index++;
+               n -= PAGE_SIZE;
+       }
+}
+
 static void zram_reset_device(struct zram *zram, bool reset_capacity)
 {
        size_t index;
        struct zram_meta *meta;
 
        down_write(&zram->init_lock);
-       if (!zram->init_done) {
+       if (!init_done(zram)) {
                up_write(&zram->init_lock);
                return;
        }
 
        meta = zram->meta;
-       zram->init_done = 0;
-
        /* Free all pages that are still in this zram device */
        for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
                unsigned long handle = meta->table[index].handle;
@@ -563,6 +613,9 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity)
                zs_free(meta->mem_pool, handle);
        }
 
+       zcomp_destroy(zram->comp);
+       zram->max_comp_streams = 1;
+
        zram_meta_free(zram->meta);
        zram->meta = NULL;
        /* Reset stats */
@@ -574,37 +627,14 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity)
        up_write(&zram->init_lock);
 }
 
-static void zram_init_device(struct zram *zram, struct zram_meta *meta)
-{
-       if (zram->disksize > 2 * (totalram_pages << PAGE_SHIFT)) {
-               pr_info(
-               "There is little point creating a zram of greater than "
-               "twice the size of memory since we expect a 2:1 compression "
-               "ratio. Note that zram uses about 0.1%% of the size of "
-               "the disk when not in use so a huge zram is "
-               "wasteful.\n"
-               "\tMemory Size: %lu kB\n"
-               "\tSize you selected: %llu kB\n"
-               "Continuing anyway ...\n",
-               (totalram_pages << PAGE_SHIFT) >> 10, zram->disksize >> 10
-               );
-       }
-
-       /* zram devices sort of resembles non-rotational disks */
-       queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
-
-       zram->meta = meta;
-       zram->init_done = 1;
-
-       pr_debug("Initialization done!\n");
-}
-
 static ssize_t disksize_store(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t len)
 {
        u64 disksize;
+       struct zcomp *comp;
        struct zram_meta *meta;
        struct zram *zram = dev_to_zram(dev);
+       int err;
 
        disksize = memparse(buf, NULL);
        if (!disksize)
@@ -614,20 +644,35 @@ static ssize_t disksize_store(struct device *dev,
        meta = zram_meta_alloc(disksize);
        if (!meta)
                return -ENOMEM;
+
+       comp = zcomp_create(zram->compressor, zram->max_comp_streams);
+       if (IS_ERR(comp)) {
+               pr_info("Cannot initialise %s compressing backend\n",
+                               zram->compressor);
+               err = PTR_ERR(comp);
+               goto out_free_meta;
+       }
+
        down_write(&zram->init_lock);
-       if (zram->init_done) {
-               up_write(&zram->init_lock);
-               zram_meta_free(meta);
+       if (init_done(zram)) {
                pr_info("Cannot change disksize for initialized device\n");
-               return -EBUSY;
+               err = -EBUSY;
+               goto out_destroy_comp;
        }
 
+       zram->meta = meta;
+       zram->comp = comp;
        zram->disksize = disksize;
        set_capacity(zram->disk, zram->disksize >> SECTOR_SHIFT);
-       zram_init_device(zram, meta);
        up_write(&zram->init_lock);
-
        return len;
+
+out_destroy_comp:
+       up_write(&zram->init_lock);
+       zcomp_destroy(comp);
+out_free_meta:
+       zram_meta_free(meta);
+       return err;
 }
 
 static ssize_t reset_store(struct device *dev,
@@ -671,26 +716,23 @@ out:
        return ret;
 }
 
-static void __zram_make_request(struct zram *zram, struct bio *bio, int rw)
+static void __zram_make_request(struct zram *zram, struct bio *bio)
 {
        int offset;
        u32 index;
        struct bio_vec bvec;
        struct bvec_iter iter;
 
-       switch (rw) {
-       case READ:
-               atomic64_inc(&zram->stats.num_reads);
-               break;
-       case WRITE:
-               atomic64_inc(&zram->stats.num_writes);
-               break;
-       }
-
        index = bio->bi_iter.bi_sector >> SECTORS_PER_PAGE_SHIFT;
        offset = (bio->bi_iter.bi_sector &
                  (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT;
 
+       if (unlikely(bio->bi_rw & REQ_DISCARD)) {
+               zram_bio_discard(zram, index, offset, bio);
+               bio_endio(bio, 0);
+               return;
+       }
+
        bio_for_each_segment(bvec, bio, iter) {
                int max_transfer_size = PAGE_SIZE - offset;
 
@@ -705,16 +747,15 @@ static void __zram_make_request(struct zram *zram, struct bio *bio, int rw)
                        bv.bv_len = max_transfer_size;
                        bv.bv_offset = bvec.bv_offset;
 
-                       if (zram_bvec_rw(zram, &bv, index, offset, bio, rw) < 0)
+                       if (zram_bvec_rw(zram, &bv, index, offset, bio) < 0)
                                goto out;
 
                        bv.bv_len = bvec.bv_len - max_transfer_size;
                        bv.bv_offset += max_transfer_size;
-                       if (zram_bvec_rw(zram, &bv, index+1, 0, bio, rw) < 0)
+                       if (zram_bvec_rw(zram, &bv, index + 1, 0, bio) < 0)
                                goto out;
                } else
-                       if (zram_bvec_rw(zram, &bvec, index, offset, bio, rw)
-                           < 0)
+                       if (zram_bvec_rw(zram, &bvec, index, offset, bio) < 0)
                                goto out;
 
                update_position(&index, &offset, &bvec);
@@ -736,7 +777,7 @@ static void zram_make_request(struct request_queue *queue, struct bio *bio)
        struct zram *zram = queue->queuedata;
 
        down_read(&zram->init_lock);
-       if (unlikely(!zram->init_done))
+       if (unlikely(!init_done(zram)))
                goto error;
 
        if (!valid_io_request(zram, bio)) {
@@ -744,7 +785,7 @@ static void zram_make_request(struct request_queue *queue, struct bio *bio)
                goto error;
        }
 
-       __zram_make_request(zram, bio, bio_data_dir(bio));
+       __zram_make_request(zram, bio);
        up_read(&zram->init_lock);
 
        return;
@@ -778,14 +819,21 @@ static DEVICE_ATTR(disksize, S_IRUGO | S_IWUSR,
                disksize_show, disksize_store);
 static DEVICE_ATTR(initstate, S_IRUGO, initstate_show, NULL);
 static DEVICE_ATTR(reset, S_IWUSR, NULL, reset_store);
-static DEVICE_ATTR(num_reads, S_IRUGO, num_reads_show, NULL);
-static DEVICE_ATTR(num_writes, S_IRUGO, num_writes_show, NULL);
-static DEVICE_ATTR(invalid_io, S_IRUGO, invalid_io_show, NULL);
-static DEVICE_ATTR(notify_free, S_IRUGO, notify_free_show, NULL);
-static DEVICE_ATTR(zero_pages, S_IRUGO, zero_pages_show, NULL);
 static DEVICE_ATTR(orig_data_size, S_IRUGO, orig_data_size_show, NULL);
-static DEVICE_ATTR(compr_data_size, S_IRUGO, compr_data_size_show, NULL);
 static DEVICE_ATTR(mem_used_total, S_IRUGO, mem_used_total_show, NULL);
+static DEVICE_ATTR(max_comp_streams, S_IRUGO | S_IWUSR,
+               max_comp_streams_show, max_comp_streams_store);
+static DEVICE_ATTR(comp_algorithm, S_IRUGO | S_IWUSR,
+               comp_algorithm_show, comp_algorithm_store);
+
+ZRAM_ATTR_RO(num_reads);
+ZRAM_ATTR_RO(num_writes);
+ZRAM_ATTR_RO(failed_reads);
+ZRAM_ATTR_RO(failed_writes);
+ZRAM_ATTR_RO(invalid_io);
+ZRAM_ATTR_RO(notify_free);
+ZRAM_ATTR_RO(zero_pages);
+ZRAM_ATTR_RO(compr_data_size);
 
 static struct attribute *zram_disk_attrs[] = {
        &dev_attr_disksize.attr,
@@ -793,12 +841,16 @@ static struct attribute *zram_disk_attrs[] = {
        &dev_attr_reset.attr,
        &dev_attr_num_reads.attr,
        &dev_attr_num_writes.attr,
+       &dev_attr_failed_reads.attr,
+       &dev_attr_failed_writes.attr,
        &dev_attr_invalid_io.attr,
        &dev_attr_notify_free.attr,
        &dev_attr_zero_pages.attr,
        &dev_attr_orig_data_size.attr,
        &dev_attr_compr_data_size.attr,
        &dev_attr_mem_used_total.attr,
+       &dev_attr_max_comp_streams.attr,
+       &dev_attr_comp_algorithm.attr,
        NULL,
 };
 
@@ -839,7 +891,8 @@ static int create_device(struct zram *zram, int device_id)
 
        /* Actual capacity set using syfs (/sys/block/zram<id>/disksize */
        set_capacity(zram->disk, 0);
-
+       /* zram devices sort of resembles non-rotational disks */
+       queue_flag_set_unlocked(QUEUE_FLAG_NONROT, zram->disk->queue);
        /*
         * To ensure that we always get PAGE_SIZE aligned
         * and n*PAGE_SIZED sized I/O requests.
@@ -849,6 +902,21 @@ static int create_device(struct zram *zram, int device_id)
                                        ZRAM_LOGICAL_BLOCK_SIZE);
        blk_queue_io_min(zram->disk->queue, PAGE_SIZE);
        blk_queue_io_opt(zram->disk->queue, PAGE_SIZE);
+       zram->disk->queue->limits.discard_granularity = PAGE_SIZE;
+       zram->disk->queue->limits.max_discard_sectors = UINT_MAX;
+       /*
+        * zram_bio_discard() will clear all logical blocks if logical block
+        * size is identical with physical block size(PAGE_SIZE). But if it is
+        * different, we will skip discarding some parts of logical blocks in
+        * the part of the request range which isn't aligned to physical block
+        * size.  So we can't ensure that all discarded logical blocks are
+        * zeroed.
+        */
+       if (ZRAM_LOGICAL_BLOCK_SIZE == PAGE_SIZE)
+               zram->disk->queue->limits.discard_zeroes_data = 1;
+       else
+               zram->disk->queue->limits.discard_zeroes_data = 0;
+       queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, zram->disk->queue);
 
        add_disk(zram->disk);
 
@@ -858,8 +926,9 @@ static int create_device(struct zram *zram, int device_id)
                pr_warn("Error creating sysfs group");
                goto out_free_disk;
        }
-
-       zram->init_done = 0;
+       strlcpy(zram->compressor, default_compressor, sizeof(zram->compressor));
+       zram->meta = NULL;
+       zram->max_comp_streams = 1;
        return 0;
 
 out_free_disk:
index ad8aa35..7f21c14 100644 (file)
 #define _ZRAM_DRV_H_
 
 #include <linux/spinlock.h>
-#include <linux/mutex.h>
 #include <linux/zsmalloc.h>
 
+#include "zcomp.h"
+
 /*
  * Some arbitrary value. This is just to catch
  * invalid value for num_devices module parameter.
@@ -64,38 +65,33 @@ enum zram_pageflags {
 struct table {
        unsigned long handle;
        u16 size;       /* object size (excluding header) */
-       u8 count;       /* object ref count (not yet used) */
        u8 flags;
 } __aligned(4);
 
 struct zram_stats {
-       atomic64_t compr_size;  /* compressed size of pages stored */
+       atomic64_t compr_data_size;     /* compressed size of pages stored */
        atomic64_t num_reads;   /* failed + successful */
        atomic64_t num_writes;  /* --do-- */
        atomic64_t failed_reads;        /* should NEVER! happen */
        atomic64_t failed_writes;       /* can happen when memory is too low */
        atomic64_t invalid_io;  /* non-page-aligned I/O requests */
        atomic64_t notify_free; /* no. of swap slot free notifications */
-       atomic_t pages_zero;            /* no. of zero filled pages */
-       atomic_t pages_stored;  /* no. of pages currently stored */
-       atomic_t good_compress; /* % of pages with compression ratio<=50% */
-       atomic_t bad_compress;  /* % of pages with compression ratio>=75% */
+       atomic64_t zero_pages;          /* no. of zero filled pages */
+       atomic64_t pages_stored;        /* no. of pages currently stored */
 };
 
 struct zram_meta {
        rwlock_t tb_lock;       /* protect table */
-       void *compress_workmem;
-       void *compress_buffer;
        struct table *table;
        struct zs_pool *mem_pool;
-       struct mutex buffer_lock; /* protect compress buffers */
 };
 
 struct zram {
        struct zram_meta *meta;
        struct request_queue *queue;
        struct gendisk *disk;
-       int init_done;
+       struct zcomp *comp;
+
        /* Prevent concurrent execution of device init, reset and R/W request */
        struct rw_semaphore init_lock;
        /*
@@ -103,7 +99,8 @@ struct zram {
         * we can store in a disk.
         */
        u64 disksize;   /* bytes */
-
+       int max_comp_streams;
        struct zram_stats stats;
+       char compressor[10];
 };
 #endif
index 1a65838..c54cac3 100644 (file)
@@ -74,7 +74,7 @@ config TCG_NSC
 
 config TCG_ATMEL
        tristate "Atmel TPM Interface"
-       depends on PPC64 || HAS_IOPORT
+       depends on PPC64 || HAS_IOPORT_MAP
        ---help---
          If you have a TPM security chip from Atmel say Yes and it 
          will be accessible from within Linux.  To compile this driver 
index d323023..0d1750a 100644 (file)
@@ -130,10 +130,6 @@ static struct ti_dt_clk omap3xxx_clks[] = {
        DT_CLK(NULL, "dss_tv_fck", "dss_tv_fck"),
        DT_CLK(NULL, "dss_96m_fck", "dss_96m_fck"),
        DT_CLK(NULL, "dss2_alwon_fck", "dss2_alwon_fck"),
-       DT_CLK(NULL, "utmi_p1_gfclk", "dummy_ck"),
-       DT_CLK(NULL, "utmi_p2_gfclk", "dummy_ck"),
-       DT_CLK(NULL, "xclk60mhsp1_ck", "dummy_ck"),
-       DT_CLK(NULL, "xclk60mhsp2_ck", "dummy_ck"),
        DT_CLK(NULL, "init_60m_fclk", "dummy_ck"),
        DT_CLK(NULL, "gpt1_fck", "gpt1_fck"),
        DT_CLK(NULL, "aes2_ick", "aes2_ick"),
index b3eb582..ad35725 100644 (file)
@@ -56,14 +56,19 @@ static struct notifier_block dummy_timer_cpu_nb = {
 
 static int __init dummy_timer_register(void)
 {
-       int err = register_cpu_notifier(&dummy_timer_cpu_nb);
+       int err = 0;
+
+       cpu_notifier_register_begin();
+       err = __register_cpu_notifier(&dummy_timer_cpu_nb);
        if (err)
-               return err;
+               goto out;
 
        /* We won't get a call on the boot CPU, so register immediately */
        if (num_possible_cpus() > 1)
                dummy_timer_setup();
 
-       return 0;
+out:
+       cpu_notifier_register_done();
+       return err;
 }
 early_initcall(dummy_timer_register);
index 822ca03..d5eaedb 100644 (file)
@@ -906,15 +906,16 @@ static void __init acpi_cpufreq_boost_init(void)
 
                acpi_cpufreq_driver.boost_supported = true;
                acpi_cpufreq_driver.boost_enabled = boost_state(0);
-               get_online_cpus();
+
+               cpu_notifier_register_begin();
 
                /* Force all MSRs to the same value */
                boost_set_msrs(acpi_cpufreq_driver.boost_enabled,
                               cpu_online_mask);
 
-               register_cpu_notifier(&boost_nb);
+               __register_cpu_notifier(&boost_nb);
 
-               put_online_cpus();
+               cpu_notifier_register_done();
        }
 }
 
index 605b016..ba06d1d 100644 (file)
@@ -308,7 +308,7 @@ config DMA_OMAP
 
 config DMA_BCM2835
        tristate "BCM2835 DMA engine support"
-       depends on (ARCH_BCM2835 || MACH_BCM2708)
+       depends on ARCH_BCM2835
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
 
@@ -350,6 +350,16 @@ config MOXART_DMA
        select DMA_VIRTUAL_CHANNELS
        help
          Enable support for the MOXA ART SoC DMA controller.
+config FSL_EDMA
+       tristate "Freescale eDMA engine support"
+       depends on OF
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         Support the Freescale eDMA engine with programmable channel
+         multiplexing capability for DMA request sources(slot).
+         This module can be found on Freescale Vybrid and LS-1 SoCs.
 
 config DMA_ENGINE
        bool
@@ -401,4 +411,13 @@ config DMATEST
 config DMA_ENGINE_RAID
        bool
 
+config QCOM_BAM_DMA
+       tristate "QCOM BAM DMA support"
+       depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       ---help---
+         Enable support for the QCOM BAM DMA controller.  This controller
+         provides DMA capabilities for a variety of on-chip devices.
+
 endif
index a029d0f..5150c82 100644 (file)
@@ -44,3 +44,5 @@ obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
 obj-$(CONFIG_TI_CPPI41) += cppi41.o
 obj-$(CONFIG_K3_DMA) += k3dma.o
 obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
+obj-$(CONFIG_FSL_EDMA) += fsl-edma.o
+obj-$(CONFIG_QCOM_BAM_DMA) += qcom_bam_dma.o
index 1e506af..de361a1 100644 (file)
@@ -13,6 +13,7 @@
  */
 
 #include <linux/device.h>
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
@@ -265,7 +266,7 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_register);
  */
 void devm_acpi_dma_controller_free(struct device *dev)
 {
-       WARN_ON(devres_destroy(dev, devm_acpi_dma_release, NULL, NULL));
+       WARN_ON(devres_release(dev, devm_acpi_dma_release, NULL, NULL));
 }
 EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
 
@@ -343,7 +344,7 @@ static int acpi_dma_parse_fixed_dma(struct acpi_resource *res, void *data)
  * @index:     index of FixedDMA descriptor for @dev
  *
  * Return:
- * Pointer to appropriate dma channel on success or NULL on error.
+ * Pointer to appropriate dma channel on success or an error pointer.
  */
 struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
                size_t index)
@@ -358,10 +359,10 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
 
        /* Check if the device was enumerated by ACPI */
        if (!dev || !ACPI_HANDLE(dev))
-               return NULL;
+               return ERR_PTR(-ENODEV);
 
        if (acpi_bus_get_device(ACPI_HANDLE(dev), &adev))
-               return NULL;
+               return ERR_PTR(-ENODEV);
 
        memset(&pdata, 0, sizeof(pdata));
        pdata.index = index;
@@ -376,7 +377,7 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
        acpi_dev_free_resource_list(&resource_list);
 
        if (dma_spec->slave_id < 0 || dma_spec->chan_id < 0)
-               return NULL;
+               return ERR_PTR(-ENODEV);
 
        mutex_lock(&acpi_dma_lock);
 
@@ -399,7 +400,7 @@ struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
        }
 
        mutex_unlock(&acpi_dma_lock);
-       return chan;
+       return chan ? chan : ERR_PTR(-EPROBE_DEFER);
 }
 EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index);
 
@@ -413,7 +414,7 @@ EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index);
  * the first FixedDMA descriptor is TX and second is RX.
  *
  * Return:
- * Pointer to appropriate dma channel on success or NULL on error.
+ * Pointer to appropriate dma channel on success or an error pointer.
  */
 struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
                const char *name)
@@ -425,7 +426,7 @@ struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
        else if (!strcmp(name, "rx"))
                index = 1;
        else
-               return NULL;
+               return ERR_PTR(-ENODEV);
 
        return acpi_dma_request_slave_chan_by_index(dev, index);
 }
index e2c04dc..c13a3bb 100644 (file)
@@ -1569,7 +1569,6 @@ static int at_dma_remove(struct platform_device *pdev)
 
                /* Disable interrupts */
                atc_disable_chan_irq(atdma, chan->chan_id);
-               tasklet_disable(&atchan->tasklet);
 
                tasklet_kill(&atchan->tasklet);
                list_del(&chan->device_node);
index c18aebf..d028f36 100644 (file)
@@ -620,12 +620,15 @@ static int cppi41_stop_chan(struct dma_chan *chan)
        u32 desc_phys;
        int ret;
 
+       desc_phys = lower_32_bits(c->desc_phys);
+       desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
+       if (!cdd->chan_busy[desc_num])
+               return 0;
+
        ret = cppi41_tear_down_chan(c);
        if (ret)
                return ret;
 
-       desc_phys = lower_32_bits(c->desc_phys);
-       desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc);
        WARN_ON(!cdd->chan_busy[desc_num]);
        cdd->chan_busy[desc_num] = NULL;
 
index ed610b4..a886713 100644 (file)
@@ -627,18 +627,13 @@ EXPORT_SYMBOL_GPL(__dma_request_channel);
 struct dma_chan *dma_request_slave_channel_reason(struct device *dev,
                                                  const char *name)
 {
-       struct dma_chan *chan;
-
        /* If device-tree is present get slave info from here */
        if (dev->of_node)
                return of_dma_request_slave_channel(dev->of_node, name);
 
        /* If device was enumerated by ACPI get slave info from here */
-       if (ACPI_HANDLE(dev)) {
-               chan = acpi_dma_request_slave_chan_by_name(dev, name);
-               if (chan)
-                       return chan;
-       }
+       if (ACPI_HANDLE(dev))
+               return acpi_dma_request_slave_chan_by_name(dev, name);
 
        return ERR_PTR(-ENODEV);
 }
index 05b6dea..e27cec2 100644 (file)
@@ -340,7 +340,7 @@ static unsigned int min_odd(unsigned int x, unsigned int y)
 static void result(const char *err, unsigned int n, unsigned int src_off,
                   unsigned int dst_off, unsigned int len, unsigned long data)
 {
-       pr_info("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)",
+       pr_info("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)\n",
                current->comm, n, err, src_off, dst_off, len, data);
 }
 
@@ -348,7 +348,7 @@ static void dbg_result(const char *err, unsigned int n, unsigned int src_off,
                       unsigned int dst_off, unsigned int len,
                       unsigned long data)
 {
-       pr_debug("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)",
+       pr_debug("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)\n",
                   current->comm, n, err, src_off, dst_off, len, data);
 }
 
index 13ac3f2..cfdbb92 100644 (file)
@@ -33,8 +33,8 @@
  * of which use ARM any more).  See the "Databook" from Synopsys for
  * information beyond what licensees probably provide.
  *
- * The driver has currently been tested only with the Atmel AT32AP7000,
- * which does not support descriptor writeback.
+ * The driver has been tested with the Atmel AT32AP7000, which does not
+ * support descriptor writeback.
  */
 
 static inline bool is_request_line_unset(struct dw_dma_chan *dwc)
@@ -1479,7 +1479,6 @@ static void dw_dma_off(struct dw_dma *dw)
 int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
 {
        struct dw_dma           *dw;
-       size_t                  size;
        bool                    autocfg;
        unsigned int            dw_params;
        unsigned int            nr_channels;
@@ -1487,6 +1486,13 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        int                     err;
        int                     i;
 
+       dw = devm_kzalloc(chip->dev, sizeof(*dw), GFP_KERNEL);
+       if (!dw)
+               return -ENOMEM;
+
+       dw->regs = chip->regs;
+       chip->dw = dw;
+
        dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
        autocfg = dw_params >> DW_PARAMS_EN & 0x1;
 
@@ -1509,9 +1515,9 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
        else
                nr_channels = pdata->nr_channels;
 
-       size = sizeof(struct dw_dma) + nr_channels * sizeof(struct dw_dma_chan);
-       dw = devm_kzalloc(chip->dev, size, GFP_KERNEL);
-       if (!dw)
+       dw->chan = devm_kcalloc(chip->dev, nr_channels, sizeof(*dw->chan),
+                               GFP_KERNEL);
+       if (!dw->chan)
                return -ENOMEM;
 
        dw->clk = devm_clk_get(chip->dev, "hclk");
@@ -1519,9 +1525,6 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
                return PTR_ERR(dw->clk);
        clk_prepare_enable(dw->clk);
 
-       dw->regs = chip->regs;
-       chip->dw = dw;
-
        /* Get hardware configuration parameters */
        if (autocfg) {
                max_blk_size = dma_readl(dw, MAX_BLK_SIZE);
index e89fc24..fec59f1 100644 (file)
@@ -75,6 +75,36 @@ static void dw_pci_remove(struct pci_dev *pdev)
                dev_warn(&pdev->dev, "can't remove device properly: %d\n", ret);
 }
 
+#ifdef CONFIG_PM_SLEEP
+
+static int dw_pci_suspend_late(struct device *dev)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+       struct dw_dma_chip *chip = pci_get_drvdata(pci);
+
+       return dw_dma_suspend(chip);
+};
+
+static int dw_pci_resume_early(struct device *dev)
+{
+       struct pci_dev *pci = to_pci_dev(dev);
+       struct dw_dma_chip *chip = pci_get_drvdata(pci);
+
+       return dw_dma_resume(chip);
+};
+
+#else /* !CONFIG_PM_SLEEP */
+
+#define dw_pci_suspend_late    NULL
+#define dw_pci_resume_early    NULL
+
+#endif /* !CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops dw_pci_dev_pm_ops = {
+       .suspend_late = dw_pci_suspend_late,
+       .resume_early = dw_pci_resume_early,
+};
+
 static DEFINE_PCI_DEVICE_TABLE(dw_pci_id_table) = {
        /* Medfield */
        { PCI_VDEVICE(INTEL, 0x0827), (kernel_ulong_t)&dw_pci_pdata },
@@ -83,6 +113,9 @@ static DEFINE_PCI_DEVICE_TABLE(dw_pci_id_table) = {
        /* BayTrail */
        { PCI_VDEVICE(INTEL, 0x0f06), (kernel_ulong_t)&dw_pci_pdata },
        { PCI_VDEVICE(INTEL, 0x0f40), (kernel_ulong_t)&dw_pci_pdata },
+
+       /* Haswell */
+       { PCI_VDEVICE(INTEL, 0x9c60), (kernel_ulong_t)&dw_pci_pdata },
        { }
 };
 MODULE_DEVICE_TABLE(pci, dw_pci_id_table);
@@ -92,6 +125,9 @@ static struct pci_driver dw_pci_driver = {
        .id_table       = dw_pci_id_table,
        .probe          = dw_pci_probe,
        .remove         = dw_pci_remove,
+       .driver = {
+               .pm     = &dw_pci_dev_pm_ops,
+       },
 };
 
 module_pci_driver(dw_pci_driver);
index deb4274..bb98d3e 100644 (file)
@@ -252,13 +252,13 @@ struct dw_dma {
        struct tasklet_struct   tasklet;
        struct clk              *clk;
 
+       /* channels */
+       struct dw_dma_chan      *chan;
        u8                      all_chan_mask;
 
        /* hardware configuration */
        unsigned char           nr_masters;
        unsigned char           data_width[4];
-
-       struct dw_dma_chan      chan[0];
 };
 
 static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
index cd8da45..cd04eb7 100644 (file)
@@ -539,6 +539,7 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
                                edma_alloc_slot(EDMA_CTLR(echan->ch_num),
                                                EDMA_SLOT_ANY);
                        if (echan->slot[i] < 0) {
+                               kfree(edesc);
                                dev_err(dev, "Failed to allocate slot\n");
                                return NULL;
                        }
@@ -553,8 +554,10 @@ static struct dma_async_tx_descriptor *edma_prep_dma_cyclic(
                ret = edma_config_pset(chan, &edesc->pset[i], src_addr,
                                       dst_addr, burst, dev_width, period_len,
                                       direction);
-               if (ret < 0)
+               if (ret < 0) {
+                       kfree(edesc);
                        return NULL;
+               }
 
                if (direction == DMA_DEV_TO_MEM)
                        dst_addr += period_len;
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
new file mode 100644 (file)
index 0000000..381e793
--- /dev/null
@@ -0,0 +1,975 @@
+/*
+ * drivers/dma/fsl-edma.c
+ *
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ *
+ * Driver for the Freescale eDMA engine with flexible channel multiplexing
+ * capability for DMA request sources. The eDMA block can be found on some
+ * Vybrid and Layerscape SoCs.
+ *
+ * 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/init.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmapool.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_dma.h>
+
+#include "virt-dma.h"
+
+#define EDMA_CR                        0x00
+#define EDMA_ES                        0x04
+#define EDMA_ERQ               0x0C
+#define EDMA_EEI               0x14
+#define EDMA_SERQ              0x1B
+#define EDMA_CERQ              0x1A
+#define EDMA_SEEI              0x19
+#define EDMA_CEEI              0x18
+#define EDMA_CINT              0x1F
+#define EDMA_CERR              0x1E
+#define EDMA_SSRT              0x1D
+#define EDMA_CDNE              0x1C
+#define EDMA_INTR              0x24
+#define EDMA_ERR               0x2C
+
+#define EDMA_TCD_SADDR(x)      (0x1000 + 32 * (x))
+#define EDMA_TCD_SOFF(x)       (0x1004 + 32 * (x))
+#define EDMA_TCD_ATTR(x)       (0x1006 + 32 * (x))
+#define EDMA_TCD_NBYTES(x)     (0x1008 + 32 * (x))
+#define EDMA_TCD_SLAST(x)      (0x100C + 32 * (x))
+#define EDMA_TCD_DADDR(x)      (0x1010 + 32 * (x))
+#define EDMA_TCD_DOFF(x)       (0x1014 + 32 * (x))
+#define EDMA_TCD_CITER_ELINK(x)        (0x1016 + 32 * (x))
+#define EDMA_TCD_CITER(x)      (0x1016 + 32 * (x))
+#define EDMA_TCD_DLAST_SGA(x)  (0x1018 + 32 * (x))
+#define EDMA_TCD_CSR(x)                (0x101C + 32 * (x))
+#define EDMA_TCD_BITER_ELINK(x)        (0x101E + 32 * (x))
+#define EDMA_TCD_BITER(x)      (0x101E + 32 * (x))
+
+#define EDMA_CR_EDBG           BIT(1)
+#define EDMA_CR_ERCA           BIT(2)
+#define EDMA_CR_ERGA           BIT(3)
+#define EDMA_CR_HOE            BIT(4)
+#define EDMA_CR_HALT           BIT(5)
+#define EDMA_CR_CLM            BIT(6)
+#define EDMA_CR_EMLM           BIT(7)
+#define EDMA_CR_ECX            BIT(16)
+#define EDMA_CR_CX             BIT(17)
+
+#define EDMA_SEEI_SEEI(x)      ((x) & 0x1F)
+#define EDMA_CEEI_CEEI(x)      ((x) & 0x1F)
+#define EDMA_CINT_CINT(x)      ((x) & 0x1F)
+#define EDMA_CERR_CERR(x)      ((x) & 0x1F)
+
+#define EDMA_TCD_ATTR_DSIZE(x)         (((x) & 0x0007))
+#define EDMA_TCD_ATTR_DMOD(x)          (((x) & 0x001F) << 3)
+#define EDMA_TCD_ATTR_SSIZE(x)         (((x) & 0x0007) << 8)
+#define EDMA_TCD_ATTR_SMOD(x)          (((x) & 0x001F) << 11)
+#define EDMA_TCD_ATTR_SSIZE_8BIT       (0x0000)
+#define EDMA_TCD_ATTR_SSIZE_16BIT      (0x0100)
+#define EDMA_TCD_ATTR_SSIZE_32BIT      (0x0200)
+#define EDMA_TCD_ATTR_SSIZE_64BIT      (0x0300)
+#define EDMA_TCD_ATTR_SSIZE_32BYTE     (0x0500)
+#define EDMA_TCD_ATTR_DSIZE_8BIT       (0x0000)
+#define EDMA_TCD_ATTR_DSIZE_16BIT      (0x0001)
+#define EDMA_TCD_ATTR_DSIZE_32BIT      (0x0002)
+#define EDMA_TCD_ATTR_DSIZE_64BIT      (0x0003)
+#define EDMA_TCD_ATTR_DSIZE_32BYTE     (0x0005)
+
+#define EDMA_TCD_SOFF_SOFF(x)          (x)
+#define EDMA_TCD_NBYTES_NBYTES(x)      (x)
+#define EDMA_TCD_SLAST_SLAST(x)                (x)
+#define EDMA_TCD_DADDR_DADDR(x)                (x)
+#define EDMA_TCD_CITER_CITER(x)                ((x) & 0x7FFF)
+#define EDMA_TCD_DOFF_DOFF(x)          (x)
+#define EDMA_TCD_DLAST_SGA_DLAST_SGA(x)        (x)
+#define EDMA_TCD_BITER_BITER(x)                ((x) & 0x7FFF)
+
+#define EDMA_TCD_CSR_START             BIT(0)
+#define EDMA_TCD_CSR_INT_MAJOR         BIT(1)
+#define EDMA_TCD_CSR_INT_HALF          BIT(2)
+#define EDMA_TCD_CSR_D_REQ             BIT(3)
+#define EDMA_TCD_CSR_E_SG              BIT(4)
+#define EDMA_TCD_CSR_E_LINK            BIT(5)
+#define EDMA_TCD_CSR_ACTIVE            BIT(6)
+#define EDMA_TCD_CSR_DONE              BIT(7)
+
+#define EDMAMUX_CHCFG_DIS              0x0
+#define EDMAMUX_CHCFG_ENBL             0x80
+#define EDMAMUX_CHCFG_SOURCE(n)                ((n) & 0x3F)
+
+#define DMAMUX_NR      2
+
+#define FSL_EDMA_BUSWIDTHS     BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+                               BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+                               BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+                               BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
+
+struct fsl_edma_hw_tcd {
+       u32     saddr;
+       u16     soff;
+       u16     attr;
+       u32     nbytes;
+       u32     slast;
+       u32     daddr;
+       u16     doff;
+       u16     citer;
+       u32     dlast_sga;
+       u16     csr;
+       u16     biter;
+};
+
+struct fsl_edma_sw_tcd {
+       dma_addr_t                      ptcd;
+       struct fsl_edma_hw_tcd          *vtcd;
+};
+
+struct fsl_edma_slave_config {
+       enum dma_transfer_direction     dir;
+       enum dma_slave_buswidth         addr_width;
+       u32                             dev_addr;
+       u32                             burst;
+       u32                             attr;
+};
+
+struct fsl_edma_chan {
+       struct virt_dma_chan            vchan;
+       enum dma_status                 status;
+       struct fsl_edma_engine          *edma;
+       struct fsl_edma_desc            *edesc;
+       struct fsl_edma_slave_config    fsc;
+       struct dma_pool                 *tcd_pool;
+};
+
+struct fsl_edma_desc {
+       struct virt_dma_desc            vdesc;
+       struct fsl_edma_chan            *echan;
+       bool                            iscyclic;
+       unsigned int                    n_tcds;
+       struct fsl_edma_sw_tcd          tcd[];
+};
+
+struct fsl_edma_engine {
+       struct dma_device       dma_dev;
+       void __iomem            *membase;
+       void __iomem            *muxbase[DMAMUX_NR];
+       struct clk              *muxclk[DMAMUX_NR];
+       struct mutex            fsl_edma_mutex;
+       u32                     n_chans;
+       int                     txirq;
+       int                     errirq;
+       bool                    big_endian;
+       struct fsl_edma_chan    chans[];
+};
+
+/*
+ * R/W functions for big- or little-endian registers
+ * the eDMA controller's endian is independent of the CPU core's endian.
+ */
+
+static u16 edma_readw(struct fsl_edma_engine *edma, void __iomem *addr)
+{
+       if (edma->big_endian)
+               return ioread16be(addr);
+       else
+               return ioread16(addr);
+}
+
+static u32 edma_readl(struct fsl_edma_engine *edma, void __iomem *addr)
+{
+       if (edma->big_endian)
+               return ioread32be(addr);
+       else
+               return ioread32(addr);
+}
+
+static void edma_writeb(struct fsl_edma_engine *edma, u8 val, void __iomem *addr)
+{
+       iowrite8(val, addr);
+}
+
+static void edma_writew(struct fsl_edma_engine *edma, u16 val, void __iomem *addr)
+{
+       if (edma->big_endian)
+               iowrite16be(val, addr);
+       else
+               iowrite16(val, addr);
+}
+
+static void edma_writel(struct fsl_edma_engine *edma, u32 val, void __iomem *addr)
+{
+       if (edma->big_endian)
+               iowrite32be(val, addr);
+       else
+               iowrite32(val, addr);
+}
+
+static struct fsl_edma_chan *to_fsl_edma_chan(struct dma_chan *chan)
+{
+       return container_of(chan, struct fsl_edma_chan, vchan.chan);
+}
+
+static struct fsl_edma_desc *to_fsl_edma_desc(struct virt_dma_desc *vd)
+{
+       return container_of(vd, struct fsl_edma_desc, vdesc);
+}
+
+static void fsl_edma_enable_request(struct fsl_edma_chan *fsl_chan)
+{
+       void __iomem *addr = fsl_chan->edma->membase;
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+
+       edma_writeb(fsl_chan->edma, EDMA_SEEI_SEEI(ch), addr + EDMA_SEEI);
+       edma_writeb(fsl_chan->edma, ch, addr + EDMA_SERQ);
+}
+
+static void fsl_edma_disable_request(struct fsl_edma_chan *fsl_chan)
+{
+       void __iomem *addr = fsl_chan->edma->membase;
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+
+       edma_writeb(fsl_chan->edma, ch, addr + EDMA_CERQ);
+       edma_writeb(fsl_chan->edma, EDMA_CEEI_CEEI(ch), addr + EDMA_CEEI);
+}
+
+static void fsl_edma_chan_mux(struct fsl_edma_chan *fsl_chan,
+                       unsigned int slot, bool enable)
+{
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+       void __iomem *muxaddr = fsl_chan->edma->muxbase[ch / DMAMUX_NR];
+       unsigned chans_per_mux, ch_off;
+
+       chans_per_mux = fsl_chan->edma->n_chans / DMAMUX_NR;
+       ch_off = fsl_chan->vchan.chan.chan_id % chans_per_mux;
+
+       if (enable)
+               edma_writeb(fsl_chan->edma,
+                               EDMAMUX_CHCFG_ENBL | EDMAMUX_CHCFG_SOURCE(slot),
+                               muxaddr + ch_off);
+       else
+               edma_writeb(fsl_chan->edma, EDMAMUX_CHCFG_DIS, muxaddr + ch_off);
+}
+
+static unsigned int fsl_edma_get_tcd_attr(enum dma_slave_buswidth addr_width)
+{
+       switch (addr_width) {
+       case 1:
+               return EDMA_TCD_ATTR_SSIZE_8BIT | EDMA_TCD_ATTR_DSIZE_8BIT;
+       case 2:
+               return EDMA_TCD_ATTR_SSIZE_16BIT | EDMA_TCD_ATTR_DSIZE_16BIT;
+       case 4:
+               return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+       case 8:
+               return EDMA_TCD_ATTR_SSIZE_64BIT | EDMA_TCD_ATTR_DSIZE_64BIT;
+       default:
+               return EDMA_TCD_ATTR_SSIZE_32BIT | EDMA_TCD_ATTR_DSIZE_32BIT;
+       }
+}
+
+static void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
+{
+       struct fsl_edma_desc *fsl_desc;
+       int i;
+
+       fsl_desc = to_fsl_edma_desc(vdesc);
+       for (i = 0; i < fsl_desc->n_tcds; i++)
+                       dma_pool_free(fsl_desc->echan->tcd_pool,
+                                       fsl_desc->tcd[i].vtcd,
+                                       fsl_desc->tcd[i].ptcd);
+       kfree(fsl_desc);
+}
+
+static int fsl_edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+               unsigned long arg)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       struct dma_slave_config *cfg = (void *)arg;
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       switch (cmd) {
+       case DMA_TERMINATE_ALL:
+               spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+               fsl_edma_disable_request(fsl_chan);
+               fsl_chan->edesc = NULL;
+               vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+               spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+               vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+               return 0;
+
+       case DMA_SLAVE_CONFIG:
+               fsl_chan->fsc.dir = cfg->direction;
+               if (cfg->direction == DMA_DEV_TO_MEM) {
+                       fsl_chan->fsc.dev_addr = cfg->src_addr;
+                       fsl_chan->fsc.addr_width = cfg->src_addr_width;
+                       fsl_chan->fsc.burst = cfg->src_maxburst;
+                       fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width);
+               } else if (cfg->direction == DMA_MEM_TO_DEV) {
+                       fsl_chan->fsc.dev_addr = cfg->dst_addr;
+                       fsl_chan->fsc.addr_width = cfg->dst_addr_width;
+                       fsl_chan->fsc.burst = cfg->dst_maxburst;
+                       fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width);
+               } else {
+                       return -EINVAL;
+               }
+               return 0;
+
+       case DMA_PAUSE:
+               spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+               if (fsl_chan->edesc) {
+                       fsl_edma_disable_request(fsl_chan);
+                       fsl_chan->status = DMA_PAUSED;
+               }
+               spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+               return 0;
+
+       case DMA_RESUME:
+               spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+               if (fsl_chan->edesc) {
+                       fsl_edma_enable_request(fsl_chan);
+                       fsl_chan->status = DMA_IN_PROGRESS;
+               }
+               spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+               return 0;
+
+       default:
+               return -ENXIO;
+       }
+}
+
+static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
+               struct virt_dma_desc *vdesc, bool in_progress)
+{
+       struct fsl_edma_desc *edesc = fsl_chan->edesc;
+       void __iomem *addr = fsl_chan->edma->membase;
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+       enum dma_transfer_direction dir = fsl_chan->fsc.dir;
+       dma_addr_t cur_addr, dma_addr;
+       size_t len, size;
+       int i;
+
+       /* calculate the total size in this desc */
+       for (len = i = 0; i < fsl_chan->edesc->n_tcds; i++)
+               len += edma_readl(fsl_chan->edma, &(edesc->tcd[i].vtcd->nbytes))
+                       * edma_readw(fsl_chan->edma, &(edesc->tcd[i].vtcd->biter));
+
+       if (!in_progress)
+               return len;
+
+       if (dir == DMA_MEM_TO_DEV)
+               cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_SADDR(ch));
+       else
+               cur_addr = edma_readl(fsl_chan->edma, addr + EDMA_TCD_DADDR(ch));
+
+       /* figure out the finished and calculate the residue */
+       for (i = 0; i < fsl_chan->edesc->n_tcds; i++) {
+               size = edma_readl(fsl_chan->edma, &(edesc->tcd[i].vtcd->nbytes))
+                       * edma_readw(fsl_chan->edma, &(edesc->tcd[i].vtcd->biter));
+               if (dir == DMA_MEM_TO_DEV)
+                       dma_addr = edma_readl(fsl_chan->edma,
+                                       &(edesc->tcd[i].vtcd->saddr));
+               else
+                       dma_addr = edma_readl(fsl_chan->edma,
+                                       &(edesc->tcd[i].vtcd->daddr));
+
+               len -= size;
+               if (cur_addr > dma_addr && cur_addr < dma_addr + size) {
+                       len += dma_addr + size - cur_addr;
+                       break;
+               }
+       }
+
+       return len;
+}
+
+static enum dma_status fsl_edma_tx_status(struct dma_chan *chan,
+               dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       struct virt_dma_desc *vdesc;
+       enum dma_status status;
+       unsigned long flags;
+
+       status = dma_cookie_status(chan, cookie, txstate);
+       if (status == DMA_COMPLETE)
+               return status;
+
+       if (!txstate)
+               return fsl_chan->status;
+
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+       vdesc = vchan_find_desc(&fsl_chan->vchan, cookie);
+       if (fsl_chan->edesc && cookie == fsl_chan->edesc->vdesc.tx.cookie)
+               txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, true);
+       else if (vdesc)
+               txstate->residue = fsl_edma_desc_residue(fsl_chan, vdesc, false);
+       else
+               txstate->residue = 0;
+
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+       return fsl_chan->status;
+}
+
+static void fsl_edma_set_tcd_params(struct fsl_edma_chan *fsl_chan,
+               u32 src, u32 dst, u16 attr, u16 soff, u32 nbytes,
+               u32 slast, u16 citer, u16 biter, u32 doff, u32 dlast_sga,
+               u16 csr)
+{
+       void __iomem *addr = fsl_chan->edma->membase;
+       u32 ch = fsl_chan->vchan.chan.chan_id;
+
+       /*
+        * TCD parameters have been swapped in fill_tcd_params(),
+        * so just write them to registers in the cpu endian here
+        */
+       writew(0, addr + EDMA_TCD_CSR(ch));
+       writel(src, addr + EDMA_TCD_SADDR(ch));
+       writel(dst, addr + EDMA_TCD_DADDR(ch));
+       writew(attr, addr + EDMA_TCD_ATTR(ch));
+       writew(soff, addr + EDMA_TCD_SOFF(ch));
+       writel(nbytes, addr + EDMA_TCD_NBYTES(ch));
+       writel(slast, addr + EDMA_TCD_SLAST(ch));
+       writew(citer, addr + EDMA_TCD_CITER(ch));
+       writew(biter, addr + EDMA_TCD_BITER(ch));
+       writew(doff, addr + EDMA_TCD_DOFF(ch));
+       writel(dlast_sga, addr + EDMA_TCD_DLAST_SGA(ch));
+       writew(csr, addr + EDMA_TCD_CSR(ch));
+}
+
+static void fill_tcd_params(struct fsl_edma_engine *edma,
+               struct fsl_edma_hw_tcd *tcd, u32 src, u32 dst,
+               u16 attr, u16 soff, u32 nbytes, u32 slast, u16 citer,
+               u16 biter, u16 doff, u32 dlast_sga, bool major_int,
+               bool disable_req, bool enable_sg)
+{
+       u16 csr = 0;
+
+       /*
+        * eDMA hardware SGs require the TCD parameters stored in memory
+        * the same endian as the eDMA module so that they can be loaded
+        * automatically by the engine
+        */
+       edma_writel(edma, src, &(tcd->saddr));
+       edma_writel(edma, dst, &(tcd->daddr));
+       edma_writew(edma, attr, &(tcd->attr));
+       edma_writew(edma, EDMA_TCD_SOFF_SOFF(soff), &(tcd->soff));
+       edma_writel(edma, EDMA_TCD_NBYTES_NBYTES(nbytes), &(tcd->nbytes));
+       edma_writel(edma, EDMA_TCD_SLAST_SLAST(slast), &(tcd->slast));
+       edma_writew(edma, EDMA_TCD_CITER_CITER(citer), &(tcd->citer));
+       edma_writew(edma, EDMA_TCD_DOFF_DOFF(doff), &(tcd->doff));
+       edma_writel(edma, EDMA_TCD_DLAST_SGA_DLAST_SGA(dlast_sga), &(tcd->dlast_sga));
+       edma_writew(edma, EDMA_TCD_BITER_BITER(biter), &(tcd->biter));
+       if (major_int)
+               csr |= EDMA_TCD_CSR_INT_MAJOR;
+
+       if (disable_req)
+               csr |= EDMA_TCD_CSR_D_REQ;
+
+       if (enable_sg)
+               csr |= EDMA_TCD_CSR_E_SG;
+
+       edma_writew(edma, csr, &(tcd->csr));
+}
+
+static struct fsl_edma_desc *fsl_edma_alloc_desc(struct fsl_edma_chan *fsl_chan,
+               int sg_len)
+{
+       struct fsl_edma_desc *fsl_desc;
+       int i;
+
+       fsl_desc = kzalloc(sizeof(*fsl_desc) + sizeof(struct fsl_edma_sw_tcd) * sg_len,
+                               GFP_NOWAIT);
+       if (!fsl_desc)
+               return NULL;
+
+       fsl_desc->echan = fsl_chan;
+       fsl_desc->n_tcds = sg_len;
+       for (i = 0; i < sg_len; i++) {
+               fsl_desc->tcd[i].vtcd = dma_pool_alloc(fsl_chan->tcd_pool,
+                                       GFP_NOWAIT, &fsl_desc->tcd[i].ptcd);
+               if (!fsl_desc->tcd[i].vtcd)
+                       goto err;
+       }
+       return fsl_desc;
+
+err:
+       while (--i >= 0)
+               dma_pool_free(fsl_chan->tcd_pool, fsl_desc->tcd[i].vtcd,
+                               fsl_desc->tcd[i].ptcd);
+       kfree(fsl_desc);
+       return NULL;
+}
+
+static struct dma_async_tx_descriptor *fsl_edma_prep_dma_cyclic(
+               struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+               size_t period_len, enum dma_transfer_direction direction,
+               unsigned long flags, void *context)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       struct fsl_edma_desc *fsl_desc;
+       dma_addr_t dma_buf_next;
+       int sg_len, i;
+       u32 src_addr, dst_addr, last_sg, nbytes;
+       u16 soff, doff, iter;
+
+       if (!is_slave_direction(fsl_chan->fsc.dir))
+               return NULL;
+
+       sg_len = buf_len / period_len;
+       fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
+       if (!fsl_desc)
+               return NULL;
+       fsl_desc->iscyclic = true;
+
+       dma_buf_next = dma_addr;
+       nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
+       iter = period_len / nbytes;
+
+       for (i = 0; i < sg_len; i++) {
+               if (dma_buf_next >= dma_addr + buf_len)
+                       dma_buf_next = dma_addr;
+
+               /* get next sg's physical address */
+               last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+               if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
+                       src_addr = dma_buf_next;
+                       dst_addr = fsl_chan->fsc.dev_addr;
+                       soff = fsl_chan->fsc.addr_width;
+                       doff = 0;
+               } else {
+                       src_addr = fsl_chan->fsc.dev_addr;
+                       dst_addr = dma_buf_next;
+                       soff = 0;
+                       doff = fsl_chan->fsc.addr_width;
+               }
+
+               fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd, src_addr,
+                               dst_addr, fsl_chan->fsc.attr, soff, nbytes, 0,
+                               iter, iter, doff, last_sg, true, false, true);
+               dma_buf_next += period_len;
+       }
+
+       return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+
+static struct dma_async_tx_descriptor *fsl_edma_prep_slave_sg(
+               struct dma_chan *chan, struct scatterlist *sgl,
+               unsigned int sg_len, enum dma_transfer_direction direction,
+               unsigned long flags, void *context)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       struct fsl_edma_desc *fsl_desc;
+       struct scatterlist *sg;
+       u32 src_addr, dst_addr, last_sg, nbytes;
+       u16 soff, doff, iter;
+       int i;
+
+       if (!is_slave_direction(fsl_chan->fsc.dir))
+               return NULL;
+
+       fsl_desc = fsl_edma_alloc_desc(fsl_chan, sg_len);
+       if (!fsl_desc)
+               return NULL;
+       fsl_desc->iscyclic = false;
+
+       nbytes = fsl_chan->fsc.addr_width * fsl_chan->fsc.burst;
+       for_each_sg(sgl, sg, sg_len, i) {
+               /* get next sg's physical address */
+               last_sg = fsl_desc->tcd[(i + 1) % sg_len].ptcd;
+
+               if (fsl_chan->fsc.dir == DMA_MEM_TO_DEV) {
+                       src_addr = sg_dma_address(sg);
+                       dst_addr = fsl_chan->fsc.dev_addr;
+                       soff = fsl_chan->fsc.addr_width;
+                       doff = 0;
+               } else {
+                       src_addr = fsl_chan->fsc.dev_addr;
+                       dst_addr = sg_dma_address(sg);
+                       soff = 0;
+                       doff = fsl_chan->fsc.addr_width;
+               }
+
+               iter = sg_dma_len(sg) / nbytes;
+               if (i < sg_len - 1) {
+                       last_sg = fsl_desc->tcd[(i + 1)].ptcd;
+                       fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd,
+                                       src_addr, dst_addr, fsl_chan->fsc.attr,
+                                       soff, nbytes, 0, iter, iter, doff, last_sg,
+                                       false, false, true);
+               } else {
+                       last_sg = 0;
+                       fill_tcd_params(fsl_chan->edma, fsl_desc->tcd[i].vtcd,
+                                       src_addr, dst_addr, fsl_chan->fsc.attr,
+                                       soff, nbytes, 0, iter, iter, doff, last_sg,
+                                       true, true, false);
+               }
+       }
+
+       return vchan_tx_prep(&fsl_chan->vchan, &fsl_desc->vdesc, flags);
+}
+
+static void fsl_edma_xfer_desc(struct fsl_edma_chan *fsl_chan)
+{
+       struct fsl_edma_hw_tcd *tcd;
+       struct virt_dma_desc *vdesc;
+
+       vdesc = vchan_next_desc(&fsl_chan->vchan);
+       if (!vdesc)
+               return;
+       fsl_chan->edesc = to_fsl_edma_desc(vdesc);
+       tcd = fsl_chan->edesc->tcd[0].vtcd;
+       fsl_edma_set_tcd_params(fsl_chan, tcd->saddr, tcd->daddr, tcd->attr,
+                       tcd->soff, tcd->nbytes, tcd->slast, tcd->citer,
+                       tcd->biter, tcd->doff, tcd->dlast_sga, tcd->csr);
+       fsl_edma_enable_request(fsl_chan);
+       fsl_chan->status = DMA_IN_PROGRESS;
+}
+
+static irqreturn_t fsl_edma_tx_handler(int irq, void *dev_id)
+{
+       struct fsl_edma_engine *fsl_edma = dev_id;
+       unsigned int intr, ch;
+       void __iomem *base_addr;
+       struct fsl_edma_chan *fsl_chan;
+
+       base_addr = fsl_edma->membase;
+
+       intr = edma_readl(fsl_edma, base_addr + EDMA_INTR);
+       if (!intr)
+               return IRQ_NONE;
+
+       for (ch = 0; ch < fsl_edma->n_chans; ch++) {
+               if (intr & (0x1 << ch)) {
+                       edma_writeb(fsl_edma, EDMA_CINT_CINT(ch),
+                               base_addr + EDMA_CINT);
+
+                       fsl_chan = &fsl_edma->chans[ch];
+
+                       spin_lock(&fsl_chan->vchan.lock);
+                       if (!fsl_chan->edesc->iscyclic) {
+                               list_del(&fsl_chan->edesc->vdesc.node);
+                               vchan_cookie_complete(&fsl_chan->edesc->vdesc);
+                               fsl_chan->edesc = NULL;
+                               fsl_chan->status = DMA_COMPLETE;
+                       } else {
+                               vchan_cyclic_callback(&fsl_chan->edesc->vdesc);
+                       }
+
+                       if (!fsl_chan->edesc)
+                               fsl_edma_xfer_desc(fsl_chan);
+
+                       spin_unlock(&fsl_chan->vchan.lock);
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t fsl_edma_err_handler(int irq, void *dev_id)
+{
+       struct fsl_edma_engine *fsl_edma = dev_id;
+       unsigned int err, ch;
+
+       err = edma_readl(fsl_edma, fsl_edma->membase + EDMA_ERR);
+       if (!err)
+               return IRQ_NONE;
+
+       for (ch = 0; ch < fsl_edma->n_chans; ch++) {
+               if (err & (0x1 << ch)) {
+                       fsl_edma_disable_request(&fsl_edma->chans[ch]);
+                       edma_writeb(fsl_edma, EDMA_CERR_CERR(ch),
+                               fsl_edma->membase + EDMA_CERR);
+                       fsl_edma->chans[ch].status = DMA_ERROR;
+               }
+       }
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t fsl_edma_irq_handler(int irq, void *dev_id)
+{
+       if (fsl_edma_tx_handler(irq, dev_id) == IRQ_HANDLED)
+               return IRQ_HANDLED;
+
+       return fsl_edma_err_handler(irq, dev_id);
+}
+
+static void fsl_edma_issue_pending(struct dma_chan *chan)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+
+       if (vchan_issue_pending(&fsl_chan->vchan) && !fsl_chan->edesc)
+               fsl_edma_xfer_desc(fsl_chan);
+
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+}
+
+static struct dma_chan *fsl_edma_xlate(struct of_phandle_args *dma_spec,
+               struct of_dma *ofdma)
+{
+       struct fsl_edma_engine *fsl_edma = ofdma->of_dma_data;
+       struct dma_chan *chan, *_chan;
+
+       if (dma_spec->args_count != 2)
+               return NULL;
+
+       mutex_lock(&fsl_edma->fsl_edma_mutex);
+       list_for_each_entry_safe(chan, _chan, &fsl_edma->dma_dev.channels, device_node) {
+               if (chan->client_count)
+                       continue;
+               if ((chan->chan_id / DMAMUX_NR) == dma_spec->args[0]) {
+                       chan = dma_get_slave_channel(chan);
+                       if (chan) {
+                               chan->device->privatecnt++;
+                               fsl_edma_chan_mux(to_fsl_edma_chan(chan),
+                                       dma_spec->args[1], true);
+                               mutex_unlock(&fsl_edma->fsl_edma_mutex);
+                               return chan;
+                       }
+               }
+       }
+       mutex_unlock(&fsl_edma->fsl_edma_mutex);
+       return NULL;
+}
+
+static int fsl_edma_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+
+       fsl_chan->tcd_pool = dma_pool_create("tcd_pool", chan->device->dev,
+                               sizeof(struct fsl_edma_hw_tcd),
+                               32, 0);
+       return 0;
+}
+
+static void fsl_edma_free_chan_resources(struct dma_chan *chan)
+{
+       struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+       unsigned long flags;
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+       fsl_edma_disable_request(fsl_chan);
+       fsl_edma_chan_mux(fsl_chan, 0, false);
+       fsl_chan->edesc = NULL;
+       vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+       spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+
+       vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+       dma_pool_destroy(fsl_chan->tcd_pool);
+       fsl_chan->tcd_pool = NULL;
+}
+
+static int fsl_dma_device_slave_caps(struct dma_chan *dchan,
+               struct dma_slave_caps *caps)
+{
+       caps->src_addr_widths = FSL_EDMA_BUSWIDTHS;
+       caps->dstn_addr_widths = FSL_EDMA_BUSWIDTHS;
+       caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       caps->cmd_pause = true;
+       caps->cmd_terminate = true;
+
+       return 0;
+}
+
+static int
+fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
+{
+       int ret;
+
+       fsl_edma->txirq = platform_get_irq_byname(pdev, "edma-tx");
+       if (fsl_edma->txirq < 0) {
+               dev_err(&pdev->dev, "Can't get edma-tx irq.\n");
+               return fsl_edma->txirq;
+       }
+
+       fsl_edma->errirq = platform_get_irq_byname(pdev, "edma-err");
+       if (fsl_edma->errirq < 0) {
+               dev_err(&pdev->dev, "Can't get edma-err irq.\n");
+               return fsl_edma->errirq;
+       }
+
+       if (fsl_edma->txirq == fsl_edma->errirq) {
+               ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
+                               fsl_edma_irq_handler, 0, "eDMA", fsl_edma);
+               if (ret) {
+                       dev_err(&pdev->dev, "Can't register eDMA IRQ.\n");
+                        return  ret;
+               }
+       } else {
+               ret = devm_request_irq(&pdev->dev, fsl_edma->txirq,
+                               fsl_edma_tx_handler, 0, "eDMA tx", fsl_edma);
+               if (ret) {
+                       dev_err(&pdev->dev, "Can't register eDMA tx IRQ.\n");
+                       return  ret;
+               }
+
+               ret = devm_request_irq(&pdev->dev, fsl_edma->errirq,
+                               fsl_edma_err_handler, 0, "eDMA err", fsl_edma);
+               if (ret) {
+                       dev_err(&pdev->dev, "Can't register eDMA err IRQ.\n");
+                       return  ret;
+               }
+       }
+
+       return 0;
+}
+
+static int fsl_edma_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct fsl_edma_engine *fsl_edma;
+       struct fsl_edma_chan *fsl_chan;
+       struct resource *res;
+       int len, chans;
+       int ret, i;
+
+       ret = of_property_read_u32(np, "dma-channels", &chans);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't get dma-channels.\n");
+               return ret;
+       }
+
+       len = sizeof(*fsl_edma) + sizeof(*fsl_chan) * chans;
+       fsl_edma = devm_kzalloc(&pdev->dev, len, GFP_KERNEL);
+       if (!fsl_edma)
+               return -ENOMEM;
+
+       fsl_edma->n_chans = chans;
+       mutex_init(&fsl_edma->fsl_edma_mutex);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       fsl_edma->membase = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(fsl_edma->membase))
+               return PTR_ERR(fsl_edma->membase);
+
+       for (i = 0; i < DMAMUX_NR; i++) {
+               char clkname[32];
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 1 + i);
+               fsl_edma->muxbase[i] = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(fsl_edma->muxbase[i]))
+                       return PTR_ERR(fsl_edma->muxbase[i]);
+
+               sprintf(clkname, "dmamux%d", i);
+               fsl_edma->muxclk[i] = devm_clk_get(&pdev->dev, clkname);
+               if (IS_ERR(fsl_edma->muxclk[i])) {
+                       dev_err(&pdev->dev, "Missing DMAMUX block clock.\n");
+                       return PTR_ERR(fsl_edma->muxclk[i]);
+               }
+
+               ret = clk_prepare_enable(fsl_edma->muxclk[i]);
+               if (ret) {
+                       dev_err(&pdev->dev, "DMAMUX clk block failed.\n");
+                       return ret;
+               }
+
+       }
+
+       ret = fsl_edma_irq_init(pdev, fsl_edma);
+       if (ret)
+               return ret;
+
+       fsl_edma->big_endian = of_property_read_bool(np, "big-endian");
+
+       INIT_LIST_HEAD(&fsl_edma->dma_dev.channels);
+       for (i = 0; i < fsl_edma->n_chans; i++) {
+               struct fsl_edma_chan *fsl_chan = &fsl_edma->chans[i];
+
+               fsl_chan->edma = fsl_edma;
+
+               fsl_chan->vchan.desc_free = fsl_edma_free_desc;
+               vchan_init(&fsl_chan->vchan, &fsl_edma->dma_dev);
+
+               edma_writew(fsl_edma, 0x0, fsl_edma->membase + EDMA_TCD_CSR(i));
+               fsl_edma_chan_mux(fsl_chan, 0, false);
+       }
+
+       dma_cap_set(DMA_PRIVATE, fsl_edma->dma_dev.cap_mask);
+       dma_cap_set(DMA_SLAVE, fsl_edma->dma_dev.cap_mask);
+       dma_cap_set(DMA_CYCLIC, fsl_edma->dma_dev.cap_mask);
+
+       fsl_edma->dma_dev.dev = &pdev->dev;
+       fsl_edma->dma_dev.device_alloc_chan_resources
+               = fsl_edma_alloc_chan_resources;
+       fsl_edma->dma_dev.device_free_chan_resources
+               = fsl_edma_free_chan_resources;
+       fsl_edma->dma_dev.device_tx_status = fsl_edma_tx_status;
+       fsl_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
+       fsl_edma->dma_dev.device_prep_dma_cyclic = fsl_edma_prep_dma_cyclic;
+       fsl_edma->dma_dev.device_control = fsl_edma_control;
+       fsl_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending;
+       fsl_edma->dma_dev.device_slave_caps = fsl_dma_device_slave_caps;
+
+       platform_set_drvdata(pdev, fsl_edma);
+
+       ret = dma_async_device_register(&fsl_edma->dma_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't register Freescale eDMA engine.\n");
+               return ret;
+       }
+
+       ret = of_dma_controller_register(np, fsl_edma_xlate, fsl_edma);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't register Freescale eDMA of_dma.\n");
+               dma_async_device_unregister(&fsl_edma->dma_dev);
+               return ret;
+       }
+
+       /* enable round robin arbitration */
+       edma_writel(fsl_edma, EDMA_CR_ERGA | EDMA_CR_ERCA, fsl_edma->membase + EDMA_CR);
+
+       return 0;
+}
+
+static int fsl_edma_remove(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct fsl_edma_engine *fsl_edma = platform_get_drvdata(pdev);
+       int i;
+
+       of_dma_controller_free(np);
+       dma_async_device_unregister(&fsl_edma->dma_dev);
+
+       for (i = 0; i < DMAMUX_NR; i++)
+               clk_disable_unprepare(fsl_edma->muxclk[i]);
+
+       return 0;
+}
+
+static const struct of_device_id fsl_edma_dt_ids[] = {
+       { .compatible = "fsl,vf610-edma", },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, fsl_edma_dt_ids);
+
+static struct platform_driver fsl_edma_driver = {
+       .driver         = {
+               .name   = "fsl-edma",
+               .owner  = THIS_MODULE,
+               .of_match_table = fsl_edma_dt_ids,
+       },
+       .probe          = fsl_edma_probe,
+       .remove         = fsl_edma_remove,
+};
+
+module_platform_driver(fsl_edma_driver);
+
+MODULE_ALIAS("platform:fsl-edma");
+MODULE_DESCRIPTION("Freescale eDMA engine driver");
+MODULE_LICENSE("GPL v2");
index 6f9ac20..286660a 100644 (file)
@@ -422,12 +422,12 @@ static irqreturn_t imxdma_err_handler(int irq, void *dev_id)
                /* Tasklet error handler */
                tasklet_schedule(&imxdma->channel[i].dma_tasklet);
 
-               printk(KERN_WARNING
-                      "DMA timeout on channel %d -%s%s%s%s\n", i,
-                      errcode & IMX_DMA_ERR_BURST ?    " burst" : "",
-                      errcode & IMX_DMA_ERR_REQUEST ?  " request" : "",
-                      errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
-                      errcode & IMX_DMA_ERR_BUFFER ?   " buffer" : "");
+               dev_warn(imxdma->dev,
+                        "DMA timeout on channel %d -%s%s%s%s\n", i,
+                        errcode & IMX_DMA_ERR_BURST ?    " burst" : "",
+                        errcode & IMX_DMA_ERR_REQUEST ?  " request" : "",
+                        errcode & IMX_DMA_ERR_TRANSFER ? " transfer" : "",
+                        errcode & IMX_DMA_ERR_BUFFER ?   " buffer" : "");
        }
        return IRQ_HANDLED;
 }
@@ -1236,6 +1236,7 @@ static int imxdma_remove(struct platform_device *pdev)
 static struct platform_driver imxdma_driver = {
        .driver         = {
                .name   = "imx-dma",
+               .owner  = THIS_MODULE,
                .of_match_table = imx_dma_of_dev_id,
        },
        .id_table       = imx_dma_devtype,
index b439679..bf02e7b 100644 (file)
@@ -867,8 +867,8 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq)
        phy->base = pdev->base;
 
        if (irq) {
-               ret = devm_request_irq(pdev->dev, irq, mmp_pdma_chan_handler, 0,
-                                      "pdma", phy);
+               ret = devm_request_irq(pdev->dev, irq, mmp_pdma_chan_handler,
+                                      IRQF_SHARED, "pdma", phy);
                if (ret) {
                        dev_err(pdev->dev, "channel request irq fail!\n");
                        return ret;
@@ -957,8 +957,8 @@ static int mmp_pdma_probe(struct platform_device *op)
        if (irq_num != dma_channels) {
                /* all chan share one irq, demux inside */
                irq = platform_get_irq(op, 0);
-               ret = devm_request_irq(pdev->dev, irq, mmp_pdma_int_handler, 0,
-                                      "pdma", pdev);
+               ret = devm_request_irq(pdev->dev, irq, mmp_pdma_int_handler,
+                                      IRQF_SHARED, "pdma", pdev);
                if (ret)
                        return ret;
        }
index 33f96aa..724f7f4 100644 (file)
@@ -22,6 +22,7 @@
 #include <mach/regs-icu.h>
 #include <linux/platform_data/dma-mmp_tdma.h>
 #include <linux/of_device.h>
+#include <linux/of_dma.h>
 
 #include "dmaengine.h"
 
@@ -541,6 +542,45 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
        return 0;
 }
 
+struct mmp_tdma_filter_param {
+       struct device_node *of_node;
+       unsigned int chan_id;
+};
+
+static bool mmp_tdma_filter_fn(struct dma_chan *chan, void *fn_param)
+{
+       struct mmp_tdma_filter_param *param = fn_param;
+       struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+       struct dma_device *pdma_device = tdmac->chan.device;
+
+       if (pdma_device->dev->of_node != param->of_node)
+               return false;
+
+       if (chan->chan_id != param->chan_id)
+               return false;
+
+       return true;
+}
+
+struct dma_chan *mmp_tdma_xlate(struct of_phandle_args *dma_spec,
+                              struct of_dma *ofdma)
+{
+       struct mmp_tdma_device *tdev = ofdma->of_dma_data;
+       dma_cap_mask_t mask = tdev->device.cap_mask;
+       struct mmp_tdma_filter_param param;
+
+       if (dma_spec->args_count != 1)
+               return NULL;
+
+       param.of_node = ofdma->of_node;
+       param.chan_id = dma_spec->args[0];
+
+       if (param.chan_id >= TDMA_CHANNEL_NUM)
+               return NULL;
+
+       return dma_request_channel(mask, mmp_tdma_filter_fn, &param);
+}
+
 static struct of_device_id mmp_tdma_dt_ids[] = {
        { .compatible = "marvell,adma-1.0", .data = (void *)MMP_AUD_TDMA},
        { .compatible = "marvell,pxa910-squ", .data = (void *)PXA910_SQU},
@@ -631,6 +671,16 @@ static int mmp_tdma_probe(struct platform_device *pdev)
                return ret;
        }
 
+       if (pdev->dev.of_node) {
+               ret = of_dma_controller_register(pdev->dev.of_node,
+                                                       mmp_tdma_xlate, tdev);
+               if (ret) {
+                       dev_err(tdev->device.dev,
+                               "failed to register controller\n");
+                       dma_async_device_unregister(&tdev->device);
+               }
+       }
+
        dev_info(tdev->device.dev, "initialized\n");
        return 0;
 }
index 64ceca2..b19f04f 100644 (file)
@@ -1088,6 +1088,23 @@ static void omap_dma_free(struct omap_dmadev *od)
        }
 }
 
+#define OMAP_DMA_BUSWIDTHS     (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+                                BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
+
+static int omap_dma_device_slave_caps(struct dma_chan *dchan,
+                                     struct dma_slave_caps *caps)
+{
+       caps->src_addr_widths = OMAP_DMA_BUSWIDTHS;
+       caps->dstn_addr_widths = OMAP_DMA_BUSWIDTHS;
+       caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       caps->cmd_pause = true;
+       caps->cmd_terminate = true;
+       caps->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+
+       return 0;
+}
+
 static int omap_dma_probe(struct platform_device *pdev)
 {
        struct omap_dmadev *od;
@@ -1118,6 +1135,7 @@ static int omap_dma_probe(struct platform_device *pdev)
        od->ddev.device_prep_slave_sg = omap_dma_prep_slave_sg;
        od->ddev.device_prep_dma_cyclic = omap_dma_prep_dma_cyclic;
        od->ddev.device_control = omap_dma_control;
+       od->ddev.device_slave_caps = omap_dma_device_slave_caps;
        od->ddev.dev = &pdev->dev;
        INIT_LIST_HEAD(&od->ddev.channels);
        INIT_LIST_HEAD(&od->pending);
index 61fdc54..05fa548 100644 (file)
@@ -964,16 +964,16 @@ static void pch_dma_remove(struct pci_dev *pdev)
        if (pd) {
                dma_async_device_unregister(&pd->dma);
 
+               free_irq(pdev->irq, pd);
+
                list_for_each_entry_safe(chan, _c, &pd->dma.channels,
                                         device_node) {
                        pd_chan = to_pd_chan(chan);
 
-                       tasklet_disable(&pd_chan->tasklet);
                        tasklet_kill(&pd_chan->tasklet);
                }
 
                pci_pool_destroy(pd->pool);
-               free_irq(pdev->irq, pd);
                pci_iounmap(pdev, pd->membase);
                pci_release_regions(pdev);
                pci_disable_device(pdev);
diff --git a/drivers/dma/qcom_bam_dma.c b/drivers/dma/qcom_bam_dma.c
new file mode 100644 (file)
index 0000000..82c9231
--- /dev/null
@@ -0,0 +1,1111 @@
+/*
+ * Copyright (c) 2013-2014, The Linux Foundation. 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 version 2 and
+ * only 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.
+ *
+ */
+/*
+ * QCOM BAM DMA engine driver
+ *
+ * QCOM BAM DMA blocks are distributed amongst a number of the on-chip
+ * peripherals on the MSM 8x74.  The configuration of the channels are dependent
+ * on the way they are hard wired to that specific peripheral.  The peripheral
+ * device tree entries specify the configuration of each channel.
+ *
+ * The DMA controller requires the use of external memory for storage of the
+ * hardware descriptors for each channel.  The descriptor FIFO is accessed as a
+ * circular buffer and operations are managed according to the offset within the
+ * FIFO.  After pipe/channel reset, all of the pipe registers and internal state
+ * are back to defaults.
+ *
+ * During DMA operations, we write descriptors to the FIFO, being careful to
+ * handle wrapping and then write the last FIFO offset to that channel's
+ * P_EVNT_REG register to kick off the transaction.  The P_SW_OFSTS register
+ * indicates the current FIFO offset that is being processed, so there is some
+ * indication of where the hardware is currently working.
+ */
+
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/dma-mapping.h>
+#include <linux/scatterlist.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_dma.h>
+#include <linux/clk.h>
+#include <linux/dmaengine.h>
+
+#include "dmaengine.h"
+#include "virt-dma.h"
+
+struct bam_desc_hw {
+       u32 addr;               /* Buffer physical address */
+       u16 size;               /* Buffer size in bytes */
+       u16 flags;
+};
+
+#define DESC_FLAG_INT BIT(15)
+#define DESC_FLAG_EOT BIT(14)
+#define DESC_FLAG_EOB BIT(13)
+
+struct bam_async_desc {
+       struct virt_dma_desc vd;
+
+       u32 num_desc;
+       u32 xfer_len;
+       struct bam_desc_hw *curr_desc;
+
+       enum dma_transfer_direction dir;
+       size_t length;
+       struct bam_desc_hw desc[0];
+};
+
+#define BAM_CTRL                       0x0000
+#define BAM_REVISION                   0x0004
+#define BAM_SW_REVISION                        0x0080
+#define BAM_NUM_PIPES                  0x003C
+#define BAM_TIMER                      0x0040
+#define BAM_TIMER_CTRL                 0x0044
+#define BAM_DESC_CNT_TRSHLD            0x0008
+#define BAM_IRQ_SRCS                   0x000C
+#define BAM_IRQ_SRCS_MSK               0x0010
+#define BAM_IRQ_SRCS_UNMASKED          0x0030
+#define BAM_IRQ_STTS                   0x0014
+#define BAM_IRQ_CLR                    0x0018
+#define BAM_IRQ_EN                     0x001C
+#define BAM_CNFG_BITS                  0x007C
+#define BAM_IRQ_SRCS_EE(ee)            (0x0800 + ((ee) * 0x80))
+#define BAM_IRQ_SRCS_MSK_EE(ee)                (0x0804 + ((ee) * 0x80))
+#define BAM_P_CTRL(pipe)               (0x1000 + ((pipe) * 0x1000))
+#define BAM_P_RST(pipe)                        (0x1004 + ((pipe) * 0x1000))
+#define BAM_P_HALT(pipe)               (0x1008 + ((pipe) * 0x1000))
+#define BAM_P_IRQ_STTS(pipe)           (0x1010 + ((pipe) * 0x1000))
+#define BAM_P_IRQ_CLR(pipe)            (0x1014 + ((pipe) * 0x1000))
+#define BAM_P_IRQ_EN(pipe)             (0x1018 + ((pipe) * 0x1000))
+#define BAM_P_EVNT_DEST_ADDR(pipe)     (0x182C + ((pipe) * 0x1000))
+#define BAM_P_EVNT_REG(pipe)           (0x1818 + ((pipe) * 0x1000))
+#define BAM_P_SW_OFSTS(pipe)           (0x1800 + ((pipe) * 0x1000))
+#define BAM_P_DATA_FIFO_ADDR(pipe)     (0x1824 + ((pipe) * 0x1000))
+#define BAM_P_DESC_FIFO_ADDR(pipe)     (0x181C + ((pipe) * 0x1000))
+#define BAM_P_EVNT_TRSHLD(pipe)                (0x1828 + ((pipe) * 0x1000))
+#define BAM_P_FIFO_SIZES(pipe)         (0x1820 + ((pipe) * 0x1000))
+
+/* BAM CTRL */
+#define BAM_SW_RST                     BIT(0)
+#define BAM_EN                         BIT(1)
+#define BAM_EN_ACCUM                   BIT(4)
+#define BAM_TESTBUS_SEL_SHIFT          5
+#define BAM_TESTBUS_SEL_MASK           0x3F
+#define BAM_DESC_CACHE_SEL_SHIFT       13
+#define BAM_DESC_CACHE_SEL_MASK                0x3
+#define BAM_CACHED_DESC_STORE          BIT(15)
+#define IBC_DISABLE                    BIT(16)
+
+/* BAM REVISION */
+#define REVISION_SHIFT         0
+#define REVISION_MASK          0xFF
+#define NUM_EES_SHIFT          8
+#define NUM_EES_MASK           0xF
+#define CE_BUFFER_SIZE         BIT(13)
+#define AXI_ACTIVE             BIT(14)
+#define USE_VMIDMT             BIT(15)
+#define SECURED                        BIT(16)
+#define BAM_HAS_NO_BYPASS      BIT(17)
+#define HIGH_FREQUENCY_BAM     BIT(18)
+#define INACTIV_TMRS_EXST      BIT(19)
+#define NUM_INACTIV_TMRS       BIT(20)
+#define DESC_CACHE_DEPTH_SHIFT 21
+#define DESC_CACHE_DEPTH_1     (0 << DESC_CACHE_DEPTH_SHIFT)
+#define DESC_CACHE_DEPTH_2     (1 << DESC_CACHE_DEPTH_SHIFT)
+#define DESC_CACHE_DEPTH_3     (2 << DESC_CACHE_DEPTH_SHIFT)
+#define DESC_CACHE_DEPTH_4     (3 << DESC_CACHE_DEPTH_SHIFT)
+#define CMD_DESC_EN            BIT(23)
+#define INACTIV_TMR_BASE_SHIFT 24
+#define INACTIV_TMR_BASE_MASK  0xFF
+
+/* BAM NUM PIPES */
+#define BAM_NUM_PIPES_SHIFT            0
+#define BAM_NUM_PIPES_MASK             0xFF
+#define PERIPH_NON_PIPE_GRP_SHIFT      16
+#define PERIPH_NON_PIP_GRP_MASK                0xFF
+#define BAM_NON_PIPE_GRP_SHIFT         24
+#define BAM_NON_PIPE_GRP_MASK          0xFF
+
+/* BAM CNFG BITS */
+#define BAM_PIPE_CNFG          BIT(2)
+#define BAM_FULL_PIPE          BIT(11)
+#define BAM_NO_EXT_P_RST       BIT(12)
+#define BAM_IBC_DISABLE                BIT(13)
+#define BAM_SB_CLK_REQ         BIT(14)
+#define BAM_PSM_CSW_REQ                BIT(15)
+#define BAM_PSM_P_RES          BIT(16)
+#define BAM_AU_P_RES           BIT(17)
+#define BAM_SI_P_RES           BIT(18)
+#define BAM_WB_P_RES           BIT(19)
+#define BAM_WB_BLK_CSW         BIT(20)
+#define BAM_WB_CSW_ACK_IDL     BIT(21)
+#define BAM_WB_RETR_SVPNT      BIT(22)
+#define BAM_WB_DSC_AVL_P_RST   BIT(23)
+#define BAM_REG_P_EN           BIT(24)
+#define BAM_PSM_P_HD_DATA      BIT(25)
+#define BAM_AU_ACCUMED         BIT(26)
+#define BAM_CMD_ENABLE         BIT(27)
+
+#define BAM_CNFG_BITS_DEFAULT  (BAM_PIPE_CNFG |        \
+                                BAM_NO_EXT_P_RST |     \
+                                BAM_IBC_DISABLE |      \
+                                BAM_SB_CLK_REQ |       \
+                                BAM_PSM_CSW_REQ |      \
+                                BAM_PSM_P_RES |        \
+                                BAM_AU_P_RES |         \
+                                BAM_SI_P_RES |         \
+                                BAM_WB_P_RES |         \
+                                BAM_WB_BLK_CSW |       \
+                                BAM_WB_CSW_ACK_IDL |   \
+                                BAM_WB_RETR_SVPNT |    \
+                                BAM_WB_DSC_AVL_P_RST | \
+                                BAM_REG_P_EN |         \
+                                BAM_PSM_P_HD_DATA |    \
+                                BAM_AU_ACCUMED |       \
+                                BAM_CMD_ENABLE)
+
+/* PIPE CTRL */
+#define P_EN                   BIT(1)
+#define P_DIRECTION            BIT(3)
+#define P_SYS_STRM             BIT(4)
+#define P_SYS_MODE             BIT(5)
+#define P_AUTO_EOB             BIT(6)
+#define P_AUTO_EOB_SEL_SHIFT   7
+#define P_AUTO_EOB_SEL_512     (0 << P_AUTO_EOB_SEL_SHIFT)
+#define P_AUTO_EOB_SEL_256     (1 << P_AUTO_EOB_SEL_SHIFT)
+#define P_AUTO_EOB_SEL_128     (2 << P_AUTO_EOB_SEL_SHIFT)
+#define P_AUTO_EOB_SEL_64      (3 << P_AUTO_EOB_SEL_SHIFT)
+#define P_PREFETCH_LIMIT_SHIFT 9
+#define P_PREFETCH_LIMIT_32    (0 << P_PREFETCH_LIMIT_SHIFT)
+#define P_PREFETCH_LIMIT_16    (1 << P_PREFETCH_LIMIT_SHIFT)
+#define P_PREFETCH_LIMIT_4     (2 << P_PREFETCH_LIMIT_SHIFT)
+#define P_WRITE_NWD            BIT(11)
+#define P_LOCK_GROUP_SHIFT     16
+#define P_LOCK_GROUP_MASK      0x1F
+
+/* BAM_DESC_CNT_TRSHLD */
+#define CNT_TRSHLD             0xffff
+#define DEFAULT_CNT_THRSHLD    0x4
+
+/* BAM_IRQ_SRCS */
+#define BAM_IRQ                        BIT(31)
+#define P_IRQ                  0x7fffffff
+
+/* BAM_IRQ_SRCS_MSK */
+#define BAM_IRQ_MSK            BAM_IRQ
+#define P_IRQ_MSK              P_IRQ
+
+/* BAM_IRQ_STTS */
+#define BAM_TIMER_IRQ          BIT(4)
+#define BAM_EMPTY_IRQ          BIT(3)
+#define BAM_ERROR_IRQ          BIT(2)
+#define BAM_HRESP_ERR_IRQ      BIT(1)
+
+/* BAM_IRQ_CLR */
+#define BAM_TIMER_CLR          BIT(4)
+#define BAM_EMPTY_CLR          BIT(3)
+#define BAM_ERROR_CLR          BIT(2)
+#define BAM_HRESP_ERR_CLR      BIT(1)
+
+/* BAM_IRQ_EN */
+#define BAM_TIMER_EN           BIT(4)
+#define BAM_EMPTY_EN           BIT(3)
+#define BAM_ERROR_EN           BIT(2)
+#define BAM_HRESP_ERR_EN       BIT(1)
+
+/* BAM_P_IRQ_EN */
+#define P_PRCSD_DESC_EN                BIT(0)
+#define P_TIMER_EN             BIT(1)
+#define P_WAKE_EN              BIT(2)
+#define P_OUT_OF_DESC_EN       BIT(3)
+#define P_ERR_EN               BIT(4)
+#define P_TRNSFR_END_EN                BIT(5)
+#define P_DEFAULT_IRQS_EN      (P_PRCSD_DESC_EN | P_ERR_EN | P_TRNSFR_END_EN)
+
+/* BAM_P_SW_OFSTS */
+#define P_SW_OFSTS_MASK                0xffff
+
+#define BAM_DESC_FIFO_SIZE     SZ_32K
+#define MAX_DESCRIPTORS (BAM_DESC_FIFO_SIZE / sizeof(struct bam_desc_hw) - 1)
+#define BAM_MAX_DATA_SIZE      (SZ_32K - 8)
+
+struct bam_chan {
+       struct virt_dma_chan vc;
+
+       struct bam_device *bdev;
+
+       /* configuration from device tree */
+       u32 id;
+
+       struct bam_async_desc *curr_txd;        /* current running dma */
+
+       /* runtime configuration */
+       struct dma_slave_config slave;
+
+       /* fifo storage */
+       struct bam_desc_hw *fifo_virt;
+       dma_addr_t fifo_phys;
+
+       /* fifo markers */
+       unsigned short head;            /* start of active descriptor entries */
+       unsigned short tail;            /* end of active descriptor entries */
+
+       unsigned int initialized;       /* is the channel hw initialized? */
+       unsigned int paused;            /* is the channel paused? */
+       unsigned int reconfigure;       /* new slave config? */
+
+       struct list_head node;
+};
+
+static inline struct bam_chan *to_bam_chan(struct dma_chan *common)
+{
+       return container_of(common, struct bam_chan, vc.chan);
+}
+
+struct bam_device {
+       void __iomem *regs;
+       struct device *dev;
+       struct dma_device common;
+       struct device_dma_parameters dma_parms;
+       struct bam_chan *channels;
+       u32 num_channels;
+
+       /* execution environment ID, from DT */
+       u32 ee;
+
+       struct clk *bamclk;
+       int irq;
+
+       /* dma start transaction tasklet */
+       struct tasklet_struct task;
+};
+
+/**
+ * bam_reset_channel - Reset individual BAM DMA channel
+ * @bchan: bam channel
+ *
+ * This function resets a specific BAM channel
+ */
+static void bam_reset_channel(struct bam_chan *bchan)
+{
+       struct bam_device *bdev = bchan->bdev;
+
+       lockdep_assert_held(&bchan->vc.lock);
+
+       /* reset channel */
+       writel_relaxed(1, bdev->regs + BAM_P_RST(bchan->id));
+       writel_relaxed(0, bdev->regs + BAM_P_RST(bchan->id));
+
+       /* don't allow cpu to reorder BAM register accesses done after this */
+       wmb();
+
+       /* make sure hw is initialized when channel is used the first time  */
+       bchan->initialized = 0;
+}
+
+/**
+ * bam_chan_init_hw - Initialize channel hardware
+ * @bchan: bam channel
+ *
+ * This function resets and initializes the BAM channel
+ */
+static void bam_chan_init_hw(struct bam_chan *bchan,
+       enum dma_transfer_direction dir)
+{
+       struct bam_device *bdev = bchan->bdev;
+       u32 val;
+
+       /* Reset the channel to clear internal state of the FIFO */
+       bam_reset_channel(bchan);
+
+       /*
+        * write out 8 byte aligned address.  We have enough space for this
+        * because we allocated 1 more descriptor (8 bytes) than we can use
+        */
+       writel_relaxed(ALIGN(bchan->fifo_phys, sizeof(struct bam_desc_hw)),
+                       bdev->regs + BAM_P_DESC_FIFO_ADDR(bchan->id));
+       writel_relaxed(BAM_DESC_FIFO_SIZE, bdev->regs +
+                       BAM_P_FIFO_SIZES(bchan->id));
+
+       /* enable the per pipe interrupts, enable EOT, ERR, and INT irqs */
+       writel_relaxed(P_DEFAULT_IRQS_EN, bdev->regs + BAM_P_IRQ_EN(bchan->id));
+
+       /* unmask the specific pipe and EE combo */
+       val = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+       val |= BIT(bchan->id);
+       writel_relaxed(val, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+
+       /* don't allow cpu to reorder the channel enable done below */
+       wmb();
+
+       /* set fixed direction and mode, then enable channel */
+       val = P_EN | P_SYS_MODE;
+       if (dir == DMA_DEV_TO_MEM)
+               val |= P_DIRECTION;
+
+       writel_relaxed(val, bdev->regs + BAM_P_CTRL(bchan->id));
+
+       bchan->initialized = 1;
+
+       /* init FIFO pointers */
+       bchan->head = 0;
+       bchan->tail = 0;
+}
+
+/**
+ * bam_alloc_chan - Allocate channel resources for DMA channel.
+ * @chan: specified channel
+ *
+ * This function allocates the FIFO descriptor memory
+ */
+static int bam_alloc_chan(struct dma_chan *chan)
+{
+       struct bam_chan *bchan = to_bam_chan(chan);
+       struct bam_device *bdev = bchan->bdev;
+
+       if (bchan->fifo_virt)
+               return 0;
+
+       /* allocate FIFO descriptor space, but only if necessary */
+       bchan->fifo_virt = dma_alloc_writecombine(bdev->dev, BAM_DESC_FIFO_SIZE,
+                               &bchan->fifo_phys, GFP_KERNEL);
+
+       if (!bchan->fifo_virt) {
+               dev_err(bdev->dev, "Failed to allocate desc fifo\n");
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+/**
+ * bam_free_chan - Frees dma resources associated with specific channel
+ * @chan: specified channel
+ *
+ * Free the allocated fifo descriptor memory and channel resources
+ *
+ */
+static void bam_free_chan(struct dma_chan *chan)
+{
+       struct bam_chan *bchan = to_bam_chan(chan);
+       struct bam_device *bdev = bchan->bdev;
+       u32 val;
+       unsigned long flags;
+
+       vchan_free_chan_resources(to_virt_chan(chan));
+
+       if (bchan->curr_txd) {
+               dev_err(bchan->bdev->dev, "Cannot free busy channel\n");
+               return;
+       }
+
+       spin_lock_irqsave(&bchan->vc.lock, flags);
+       bam_reset_channel(bchan);
+       spin_unlock_irqrestore(&bchan->vc.lock, flags);
+
+       dma_free_writecombine(bdev->dev, BAM_DESC_FIFO_SIZE, bchan->fifo_virt,
+                               bchan->fifo_phys);
+       bchan->fifo_virt = NULL;
+
+       /* mask irq for pipe/channel */
+       val = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+       val &= ~BIT(bchan->id);
+       writel_relaxed(val, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+
+       /* disable irq */
+       writel_relaxed(0, bdev->regs + BAM_P_IRQ_EN(bchan->id));
+}
+
+/**
+ * bam_slave_config - set slave configuration for channel
+ * @chan: dma channel
+ * @cfg: slave configuration
+ *
+ * Sets slave configuration for channel
+ *
+ */
+static void bam_slave_config(struct bam_chan *bchan,
+               struct dma_slave_config *cfg)
+{
+       memcpy(&bchan->slave, cfg, sizeof(*cfg));
+       bchan->reconfigure = 1;
+}
+
+/**
+ * bam_prep_slave_sg - Prep slave sg transaction
+ *
+ * @chan: dma channel
+ * @sgl: scatter gather list
+ * @sg_len: length of sg
+ * @direction: DMA transfer direction
+ * @flags: DMA flags
+ * @context: transfer context (unused)
+ */
+static struct dma_async_tx_descriptor *bam_prep_slave_sg(struct dma_chan *chan,
+       struct scatterlist *sgl, unsigned int sg_len,
+       enum dma_transfer_direction direction, unsigned long flags,
+       void *context)
+{
+       struct bam_chan *bchan = to_bam_chan(chan);
+       struct bam_device *bdev = bchan->bdev;
+       struct bam_async_desc *async_desc;
+       struct scatterlist *sg;
+       u32 i;
+       struct bam_desc_hw *desc;
+       unsigned int num_alloc = 0;
+
+
+       if (!is_slave_direction(direction)) {
+               dev_err(bdev->dev, "invalid dma direction\n");
+               return NULL;
+       }
+
+       /* calculate number of required entries */
+       for_each_sg(sgl, sg, sg_len, i)
+               num_alloc += DIV_ROUND_UP(sg_dma_len(sg), BAM_MAX_DATA_SIZE);
+
+       /* allocate enough room to accomodate the number of entries */
+       async_desc = kzalloc(sizeof(*async_desc) +
+                       (num_alloc * sizeof(struct bam_desc_hw)), GFP_NOWAIT);
+
+       if (!async_desc)
+               goto err_out;
+
+       async_desc->num_desc = num_alloc;
+       async_desc->curr_desc = async_desc->desc;
+       async_desc->dir = direction;
+
+       /* fill in temporary descriptors */
+       desc = async_desc->desc;
+       for_each_sg(sgl, sg, sg_len, i) {
+               unsigned int remainder = sg_dma_len(sg);
+               unsigned int curr_offset = 0;
+
+               do {
+                       desc->addr = sg_dma_address(sg) + curr_offset;
+
+                       if (remainder > BAM_MAX_DATA_SIZE) {
+                               desc->size = BAM_MAX_DATA_SIZE;
+                               remainder -= BAM_MAX_DATA_SIZE;
+                               curr_offset += BAM_MAX_DATA_SIZE;
+                       } else {
+                               desc->size = remainder;
+                               remainder = 0;
+                       }
+
+                       async_desc->length += desc->size;
+                       desc++;
+               } while (remainder > 0);
+       }
+
+       return vchan_tx_prep(&bchan->vc, &async_desc->vd, flags);
+
+err_out:
+       kfree(async_desc);
+       return NULL;
+}
+
+/**
+ * bam_dma_terminate_all - terminate all transactions on a channel
+ * @bchan: bam dma channel
+ *
+ * Dequeues and frees all transactions
+ * No callbacks are done
+ *
+ */
+static void bam_dma_terminate_all(struct bam_chan *bchan)
+{
+       unsigned long flag;
+       LIST_HEAD(head);
+
+       /* remove all transactions, including active transaction */
+       spin_lock_irqsave(&bchan->vc.lock, flag);
+       if (bchan->curr_txd) {
+               list_add(&bchan->curr_txd->vd.node, &bchan->vc.desc_issued);
+               bchan->curr_txd = NULL;
+       }
+
+       vchan_get_all_descriptors(&bchan->vc, &head);
+       spin_unlock_irqrestore(&bchan->vc.lock, flag);
+
+       vchan_dma_desc_free_list(&bchan->vc, &head);
+}
+
+/**
+ * bam_control - DMA device control
+ * @chan: dma channel
+ * @cmd: control cmd
+ * @arg: cmd argument
+ *
+ * Perform DMA control command
+ *
+ */
+static int bam_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+       unsigned long arg)
+{
+       struct bam_chan *bchan = to_bam_chan(chan);
+       struct bam_device *bdev = bchan->bdev;
+       int ret = 0;
+       unsigned long flag;
+
+       switch (cmd) {
+       case DMA_PAUSE:
+               spin_lock_irqsave(&bchan->vc.lock, flag);
+               writel_relaxed(1, bdev->regs + BAM_P_HALT(bchan->id));
+               bchan->paused = 1;
+               spin_unlock_irqrestore(&bchan->vc.lock, flag);
+               break;
+
+       case DMA_RESUME:
+               spin_lock_irqsave(&bchan->vc.lock, flag);
+               writel_relaxed(0, bdev->regs + BAM_P_HALT(bchan->id));
+               bchan->paused = 0;
+               spin_unlock_irqrestore(&bchan->vc.lock, flag);
+               break;
+
+       case DMA_TERMINATE_ALL:
+               bam_dma_terminate_all(bchan);
+               break;
+
+       case DMA_SLAVE_CONFIG:
+               spin_lock_irqsave(&bchan->vc.lock, flag);
+               bam_slave_config(bchan, (struct dma_slave_config *)arg);
+               spin_unlock_irqrestore(&bchan->vc.lock, flag);
+               break;
+
+       default:
+               ret = -ENXIO;
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * process_channel_irqs - processes the channel interrupts
+ * @bdev: bam controller
+ *
+ * This function processes the channel interrupts
+ *
+ */
+static u32 process_channel_irqs(struct bam_device *bdev)
+{
+       u32 i, srcs, pipe_stts;
+       unsigned long flags;
+       struct bam_async_desc *async_desc;
+
+       srcs = readl_relaxed(bdev->regs + BAM_IRQ_SRCS_EE(bdev->ee));
+
+       /* return early if no pipe/channel interrupts are present */
+       if (!(srcs & P_IRQ))
+               return srcs;
+
+       for (i = 0; i < bdev->num_channels; i++) {
+               struct bam_chan *bchan = &bdev->channels[i];
+
+               if (!(srcs & BIT(i)))
+                       continue;
+
+               /* clear pipe irq */
+               pipe_stts = readl_relaxed(bdev->regs +
+                       BAM_P_IRQ_STTS(i));
+
+               writel_relaxed(pipe_stts, bdev->regs +
+                               BAM_P_IRQ_CLR(i));
+
+               spin_lock_irqsave(&bchan->vc.lock, flags);
+               async_desc = bchan->curr_txd;
+
+               if (async_desc) {
+                       async_desc->num_desc -= async_desc->xfer_len;
+                       async_desc->curr_desc += async_desc->xfer_len;
+                       bchan->curr_txd = NULL;
+
+                       /* manage FIFO */
+                       bchan->head += async_desc->xfer_len;
+                       bchan->head %= MAX_DESCRIPTORS;
+
+                       /*
+                        * if complete, process cookie.  Otherwise
+                        * push back to front of desc_issued so that
+                        * it gets restarted by the tasklet
+                        */
+                       if (!async_desc->num_desc)
+                               vchan_cookie_complete(&async_desc->vd);
+                       else
+                               list_add(&async_desc->vd.node,
+                                       &bchan->vc.desc_issued);
+               }
+
+               spin_unlock_irqrestore(&bchan->vc.lock, flags);
+       }
+
+       return srcs;
+}
+
+/**
+ * bam_dma_irq - irq handler for bam controller
+ * @irq: IRQ of interrupt
+ * @data: callback data
+ *
+ * IRQ handler for the bam controller
+ */
+static irqreturn_t bam_dma_irq(int irq, void *data)
+{
+       struct bam_device *bdev = data;
+       u32 clr_mask = 0, srcs = 0;
+
+       srcs |= process_channel_irqs(bdev);
+
+       /* kick off tasklet to start next dma transfer */
+       if (srcs & P_IRQ)
+               tasklet_schedule(&bdev->task);
+
+       if (srcs & BAM_IRQ)
+               clr_mask = readl_relaxed(bdev->regs + BAM_IRQ_STTS);
+
+       /* don't allow reorder of the various accesses to the BAM registers */
+       mb();
+
+       writel_relaxed(clr_mask, bdev->regs + BAM_IRQ_CLR);
+
+       return IRQ_HANDLED;
+}
+
+/**
+ * bam_tx_status - returns status of transaction
+ * @chan: dma channel
+ * @cookie: transaction cookie
+ * @txstate: DMA transaction state
+ *
+ * Return status of dma transaction
+ */
+static enum dma_status bam_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
+               struct dma_tx_state *txstate)
+{
+       struct bam_chan *bchan = to_bam_chan(chan);
+       struct virt_dma_desc *vd;
+       int ret;
+       size_t residue = 0;
+       unsigned int i;
+       unsigned long flags;
+
+       ret = dma_cookie_status(chan, cookie, txstate);
+       if (ret == DMA_COMPLETE)
+               return ret;
+
+       if (!txstate)
+               return bchan->paused ? DMA_PAUSED : ret;
+
+       spin_lock_irqsave(&bchan->vc.lock, flags);
+       vd = vchan_find_desc(&bchan->vc, cookie);
+       if (vd)
+               residue = container_of(vd, struct bam_async_desc, vd)->length;
+       else if (bchan->curr_txd && bchan->curr_txd->vd.tx.cookie == cookie)
+               for (i = 0; i < bchan->curr_txd->num_desc; i++)
+                       residue += bchan->curr_txd->curr_desc[i].size;
+
+       spin_unlock_irqrestore(&bchan->vc.lock, flags);
+
+       dma_set_residue(txstate, residue);
+
+       if (ret == DMA_IN_PROGRESS && bchan->paused)
+               ret = DMA_PAUSED;
+
+       return ret;
+}
+
+/**
+ * bam_apply_new_config
+ * @bchan: bam dma channel
+ * @dir: DMA direction
+ */
+static void bam_apply_new_config(struct bam_chan *bchan,
+       enum dma_transfer_direction dir)
+{
+       struct bam_device *bdev = bchan->bdev;
+       u32 maxburst;
+
+       if (dir == DMA_DEV_TO_MEM)
+               maxburst = bchan->slave.src_maxburst;
+       else
+               maxburst = bchan->slave.dst_maxburst;
+
+       writel_relaxed(maxburst, bdev->regs + BAM_DESC_CNT_TRSHLD);
+
+       bchan->reconfigure = 0;
+}
+
+/**
+ * bam_start_dma - start next transaction
+ * @bchan - bam dma channel
+ */
+static void bam_start_dma(struct bam_chan *bchan)
+{
+       struct virt_dma_desc *vd = vchan_next_desc(&bchan->vc);
+       struct bam_device *bdev = bchan->bdev;
+       struct bam_async_desc *async_desc;
+       struct bam_desc_hw *desc;
+       struct bam_desc_hw *fifo = PTR_ALIGN(bchan->fifo_virt,
+                                       sizeof(struct bam_desc_hw));
+
+       lockdep_assert_held(&bchan->vc.lock);
+
+       if (!vd)
+               return;
+
+       list_del(&vd->node);
+
+       async_desc = container_of(vd, struct bam_async_desc, vd);
+       bchan->curr_txd = async_desc;
+
+       /* on first use, initialize the channel hardware */
+       if (!bchan->initialized)
+               bam_chan_init_hw(bchan, async_desc->dir);
+
+       /* apply new slave config changes, if necessary */
+       if (bchan->reconfigure)
+               bam_apply_new_config(bchan, async_desc->dir);
+
+       desc = bchan->curr_txd->curr_desc;
+
+       if (async_desc->num_desc > MAX_DESCRIPTORS)
+               async_desc->xfer_len = MAX_DESCRIPTORS;
+       else
+               async_desc->xfer_len = async_desc->num_desc;
+
+       /* set INT on last descriptor */
+       desc[async_desc->xfer_len - 1].flags |= DESC_FLAG_INT;
+
+       if (bchan->tail + async_desc->xfer_len > MAX_DESCRIPTORS) {
+               u32 partial = MAX_DESCRIPTORS - bchan->tail;
+
+               memcpy(&fifo[bchan->tail], desc,
+                               partial * sizeof(struct bam_desc_hw));
+               memcpy(fifo, &desc[partial], (async_desc->xfer_len - partial) *
+                               sizeof(struct bam_desc_hw));
+       } else {
+               memcpy(&fifo[bchan->tail], desc,
+                       async_desc->xfer_len * sizeof(struct bam_desc_hw));
+       }
+
+       bchan->tail += async_desc->xfer_len;
+       bchan->tail %= MAX_DESCRIPTORS;
+
+       /* ensure descriptor writes and dma start not reordered */
+       wmb();
+       writel_relaxed(bchan->tail * sizeof(struct bam_desc_hw),
+                       bdev->regs + BAM_P_EVNT_REG(bchan->id));
+}
+
+/**
+ * dma_tasklet - DMA IRQ tasklet
+ * @data: tasklet argument (bam controller structure)
+ *
+ * Sets up next DMA operation and then processes all completed transactions
+ */
+static void dma_tasklet(unsigned long data)
+{
+       struct bam_device *bdev = (struct bam_device *)data;
+       struct bam_chan *bchan;
+       unsigned long flags;
+       unsigned int i;
+
+       /* go through the channels and kick off transactions */
+       for (i = 0; i < bdev->num_channels; i++) {
+               bchan = &bdev->channels[i];
+               spin_lock_irqsave(&bchan->vc.lock, flags);
+
+               if (!list_empty(&bchan->vc.desc_issued) && !bchan->curr_txd)
+                       bam_start_dma(bchan);
+               spin_unlock_irqrestore(&bchan->vc.lock, flags);
+       }
+}
+
+/**
+ * bam_issue_pending - starts pending transactions
+ * @chan: dma channel
+ *
+ * Calls tasklet directly which in turn starts any pending transactions
+ */
+static void bam_issue_pending(struct dma_chan *chan)
+{
+       struct bam_chan *bchan = to_bam_chan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&bchan->vc.lock, flags);
+
+       /* if work pending and idle, start a transaction */
+       if (vchan_issue_pending(&bchan->vc) && !bchan->curr_txd)
+               bam_start_dma(bchan);
+
+       spin_unlock_irqrestore(&bchan->vc.lock, flags);
+}
+
+/**
+ * bam_dma_free_desc - free descriptor memory
+ * @vd: virtual descriptor
+ *
+ */
+static void bam_dma_free_desc(struct virt_dma_desc *vd)
+{
+       struct bam_async_desc *async_desc = container_of(vd,
+                       struct bam_async_desc, vd);
+
+       kfree(async_desc);
+}
+
+static struct dma_chan *bam_dma_xlate(struct of_phandle_args *dma_spec,
+               struct of_dma *of)
+{
+       struct bam_device *bdev = container_of(of->of_dma_data,
+                                       struct bam_device, common);
+       unsigned int request;
+
+       if (dma_spec->args_count != 1)
+               return NULL;
+
+       request = dma_spec->args[0];
+       if (request >= bdev->num_channels)
+               return NULL;
+
+       return dma_get_slave_channel(&(bdev->channels[request].vc.chan));
+}
+
+/**
+ * bam_init
+ * @bdev: bam device
+ *
+ * Initialization helper for global bam registers
+ */
+static int bam_init(struct bam_device *bdev)
+{
+       u32 val;
+
+       /* read revision and configuration information */
+       val = readl_relaxed(bdev->regs + BAM_REVISION) >> NUM_EES_SHIFT;
+       val &= NUM_EES_MASK;
+
+       /* check that configured EE is within range */
+       if (bdev->ee >= val)
+               return -EINVAL;
+
+       val = readl_relaxed(bdev->regs + BAM_NUM_PIPES);
+       bdev->num_channels = val & BAM_NUM_PIPES_MASK;
+
+       /* s/w reset bam */
+       /* after reset all pipes are disabled and idle */
+       val = readl_relaxed(bdev->regs + BAM_CTRL);
+       val |= BAM_SW_RST;
+       writel_relaxed(val, bdev->regs + BAM_CTRL);
+       val &= ~BAM_SW_RST;
+       writel_relaxed(val, bdev->regs + BAM_CTRL);
+
+       /* make sure previous stores are visible before enabling BAM */
+       wmb();
+
+       /* enable bam */
+       val |= BAM_EN;
+       writel_relaxed(val, bdev->regs + BAM_CTRL);
+
+       /* set descriptor threshhold, start with 4 bytes */
+       writel_relaxed(DEFAULT_CNT_THRSHLD, bdev->regs + BAM_DESC_CNT_TRSHLD);
+
+       /* Enable default set of h/w workarounds, ie all except BAM_FULL_PIPE */
+       writel_relaxed(BAM_CNFG_BITS_DEFAULT, bdev->regs + BAM_CNFG_BITS);
+
+       /* enable irqs for errors */
+       writel_relaxed(BAM_ERROR_EN | BAM_HRESP_ERR_EN,
+                               bdev->regs + BAM_IRQ_EN);
+
+       /* unmask global bam interrupt */
+       writel_relaxed(BAM_IRQ_MSK, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+
+       return 0;
+}
+
+static void bam_channel_init(struct bam_device *bdev, struct bam_chan *bchan,
+       u32 index)
+{
+       bchan->id = index;
+       bchan->bdev = bdev;
+
+       vchan_init(&bchan->vc, &bdev->common);
+       bchan->vc.desc_free = bam_dma_free_desc;
+}
+
+static int bam_dma_probe(struct platform_device *pdev)
+{
+       struct bam_device *bdev;
+       struct resource *iores;
+       int ret, i;
+
+       bdev = devm_kzalloc(&pdev->dev, sizeof(*bdev), GFP_KERNEL);
+       if (!bdev)
+               return -ENOMEM;
+
+       bdev->dev = &pdev->dev;
+
+       iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       bdev->regs = devm_ioremap_resource(&pdev->dev, iores);
+       if (IS_ERR(bdev->regs))
+               return PTR_ERR(bdev->regs);
+
+       bdev->irq = platform_get_irq(pdev, 0);
+       if (bdev->irq < 0)
+               return bdev->irq;
+
+       ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &bdev->ee);
+       if (ret) {
+               dev_err(bdev->dev, "Execution environment unspecified\n");
+               return ret;
+       }
+
+       bdev->bamclk = devm_clk_get(bdev->dev, "bam_clk");
+       if (IS_ERR(bdev->bamclk))
+               return PTR_ERR(bdev->bamclk);
+
+       ret = clk_prepare_enable(bdev->bamclk);
+       if (ret) {
+               dev_err(bdev->dev, "failed to prepare/enable clock\n");
+               return ret;
+       }
+
+       ret = bam_init(bdev);
+       if (ret)
+               goto err_disable_clk;
+
+       tasklet_init(&bdev->task, dma_tasklet, (unsigned long)bdev);
+
+       bdev->channels = devm_kcalloc(bdev->dev, bdev->num_channels,
+                               sizeof(*bdev->channels), GFP_KERNEL);
+
+       if (!bdev->channels) {
+               ret = -ENOMEM;
+               goto err_disable_clk;
+       }
+
+       /* allocate and initialize channels */
+       INIT_LIST_HEAD(&bdev->common.channels);
+
+       for (i = 0; i < bdev->num_channels; i++)
+               bam_channel_init(bdev, &bdev->channels[i], i);
+
+       ret = devm_request_irq(bdev->dev, bdev->irq, bam_dma_irq,
+                       IRQF_TRIGGER_HIGH, "bam_dma", bdev);
+       if (ret)
+               goto err_disable_clk;
+
+       /* set max dma segment size */
+       bdev->common.dev = bdev->dev;
+       bdev->common.dev->dma_parms = &bdev->dma_parms;
+       ret = dma_set_max_seg_size(bdev->common.dev, BAM_MAX_DATA_SIZE);
+       if (ret) {
+               dev_err(bdev->dev, "cannot set maximum segment size\n");
+               goto err_disable_clk;
+       }
+
+       platform_set_drvdata(pdev, bdev);
+
+       /* set capabilities */
+       dma_cap_zero(bdev->common.cap_mask);
+       dma_cap_set(DMA_SLAVE, bdev->common.cap_mask);
+
+       /* initialize dmaengine apis */
+       bdev->common.device_alloc_chan_resources = bam_alloc_chan;
+       bdev->common.device_free_chan_resources = bam_free_chan;
+       bdev->common.device_prep_slave_sg = bam_prep_slave_sg;
+       bdev->common.device_control = bam_control;
+       bdev->common.device_issue_pending = bam_issue_pending;
+       bdev->common.device_tx_status = bam_tx_status;
+       bdev->common.dev = bdev->dev;
+
+       ret = dma_async_device_register(&bdev->common);
+       if (ret) {
+               dev_err(bdev->dev, "failed to register dma async device\n");
+               goto err_disable_clk;
+       }
+
+       ret = of_dma_controller_register(pdev->dev.of_node, bam_dma_xlate,
+                                       &bdev->common);
+       if (ret)
+               goto err_unregister_dma;
+
+       return 0;
+
+err_unregister_dma:
+       dma_async_device_unregister(&bdev->common);
+err_disable_clk:
+       clk_disable_unprepare(bdev->bamclk);
+       return ret;
+}
+
+static int bam_dma_remove(struct platform_device *pdev)
+{
+       struct bam_device *bdev = platform_get_drvdata(pdev);
+       u32 i;
+
+       of_dma_controller_free(pdev->dev.of_node);
+       dma_async_device_unregister(&bdev->common);
+
+       /* mask all interrupts for this execution environment */
+       writel_relaxed(0, bdev->regs + BAM_IRQ_SRCS_MSK_EE(bdev->ee));
+
+       devm_free_irq(bdev->dev, bdev->irq, bdev);
+
+       for (i = 0; i < bdev->num_channels; i++) {
+               bam_dma_terminate_all(&bdev->channels[i]);
+               tasklet_kill(&bdev->channels[i].vc.task);
+
+               dma_free_writecombine(bdev->dev, BAM_DESC_FIFO_SIZE,
+                       bdev->channels[i].fifo_virt,
+                       bdev->channels[i].fifo_phys);
+       }
+
+       tasklet_kill(&bdev->task);
+
+       clk_disable_unprepare(bdev->bamclk);
+
+       return 0;
+}
+
+static const struct of_device_id bam_of_match[] = {
+       { .compatible = "qcom,bam-v1.4.0", },
+       {}
+};
+MODULE_DEVICE_TABLE(of, bam_of_match);
+
+static struct platform_driver bam_dma_driver = {
+       .probe = bam_dma_probe,
+       .remove = bam_dma_remove,
+       .driver = {
+               .name = "bam-dma-engine",
+               .owner = THIS_MODULE,
+               .of_match_table = bam_of_match,
+       },
+};
+
+module_platform_driver(bam_dma_driver);
+
+MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
+MODULE_DESCRIPTION("QCOM BAM DMA engine driver");
+MODULE_LICENSE("GPL v2");
index 4eddedb..b209a0f 100644 (file)
@@ -192,7 +192,7 @@ struct s3c24xx_dma_phy {
        unsigned int                    id;
        bool                            valid;
        void __iomem                    *base;
-       unsigned int                    irq;
+       int                             irq;
        struct clk                      *clk;
        spinlock_t                      lock;
        struct s3c24xx_dma_chan         *serving;
index dadd9e0..b4c8138 100644 (file)
@@ -29,6 +29,12 @@ config RCAR_HPB_DMAE
        help
          Enable support for the Renesas R-Car series DMA controllers.
 
+config RCAR_AUDMAC_PP
+       tristate "Renesas R-Car Audio DMAC Peripheral Peripheral support"
+       depends on SH_DMAE_BASE
+       help
+         Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral controllers.
+
 config SHDMA_R8A73A4
        def_bool y
        depends on ARCH_R8A73A4 && SH_DMAE != n
index e856af2..1ce88b2 100644 (file)
@@ -7,3 +7,4 @@ endif
 shdma-objs := $(shdma-y)
 obj-$(CONFIG_SUDMAC) += sudmac.o
 obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
+obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
diff --git a/drivers/dma/sh/rcar-audmapp.c b/drivers/dma/sh/rcar-audmapp.c
new file mode 100644 (file)
index 0000000..2de7728
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+ * This is for Renesas R-Car Audio-DMAC-peri-peri.
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ * Copyright (C) 2014 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * based on the drivers/dma/sh/shdma.c
+ *
+ * Copyright (C) 2011-2012 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ * Copyright (C) 2009 Nobuhiro Iwamatsu <iwamatsu.nobuhiro@renesas.com>
+ * Copyright (C) 2009 Renesas Solutions, Inc. All rights reserved.
+ * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * This 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/delay.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/platform_data/dma-rcar-audmapp.h>
+#include <linux/platform_device.h>
+#include <linux/shdma-base.h>
+
+/*
+ * DMA register
+ */
+#define PDMASAR                0x00
+#define PDMADAR                0x04
+#define PDMACHCR       0x0c
+
+/* PDMACHCR */
+#define PDMACHCR_DE            (1 << 0)
+
+#define AUDMAPP_MAX_CHANNELS   29
+
+/* Default MEMCPY transfer size = 2^2 = 4 bytes */
+#define LOG2_DEFAULT_XFER_SIZE 2
+#define AUDMAPP_SLAVE_NUMBER   256
+#define AUDMAPP_LEN_MAX                (16 * 1024 * 1024)
+
+struct audmapp_chan {
+       struct shdma_chan shdma_chan;
+       struct audmapp_slave_config *config;
+       void __iomem *base;
+};
+
+struct audmapp_device {
+       struct shdma_dev shdma_dev;
+       struct audmapp_pdata *pdata;
+       struct device *dev;
+       void __iomem *chan_reg;
+};
+
+#define to_chan(chan) container_of(chan, struct audmapp_chan, shdma_chan)
+#define to_dev(chan) container_of(chan->shdma_chan.dma_chan.device,    \
+                                 struct audmapp_device, shdma_dev.dma_dev)
+
+static void audmapp_write(struct audmapp_chan *auchan, u32 data, u32 reg)
+{
+       struct audmapp_device *audev = to_dev(auchan);
+       struct device *dev = audev->dev;
+
+       dev_dbg(dev, "w %p : %08x\n", auchan->base + reg, data);
+
+       iowrite32(data, auchan->base + reg);
+}
+
+static u32 audmapp_read(struct audmapp_chan *auchan, u32 reg)
+{
+       return ioread32(auchan->base + reg);
+}
+
+static void audmapp_halt(struct shdma_chan *schan)
+{
+       struct audmapp_chan *auchan = to_chan(schan);
+       int i;
+
+       audmapp_write(auchan, 0, PDMACHCR);
+
+       for (i = 0; i < 1024; i++) {
+               if (0 == audmapp_read(auchan, PDMACHCR))
+                       return;
+               udelay(1);
+       }
+}
+
+static void audmapp_start_xfer(struct shdma_chan *schan,
+                              struct shdma_desc *sdecs)
+{
+       struct audmapp_chan *auchan = to_chan(schan);
+       struct audmapp_device *audev = to_dev(auchan);
+       struct audmapp_slave_config *cfg = auchan->config;
+       struct device *dev = audev->dev;
+       u32 chcr = cfg->chcr | PDMACHCR_DE;
+
+       dev_dbg(dev, "src/dst/chcr = %pad/%pad/%x\n",
+               &cfg->src, &cfg->dst, cfg->chcr);
+
+       audmapp_write(auchan, cfg->src, PDMASAR);
+       audmapp_write(auchan, cfg->dst, PDMADAR);
+       audmapp_write(auchan, chcr,     PDMACHCR);
+}
+
+static struct audmapp_slave_config *
+audmapp_find_slave(struct audmapp_chan *auchan, int slave_id)
+{
+       struct audmapp_device *audev = to_dev(auchan);
+       struct audmapp_pdata *pdata = audev->pdata;
+       struct audmapp_slave_config *cfg;
+       int i;
+
+       if (slave_id >= AUDMAPP_SLAVE_NUMBER)
+               return NULL;
+
+       for (i = 0, cfg = pdata->slave; i < pdata->slave_num; i++, cfg++)
+               if (cfg->slave_id == slave_id)
+                       return cfg;
+
+       return NULL;
+}
+
+static int audmapp_set_slave(struct shdma_chan *schan, int slave_id,
+                            dma_addr_t slave_addr, bool try)
+{
+       struct audmapp_chan *auchan = to_chan(schan);
+       struct audmapp_slave_config *cfg =
+               audmapp_find_slave(auchan, slave_id);
+
+       if (!cfg)
+               return -ENODEV;
+       if (try)
+               return 0;
+
+       auchan->config  = cfg;
+
+       return 0;
+}
+
+static int audmapp_desc_setup(struct shdma_chan *schan,
+                             struct shdma_desc *sdecs,
+                             dma_addr_t src, dma_addr_t dst, size_t *len)
+{
+       struct audmapp_chan *auchan = to_chan(schan);
+       struct audmapp_slave_config *cfg = auchan->config;
+
+       if (!cfg)
+               return -ENODEV;
+
+       if (*len > (size_t)AUDMAPP_LEN_MAX)
+               *len = (size_t)AUDMAPP_LEN_MAX;
+
+       return 0;
+}
+
+static void audmapp_setup_xfer(struct shdma_chan *schan,
+                              int slave_id)
+{
+}
+
+static dma_addr_t audmapp_slave_addr(struct shdma_chan *schan)
+{
+       return 0; /* always fixed address */
+}
+
+static bool audmapp_channel_busy(struct shdma_chan *schan)
+{
+       struct audmapp_chan *auchan = to_chan(schan);
+       u32 chcr = audmapp_read(auchan, PDMACHCR);
+
+       return chcr & ~PDMACHCR_DE;
+}
+
+static bool audmapp_desc_completed(struct shdma_chan *schan,
+                                  struct shdma_desc *sdesc)
+{
+       return true;
+}
+
+static struct shdma_desc *audmapp_embedded_desc(void *buf, int i)
+{
+       return &((struct shdma_desc *)buf)[i];
+}
+
+static const struct shdma_ops audmapp_shdma_ops = {
+       .halt_channel   = audmapp_halt,
+       .desc_setup     = audmapp_desc_setup,
+       .set_slave      = audmapp_set_slave,
+       .start_xfer     = audmapp_start_xfer,
+       .embedded_desc  = audmapp_embedded_desc,
+       .setup_xfer     = audmapp_setup_xfer,
+       .slave_addr     = audmapp_slave_addr,
+       .channel_busy   = audmapp_channel_busy,
+       .desc_completed = audmapp_desc_completed,
+};
+
+static int audmapp_chan_probe(struct platform_device *pdev,
+                             struct audmapp_device *audev, int id)
+{
+       struct shdma_dev *sdev = &audev->shdma_dev;
+       struct audmapp_chan *auchan;
+       struct shdma_chan *schan;
+       struct device *dev = audev->dev;
+
+       auchan = devm_kzalloc(dev, sizeof(*auchan), GFP_KERNEL);
+       if (!auchan)
+               return -ENOMEM;
+
+       schan = &auchan->shdma_chan;
+       schan->max_xfer_len = AUDMAPP_LEN_MAX;
+
+       shdma_chan_probe(sdev, schan, id);
+
+       auchan->base = audev->chan_reg + 0x20 + (0x10 * id);
+       dev_dbg(dev, "%02d : %p / %p", id, auchan->base, audev->chan_reg);
+
+       return 0;
+}
+
+static void audmapp_chan_remove(struct audmapp_device *audev)
+{
+       struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+       struct shdma_chan *schan;
+       int i;
+
+       shdma_for_each_chan(schan, &audev->shdma_dev, i) {
+               BUG_ON(!schan);
+               shdma_chan_remove(schan);
+       }
+       dma_dev->chancnt = 0;
+}
+
+static int audmapp_probe(struct platform_device *pdev)
+{
+       struct audmapp_pdata *pdata = pdev->dev.platform_data;
+       struct audmapp_device *audev;
+       struct shdma_dev *sdev;
+       struct dma_device *dma_dev;
+       struct resource *res;
+       int err, i;
+
+       if (!pdata)
+               return -ENODEV;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       audev = devm_kzalloc(&pdev->dev, sizeof(*audev), GFP_KERNEL);
+       if (!audev)
+               return -ENOMEM;
+
+       audev->dev      = &pdev->dev;
+       audev->pdata    = pdata;
+       audev->chan_reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(audev->chan_reg))
+               return PTR_ERR(audev->chan_reg);
+
+       sdev            = &audev->shdma_dev;
+       sdev->ops       = &audmapp_shdma_ops;
+       sdev->desc_size = sizeof(struct shdma_desc);
+
+       dma_dev                 = &sdev->dma_dev;
+       dma_dev->copy_align     = LOG2_DEFAULT_XFER_SIZE;
+       dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
+
+       err = shdma_init(&pdev->dev, sdev, AUDMAPP_MAX_CHANNELS);
+       if (err < 0)
+               return err;
+
+       platform_set_drvdata(pdev, audev);
+
+       /* Create DMA Channel */
+       for (i = 0; i < AUDMAPP_MAX_CHANNELS; i++) {
+               err = audmapp_chan_probe(pdev, audev, i);
+               if (err)
+                       goto chan_probe_err;
+       }
+
+       err = dma_async_device_register(dma_dev);
+       if (err < 0)
+               goto chan_probe_err;
+
+       return err;
+
+chan_probe_err:
+       audmapp_chan_remove(audev);
+       shdma_cleanup(sdev);
+
+       return err;
+}
+
+static int audmapp_remove(struct platform_device *pdev)
+{
+       struct audmapp_device *audev = platform_get_drvdata(pdev);
+       struct dma_device *dma_dev = &audev->shdma_dev.dma_dev;
+
+       dma_async_device_unregister(dma_dev);
+
+       audmapp_chan_remove(audev);
+       shdma_cleanup(&audev->shdma_dev);
+
+       return 0;
+}
+
+static struct platform_driver audmapp_driver = {
+       .probe          = audmapp_probe,
+       .remove         = audmapp_remove,
+       .driver         = {
+               .owner  = THIS_MODULE,
+               .name   = "rcar-audmapp-engine",
+       },
+};
+module_platform_driver(audmapp_driver);
+
+MODULE_AUTHOR("Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>");
+MODULE_DESCRIPTION("Renesas R-Car Audio DMAC peri-peri driver");
+MODULE_LICENSE("GPL");
index 2e7b394..5239677 100644 (file)
@@ -227,7 +227,7 @@ bool shdma_chan_filter(struct dma_chan *chan, void *arg)
        struct shdma_chan *schan = to_shdma_chan(chan);
        struct shdma_dev *sdev = to_shdma_dev(schan->dma_chan.device);
        const struct shdma_ops *ops = sdev->ops;
-       int match = (int)arg;
+       int match = (long)arg;
        int ret;
 
        if (match < 0)
@@ -491,8 +491,8 @@ static struct shdma_desc *shdma_add_desc(struct shdma_chan *schan,
        }
 
        dev_dbg(schan->dev,
-               "chaining (%u/%u)@%x -> %x with %p, cookie %d\n",
-               copy_size, *len, *src, *dst, &new->async_tx,
+               "chaining (%zu/%zu)@%pad -> %pad with %p, cookie %d\n",
+               copy_size, *len, src, dst, &new->async_tx,
                new->async_tx.cookie);
 
        new->mark = DESC_PREPARED;
@@ -555,8 +555,8 @@ static struct dma_async_tx_descriptor *shdma_prep_sg(struct shdma_chan *schan,
                        goto err_get_desc;
 
                do {
-                       dev_dbg(schan->dev, "Add SG #%d@%p[%d], dma %llx\n",
-                               i, sg, len, (unsigned long long)sg_addr);
+                       dev_dbg(schan->dev, "Add SG #%d@%p[%zu], dma %pad\n",
+                               i, sg, len, &sg_addr);
 
                        if (direction == DMA_DEV_TO_MEM)
                                new = shdma_add_desc(schan, flags,
index 06473a0..b4ff9d3 100644 (file)
@@ -33,7 +33,8 @@ static struct dma_chan *shdma_of_xlate(struct of_phandle_args *dma_spec,
        /* Only slave DMA channels can be allocated via DT */
        dma_cap_set(DMA_SLAVE, mask);
 
-       chan = dma_request_channel(mask, shdma_chan_filter, (void *)id);
+       chan = dma_request_channel(mask, shdma_chan_filter,
+                                  (void *)(uintptr_t)id);
        if (chan)
                to_shdma_chan(chan)->hw_req = id;
 
index 0d765c0..dda7e75 100644 (file)
@@ -443,6 +443,7 @@ static bool sh_dmae_reset(struct sh_dmae_device *shdev)
        return ret;
 }
 
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARM)
 static irqreturn_t sh_dmae_err(int irq, void *data)
 {
        struct sh_dmae_device *shdev = data;
@@ -453,6 +454,7 @@ static irqreturn_t sh_dmae_err(int irq, void *data)
        sh_dmae_reset(shdev);
        return IRQ_HANDLED;
 }
+#endif
 
 static bool sh_dmae_desc_completed(struct shdma_chan *schan,
                                   struct shdma_desc *sdesc)
@@ -637,7 +639,7 @@ static int sh_dmae_resume(struct device *dev)
 #define sh_dmae_resume NULL
 #endif
 
-const struct dev_pm_ops sh_dmae_pm = {
+static const struct dev_pm_ops sh_dmae_pm = {
        .suspend                = sh_dmae_suspend,
        .resume                 = sh_dmae_resume,
        .runtime_suspend        = sh_dmae_runtime_suspend,
@@ -685,9 +687,12 @@ MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
 static int sh_dmae_probe(struct platform_device *pdev)
 {
        const struct sh_dmae_pdata *pdata;
-       unsigned long irqflags = 0,
-               chan_flag[SH_DMAE_MAX_CHANNELS] = {};
-       int errirq, chan_irq[SH_DMAE_MAX_CHANNELS];
+       unsigned long chan_flag[SH_DMAE_MAX_CHANNELS] = {};
+       int chan_irq[SH_DMAE_MAX_CHANNELS];
+#if defined(CONFIG_CPU_SH4) || defined(CONFIG_ARM)
+       unsigned long irqflags = 0;
+       int errirq;
+#endif
        int err, i, irq_cnt = 0, irqres = 0, irq_cap = 0;
        struct sh_dmae_device *shdev;
        struct dma_device *dma_dev;
index c7e9cdf..4e7df43 100644 (file)
@@ -178,8 +178,8 @@ static int sudmac_desc_setup(struct shdma_chan *schan,
        struct sudmac_chan *sc = to_chan(schan);
        struct sudmac_desc *sd = to_desc(sdesc);
 
-       dev_dbg(sc->shdma_chan.dev, "%s: src=%x, dst=%x, len=%d\n",
-               __func__, src, dst, *len);
+       dev_dbg(sc->shdma_chan.dev, "%s: src=%pad, dst=%pad, len=%zu\n",
+               __func__, &src, &dst, *len);
 
        if (*len > schan->max_xfer_len)
                *len = schan->max_xfer_len;
index d4d3a31..a1bd829 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
 #include <linux/clk.h>
+#include <linux/of_dma.h>
 #include <linux/sirfsoc_dma.h>
 
 #include "dmaengine.h"
@@ -659,6 +660,18 @@ static int sirfsoc_dma_device_slave_caps(struct dma_chan *dchan,
        return 0;
 }
 
+static struct dma_chan *of_dma_sirfsoc_xlate(struct of_phandle_args *dma_spec,
+       struct of_dma *ofdma)
+{
+       struct sirfsoc_dma *sdma = ofdma->of_dma_data;
+       unsigned int request = dma_spec->args[0];
+
+       if (request > SIRFSOC_DMA_CHANNELS)
+               return NULL;
+
+       return dma_get_slave_channel(&sdma->channels[request].chan);
+}
+
 static int sirfsoc_dma_probe(struct platform_device *op)
 {
        struct device_node *dn = op->dev.of_node;
@@ -764,11 +777,20 @@ static int sirfsoc_dma_probe(struct platform_device *op)
        if (ret)
                goto free_irq;
 
+       /* Device-tree DMA controller registration */
+       ret = of_dma_controller_register(dn, of_dma_sirfsoc_xlate, sdma);
+       if (ret) {
+               dev_err(dev, "failed to register DMA controller\n");
+               goto unreg_dma_dev;
+       }
+
        pm_runtime_enable(&op->dev);
        dev_info(dev, "initialized SIRFSOC DMAC driver\n");
 
        return 0;
 
+unreg_dma_dev:
+       dma_async_device_unregister(dma);
 free_irq:
        free_irq(sdma->irq, sdma);
 irq_dispose:
@@ -781,6 +803,7 @@ static int sirfsoc_dma_remove(struct platform_device *op)
        struct device *dev = &op->dev;
        struct sirfsoc_dma *sdma = dev_get_drvdata(dev);
 
+       of_dma_controller_free(op->dev.of_node);
        dma_async_device_unregister(&sdma->dma);
        free_irq(sdma->irq, sdma);
        irq_dispose_mapping(sdma->irq);
index bfef20f..e73c675 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Intel ICH6-10, Series 5 and 6 GPIO driver
+ * Intel ICH6-10, Series 5 and 6, Atom C2000 (Avoton/Rangeley) GPIO driver
  *
  * Copyright (C) 2010 Extreme Engineering Solutions.
  *
@@ -55,6 +55,16 @@ static const u8 ichx_reglen[3] = {
        0x30, 0x10, 0x10,
 };
 
+static const u8 avoton_regs[4][3] = {
+       {0x00, 0x80, 0x00},
+       {0x04, 0x84, 0x00},
+       {0x08, 0x88, 0x00},
+};
+
+static const u8 avoton_reglen[3] = {
+       0x10, 0x10, 0x00,
+};
+
 #define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start)
 #define ICHX_READ(reg, base_res)       inl((reg) + (base_res)->start)
 
@@ -353,6 +363,17 @@ static struct ichx_desc intel5_desc = {
        .reglen = ichx_reglen,
 };
 
+/* Avoton */
+static struct ichx_desc avoton_desc = {
+       /* Avoton has only 59 GPIOs, but we assume the first set of register
+        * (Core) has 32 instead of 31 to keep gpio-ich compliance
+        */
+       .ngpio = 60,
+       .regs = avoton_regs,
+       .reglen = avoton_reglen,
+       .use_outlvl_cache = true,
+};
+
 static int ichx_gpio_request_regions(struct resource *res_base,
                                                const char *name, u8 use_gpio)
 {
@@ -427,6 +448,9 @@ static int ichx_gpio_probe(struct platform_device *pdev)
        case ICH_V10CONS_GPIO:
                ichx_priv.desc = &ich10_cons_desc;
                break;
+       case AVOTON_GPIO:
+               ichx_priv.desc = &avoton_desc;
+               break;
        default:
                return -ENODEV;
        }
index 8e7fa4d..d1cc2f6 100644 (file)
@@ -199,3 +199,5 @@ source "drivers/gpu/drm/msm/Kconfig"
 source "drivers/gpu/drm/tegra/Kconfig"
 
 source "drivers/gpu/drm/panel/Kconfig"
+
+source "drivers/gpu/drm/bridge/Kconfig"
index 292a79d..9d25dbb 100644 (file)
@@ -13,7 +13,8 @@ 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_vma_manager.o drm_flip_work.o
+               drm_rect.o drm_vma_manager.o drm_flip_work.o \
+               drm_plane_helper.o
 
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
@@ -63,3 +64,4 @@ obj-$(CONFIG_DRM_MSM) += msm/
 obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-y                  += i2c/
 obj-y                  += panel/
+obj-y                  += bridge/
index d8e3982..81c34f9 100644 (file)
@@ -478,11 +478,12 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
        unsigned i;
        bool interlaced;
 
-       drm_framebuffer_reference(crtc->fb);
+       drm_framebuffer_reference(crtc->primary->fb);
 
        interlaced = !!(adj->flags & DRM_MODE_FLAG_INTERLACE);
 
-       i = armada_drm_crtc_calc_fb(dcrtc->crtc.fb, x, y, regs, interlaced);
+       i = armada_drm_crtc_calc_fb(dcrtc->crtc.primary->fb,
+                                   x, y, regs, interlaced);
 
        rm = adj->crtc_hsync_start - adj->crtc_hdisplay;
        lm = adj->crtc_htotal - adj->crtc_hsync_end;
@@ -567,10 +568,10 @@ static int armada_drm_crtc_mode_set(struct drm_crtc *crtc,
        }
 
        val = CFG_GRA_ENA | CFG_GRA_HSMOOTH;
-       val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt);
-       val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.fb)->mod);
+       val |= CFG_GRA_FMT(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt);
+       val |= CFG_GRA_MOD(drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->mod);
 
-       if (drm_fb_to_armada_fb(dcrtc->crtc.fb)->fmt > CFG_420)
+       if (drm_fb_to_armada_fb(dcrtc->crtc.primary->fb)->fmt > CFG_420)
                val |= CFG_PALETTE_ENA;
 
        if (interlaced)
@@ -608,7 +609,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        struct armada_regs regs[4];
        unsigned i;
 
-       i = armada_drm_crtc_calc_fb(crtc->fb, crtc->x, crtc->y, regs,
+       i = armada_drm_crtc_calc_fb(crtc->primary->fb, crtc->x, crtc->y, regs,
                                    dcrtc->interlaced);
        armada_reg_queue_end(regs, i);
 
@@ -616,7 +617,7 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        wait_event(dcrtc->frame_wait, !dcrtc->frame_work);
 
        /* Take a reference to the new fb as we're using it */
-       drm_framebuffer_reference(crtc->fb);
+       drm_framebuffer_reference(crtc->primary->fb);
 
        /* Update the base in the CRTC */
        armada_drm_crtc_update_regs(dcrtc, regs);
@@ -637,7 +638,7 @@ static void armada_drm_crtc_disable(struct drm_crtc *crtc)
        struct armada_crtc *dcrtc = drm_to_armada_crtc(crtc);
 
        armada_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-       armada_drm_crtc_finish_fb(dcrtc, crtc->fb, true);
+       armada_drm_crtc_finish_fb(dcrtc, crtc->primary->fb, true);
 
        /* Power down most RAMs and FIFOs */
        writel_relaxed(CFG_PDWN256x32 | CFG_PDWN256x24 | CFG_PDWN256x8 |
@@ -678,6 +679,7 @@ static void armada_load_cursor_argb(void __iomem *base, uint32_t *pix,
                                       base + LCD_SPU_SRAM_WRDAT);
                        writel_relaxed(addr | SRAM_WRITE,
                                       base + LCD_SPU_SRAM_CTRL);
+                       readl_relaxed(base + LCD_SPU_HWC_OVSA_HPXL_VLN);
                        addr += 1;
                        if ((addr & 0x00ff) == 0)
                                addr += 0xf00;
@@ -904,7 +906,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
        int ret;
 
        /* We don't support changing the pixel format */
-       if (fb->pixel_format != crtc->fb->pixel_format)
+       if (fb->pixel_format != crtc->primary->fb->pixel_format)
                return -EINVAL;
 
        work = kmalloc(sizeof(*work), GFP_KERNEL);
@@ -912,7 +914,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
                return -ENOMEM;
 
        work->event = event;
-       work->old_fb = dcrtc->crtc.fb;
+       work->old_fb = dcrtc->crtc.primary->fb;
 
        i = armada_drm_crtc_calc_fb(fb, crtc->x, crtc->y, work->regs,
                                    dcrtc->interlaced);
@@ -941,7 +943,7 @@ static int armada_drm_crtc_page_flip(struct drm_crtc *crtc,
         * will _not_ drop that reference on successful return from this
         * function.  Simply mark this new framebuffer as the current one.
         */
-       dcrtc->crtc.fb = fb;
+       dcrtc->crtc.primary->fb = fb;
 
        /*
         * Finally, if the display is blanked, we won't receive an
index cca063b..a4afdc8 100644 (file)
@@ -81,7 +81,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
        u32 refresh_rate_index = 0, mode_id, color_index, refresh_rate;
        u32 hborder, vborder;
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
                vbios_mode->std_table = &vbios_stdtable[VGAModeIndex];
                color_index = VGAModeIndex - 1;
@@ -176,7 +176,7 @@ static bool ast_get_vbios_mode_info(struct drm_crtc *crtc, struct drm_display_mo
                ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x8e, mode_id & 0xff);
 
                ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x91, 0xa8);
-               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->fb->bits_per_pixel);
+               ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x92, crtc->primary->fb->bits_per_pixel);
                ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x93, adjusted_mode->clock / 1000);
                ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x94, adjusted_mode->crtc_hdisplay);
                ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x95, adjusted_mode->crtc_hdisplay >> 8);
@@ -340,7 +340,7 @@ static void ast_set_offset_reg(struct drm_crtc *crtc)
 
        u16 offset;
 
-       offset = crtc->fb->pitches[0] >> 3;
+       offset = crtc->primary->fb->pitches[0] >> 3;
        ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0x13, (offset & 0xff));
        ast_set_index_reg(ast, AST_IO_CRTC_PORT, 0xb0, (offset >> 8) & 0x3f);
 }
@@ -365,7 +365,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode
        struct ast_private *ast = crtc->dev->dev_private;
        u8 jregA0 = 0, jregA3 = 0, jregA8 = 0;
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
                jregA0 = 0x70;
                jregA3 = 0x01;
@@ -418,7 +418,7 @@ static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mo
 static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
                     struct ast_vbios_mode_info *vbios_mode)
 {
-       switch (crtc->fb->bits_per_pixel) {
+       switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
                break;
        default:
@@ -490,7 +490,7 @@ static int ast_crtc_do_set_base(struct drm_crtc *crtc,
                ast_bo_unreserve(bo);
        }
 
-       ast_fb = to_ast_framebuffer(crtc->fb);
+       ast_fb = to_ast_framebuffer(crtc->primary->fb);
        obj = ast_fb->obj;
        bo = gem_to_ast_bo(obj);
 
index 4ea9b17..b824622 100644 (file)
@@ -259,7 +259,9 @@ int ast_mm_init(struct ast_private *ast)
 
        ret = ttm_bo_device_init(&ast->ttm.bdev,
                                 ast->ttm.bo_global_ref.ref.object,
-                                &ast_bo_driver, DRM_FILE_PAGE_OFFSET,
+                                &ast_bo_driver,
+                                dev->anon_inode->i_mapping,
+                                DRM_FILE_PAGE_OFFSET,
                                 true);
        if (ret) {
                DRM_ERROR("Error initialising bo driver; %d\n", ret);
@@ -324,7 +326,6 @@ int ast_bo_create(struct drm_device *dev, int size, int align,
        }
 
        astbo->bo.bdev = &ast->ttm.bdev;
-       astbo->bo.bdev->dev_mapping = dev->dev_mapping;
 
        ast_ttm_placement(astbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
 
index 62ec7d4..dcf2e55 100644 (file)
@@ -62,10 +62,10 @@ static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                }
        }
 
-       if (WARN_ON(crtc->fb == NULL))
+       if (WARN_ON(crtc->primary->fb == NULL))
                return -EINVAL;
 
-       bochs_fb = to_bochs_framebuffer(crtc->fb);
+       bochs_fb = to_bochs_framebuffer(crtc->primary->fb);
        bo = gem_to_bochs_bo(bochs_fb->obj);
        ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
        if (ret)
index ce68587..f488be5 100644 (file)
@@ -225,7 +225,9 @@ int bochs_mm_init(struct bochs_device *bochs)
 
        ret = ttm_bo_device_init(&bochs->ttm.bdev,
                                 bochs->ttm.bo_global_ref.ref.object,
-                                &bochs_bo_driver, DRM_FILE_PAGE_OFFSET,
+                                &bochs_bo_driver,
+                                bochs->dev->anon_inode->i_mapping,
+                                DRM_FILE_PAGE_OFFSET,
                                 true);
        if (ret) {
                DRM_ERROR("Error initialising bo driver; %d\n", ret);
@@ -359,7 +361,7 @@ static int bochs_bo_create(struct drm_device *dev, int size, int align,
        }
 
        bochsbo->bo.bdev = &bochs->ttm.bdev;
-       bochsbo->bo.bdev->dev_mapping = dev->dev_mapping;
+       bochsbo->bo.bdev->dev_mapping = dev->anon_inode->i_mapping;
 
        bochs_ttm_placement(bochsbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
 
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
new file mode 100644 (file)
index 0000000..884923f
--- /dev/null
@@ -0,0 +1,5 @@
+config DRM_PTN3460
+       tristate "PTN3460 DP/LVDS bridge"
+       depends on DRM
+       select DRM_KMS_HELPER
+       ---help---
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
new file mode 100644 (file)
index 0000000..b4733e1
--- /dev/null
@@ -0,0 +1,3 @@
+ccflags-y := -Iinclude/drm
+
+obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
new file mode 100644 (file)
index 0000000..b171901
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * NXP PTN3460 DP/LVDS bridge driver
+ *
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "drmP.h"
+#include "drm_edid.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+#include "bridge/ptn3460.h"
+
+#define PTN3460_EDID_ADDR                      0x0
+#define PTN3460_EDID_EMULATION_ADDR            0x84
+#define PTN3460_EDID_ENABLE_EMULATION          0
+#define PTN3460_EDID_EMULATION_SELECTION       1
+#define PTN3460_EDID_SRAM_LOAD_ADDR            0x85
+
+struct ptn3460_bridge {
+       struct drm_connector connector;
+       struct i2c_client *client;
+       struct drm_encoder *encoder;
+       struct drm_bridge *bridge;
+       struct edid *edid;
+       int gpio_pd_n;
+       int gpio_rst_n;
+       u32 edid_emulation;
+       bool enabled;
+};
+
+static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
+               u8 *buf, int len)
+{
+       int ret;
+
+       ret = i2c_master_send(ptn_bridge->client, &addr, 1);
+       if (ret <= 0) {
+               DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
+               return ret;
+       }
+
+       ret = i2c_master_recv(ptn_bridge->client, buf, len);
+       if (ret <= 0) {
+               DRM_ERROR("Failed to recv i2c data, ret=%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ptn3460_write_byte(struct ptn3460_bridge *ptn_bridge, char addr,
+               char val)
+{
+       int ret;
+       char buf[2];
+
+       buf[0] = addr;
+       buf[1] = val;
+
+       ret = i2c_master_send(ptn_bridge->client, buf, ARRAY_SIZE(buf));
+       if (ret <= 0) {
+               DRM_ERROR("Failed to send i2c command, ret=%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
+{
+       int ret;
+       char val;
+
+       /* Load the selected edid into SRAM (accessed at PTN3460_EDID_ADDR) */
+       ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
+                       ptn_bridge->edid_emulation);
+       if (ret) {
+               DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret);
+               return ret;
+       }
+
+       /* Enable EDID emulation and select the desired EDID */
+       val = 1 << PTN3460_EDID_ENABLE_EMULATION |
+               ptn_bridge->edid_emulation << PTN3460_EDID_EMULATION_SELECTION;
+
+       ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
+       if (ret) {
+               DRM_ERROR("Failed to write edid value, ret=%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void ptn3460_pre_enable(struct drm_bridge *bridge)
+{
+       struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+       int ret;
+
+       if (ptn_bridge->enabled)
+               return;
+
+       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
+               gpio_set_value(ptn_bridge->gpio_pd_n, 1);
+
+       if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
+               gpio_set_value(ptn_bridge->gpio_rst_n, 0);
+               udelay(10);
+               gpio_set_value(ptn_bridge->gpio_rst_n, 1);
+       }
+
+       /*
+        * There's a bug in the PTN chip where it falsely asserts hotplug before
+        * it is fully functional. We're forced to wait for the maximum start up
+        * time specified in the chip's datasheet to make sure we're really up.
+        */
+       msleep(90);
+
+       ret = ptn3460_select_edid(ptn_bridge);
+       if (ret)
+               DRM_ERROR("Select edid failed ret=%d\n", ret);
+
+       ptn_bridge->enabled = true;
+}
+
+static void ptn3460_enable(struct drm_bridge *bridge)
+{
+}
+
+static void ptn3460_disable(struct drm_bridge *bridge)
+{
+       struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+
+       if (!ptn_bridge->enabled)
+               return;
+
+       ptn_bridge->enabled = false;
+
+       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
+               gpio_set_value(ptn_bridge->gpio_rst_n, 1);
+
+       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
+               gpio_set_value(ptn_bridge->gpio_pd_n, 0);
+}
+
+static void ptn3460_post_disable(struct drm_bridge *bridge)
+{
+}
+
+void ptn3460_bridge_destroy(struct drm_bridge *bridge)
+{
+       struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+
+       drm_bridge_cleanup(bridge);
+       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
+               gpio_free(ptn_bridge->gpio_pd_n);
+       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
+               gpio_free(ptn_bridge->gpio_rst_n);
+       /* Nothing else to free, we've got devm allocated memory */
+}
+
+struct drm_bridge_funcs ptn3460_bridge_funcs = {
+       .pre_enable = ptn3460_pre_enable,
+       .enable = ptn3460_enable,
+       .disable = ptn3460_disable,
+       .post_disable = ptn3460_post_disable,
+       .destroy = ptn3460_bridge_destroy,
+};
+
+int ptn3460_get_modes(struct drm_connector *connector)
+{
+       struct ptn3460_bridge *ptn_bridge;
+       u8 *edid;
+       int ret, num_modes;
+       bool power_off;
+
+       ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
+
+       if (ptn_bridge->edid)
+               return drm_add_edid_modes(connector, ptn_bridge->edid);
+
+       power_off = !ptn_bridge->enabled;
+       ptn3460_pre_enable(ptn_bridge->bridge);
+
+       edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
+       if (!edid) {
+               DRM_ERROR("Failed to allocate edid\n");
+               return 0;
+       }
+
+       ret = ptn3460_read_bytes(ptn_bridge, PTN3460_EDID_ADDR, edid,
+                       EDID_LENGTH);
+       if (ret) {
+               kfree(edid);
+               num_modes = 0;
+               goto out;
+       }
+
+       ptn_bridge->edid = (struct edid *)edid;
+       drm_mode_connector_update_edid_property(connector, ptn_bridge->edid);
+
+       num_modes = drm_add_edid_modes(connector, ptn_bridge->edid);
+
+out:
+       if (power_off)
+               ptn3460_disable(ptn_bridge->bridge);
+
+       return num_modes;
+}
+
+static int ptn3460_mode_valid(struct drm_connector *connector,
+               struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
+{
+       struct ptn3460_bridge *ptn_bridge;
+
+       ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
+
+       return ptn_bridge->encoder;
+}
+
+struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
+       .get_modes = ptn3460_get_modes,
+       .mode_valid = ptn3460_mode_valid,
+       .best_encoder = ptn3460_best_encoder,
+};
+
+enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
+               bool force)
+{
+       return connector_status_connected;
+}
+
+void ptn3460_connector_destroy(struct drm_connector *connector)
+{
+       drm_connector_cleanup(connector);
+}
+
+struct drm_connector_funcs ptn3460_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = ptn3460_detect,
+       .destroy = ptn3460_connector_destroy,
+};
+
+int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
+               struct i2c_client *client, struct device_node *node)
+{
+       int ret;
+       struct drm_bridge *bridge;
+       struct ptn3460_bridge *ptn_bridge;
+
+       bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL);
+       if (!bridge) {
+               DRM_ERROR("Failed to allocate drm bridge\n");
+               return -ENOMEM;
+       }
+
+       ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
+       if (!ptn_bridge) {
+               DRM_ERROR("Failed to allocate ptn bridge\n");
+               return -ENOMEM;
+       }
+
+       ptn_bridge->client = client;
+       ptn_bridge->encoder = encoder;
+       ptn_bridge->bridge = bridge;
+       ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
+       if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
+               ret = gpio_request_one(ptn_bridge->gpio_pd_n,
+                               GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
+               if (ret) {
+                       DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret);
+                       return ret;
+               }
+       }
+
+       ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0);
+       if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
+               /*
+                * Request the reset pin low to avoid the bridge being
+                * initialized prematurely
+                */
+               ret = gpio_request_one(ptn_bridge->gpio_rst_n,
+                               GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
+               if (ret) {
+                       DRM_ERROR("Request reset-gpio failed (%d)\n", ret);
+                       gpio_free(ptn_bridge->gpio_pd_n);
+                       return ret;
+               }
+       }
+
+       ret = of_property_read_u32(node, "edid-emulation",
+                       &ptn_bridge->edid_emulation);
+       if (ret) {
+               DRM_ERROR("Can't read edid emulation value\n");
+               goto err;
+       }
+
+       ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs);
+       if (ret) {
+               DRM_ERROR("Failed to initialize bridge with drm\n");
+               goto err;
+       }
+
+       bridge->driver_private = ptn_bridge;
+       encoder->bridge = bridge;
+
+       ret = drm_connector_init(dev, &ptn_bridge->connector,
+                       &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+       if (ret) {
+               DRM_ERROR("Failed to initialize connector with drm\n");
+               goto err;
+       }
+       drm_connector_helper_add(&ptn_bridge->connector,
+                       &ptn3460_connector_helper_funcs);
+       drm_sysfs_connector_add(&ptn_bridge->connector);
+       drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder);
+
+       return 0;
+
+err:
+       if (gpio_is_valid(ptn_bridge->gpio_pd_n))
+               gpio_free(ptn_bridge->gpio_pd_n);
+       if (gpio_is_valid(ptn_bridge->gpio_rst_n))
+               gpio_free(ptn_bridge->gpio_rst_n);
+       return ret;
+}
+EXPORT_SYMBOL(ptn3460_init);
index 530f78f..2d64aea 100644 (file)
@@ -149,7 +149,7 @@ static int cirrus_crtc_do_set_base(struct drm_crtc *crtc,
                cirrus_bo_unreserve(bo);
        }
 
-       cirrus_fb = to_cirrus_framebuffer(crtc->fb);
+       cirrus_fb = to_cirrus_framebuffer(crtc->primary->fb);
        obj = cirrus_fb->obj;
        bo = gem_to_cirrus_bo(obj);
 
@@ -268,7 +268,7 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
        sr07 = RREG8(SEQ_DATA);
        sr07 &= 0xe0;
        hdr = 0;
-       switch (crtc->fb->bits_per_pixel) {
+       switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
                sr07 |= 0x11;
                break;
@@ -291,13 +291,13 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
        WREG_SEQ(0x7, sr07);
 
        /* Program the pitch */
-       tmp = crtc->fb->pitches[0] / 8;
+       tmp = crtc->primary->fb->pitches[0] / 8;
        WREG_CRT(VGA_CRTC_OFFSET, tmp);
 
        /* Enable extended blanking and pitch bits, and enable full memory */
        tmp = 0x22;
-       tmp |= (crtc->fb->pitches[0] >> 7) & 0x10;
-       tmp |= (crtc->fb->pitches[0] >> 6) & 0x40;
+       tmp |= (crtc->primary->fb->pitches[0] >> 7) & 0x10;
+       tmp |= (crtc->primary->fb->pitches[0] >> 6) & 0x40;
        WREG_CRT(0x1b, tmp);
 
        /* Enable high-colour modes */
index 8b37c25..92e6b77 100644 (file)
@@ -259,7 +259,9 @@ int cirrus_mm_init(struct cirrus_device *cirrus)
 
        ret = ttm_bo_device_init(&cirrus->ttm.bdev,
                                 cirrus->ttm.bo_global_ref.ref.object,
-                                &cirrus_bo_driver, DRM_FILE_PAGE_OFFSET,
+                                &cirrus_bo_driver,
+                                dev->anon_inode->i_mapping,
+                                DRM_FILE_PAGE_OFFSET,
                                 true);
        if (ret) {
                DRM_ERROR("Error initialising bo driver; %d\n", ret);
@@ -329,7 +331,6 @@ int cirrus_bo_create(struct drm_device *dev, int size, int align,
        }
 
        cirrusbo->bo.bdev = &cirrus->ttm.bdev;
-       cirrusbo->bo.bdev->dev_mapping = dev->dev_mapping;
 
        cirrus_ttm_placement(cirrusbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
 
index 3b7d32d..d8b7099 100644 (file)
 #include <drm/drm_edid.h>
 #include <drm/drm_fourcc.h>
 
+#include "drm_crtc_internal.h"
+
 /**
  * drm_modeset_lock_all - take all modeset locks
  * @dev: drm device
  *
  * This function takes all modeset locks, suitable where a more fine-grained
- * scheme isn't (yet) implemented.
+ * scheme isn't (yet) implemented. Locks must be dropped with
+ * drm_modeset_unlock_all.
  */
 void drm_modeset_lock_all(struct drm_device *dev)
 {
@@ -59,6 +62,8 @@ EXPORT_SYMBOL(drm_modeset_lock_all);
 /**
  * drm_modeset_unlock_all - drop all modeset locks
  * @dev: device
+ *
+ * This function drop all modeset locks taken by drm_modeset_lock_all.
  */
 void drm_modeset_unlock_all(struct drm_device *dev)
 {
@@ -74,6 +79,8 @@ EXPORT_SYMBOL(drm_modeset_unlock_all);
 /**
  * drm_warn_on_modeset_not_all_locked - check that all modeset locks are locked
  * @dev: device
+ *
+ * Useful as a debug assert.
  */
 void drm_warn_on_modeset_not_all_locked(struct drm_device *dev)
 {
@@ -114,6 +121,13 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] =
 
 DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
 
+static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
+{
+       { DRM_PLANE_TYPE_OVERLAY, "Overlay" },
+       { DRM_PLANE_TYPE_PRIMARY, "Primary" },
+       { DRM_PLANE_TYPE_CURSOR, "Cursor" },
+};
+
 /*
  * Optional properties
  */
@@ -215,6 +229,16 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] =
        { DRM_MODE_ENCODER_DSI, "DSI" },
 };
 
+static const struct drm_prop_enum_list drm_subpixel_enum_list[] =
+{
+       { SubPixelUnknown, "Unknown" },
+       { SubPixelHorizontalRGB, "Horizontal RGB" },
+       { SubPixelHorizontalBGR, "Horizontal BGR" },
+       { SubPixelVerticalRGB, "Vertical RGB" },
+       { SubPixelVerticalBGR, "Vertical BGR" },
+       { SubPixelNone, "None" },
+};
+
 void drm_connector_ida_init(void)
 {
        int i;
@@ -231,6 +255,15 @@ void drm_connector_ida_destroy(void)
                ida_destroy(&drm_connector_enum_list[i].ida);
 }
 
+/**
+ * drm_get_encoder_name - return a string for encoder
+ * @encoder: encoder to compute name of
+ *
+ * Note that the buffer used by this function is globally shared and owned by
+ * the function itself.
+ *
+ * FIXME: This isn't really multithreading safe.
+ */
 const char *drm_get_encoder_name(const struct drm_encoder *encoder)
 {
        static char buf[32];
@@ -242,6 +275,15 @@ const char *drm_get_encoder_name(const struct drm_encoder *encoder)
 }
 EXPORT_SYMBOL(drm_get_encoder_name);
 
+/**
+ * drm_get_connector_name - return a string for connector
+ * @connector: connector to compute name of
+ *
+ * Note that the buffer used by this function is globally shared and owned by
+ * the function itself.
+ *
+ * FIXME: This isn't really multithreading safe.
+ */
 const char *drm_get_connector_name(const struct drm_connector *connector)
 {
        static char buf[32];
@@ -253,6 +295,13 @@ const char *drm_get_connector_name(const struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_get_connector_name);
 
+/**
+ * drm_get_connector_status_name - return a string for connector status
+ * @status: connector status to compute name of
+ *
+ * In contrast to the other drm_get_*_name functions this one here returns a
+ * const pointer and hence is threadsafe.
+ */
 const char *drm_get_connector_status_name(enum drm_connector_status status)
 {
        if (status == connector_status_connected)
@@ -264,11 +313,33 @@ const char *drm_get_connector_status_name(enum drm_connector_status status)
 }
 EXPORT_SYMBOL(drm_get_connector_status_name);
 
+/**
+ * drm_get_subpixel_order_name - return a string for a given subpixel enum
+ * @order: enum of subpixel_order
+ *
+ * Note you could abuse this and return something out of bounds, but that
+ * would be a caller error.  No unscrubbed user data should make it here.
+ */
+const char *drm_get_subpixel_order_name(enum subpixel_order order)
+{
+       return drm_subpixel_enum_list[order].name;
+}
+EXPORT_SYMBOL(drm_get_subpixel_order_name);
+
 static char printable_char(int c)
 {
        return isascii(c) && isprint(c) ? c : '?';
 }
 
+/**
+ * drm_get_format_name - return a string for drm fourcc format
+ * @format: format to compute name of
+ *
+ * Note that the buffer used by this function is globally shared and owned by
+ * the function itself.
+ *
+ * FIXME: This isn't really multithreading safe.
+ */
 const char *drm_get_format_name(uint32_t format)
 {
        static char buf[32];
@@ -293,14 +364,16 @@ EXPORT_SYMBOL(drm_get_format_name);
  * @obj_type: object type
  *
  * Create a unique identifier based on @ptr in @dev's identifier space.  Used
- * for tracking modes, CRTCs and connectors.
+ * for tracking modes, CRTCs and connectors. Note that despite the _get postfix
+ * modeset identifiers are _not_ reference counted. Hence don't use this for
+ * reference counted modeset objects like framebuffers.
  *
- * RETURNS:
+ * Returns:
  * New unique (relative to other objects in @dev) integer identifier for the
  * object.
  */
-static int drm_mode_object_get(struct drm_device *dev,
-                              struct drm_mode_object *obj, uint32_t obj_type)
+int drm_mode_object_get(struct drm_device *dev,
+                       struct drm_mode_object *obj, uint32_t obj_type)
 {
        int ret;
 
@@ -324,10 +397,12 @@ static int drm_mode_object_get(struct drm_device *dev,
  * @dev: DRM device
  * @object: object to free
  *
- * Free @id from @dev's unique identifier pool.
+ * Free @id from @dev's unique identifier pool. Note that despite the _get
+ * postfix modeset identifiers are _not_ reference counted. Hence don't use this
+ * for reference counted modeset objects like framebuffers.
  */
-static void drm_mode_object_put(struct drm_device *dev,
-                               struct drm_mode_object *object)
+void drm_mode_object_put(struct drm_device *dev,
+                        struct drm_mode_object *object)
 {
        mutex_lock(&dev->mode_config.idr_mutex);
        idr_remove(&dev->mode_config.crtc_idr, object->id);
@@ -377,7 +452,7 @@ EXPORT_SYMBOL(drm_mode_object_find);
  * since all the fb attributes are invariant over its lifetime, no further
  * locking but only correct reference counting is required.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, error code on failure.
  */
 int drm_framebuffer_init(struct drm_device *dev, struct drm_framebuffer *fb,
@@ -438,7 +513,7 @@ static struct drm_framebuffer *__drm_framebuffer_lookup(struct drm_device *dev,
  *
  * If successful, this grabs an additional reference to the framebuffer -
  * callers need to make sure to eventually unreference the returned framebuffer
- * again.
+ * again, using @drm_framebuffer_unreference.
  */
 struct drm_framebuffer *drm_framebuffer_lookup(struct drm_device *dev,
                                               uint32_t id)
@@ -471,6 +546,8 @@ EXPORT_SYMBOL(drm_framebuffer_unreference);
 /**
  * drm_framebuffer_reference - incr the fb refcnt
  * @fb: framebuffer
+ *
+ * This functions increments the fb's refcount.
  */
 void drm_framebuffer_reference(struct drm_framebuffer *fb)
 {
@@ -527,8 +604,9 @@ EXPORT_SYMBOL(drm_framebuffer_unregister_private);
  * drm_framebuffer_cleanup - remove a framebuffer object
  * @fb: framebuffer to remove
  *
- * Cleanup references to a user-created framebuffer. This function is intended
- * to be used from the drivers ->destroy callback.
+ * Cleanup framebuffer. This function is intended to be used from the drivers
+ * ->destroy callback. It can also be used to clean up driver private
+ *  framebuffers embedded into a larger structure.
  *
  * Note that this function does not remove the fb from active usuage - if it is
  * still used anywhere, hilarity can ensue since userspace could call getfb on
@@ -591,7 +669,7 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
                drm_modeset_lock_all(dev);
                /* remove from any CRTC */
                list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-                       if (crtc->fb == fb) {
+                       if (crtc->primary->fb == fb) {
                                /* should turn off the crtc */
                                memset(&set, 0, sizeof(struct drm_mode_set));
                                set.crtc = crtc;
@@ -614,18 +692,23 @@ void drm_framebuffer_remove(struct drm_framebuffer *fb)
 EXPORT_SYMBOL(drm_framebuffer_remove);
 
 /**
- * drm_crtc_init - Initialise a new CRTC object
+ * drm_crtc_init_with_planes - Initialise a new CRTC object with
+ *    specified primary and cursor planes.
  * @dev: DRM device
  * @crtc: CRTC object to init
+ * @primary: Primary plane for CRTC
+ * @cursor: Cursor plane for CRTC
  * @funcs: callbacks for the new CRTC
  *
  * Inits a new object created as base part of a driver crtc object.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, error code on failure.
  */
-int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
-                  const struct drm_crtc_funcs *funcs)
+int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
+                             struct drm_plane *primary,
+                             void *cursor,
+                             const struct drm_crtc_funcs *funcs)
 {
        int ret;
 
@@ -646,12 +729,16 @@ int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
        list_add_tail(&crtc->head, &dev->mode_config.crtc_list);
        dev->mode_config.num_crtc++;
 
+       crtc->primary = primary;
+       if (primary)
+               primary->possible_crtcs = 1 << drm_crtc_index(crtc);
+
  out:
        drm_modeset_unlock_all(dev);
 
        return ret;
 }
-EXPORT_SYMBOL(drm_crtc_init);
+EXPORT_SYMBOL(drm_crtc_init_with_planes);
 
 /**
  * drm_crtc_cleanup - Clean up the core crtc usage
@@ -697,20 +784,6 @@ unsigned int drm_crtc_index(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_index);
 
-/**
- * drm_mode_probed_add - add a mode to a connector's probed mode list
- * @connector: connector the new mode
- * @mode: mode data
- *
- * Add @mode to @connector's mode list for later use.
- */
-void drm_mode_probed_add(struct drm_connector *connector,
-                        struct drm_display_mode *mode)
-{
-       list_add_tail(&mode->head, &connector->probed_modes);
-}
-EXPORT_SYMBOL(drm_mode_probed_add);
-
 /*
  * drm_mode_remove - remove and free a mode
  * @connector: connector list to modify
@@ -735,7 +808,7 @@ static void drm_mode_remove(struct drm_connector *connector,
  * Initialises a preallocated connector. Connectors should be
  * subclassed as part of driver connector objects.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, error code on failure.
  */
 int drm_connector_init(struct drm_device *dev,
@@ -813,6 +886,14 @@ void drm_connector_cleanup(struct drm_connector *connector)
 }
 EXPORT_SYMBOL(drm_connector_cleanup);
 
+/**
+ * drm_connector_unplug_all - unregister connector userspace interfaces
+ * @dev: drm device
+ *
+ * This function unregisters all connector userspace interfaces in sysfs. Should
+ * be call when the device is disconnected, e.g. from an usb driver's
+ * ->disconnect callback.
+ */
 void drm_connector_unplug_all(struct drm_device *dev)
 {
        struct drm_connector *connector;
@@ -824,6 +905,18 @@ void drm_connector_unplug_all(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_connector_unplug_all);
 
+/**
+ * drm_bridge_init - initialize a drm transcoder/bridge
+ * @dev: drm device
+ * @bridge: transcoder/bridge to set up
+ * @funcs: bridge function table
+ *
+ * Initialises a preallocated bridge. Bridges should be
+ * subclassed as part of driver connector objects.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
 int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
                const struct drm_bridge_funcs *funcs)
 {
@@ -847,6 +940,12 @@ int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
 }
 EXPORT_SYMBOL(drm_bridge_init);
 
+/**
+ * drm_bridge_cleanup - cleans up an initialised bridge
+ * @bridge: bridge to cleanup
+ *
+ * Cleans up the bridge but doesn't free the object.
+ */
 void drm_bridge_cleanup(struct drm_bridge *bridge)
 {
        struct drm_device *dev = bridge->dev;
@@ -859,6 +958,19 @@ void drm_bridge_cleanup(struct drm_bridge *bridge)
 }
 EXPORT_SYMBOL(drm_bridge_cleanup);
 
+/**
+ * drm_encoder_init - Init a preallocated encoder
+ * @dev: drm device
+ * @encoder: the encoder to init
+ * @funcs: callbacks for this encoder
+ * @encoder_type: user visible type of the encoder
+ *
+ * Initialises a preallocated encoder. Encoder should be
+ * subclassed as part of driver encoder objects.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
 int drm_encoder_init(struct drm_device *dev,
                      struct drm_encoder *encoder,
                      const struct drm_encoder_funcs *funcs,
@@ -886,6 +998,12 @@ int drm_encoder_init(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_encoder_init);
 
+/**
+ * drm_encoder_cleanup - cleans up an initialised encoder
+ * @encoder: encoder to cleanup
+ *
+ * Cleans up the encoder but doesn't free the object.
+ */
 void drm_encoder_cleanup(struct drm_encoder *encoder)
 {
        struct drm_device *dev = encoder->dev;
@@ -898,25 +1016,25 @@ void drm_encoder_cleanup(struct drm_encoder *encoder)
 EXPORT_SYMBOL(drm_encoder_cleanup);
 
 /**
- * drm_plane_init - Initialise a new plane object
+ * drm_universal_plane_init - Initialize a new universal plane object
  * @dev: DRM device
  * @plane: plane object to init
  * @possible_crtcs: bitmask of possible CRTCs
  * @funcs: callbacks for the new plane
  * @formats: array of supported formats (%DRM_FORMAT_*)
  * @format_count: number of elements in @formats
- * @priv: plane is private (hidden from userspace)?
+ * @type: type of plane (overlay, primary, cursor)
  *
- * Inits a new object created as base part of a driver plane object.
+ * Initializes a plane object of type @type.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, error code on failure.
  */
-int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
-                  unsigned long possible_crtcs,
-                  const struct drm_plane_funcs *funcs,
-                  const uint32_t *formats, uint32_t format_count,
-                  bool priv)
+int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
+                            unsigned long possible_crtcs,
+                            const struct drm_plane_funcs *funcs,
+                            const uint32_t *formats, uint32_t format_count,
+                            enum drm_plane_type type)
 {
        int ret;
 
@@ -941,23 +1059,53 @@ int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
        memcpy(plane->format_types, formats, format_count * sizeof(uint32_t));
        plane->format_count = format_count;
        plane->possible_crtcs = possible_crtcs;
+       plane->type = type;
 
-       /* private planes are not exposed to userspace, but depending on
-        * display hardware, might be convenient to allow sharing programming
-        * for the scanout engine with the crtc implementation.
-        */
-       if (!priv) {
-               list_add_tail(&plane->head, &dev->mode_config.plane_list);
-               dev->mode_config.num_plane++;
-       } else {
-               INIT_LIST_HEAD(&plane->head);
-       }
+       list_add_tail(&plane->head, &dev->mode_config.plane_list);
+       dev->mode_config.num_total_plane++;
+       if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+               dev->mode_config.num_overlay_plane++;
+
+       drm_object_attach_property(&plane->base,
+                                  dev->mode_config.plane_type_property,
+                                  plane->type);
 
  out:
        drm_modeset_unlock_all(dev);
 
        return ret;
 }
+EXPORT_SYMBOL(drm_universal_plane_init);
+
+/**
+ * drm_plane_init - Initialize a legacy plane
+ * @dev: DRM device
+ * @plane: plane object to init
+ * @possible_crtcs: bitmask of possible CRTCs
+ * @funcs: callbacks for the new plane
+ * @formats: array of supported formats (%DRM_FORMAT_*)
+ * @format_count: number of elements in @formats
+ * @is_primary: plane type (primary vs overlay)
+ *
+ * Legacy API to initialize a DRM plane.
+ *
+ * New drivers should call drm_universal_plane_init() instead.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_plane_init(struct drm_device *dev, struct drm_plane *plane,
+                  unsigned long possible_crtcs,
+                  const struct drm_plane_funcs *funcs,
+                  const uint32_t *formats, uint32_t format_count,
+                  bool is_primary)
+{
+       enum drm_plane_type type;
+
+       type = is_primary ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+       return drm_universal_plane_init(dev, plane, possible_crtcs, funcs,
+                                       formats, format_count, type);
+}
 EXPORT_SYMBOL(drm_plane_init);
 
 /**
@@ -975,11 +1123,13 @@ void drm_plane_cleanup(struct drm_plane *plane)
        drm_modeset_lock_all(dev);
        kfree(plane->format_types);
        drm_mode_object_put(dev, &plane->base);
-       /* if not added to a list, it must be a private plane */
-       if (!list_empty(&plane->head)) {
-               list_del(&plane->head);
-               dev->mode_config.num_plane--;
-       }
+
+       BUG_ON(list_empty(&plane->head));
+
+       list_del(&plane->head);
+       dev->mode_config.num_total_plane--;
+       if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+               dev->mode_config.num_overlay_plane--;
        drm_modeset_unlock_all(dev);
 }
 EXPORT_SYMBOL(drm_plane_cleanup);
@@ -1010,50 +1160,6 @@ void drm_plane_force_disable(struct drm_plane *plane)
 }
 EXPORT_SYMBOL(drm_plane_force_disable);
 
-/**
- * drm_mode_create - create a new display mode
- * @dev: DRM device
- *
- * Create a new drm_display_mode, give it an ID, and return it.
- *
- * RETURNS:
- * Pointer to new mode on success, NULL on error.
- */
-struct drm_display_mode *drm_mode_create(struct drm_device *dev)
-{
-       struct drm_display_mode *nmode;
-
-       nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
-       if (!nmode)
-               return NULL;
-
-       if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
-               kfree(nmode);
-               return NULL;
-       }
-
-       return nmode;
-}
-EXPORT_SYMBOL(drm_mode_create);
-
-/**
- * drm_mode_destroy - remove a mode
- * @dev: DRM device
- * @mode: mode to remove
- *
- * Free @mode's unique identifier, then free it.
- */
-void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
-{
-       if (!mode)
-               return;
-
-       drm_mode_object_put(dev, &mode->base);
-
-       kfree(mode);
-}
-EXPORT_SYMBOL(drm_mode_destroy);
-
 static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
 {
        struct drm_property *edid;
@@ -1075,6 +1181,21 @@ static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
        return 0;
 }
 
+static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
+{
+       struct drm_property *type;
+
+       /*
+        * Standard properties (apply to all planes)
+        */
+       type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+                                       "type", drm_plane_type_enum_list,
+                                       ARRAY_SIZE(drm_plane_type_enum_list));
+       dev->mode_config.plane_type_property = type;
+
+       return 0;
+}
+
 /**
  * drm_mode_create_dvi_i_properties - create DVI-I specific connector properties
  * @dev: DRM device
@@ -1257,6 +1378,10 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
        return 0;
 }
 
+/*
+ * NOTE: Driver's shouldn't ever call drm_mode_group_init_legacy_group - it is
+ * the drm core's responsibility to set up mode control groups.
+ */
 int drm_mode_group_init_legacy_group(struct drm_device *dev,
                                     struct drm_mode_group *group)
 {
@@ -1333,7 +1458,7 @@ static void drm_crtc_convert_to_umode(struct drm_mode_modeinfo *out,
  * Convert a drm_mode_modeinfo into a drm_display_mode structure to return to
  * the caller.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 static int drm_crtc_convert_umode(struct drm_display_mode *out,
@@ -1376,7 +1501,7 @@ static int drm_crtc_convert_umode(struct drm_display_mode *out,
  *
  * Called by the user via ioctl.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 int drm_mode_getresources(struct drm_device *dev, void *data,
@@ -1429,9 +1554,9 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        mutex_unlock(&file_priv->fbs_lock);
 
        drm_modeset_lock_all(dev);
-       mode_group = &file_priv->master->minor->mode_group;
-       if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
+       if (!drm_is_primary_client(file_priv)) {
 
+               mode_group = NULL;
                list_for_each(lh, &dev->mode_config.crtc_list)
                        crtc_count++;
 
@@ -1442,6 +1567,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
                        encoder_count++;
        } else {
 
+               mode_group = &file_priv->master->minor->mode_group;
                crtc_count = mode_group->num_crtcs;
                connector_count = mode_group->num_connectors;
                encoder_count = mode_group->num_encoders;
@@ -1456,7 +1582,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        if (card_res->count_crtcs >= crtc_count) {
                copied = 0;
                crtc_id = (uint32_t __user *)(unsigned long)card_res->crtc_id_ptr;
-               if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
+               if (!mode_group) {
                        list_for_each_entry(crtc, &dev->mode_config.crtc_list,
                                            head) {
                                DRM_DEBUG_KMS("[CRTC:%d]\n", crtc->base.id);
@@ -1483,7 +1609,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        if (card_res->count_encoders >= encoder_count) {
                copied = 0;
                encoder_id = (uint32_t __user *)(unsigned long)card_res->encoder_id_ptr;
-               if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
+               if (!mode_group) {
                        list_for_each_entry(encoder,
                                            &dev->mode_config.encoder_list,
                                            head) {
@@ -1514,7 +1640,7 @@ int drm_mode_getresources(struct drm_device *dev, void *data,
        if (card_res->count_connectors >= connector_count) {
                copied = 0;
                connector_id = (uint32_t __user *)(unsigned long)card_res->connector_id_ptr;
-               if (file_priv->master->minor->type == DRM_MINOR_CONTROL) {
+               if (!mode_group) {
                        list_for_each_entry(connector,
                                            &dev->mode_config.connector_list,
                                            head) {
@@ -1561,7 +1687,7 @@ out:
  *
  * Called by the user via ioctl.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 int drm_mode_getcrtc(struct drm_device *dev,
@@ -1588,8 +1714,8 @@ int drm_mode_getcrtc(struct drm_device *dev,
        crtc_resp->x = crtc->x;
        crtc_resp->y = crtc->y;
        crtc_resp->gamma_size = crtc->gamma_size;
-       if (crtc->fb)
-               crtc_resp->fb_id = crtc->fb->base.id;
+       if (crtc->primary->fb)
+               crtc_resp->fb_id = crtc->primary->fb->base.id;
        else
                crtc_resp->fb_id = 0;
 
@@ -1630,7 +1756,7 @@ static bool drm_mode_expose_to_userspace(const struct drm_display_mode *mode,
  *
  * Called by the user via ioctl.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 int drm_mode_getconnector(struct drm_device *dev, void *data,
@@ -1765,6 +1891,19 @@ out:
        return ret;
 }
 
+/**
+ * drm_mode_getencoder - get encoder configuration
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Construct a encoder configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_getencoder(struct drm_device *dev, void *data,
                        struct drm_file *file_priv)
 {
@@ -1800,21 +1939,27 @@ out:
 }
 
 /**
- * drm_mode_getplane_res - get plane info
+ * drm_mode_getplane_res - enumerate all plane resources
  * @dev: DRM device
  * @data: ioctl data
  * @file_priv: DRM file info
  *
- * Return an plane count and set of IDs.
+ * Construct a list of plane ids to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
  */
 int drm_mode_getplane_res(struct drm_device *dev, void *data,
-                           struct drm_file *file_priv)
+                         struct drm_file *file_priv)
 {
        struct drm_mode_get_plane_res *plane_resp = data;
        struct drm_mode_config *config;
        struct drm_plane *plane;
        uint32_t __user *plane_ptr;
        int copied = 0, ret = 0;
+       unsigned num_planes;
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                return -EINVAL;
@@ -1822,15 +1967,28 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
        drm_modeset_lock_all(dev);
        config = &dev->mode_config;
 
+       if (file_priv->universal_planes)
+               num_planes = config->num_total_plane;
+       else
+               num_planes = config->num_overlay_plane;
+
        /*
         * This ioctl is called twice, once to determine how much space is
         * needed, and the 2nd time to fill it.
         */
-       if (config->num_plane &&
-           (plane_resp->count_planes >= config->num_plane)) {
+       if (num_planes &&
+           (plane_resp->count_planes >= num_planes)) {
                plane_ptr = (uint32_t __user *)(unsigned long)plane_resp->plane_id_ptr;
 
                list_for_each_entry(plane, &config->plane_list, head) {
+                       /*
+                        * Unless userspace set the 'universal planes'
+                        * capability bit, only advertise overlays.
+                        */
+                       if (plane->type != DRM_PLANE_TYPE_OVERLAY &&
+                           !file_priv->universal_planes)
+                               continue;
+
                        if (put_user(plane->base.id, plane_ptr + copied)) {
                                ret = -EFAULT;
                                goto out;
@@ -1838,7 +1996,7 @@ int drm_mode_getplane_res(struct drm_device *dev, void *data,
                        copied++;
                }
        }
-       plane_resp->count_planes = config->num_plane;
+       plane_resp->count_planes = num_planes;
 
 out:
        drm_modeset_unlock_all(dev);
@@ -1846,16 +2004,20 @@ out:
 }
 
 /**
- * drm_mode_getplane - get plane info
+ * drm_mode_getplane - get plane configuration
  * @dev: DRM device
  * @data: ioctl data
  * @file_priv: DRM file info
  *
- * Return plane info, including formats supported, gamma size, any
- * current fb, etc.
+ * Construct a plane configuration structure to return to the user.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
  */
 int drm_mode_getplane(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv)
+                     struct drm_file *file_priv)
 {
        struct drm_mode_get_plane *plane_resp = data;
        struct drm_mode_object *obj;
@@ -1911,16 +2073,19 @@ out:
 }
 
 /**
- * drm_mode_setplane - set up or tear down an plane
+ * drm_mode_setplane - configure a plane's configuration
  * @dev: DRM device
  * @data: ioctl data*
  * @file_priv: DRM file info
  *
- * Set plane info, including placement, fb, scaling, and other factors.
+ * Set plane configuration, including placement, fb, scaling, and other factors.
  * Or pass a NULL fb to disable.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
  */
 int drm_mode_setplane(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv)
+                     struct drm_file *file_priv)
 {
        struct drm_mode_set_plane *plane_req = data;
        struct drm_mode_object *obj;
@@ -2050,6 +2215,9 @@ out:
  *
  * This is a little helper to wrap internal calls to the ->set_config driver
  * interface. The only thing it adds is correct refcounting dance.
+ * 
+ * Returns:
+ * Zero on success, errno on failure.
  */
 int drm_mode_set_config_internal(struct drm_mode_set *set)
 {
@@ -2064,19 +2232,21 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
         * crtcs. Atomic modeset will have saner semantics ...
         */
        list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head)
-               tmp->old_fb = tmp->fb;
+               tmp->old_fb = tmp->primary->fb;
 
        fb = set->fb;
 
        ret = crtc->funcs->set_config(set);
        if (ret == 0) {
+               crtc->primary->crtc = crtc;
+
                /* crtc->fb must be updated by ->set_config, enforces this. */
-               WARN_ON(fb != crtc->fb);
+               WARN_ON(fb != crtc->primary->fb);
        }
 
        list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
-               if (tmp->fb)
-                       drm_framebuffer_reference(tmp->fb);
+               if (tmp->primary->fb)
+                       drm_framebuffer_reference(tmp->primary->fb);
                if (tmp->old_fb)
                        drm_framebuffer_unreference(tmp->old_fb);
        }
@@ -2085,14 +2255,19 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
 }
 EXPORT_SYMBOL(drm_mode_set_config_internal);
 
-/*
- * Checks that the framebuffer is big enough for the CRTC viewport
- * (x, y, hdisplay, vdisplay)
+/**
+ * drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
+ *     CRTC viewport
+ * @crtc: CRTC that framebuffer will be displayed on
+ * @x: x panning
+ * @y: y panning
+ * @mode: mode that framebuffer will be displayed under
+ * @fb: framebuffer to check size of
  */
-static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
-                                  int x, int y,
-                                  const struct drm_display_mode *mode,
-                                  const struct drm_framebuffer *fb)
+int drm_crtc_check_viewport(const struct drm_crtc *crtc,
+                           int x, int y,
+                           const struct drm_display_mode *mode,
+                           const struct drm_framebuffer *fb)
 
 {
        int hdisplay, vdisplay;
@@ -2123,6 +2298,7 @@ static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
 
        return 0;
 }
+EXPORT_SYMBOL(drm_crtc_check_viewport);
 
 /**
  * drm_mode_setcrtc - set CRTC configuration
@@ -2134,7 +2310,7 @@ static int drm_crtc_check_viewport(const struct drm_crtc *crtc,
  *
  * Called by the user via ioctl.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 int drm_mode_setcrtc(struct drm_device *dev, void *data,
@@ -2174,12 +2350,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
                /* If we have a mode we need a framebuffer. */
                /* If we pass -1, set the mode with the currently bound fb */
                if (crtc_req->fb_id == -1) {
-                       if (!crtc->fb) {
+                       if (!crtc->primary->fb) {
                                DRM_DEBUG_KMS("CRTC doesn't have current FB\n");
                                ret = -EINVAL;
                                goto out;
                        }
-                       fb = crtc->fb;
+                       fb = crtc->primary->fb;
                        /* Make refcounting symmetric with the lookup path. */
                        drm_framebuffer_reference(fb);
                } else {
@@ -2336,8 +2512,23 @@ out:
        return ret;
 
 }
+
+
+/**
+ * drm_mode_cursor_ioctl - set CRTC's cursor configuration
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Set the cursor configuration based on user request.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_cursor_ioctl(struct drm_device *dev,
-                       void *data, struct drm_file *file_priv)
+                         void *data, struct drm_file *file_priv)
 {
        struct drm_mode_cursor *req = data;
        struct drm_mode_cursor2 new_req;
@@ -2348,6 +2539,21 @@ int drm_mode_cursor_ioctl(struct drm_device *dev,
        return drm_mode_cursor_common(dev, &new_req, file_priv);
 }
 
+/**
+ * drm_mode_cursor2_ioctl - set CRTC's cursor configuration
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Set the cursor configuration based on user request. This implements the 2nd
+ * version of the cursor ioctl, which allows userspace to additionally specify
+ * the hotspot of the pointer.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_cursor2_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
 {
@@ -2355,7 +2561,14 @@ int drm_mode_cursor2_ioctl(struct drm_device *dev,
        return drm_mode_cursor_common(dev, req, file_priv);
 }
 
-/* Original addfb only supported RGB formats, so figure out which one */
+/**
+ * drm_mode_legacy_fb_format - compute drm fourcc code from legacy description
+ * @bpp: bits per pixels
+ * @depth: bit depth per pixel
+ *
+ * Computes a drm fourcc pixel format code for the given @bpp/@depth values.
+ * Useful in fbdev emulation code, since that deals in those values.
+ */
 uint32_t drm_mode_legacy_fb_format(uint32_t bpp, uint32_t depth)
 {
        uint32_t fmt;
@@ -2397,11 +2610,12 @@ EXPORT_SYMBOL(drm_mode_legacy_fb_format);
  * @data: data pointer for the ioctl
  * @file_priv: drm file for the ioctl call
  *
- * Add a new FB to the specified CRTC, given a user request.
+ * Add a new FB to the specified CRTC, given a user request. This is the
+ * original addfb ioclt which only supported RGB formats.
  *
  * Called by the user via ioctl.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 int drm_mode_addfb(struct drm_device *dev,
@@ -2574,11 +2788,13 @@ static int framebuffer_check(const struct drm_mode_fb_cmd2 *r)
  * @data: data pointer for the ioctl
  * @file_priv: drm file for the ioctl call
  *
- * Add a new FB to the specified CRTC, given a user request with format.
+ * Add a new FB to the specified CRTC, given a user request with format. This is
+ * the 2nd version of the addfb ioctl, which supports multi-planar framebuffers
+ * and uses fourcc codes as pixel format specifiers.
  *
  * Called by the user via ioctl.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 int drm_mode_addfb2(struct drm_device *dev,
@@ -2638,7 +2854,7 @@ int drm_mode_addfb2(struct drm_device *dev,
  *
  * Called by the user via ioctl.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 int drm_mode_rmfb(struct drm_device *dev,
@@ -2692,7 +2908,7 @@ fail_lookup:
  *
  * Called by the user via ioctl.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 int drm_mode_getfb(struct drm_device *dev,
@@ -2715,7 +2931,8 @@ int drm_mode_getfb(struct drm_device *dev,
        r->bpp = fb->bits_per_pixel;
        r->pitch = fb->pitches[0];
        if (fb->funcs->create_handle) {
-               if (file_priv->is_master || capable(CAP_SYS_ADMIN)) {
+               if (file_priv->is_master || capable(CAP_SYS_ADMIN) ||
+                   drm_is_control_client(file_priv)) {
                        ret = fb->funcs->create_handle(fb, file_priv,
                                                       &r->handle);
                } else {
@@ -2736,6 +2953,25 @@ int drm_mode_getfb(struct drm_device *dev,
        return ret;
 }
 
+/**
+ * drm_mode_dirtyfb_ioctl - flush frontbuffer rendering on an FB
+ * @dev: drm device for the ioctl
+ * @data: data pointer for the ioctl
+ * @file_priv: drm file for the ioctl call
+ *
+ * Lookup the FB and flush out the damaged area supplied by userspace as a clip
+ * rectangle list. Generic userspace which does frontbuffer rendering must call
+ * this ioctl to flush out the changes on manual-update display outputs, e.g.
+ * usb display-link, mipi manual update panels or edp panel self refresh modes.
+ *
+ * Modesetting drivers which always update the frontbuffer do not need to
+ * implement the corresponding ->dirty framebuffer callback.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
 {
@@ -2813,7 +3049,7 @@ out_err1:
  *
  * Called by the user via ioctl.
  *
- * RETURNS:
+ * Returns:
  * Zero on success, errno on failure.
  */
 void drm_fb_release(struct drm_file *priv)
@@ -2837,6 +3073,20 @@ void drm_fb_release(struct drm_file *priv)
        mutex_unlock(&priv->fbs_lock);
 }
 
+/**
+ * drm_property_create - create a new property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @num_values: number of pre-defined values
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create(struct drm_device *dev, int flags,
                                         const char *name, int num_values)
 {
@@ -2875,6 +3125,24 @@ fail:
 }
 EXPORT_SYMBOL(drm_property_create);
 
+/**
+ * drm_property_create - create a new enumeration property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @props: enumeration lists with property values
+ * @num_values: number of pre-defined values
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is only allowed to set one of the predefined values for enumeration
+ * properties.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
                                         const char *name,
                                         const struct drm_prop_enum_list *props,
@@ -2903,6 +3171,24 @@ struct drm_property *drm_property_create_enum(struct drm_device *dev, int flags,
 }
 EXPORT_SYMBOL(drm_property_create_enum);
 
+/**
+ * drm_property_create - create a new bitmask property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @props: enumeration lists with property bitflags
+ * @num_values: number of pre-defined values
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Compared to plain enumeration properties userspace is allowed to set any
+ * or'ed together combination of the predefined property bitflag values
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
                                         int flags, const char *name,
                                         const struct drm_prop_enum_list *props,
@@ -2931,6 +3217,24 @@ struct drm_property *drm_property_create_bitmask(struct drm_device *dev,
 }
 EXPORT_SYMBOL(drm_property_create_bitmask);
 
+/**
+ * drm_property_create - create a new ranged property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @min: minimum value of the property
+ * @max: maximum value of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is allowed to set any interger value in the (min, max) range
+ * inclusive.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
 struct drm_property *drm_property_create_range(struct drm_device *dev, int flags,
                                         const char *name,
                                         uint64_t min, uint64_t max)
@@ -2950,6 +3254,21 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags
 }
 EXPORT_SYMBOL(drm_property_create_range);
 
+/**
+ * drm_property_add_enum - add a possible value to an enumeration property
+ * @property: enumeration property to change
+ * @index: index of the new enumeration
+ * @value: value of the new enumeration
+ * @name: symbolic name of the new enumeration
+ *
+ * This functions adds enumerations to a property.
+ *
+ * It's use is deprecated, drivers should use one of the more specific helpers
+ * to directly create the property with all enumerations already attached.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
 int drm_property_add_enum(struct drm_property *property, int index,
                          uint64_t value, const char *name)
 {
@@ -2989,6 +3308,14 @@ int drm_property_add_enum(struct drm_property *property, int index,
 }
 EXPORT_SYMBOL(drm_property_add_enum);
 
+/**
+ * drm_property_destroy - destroy a drm property
+ * @dev: drm device
+ * @property: property to destry
+ *
+ * This function frees a property including any attached resources like
+ * enumeration values.
+ */
 void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
 {
        struct drm_property_enum *prop_enum, *pt;
@@ -3006,6 +3333,16 @@ void drm_property_destroy(struct drm_device *dev, struct drm_property *property)
 }
 EXPORT_SYMBOL(drm_property_destroy);
 
+/**
+ * drm_object_attach_property - attach a property to a modeset object
+ * @obj: drm modeset object
+ * @property: property to attach
+ * @init_val: initial value of the property
+ *
+ * This attaches the given property to the modeset object with the given initial
+ * value. Currently this function cannot fail since the properties are stored in
+ * a statically sized array.
+ */
 void drm_object_attach_property(struct drm_mode_object *obj,
                                struct drm_property *property,
                                uint64_t init_val)
@@ -3026,6 +3363,19 @@ void drm_object_attach_property(struct drm_mode_object *obj,
 }
 EXPORT_SYMBOL(drm_object_attach_property);
 
+/**
+ * drm_object_property_set_value - set the value of a property
+ * @obj: drm mode object to set property value for
+ * @property: property to set
+ * @val: value the property should be set to
+ *
+ * This functions sets a given property on a given object. This function only
+ * changes the software state of the property, it does not call into the
+ * driver's ->set_property callback.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
 int drm_object_property_set_value(struct drm_mode_object *obj,
                                  struct drm_property *property, uint64_t val)
 {
@@ -3042,6 +3392,20 @@ int drm_object_property_set_value(struct drm_mode_object *obj,
 }
 EXPORT_SYMBOL(drm_object_property_set_value);
 
+/**
+ * drm_object_property_get_value - retrieve the value of a property
+ * @obj: drm mode object to get property value from
+ * @property: property to retrieve
+ * @val: storage for the property value
+ *
+ * This function retrieves the softare state of the given property for the given
+ * property. Since there is no driver callback to retrieve the current property
+ * value this might be out of sync with the hardware, depending upon the driver
+ * and property.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
 int drm_object_property_get_value(struct drm_mode_object *obj,
                                  struct drm_property *property, uint64_t *val)
 {
@@ -3058,6 +3422,19 @@ int drm_object_property_get_value(struct drm_mode_object *obj,
 }
 EXPORT_SYMBOL(drm_object_property_get_value);
 
+/**
+ * drm_mode_getproperty_ioctl - get the current value of a connector's property
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * This function retrieves the current value for an connectors's property.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_getproperty_ioctl(struct drm_device *dev,
                               void *data, struct drm_file *file_priv)
 {
@@ -3196,6 +3573,20 @@ static void drm_property_destroy_blob(struct drm_device *dev,
        kfree(blob);
 }
 
+/**
+ * drm_mode_getblob_ioctl - get the contents of a blob property value
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * This function retrieves the contents of a blob property. The value stored in
+ * an object's blob property is just a normal modeset object id.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_getblob_ioctl(struct drm_device *dev,
                           void *data, struct drm_file *file_priv)
 {
@@ -3230,6 +3621,17 @@ done:
        return ret;
 }
 
+/**
+ * drm_mode_connector_update_edid_property - update the edid property of a connector
+ * @connector: drm connector
+ * @edid: new value of the edid property
+ *
+ * This function creates a new blob modeset object and assigns its id to the
+ * connector's edid property.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_connector_update_edid_property(struct drm_connector *connector,
                                            struct edid *edid)
 {
@@ -3287,6 +3689,20 @@ static bool drm_property_change_is_valid(struct drm_property *property,
        }
 }
 
+/**
+ * drm_mode_connector_property_set_ioctl - set the current value of a connector property
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * This function sets the current value for a connectors's property. It also
+ * calls into a driver's ->set_property callback to update the hardware state
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_connector_property_set_ioctl(struct drm_device *dev,
                                       void *data, struct drm_file *file_priv)
 {
@@ -3353,6 +3769,21 @@ static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
        return ret;
 }
 
+/**
+ * drm_mode_getproperty_ioctl - get the current value of a object's property
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * This function retrieves the current value for an object's property. Compared
+ * to the connector specific ioctl this one is extended to also work on crtc and
+ * plane objects.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
                                      struct drm_file *file_priv)
 {
@@ -3409,6 +3840,22 @@ out:
        return ret;
 }
 
+/**
+ * drm_mode_obj_set_property_ioctl - set the current value of an object's property
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * This function sets the current value for an object's property. It also calls
+ * into a driver's ->set_property callback to update the hardware state.
+ * Compared to the connector specific ioctl this one is extended to also work on
+ * crtc and plane objects.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
                                    struct drm_file *file_priv)
 {
@@ -3468,6 +3915,18 @@ out:
        return ret;
 }
 
+/**
+ * drm_mode_connector_attach_encoder - attach a connector to an encoder
+ * @connector: connector to attach
+ * @encoder: encoder to attach @connector to
+ *
+ * This function links up a connector to an encoder. Note that the routing
+ * restrictions between encoders and crtcs are exposed to userspace through the
+ * possible_clones and possible_crtcs bitmasks.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_connector_attach_encoder(struct drm_connector *connector,
                                      struct drm_encoder *encoder)
 {
@@ -3483,23 +3942,20 @@ int drm_mode_connector_attach_encoder(struct drm_connector *connector,
 }
 EXPORT_SYMBOL(drm_mode_connector_attach_encoder);
 
-void drm_mode_connector_detach_encoder(struct drm_connector *connector,
-                                   struct drm_encoder *encoder)
-{
-       int i;
-       for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
-               if (connector->encoder_ids[i] == encoder->base.id) {
-                       connector->encoder_ids[i] = 0;
-                       if (connector->encoder == encoder)
-                               connector->encoder = NULL;
-                       break;
-               }
-       }
-}
-EXPORT_SYMBOL(drm_mode_connector_detach_encoder);
-
+/**
+ * drm_mode_crtc_set_gamma_size - set the gamma table size
+ * @crtc: CRTC to set the gamma table size for
+ * @gamma_size: size of the gamma table
+ *
+ * Drivers which support gamma tables should set this to the supported gamma
+ * table size when initializing the CRTC. Currently the drm core only supports a
+ * fixed gamma table size.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
-                                 int gamma_size)
+                                int gamma_size)
 {
        crtc->gamma_size = gamma_size;
 
@@ -3513,6 +3969,20 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
 }
 EXPORT_SYMBOL(drm_mode_crtc_set_gamma_size);
 
+/**
+ * drm_mode_gamma_set_ioctl - set the gamma table
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * Set the gamma table of a CRTC to the one passed in by the user. Userspace can
+ * inquire the required gamma table size through drm_mode_gamma_get_ioctl.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_gamma_set_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
 {
@@ -3572,6 +4042,21 @@ out:
 
 }
 
+/**
+ * drm_mode_gamma_get_ioctl - get the gamma table
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * Copy the current gamma table into the storage provided. This also provides
+ * the gamma table size the driver expects, which can be used to size the
+ * allocated storage.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_gamma_get_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
 {
@@ -3622,6 +4107,24 @@ out:
        return ret;
 }
 
+/**
+ * drm_mode_page_flip_ioctl - schedule an asynchronous fb update
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * This schedules an asynchronous update on a given CRTC, called page flip.
+ * Optionally a drm event is generated to signal the completion of the event.
+ * Generic drivers cannot assume that a pageflip with changed framebuffer
+ * properties (including driver specific metadata like tiling layout) will work,
+ * but some drivers support e.g. pixel format changes through the pageflip
+ * ioctl.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_page_flip_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
 {
@@ -3646,7 +4149,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
        crtc = obj_to_crtc(obj);
 
        mutex_lock(&crtc->mutex);
-       if (crtc->fb == NULL) {
+       if (crtc->primary->fb == NULL) {
                /* The framebuffer is currently unbound, presumably
                 * due to a hotplug event, that userspace has not
                 * yet discovered.
@@ -3668,7 +4171,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
        if (ret)
                goto out;
 
-       if (crtc->fb->pixel_format != fb->pixel_format) {
+       if (crtc->primary->fb->pixel_format != fb->pixel_format) {
                DRM_DEBUG_KMS("Page flip is not allowed to change frame buffer format.\n");
                ret = -EINVAL;
                goto out;
@@ -3701,7 +4204,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
                        (void (*) (struct drm_pending_event *)) kfree;
        }
 
-       old_fb = crtc->fb;
+       old_fb = crtc->primary->fb;
        ret = crtc->funcs->page_flip(crtc, fb, e, page_flip->flags);
        if (ret) {
                if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
@@ -3719,7 +4222,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
                 * Failing to do so will screw with the reference counting
                 * on framebuffers.
                 */
-               WARN_ON(crtc->fb != fb);
+               WARN_ON(crtc->primary->fb != fb);
                /* Unref only the old framebuffer. */
                fb = NULL;
        }
@@ -3734,6 +4237,14 @@ out:
        return ret;
 }
 
+/**
+ * drm_mode_config_reset - call ->reset callbacks
+ * @dev: drm device
+ *
+ * This functions calls all the crtc's, encoder's and connector's ->reset
+ * callback. Drivers can use this in e.g. their driver load or resume code to
+ * reset hardware and software state.
+ */
 void drm_mode_config_reset(struct drm_device *dev)
 {
        struct drm_crtc *crtc;
@@ -3757,16 +4268,66 @@ void drm_mode_config_reset(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_mode_config_reset);
 
+/**
+ * drm_mode_create_dumb_ioctl - create a dumb backing storage buffer
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * This creates a new dumb buffer in the driver's backing storage manager (GEM,
+ * TTM or something else entirely) and returns the resulting buffer handle. This
+ * handle can then be wrapped up into a framebuffer modeset object.
+ *
+ * Note that userspace is not allowed to use such objects for render
+ * acceleration - drivers must create their own private ioctls for such a use
+ * case.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_create_dumb_ioctl(struct drm_device *dev,
                               void *data, struct drm_file *file_priv)
 {
        struct drm_mode_create_dumb *args = data;
+       u32 cpp, stride, size;
 
        if (!dev->driver->dumb_create)
                return -ENOSYS;
+       if (!args->width || !args->height || !args->bpp)
+               return -EINVAL;
+
+       /* overflow checks for 32bit size calculations */
+       cpp = DIV_ROUND_UP(args->bpp, 8);
+       if (cpp > 0xffffffffU / args->width)
+               return -EINVAL;
+       stride = cpp * args->width;
+       if (args->height > 0xffffffffU / stride)
+               return -EINVAL;
+
+       /* test for wrap-around */
+       size = args->height * stride;
+       if (PAGE_ALIGN(size) == 0)
+               return -EINVAL;
+
        return dev->driver->dumb_create(file_priv, dev, args);
 }
 
+/**
+ * drm_mode_mmap_dumb_ioctl - create an mmap offset for a dumb backing storage buffer
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * Allocate an offset in the drm device node's address space to be able to
+ * memory map a dumb buffer.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
                             void *data, struct drm_file *file_priv)
 {
@@ -3779,6 +4340,21 @@ int drm_mode_mmap_dumb_ioctl(struct drm_device *dev,
        return dev->driver->dumb_map_offset(file_priv, dev, args->handle, &args->offset);
 }
 
+/**
+ * drm_mode_destroy_dumb_ioctl - destroy a dumb backing strage buffer
+ * @dev: DRM device
+ * @data: ioctl data
+ * @file_priv: DRM file info
+ *
+ * This destroys the userspace handle for the given dumb backing storage buffer.
+ * Since buffer objects must be reference counted in the kernel a buffer object
+ * won't be immediately freed if a framebuffer modeset object still uses it.
+ *
+ * Called by the user via ioctl.
+ *
+ * Returns:
+ * Zero on success, errno on failure.
+ */
 int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
                                void *data, struct drm_file *file_priv)
 {
@@ -3790,9 +4366,14 @@ int drm_mode_destroy_dumb_ioctl(struct drm_device *dev,
        return dev->driver->dumb_destroy(file_priv, dev, args->handle);
 }
 
-/*
- * Just need to support RGB formats here for compat with code that doesn't
- * use pixel formats directly yet.
+/**
+ * drm_fb_get_bpp_depth - get the bpp/depth values for format
+ * @format: pixel format (DRM_FORMAT_*)
+ * @depth: storage for the depth value
+ * @bpp: storage for the bpp value
+ *
+ * This only supports RGB formats here for compat with code that doesn't use
+ * pixel formats directly yet.
  */
 void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
                          int *bpp)
@@ -3864,7 +4445,7 @@ EXPORT_SYMBOL(drm_fb_get_bpp_depth);
  * drm_format_num_planes - get the number of planes for format
  * @format: pixel format (DRM_FORMAT_*)
  *
- * RETURNS:
+ * Returns:
  * The number of planes used by the specified pixel format.
  */
 int drm_format_num_planes(uint32_t format)
@@ -3899,7 +4480,7 @@ EXPORT_SYMBOL(drm_format_num_planes);
  * @format: pixel format (DRM_FORMAT_*)
  * @plane: plane index
  *
- * RETURNS:
+ * Returns:
  * The bytes per pixel value for the specified plane.
  */
 int drm_format_plane_cpp(uint32_t format, int plane)
@@ -3945,7 +4526,7 @@ EXPORT_SYMBOL(drm_format_plane_cpp);
  * drm_format_horz_chroma_subsampling - get the horizontal chroma subsampling factor
  * @format: pixel format (DRM_FORMAT_*)
  *
- * RETURNS:
+ * Returns:
  * The horizontal chroma subsampling factor for the
  * specified pixel format.
  */
@@ -3980,7 +4561,7 @@ EXPORT_SYMBOL(drm_format_horz_chroma_subsampling);
  * drm_format_vert_chroma_subsampling - get the vertical chroma subsampling factor
  * @format: pixel format (DRM_FORMAT_*)
  *
- * RETURNS:
+ * Returns:
  * The vertical chroma subsampling factor for the
  * specified pixel format.
  */
@@ -4030,6 +4611,7 @@ void drm_mode_config_init(struct drm_device *dev)
 
        drm_modeset_lock_all(dev);
        drm_mode_create_standard_connector_properties(dev);
+       drm_mode_create_standard_plane_properties(dev);
        drm_modeset_unlock_all(dev);
 
        /* Just to be sure */
@@ -4037,6 +4619,8 @@ void drm_mode_config_init(struct drm_device *dev)
        dev->mode_config.num_connector = 0;
        dev->mode_config.num_crtc = 0;
        dev->mode_config.num_encoder = 0;
+       dev->mode_config.num_overlay_plane = 0;
+       dev->mode_config.num_total_plane = 0;
 }
 EXPORT_SYMBOL(drm_mode_config_init);
 
index f7a8120..c43825e 100644 (file)
@@ -105,9 +105,6 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
  * @maxX: max width for modes
  * @maxY: max height for modes
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
  * Based on the helper callbacks implemented by @connector try to detect all
  * valid modes.  Modes will first be added to the connector's probed_modes list,
  * then culled (based on validity and the @maxX, @maxY parameters) and put into
@@ -117,8 +114,8 @@ static void drm_mode_validate_flag(struct drm_connector *connector,
  * @connector vfunc for drivers that use the crtc helpers for output mode
  * filtering and detection.
  *
- * RETURNS:
- * Number of modes found on @connector.
+ * Returns:
+ * The number of modes found on @connector.
  */
 int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
                                            uint32_t maxX, uint32_t maxY)
@@ -131,6 +128,8 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
        int mode_flags = 0;
        bool verbose_prune = true;
 
+       WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
+
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n", connector->base.id,
                        drm_get_connector_name(connector));
        /* set all modes to the unverified state */
@@ -176,8 +175,7 @@ int drm_helper_probe_single_connector_modes(struct drm_connector *connector,
        drm_mode_connector_list_update(connector);
 
        if (maxX && maxY)
-               drm_mode_validate_size(dev, &connector->modes, maxX,
-                                      maxY, 0);
+               drm_mode_validate_size(dev, &connector->modes, maxX, maxY);
 
        if (connector->interlace_allowed)
                mode_flags |= DRM_MODE_FLAG_INTERLACE;
@@ -219,18 +217,19 @@ EXPORT_SYMBOL(drm_helper_probe_single_connector_modes);
  * drm_helper_encoder_in_use - check if a given encoder is in use
  * @encoder: encoder to check
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
- * Walk @encoders's DRM device's mode_config and see if it's in use.
+ * Checks whether @encoder is with the current mode setting output configuration
+ * in use by any connector. This doesn't mean that it is actually enabled since
+ * the DPMS state is tracked separately.
  *
- * RETURNS:
- * True if @encoder is part of the mode_config, false otherwise.
+ * Returns:
+ * True if @encoder is used, false otherwise.
  */
 bool drm_helper_encoder_in_use(struct drm_encoder *encoder)
 {
        struct drm_connector *connector;
        struct drm_device *dev = encoder->dev;
+
+       WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
        list_for_each_entry(connector, &dev->mode_config.connector_list, head)
                if (connector->encoder == encoder)
                        return true;
@@ -242,19 +241,19 @@ EXPORT_SYMBOL(drm_helper_encoder_in_use);
  * drm_helper_crtc_in_use - check if a given CRTC is in a mode_config
  * @crtc: CRTC to check
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
- * Walk @crtc's DRM device's mode_config and see if it's in use.
+ * Checks whether @crtc is with the current mode setting output configuration
+ * in use by any connector. This doesn't mean that it is actually enabled since
+ * the DPMS state is tracked separately.
  *
- * RETURNS:
- * True if @crtc is part of the mode_config, false otherwise.
+ * Returns:
+ * True if @crtc is used, false otherwise.
  */
 bool drm_helper_crtc_in_use(struct drm_crtc *crtc)
 {
        struct drm_encoder *encoder;
        struct drm_device *dev = crtc->dev;
-       /* FIXME: Locking around list access? */
+
+       WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
                if (encoder->crtc == crtc && drm_helper_encoder_in_use(encoder))
                        return true;
@@ -279,27 +278,17 @@ drm_encoder_disable(struct drm_encoder *encoder)
                encoder->bridge->funcs->post_disable(encoder->bridge);
 }
 
-/**
- * drm_helper_disable_unused_functions - disable unused objects
- * @dev: DRM device
- *
- * LOCKING:
- * Caller must hold mode config lock.
- *
- * If an connector or CRTC isn't part of @dev's mode_config, it can be disabled
- * by calling its dpms function, which should power it off.
- */
-void drm_helper_disable_unused_functions(struct drm_device *dev)
+static void __drm_helper_disable_unused_functions(struct drm_device *dev)
 {
        struct drm_encoder *encoder;
        struct drm_connector *connector;
        struct drm_crtc *crtc;
 
+       drm_warn_on_modeset_not_all_locked(dev);
+
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                if (!connector->encoder)
                        continue;
-               if (connector->status == connector_status_disconnected)
-                       connector->encoder = NULL;
        }
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
@@ -318,10 +307,27 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
                                (*crtc_funcs->disable)(crtc);
                        else
                                (*crtc_funcs->dpms)(crtc, DRM_MODE_DPMS_OFF);
-                       crtc->fb = NULL;
+                       crtc->primary->fb = NULL;
                }
        }
 }
+
+/**
+ * drm_helper_disable_unused_functions - disable unused objects
+ * @dev: DRM device
+ *
+ * This function walks through the entire mode setting configuration of @dev. It
+ * will remove any crtc links of unused encoders and encoder links of
+ * disconnected connectors. Then it will disable all unused encoders and crtcs
+ * either by calling their disable callback if available or by calling their
+ * dpms callback with DRM_MODE_DPMS_OFF.
+ */
+void drm_helper_disable_unused_functions(struct drm_device *dev)
+{
+       drm_modeset_lock_all(dev);
+       __drm_helper_disable_unused_functions(dev);
+       drm_modeset_unlock_all(dev);
+}
 EXPORT_SYMBOL(drm_helper_disable_unused_functions);
 
 /*
@@ -355,9 +361,6 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
  * @y: vertical offset into the surface
  * @old_fb: old framebuffer, for cleanup
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
  * Try to set @mode on @crtc.  Give @crtc and its associated connectors a chance
  * to fixup or reject the mode prior to trying to set it. This is an internal
  * helper that drivers could e.g. use to update properties that require the
@@ -367,8 +370,8 @@ drm_crtc_prepare_encoders(struct drm_device *dev)
  * drm_crtc_helper_set_config() helper function to drive the mode setting
  * sequence.
  *
- * RETURNS:
- * True if the mode was set successfully, or false otherwise.
+ * Returns:
+ * True if the mode was set successfully, false otherwise.
  */
 bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                              struct drm_display_mode *mode,
@@ -384,6 +387,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        struct drm_encoder *encoder;
        bool ret = true;
 
+       drm_warn_on_modeset_not_all_locked(dev);
+
        saved_enabled = crtc->enabled;
        crtc->enabled = drm_helper_crtc_in_use(crtc);
        if (!crtc->enabled)
@@ -552,7 +557,7 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
                }
        }
 
-       drm_helper_disable_unused_functions(dev);
+       __drm_helper_disable_unused_functions(dev);
        return 0;
 }
 
@@ -560,17 +565,14 @@ drm_crtc_helper_disable(struct drm_crtc *crtc)
  * drm_crtc_helper_set_config - set a new config from userspace
  * @set: mode set configuration
  *
- * LOCKING:
- * Caller must hold mode config lock.
- *
  * Setup a new configuration, provided by the upper layers (either an ioctl call
  * from userspace or internally e.g. from the fbdev support code) in @set, and
  * enable it. This is the main helper functions for drivers that implement
  * kernel mode setting with the crtc helper functions and the assorted
  * ->prepare(), ->modeset() and ->commit() helper callbacks.
  *
- * RETURNS:
- * Returns 0 on success, -ERRNO on failure.
+ * Returns:
+ * Returns 0 on success, negative errno numbers on failure.
  */
 int drm_crtc_helper_set_config(struct drm_mode_set *set)
 {
@@ -612,6 +614,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 
        dev = set->crtc->dev;
 
+       drm_warn_on_modeset_not_all_locked(dev);
+
        /*
         * Allocate space for the backup of all (non-pointer) encoder and
         * connector data.
@@ -647,19 +651,19 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
        save_set.mode = &set->crtc->mode;
        save_set.x = set->crtc->x;
        save_set.y = set->crtc->y;
-       save_set.fb = set->crtc->fb;
+       save_set.fb = set->crtc->primary->fb;
 
        /* We should be able to check here if the fb has the same properties
         * and then just flip_or_move it */
-       if (set->crtc->fb != set->fb) {
+       if (set->crtc->primary->fb != set->fb) {
                /* If we have no fb then treat it as a full mode set */
-               if (set->crtc->fb == NULL) {
+               if (set->crtc->primary->fb == NULL) {
                        DRM_DEBUG_KMS("crtc has no fb, full mode set\n");
                        mode_changed = true;
                } else if (set->fb == NULL) {
                        mode_changed = true;
                } else if (set->fb->pixel_format !=
-                          set->crtc->fb->pixel_format) {
+                          set->crtc->primary->fb->pixel_format) {
                        mode_changed = true;
                } else
                        fb_changed = true;
@@ -689,12 +693,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                if (new_encoder == NULL)
                                        /* don't break so fail path works correct */
                                        fail = 1;
-                               break;
 
                                if (connector->dpms != DRM_MODE_DPMS_ON) {
                                        DRM_DEBUG_KMS("connector dpms not on, full mode switch\n");
                                        mode_changed = true;
                                }
+
+                               break;
                        }
                }
 
@@ -760,13 +765,13 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                        DRM_DEBUG_KMS("attempting to set mode from"
                                        " userspace\n");
                        drm_mode_debug_printmodeline(set->mode);
-                       set->crtc->fb = set->fb;
+                       set->crtc->primary->fb = set->fb;
                        if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
                                                      set->x, set->y,
                                                      save_set.fb)) {
                                DRM_ERROR("failed to set mode on [CRTC:%d]\n",
                                          set->crtc->base.id);
-                               set->crtc->fb = save_set.fb;
+                               set->crtc->primary->fb = save_set.fb;
                                ret = -EINVAL;
                                goto fail;
                        }
@@ -777,17 +782,17 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                                set->connectors[i]->funcs->dpms(set->connectors[i], DRM_MODE_DPMS_ON);
                        }
                }
-               drm_helper_disable_unused_functions(dev);
+               __drm_helper_disable_unused_functions(dev);
        } else if (fb_changed) {
                set->crtc->x = set->x;
                set->crtc->y = set->y;
-               set->crtc->fb = set->fb;
+               set->crtc->primary->fb = set->fb;
                ret = crtc_funcs->mode_set_base(set->crtc,
                                                set->x, set->y, save_set.fb);
                if (ret != 0) {
                        set->crtc->x = save_set.x;
                        set->crtc->y = save_set.y;
-                       set->crtc->fb = save_set.fb;
+                       set->crtc->primary->fb = save_set.fb;
                        goto fail;
                }
        }
@@ -924,8 +929,16 @@ void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
 }
 EXPORT_SYMBOL(drm_helper_connector_dpms);
 
-int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
-                                  struct drm_mode_fb_cmd2 *mode_cmd)
+/**
+ * drm_helper_mode_fill_fb_struct - fill out framebuffer metadata
+ * @fb: drm_framebuffer object to fill out
+ * @mode_cmd: metadata from the userspace fb creation request
+ *
+ * This helper can be used in a drivers fb_create callback to pre-fill the fb's
+ * metadata fields.
+ */
+void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
+                                   struct drm_mode_fb_cmd2 *mode_cmd)
 {
        int i;
 
@@ -938,26 +951,47 @@ int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
        drm_fb_get_bpp_depth(mode_cmd->pixel_format, &fb->depth,
                                    &fb->bits_per_pixel);
        fb->pixel_format = mode_cmd->pixel_format;
-
-       return 0;
 }
 EXPORT_SYMBOL(drm_helper_mode_fill_fb_struct);
 
-int drm_helper_resume_force_mode(struct drm_device *dev)
+/**
+ * drm_helper_resume_force_mode - force-restore mode setting configuration
+ * @dev: drm_device which should be restored
+ *
+ * Drivers which use the mode setting helpers can use this function to
+ * force-restore the mode setting configuration e.g. on resume or when something
+ * else might have trampled over the hw state (like some overzealous old BIOSen
+ * tended to do).
+ *
+ * This helper doesn't provide a error return value since restoring the old
+ * config should never fail due to resource allocation issues since the driver
+ * has successfully set the restored configuration already. Hence this should
+ * boil down to the equivalent of a few dpms on calls, which also don't provide
+ * an error code.
+ *
+ * Drivers where simply restoring an old configuration again might fail (e.g.
+ * due to slight differences in allocating shared resources when the
+ * configuration is restored in a different order than when userspace set it up)
+ * need to use their own restore logic.
+ */
+void drm_helper_resume_force_mode(struct drm_device *dev)
 {
        struct drm_crtc *crtc;
        struct drm_encoder *encoder;
        struct drm_crtc_helper_funcs *crtc_funcs;
-       int ret, encoder_dpms;
+       int encoder_dpms;
+       bool ret;
 
+       drm_modeset_lock_all(dev);
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
 
                if (!crtc->enabled)
                        continue;
 
                ret = drm_crtc_helper_set_mode(crtc, &crtc->mode,
-                                              crtc->x, crtc->y, crtc->fb);
+                                              crtc->x, crtc->y, crtc->primary->fb);
 
+               /* Restoring the old config should never fail! */
                if (ret == false)
                        DRM_ERROR("failed to set mode on crtc %p\n", crtc);
 
@@ -980,12 +1014,29 @@ int drm_helper_resume_force_mode(struct drm_device *dev)
                                                     drm_helper_choose_crtc_dpms(crtc));
                }
        }
+
        /* disable the unused connectors while restoring the modesetting */
-       drm_helper_disable_unused_functions(dev);
-       return 0;
+       __drm_helper_disable_unused_functions(dev);
+       drm_modeset_unlock_all(dev);
 }
 EXPORT_SYMBOL(drm_helper_resume_force_mode);
 
+/**
+ * drm_kms_helper_hotplug_event - fire off KMS hotplug events
+ * @dev: drm_device whose connector state changed
+ *
+ * This function fires off the uevent for userspace and also calls the
+ * output_poll_changed function, which is most commonly used to inform the fbdev
+ * emulation code and allow it to update the fbcon output configuration.
+ *
+ * Drivers should call this from their hotplug handling code when a change is
+ * detected. Note that this function does not do any output detection of its
+ * own, like drm_helper_hpd_irq_event() does - this is assumed to be done by the
+ * driver already.
+ *
+ * This function must be called from process context with no mode
+ * setting locks held.
+ */
 void drm_kms_helper_hotplug_event(struct drm_device *dev)
 {
        /* send a uevent + call fbdev */
@@ -1054,6 +1105,16 @@ static void output_poll_execute(struct work_struct *work)
                schedule_delayed_work(delayed_work, DRM_OUTPUT_POLL_PERIOD);
 }
 
+/**
+ * drm_kms_helper_poll_disable - disable output polling
+ * @dev: drm_device
+ *
+ * This function disables the output polling work.
+ *
+ * Drivers can call this helper from their device suspend implementation. It is
+ * not an error to call this even when output polling isn't enabled or arlready
+ * disabled.
+ */
 void drm_kms_helper_poll_disable(struct drm_device *dev)
 {
        if (!dev->mode_config.poll_enabled)
@@ -1062,6 +1123,16 @@ void drm_kms_helper_poll_disable(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_kms_helper_poll_disable);
 
+/**
+ * drm_kms_helper_poll_enable - re-enable output polling.
+ * @dev: drm_device
+ *
+ * This function re-enables the output polling work.
+ *
+ * Drivers can call this helper from their device resume implementation. It is
+ * an error to call this when the output polling support has not yet been set
+ * up.
+ */
 void drm_kms_helper_poll_enable(struct drm_device *dev)
 {
        bool poll = false;
@@ -1081,6 +1152,25 @@ void drm_kms_helper_poll_enable(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_kms_helper_poll_enable);
 
+/**
+ * drm_kms_helper_poll_init - initialize and enable output polling
+ * @dev: drm_device
+ *
+ * This function intializes and then also enables output polling support for
+ * @dev. Drivers which do not have reliable hotplug support in hardware can use
+ * this helper infrastructure to regularly poll such connectors for changes in
+ * their connection state.
+ *
+ * Drivers can control which connectors are polled by setting the
+ * DRM_CONNECTOR_POLL_CONNECT and DRM_CONNECTOR_POLL_DISCONNECT flags. On
+ * connectors where probing live outputs can result in visual distortion drivers
+ * should not set the DRM_CONNECTOR_POLL_DISCONNECT flag to avoid this.
+ * Connectors which have no flag or only DRM_CONNECTOR_POLL_HPD set are
+ * completely ignored by the polling logic.
+ *
+ * Note that a connector can be both polled and probed from the hotplug handler,
+ * in case the hotplug interrupt is known to be unreliable.
+ */
 void drm_kms_helper_poll_init(struct drm_device *dev)
 {
        INIT_DELAYED_WORK(&dev->mode_config.output_poll_work, output_poll_execute);
@@ -1090,12 +1180,39 @@ void drm_kms_helper_poll_init(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_kms_helper_poll_init);
 
+/**
+ * drm_kms_helper_poll_fini - disable output polling and clean it up
+ * @dev: drm_device
+ */
 void drm_kms_helper_poll_fini(struct drm_device *dev)
 {
        drm_kms_helper_poll_disable(dev);
 }
 EXPORT_SYMBOL(drm_kms_helper_poll_fini);
 
+/**
+ * drm_helper_hpd_irq_event - hotplug processing
+ * @dev: drm_device
+ *
+ * Drivers can use this helper function to run a detect cycle on all connectors
+ * which have the DRM_CONNECTOR_POLL_HPD flag set in their &polled member. All
+ * other connectors are ignored, which is useful to avoid reprobing fixed
+ * panels.
+ *
+ * This helper function is useful for drivers which can't or don't track hotplug
+ * interrupts for each connector.
+ *
+ * Drivers which support hotplug interrupts for each connector individually and
+ * which have a more fine-grained detect logic should bypass this code and
+ * directly call drm_kms_helper_hotplug_event() in case the connector state
+ * changed.
+ *
+ * This function must be called from process context with no mode
+ * setting locks held.
+ *
+ * Note that a connector can be both polled and probed from the hotplug handler,
+ * in case the hotplug interrupt is known to be unreliable.
+ */
 bool drm_helper_hpd_irq_event(struct drm_device *dev)
 {
        struct drm_connector *connector;
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
new file mode 100644 (file)
index 0000000..a2945ee
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2006 Keith Packard
+ * Copyright © 2007-2008 Dave Airlie
+ * Copyright © 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ * Copyright © 2014 Intel Corporation
+ *   Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ * 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.
+ */
+
+/*
+ * This header file contains mode setting related functions and definitions
+ * which are only used within the drm module as internal implementation details
+ * and are not exported to drivers.
+ */
+
+int drm_mode_object_get(struct drm_device *dev,
+                       struct drm_mode_object *obj, uint32_t obj_type);
+void drm_mode_object_put(struct drm_device *dev,
+                        struct drm_mode_object *object);
+
index 9e978aa..2767148 100644 (file)
@@ -346,3 +346,399 @@ int drm_dp_bw_code_to_link_rate(u8 link_bw)
        }
 }
 EXPORT_SYMBOL(drm_dp_bw_code_to_link_rate);
+
+/**
+ * DOC: dp helpers
+ *
+ * The DisplayPort AUX channel is an abstraction to allow generic, driver-
+ * independent access to AUX functionality. Drivers can take advantage of
+ * this by filling in the fields of the drm_dp_aux structure.
+ *
+ * Transactions are described using a hardware-independent drm_dp_aux_msg
+ * structure, which is passed into a driver's .transfer() implementation.
+ * Both native and I2C-over-AUX transactions are supported.
+ */
+
+static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
+                             unsigned int offset, void *buffer, size_t size)
+{
+       struct drm_dp_aux_msg msg;
+       unsigned int retry;
+       int err;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.address = offset;
+       msg.request = request;
+       msg.buffer = buffer;
+       msg.size = size;
+
+       /*
+        * The specification doesn't give any recommendation on how often to
+        * retry native transactions, so retry 7 times like for I2C-over-AUX
+        * transactions.
+        */
+       for (retry = 0; retry < 7; retry++) {
+               err = aux->transfer(aux, &msg);
+               if (err < 0) {
+                       if (err == -EBUSY)
+                               continue;
+
+                       return err;
+               }
+
+
+               switch (msg.reply & DP_AUX_NATIVE_REPLY_MASK) {
+               case DP_AUX_NATIVE_REPLY_ACK:
+                       if (err < size)
+                               return -EPROTO;
+                       return err;
+
+               case DP_AUX_NATIVE_REPLY_NACK:
+                       return -EIO;
+
+               case DP_AUX_NATIVE_REPLY_DEFER:
+                       usleep_range(400, 500);
+                       break;
+               }
+       }
+
+       DRM_DEBUG_KMS("too many retries, giving up\n");
+       return -EIO;
+}
+
+/**
+ * drm_dp_dpcd_read() - read a series of bytes from the DPCD
+ * @aux: DisplayPort AUX channel
+ * @offset: address of the (first) register to read
+ * @buffer: buffer to store the register values
+ * @size: number of bytes in @buffer
+ *
+ * Returns the number of bytes transferred on success, or a negative error
+ * code on failure. -EIO is returned if the request was NAKed by the sink or
+ * if the retry count was exceeded. If not all bytes were transferred, this
+ * function returns -EPROTO. Errors from the underlying AUX channel transfer
+ * function, with the exception of -EBUSY (which causes the transaction to
+ * be retried), are propagated to the caller.
+ */
+ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
+                        void *buffer, size_t size)
+{
+       return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer,
+                                 size);
+}
+EXPORT_SYMBOL(drm_dp_dpcd_read);
+
+/**
+ * drm_dp_dpcd_write() - write a series of bytes to the DPCD
+ * @aux: DisplayPort AUX channel
+ * @offset: address of the (first) register to write
+ * @buffer: buffer containing the values to write
+ * @size: number of bytes in @buffer
+ *
+ * Returns the number of bytes transferred on success, or a negative error
+ * code on failure. -EIO is returned if the request was NAKed by the sink or
+ * if the retry count was exceeded. If not all bytes were transferred, this
+ * function returns -EPROTO. Errors from the underlying AUX channel transfer
+ * function, with the exception of -EBUSY (which causes the transaction to
+ * be retried), are propagated to the caller.
+ */
+ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
+                         void *buffer, size_t size)
+{
+       return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_WRITE, offset, buffer,
+                                 size);
+}
+EXPORT_SYMBOL(drm_dp_dpcd_write);
+
+/**
+ * drm_dp_dpcd_read_link_status() - read DPCD link status (bytes 0x202-0x207)
+ * @aux: DisplayPort AUX channel
+ * @status: buffer to store the link status in (must be at least 6 bytes)
+ *
+ * Returns the number of bytes transferred on success or a negative error
+ * code on failure.
+ */
+int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
+                                u8 status[DP_LINK_STATUS_SIZE])
+{
+       return drm_dp_dpcd_read(aux, DP_LANE0_1_STATUS, status,
+                               DP_LINK_STATUS_SIZE);
+}
+EXPORT_SYMBOL(drm_dp_dpcd_read_link_status);
+
+/**
+ * drm_dp_link_probe() - probe a DisplayPort link for capabilities
+ * @aux: DisplayPort AUX channel
+ * @link: pointer to structure in which to return link capabilities
+ *
+ * The structure filled in by this function can usually be passed directly
+ * into drm_dp_link_power_up() and drm_dp_link_configure() to power up and
+ * configure the link based on the link's capabilities.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link)
+{
+       u8 values[3];
+       int err;
+
+       memset(link, 0, sizeof(*link));
+
+       err = drm_dp_dpcd_read(aux, DP_DPCD_REV, values, sizeof(values));
+       if (err < 0)
+               return err;
+
+       link->revision = values[0];
+       link->rate = drm_dp_bw_code_to_link_rate(values[1]);
+       link->num_lanes = values[2] & DP_MAX_LANE_COUNT_MASK;
+
+       if (values[2] & DP_ENHANCED_FRAME_CAP)
+               link->capabilities |= DP_LINK_CAP_ENHANCED_FRAMING;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_dp_link_probe);
+
+/**
+ * drm_dp_link_power_up() - power up a DisplayPort link
+ * @aux: DisplayPort AUX channel
+ * @link: pointer to a structure containing the link configuration
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
+{
+       u8 value;
+       int err;
+
+       /* DP_SET_POWER register is only available on DPCD v1.1 and later */
+       if (link->revision < 0x11)
+               return 0;
+
+       err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
+       if (err < 0)
+               return err;
+
+       value &= ~DP_SET_POWER_MASK;
+       value |= DP_SET_POWER_D0;
+
+       err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
+       if (err < 0)
+               return err;
+
+       /*
+        * According to the DP 1.1 specification, a "Sink Device must exit the
+        * power saving state within 1 ms" (Section 2.5.3.1, Table 5-52, "Sink
+        * Control Field" (register 0x600).
+        */
+       usleep_range(1000, 2000);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_dp_link_power_up);
+
+/**
+ * drm_dp_link_configure() - configure a DisplayPort link
+ * @aux: DisplayPort AUX channel
+ * @link: pointer to a structure containing the link configuration
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link)
+{
+       u8 values[2];
+       int err;
+
+       values[0] = drm_dp_link_rate_to_bw_code(link->rate);
+       values[1] = link->num_lanes;
+
+       if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
+               values[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
+
+       err = drm_dp_dpcd_write(aux, DP_LINK_BW_SET, values, sizeof(values));
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_dp_link_configure);
+
+/*
+ * I2C-over-AUX implementation
+ */
+
+static u32 drm_dp_i2c_functionality(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL |
+              I2C_FUNC_SMBUS_READ_BLOCK_DATA |
+              I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+              I2C_FUNC_10BIT_ADDR;
+}
+
+/*
+ * Transfer a single I2C-over-AUX message and handle various error conditions,
+ * retrying the transaction as appropriate.
+ */
+static int drm_dp_i2c_do_msg(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+       unsigned int retry;
+       int err;
+
+       /*
+        * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device
+        * is required to retry at least seven times upon receiving AUX_DEFER
+        * before giving up the AUX transaction.
+        */
+       for (retry = 0; retry < 7; retry++) {
+               err = aux->transfer(aux, msg);
+               if (err < 0) {
+                       if (err == -EBUSY)
+                               continue;
+
+                       DRM_DEBUG_KMS("transaction failed: %d\n", err);
+                       return err;
+               }
+
+
+               switch (msg->reply & DP_AUX_NATIVE_REPLY_MASK) {
+               case DP_AUX_NATIVE_REPLY_ACK:
+                       /*
+                        * For I2C-over-AUX transactions this isn't enough, we
+                        * need to check for the I2C ACK reply.
+                        */
+                       break;
+
+               case DP_AUX_NATIVE_REPLY_NACK:
+                       DRM_DEBUG_KMS("native nack\n");
+                       return -EREMOTEIO;
+
+               case DP_AUX_NATIVE_REPLY_DEFER:
+                       DRM_DEBUG_KMS("native defer");
+                       /*
+                        * We could check for I2C bit rate capabilities and if
+                        * available adjust this interval. We could also be
+                        * more careful with DP-to-legacy adapters where a
+                        * long legacy cable may force very low I2C bit rates.
+                        *
+                        * For now just defer for long enough to hopefully be
+                        * safe for all use-cases.
+                        */
+                       usleep_range(500, 600);
+                       continue;
+
+               default:
+                       DRM_ERROR("invalid native reply %#04x\n", msg->reply);
+                       return -EREMOTEIO;
+               }
+
+               switch (msg->reply & DP_AUX_I2C_REPLY_MASK) {
+               case DP_AUX_I2C_REPLY_ACK:
+                       /*
+                        * Both native ACK and I2C ACK replies received. We
+                        * can assume the transfer was successful.
+                        */
+                       if (err < msg->size)
+                               return -EPROTO;
+                       return 0;
+
+               case DP_AUX_I2C_REPLY_NACK:
+                       DRM_DEBUG_KMS("I2C nack\n");
+                       return -EREMOTEIO;
+
+               case DP_AUX_I2C_REPLY_DEFER:
+                       DRM_DEBUG_KMS("I2C defer\n");
+                       usleep_range(400, 500);
+                       continue;
+
+               default:
+                       DRM_ERROR("invalid I2C reply %#04x\n", msg->reply);
+                       return -EREMOTEIO;
+               }
+       }
+
+       DRM_DEBUG_KMS("too many retries, giving up\n");
+       return -EREMOTEIO;
+}
+
+static int drm_dp_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs,
+                          int num)
+{
+       struct drm_dp_aux *aux = adapter->algo_data;
+       unsigned int i, j;
+
+       for (i = 0; i < num; i++) {
+               struct drm_dp_aux_msg msg;
+               int err;
+
+               /*
+                * Many hardware implementations support FIFOs larger than a
+                * single byte, but it has been empirically determined that
+                * transferring data in larger chunks can actually lead to
+                * decreased performance. Therefore each message is simply
+                * transferred byte-by-byte.
+                */
+               for (j = 0; j < msgs[i].len; j++) {
+                       memset(&msg, 0, sizeof(msg));
+                       msg.address = msgs[i].addr;
+
+                       msg.request = (msgs[i].flags & I2C_M_RD) ?
+                                       DP_AUX_I2C_READ :
+                                       DP_AUX_I2C_WRITE;
+
+                       /*
+                        * All messages except the last one are middle-of-
+                        * transfer messages.
+                        */
+                       if ((i < num - 1) || (j < msgs[i].len - 1))
+                               msg.request |= DP_AUX_I2C_MOT;
+
+                       msg.buffer = msgs[i].buf + j;
+                       msg.size = 1;
+
+                       err = drm_dp_i2c_do_msg(aux, &msg);
+                       if (err < 0)
+                               return err;
+               }
+       }
+
+       return num;
+}
+
+static const struct i2c_algorithm drm_dp_i2c_algo = {
+       .functionality = drm_dp_i2c_functionality,
+       .master_xfer = drm_dp_i2c_xfer,
+};
+
+/**
+ * drm_dp_aux_register_i2c_bus() - register an I2C adapter for I2C-over-AUX
+ * @aux: DisplayPort AUX channel
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux)
+{
+       aux->ddc.algo = &drm_dp_i2c_algo;
+       aux->ddc.algo_data = aux;
+       aux->ddc.retries = 3;
+
+       aux->ddc.class = I2C_CLASS_DDC;
+       aux->ddc.owner = THIS_MODULE;
+       aux->ddc.dev.parent = aux->dev;
+       aux->ddc.dev.of_node = aux->dev->of_node;
+
+       strlcpy(aux->ddc.name, aux->name ? aux->name : dev_name(aux->dev),
+               sizeof(aux->ddc.name));
+
+       return i2c_add_adapter(&aux->ddc);
+}
+EXPORT_SYMBOL(drm_dp_aux_register_i2c_bus);
+
+/**
+ * drm_dp_aux_unregister_i2c_bus() - unregister an I2C-over-AUX adapter
+ * @aux: DisplayPort AUX channel
+ */
+void drm_dp_aux_unregister_i2c_bus(struct drm_dp_aux *aux)
+{
+       i2c_del_adapter(&aux->ddc);
+}
+EXPORT_SYMBOL(drm_dp_aux_unregister_i2c_bus);
index 345be03..03711d0 100644 (file)
@@ -285,6 +285,45 @@ static int drm_version(struct drm_device *dev, void *data,
        return err;
 }
 
+/**
+ * drm_ioctl_permit - Check ioctl permissions against caller
+ *
+ * @flags: ioctl permission flags.
+ * @file_priv: Pointer to struct drm_file identifying the caller.
+ *
+ * Checks whether the caller is allowed to run an ioctl with the
+ * indicated permissions. If so, returns zero. Otherwise returns an
+ * error code suitable for ioctl return.
+ */
+static int drm_ioctl_permit(u32 flags, struct drm_file *file_priv)
+{
+       /* ROOT_ONLY is only for CAP_SYS_ADMIN */
+       if (unlikely((flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)))
+               return -EACCES;
+
+       /* AUTH is only for authenticated or render client */
+       if (unlikely((flags & DRM_AUTH) && !drm_is_render_client(file_priv) &&
+                    !file_priv->authenticated))
+               return -EACCES;
+
+       /* MASTER is only for master or control clients */
+       if (unlikely((flags & DRM_MASTER) && !file_priv->is_master &&
+                    !drm_is_control_client(file_priv)))
+               return -EACCES;
+
+       /* Control clients must be explicitly allowed */
+       if (unlikely(!(flags & DRM_CONTROL_ALLOW) &&
+                    drm_is_control_client(file_priv)))
+               return -EACCES;
+
+       /* Render clients must be explicitly allowed */
+       if (unlikely(!(flags & DRM_RENDER_ALLOW) &&
+                    drm_is_render_client(file_priv)))
+               return -EACCES;
+
+       return 0;
+}
+
 /**
  * Called whenever a process performs an ioctl on /dev/drm.
  *
@@ -344,65 +383,64 @@ long drm_ioctl(struct file *filp,
 
        DRM_DEBUG("pid=%d, dev=0x%lx, auth=%d, %s\n",
                  task_pid_nr(current),
-                 (long)old_encode_dev(file_priv->minor->device),
+                 (long)old_encode_dev(file_priv->minor->kdev->devt),
                  file_priv->authenticated, ioctl->name);
 
        /* Do not trust userspace, use our own definition */
        func = ioctl->func;
 
-       if (!func) {
+       if (unlikely(!func)) {
                DRM_DEBUG("no function\n");
                retcode = -EINVAL;
-       } else if (((ioctl->flags & DRM_ROOT_ONLY) && !capable(CAP_SYS_ADMIN)) ||
-                  ((ioctl->flags & DRM_AUTH) && !drm_is_render_client(file_priv) && !file_priv->authenticated) ||
-                  ((ioctl->flags & DRM_MASTER) && !file_priv->is_master) ||
-                  (!(ioctl->flags & DRM_CONTROL_ALLOW) && (file_priv->minor->type == DRM_MINOR_CONTROL)) ||
-                  (!(ioctl->flags & DRM_RENDER_ALLOW) && drm_is_render_client(file_priv))) {
-               retcode = -EACCES;
-       } else {
-               if (cmd & (IOC_IN | IOC_OUT)) {
-                       if (asize <= sizeof(stack_kdata)) {
-                               kdata = stack_kdata;
-                       } else {
-                               kdata = kmalloc(asize, GFP_KERNEL);
-                               if (!kdata) {
-                                       retcode = -ENOMEM;
-                                       goto err_i1;
-                               }
-                       }
-                       if (asize > usize)
-                               memset(kdata + usize, 0, asize - usize);
-               }
+               goto err_i1;
+       }
 
-               if (cmd & IOC_IN) {
-                       if (copy_from_user(kdata, (void __user *)arg,
-                                          usize) != 0) {
-                               retcode = -EFAULT;
+       retcode = drm_ioctl_permit(ioctl->flags, file_priv);
+       if (unlikely(retcode))
+               goto err_i1;
+
+       if (cmd & (IOC_IN | IOC_OUT)) {
+               if (asize <= sizeof(stack_kdata)) {
+                       kdata = stack_kdata;
+               } else {
+                       kdata = kmalloc(asize, GFP_KERNEL);
+                       if (!kdata) {
+                               retcode = -ENOMEM;
                                goto err_i1;
                        }
-               } else
-                       memset(kdata, 0, usize);
-
-               if (ioctl->flags & DRM_UNLOCKED)
-                       retcode = func(dev, kdata, file_priv);
-               else {
-                       mutex_lock(&drm_global_mutex);
-                       retcode = func(dev, kdata, file_priv);
-                       mutex_unlock(&drm_global_mutex);
                }
+               if (asize > usize)
+                       memset(kdata + usize, 0, asize - usize);
+       }
 
-               if (cmd & IOC_OUT) {
-                       if (copy_to_user((void __user *)arg, kdata,
-                                        usize) != 0)
-                               retcode = -EFAULT;
+       if (cmd & IOC_IN) {
+               if (copy_from_user(kdata, (void __user *)arg,
+                                  usize) != 0) {
+                       retcode = -EFAULT;
+                       goto err_i1;
                }
+       } else
+               memset(kdata, 0, usize);
+
+       if (ioctl->flags & DRM_UNLOCKED)
+               retcode = func(dev, kdata, file_priv);
+       else {
+               mutex_lock(&drm_global_mutex);
+               retcode = func(dev, kdata, file_priv);
+               mutex_unlock(&drm_global_mutex);
+       }
+
+       if (cmd & IOC_OUT) {
+               if (copy_to_user((void __user *)arg, kdata,
+                                usize) != 0)
+                       retcode = -EFAULT;
        }
 
       err_i1:
        if (!ioctl)
                DRM_DEBUG("invalid ioctl: pid=%d, dev=0x%lx, auth=%d, cmd=0x%02x, nr=0x%02x\n",
                          task_pid_nr(current),
-                         (long)old_encode_dev(file_priv->minor->device),
+                         (long)old_encode_dev(file_priv->minor->kdev->devt),
                          file_priv->authenticated, cmd, nr);
 
        if (kdata != stack_kdata)
@@ -412,3 +450,21 @@ long drm_ioctl(struct file *filp,
        return retcode;
 }
 EXPORT_SYMBOL(drm_ioctl);
+
+/**
+ * drm_ioctl_flags - Check for core ioctl and return ioctl permission flags
+ *
+ * @nr: Ioctl number.
+ * @flags: Where to return the ioctl permission flags
+ */
+bool drm_ioctl_flags(unsigned int nr, unsigned int *flags)
+{
+       if ((nr >= DRM_COMMAND_END && nr < DRM_CORE_IOCTL_COUNT) ||
+           (nr < DRM_COMMAND_BASE)) {
+               *flags = drm_ioctls[nr].flags;
+               return true;
+       }
+
+       return false;
+}
+EXPORT_SYMBOL(drm_ioctl_flags);
index b924306..d4e3f9d 100644 (file)
@@ -1098,10 +1098,14 @@ EXPORT_SYMBOL(drm_edid_is_valid);
 /**
  * Get EDID information via I2C.
  *
- * \param adapter : i2c device adaptor
- * \param buf     : EDID data buffer to be filled
- * \param len     : EDID data buffer length
- * \return 0 on success or -1 on failure.
+ * @adapter : i2c device adaptor
+ * @buf: EDID data buffer to be filled
+ * @block: 128 byte EDID block to start fetching from
+ * @len: EDID data buffer length to fetch
+ *
+ * Returns:
+ *
+ * 0 on success or -1 on failure.
  *
  * Try to fetch EDID information by calling i2c driver function.
  */
@@ -1243,9 +1247,11 @@ out:
 
 /**
  * Probe DDC presence.
+ * @adapter: i2c adapter to probe
+ *
+ * Returns:
  *
- * \param adapter : i2c device adaptor
- * \return 1 on success
+ * 1 on success
  */
 bool
 drm_probe_ddc(struct i2c_adapter *adapter)
@@ -1586,8 +1592,10 @@ bad_std_timing(u8 a, u8 b)
 
 /**
  * drm_mode_std - convert standard mode info (width, height, refresh) into mode
+ * @connector: connector of for the EDID block
+ * @edid: EDID block to scan
  * @t: standard timing params
- * @timing_level: standard timing level
+ * @revision: standard timing level
  *
  * Take the standard timing params (in this case width, aspect, and refresh)
  * and convert them into a real mode using CVT/GTF/DMT.
@@ -2132,6 +2140,7 @@ do_established_modes(struct detailed_timing *timing, void *c)
 
 /**
  * add_established_modes - get est. modes from EDID and add them
+ * @connector: connector of for the EDID block
  * @edid: EDID block to scan
  *
  * Each EDID block contains a bitmap of the supported "established modes" list
@@ -2194,6 +2203,7 @@ do_standard_modes(struct detailed_timing *timing, void *c)
 
 /**
  * add_standard_modes - get std. modes from EDID and add them
+ * @connector: connector of for the EDID block
  * @edid: EDID block to scan
  *
  * Standard modes can be calculated using the appropriate standard (DMT,
@@ -2580,6 +2590,9 @@ drm_display_mode_from_vic_index(struct drm_connector *connector,
                return NULL;
 
        newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]);
+       if (!newmode)
+               return NULL;
+
        newmode->vrefresh = 0;
 
        return newmode;
@@ -3300,6 +3313,7 @@ EXPORT_SYMBOL(drm_detect_hdmi_monitor);
 
 /**
  * drm_detect_monitor_audio - check monitor audio capability
+ * @edid: EDID block to scan
  *
  * Monitor should have CEA extension block.
  * If monitor has 'basic audio', but no CEA audio blocks, it's 'basic
@@ -3345,6 +3359,7 @@ EXPORT_SYMBOL(drm_detect_monitor_audio);
 
 /**
  * drm_rgb_quant_range_selectable - is RGB quantization range selectable?
+ * @edid: EDID block to scan
  *
  * Check whether the monitor reports the RGB quantization range selection
  * as supported. The AVI infoframe can then be used to inform the monitor
@@ -3564,8 +3579,8 @@ void drm_set_preferred_mode(struct drm_connector *connector,
        struct drm_display_mode *mode;
 
        list_for_each_entry(mode, &connector->probed_modes, head) {
-               if (drm_mode_width(mode)  == hpref &&
-                   drm_mode_height(mode) == vpref)
+               if (mode->hdisplay  == hpref &&
+                   mode->vdisplay == vpref)
                        mode->type |= DRM_MODE_TYPE_PREFERRED;
        }
 }
@@ -3599,6 +3614,7 @@ drm_hdmi_avi_infoframe_from_display_mode(struct hdmi_avi_infoframe *frame,
 
        frame->picture_aspect = HDMI_PICTURE_ASPECT_NONE;
        frame->active_aspect = HDMI_ACTIVE_ASPECT_PICTURE;
+       frame->scan_mode = HDMI_SCAN_MODE_UNDERSCAN;
 
        return 0;
 }
index 98a0363..04d3fd3 100644 (file)
@@ -232,7 +232,7 @@ static struct drm_framebuffer *drm_mode_config_fb(struct drm_crtc *crtc)
 
        list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
                if (crtc->base.id == c->base.id)
-                       return c->fb;
+                       return c->primary->fb;
        }
 
        return NULL;
@@ -291,7 +291,8 @@ bool drm_fb_helper_restore_fbdev_mode(struct drm_fb_helper *fb_helper)
        drm_warn_on_modeset_not_all_locked(dev);
 
        list_for_each_entry(plane, &dev->mode_config.plane_list, head)
-               drm_plane_force_disable(plane);
+               if (plane->type != DRM_PLANE_TYPE_PRIMARY)
+                       drm_plane_force_disable(plane);
 
        for (i = 0; i < fb_helper->crtc_count; i++) {
                struct drm_mode_set *mode_set = &fb_helper->crtc_info[i].mode_set;
@@ -365,9 +366,9 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
                return false;
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               if (crtc->fb)
+               if (crtc->primary->fb)
                        crtcs_bound++;
-               if (crtc->fb == fb_helper->fb)
+               if (crtc->primary->fb == fb_helper->fb)
                        bound++;
        }
 
@@ -516,6 +517,9 @@ int drm_fb_helper_init(struct drm_device *dev,
        struct drm_crtc *crtc;
        int i;
 
+       if (!max_conn_count)
+               return -EINVAL;
+
        fb_helper->dev = dev;
 
        INIT_LIST_HEAD(&fb_helper->kernel_fb_list);
@@ -809,8 +813,6 @@ int drm_fb_helper_set_par(struct fb_info *info)
        struct drm_fb_helper *fb_helper = info->par;
        struct drm_device *dev = fb_helper->dev;
        struct fb_var_screeninfo *var = &info->var;
-       int ret;
-       int i;
 
        if (var->pixclock != 0) {
                DRM_ERROR("PIXEL CLOCK SET\n");
@@ -818,13 +820,7 @@ int drm_fb_helper_set_par(struct fb_info *info)
        }
 
        drm_modeset_lock_all(dev);
-       for (i = 0; i < fb_helper->crtc_count; i++) {
-               ret = drm_mode_set_config_internal(&fb_helper->crtc_info[i].mode_set);
-               if (ret) {
-                       drm_modeset_unlock_all(dev);
-                       return ret;
-               }
-       }
+       drm_fb_helper_restore_fbdev_mode(fb_helper);
        drm_modeset_unlock_all(dev);
 
        if (fb_helper->delayed_hotplug) {
@@ -1136,19 +1132,20 @@ static int drm_fb_helper_probe_connector_modes(struct drm_fb_helper *fb_helper,
        return count;
 }
 
-static struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
+struct drm_display_mode *drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector, int width, int height)
 {
        struct drm_display_mode *mode;
 
        list_for_each_entry(mode, &fb_connector->connector->modes, head) {
-               if (drm_mode_width(mode) > width ||
-                   drm_mode_height(mode) > height)
+               if (mode->hdisplay > width ||
+                   mode->vdisplay > height)
                        continue;
                if (mode->type & DRM_MODE_TYPE_PREFERRED)
                        return mode;
        }
        return NULL;
 }
+EXPORT_SYMBOL(drm_has_preferred_mode);
 
 static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
 {
@@ -1157,11 +1154,12 @@ static bool drm_has_cmdline_mode(struct drm_fb_helper_connector *fb_connector)
        return cmdline_mode->specified;
 }
 
-static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
+struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
                                                      int width, int height)
 {
        struct drm_cmdline_mode *cmdline_mode;
        struct drm_display_mode *mode = NULL;
+       bool prefer_non_interlace;
 
        cmdline_mode = &fb_helper_conn->cmdline_mode;
        if (cmdline_mode->specified == false)
@@ -1173,6 +1171,8 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
        if (cmdline_mode->rb || cmdline_mode->margins)
                goto create_mode;
 
+       prefer_non_interlace = !cmdline_mode->interlace;
+ again:
        list_for_each_entry(mode, &fb_helper_conn->connector->modes, head) {
                /* check width/height */
                if (mode->hdisplay != cmdline_mode->xres ||
@@ -1187,16 +1187,25 @@ static struct drm_display_mode *drm_pick_cmdline_mode(struct drm_fb_helper_conne
                if (cmdline_mode->interlace) {
                        if (!(mode->flags & DRM_MODE_FLAG_INTERLACE))
                                continue;
+               } else if (prefer_non_interlace) {
+                       if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                               continue;
                }
                return mode;
        }
 
+       if (prefer_non_interlace) {
+               prefer_non_interlace = false;
+               goto again;
+       }
+
 create_mode:
        mode = drm_mode_create_from_cmdline_mode(fb_helper_conn->connector->dev,
                                                 cmdline_mode);
        list_add(&mode->head, &fb_helper_conn->connector->modes);
        return mode;
 }
+EXPORT_SYMBOL(drm_pick_cmdline_mode);
 
 static bool drm_connector_enabled(struct drm_connector *connector, bool strict)
 {
@@ -1539,9 +1548,11 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
 
        drm_fb_helper_parse_command_line(fb_helper);
 
+       mutex_lock(&dev->mode_config.mutex);
        count = drm_fb_helper_probe_connector_modes(fb_helper,
                                                    dev->mode_config.max_width,
                                                    dev->mode_config.max_height);
+       mutex_unlock(&dev->mode_config.mutex);
        /*
         * we shouldn't end up with no modes here.
         */
index 309023f..e1eba0b 100644 (file)
 #include <linux/slab.h>
 #include <linux/module.h>
 
-/* from BKL pushdown: note that nothing else serializes idr_find() */
+/* from BKL pushdown */
 DEFINE_MUTEX(drm_global_mutex);
 EXPORT_SYMBOL(drm_global_mutex);
 
 static int drm_open_helper(struct inode *inode, struct file *filp,
-                          struct drm_device * dev);
+                          struct drm_minor *minor);
 
 static int drm_setup(struct drm_device * dev)
 {
@@ -79,38 +79,23 @@ static int drm_setup(struct drm_device * dev)
  */
 int drm_open(struct inode *inode, struct file *filp)
 {
-       struct drm_device *dev = NULL;
-       int minor_id = iminor(inode);
+       struct drm_device *dev;
        struct drm_minor *minor;
-       int retcode = 0;
+       int retcode;
        int need_setup = 0;
-       struct address_space *old_mapping;
-       struct address_space *old_imapping;
-
-       minor = idr_find(&drm_minors_idr, minor_id);
-       if (!minor)
-               return -ENODEV;
 
-       if (!(dev = minor->dev))
-               return -ENODEV;
-
-       if (drm_device_is_unplugged(dev))
-               return -ENODEV;
+       minor = drm_minor_acquire(iminor(inode));
+       if (IS_ERR(minor))
+               return PTR_ERR(minor);
 
+       dev = minor->dev;
        if (!dev->open_count++)
                need_setup = 1;
-       mutex_lock(&dev->struct_mutex);
-       old_imapping = inode->i_mapping;
-       old_mapping = dev->dev_mapping;
-       if (old_mapping == NULL)
-               dev->dev_mapping = &inode->i_data;
-       /* ihold ensures nobody can remove inode with our i_data */
-       ihold(container_of(dev->dev_mapping, struct inode, i_data));
-       inode->i_mapping = dev->dev_mapping;
-       filp->f_mapping = dev->dev_mapping;
-       mutex_unlock(&dev->struct_mutex);
 
-       retcode = drm_open_helper(inode, filp, dev);
+       /* share address_space across all char-devs of a single device */
+       filp->f_mapping = dev->anon_inode->i_mapping;
+
+       retcode = drm_open_helper(inode, filp, minor);
        if (retcode)
                goto err_undo;
        if (need_setup) {
@@ -121,13 +106,8 @@ int drm_open(struct inode *inode, struct file *filp)
        return 0;
 
 err_undo:
-       mutex_lock(&dev->struct_mutex);
-       filp->f_mapping = old_imapping;
-       inode->i_mapping = old_imapping;
-       iput(container_of(dev->dev_mapping, struct inode, i_data));
-       dev->dev_mapping = old_mapping;
-       mutex_unlock(&dev->struct_mutex);
        dev->open_count--;
+       drm_minor_release(minor);
        return retcode;
 }
 EXPORT_SYMBOL(drm_open);
@@ -143,33 +123,30 @@ EXPORT_SYMBOL(drm_open);
  */
 int drm_stub_open(struct inode *inode, struct file *filp)
 {
-       struct drm_device *dev = NULL;
+       struct drm_device *dev;
        struct drm_minor *minor;
-       int minor_id = iminor(inode);
        int err = -ENODEV;
        const struct file_operations *new_fops;
 
        DRM_DEBUG("\n");
 
        mutex_lock(&drm_global_mutex);
-       minor = idr_find(&drm_minors_idr, minor_id);
-       if (!minor)
-               goto out;
-
-       if (!(dev = minor->dev))
-               goto out;
-
-       if (drm_device_is_unplugged(dev))
-               goto out;
+       minor = drm_minor_acquire(iminor(inode));
+       if (IS_ERR(minor))
+               goto out_unlock;
 
+       dev = minor->dev;
        new_fops = fops_get(dev->driver->fops);
        if (!new_fops)
-               goto out;
+               goto out_release;
 
        replace_fops(filp, new_fops);
        if (filp->f_op->open)
                err = filp->f_op->open(inode, filp);
-out:
+
+out_release:
+       drm_minor_release(minor);
+out_unlock:
        mutex_unlock(&drm_global_mutex);
        return err;
 }
@@ -196,16 +173,16 @@ static int drm_cpu_valid(void)
  *
  * \param inode device inode.
  * \param filp file pointer.
- * \param dev device.
+ * \param minor acquired minor-object.
  * \return zero on success or a negative number on failure.
  *
  * Creates and initializes a drm_file structure for the file private data in \p
  * filp and add it into the double linked list in \p dev.
  */
 static int drm_open_helper(struct inode *inode, struct file *filp,
-                          struct drm_device * dev)
+                          struct drm_minor *minor)
 {
-       int minor_id = iminor(inode);
+       struct drm_device *dev = minor->dev;
        struct drm_file *priv;
        int ret;
 
@@ -216,7 +193,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
        if (dev->switch_power_state != DRM_SWITCH_POWER_ON && dev->switch_power_state != DRM_SWITCH_POWER_DYNAMIC_OFF)
                return -EINVAL;
 
-       DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor_id);
+       DRM_DEBUG("pid = %d, minor = %d\n", task_pid_nr(current), minor->index);
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -226,11 +203,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
        priv->filp = filp;
        priv->uid = current_euid();
        priv->pid = get_pid(task_pid(current));
-       priv->minor = idr_find(&drm_minors_idr, minor_id);
-       if (!priv->minor) {
-               ret = -ENODEV;
-               goto out_put_pid;
-       }
+       priv->minor = minor;
 
        /* for compatibility root is always authenticated */
        priv->always_authenticated = capable(CAP_SYS_ADMIN);
@@ -258,12 +231,11 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
 
        /* if there is no current master make this fd it, but do not create
         * any master object for render clients */
-       mutex_lock(&dev->struct_mutex);
-       if (!priv->minor->master && !drm_is_render_client(priv)) {
+       mutex_lock(&dev->master_mutex);
+       if (drm_is_primary_client(priv) && !priv->minor->master) {
                /* create a new master */
                priv->minor->master = drm_master_create(priv->minor);
                if (!priv->minor->master) {
-                       mutex_unlock(&dev->struct_mutex);
                        ret = -ENOMEM;
                        goto out_close;
                }
@@ -271,37 +243,31 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                priv->is_master = 1;
                /* take another reference for the copy in the local file priv */
                priv->master = drm_master_get(priv->minor->master);
-
                priv->authenticated = 1;
 
-               mutex_unlock(&dev->struct_mutex);
                if (dev->driver->master_create) {
                        ret = dev->driver->master_create(dev, priv->master);
                        if (ret) {
-                               mutex_lock(&dev->struct_mutex);
                                /* drop both references if this fails */
                                drm_master_put(&priv->minor->master);
                                drm_master_put(&priv->master);
-                               mutex_unlock(&dev->struct_mutex);
                                goto out_close;
                        }
                }
-               mutex_lock(&dev->struct_mutex);
                if (dev->driver->master_set) {
                        ret = dev->driver->master_set(dev, priv, true);
                        if (ret) {
                                /* drop both references if this fails */
                                drm_master_put(&priv->minor->master);
                                drm_master_put(&priv->master);
-                               mutex_unlock(&dev->struct_mutex);
                                goto out_close;
                        }
                }
-       } else if (!drm_is_render_client(priv)) {
+       } else if (drm_is_primary_client(priv)) {
                /* get a reference to the master */
                priv->master = drm_master_get(priv->minor->master);
        }
-       mutex_unlock(&dev->struct_mutex);
+       mutex_unlock(&dev->master_mutex);
 
        mutex_lock(&dev->struct_mutex);
        list_add(&priv->lhead, &dev->filelist);
@@ -330,6 +296,7 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
        return 0;
 
 out_close:
+       mutex_unlock(&dev->master_mutex);
        if (dev->driver->postclose)
                dev->driver->postclose(dev, priv);
 out_prime_destroy:
@@ -337,7 +304,6 @@ out_prime_destroy:
                drm_prime_destroy_file_private(&priv->prime);
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_release(dev, priv);
-out_put_pid:
        put_pid(priv->pid);
        kfree(priv);
        filp->private_data = NULL;
@@ -435,7 +401,6 @@ int drm_lastclose(struct drm_device * dev)
 
        drm_legacy_dma_takedown(dev);
 
-       dev->dev_mapping = NULL;
        mutex_unlock(&dev->struct_mutex);
 
        drm_legacy_dev_reinit(dev);
@@ -459,7 +424,8 @@ int drm_lastclose(struct drm_device * dev)
 int drm_release(struct inode *inode, struct file *filp)
 {
        struct drm_file *file_priv = filp->private_data;
-       struct drm_device *dev = file_priv->minor->dev;
+       struct drm_minor *minor = file_priv->minor;
+       struct drm_device *dev = minor->dev;
        int retcode = 0;
 
        mutex_lock(&drm_global_mutex);
@@ -475,7 +441,7 @@ int drm_release(struct inode *inode, struct file *filp)
 
        DRM_DEBUG("pid = %d, device = 0x%lx, open_count = %d\n",
                  task_pid_nr(current),
-                 (long)old_encode_dev(file_priv->minor->device),
+                 (long)old_encode_dev(file_priv->minor->kdev->devt),
                  dev->open_count);
 
        /* Release any auth tokens that might point to this file_priv,
@@ -518,11 +484,13 @@ int drm_release(struct inode *inode, struct file *filp)
        }
        mutex_unlock(&dev->ctxlist_mutex);
 
-       mutex_lock(&dev->struct_mutex);
+       mutex_lock(&dev->master_mutex);
 
        if (file_priv->is_master) {
                struct drm_master *master = file_priv->master;
                struct drm_file *temp;
+
+               mutex_lock(&dev->struct_mutex);
                list_for_each_entry(temp, &dev->filelist, lhead) {
                        if ((temp->master == file_priv->master) &&
                            (temp != file_priv))
@@ -541,6 +509,7 @@ int drm_release(struct inode *inode, struct file *filp)
                        master->lock.file_priv = NULL;
                        wake_up_interruptible_all(&master->lock.lock_queue);
                }
+               mutex_unlock(&dev->struct_mutex);
 
                if (file_priv->minor->master == file_priv->master) {
                        /* drop the reference held my the minor */
@@ -550,13 +519,13 @@ int drm_release(struct inode *inode, struct file *filp)
                }
        }
 
-       BUG_ON(dev->dev_mapping == NULL);
-       iput(container_of(dev->dev_mapping, struct inode, i_data));
-
-       /* drop the reference held my the file priv */
+       /* drop the master reference held by the file priv */
        if (file_priv->master)
                drm_master_put(&file_priv->master);
        file_priv->is_master = 0;
+       mutex_unlock(&dev->master_mutex);
+
+       mutex_lock(&dev->struct_mutex);
        list_del(&file_priv->lhead);
        mutex_unlock(&dev->struct_mutex);
 
@@ -581,6 +550,8 @@ int drm_release(struct inode *inode, struct file *filp)
        }
        mutex_unlock(&drm_global_mutex);
 
+       drm_minor_release(minor);
+
        return retcode;
 }
 EXPORT_SYMBOL(drm_release);
index 5bbad87..9909bef 100644 (file)
@@ -85,9 +85,9 @@
 #endif
 
 /**
- * Initialize the GEM device fields
+ * drm_gem_init - Initialize the GEM device fields
+ * @dev: drm_devic structure to initialize
  */
-
 int
 drm_gem_init(struct drm_device *dev)
 {
@@ -120,6 +120,11 @@ drm_gem_destroy(struct drm_device *dev)
 }
 
 /**
+ * drm_gem_object_init - initialize an allocated shmem-backed GEM object
+ * @dev: drm_device the object should be initialized for
+ * @obj: drm_gem_object to initialize
+ * @size: object size
+ *
  * Initialize an already allocated GEM object of the specified size with
  * shmfs backing store.
  */
@@ -141,6 +146,11 @@ int drm_gem_object_init(struct drm_device *dev,
 EXPORT_SYMBOL(drm_gem_object_init);
 
 /**
+ * drm_gem_object_init - initialize an allocated private GEM object
+ * @dev: drm_device the object should be initialized for
+ * @obj: drm_gem_object to initialize
+ * @size: object size
+ *
  * Initialize an already allocated GEM object of the specified size with
  * no GEM provided backing store. Instead the caller is responsible for
  * backing the object and handling it.
@@ -176,6 +186,9 @@ drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
 }
 
 /**
+ * drm_gem_object_free - release resources bound to userspace handles
+ * @obj: GEM object to clean up.
+ *
  * Called after the last handle to the object has been closed
  *
  * Removes any name for the object. Note that this must be
@@ -225,7 +238,12 @@ drm_gem_object_handle_unreference_unlocked(struct drm_gem_object *obj)
 }
 
 /**
- * Removes the mapping from handle to filp for this object.
+ * drm_gem_handle_delete - deletes the given file-private handle
+ * @filp: drm file-private structure to use for the handle look up
+ * @handle: userspace handle to delete
+ *
+ * Removes the GEM handle from the @filp lookup table and if this is the last
+ * handle also cleans up linked resources like GEM names.
  */
 int
 drm_gem_handle_delete(struct drm_file *filp, u32 handle)
@@ -270,6 +288,9 @@ EXPORT_SYMBOL(drm_gem_handle_delete);
 
 /**
  * drm_gem_dumb_destroy - dumb fb callback helper for gem based drivers
+ * @file: drm file-private structure to remove the dumb handle from
+ * @dev: corresponding drm_device
+ * @handle: the dumb handle to remove
  * 
  * This implements the ->dumb_destroy kms driver callback for drivers which use
  * gem to manage their backing storage.
@@ -284,6 +305,9 @@ EXPORT_SYMBOL(drm_gem_dumb_destroy);
 
 /**
  * drm_gem_handle_create_tail - internal functions to create a handle
+ * @file_priv: drm file-private structure to register the handle for
+ * @obj: object to register
+ * @handlep: pionter to return the created handle to the caller
  * 
  * This expects the dev->object_name_lock to be held already and will drop it
  * before returning. Used to avoid races in establishing new handles when
@@ -336,6 +360,11 @@ drm_gem_handle_create_tail(struct drm_file *file_priv,
 }
 
 /**
+ * gem_handle_create - create a gem handle for an object
+ * @file_priv: drm file-private structure to register the handle for
+ * @obj: object to register
+ * @handlep: pionter to return the created handle to the caller
+ *
  * Create a handle for this object. This adds a handle reference
  * to the object, which includes a regular reference count. Callers
  * will likely want to dereference the object afterwards.
@@ -536,6 +565,11 @@ drm_gem_object_lookup(struct drm_device *dev, struct drm_file *filp,
 EXPORT_SYMBOL(drm_gem_object_lookup);
 
 /**
+ * drm_gem_close_ioctl - implementation of the GEM_CLOSE ioctl
+ * @dev: drm_device
+ * @data: ioctl data
+ * @file_priv: drm file-private structure
+ *
  * Releases the handle to an mm object.
  */
 int
@@ -554,6 +588,11 @@ drm_gem_close_ioctl(struct drm_device *dev, void *data,
 }
 
 /**
+ * drm_gem_flink_ioctl - implementation of the GEM_FLINK ioctl
+ * @dev: drm_device
+ * @data: ioctl data
+ * @file_priv: drm file-private structure
+ *
  * Create a global name for an object, returning the name.
  *
  * Note that the name does not hold a reference; when the object
@@ -601,6 +640,11 @@ err:
 }
 
 /**
+ * drm_gem_open - implementation of the GEM_OPEN ioctl
+ * @dev: drm_device
+ * @data: ioctl data
+ * @file_priv: drm file-private structure
+ *
  * Open an object using the global name, returning a handle and the size.
  *
  * This handle (of course) holds a reference to the object, so the object
@@ -640,6 +684,10 @@ drm_gem_open_ioctl(struct drm_device *dev, void *data,
 }
 
 /**
+ * gem_gem_open - initalizes GEM file-private structures at devnode open time
+ * @dev: drm_device which is being opened by userspace
+ * @file_private: drm file-private structure to set up
+ *
  * Called at device open time, sets up the structure for handling refcounting
  * of mm objects.
  */
@@ -650,7 +698,7 @@ drm_gem_open(struct drm_device *dev, struct drm_file *file_private)
        spin_lock_init(&file_private->table_lock);
 }
 
-/**
+/*
  * Called at device close to release the file's
  * handle references on objects.
  */
@@ -674,6 +722,10 @@ drm_gem_object_release_handle(int id, void *ptr, void *data)
 }
 
 /**
+ * drm_gem_release - release file-private GEM resources
+ * @dev: drm_device which is being closed by userspace
+ * @file_private: drm file-private structure to clean up
+ *
  * Called at close time when the filp is going away.
  *
  * Releases any remaining references on objects by this filp.
@@ -692,11 +744,16 @@ drm_gem_object_release(struct drm_gem_object *obj)
        WARN_ON(obj->dma_buf);
 
        if (obj->filp)
-           fput(obj->filp);
+               fput(obj->filp);
+
+       drm_gem_free_mmap_offset(obj);
 }
 EXPORT_SYMBOL(drm_gem_object_release);
 
 /**
+ * drm_gem_object_free - free a GEM object
+ * @kref: kref of the object to free
+ *
  * Called after the last reference to the object has been lost.
  * Must be called holding struct_ mutex
  *
@@ -782,7 +839,7 @@ int drm_gem_mmap_obj(struct drm_gem_object *obj, unsigned long obj_size,
        vma->vm_flags |= VM_IO | VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP;
        vma->vm_ops = dev->driver->gem_vm_ops;
        vma->vm_private_data = obj;
-       vma->vm_page_prot =  pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+       vma->vm_page_prot = pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
 
        /* Take a ref for this mapping of the object, so that the fault
         * handler can dereference the mmap offset's pointer to the object.
@@ -818,7 +875,7 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
        struct drm_device *dev = priv->minor->dev;
        struct drm_gem_object *obj;
        struct drm_vma_offset_node *node;
-       int ret = 0;
+       int ret;
 
        if (drm_device_is_unplugged(dev))
                return -ENODEV;
index 6b51bf9..05c97c5 100644 (file)
@@ -79,7 +79,6 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
                unsigned int size)
 {
        struct drm_gem_cma_object *cma_obj;
-       struct sg_table *sgt = NULL;
        int ret;
 
        size = round_up(size, PAGE_SIZE);
@@ -97,23 +96,9 @@ struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm,
                goto error;
        }
 
-       sgt = kzalloc(sizeof(*cma_obj->sgt), GFP_KERNEL);
-       if (sgt == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-
-       ret = dma_get_sgtable(drm->dev, sgt, cma_obj->vaddr,
-                             cma_obj->paddr, size);
-       if (ret < 0)
-               goto error;
-
-       cma_obj->sgt = sgt;
-
        return cma_obj;
 
 error:
-       kfree(sgt);
        drm_gem_cma_free_object(&cma_obj->base);
        return ERR_PTR(ret);
 }
@@ -175,10 +160,6 @@ void drm_gem_cma_free_object(struct drm_gem_object *gem_obj)
        if (cma_obj->vaddr) {
                dma_free_writecombine(gem_obj->dev->dev, cma_obj->base.size,
                                      cma_obj->vaddr, cma_obj->paddr);
-               if (cma_obj->sgt) {
-                       sg_free_table(cma_obj->sgt);
-                       kfree(cma_obj->sgt);
-               }
        } else if (gem_obj->import_attach) {
                drm_prime_gem_destroy(gem_obj, cma_obj->sgt);
        }
@@ -253,8 +234,17 @@ static int drm_gem_cma_mmap_obj(struct drm_gem_cma_object *cma_obj,
 {
        int ret;
 
-       ret = remap_pfn_range(vma, vma->vm_start, cma_obj->paddr >> PAGE_SHIFT,
-                       vma->vm_end - vma->vm_start, vma->vm_page_prot);
+       /*
+        * Clear the VM_PFNMAP flag that was set by drm_gem_mmap(), and set the
+        * vm_pgoff (used as a fake buffer offset by DRM) to 0 as we want to map
+        * the whole buffer.
+        */
+       vma->vm_flags &= ~VM_PFNMAP;
+       vma->vm_pgoff = 0;
+
+       ret = dma_mmap_writecombine(cma_obj->base.dev->dev, vma,
+                                   cma_obj->vaddr, cma_obj->paddr,
+                                   vma->vm_end - vma->vm_start);
        if (ret)
                drm_gem_vm_close(vma);
 
@@ -292,9 +282,9 @@ void drm_gem_cma_describe(struct drm_gem_cma_object *cma_obj, struct seq_file *m
 
        off = drm_vma_node_start(&obj->vma_node);
 
-       seq_printf(m, "%2d (%2d) %08llx %08Zx %p %d",
+       seq_printf(m, "%2d (%2d) %08llx %pad %p %d",
                        obj->name, obj->refcount.refcount.counter,
-                       off, cma_obj->paddr, cma_obj->vaddr, obj->size);
+                       off, &cma_obj->paddr, cma_obj->vaddr, obj->size);
 
        seq_printf(m, "\n");
 }
@@ -342,7 +332,7 @@ drm_gem_cma_prime_import_sg_table(struct drm_device *dev, size_t size,
        cma_obj->paddr = sg_dma_address(sgt->sgl);
        cma_obj->sgt = sgt;
 
-       DRM_DEBUG_PRIME("dma_addr = 0x%x, size = %zu\n", cma_obj->paddr, size);
+       DRM_DEBUG_PRIME("dma_addr = %pad, size = %zu\n", &cma_obj->paddr, size);
 
        return &cma_obj->base;
 }
index f4dc9b7..93a4204 100644 (file)
@@ -328,6 +328,13 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
                        return -EINVAL;
                file_priv->stereo_allowed = req->value;
                break;
+       case DRM_CLIENT_CAP_UNIVERSAL_PLANES:
+               if (!drm_universal_planes)
+                       return -EINVAL;
+               if (req->value > 1)
+                       return -EINVAL;
+               file_priv->universal_planes = req->value;
+               break;
        default:
                return -EINVAL;
        }
index b155ee2..09821f4 100644 (file)
@@ -142,8 +142,12 @@ int mipi_dsi_host_register(struct mipi_dsi_host *host)
 {
        struct device_node *node;
 
-       for_each_available_child_of_node(host->dev->of_node, node)
+       for_each_available_child_of_node(host->dev->of_node, node) {
+               /* skip nodes without reg property */
+               if (!of_find_property(node, "reg", NULL))
+                       continue;
                of_mipi_dsi_device_add(host, node);
+       }
 
        return 0;
 }
index af93cc5..71e2d3f 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/export.h>
 
-#define MM_UNUSED_TARGET 4
+/**
+ * DOC: Overview
+ *
+ * drm_mm provides a simple range allocator. The drivers are free to use the
+ * resource allocator from the linux core if it suits them, the upside of drm_mm
+ * is that it's in the DRM core. Which means that it's easier to extend for
+ * some of the crazier special purpose needs of gpus.
+ *
+ * The main data struct is &drm_mm, allocations are tracked in &drm_mm_node.
+ * Drivers are free to embed either of them into their own suitable
+ * datastructures. drm_mm itself will not do any allocations of its own, so if
+ * drivers choose not to embed nodes they need to still allocate them
+ * themselves.
+ *
+ * The range allocator also supports reservation of preallocated blocks. This is
+ * useful for taking over initial mode setting configurations from the firmware,
+ * where an object needs to be created which exactly matches the firmware's
+ * scanout target. As long as the range is still free it can be inserted anytime
+ * after the allocator is initialized, which helps with avoiding looped
+ * depencies in the driver load sequence.
+ *
+ * drm_mm maintains a stack of most recently freed holes, which of all
+ * simplistic datastructures seems to be a fairly decent approach to clustering
+ * allocations and avoiding too much fragmentation. This means free space
+ * searches are O(num_holes). Given that all the fancy features drm_mm supports
+ * something better would be fairly complex and since gfx thrashing is a fairly
+ * steep cliff not a real concern. Removing a node again is O(1).
+ *
+ * drm_mm supports a few features: Alignment and range restrictions can be
+ * supplied. Further more every &drm_mm_node has a color value (which is just an
+ * opaqua unsigned long) which in conjunction with a driver callback can be used
+ * to implement sophisticated placement restrictions. The i915 DRM driver uses
+ * this to implement guard pages between incompatible caching domains in the
+ * graphics TT.
+ *
+ * Two behaviors are supported for searching and allocating: bottom-up and top-down.
+ * The default is bottom-up. Top-down allocation can be used if the memory area
+ * has different restrictions, or just to reduce fragmentation.
+ *
+ * Finally iteration helpers to walk all nodes and all holes are provided as are
+ * some basic allocator dumpers for debugging.
+ */
 
 static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
                                                unsigned long size,
@@ -65,7 +106,8 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
 static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
                                 struct drm_mm_node *node,
                                 unsigned long size, unsigned alignment,
-                                unsigned long color)
+                                unsigned long color,
+                                enum drm_mm_allocator_flags flags)
 {
        struct drm_mm *mm = hole_node->mm;
        unsigned long hole_start = drm_mm_hole_node_start(hole_node);
@@ -78,12 +120,22 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
        if (mm->color_adjust)
                mm->color_adjust(hole_node, color, &adj_start, &adj_end);
 
+       if (flags & DRM_MM_CREATE_TOP)
+               adj_start = adj_end - size;
+
        if (alignment) {
                unsigned tmp = adj_start % alignment;
-               if (tmp)
-                       adj_start += alignment - tmp;
+               if (tmp) {
+                       if (flags & DRM_MM_CREATE_TOP)
+                               adj_start -= tmp;
+                       else
+                               adj_start += alignment - tmp;
+               }
        }
 
+       BUG_ON(adj_start < hole_start);
+       BUG_ON(adj_end > hole_end);
+
        if (adj_start == hole_start) {
                hole_node->hole_follows = 0;
                list_del(&hole_node->hole_stack);
@@ -107,6 +159,20 @@ static void drm_mm_insert_helper(struct drm_mm_node *hole_node,
        }
 }
 
+/**
+ * drm_mm_reserve_node - insert an pre-initialized node
+ * @mm: drm_mm allocator to insert @node into
+ * @node: drm_mm_node to insert
+ *
+ * This functions inserts an already set-up drm_mm_node into the allocator,
+ * meaning that start, size and color must be set by the caller. This is useful
+ * to initialize the allocator with preallocated objects which must be set-up
+ * before the range allocator can be set-up, e.g. when taking over a firmware
+ * framebuffer.
+ *
+ * Returns:
+ * 0 on success, -ENOSPC if there's no hole where @node is.
+ */
 int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
 {
        struct drm_mm_node *hole;
@@ -148,23 +214,34 @@ int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node)
 EXPORT_SYMBOL(drm_mm_reserve_node);
 
 /**
- * Search for free space and insert a preallocated memory node. Returns
- * -ENOSPC if no suitable free area is available. The preallocated memory node
- * must be cleared.
+ * drm_mm_insert_node_generic - search for space and insert @node
+ * @mm: drm_mm to allocate from
+ * @node: preallocate node to insert
+ * @size: size of the allocation
+ * @alignment: alignment of the allocation
+ * @color: opaque tag value to use for this node
+ * @sflags: flags to fine-tune the allocation search
+ * @aflags: flags to fine-tune the allocation behavior
+ *
+ * The preallocated node must be cleared to 0.
+ *
+ * Returns:
+ * 0 on success, -ENOSPC if there's no suitable hole.
  */
 int drm_mm_insert_node_generic(struct drm_mm *mm, struct drm_mm_node *node,
                               unsigned long size, unsigned alignment,
                               unsigned long color,
-                              enum drm_mm_search_flags flags)
+                              enum drm_mm_search_flags sflags,
+                              enum drm_mm_allocator_flags aflags)
 {
        struct drm_mm_node *hole_node;
 
        hole_node = drm_mm_search_free_generic(mm, size, alignment,
-                                              color, flags);
+                                              color, sflags);
        if (!hole_node)
                return -ENOSPC;
 
-       drm_mm_insert_helper(hole_node, node, size, alignment, color);
+       drm_mm_insert_helper(hole_node, node, size, alignment, color, aflags);
        return 0;
 }
 EXPORT_SYMBOL(drm_mm_insert_node_generic);
@@ -173,7 +250,8 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
                                       struct drm_mm_node *node,
                                       unsigned long size, unsigned alignment,
                                       unsigned long color,
-                                      unsigned long start, unsigned long end)
+                                      unsigned long start, unsigned long end,
+                                      enum drm_mm_allocator_flags flags)
 {
        struct drm_mm *mm = hole_node->mm;
        unsigned long hole_start = drm_mm_hole_node_start(hole_node);
@@ -188,13 +266,20 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
        if (adj_end > end)
                adj_end = end;
 
+       if (flags & DRM_MM_CREATE_TOP)
+               adj_start = adj_end - size;
+
        if (mm->color_adjust)
                mm->color_adjust(hole_node, color, &adj_start, &adj_end);
 
        if (alignment) {
                unsigned tmp = adj_start % alignment;
-               if (tmp)
-                       adj_start += alignment - tmp;
+               if (tmp) {
+                       if (flags & DRM_MM_CREATE_TOP)
+                               adj_start -= tmp;
+                       else
+                               adj_start += alignment - tmp;
+               }
        }
 
        if (adj_start == hole_start) {
@@ -211,6 +296,8 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
        INIT_LIST_HEAD(&node->hole_stack);
        list_add(&node->node_list, &hole_node->node_list);
 
+       BUG_ON(node->start < start);
+       BUG_ON(node->start < adj_start);
        BUG_ON(node->start + node->size > adj_end);
        BUG_ON(node->start + node->size > end);
 
@@ -222,32 +309,51 @@ static void drm_mm_insert_helper_range(struct drm_mm_node *hole_node,
 }
 
 /**
- * Search for free space and insert a preallocated memory node. Returns
- * -ENOSPC if no suitable free area is available. This is for range
- * restricted allocations. The preallocated memory node must be cleared.
+ * drm_mm_insert_node_in_range_generic - ranged search for space and insert @node
+ * @mm: drm_mm to allocate from
+ * @node: preallocate node to insert
+ * @size: size of the allocation
+ * @alignment: alignment of the allocation
+ * @color: opaque tag value to use for this node
+ * @start: start of the allowed range for this node
+ * @end: end of the allowed range for this node
+ * @sflags: flags to fine-tune the allocation search
+ * @aflags: flags to fine-tune the allocation behavior
+ *
+ * The preallocated node must be cleared to 0.
+ *
+ * Returns:
+ * 0 on success, -ENOSPC if there's no suitable hole.
  */
 int drm_mm_insert_node_in_range_generic(struct drm_mm *mm, struct drm_mm_node *node,
-                                       unsigned long size, unsigned alignment, unsigned long color,
+                                       unsigned long size, unsigned alignment,
+                                       unsigned long color,
                                        unsigned long start, unsigned long end,
-                                       enum drm_mm_search_flags flags)
+                                       enum drm_mm_search_flags sflags,
+                                       enum drm_mm_allocator_flags aflags)
 {
        struct drm_mm_node *hole_node;
 
        hole_node = drm_mm_search_free_in_range_generic(mm,
                                                        size, alignment, color,
-                                                       start, end, flags);
+                                                       start, end, sflags);
        if (!hole_node)
                return -ENOSPC;
 
        drm_mm_insert_helper_range(hole_node, node,
                                   size, alignment, color,
-                                  start, end);
+                                  start, end, aflags);
        return 0;
 }
 EXPORT_SYMBOL(drm_mm_insert_node_in_range_generic);
 
 /**
- * Remove a memory node from the allocator.
+ * drm_mm_remove_node - Remove a memory node from the allocator.
+ * @node: drm_mm_node to remove
+ *
+ * This just removes a node from its drm_mm allocator. The node does not need to
+ * be cleared again before it can be re-inserted into this or any other drm_mm
+ * allocator. It is a bug to call this function on a un-allocated node.
  */
 void drm_mm_remove_node(struct drm_mm_node *node)
 {
@@ -315,7 +421,10 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
        best = NULL;
        best_size = ~0UL;
 
-       drm_mm_for_each_hole(entry, mm, adj_start, adj_end) {
+       __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
+                              flags & DRM_MM_SEARCH_BELOW) {
+               unsigned long hole_size = adj_end - adj_start;
+
                if (mm->color_adjust) {
                        mm->color_adjust(entry, color, &adj_start, &adj_end);
                        if (adj_end <= adj_start)
@@ -328,9 +437,9 @@ static struct drm_mm_node *drm_mm_search_free_generic(const struct drm_mm *mm,
                if (!(flags & DRM_MM_SEARCH_BEST))
                        return entry;
 
-               if (entry->size < best_size) {
+               if (hole_size < best_size) {
                        best = entry;
-                       best_size = entry->size;
+                       best_size = hole_size;
                }
        }
 
@@ -356,7 +465,10 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
        best = NULL;
        best_size = ~0UL;
 
-       drm_mm_for_each_hole(entry, mm, adj_start, adj_end) {
+       __drm_mm_for_each_hole(entry, mm, adj_start, adj_end,
+                              flags & DRM_MM_SEARCH_BELOW) {
+               unsigned long hole_size = adj_end - adj_start;
+
                if (adj_start < start)
                        adj_start = start;
                if (adj_end > end)
@@ -374,9 +486,9 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
                if (!(flags & DRM_MM_SEARCH_BEST))
                        return entry;
 
-               if (entry->size < best_size) {
+               if (hole_size < best_size) {
                        best = entry;
-                       best_size = entry->size;
+                       best_size = hole_size;
                }
        }
 
@@ -384,7 +496,13 @@ static struct drm_mm_node *drm_mm_search_free_in_range_generic(const struct drm_
 }
 
 /**
- * Moves an allocation. To be used with embedded struct drm_mm_node.
+ * drm_mm_replace_node - move an allocation from @old to @new
+ * @old: drm_mm_node to remove from the allocator
+ * @new: drm_mm_node which should inherit @old's allocation
+ *
+ * This is useful for when drivers embed the drm_mm_node structure and hence
+ * can't move allocations by reassigning pointers. It's a combination of remove
+ * and insert with the guarantee that the allocation start will match.
  */
 void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
 {
@@ -402,12 +520,46 @@ void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new)
 EXPORT_SYMBOL(drm_mm_replace_node);
 
 /**
- * Initializa lru scanning.
+ * DOC: lru scan roaster
+ *
+ * Very often GPUs need to have continuous allocations for a given object. When
+ * evicting objects to make space for a new one it is therefore not most
+ * efficient when we simply start to select all objects from the tail of an LRU
+ * until there's a suitable hole: Especially for big objects or nodes that
+ * otherwise have special allocation constraints there's a good chance we evict
+ * lots of (smaller) objects unecessarily.
+ *
+ * The DRM range allocator supports this use-case through the scanning
+ * interfaces. First a scan operation needs to be initialized with
+ * drm_mm_init_scan() or drm_mm_init_scan_with_range(). The the driver adds
+ * objects to the roaster (probably by walking an LRU list, but this can be
+ * freely implemented) until a suitable hole is found or there's no further
+ * evitable object.
+ *
+ * The the driver must walk through all objects again in exactly the reverse
+ * order to restore the allocator state. Note that while the allocator is used
+ * in the scan mode no other operation is allowed.
+ *
+ * Finally the driver evicts all objects selected in the scan. Adding and
+ * removing an object is O(1), and since freeing a node is also O(1) the overall
+ * complexity is O(scanned_objects). So like the free stack which needs to be
+ * walked before a scan operation even begins this is linear in the number of
+ * objects. It doesn't seem to hurt badly.
+ */
+
+/**
+ * drm_mm_init_scan - initialize lru scanning
+ * @mm: drm_mm to scan
+ * @size: size of the allocation
+ * @alignment: alignment of the allocation
+ * @color: opaque tag value to use for the allocation
  *
  * This simply sets up the scanning routines with the parameters for the desired
- * hole.
+ * hole. Note that there's no need to specify allocation flags, since they only
+ * change the place a node is allocated from within a suitable hole.
  *
- * Warning: As long as the scan list is non-empty, no other operations than
+ * Warning:
+ * As long as the scan list is non-empty, no other operations than
  * adding/removing nodes to/from the scan list are allowed.
  */
 void drm_mm_init_scan(struct drm_mm *mm,
@@ -427,12 +579,20 @@ void drm_mm_init_scan(struct drm_mm *mm,
 EXPORT_SYMBOL(drm_mm_init_scan);
 
 /**
- * Initializa lru scanning.
+ * drm_mm_init_scan - initialize range-restricted lru scanning
+ * @mm: drm_mm to scan
+ * @size: size of the allocation
+ * @alignment: alignment of the allocation
+ * @color: opaque tag value to use for the allocation
+ * @start: start of the allowed range for the allocation
+ * @end: end of the allowed range for the allocation
  *
  * This simply sets up the scanning routines with the parameters for the desired
- * hole. This version is for range-restricted scans.
+ * hole. Note that there's no need to specify allocation flags, since they only
+ * change the place a node is allocated from within a suitable hole.
  *
- * Warning: As long as the scan list is non-empty, no other operations than
+ * Warning:
+ * As long as the scan list is non-empty, no other operations than
  * adding/removing nodes to/from the scan list are allowed.
  */
 void drm_mm_init_scan_with_range(struct drm_mm *mm,
@@ -456,12 +616,16 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm,
 EXPORT_SYMBOL(drm_mm_init_scan_with_range);
 
 /**
+ * drm_mm_scan_add_block - add a node to the scan list
+ * @node: drm_mm_node to add
+ *
  * Add a node to the scan list that might be freed to make space for the desired
  * hole.
  *
- * Returns non-zero, if a hole has been found, zero otherwise.
+ * Returns:
+ * True if a hole has been found, false otherwise.
  */
-int drm_mm_scan_add_block(struct drm_mm_node *node)
+bool drm_mm_scan_add_block(struct drm_mm_node *node)
 {
        struct drm_mm *mm = node->mm;
        struct drm_mm_node *prev_node;
@@ -501,15 +665,16 @@ int drm_mm_scan_add_block(struct drm_mm_node *node)
                            mm->scan_size, mm->scan_alignment)) {
                mm->scan_hit_start = hole_start;
                mm->scan_hit_end = hole_end;
-               return 1;
+               return true;
        }
 
-       return 0;
+       return false;
 }
 EXPORT_SYMBOL(drm_mm_scan_add_block);
 
 /**
- * Remove a node from the scan list.
+ * drm_mm_scan_remove_block - remove a node from the scan list
+ * @node: drm_mm_node to remove
  *
  * Nodes _must_ be removed in the exact same order from the scan list as they
  * have been added, otherwise the internal state of the memory manager will be
@@ -519,10 +684,11 @@ EXPORT_SYMBOL(drm_mm_scan_add_block);
  * immediately following drm_mm_search_free with !DRM_MM_SEARCH_BEST will then
  * return the just freed block (because its at the top of the free_stack list).
  *
- * Returns one if this block should be evicted, zero otherwise. Will always
- * return zero when no hole has been found.
+ * Returns:
+ * True if this block should be evicted, false otherwise. Will always
+ * return false when no hole has been found.
  */
-int drm_mm_scan_remove_block(struct drm_mm_node *node)
+bool drm_mm_scan_remove_block(struct drm_mm_node *node)
 {
        struct drm_mm *mm = node->mm;
        struct drm_mm_node *prev_node;
@@ -543,7 +709,15 @@ int drm_mm_scan_remove_block(struct drm_mm_node *node)
 }
 EXPORT_SYMBOL(drm_mm_scan_remove_block);
 
-int drm_mm_clean(struct drm_mm * mm)
+/**
+ * drm_mm_clean - checks whether an allocator is clean
+ * @mm: drm_mm allocator to check
+ *
+ * Returns:
+ * True if the allocator is completely free, false if there's still a node
+ * allocated in it.
+ */
+bool drm_mm_clean(struct drm_mm * mm)
 {
        struct list_head *head = &mm->head_node.node_list;
 
@@ -551,6 +725,14 @@ int drm_mm_clean(struct drm_mm * mm)
 }
 EXPORT_SYMBOL(drm_mm_clean);
 
+/**
+ * drm_mm_init - initialize a drm-mm allocator
+ * @mm: the drm_mm structure to initialize
+ * @start: start of the range managed by @mm
+ * @size: end of the range managed by @mm
+ *
+ * Note that @mm must be cleared to 0 before calling this function.
+ */
 void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
 {
        INIT_LIST_HEAD(&mm->hole_stack);
@@ -572,6 +754,13 @@ void drm_mm_init(struct drm_mm * mm, unsigned long start, unsigned long size)
 }
 EXPORT_SYMBOL(drm_mm_init);
 
+/**
+ * drm_mm_takedown - clean up a drm_mm allocator
+ * @mm: drm_mm allocator to clean up
+ *
+ * Note that it is a bug to call this function on an allocator which is not
+ * clean.
+ */
 void drm_mm_takedown(struct drm_mm * mm)
 {
        WARN(!list_empty(&mm->head_node.node_list),
@@ -597,6 +786,11 @@ static unsigned long drm_mm_debug_hole(struct drm_mm_node *entry,
        return 0;
 }
 
+/**
+ * drm_mm_debug_table - dump allocator state to dmesg
+ * @mm: drm_mm allocator to dump
+ * @prefix: prefix to use for dumping to dmesg
+ */
 void drm_mm_debug_table(struct drm_mm *mm, const char *prefix)
 {
        struct drm_mm_node *entry;
@@ -635,6 +829,11 @@ static unsigned long drm_mm_dump_hole(struct seq_file *m, struct drm_mm_node *en
        return 0;
 }
 
+/**
+ * drm_mm_dump_table - dump allocator state to a seq_file
+ * @m: seq_file to dump to
+ * @mm: drm_mm allocator to dump
+ */
 int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm)
 {
        struct drm_mm_node *entry;
index b073315..8b41057 100644 (file)
 #include <drm/drm_crtc.h>
 #include <video/of_videomode.h>
 #include <video/videomode.h>
+#include <drm/drm_modes.h>
+
+#include "drm_crtc_internal.h"
 
 /**
- * drm_mode_debug_printmodeline - debug print a mode
- * @dev: DRM device
+ * drm_mode_debug_printmodeline - print a mode to dmesg
  * @mode: mode to print
  *
- * LOCKING:
- * None.
- *
  * Describe @mode using DRM_DEBUG.
  */
 void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
@@ -61,18 +60,77 @@ void drm_mode_debug_printmodeline(const struct drm_display_mode *mode)
 EXPORT_SYMBOL(drm_mode_debug_printmodeline);
 
 /**
- * drm_cvt_mode -create a modeline based on CVT algorithm
+ * drm_mode_create - create a new display mode
  * @dev: DRM device
- * @hdisplay: hdisplay size
- * @vdisplay: vdisplay size
- * @vrefresh  : vrefresh rate
- * @reduced : Whether the GTF calculation is simplified
- * @interlaced:Whether the interlace is supported
  *
- * LOCKING:
- * none.
+ * Create a new, cleared drm_display_mode with kzalloc, allocate an ID for it
+ * and return it.
  *
- * return the modeline based on CVT algorithm
+ * Returns:
+ * Pointer to new mode on success, NULL on error.
+ */
+struct drm_display_mode *drm_mode_create(struct drm_device *dev)
+{
+       struct drm_display_mode *nmode;
+
+       nmode = kzalloc(sizeof(struct drm_display_mode), GFP_KERNEL);
+       if (!nmode)
+               return NULL;
+
+       if (drm_mode_object_get(dev, &nmode->base, DRM_MODE_OBJECT_MODE)) {
+               kfree(nmode);
+               return NULL;
+       }
+
+       return nmode;
+}
+EXPORT_SYMBOL(drm_mode_create);
+
+/**
+ * drm_mode_destroy - remove a mode
+ * @dev: DRM device
+ * @mode: mode to remove
+ *
+ * Release @mode's unique ID, then free it @mode structure itself using kfree.
+ */
+void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode)
+{
+       if (!mode)
+               return;
+
+       drm_mode_object_put(dev, &mode->base);
+
+       kfree(mode);
+}
+EXPORT_SYMBOL(drm_mode_destroy);
+
+/**
+ * drm_mode_probed_add - add a mode to a connector's probed_mode list
+ * @connector: connector the new mode
+ * @mode: mode data
+ *
+ * Add @mode to @connector's probed_mode list for later use. This list should
+ * then in a second step get filtered and all the modes actually supported by
+ * the hardware moved to the @connector's modes list.
+ */
+void drm_mode_probed_add(struct drm_connector *connector,
+                        struct drm_display_mode *mode)
+{
+       WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
+
+       list_add_tail(&mode->head, &connector->probed_modes);
+}
+EXPORT_SYMBOL(drm_mode_probed_add);
+
+/**
+ * drm_cvt_mode -create a modeline based on the CVT algorithm
+ * @dev: drm device
+ * @hdisplay: hdisplay size
+ * @vdisplay: vdisplay size
+ * @vrefresh: vrefresh rate
+ * @reduced: whether to use reduced blanking
+ * @interlaced: whether to compute an interlaced mode
+ * @margins: whether to add margins (borders)
  *
  * This function is called to generate the modeline based on CVT algorithm
  * according to the hdisplay, vdisplay, vrefresh.
@@ -82,12 +140,17 @@ EXPORT_SYMBOL(drm_mode_debug_printmodeline);
  *
  * And it is copied from xf86CVTmode in xserver/hw/xfree86/modes/xf86cvt.c.
  * What I have done is to translate it by using integer calculation.
+ *
+ * Returns:
+ * The modeline based on the CVT algorithm stored in a drm_display_mode object.
+ * The display mode object is allocated with drm_mode_create(). Returns NULL
+ * when no mode could be allocated.
  */
-#define HV_FACTOR                      1000
 struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
                                      int vdisplay, int vrefresh,
                                      bool reduced, bool interlaced, bool margins)
 {
+#define HV_FACTOR                      1000
        /* 1) top/bottom margin size (% of height) - default: 1.8, */
 #define        CVT_MARGIN_PERCENTAGE           18
        /* 2) character cell horizontal granularity (pixels) - default 8 */
@@ -281,23 +344,25 @@ struct drm_display_mode *drm_cvt_mode(struct drm_device *dev, int hdisplay,
 EXPORT_SYMBOL(drm_cvt_mode);
 
 /**
- * drm_gtf_mode_complex - create the modeline based on full GTF algorithm
- *
- * @dev                :drm device
- * @hdisplay   :hdisplay size
- * @vdisplay   :vdisplay size
- * @vrefresh   :vrefresh rate.
- * @interlaced :whether the interlace is supported
- * @margins    :desired margin size
- * @GTF_[MCKJ]  :extended GTF formula parameters
- *
- * LOCKING.
- * none.
- *
- * return the modeline based on full GTF algorithm.
+ * drm_gtf_mode_complex - create the modeline based on the full GTF algorithm
+ * @dev: drm device
+ * @hdisplay: hdisplay size
+ * @vdisplay: vdisplay size
+ * @vrefresh: vrefresh rate.
+ * @interlaced: whether to compute an interlaced mode
+ * @margins: desired margin (borders) size
+ * @GTF_M: extended GTF formula parameters
+ * @GTF_2C: extended GTF formula parameters
+ * @GTF_K: extended GTF formula parameters
+ * @GTF_2J: extended GTF formula parameters
  *
  * GTF feature blocks specify C and J in multiples of 0.5, so we pass them
  * in here multiplied by two.  For a C of 40, pass in 80.
+ *
+ * Returns:
+ * The modeline based on the full GTF algorithm stored in a drm_display_mode object.
+ * The display mode object is allocated with drm_mode_create(). Returns NULL
+ * when no mode could be allocated.
  */
 struct drm_display_mode *
 drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
@@ -467,17 +532,13 @@ drm_gtf_mode_complex(struct drm_device *dev, int hdisplay, int vdisplay,
 EXPORT_SYMBOL(drm_gtf_mode_complex);
 
 /**
- * drm_gtf_mode - create the modeline based on GTF algorithm
- *
- * @dev                :drm device
- * @hdisplay   :hdisplay size
- * @vdisplay   :vdisplay size
- * @vrefresh   :vrefresh rate.
- * @interlaced :whether the interlace is supported
- * @margins    :whether the margin is supported
- *
- * LOCKING.
- * none.
+ * drm_gtf_mode - create the modeline based on the GTF algorithm
+ * @dev: drm device
+ * @hdisplay: hdisplay size
+ * @vdisplay: vdisplay size
+ * @vrefresh: vrefresh rate.
+ * @interlaced: whether to compute an interlaced mode
+ * @margins: desired margin (borders) size
  *
  * return the modeline based on GTF algorithm
  *
@@ -496,19 +557,32 @@ EXPORT_SYMBOL(drm_gtf_mode_complex);
  * C = 40
  * K = 128
  * J = 20
+ *
+ * Returns:
+ * The modeline based on the GTF algorithm stored in a drm_display_mode object.
+ * The display mode object is allocated with drm_mode_create(). Returns NULL
+ * when no mode could be allocated.
  */
 struct drm_display_mode *
 drm_gtf_mode(struct drm_device *dev, int hdisplay, int vdisplay, int vrefresh,
-            bool lace, int margins)
+            bool interlaced, int margins)
 {
-       return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh, lace,
-                                   margins, 600, 40 * 2, 128, 20 * 2);
+       return drm_gtf_mode_complex(dev, hdisplay, vdisplay, vrefresh,
+                                   interlaced, margins,
+                                   600, 40 * 2, 128, 20 * 2);
 }
 EXPORT_SYMBOL(drm_gtf_mode);
 
 #ifdef CONFIG_VIDEOMODE_HELPERS
-int drm_display_mode_from_videomode(const struct videomode *vm,
-                                   struct drm_display_mode *dmode)
+/**
+ * drm_display_mode_from_videomode - fill in @dmode using @vm,
+ * @vm: videomode structure to use as source
+ * @dmode: drm_display_mode structure to use as destination
+ *
+ * Fills out @dmode using the display mode specified in @vm.
+ */
+void drm_display_mode_from_videomode(const struct videomode *vm,
+                                    struct drm_display_mode *dmode)
 {
        dmode->hdisplay = vm->hactive;
        dmode->hsync_start = dmode->hdisplay + vm->hfront_porch;
@@ -538,8 +612,6 @@ int drm_display_mode_from_videomode(const struct videomode *vm,
        if (vm->flags & DISPLAY_FLAGS_DOUBLECLK)
                dmode->flags |= DRM_MODE_FLAG_DBLCLK;
        drm_mode_set_name(dmode);
-
-       return 0;
 }
 EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
 
@@ -553,6 +625,9 @@ EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
  * This function is expensive and should only be used, if only one mode is to be
  * read from DT. To get multiple modes start with of_get_display_timings and
  * work with that instead.
+ *
+ * Returns:
+ * 0 on success, a negative errno code when no of videomode node was found.
  */
 int of_get_drm_display_mode(struct device_node *np,
                            struct drm_display_mode *dmode, int index)
@@ -580,10 +655,8 @@ EXPORT_SYMBOL_GPL(of_get_drm_display_mode);
  * drm_mode_set_name - set the name on a mode
  * @mode: name will be set in this mode
  *
- * LOCKING:
- * None.
- *
- * Set the name of @mode to a standard format.
+ * Set the name of @mode to a standard format which is <hdisplay>x<vdisplay>
+ * with an optional 'i' suffix for interlaced modes.
  */
 void drm_mode_set_name(struct drm_display_mode *mode)
 {
@@ -595,54 +668,12 @@ void drm_mode_set_name(struct drm_display_mode *mode)
 }
 EXPORT_SYMBOL(drm_mode_set_name);
 
-/**
- * drm_mode_width - get the width of a mode
- * @mode: mode
- *
- * LOCKING:
- * None.
- *
- * Return @mode's width (hdisplay) value.
- *
- * FIXME: is this needed?
- *
- * RETURNS:
- * @mode->hdisplay
- */
-int drm_mode_width(const struct drm_display_mode *mode)
-{
-       return mode->hdisplay;
-
-}
-EXPORT_SYMBOL(drm_mode_width);
-
-/**
- * drm_mode_height - get the height of a mode
- * @mode: mode
- *
- * LOCKING:
- * None.
- *
- * Return @mode's height (vdisplay) value.
- *
- * FIXME: is this needed?
- *
- * RETURNS:
- * @mode->vdisplay
- */
-int drm_mode_height(const struct drm_display_mode *mode)
-{
-       return mode->vdisplay;
-}
-EXPORT_SYMBOL(drm_mode_height);
-
 /** drm_mode_hsync - get the hsync of a mode
  * @mode: mode
  *
- * LOCKING:
- * None.
- *
- * Return @modes's hsync rate in kHz, rounded to the nearest int.
+ * Returns:
+ * @modes's hsync rate in kHz, rounded to the nearest integer. Calculates the
+ * value first if it is not yet set.
  */
 int drm_mode_hsync(const struct drm_display_mode *mode)
 {
@@ -666,17 +697,9 @@ EXPORT_SYMBOL(drm_mode_hsync);
  * drm_mode_vrefresh - get the vrefresh of a mode
  * @mode: mode
  *
- * LOCKING:
- * None.
- *
- * Return @mode's vrefresh rate in Hz or calculate it if necessary.
- *
- * FIXME: why is this needed?  shouldn't vrefresh be set already?
- *
- * RETURNS:
- * Vertical refresh rate. It will be the result of actual value plus 0.5.
- * If it is 70.288, it will return 70Hz.
- * If it is 59.6, it will return 60Hz.
+ * Returns:
+ * @modes's vrefresh rate in Hz, rounded to the nearest integer. Calculates the
+ * value first if it is not yet set.
  */
 int drm_mode_vrefresh(const struct drm_display_mode *mode)
 {
@@ -705,14 +728,11 @@ int drm_mode_vrefresh(const struct drm_display_mode *mode)
 EXPORT_SYMBOL(drm_mode_vrefresh);
 
 /**
- * drm_mode_set_crtcinfo - set CRTC modesetting parameters
+ * drm_mode_set_crtcinfo - set CRTC modesetting timing parameters
  * @p: mode
  * @adjust_flags: a combination of adjustment flags
  *
- * LOCKING:
- * None.
- *
- * Setup the CRTC modesetting parameters for @p, adjusting if necessary.
+ * Setup the CRTC modesetting timing parameters for @p, adjusting if necessary.
  *
  * - The CRTC_INTERLACE_HALVE_V flag can be used to halve vertical timings of
  *   interlaced modes.
@@ -780,15 +800,11 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
 }
 EXPORT_SYMBOL(drm_mode_set_crtcinfo);
 
-
 /**
  * drm_mode_copy - copy the mode
  * @dst: mode to overwrite
  * @src: mode to copy
  *
- * LOCKING:
- * None.
- *
  * Copy an existing mode into another mode, preserving the object id and
  * list head of the destination mode.
  */
@@ -805,13 +821,14 @@ EXPORT_SYMBOL(drm_mode_copy);
 
 /**
  * drm_mode_duplicate - allocate and duplicate an existing mode
- * @m: mode to duplicate
- *
- * LOCKING:
- * None.
+ * @dev: drm_device to allocate the duplicated mode for
+ * @mode: mode to duplicate
  *
  * Just allocate a new mode, copy the existing mode into it, and return
  * a pointer to it.  Used to create new instances of established modes.
+ *
+ * Returns:
+ * Pointer to duplicated mode on success, NULL on error.
  */
 struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
                                            const struct drm_display_mode *mode)
@@ -833,12 +850,9 @@ EXPORT_SYMBOL(drm_mode_duplicate);
  * @mode1: first mode
  * @mode2: second mode
  *
- * LOCKING:
- * None.
- *
  * Check to see if @mode1 and @mode2 are equivalent.
  *
- * RETURNS:
+ * Returns:
  * True if the modes are equal, false otherwise.
  */
 bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2)
@@ -864,13 +878,10 @@ EXPORT_SYMBOL(drm_mode_equal);
  * @mode1: first mode
  * @mode2: second mode
  *
- * LOCKING:
- * None.
- *
  * Check to see if @mode1 and @mode2 are equivalent, but
  * don't check the pixel clocks nor the stereo layout.
  *
- * RETURNS:
+ * Returns:
  * True if the modes are equal, false otherwise.
  */
 bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
@@ -900,25 +911,19 @@ EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
  * @mode_list: list of modes to check
  * @maxX: maximum width
  * @maxY: maximum height
- * @maxPitch: max pitch
  *
- * LOCKING:
- * Caller must hold a lock protecting @mode_list.
- *
- * The DRM device (@dev) has size and pitch limits.  Here we validate the
- * modes we probed for @dev against those limits and set their status as
- * necessary.
+ * This function is a helper which can be used to validate modes against size
+ * limitations of the DRM device/connector. If a mode is too big its status
+ * memeber is updated with the appropriate validation failure code. The list
+ * itself is not changed.
  */
 void drm_mode_validate_size(struct drm_device *dev,
                            struct list_head *mode_list,
-                           int maxX, int maxY, int maxPitch)
+                           int maxX, int maxY)
 {
        struct drm_display_mode *mode;
 
        list_for_each_entry(mode, mode_list, head) {
-               if (maxPitch > 0 && mode->hdisplay > maxPitch)
-                       mode->status = MODE_BAD_WIDTH;
-
                if (maxX > 0 && mode->hdisplay > maxX)
                        mode->status = MODE_VIRTUAL_X;
 
@@ -934,12 +939,10 @@ EXPORT_SYMBOL(drm_mode_validate_size);
  * @mode_list: list of modes to check
  * @verbose: be verbose about it
  *
- * LOCKING:
- * Caller must hold a lock protecting @mode_list.
- *
- * Once mode list generation is complete, a caller can use this routine to
- * remove invalid modes from a mode list.  If any of the modes have a
- * status other than %MODE_OK, they are removed from @mode_list and freed.
+ * This helper function can be used to prune a display mode list after
+ * validation has been completed. All modes who's status is not MODE_OK will be
+ * removed from the list, and if @verbose the status code and mode name is also
+ * printed to dmesg.
  */
 void drm_mode_prune_invalid(struct drm_device *dev,
                            struct list_head *mode_list, bool verbose)
@@ -966,13 +969,10 @@ EXPORT_SYMBOL(drm_mode_prune_invalid);
  * @lh_a: list_head for first mode
  * @lh_b: list_head for second mode
  *
- * LOCKING:
- * None.
- *
  * Compare two modes, given by @lh_a and @lh_b, returning a value indicating
  * which is better.
  *
- * RETURNS:
+ * Returns:
  * Negative if @lh_a is better than @lh_b, zero if they're equivalent, or
  * positive if @lh_b is better than @lh_a.
  */
@@ -1000,12 +1000,9 @@ static int drm_mode_compare(void *priv, struct list_head *lh_a, struct list_head
 
 /**
  * drm_mode_sort - sort mode list
- * @mode_list: list to sort
+ * @mode_list: list of drm_display_mode structures to sort
  *
- * LOCKING:
- * Caller must hold a lock protecting @mode_list.
- *
- * Sort @mode_list by favorability, putting good modes first.
+ * Sort @mode_list by favorability, moving good modes to the head of the list.
  */
 void drm_mode_sort(struct list_head *mode_list)
 {
@@ -1017,13 +1014,12 @@ EXPORT_SYMBOL(drm_mode_sort);
  * drm_mode_connector_list_update - update the mode list for the connector
  * @connector: the connector to update
  *
- * LOCKING:
- * Caller must hold a lock protecting @mode_list.
- *
  * This moves the modes from the @connector probed_modes list
  * to the actual mode list. It compares the probed mode against the current
- * list and only adds different modes. All modes unverified after this point
- * will be removed by the prune invalid modes.
+ * list and only adds different/new modes.
+ *
+ * This is just a helper functions doesn't validate any modes itself and also
+ * doesn't prune any invalid modes. Callers need to do that themselves.
  */
 void drm_mode_connector_list_update(struct drm_connector *connector)
 {
@@ -1031,6 +1027,8 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
        struct drm_display_mode *pmode, *pt;
        int found_it;
 
+       WARN_ON(!mutex_is_locked(&connector->dev->mode_config.mutex));
+
        list_for_each_entry_safe(pmode, pt, &connector->probed_modes,
                                 head) {
                found_it = 0;
@@ -1056,17 +1054,25 @@ void drm_mode_connector_list_update(struct drm_connector *connector)
 EXPORT_SYMBOL(drm_mode_connector_list_update);
 
 /**
- * drm_mode_parse_command_line_for_connector - parse command line for connector
- * @mode_option - per connector mode option
- * @connector - connector to parse line for
+ * drm_mode_parse_command_line_for_connector - parse command line modeline for connector
+ * @mode_option: optional per connector mode option
+ * @connector: connector to parse modeline for
+ * @mode: preallocated drm_cmdline_mode structure to fill out
+ *
+ * This parses @mode_option command line modeline for modes and options to
+ * configure the connector. If @mode_option is NULL the default command line
+ * modeline in fb_mode_option will be parsed instead.
  *
- * This parses the connector specific then generic command lines for
- * modes and options to configure the connector.
+ * This uses the same parameters as the fb modedb.c, except for an extra
+ * force-enable, force-enable-digital and force-disable bit at the end:
  *
- * This uses the same parameters as the fb modedb.c, except for extra
  *     <xres>x<yres>[M][R][-<bpp>][@<refresh>][i][m][eDd]
  *
- * enable/enable Digital/disable bit at the end
+ * The intermediate drm_cmdline_mode structure is required to store additional
+ * options from the command line modline like the force-enabel/disable flag.
+ *
+ * Returns:
+ * True if a valid modeline has been parsed, false otherwise.
  */
 bool drm_mode_parse_command_line_for_connector(const char *mode_option,
                                               struct drm_connector *connector,
@@ -1219,6 +1225,14 @@ done:
 }
 EXPORT_SYMBOL(drm_mode_parse_command_line_for_connector);
 
+/**
+ * drm_mode_create_from_cmdline_mode - convert a command line modeline into a DRM display mode
+ * @dev: DRM device to create the new mode for
+ * @cmd: input command line modeline
+ *
+ * Returns:
+ * Pointer to converted mode on success, NULL on error.
+ */
 struct drm_display_mode *
 drm_mode_create_from_cmdline_mode(struct drm_device *dev,
                                  struct drm_cmdline_mode *cmd)
index f7af69b..9c696a5 100644 (file)
@@ -351,7 +351,7 @@ err_agp:
        drm_pci_agp_destroy(dev);
        pci_disable_device(pdev);
 err_free:
-       drm_dev_free(dev);
+       drm_dev_unref(dev);
        return ret;
 }
 EXPORT_SYMBOL(drm_get_pci_dev);
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
new file mode 100644 (file)
index 0000000..e768d35
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * DRM universal plane helper functions
+ *
+ * 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 <linux/list.h>
+#include <drm/drmP.h>
+#include <drm/drm_rect.h>
+
+#define SUBPIXEL_MASK 0xffff
+
+/*
+ * This is the minimal list of formats that seem to be safe for modeset use
+ * with all current DRM drivers.  Most hardware can actually support more
+ * formats than this and drivers may specify a more accurate list when
+ * creating the primary plane.  However drivers that still call
+ * drm_plane_init() will use this minimal format list as the default.
+ */
+const static uint32_t safe_modeset_formats[] = {
+       DRM_FORMAT_XRGB8888,
+       DRM_FORMAT_ARGB8888,
+};
+
+/*
+ * Returns the connectors currently associated with a CRTC.  This function
+ * should be called twice:  once with a NULL connector list to retrieve
+ * the list size, and once with the properly allocated list to be filled in.
+ */
+static int get_connectors_for_crtc(struct drm_crtc *crtc,
+                                  struct drm_connector **connector_list,
+                                  int num_connectors)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_connector *connector;
+       int count = 0;
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+               if (connector->encoder && connector->encoder->crtc == crtc) {
+                       if (connector_list != NULL && count < num_connectors)
+                               *(connector_list++) = connector;
+
+                       count++;
+               }
+
+       return count;
+}
+
+/**
+ * drm_primary_helper_update() - Helper for primary plane update
+ * @plane: plane object to update
+ * @crtc: owning CRTC of owning plane
+ * @fb: framebuffer to flip onto plane
+ * @crtc_x: x offset of primary plane on crtc
+ * @crtc_y: y offset of primary plane on crtc
+ * @crtc_w: width of primary plane rectangle on crtc
+ * @crtc_h: height of primary plane rectangle on crtc
+ * @src_x: x offset of @fb for panning
+ * @src_y: y offset of @fb for panning
+ * @src_w: width of source rectangle in @fb
+ * @src_h: height of source rectangle in @fb
+ *
+ * Provides a default plane update handler for primary planes.  This is handler
+ * is called in response to a userspace SetPlane operation on the plane with a
+ * non-NULL framebuffer.  We call the driver's modeset handler to update the
+ * framebuffer.
+ *
+ * SetPlane() on a primary plane of a disabled CRTC is not supported, and will
+ * return an error.
+ *
+ * Note that we make some assumptions about hardware limitations that may not be
+ * true for all hardware --
+ *   1) Primary plane cannot be repositioned.
+ *   2) Primary plane cannot be scaled.
+ *   3) Primary plane must cover the entire CRTC.
+ *   4) Subpixel positioning is not supported.
+ * Drivers for hardware that don't have these restrictions can provide their
+ * own implementation rather than using this helper.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_primary_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
+                             struct drm_framebuffer *fb,
+                             int crtc_x, int crtc_y,
+                             unsigned int crtc_w, unsigned int crtc_h,
+                             uint32_t src_x, uint32_t src_y,
+                             uint32_t src_w, uint32_t src_h)
+{
+       struct drm_mode_set set = {
+               .crtc = crtc,
+               .fb = fb,
+               .mode = &crtc->mode,
+               .x = src_x >> 16,
+               .y = src_y >> 16,
+       };
+       struct drm_rect dest = {
+               .x1 = crtc_x,
+               .y1 = crtc_y,
+               .x2 = crtc_x + crtc_w,
+               .y2 = crtc_y + crtc_h,
+       };
+       struct drm_rect clip = {
+               .x2 = crtc->mode.hdisplay,
+               .y2 = crtc->mode.vdisplay,
+       };
+       struct drm_connector **connector_list;
+       struct drm_framebuffer *tmpfb;
+       int num_connectors, ret;
+
+       if (!crtc->enabled) {
+               DRM_DEBUG_KMS("Cannot update primary plane of a disabled CRTC.\n");
+               return -EINVAL;
+       }
+
+       /* Disallow subpixel positioning */
+       if ((src_x | src_y | src_w | src_h) & SUBPIXEL_MASK) {
+               DRM_DEBUG_KMS("Primary plane does not support subpixel positioning\n");
+               return -EINVAL;
+       }
+
+       /* Primary planes are locked to their owning CRTC */
+       if (plane->possible_crtcs != drm_crtc_mask(crtc)) {
+               DRM_DEBUG_KMS("Cannot change primary plane CRTC\n");
+               return -EINVAL;
+       }
+
+       /* Disallow scaling */
+       if (crtc_w != src_w || crtc_h != src_h) {
+               DRM_DEBUG_KMS("Can't scale primary plane\n");
+               return -EINVAL;
+       }
+
+       /* Make sure primary plane covers entire CRTC */
+       drm_rect_intersect(&dest, &clip);
+       if (dest.x1 != 0 || dest.y1 != 0 ||
+           dest.x2 != crtc->mode.hdisplay || dest.y2 != crtc->mode.vdisplay) {
+               DRM_DEBUG_KMS("Primary plane must cover entire CRTC\n");
+               return -EINVAL;
+       }
+
+       /* Framebuffer must be big enough to cover entire plane */
+       ret = drm_crtc_check_viewport(crtc, crtc_x, crtc_y, &crtc->mode, fb);
+       if (ret)
+               return ret;
+
+       /* Find current connectors for CRTC */
+       num_connectors = get_connectors_for_crtc(crtc, NULL, 0);
+       BUG_ON(num_connectors == 0);
+       connector_list = kzalloc(num_connectors * sizeof(*connector_list),
+                                GFP_KERNEL);
+       if (!connector_list)
+               return -ENOMEM;
+       get_connectors_for_crtc(crtc, connector_list, num_connectors);
+
+       set.connectors = connector_list;
+       set.num_connectors = num_connectors;
+
+       /*
+        * set_config() adjusts crtc->primary->fb; however the DRM setplane
+        * code that called us expects to handle the framebuffer update and
+        * reference counting; save and restore the current fb before
+        * calling it.
+        *
+        * N.B., we call set_config() directly here rather than using
+        * drm_mode_set_config_internal.  We're reprogramming the same
+        * connectors that were already in use, so we shouldn't need the extra
+        * cross-CRTC fb refcounting to accomodate stealing connectors.
+        * drm_mode_setplane() already handles the basic refcounting for the
+        * framebuffers involved in this operation.
+        */
+       tmpfb = plane->fb;
+       ret = crtc->funcs->set_config(&set);
+       plane->fb = tmpfb;
+
+       kfree(connector_list);
+       return ret;
+}
+EXPORT_SYMBOL(drm_primary_helper_update);
+
+/**
+ * drm_primary_helper_disable() - Helper for primary plane disable
+ * @plane: plane to disable
+ *
+ * Provides a default plane disable handler for primary planes.  This is handler
+ * is called in response to a userspace SetPlane operation on the plane with a
+ * NULL framebuffer parameter.  We call the driver's modeset handler with a NULL
+ * framebuffer to disable the CRTC if no other planes are currently enabled.
+ * If other planes are still enabled on the same CRTC, we return -EBUSY.
+ *
+ * Note that some hardware may be able to disable the primary plane without
+ * disabling the whole CRTC.  Drivers for such hardware should provide their
+ * own disable handler that disables just the primary plane (and they'll likely
+ * need to provide their own update handler as well to properly re-enable a
+ * disabled primary plane).
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_primary_helper_disable(struct drm_plane *plane)
+{
+       struct drm_plane *p;
+       struct drm_mode_set set = {
+               .crtc = plane->crtc,
+               .fb = NULL,
+       };
+
+       if (plane->crtc == NULL || plane->fb == NULL)
+               /* Already disabled */
+               return 0;
+
+       list_for_each_entry(p, &plane->dev->mode_config.plane_list, head)
+               if (p != plane && p->fb) {
+                       DRM_DEBUG_KMS("Cannot disable primary plane while other planes are still active on CRTC.\n");
+                       return -EBUSY;
+               }
+
+       /*
+        * N.B.  We call set_config() directly here rather than
+        * drm_mode_set_config_internal() since drm_mode_setplane() already
+        * handles the basic refcounting and we don't need the special
+        * cross-CRTC refcounting (no chance of stealing connectors from
+        * other CRTC's with this update).
+        */
+       return plane->crtc->funcs->set_config(&set);
+}
+EXPORT_SYMBOL(drm_primary_helper_disable);
+
+/**
+ * drm_primary_helper_destroy() - Helper for primary plane destruction
+ * @plane: plane to destroy
+ *
+ * Provides a default plane destroy handler for primary planes.  This handler
+ * is called during CRTC destruction.  We disable the primary plane, remove
+ * it from the DRM plane list, and deallocate the plane structure.
+ */
+void drm_primary_helper_destroy(struct drm_plane *plane)
+{
+       plane->funcs->disable_plane(plane);
+       drm_plane_cleanup(plane);
+       kfree(plane);
+}
+EXPORT_SYMBOL(drm_primary_helper_destroy);
+
+const struct drm_plane_funcs drm_primary_helper_funcs = {
+       .update_plane = drm_primary_helper_update,
+       .disable_plane = drm_primary_helper_disable,
+       .destroy = drm_primary_helper_destroy,
+};
+EXPORT_SYMBOL(drm_primary_helper_funcs);
+
+/**
+ * drm_primary_helper_create_plane() - Create a generic primary plane
+ * @dev: drm device
+ * @formats: pixel formats supported, or NULL for a default safe list
+ * @num_formats: size of @formats; ignored if @formats is NULL
+ *
+ * Allocates and initializes a primary plane that can be used with the primary
+ * plane helpers.  Drivers that wish to use driver-specific plane structures or
+ * provide custom handler functions may perform their own allocation and
+ * initialization rather than calling this function.
+ */
+struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
+                                                 const uint32_t *formats,
+                                                 int num_formats)
+{
+       struct drm_plane *primary;
+       int ret;
+
+       primary = kzalloc(sizeof(*primary), GFP_KERNEL);
+       if (primary == NULL) {
+               DRM_DEBUG_KMS("Failed to allocate primary plane\n");
+               return NULL;
+       }
+
+       if (formats == NULL) {
+               formats = safe_modeset_formats;
+               num_formats = ARRAY_SIZE(safe_modeset_formats);
+       }
+
+       /* possible_crtc's will be filled in later by crtc_init */
+       ret = drm_plane_init(dev, primary, 0, &drm_primary_helper_funcs,
+                            formats, num_formats,
+                            DRM_PLANE_TYPE_PRIMARY);
+       if (ret) {
+               kfree(primary);
+               primary = NULL;
+       }
+
+       return primary;
+}
+EXPORT_SYMBOL(drm_primary_helper_create_plane);
+
+/**
+ * drm_crtc_init - Legacy CRTC initialization function
+ * @dev: DRM device
+ * @crtc: CRTC object to init
+ * @funcs: callbacks for the new CRTC
+ *
+ * Initialize a CRTC object with a default helper-provided primary plane and no
+ * cursor plane.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_crtc_init(struct drm_device *dev, struct drm_crtc *crtc,
+                 const struct drm_crtc_funcs *funcs)
+{
+       struct drm_plane *primary;
+
+       primary = drm_primary_helper_create_plane(dev, NULL, 0);
+       return drm_crtc_init_with_planes(dev, crtc, primary, NULL, funcs);
+}
+EXPORT_SYMBOL(drm_crtc_init);
index 21fc820..319ff53 100644 (file)
@@ -64,7 +64,7 @@ static int drm_get_platform_dev(struct platform_device *platdev,
        return 0;
 
 err_free:
-       drm_dev_free(dev);
+       drm_dev_unref(dev);
        return ret;
 }
 
index bb516fd..304ca8c 100644 (file)
@@ -68,7 +68,8 @@ struct drm_prime_attachment {
        enum dma_data_direction dir;
 };
 
-static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv, struct dma_buf *dma_buf, uint32_t handle)
+static int drm_prime_add_buf_handle(struct drm_prime_file_private *prime_fpriv,
+                                   struct dma_buf *dma_buf, uint32_t handle)
 {
        struct drm_prime_member *member;
 
@@ -174,7 +175,7 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr
 }
 
 static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
-               enum dma_data_direction dir)
+                                           enum dma_data_direction dir)
 {
        struct drm_prime_attachment *prime_attach = attach->priv;
        struct drm_gem_object *obj = attach->dmabuf->priv;
@@ -211,11 +212,19 @@ static struct sg_table *drm_gem_map_dma_buf(struct dma_buf_attachment *attach,
 }
 
 static void drm_gem_unmap_dma_buf(struct dma_buf_attachment *attach,
-               struct sg_table *sgt, enum dma_data_direction dir)
+                                 struct sg_table *sgt,
+                                 enum dma_data_direction dir)
 {
        /* nothing to be done here */
 }
 
+/**
+ * drm_gem_dmabuf_release - dma_buf release implementation for GEM
+ * @dma_buf: buffer to be released
+ *
+ * Generic release function for dma_bufs exported as PRIME buffers. GEM drivers
+ * must use this in their dma_buf ops structure as the release callback.
+ */
 void drm_gem_dmabuf_release(struct dma_buf *dma_buf)
 {
        struct drm_gem_object *obj = dma_buf->priv;
@@ -242,30 +251,30 @@ static void drm_gem_dmabuf_vunmap(struct dma_buf *dma_buf, void *vaddr)
 }
 
 static void *drm_gem_dmabuf_kmap_atomic(struct dma_buf *dma_buf,
-               unsigned long page_num)
+                                       unsigned long page_num)
 {
        return NULL;
 }
 
 static void drm_gem_dmabuf_kunmap_atomic(struct dma_buf *dma_buf,
-               unsigned long page_num, void *addr)
+                                        unsigned long page_num, void *addr)
 {
 
 }
 static void *drm_gem_dmabuf_kmap(struct dma_buf *dma_buf,
-               unsigned long page_num)
+                                unsigned long page_num)
 {
        return NULL;
 }
 
 static void drm_gem_dmabuf_kunmap(struct dma_buf *dma_buf,
-               unsigned long page_num, void *addr)
+                                 unsigned long page_num, void *addr)
 {
 
 }
 
 static int drm_gem_dmabuf_mmap(struct dma_buf *dma_buf,
-               struct vm_area_struct *vma)
+                              struct vm_area_struct *vma)
 {
        struct drm_gem_object *obj = dma_buf->priv;
        struct drm_device *dev = obj->dev;
@@ -315,6 +324,15 @@ static const struct dma_buf_ops drm_gem_prime_dmabuf_ops =  {
  *    driver's scatter/gather table
  */
 
+/**
+ * drm_gem_prime_export - helper library implemention of the export callback
+ * @dev: drm_device to export from
+ * @obj: GEM object to export
+ * @flags: flags like DRM_CLOEXEC
+ *
+ * This is the implementation of the gem_prime_export functions for GEM drivers
+ * using the PRIME helpers.
+ */
 struct dma_buf *drm_gem_prime_export(struct drm_device *dev,
                                     struct drm_gem_object *obj, int flags)
 {
@@ -355,9 +373,23 @@ static struct dma_buf *export_and_register_object(struct drm_device *dev,
        return dmabuf;
 }
 
+/**
+ * drm_gem_prime_handle_to_fd - PRIME export function for GEM drivers
+ * @dev: dev to export the buffer from
+ * @file_priv: drm file-private structure
+ * @handle: buffer handle to export
+ * @flags: flags like DRM_CLOEXEC
+ * @prime_fd: pointer to storage for the fd id of the create dma-buf
+ *
+ * This is the PRIME export function which must be used mandatorily by GEM
+ * drivers to ensure correct lifetime management of the underlying GEM object.
+ * The actual exporting from GEM object to a dma-buf is done through the
+ * gem_prime_export driver callback.
+ */
 int drm_gem_prime_handle_to_fd(struct drm_device *dev,
-               struct drm_file *file_priv, uint32_t handle, uint32_t flags,
-               int *prime_fd)
+                              struct drm_file *file_priv, uint32_t handle,
+                              uint32_t flags,
+                              int *prime_fd)
 {
        struct drm_gem_object *obj;
        int ret = 0;
@@ -441,6 +473,14 @@ out_unlock:
 }
 EXPORT_SYMBOL(drm_gem_prime_handle_to_fd);
 
+/**
+ * drm_gem_prime_import - helper library implemention of the import callback
+ * @dev: drm_device to import into
+ * @dma_buf: dma-buf object to import
+ *
+ * This is the implementation of the gem_prime_import functions for GEM drivers
+ * using the PRIME helpers.
+ */
 struct drm_gem_object *drm_gem_prime_import(struct drm_device *dev,
                                            struct dma_buf *dma_buf)
 {
@@ -496,8 +536,21 @@ fail_detach:
 }
 EXPORT_SYMBOL(drm_gem_prime_import);
 
+/**
+ * drm_gem_prime_fd_to_handle - PRIME import function for GEM drivers
+ * @dev: dev to export the buffer from
+ * @file_priv: drm file-private structure
+ * @prime_fd: fd id of the dma-buf which should be imported
+ * @handle: pointer to storage for the handle of the imported buffer object
+ *
+ * This is the PRIME import function which must be used mandatorily by GEM
+ * drivers to ensure correct lifetime management of the underlying GEM object.
+ * The actual importing of GEM object from the dma-buf is done through the
+ * gem_import_export driver callback.
+ */
 int drm_gem_prime_fd_to_handle(struct drm_device *dev,
-               struct drm_file *file_priv, int prime_fd, uint32_t *handle)
+                              struct drm_file *file_priv, int prime_fd,
+                              uint32_t *handle)
 {
        struct dma_buf *dma_buf;
        struct drm_gem_object *obj;
@@ -598,12 +651,14 @@ int drm_prime_fd_to_handle_ioctl(struct drm_device *dev, void *data,
                        args->fd, &args->handle);
 }
 
-/*
- * drm_prime_pages_to_sg
+/**
+ * drm_prime_pages_to_sg - converts a page array into an sg list
+ * @pages: pointer to the array of page pointers to convert
+ * @nr_pages: length of the page vector
  *
- * this helper creates an sg table object from a set of pages
+ * This helper creates an sg table object from a set of pages
  * the driver is responsible for mapping the pages into the
- * importers address space
+ * importers address space for use with dma_buf itself.
  */
 struct sg_table *drm_prime_pages_to_sg(struct page **pages, int nr_pages)
 {
@@ -628,9 +683,16 @@ out:
 }
 EXPORT_SYMBOL(drm_prime_pages_to_sg);
 
-/* export an sg table into an array of pages and addresses
-   this is currently required by the TTM driver in order to do correct fault
-   handling */
+/**
+ * drm_prime_sg_to_page_addr_arrays - convert an sg table into a page array
+ * @sgt: scatter-gather table to convert
+ * @pages: array of page pointers to store the page array in
+ * @addrs: optional array to store the dma bus address of each page
+ * @max_pages: size of both the passed-in arrays
+ *
+ * Exports an sg table into an array of pages and addresses. This is currently
+ * required by the TTM driver in order to do correct fault handling.
+ */
 int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
                                     dma_addr_t *addrs, int max_pages)
 {
@@ -663,7 +725,15 @@ int drm_prime_sg_to_page_addr_arrays(struct sg_table *sgt, struct page **pages,
        return 0;
 }
 EXPORT_SYMBOL(drm_prime_sg_to_page_addr_arrays);
-/* helper function to cleanup a GEM/prime object */
+
+/**
+ * drm_prime_gem_destroy - helper to clean up a PRIME-imported GEM object
+ * @obj: GEM object which was created from a dma-buf
+ * @sg: the sg-table which was pinned at import time
+ *
+ * This is the cleanup functions which GEM drivers need to call when they use
+ * @drm_gem_prime_import to import dma-bufs.
+ */
 void drm_prime_gem_destroy(struct drm_gem_object *obj, struct sg_table *sg)
 {
        struct dma_buf_attachment *attach;
@@ -683,11 +753,9 @@ void drm_prime_init_file_private(struct drm_prime_file_private *prime_fpriv)
        INIT_LIST_HEAD(&prime_fpriv->head);
        mutex_init(&prime_fpriv->lock);
 }
-EXPORT_SYMBOL(drm_prime_init_file_private);
 
 void drm_prime_destroy_file_private(struct drm_prime_file_private *prime_fpriv)
 {
        /* by now drm_gem_release should've made sure the list is empty */
        WARN_ON(!list_empty(&prime_fpriv->head));
 }
-EXPORT_SYMBOL(drm_prime_destroy_file_private);
index 98a33c5..4c24c3a 100644 (file)
  * DEALINGS IN THE SOFTWARE.
  */
 
+#include <linux/fs.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/mount.h>
 #include <linux/slab.h>
 #include <drm/drmP.h>
 #include <drm/drm_core.h>
@@ -43,6 +45,10 @@ EXPORT_SYMBOL(drm_debug);
 unsigned int drm_rnodes = 0;   /* 1 to enable experimental render nodes API */
 EXPORT_SYMBOL(drm_rnodes);
 
+/* 1 to allow user space to request universal planes (experimental) */
+unsigned int drm_universal_planes = 0;
+EXPORT_SYMBOL(drm_universal_planes);
+
 unsigned int drm_vblank_offdelay = 5000;    /* Default to 5000 msecs. */
 EXPORT_SYMBOL(drm_vblank_offdelay);
 
@@ -66,10 +72,12 @@ MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
 
 module_param_named(debug, drm_debug, int, 0600);
 module_param_named(rnodes, drm_rnodes, int, 0600);
+module_param_named(universal_planes, drm_universal_planes, int, 0600);
 module_param_named(vblankoffdelay, drm_vblank_offdelay, int, 0600);
 module_param_named(timestamp_precision_usec, drm_timestamp_precision, int, 0600);
 module_param_named(timestamp_monotonic, drm_timestamp_monotonic, int, 0600);
 
+static DEFINE_SPINLOCK(drm_minor_lock);
 struct idr drm_minors_idr;
 
 struct class *drm_class;
@@ -94,48 +102,20 @@ int drm_err(const char *func, const char *format, ...)
 }
 EXPORT_SYMBOL(drm_err);
 
-void drm_ut_debug_printk(unsigned int request_level,
-                        const char *prefix,
-                        const char *function_name,
-                        const char *format, ...)
+void drm_ut_debug_printk(const char *function_name, const char *format, ...)
 {
        struct va_format vaf;
        va_list args;
 
-       if (drm_debug & request_level) {
-               va_start(args, format);
-               vaf.fmt = format;
-               vaf.va = &args;
-
-               if (function_name)
-                       printk(KERN_DEBUG "[%s:%s], %pV", prefix,
-                              function_name, &vaf);
-               else
-                       printk(KERN_DEBUG "%pV", &vaf);
-               va_end(args);
-       }
-}
-EXPORT_SYMBOL(drm_ut_debug_printk);
-
-static int drm_minor_get_id(struct drm_device *dev, int type)
-{
-       int ret;
-       int base = 0, limit = 63;
-
-       if (type == DRM_MINOR_CONTROL) {
-               base += 64;
-               limit = base + 63;
-       } else if (type == DRM_MINOR_RENDER) {
-               base += 128;
-               limit = base + 63;
-       }
+       va_start(args, format);
+       vaf.fmt = format;
+       vaf.va = &args;
 
-       mutex_lock(&dev->struct_mutex);
-       ret = idr_alloc(&drm_minors_idr, NULL, base, limit, GFP_KERNEL);
-       mutex_unlock(&dev->struct_mutex);
+       printk(KERN_DEBUG "[" DRM_NAME ":%s] %pV", function_name, &vaf);
 
-       return ret == -ENOSPC ? -EINVAL : ret;
+       va_end(args);
 }
+EXPORT_SYMBOL(drm_ut_debug_printk);
 
 struct drm_master *drm_master_create(struct drm_minor *minor)
 {
@@ -152,8 +132,6 @@ struct drm_master *drm_master_create(struct drm_minor *minor)
        INIT_LIST_HEAD(&master->magicfree);
        master->minor = minor;
 
-       list_add_tail(&master->head, &minor->master_list);
-
        return master;
 }
 
@@ -171,8 +149,7 @@ static void drm_master_destroy(struct kref *kref)
        struct drm_device *dev = master->minor->dev;
        struct drm_map_list *r_list, *list_temp;
 
-       list_del(&master->head);
-
+       mutex_lock(&dev->struct_mutex);
        if (dev->driver->master_destroy)
                dev->driver->master_destroy(dev, master);
 
@@ -200,6 +177,7 @@ static void drm_master_destroy(struct kref *kref)
 
        drm_ht_remove(&master->magiclist);
 
+       mutex_unlock(&dev->struct_mutex);
        kfree(master);
 }
 
@@ -215,19 +193,20 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
 {
        int ret = 0;
 
+       mutex_lock(&dev->master_mutex);
        if (file_priv->is_master)
-               return 0;
-
-       if (file_priv->minor->master && file_priv->minor->master != file_priv->master)
-               return -EINVAL;
+               goto out_unlock;
 
-       if (!file_priv->master)
-               return -EINVAL;
+       if (file_priv->minor->master) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
 
-       if (file_priv->minor->master)
-               return -EINVAL;
+       if (!file_priv->master) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
 
-       mutex_lock(&dev->struct_mutex);
        file_priv->minor->master = drm_master_get(file_priv->master);
        file_priv->is_master = 1;
        if (dev->driver->master_set) {
@@ -237,142 +216,211 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
                        drm_master_put(&file_priv->minor->master);
                }
        }
-       mutex_unlock(&dev->struct_mutex);
 
+out_unlock:
+       mutex_unlock(&dev->master_mutex);
        return ret;
 }
 
 int drm_dropmaster_ioctl(struct drm_device *dev, void *data,
                         struct drm_file *file_priv)
 {
+       int ret = -EINVAL;
+
+       mutex_lock(&dev->master_mutex);
        if (!file_priv->is_master)
-               return -EINVAL;
+               goto out_unlock;
 
        if (!file_priv->minor->master)
-               return -EINVAL;
+               goto out_unlock;
 
-       mutex_lock(&dev->struct_mutex);
+       ret = 0;
        if (dev->driver->master_drop)
                dev->driver->master_drop(dev, file_priv, false);
        drm_master_put(&file_priv->minor->master);
        file_priv->is_master = 0;
-       mutex_unlock(&dev->struct_mutex);
-       return 0;
+
+out_unlock:
+       mutex_unlock(&dev->master_mutex);
+       return ret;
 }
 
-/**
- * drm_get_minor - Allocate and register new DRM minor
- * @dev: DRM device
- * @minor: Pointer to where new minor is stored
- * @type: Type of minor
- *
- * Allocate a new minor of the given type and register it. A pointer to the new
- * minor is returned in @minor.
- * Caller must hold the global DRM mutex.
+/*
+ * DRM Minors
+ * A DRM device can provide several char-dev interfaces on the DRM-Major. Each
+ * of them is represented by a drm_minor object. Depending on the capabilities
+ * of the device-driver, different interfaces are registered.
  *
- * RETURNS:
- * 0 on success, negative error code on failure.
+ * Minors can be accessed via dev->$minor_name. This pointer is either
+ * NULL or a valid drm_minor pointer and stays valid as long as the device is
+ * valid. This means, DRM minors have the same life-time as the underlying
+ * device. However, this doesn't mean that the minor is active. Minors are
+ * registered and unregistered dynamically according to device-state.
  */
-static int drm_get_minor(struct drm_device *dev, struct drm_minor **minor,
-                        int type)
+
+static struct drm_minor **drm_minor_get_slot(struct drm_device *dev,
+                                            unsigned int type)
+{
+       switch (type) {
+       case DRM_MINOR_LEGACY:
+               return &dev->primary;
+       case DRM_MINOR_RENDER:
+               return &dev->render;
+       case DRM_MINOR_CONTROL:
+               return &dev->control;
+       default:
+               return NULL;
+       }
+}
+
+static int drm_minor_alloc(struct drm_device *dev, unsigned int type)
+{
+       struct drm_minor *minor;
+
+       minor = kzalloc(sizeof(*minor), GFP_KERNEL);
+       if (!minor)
+               return -ENOMEM;
+
+       minor->type = type;
+       minor->dev = dev;
+
+       *drm_minor_get_slot(dev, type) = minor;
+       return 0;
+}
+
+static void drm_minor_free(struct drm_device *dev, unsigned int type)
+{
+       struct drm_minor **slot;
+
+       slot = drm_minor_get_slot(dev, type);
+       if (*slot) {
+               kfree(*slot);
+               *slot = NULL;
+       }
+}
+
+static int drm_minor_register(struct drm_device *dev, unsigned int type)
 {
        struct drm_minor *new_minor;
+       unsigned long flags;
        int ret;
        int minor_id;
 
        DRM_DEBUG("\n");
 
-       minor_id = drm_minor_get_id(dev, type);
+       new_minor = *drm_minor_get_slot(dev, type);
+       if (!new_minor)
+               return 0;
+
+       idr_preload(GFP_KERNEL);
+       spin_lock_irqsave(&drm_minor_lock, flags);
+       minor_id = idr_alloc(&drm_minors_idr,
+                            NULL,
+                            64 * type,
+                            64 * (type + 1),
+                            GFP_NOWAIT);
+       spin_unlock_irqrestore(&drm_minor_lock, flags);
+       idr_preload_end();
+
        if (minor_id < 0)
                return minor_id;
 
-       new_minor = kzalloc(sizeof(struct drm_minor), GFP_KERNEL);
-       if (!new_minor) {
-               ret = -ENOMEM;
-               goto err_idr;
-       }
-
-       new_minor->type = type;
-       new_minor->device = MKDEV(DRM_MAJOR, minor_id);
-       new_minor->dev = dev;
        new_minor->index = minor_id;
-       INIT_LIST_HEAD(&new_minor->master_list);
-
-       idr_replace(&drm_minors_idr, new_minor, minor_id);
 
-#if defined(CONFIG_DEBUG_FS)
        ret = drm_debugfs_init(new_minor, minor_id, drm_debugfs_root);
        if (ret) {
                DRM_ERROR("DRM: Failed to initialize /sys/kernel/debug/dri.\n");
-               goto err_mem;
+               goto err_id;
        }
-#endif
 
        ret = drm_sysfs_device_add(new_minor);
        if (ret) {
-               printk(KERN_ERR
-                      "DRM: Error sysfs_device_add.\n");
+               DRM_ERROR("DRM: Error sysfs_device_add.\n");
                goto err_debugfs;
        }
-       *minor = new_minor;
+
+       /* replace NULL with @minor so lookups will succeed from now on */
+       spin_lock_irqsave(&drm_minor_lock, flags);
+       idr_replace(&drm_minors_idr, new_minor, new_minor->index);
+       spin_unlock_irqrestore(&drm_minor_lock, flags);
 
        DRM_DEBUG("new minor assigned %d\n", minor_id);
        return 0;
 
-
 err_debugfs:
-#if defined(CONFIG_DEBUG_FS)
        drm_debugfs_cleanup(new_minor);
-err_mem:
-#endif
-       kfree(new_minor);
-err_idr:
+err_id:
+       spin_lock_irqsave(&drm_minor_lock, flags);
        idr_remove(&drm_minors_idr, minor_id);
-       *minor = NULL;
+       spin_unlock_irqrestore(&drm_minor_lock, flags);
+       new_minor->index = 0;
        return ret;
 }
 
-/**
- * drm_unplug_minor - Unplug DRM minor
- * @minor: Minor to unplug
- *
- * Unplugs the given DRM minor but keeps the object. So after this returns,
- * minor->dev is still valid so existing open-files can still access it to get
- * device information from their drm_file ojects.
- * If the minor is already unplugged or if @minor is NULL, nothing is done.
- * The global DRM mutex must be held by the caller.
- */
-static void drm_unplug_minor(struct drm_minor *minor)
+static void drm_minor_unregister(struct drm_device *dev, unsigned int type)
 {
+       struct drm_minor *minor;
+       unsigned long flags;
+
+       minor = *drm_minor_get_slot(dev, type);
        if (!minor || !minor->kdev)
                return;
 
-#if defined(CONFIG_DEBUG_FS)
-       drm_debugfs_cleanup(minor);
-#endif
+       spin_lock_irqsave(&drm_minor_lock, flags);
+       idr_remove(&drm_minors_idr, minor->index);
+       spin_unlock_irqrestore(&drm_minor_lock, flags);
+       minor->index = 0;
 
+       drm_debugfs_cleanup(minor);
        drm_sysfs_device_remove(minor);
-       idr_remove(&drm_minors_idr, minor->index);
 }
 
 /**
- * drm_put_minor - Destroy DRM minor
- * @minor: Minor to destroy
+ * drm_minor_acquire - Acquire a DRM minor
+ * @minor_id: Minor ID of the DRM-minor
+ *
+ * Looks up the given minor-ID and returns the respective DRM-minor object. The
+ * refence-count of the underlying device is increased so you must release this
+ * object with drm_minor_release().
  *
- * This calls drm_unplug_minor() on the given minor and then frees it. Nothing
- * is done if @minor is NULL. It is fine to call this on already unplugged
- * minors.
- * The global DRM mutex must be held by the caller.
+ * As long as you hold this minor, it is guaranteed that the object and the
+ * minor->dev pointer will stay valid! However, the device may get unplugged and
+ * unregistered while you hold the minor.
+ *
+ * Returns:
+ * Pointer to minor-object with increased device-refcount, or PTR_ERR on
+ * failure.
  */
-static void drm_put_minor(struct drm_minor *minor)
+struct drm_minor *drm_minor_acquire(unsigned int minor_id)
 {
-       if (!minor)
-               return;
+       struct drm_minor *minor;
+       unsigned long flags;
+
+       spin_lock_irqsave(&drm_minor_lock, flags);
+       minor = idr_find(&drm_minors_idr, minor_id);
+       if (minor)
+               drm_dev_ref(minor->dev);
+       spin_unlock_irqrestore(&drm_minor_lock, flags);
+
+       if (!minor) {
+               return ERR_PTR(-ENODEV);
+       } else if (drm_device_is_unplugged(minor->dev)) {
+               drm_dev_unref(minor->dev);
+               return ERR_PTR(-ENODEV);
+       }
 
-       DRM_DEBUG("release secondary minor %d\n", minor->index);
+       return minor;
+}
 
-       drm_unplug_minor(minor);
-       kfree(minor);
+/**
+ * drm_minor_release - Release DRM minor
+ * @minor: Pointer to DRM minor object
+ *
+ * Release a minor that was previously acquired via drm_minor_acquire().
+ */
+void drm_minor_release(struct drm_minor *minor)
+{
+       drm_dev_unref(minor->dev);
 }
 
 /**
@@ -392,18 +440,16 @@ void drm_put_dev(struct drm_device *dev)
        }
 
        drm_dev_unregister(dev);
-       drm_dev_free(dev);
+       drm_dev_unref(dev);
 }
 EXPORT_SYMBOL(drm_put_dev);
 
 void drm_unplug_dev(struct drm_device *dev)
 {
        /* for a USB device */
-       if (drm_core_check_feature(dev, DRIVER_MODESET))
-               drm_unplug_minor(dev->control);
-       if (dev->render)
-               drm_unplug_minor(dev->render);
-       drm_unplug_minor(dev->primary);
+       drm_minor_unregister(dev, DRM_MINOR_LEGACY);
+       drm_minor_unregister(dev, DRM_MINOR_RENDER);
+       drm_minor_unregister(dev, DRM_MINOR_CONTROL);
 
        mutex_lock(&drm_global_mutex);
 
@@ -416,6 +462,78 @@ void drm_unplug_dev(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_unplug_dev);
 
+/*
+ * DRM internal mount
+ * We want to be able to allocate our own "struct address_space" to control
+ * memory-mappings in VRAM (or stolen RAM, ...). However, core MM does not allow
+ * stand-alone address_space objects, so we need an underlying inode. As there
+ * is no way to allocate an independent inode easily, we need a fake internal
+ * VFS mount-point.
+ *
+ * The drm_fs_inode_new() function allocates a new inode, drm_fs_inode_free()
+ * frees it again. You are allowed to use iget() and iput() to get references to
+ * the inode. But each drm_fs_inode_new() call must be paired with exactly one
+ * drm_fs_inode_free() call (which does not have to be the last iput()).
+ * We use drm_fs_inode_*() to manage our internal VFS mount-point and share it
+ * between multiple inode-users. You could, technically, call
+ * iget() + drm_fs_inode_free() directly after alloc and sometime later do an
+ * iput(), but this way you'd end up with a new vfsmount for each inode.
+ */
+
+static int drm_fs_cnt;
+static struct vfsmount *drm_fs_mnt;
+
+static const struct dentry_operations drm_fs_dops = {
+       .d_dname        = simple_dname,
+};
+
+static const struct super_operations drm_fs_sops = {
+       .statfs         = simple_statfs,
+};
+
+static struct dentry *drm_fs_mount(struct file_system_type *fs_type, int flags,
+                                  const char *dev_name, void *data)
+{
+       return mount_pseudo(fs_type,
+                           "drm:",
+                           &drm_fs_sops,
+                           &drm_fs_dops,
+                           0x010203ff);
+}
+
+static struct file_system_type drm_fs_type = {
+       .name           = "drm",
+       .owner          = THIS_MODULE,
+       .mount          = drm_fs_mount,
+       .kill_sb        = kill_anon_super,
+};
+
+static struct inode *drm_fs_inode_new(void)
+{
+       struct inode *inode;
+       int r;
+
+       r = simple_pin_fs(&drm_fs_type, &drm_fs_mnt, &drm_fs_cnt);
+       if (r < 0) {
+               DRM_ERROR("Cannot mount pseudo fs: %d\n", r);
+               return ERR_PTR(r);
+       }
+
+       inode = alloc_anon_inode(drm_fs_mnt->mnt_sb);
+       if (IS_ERR(inode))
+               simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
+
+       return inode;
+}
+
+static void drm_fs_inode_free(struct inode *inode)
+{
+       if (inode) {
+               iput(inode);
+               simple_release_fs(&drm_fs_mnt, &drm_fs_cnt);
+       }
+}
+
 /**
  * drm_dev_alloc - Allocate new drm device
  * @driver: DRM driver to allocate device for
@@ -425,6 +543,9 @@ EXPORT_SYMBOL(drm_unplug_dev);
  * Call drm_dev_register() to advertice the device to user space and register it
  * with other core subsystems.
  *
+ * The initial ref-count of the object is 1. Use drm_dev_ref() and
+ * drm_dev_unref() to take and drop further ref-counts.
+ *
  * RETURNS:
  * Pointer to new DRM device, or NULL if out of memory.
  */
@@ -438,6 +559,7 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
        if (!dev)
                return NULL;
 
+       kref_init(&dev->ref);
        dev->dev = parent;
        dev->driver = driver;
 
@@ -451,9 +573,33 @@ struct drm_device *drm_dev_alloc(struct drm_driver *driver,
        spin_lock_init(&dev->event_lock);
        mutex_init(&dev->struct_mutex);
        mutex_init(&dev->ctxlist_mutex);
+       mutex_init(&dev->master_mutex);
 
-       if (drm_ht_create(&dev->map_hash, 12))
+       dev->anon_inode = drm_fs_inode_new();
+       if (IS_ERR(dev->anon_inode)) {
+               ret = PTR_ERR(dev->anon_inode);
+               DRM_ERROR("Cannot allocate anonymous inode: %d\n", ret);
                goto err_free;
+       }
+
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               ret = drm_minor_alloc(dev, DRM_MINOR_CONTROL);
+               if (ret)
+                       goto err_minors;
+       }
+
+       if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) {
+               ret = drm_minor_alloc(dev, DRM_MINOR_RENDER);
+               if (ret)
+                       goto err_minors;
+       }
+
+       ret = drm_minor_alloc(dev, DRM_MINOR_LEGACY);
+       if (ret)
+               goto err_minors;
+
+       if (drm_ht_create(&dev->map_hash, 12))
+               goto err_minors;
 
        ret = drm_ctxbitmap_init(dev);
        if (ret) {
@@ -475,38 +621,71 @@ err_ctxbitmap:
        drm_ctxbitmap_cleanup(dev);
 err_ht:
        drm_ht_remove(&dev->map_hash);
+err_minors:
+       drm_minor_free(dev, DRM_MINOR_LEGACY);
+       drm_minor_free(dev, DRM_MINOR_RENDER);
+       drm_minor_free(dev, DRM_MINOR_CONTROL);
+       drm_fs_inode_free(dev->anon_inode);
 err_free:
+       mutex_destroy(&dev->master_mutex);
        kfree(dev);
        return NULL;
 }
 EXPORT_SYMBOL(drm_dev_alloc);
 
-/**
- * drm_dev_free - Free DRM device
- * @dev: DRM device to free
- *
- * Free a DRM device that has previously been allocated via drm_dev_alloc().
- * You must not use kfree() instead or you will leak memory.
- *
- * This must not be called once the device got registered. Use drm_put_dev()
- * instead, which then calls drm_dev_free().
- */
-void drm_dev_free(struct drm_device *dev)
+static void drm_dev_release(struct kref *ref)
 {
-       drm_put_minor(dev->control);
-       drm_put_minor(dev->render);
-       drm_put_minor(dev->primary);
+       struct drm_device *dev = container_of(ref, struct drm_device, ref);
 
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_destroy(dev);
 
        drm_ctxbitmap_cleanup(dev);
        drm_ht_remove(&dev->map_hash);
+       drm_fs_inode_free(dev->anon_inode);
+
+       drm_minor_free(dev, DRM_MINOR_LEGACY);
+       drm_minor_free(dev, DRM_MINOR_RENDER);
+       drm_minor_free(dev, DRM_MINOR_CONTROL);
 
        kfree(dev->devname);
+
+       mutex_destroy(&dev->master_mutex);
        kfree(dev);
 }
-EXPORT_SYMBOL(drm_dev_free);
+
+/**
+ * drm_dev_ref - Take reference of a DRM device
+ * @dev: device to take reference of or NULL
+ *
+ * This increases the ref-count of @dev by one. You *must* already own a
+ * reference when calling this. Use drm_dev_unref() to drop this reference
+ * again.
+ *
+ * This function never fails. However, this function does not provide *any*
+ * guarantee whether the device is alive or running. It only provides a
+ * reference to the object and the memory associated with it.
+ */
+void drm_dev_ref(struct drm_device *dev)
+{
+       if (dev)
+               kref_get(&dev->ref);
+}
+EXPORT_SYMBOL(drm_dev_ref);
+
+/**
+ * drm_dev_unref - Drop reference of a DRM device
+ * @dev: device to drop reference of or NULL
+ *
+ * This decreases the ref-count of @dev by one. The device is destroyed if the
+ * ref-count drops to zero.
+ */
+void drm_dev_unref(struct drm_device *dev)
+{
+       if (dev)
+               kref_put(&dev->ref, drm_dev_release);
+}
+EXPORT_SYMBOL(drm_dev_unref);
 
 /**
  * drm_dev_register - Register DRM device
@@ -527,26 +706,22 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 
        mutex_lock(&drm_global_mutex);
 
-       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
-               ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
-               if (ret)
-                       goto out_unlock;
-       }
+       ret = drm_minor_register(dev, DRM_MINOR_CONTROL);
+       if (ret)
+               goto err_minors;
 
-       if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) {
-               ret = drm_get_minor(dev, &dev->render, DRM_MINOR_RENDER);
-               if (ret)
-                       goto err_control_node;
-       }
+       ret = drm_minor_register(dev, DRM_MINOR_RENDER);
+       if (ret)
+               goto err_minors;
 
-       ret = drm_get_minor(dev, &dev->primary, DRM_MINOR_LEGACY);
+       ret = drm_minor_register(dev, DRM_MINOR_LEGACY);
        if (ret)
-               goto err_render_node;
+               goto err_minors;
 
        if (dev->driver->load) {
                ret = dev->driver->load(dev, flags);
                if (ret)
-                       goto err_primary_node;
+                       goto err_minors;
        }
 
        /* setup grouping for legacy outputs */
@@ -563,12 +738,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 err_unload:
        if (dev->driver->unload)
                dev->driver->unload(dev);
-err_primary_node:
-       drm_unplug_minor(dev->primary);
-err_render_node:
-       drm_unplug_minor(dev->render);
-err_control_node:
-       drm_unplug_minor(dev->control);
+err_minors:
+       drm_minor_unregister(dev, DRM_MINOR_LEGACY);
+       drm_minor_unregister(dev, DRM_MINOR_RENDER);
+       drm_minor_unregister(dev, DRM_MINOR_CONTROL);
 out_unlock:
        mutex_unlock(&drm_global_mutex);
        return ret;
@@ -581,7 +754,7 @@ EXPORT_SYMBOL(drm_dev_register);
  *
  * Unregister the DRM device from the system. This does the reverse of
  * drm_dev_register() but does not deallocate the device. The caller must call
- * drm_dev_free() to free all resources.
+ * drm_dev_unref() to drop their final reference.
  */
 void drm_dev_unregister(struct drm_device *dev)
 {
@@ -600,8 +773,8 @@ void drm_dev_unregister(struct drm_device *dev)
        list_for_each_entry_safe(r_list, list_temp, &dev->maplist, head)
                drm_rmmap(dev, r_list->map);
 
-       drm_unplug_minor(dev->control);
-       drm_unplug_minor(dev->render);
-       drm_unplug_minor(dev->primary);
+       drm_minor_unregister(dev, DRM_MINOR_LEGACY);
+       drm_minor_unregister(dev, DRM_MINOR_RENDER);
+       drm_minor_unregister(dev, DRM_MINOR_CONTROL);
 }
 EXPORT_SYMBOL(drm_dev_unregister);
index 0f8cb1a..c3406aa 100644 (file)
@@ -30,7 +30,7 @@ int drm_get_usb_dev(struct usb_interface *interface,
        return 0;
 
 err_free:
-       drm_dev_free(dev);
+       drm_dev_unref(dev);
        return ret;
 
 }
index 6e1a1a2..5bf5bca 100644 (file)
@@ -31,6 +31,30 @@ config DRM_EXYNOS_FIMD
        help
          Choose this option if you want to use Exynos FIMD for DRM.
 
+config DRM_EXYNOS_DPI
+       bool "EXYNOS DRM parallel output support"
+       depends on DRM_EXYNOS
+       select DRM_PANEL
+       default n
+       help
+         This enables support for Exynos parallel output.
+
+config DRM_EXYNOS_DSI
+       bool "EXYNOS DRM MIPI-DSI driver support"
+       depends on DRM_EXYNOS
+       select DRM_MIPI_DSI
+       select DRM_PANEL
+       default n
+       help
+         This enables support for Exynos MIPI-DSI device.
+
+config DRM_EXYNOS_DP
+       bool "EXYNOS DRM DP driver support"
+       depends on DRM_EXYNOS && ARCH_EXYNOS
+       default DRM_EXYNOS
+       help
+         This enables support for DP device.
+
 config DRM_EXYNOS_HDMI
        bool "Exynos DRM HDMI"
        depends on DRM_EXYNOS && !VIDEO_SAMSUNG_S5P_TV
index 639b49e..33ae365 100644 (file)
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
-exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
+exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \
                exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
                exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
                exynos_drm_plane.o
@@ -11,9 +11,10 @@ exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o exynos_drm_connector.o \
 exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD)    += exynos_drm_fimd.o
-exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)    += exynos_hdmi.o exynos_mixer.o \
-                                          exynos_ddc.o exynos_hdmiphy.o \
-                                          exynos_drm_hdmi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_DPI)     += exynos_drm_dpi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_DSI)     += exynos_drm_dsi.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_DP)      += exynos_dp_core.o exynos_dp_reg.o
+exynosdrm-$(CONFIG_DRM_EXYNOS_HDMI)    += exynos_hdmi.o exynos_mixer.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_VIDI)    += exynos_drm_vidi.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_G2D)     += exynos_drm_g2d.o
 exynosdrm-$(CONFIG_DRM_EXYNOS_IPP)     += exynos_drm_ipp.o
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
new file mode 100644 (file)
index 0000000..aed533b
--- /dev/null
@@ -0,0 +1,1356 @@
+/*
+ * Samsung SoC DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/phy/phy.h>
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/bridge/ptn3460.h>
+
+#include "exynos_drm_drv.h"
+#include "exynos_dp_core.h"
+
+#define ctx_from_connector(c)  container_of(c, struct exynos_dp_device, \
+                                       connector)
+
+struct bridge_init {
+       struct i2c_client *client;
+       struct device_node *node;
+};
+
+static int exynos_dp_init_dp(struct exynos_dp_device *dp)
+{
+       exynos_dp_reset(dp);
+
+       exynos_dp_swreset(dp);
+
+       exynos_dp_init_analog_param(dp);
+       exynos_dp_init_interrupt(dp);
+
+       /* SW defined function Normal operation */
+       exynos_dp_enable_sw_function(dp);
+
+       exynos_dp_config_interrupt(dp);
+       exynos_dp_init_analog_func(dp);
+
+       exynos_dp_init_hpd(dp);
+       exynos_dp_init_aux(dp);
+
+       return 0;
+}
+
+static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
+{
+       int timeout_loop = 0;
+
+       while (exynos_dp_get_plug_in_status(dp) != 0) {
+               timeout_loop++;
+               if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+                       dev_err(dp->dev, "failed to get hpd plug status\n");
+                       return -ETIMEDOUT;
+               }
+               usleep_range(10, 11);
+       }
+
+       return 0;
+}
+
+static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
+{
+       int i;
+       unsigned char sum = 0;
+
+       for (i = 0; i < EDID_BLOCK_LENGTH; i++)
+               sum = sum + edid_data[i];
+
+       return sum;
+}
+
+static int exynos_dp_read_edid(struct exynos_dp_device *dp)
+{
+       unsigned char edid[EDID_BLOCK_LENGTH * 2];
+       unsigned int extend_block = 0;
+       unsigned char sum;
+       unsigned char test_vector;
+       int retval;
+
+       /*
+        * EDID device address is 0x50.
+        * However, if necessary, you must have set upper address
+        * into E-EDID in I2C device, 0x30.
+        */
+
+       /* Read Extension Flag, Number of 128-byte EDID extension blocks */
+       retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+                               EDID_EXTENSION_FLAG,
+                               &extend_block);
+       if (retval)
+               return retval;
+
+       if (extend_block > 0) {
+               dev_dbg(dp->dev, "EDID data includes a single extension!\n");
+
+               /* Read EDID data */
+               retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
+                                               EDID_HEADER_PATTERN,
+                                               EDID_BLOCK_LENGTH,
+                                               &edid[EDID_HEADER_PATTERN]);
+               if (retval != 0) {
+                       dev_err(dp->dev, "EDID Read failed!\n");
+                       return -EIO;
+               }
+               sum = exynos_dp_calc_edid_check_sum(edid);
+               if (sum != 0) {
+                       dev_err(dp->dev, "EDID bad checksum!\n");
+                       return -EIO;
+               }
+
+               /* Read additional EDID data */
+               retval = exynos_dp_read_bytes_from_i2c(dp,
+                               I2C_EDID_DEVICE_ADDR,
+                               EDID_BLOCK_LENGTH,
+                               EDID_BLOCK_LENGTH,
+                               &edid[EDID_BLOCK_LENGTH]);
+               if (retval != 0) {
+                       dev_err(dp->dev, "EDID Read failed!\n");
+                       return -EIO;
+               }
+               sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
+               if (sum != 0) {
+                       dev_err(dp->dev, "EDID bad checksum!\n");
+                       return -EIO;
+               }
+
+               exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
+                                       &test_vector);
+               if (test_vector & DPCD_TEST_EDID_READ) {
+                       exynos_dp_write_byte_to_dpcd(dp,
+                               DPCD_ADDR_TEST_EDID_CHECKSUM,
+                               edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
+                       exynos_dp_write_byte_to_dpcd(dp,
+                               DPCD_ADDR_TEST_RESPONSE,
+                               DPCD_TEST_EDID_CHECKSUM_WRITE);
+               }
+       } else {
+               dev_info(dp->dev, "EDID data does not include any extensions.\n");
+
+               /* Read EDID data */
+               retval = exynos_dp_read_bytes_from_i2c(dp,
+                               I2C_EDID_DEVICE_ADDR,
+                               EDID_HEADER_PATTERN,
+                               EDID_BLOCK_LENGTH,
+                               &edid[EDID_HEADER_PATTERN]);
+               if (retval != 0) {
+                       dev_err(dp->dev, "EDID Read failed!\n");
+                       return -EIO;
+               }
+               sum = exynos_dp_calc_edid_check_sum(edid);
+               if (sum != 0) {
+                       dev_err(dp->dev, "EDID bad checksum!\n");
+                       return -EIO;
+               }
+
+               exynos_dp_read_byte_from_dpcd(dp,
+                       DPCD_ADDR_TEST_REQUEST,
+                       &test_vector);
+               if (test_vector & DPCD_TEST_EDID_READ) {
+                       exynos_dp_write_byte_to_dpcd(dp,
+                               DPCD_ADDR_TEST_EDID_CHECKSUM,
+                               edid[EDID_CHECKSUM]);
+                       exynos_dp_write_byte_to_dpcd(dp,
+                               DPCD_ADDR_TEST_RESPONSE,
+                               DPCD_TEST_EDID_CHECKSUM_WRITE);
+               }
+       }
+
+       dev_err(dp->dev, "EDID Read success!\n");
+       return 0;
+}
+
+static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
+{
+       u8 buf[12];
+       int i;
+       int retval;
+
+       /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
+       retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV,
+                               12, buf);
+       if (retval)
+               return retval;
+
+       /* Read EDID */
+       for (i = 0; i < 3; i++) {
+               retval = exynos_dp_read_edid(dp);
+               if (!retval)
+                       break;
+       }
+
+       return retval;
+}
+
+static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
+                                               bool enable)
+{
+       u8 data;
+
+       exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
+
+       if (enable)
+               exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
+                       DPCD_ENHANCED_FRAME_EN |
+                       DPCD_LANE_COUNT_SET(data));
+       else
+               exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
+                       DPCD_LANE_COUNT_SET(data));
+}
+
+static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
+{
+       u8 data;
+       int retval;
+
+       exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+       retval = DPCD_ENHANCED_FRAME_CAP(data);
+
+       return retval;
+}
+
+static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
+{
+       u8 data;
+
+       data = exynos_dp_is_enhanced_mode_available(dp);
+       exynos_dp_enable_rx_to_enhanced_mode(dp, data);
+       exynos_dp_enable_enhanced_mode(dp, data);
+}
+
+static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
+{
+       exynos_dp_set_training_pattern(dp, DP_NONE);
+
+       exynos_dp_write_byte_to_dpcd(dp,
+               DPCD_ADDR_TRAINING_PATTERN_SET,
+               DPCD_TRAINING_PATTERN_DISABLED);
+}
+
+static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
+                                       int pre_emphasis, int lane)
+{
+       switch (lane) {
+       case 0:
+               exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
+               break;
+       case 1:
+               exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
+               break;
+
+       case 2:
+               exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
+               break;
+
+       case 3:
+               exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
+               break;
+       }
+}
+
+static int exynos_dp_link_start(struct exynos_dp_device *dp)
+{
+       u8 buf[4];
+       int lane, lane_count, pll_tries, retval;
+
+       lane_count = dp->link_train.lane_count;
+
+       dp->link_train.lt_state = CLOCK_RECOVERY;
+       dp->link_train.eq_loop = 0;
+
+       for (lane = 0; lane < lane_count; lane++)
+               dp->link_train.cr_loop[lane] = 0;
+
+       /* Set link rate and count as you want to establish*/
+       exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
+       exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
+
+       /* Setup RX configuration */
+       buf[0] = dp->link_train.link_rate;
+       buf[1] = dp->link_train.lane_count;
+       retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
+                               2, buf);
+       if (retval)
+               return retval;
+
+       /* Set TX pre-emphasis to minimum */
+       for (lane = 0; lane < lane_count; lane++)
+               exynos_dp_set_lane_lane_pre_emphasis(dp,
+                       PRE_EMPHASIS_LEVEL_0, lane);
+
+       /* Wait for PLL lock */
+       pll_tries = 0;
+       while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+               if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
+                       dev_err(dp->dev, "Wait for PLL lock timed out\n");
+                       return -ETIMEDOUT;
+               }
+
+               pll_tries++;
+               usleep_range(90, 120);
+       }
+
+       /* Set training pattern 1 */
+       exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
+
+       /* Set RX training pattern */
+       retval = exynos_dp_write_byte_to_dpcd(dp,
+                       DPCD_ADDR_TRAINING_PATTERN_SET,
+                       DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
+       if (retval)
+               return retval;
+
+       for (lane = 0; lane < lane_count; lane++)
+               buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
+                           DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
+
+       retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
+                       lane_count, buf);
+
+       return retval;
+}
+
+static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
+{
+       int shift = (lane & 1) * 4;
+       u8 link_value = link_status[lane>>1];
+
+       return (link_value >> shift) & 0xf;
+}
+
+static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
+{
+       int lane;
+       u8 lane_status;
+
+       for (lane = 0; lane < lane_count; lane++) {
+               lane_status = exynos_dp_get_lane_status(link_status, lane);
+               if ((lane_status & DPCD_LANE_CR_DONE) == 0)
+                       return -EINVAL;
+       }
+       return 0;
+}
+
+static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
+                               int lane_count)
+{
+       int lane;
+       u8 lane_status;
+
+       if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
+               return -EINVAL;
+
+       for (lane = 0; lane < lane_count; lane++) {
+               lane_status = exynos_dp_get_lane_status(link_status, lane);
+               lane_status &= DPCD_CHANNEL_EQ_BITS;
+               if (lane_status != DPCD_CHANNEL_EQ_BITS)
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
+                                                       int lane)
+{
+       int shift = (lane & 1) * 4;
+       u8 link_value = adjust_request[lane>>1];
+
+       return (link_value >> shift) & 0x3;
+}
+
+static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
+                                       u8 adjust_request[2],
+                                       int lane)
+{
+       int shift = (lane & 1) * 4;
+       u8 link_value = adjust_request[lane>>1];
+
+       return ((link_value >> shift) & 0xc) >> 2;
+}
+
+static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
+                                       u8 training_lane_set, int lane)
+{
+       switch (lane) {
+       case 0:
+               exynos_dp_set_lane0_link_training(dp, training_lane_set);
+               break;
+       case 1:
+               exynos_dp_set_lane1_link_training(dp, training_lane_set);
+               break;
+
+       case 2:
+               exynos_dp_set_lane2_link_training(dp, training_lane_set);
+               break;
+
+       case 3:
+               exynos_dp_set_lane3_link_training(dp, training_lane_set);
+               break;
+       }
+}
+
+static unsigned int exynos_dp_get_lane_link_training(
+                               struct exynos_dp_device *dp,
+                               int lane)
+{
+       u32 reg;
+
+       switch (lane) {
+       case 0:
+               reg = exynos_dp_get_lane0_link_training(dp);
+               break;
+       case 1:
+               reg = exynos_dp_get_lane1_link_training(dp);
+               break;
+       case 2:
+               reg = exynos_dp_get_lane2_link_training(dp);
+               break;
+       case 3:
+               reg = exynos_dp_get_lane3_link_training(dp);
+               break;
+       default:
+               WARN_ON(1);
+               return 0;
+       }
+
+       return reg;
+}
+
+static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
+{
+       exynos_dp_training_pattern_dis(dp);
+       exynos_dp_set_enhanced_mode(dp);
+
+       dp->link_train.lt_state = FAILED;
+}
+
+static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
+                                       u8 adjust_request[2])
+{
+       int lane, lane_count;
+       u8 voltage_swing, pre_emphasis, training_lane;
+
+       lane_count = dp->link_train.lane_count;
+       for (lane = 0; lane < lane_count; lane++) {
+               voltage_swing = exynos_dp_get_adjust_request_voltage(
+                                               adjust_request, lane);
+               pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+                                               adjust_request, lane);
+               training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
+                               DPCD_PRE_EMPHASIS_SET(pre_emphasis);
+
+               if (voltage_swing == VOLTAGE_LEVEL_3)
+                       training_lane |= DPCD_MAX_SWING_REACHED;
+               if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
+                       training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
+
+               dp->link_train.training_lane[lane] = training_lane;
+       }
+}
+
+static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
+{
+       int lane, lane_count, retval;
+       u8 voltage_swing, pre_emphasis, training_lane;
+       u8 link_status[2], adjust_request[2];
+
+       usleep_range(100, 101);
+
+       lane_count = dp->link_train.lane_count;
+
+       retval =  exynos_dp_read_bytes_from_dpcd(dp,
+                       DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
+       if (retval)
+               return retval;
+
+       retval =  exynos_dp_read_bytes_from_dpcd(dp,
+                       DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
+       if (retval)
+               return retval;
+
+       if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
+               /* set training pattern 2 for EQ */
+               exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
+
+               retval = exynos_dp_write_byte_to_dpcd(dp,
+                               DPCD_ADDR_TRAINING_PATTERN_SET,
+                               DPCD_SCRAMBLING_DISABLED |
+                               DPCD_TRAINING_PATTERN_2);
+               if (retval)
+                       return retval;
+
+               dev_info(dp->dev, "Link Training Clock Recovery success\n");
+               dp->link_train.lt_state = EQUALIZER_TRAINING;
+       } else {
+               for (lane = 0; lane < lane_count; lane++) {
+                       training_lane = exynos_dp_get_lane_link_training(
+                                                       dp, lane);
+                       voltage_swing = exynos_dp_get_adjust_request_voltage(
+                                                       adjust_request, lane);
+                       pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
+                                                       adjust_request, lane);
+
+                       if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
+                                       voltage_swing &&
+                           DPCD_PRE_EMPHASIS_GET(training_lane) ==
+                                       pre_emphasis)
+                               dp->link_train.cr_loop[lane]++;
+
+                       if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
+                           voltage_swing == VOLTAGE_LEVEL_3 ||
+                           pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
+                               dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
+                                       dp->link_train.cr_loop[lane],
+                                       voltage_swing, pre_emphasis);
+                               exynos_dp_reduce_link_rate(dp);
+                               return -EIO;
+                       }
+               }
+       }
+
+       exynos_dp_get_adjust_training_lane(dp, adjust_request);
+
+       for (lane = 0; lane < lane_count; lane++)
+               exynos_dp_set_lane_link_training(dp,
+                       dp->link_train.training_lane[lane], lane);
+
+       retval = exynos_dp_write_bytes_to_dpcd(dp,
+                       DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
+                       dp->link_train.training_lane);
+       if (retval)
+               return retval;
+
+       return retval;
+}
+
+static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
+{
+       int lane, lane_count, retval;
+       u32 reg;
+       u8 link_align, link_status[2], adjust_request[2];
+
+       usleep_range(400, 401);
+
+       lane_count = dp->link_train.lane_count;
+
+       retval = exynos_dp_read_bytes_from_dpcd(dp,
+                       DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
+       if (retval)
+               return retval;
+
+       if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
+               exynos_dp_reduce_link_rate(dp);
+               return -EIO;
+       }
+
+       retval = exynos_dp_read_bytes_from_dpcd(dp,
+                       DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
+       if (retval)
+               return retval;
+
+       retval = exynos_dp_read_byte_from_dpcd(dp,
+                       DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
+       if (retval)
+               return retval;
+
+       exynos_dp_get_adjust_training_lane(dp, adjust_request);
+
+       if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
+               /* traing pattern Set to Normal */
+               exynos_dp_training_pattern_dis(dp);
+
+               dev_info(dp->dev, "Link Training success!\n");
+
+               exynos_dp_get_link_bandwidth(dp, &reg);
+               dp->link_train.link_rate = reg;
+               dev_dbg(dp->dev, "final bandwidth = %.2x\n",
+                       dp->link_train.link_rate);
+
+               exynos_dp_get_lane_count(dp, &reg);
+               dp->link_train.lane_count = reg;
+               dev_dbg(dp->dev, "final lane count = %.2x\n",
+                       dp->link_train.lane_count);
+
+               /* set enhanced mode if available */
+               exynos_dp_set_enhanced_mode(dp);
+               dp->link_train.lt_state = FINISHED;
+
+               return 0;
+       }
+
+       /* not all locked */
+       dp->link_train.eq_loop++;
+
+       if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
+               dev_err(dp->dev, "EQ Max loop\n");
+               exynos_dp_reduce_link_rate(dp);
+               return -EIO;
+       }
+
+       for (lane = 0; lane < lane_count; lane++)
+               exynos_dp_set_lane_link_training(dp,
+                       dp->link_train.training_lane[lane], lane);
+
+       retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
+                       lane_count, dp->link_train.training_lane);
+
+       return retval;
+}
+
+static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
+                                       u8 *bandwidth)
+{
+       u8 data;
+
+       /*
+        * For DP rev.1.1, Maximum link rate of Main Link lanes
+        * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
+        */
+       exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
+       *bandwidth = data;
+}
+
+static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
+                                       u8 *lane_count)
+{
+       u8 data;
+
+       /*
+        * For DP rev.1.1, Maximum number of Main Link lanes
+        * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
+        */
+       exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
+       *lane_count = DPCD_MAX_LANE_COUNT(data);
+}
+
+static void exynos_dp_init_training(struct exynos_dp_device *dp,
+                       enum link_lane_count_type max_lane,
+                       enum link_rate_type max_rate)
+{
+       /*
+        * MACRO_RST must be applied after the PLL_LOCK to avoid
+        * the DP inter pair skew issue for at least 10 us
+        */
+       exynos_dp_reset_macro(dp);
+
+       /* Initialize by reading RX's DPCD */
+       exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
+       exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
+
+       if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
+          (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
+               dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
+                       dp->link_train.link_rate);
+               dp->link_train.link_rate = LINK_RATE_1_62GBPS;
+       }
+
+       if (dp->link_train.lane_count == 0) {
+               dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
+                       dp->link_train.lane_count);
+               dp->link_train.lane_count = (u8)LANE_COUNT1;
+       }
+
+       /* Setup TX lane count & rate */
+       if (dp->link_train.lane_count > max_lane)
+               dp->link_train.lane_count = max_lane;
+       if (dp->link_train.link_rate > max_rate)
+               dp->link_train.link_rate = max_rate;
+
+       /* All DP analog module power up */
+       exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
+}
+
+static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
+{
+       int retval = 0, training_finished = 0;
+
+       dp->link_train.lt_state = START;
+
+       /* Process here */
+       while (!retval && !training_finished) {
+               switch (dp->link_train.lt_state) {
+               case START:
+                       retval = exynos_dp_link_start(dp);
+                       if (retval)
+                               dev_err(dp->dev, "LT link start failed!\n");
+                       break;
+               case CLOCK_RECOVERY:
+                       retval = exynos_dp_process_clock_recovery(dp);
+                       if (retval)
+                               dev_err(dp->dev, "LT CR failed!\n");
+                       break;
+               case EQUALIZER_TRAINING:
+                       retval = exynos_dp_process_equalizer_training(dp);
+                       if (retval)
+                               dev_err(dp->dev, "LT EQ failed!\n");
+                       break;
+               case FINISHED:
+                       training_finished = 1;
+                       break;
+               case FAILED:
+                       return -EREMOTEIO;
+               }
+       }
+       if (retval)
+               dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
+
+       return retval;
+}
+
+static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
+                               u32 count,
+                               u32 bwtype)
+{
+       int i;
+       int retval;
+
+       for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
+               exynos_dp_init_training(dp, count, bwtype);
+               retval = exynos_dp_sw_link_training(dp);
+               if (retval == 0)
+                       break;
+
+               usleep_range(100, 110);
+       }
+
+       return retval;
+}
+
+static int exynos_dp_config_video(struct exynos_dp_device *dp)
+{
+       int retval = 0;
+       int timeout_loop = 0;
+       int done_count = 0;
+
+       exynos_dp_config_video_slave_mode(dp);
+
+       exynos_dp_set_video_color_format(dp);
+
+       if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+               dev_err(dp->dev, "PLL is not locked yet.\n");
+               return -EINVAL;
+       }
+
+       for (;;) {
+               timeout_loop++;
+               if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
+                       break;
+               if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+                       dev_err(dp->dev, "Timeout of video streamclk ok\n");
+                       return -ETIMEDOUT;
+               }
+
+               usleep_range(1, 2);
+       }
+
+       /* Set to use the register calculated M/N video */
+       exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
+
+       /* For video bist, Video timing must be generated by register */
+       exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
+
+       /* Disable video mute */
+       exynos_dp_enable_video_mute(dp, 0);
+
+       /* Configure video slave mode */
+       exynos_dp_enable_video_master(dp, 0);
+
+       /* Enable video */
+       exynos_dp_start_video(dp);
+
+       timeout_loop = 0;
+
+       for (;;) {
+               timeout_loop++;
+               if (exynos_dp_is_video_stream_on(dp) == 0) {
+                       done_count++;
+                       if (done_count > 10)
+                               break;
+               } else if (done_count) {
+                       done_count = 0;
+               }
+               if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+                       dev_err(dp->dev, "Timeout of video streamclk ok\n");
+                       return -ETIMEDOUT;
+               }
+
+               usleep_range(1000, 1001);
+       }
+
+       if (retval != 0)
+               dev_err(dp->dev, "Video stream is not detected!\n");
+
+       return retval;
+}
+
+static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
+{
+       u8 data;
+
+       if (enable) {
+               exynos_dp_enable_scrambling(dp);
+
+               exynos_dp_read_byte_from_dpcd(dp,
+                       DPCD_ADDR_TRAINING_PATTERN_SET,
+                       &data);
+               exynos_dp_write_byte_to_dpcd(dp,
+                       DPCD_ADDR_TRAINING_PATTERN_SET,
+                       (u8)(data & ~DPCD_SCRAMBLING_DISABLED));
+       } else {
+               exynos_dp_disable_scrambling(dp);
+
+               exynos_dp_read_byte_from_dpcd(dp,
+                       DPCD_ADDR_TRAINING_PATTERN_SET,
+                       &data);
+               exynos_dp_write_byte_to_dpcd(dp,
+                       DPCD_ADDR_TRAINING_PATTERN_SET,
+                       (u8)(data | DPCD_SCRAMBLING_DISABLED));
+       }
+}
+
+static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
+{
+       struct exynos_dp_device *dp = arg;
+
+       enum dp_irq_type irq_type;
+
+       irq_type = exynos_dp_get_irq_type(dp);
+       switch (irq_type) {
+       case DP_IRQ_TYPE_HP_CABLE_IN:
+               dev_dbg(dp->dev, "Received irq - cable in\n");
+               schedule_work(&dp->hotplug_work);
+               exynos_dp_clear_hotplug_interrupts(dp);
+               break;
+       case DP_IRQ_TYPE_HP_CABLE_OUT:
+               dev_dbg(dp->dev, "Received irq - cable out\n");
+               exynos_dp_clear_hotplug_interrupts(dp);
+               break;
+       case DP_IRQ_TYPE_HP_CHANGE:
+               /*
+                * We get these change notifications once in a while, but there
+                * is nothing we can do with them. Just ignore it for now and
+                * only handle cable changes.
+                */
+               dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
+               exynos_dp_clear_hotplug_interrupts(dp);
+               break;
+       default:
+               dev_err(dp->dev, "Received irq - unknown type!\n");
+               break;
+       }
+       return IRQ_HANDLED;
+}
+
+static void exynos_dp_hotplug(struct work_struct *work)
+{
+       struct exynos_dp_device *dp;
+       int ret;
+
+       dp = container_of(work, struct exynos_dp_device, hotplug_work);
+
+       ret = exynos_dp_detect_hpd(dp);
+       if (ret) {
+               /* Cable has been disconnected, we're done */
+               return;
+       }
+
+       ret = exynos_dp_handle_edid(dp);
+       if (ret) {
+               dev_err(dp->dev, "unable to handle edid\n");
+               return;
+       }
+
+       ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
+                                       dp->video_info->link_rate);
+       if (ret) {
+               dev_err(dp->dev, "unable to do link train\n");
+               return;
+       }
+
+       exynos_dp_enable_scramble(dp, 1);
+       exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
+       exynos_dp_enable_enhanced_mode(dp, 1);
+
+       exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
+       exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
+
+       exynos_dp_init_video(dp);
+       ret = exynos_dp_config_video(dp);
+       if (ret)
+               dev_err(dp->dev, "unable to config video\n");
+}
+
+static enum drm_connector_status exynos_dp_detect(
+                               struct drm_connector *connector, bool force)
+{
+       return connector_status_connected;
+}
+
+static void exynos_dp_connector_destroy(struct drm_connector *connector)
+{
+}
+
+static struct drm_connector_funcs exynos_dp_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = exynos_dp_detect,
+       .destroy = exynos_dp_connector_destroy,
+};
+
+static int exynos_dp_get_modes(struct drm_connector *connector)
+{
+       struct exynos_dp_device *dp = ctx_from_connector(connector);
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_create(connector->dev);
+       if (!mode) {
+               DRM_ERROR("failed to create a new display mode.\n");
+               return 0;
+       }
+
+       drm_display_mode_from_videomode(&dp->panel.vm, mode);
+       mode->width_mm = dp->panel.width_mm;
+       mode->height_mm = dp->panel.height_mm;
+       connector->display_info.width_mm = mode->width_mm;
+       connector->display_info.height_mm = mode->height_mm;
+
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+       drm_mode_set_name(mode);
+       drm_mode_probed_add(connector, mode);
+
+       return 1;
+}
+
+static int exynos_dp_mode_valid(struct drm_connector *connector,
+                       struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static struct drm_encoder *exynos_dp_best_encoder(
+                       struct drm_connector *connector)
+{
+       struct exynos_dp_device *dp = ctx_from_connector(connector);
+
+       return dp->encoder;
+}
+
+static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
+       .get_modes = exynos_dp_get_modes,
+       .mode_valid = exynos_dp_mode_valid,
+       .best_encoder = exynos_dp_best_encoder,
+};
+
+static int exynos_dp_initialize(struct exynos_drm_display *display,
+                               struct drm_device *drm_dev)
+{
+       struct exynos_dp_device *dp = display->ctx;
+
+       dp->drm_dev = drm_dev;
+
+       return 0;
+}
+
+static bool find_bridge(const char *compat, struct bridge_init *bridge)
+{
+       bridge->client = NULL;
+       bridge->node = of_find_compatible_node(NULL, NULL, compat);
+       if (!bridge->node)
+               return false;
+
+       bridge->client = of_find_i2c_device_by_node(bridge->node);
+       if (!bridge->client)
+               return false;
+
+       return true;
+}
+
+/* returns the number of bridges attached */
+static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
+               struct drm_encoder *encoder)
+{
+       struct bridge_init bridge;
+       int ret;
+
+       if (find_bridge("nxp,ptn3460", &bridge)) {
+               ret = ptn3460_init(dev, encoder, bridge.client, bridge.node);
+               if (!ret)
+                       return 1;
+       }
+       return 0;
+}
+
+static int exynos_dp_create_connector(struct exynos_drm_display *display,
+                               struct drm_encoder *encoder)
+{
+       struct exynos_dp_device *dp = display->ctx;
+       struct drm_connector *connector = &dp->connector;
+       int ret;
+
+       dp->encoder = encoder;
+
+       /* Pre-empt DP connector creation if there's a bridge */
+       ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder);
+       if (ret)
+               return 0;
+
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+       ret = drm_connector_init(dp->drm_dev, connector,
+                       &exynos_dp_connector_funcs, DRM_MODE_CONNECTOR_eDP);
+       if (ret) {
+               DRM_ERROR("Failed to initialize connector with drm\n");
+               return ret;
+       }
+
+       drm_connector_helper_add(connector, &exynos_dp_connector_helper_funcs);
+       drm_sysfs_connector_add(connector);
+       drm_mode_connector_attach_encoder(connector, encoder);
+
+       return 0;
+}
+
+static void exynos_dp_phy_init(struct exynos_dp_device *dp)
+{
+       if (dp->phy) {
+               phy_power_on(dp->phy);
+       } else if (dp->phy_addr) {
+               u32 reg;
+
+               reg = __raw_readl(dp->phy_addr);
+               reg |= dp->enable_mask;
+               __raw_writel(reg, dp->phy_addr);
+       }
+}
+
+static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
+{
+       if (dp->phy) {
+               phy_power_off(dp->phy);
+       } else if (dp->phy_addr) {
+               u32 reg;
+
+               reg = __raw_readl(dp->phy_addr);
+               reg &= ~(dp->enable_mask);
+               __raw_writel(reg, dp->phy_addr);
+       }
+}
+
+static void exynos_dp_poweron(struct exynos_dp_device *dp)
+{
+       if (dp->dpms_mode == DRM_MODE_DPMS_ON)
+               return;
+
+       clk_prepare_enable(dp->clock);
+       exynos_dp_phy_init(dp);
+       exynos_dp_init_dp(dp);
+       enable_irq(dp->irq);
+}
+
+static void exynos_dp_poweroff(struct exynos_dp_device *dp)
+{
+       if (dp->dpms_mode != DRM_MODE_DPMS_ON)
+               return;
+
+       disable_irq(dp->irq);
+       flush_work(&dp->hotplug_work);
+       exynos_dp_phy_exit(dp);
+       clk_disable_unprepare(dp->clock);
+}
+
+static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
+{
+       struct exynos_dp_device *dp = display->ctx;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               exynos_dp_poweron(dp);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               exynos_dp_poweroff(dp);
+               break;
+       default:
+               break;
+       };
+       dp->dpms_mode = mode;
+}
+
+static struct exynos_drm_display_ops exynos_dp_display_ops = {
+       .initialize = exynos_dp_initialize,
+       .create_connector = exynos_dp_create_connector,
+       .dpms = exynos_dp_dpms,
+};
+
+static struct exynos_drm_display exynos_dp_display = {
+       .type = EXYNOS_DISPLAY_TYPE_LCD,
+       .ops = &exynos_dp_display_ops,
+};
+
+static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
+{
+       struct device_node *dp_node = dev->of_node;
+       struct video_info *dp_video_config;
+
+       dp_video_config = devm_kzalloc(dev,
+                               sizeof(*dp_video_config), GFP_KERNEL);
+       if (!dp_video_config) {
+               dev_err(dev, "memory allocation for video config failed\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       dp_video_config->h_sync_polarity =
+               of_property_read_bool(dp_node, "hsync-active-high");
+
+       dp_video_config->v_sync_polarity =
+               of_property_read_bool(dp_node, "vsync-active-high");
+
+       dp_video_config->interlaced =
+               of_property_read_bool(dp_node, "interlaced");
+
+       if (of_property_read_u32(dp_node, "samsung,color-space",
+                               &dp_video_config->color_space)) {
+               dev_err(dev, "failed to get color-space\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (of_property_read_u32(dp_node, "samsung,dynamic-range",
+                               &dp_video_config->dynamic_range)) {
+               dev_err(dev, "failed to get dynamic-range\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
+                               &dp_video_config->ycbcr_coeff)) {
+               dev_err(dev, "failed to get ycbcr-coeff\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (of_property_read_u32(dp_node, "samsung,color-depth",
+                               &dp_video_config->color_depth)) {
+               dev_err(dev, "failed to get color-depth\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (of_property_read_u32(dp_node, "samsung,link-rate",
+                               &dp_video_config->link_rate)) {
+               dev_err(dev, "failed to get link-rate\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (of_property_read_u32(dp_node, "samsung,lane-count",
+                               &dp_video_config->lane_count)) {
+               dev_err(dev, "failed to get lane-count\n");
+               return ERR_PTR(-EINVAL);
+       }
+
+       return dp_video_config;
+}
+
+static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
+{
+       struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
+       u32 phy_base;
+       int ret = 0;
+
+       dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
+       if (!dp_phy_node) {
+               dp->phy = devm_phy_get(dp->dev, "dp");
+               if (IS_ERR(dp->phy))
+                       return PTR_ERR(dp->phy);
+               else
+                       return 0;
+       }
+
+       if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
+               dev_err(dp->dev, "failed to get reg for dptx-phy\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
+                               &dp->enable_mask)) {
+               dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
+               ret = -EINVAL;
+               goto err;
+       }
+
+       dp->phy_addr = ioremap(phy_base, SZ_4);
+       if (!dp->phy_addr) {
+               dev_err(dp->dev, "failed to ioremap dp-phy\n");
+               ret = -ENOMEM;
+               goto err;
+       }
+
+err:
+       of_node_put(dp_phy_node);
+
+       return ret;
+}
+
+static int exynos_dp_dt_parse_panel(struct exynos_dp_device *dp)
+{
+       int ret;
+
+       ret = of_get_videomode(dp->dev->of_node, &dp->panel.vm,
+                       OF_USE_NATIVE_MODE);
+       if (ret) {
+               DRM_ERROR("failed: of_get_videomode() : %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static int exynos_dp_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct exynos_dp_device *dp;
+
+       int ret = 0;
+
+       dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
+                               GFP_KERNEL);
+       if (!dp) {
+               dev_err(&pdev->dev, "no memory for device data\n");
+               return -ENOMEM;
+       }
+
+       dp->dev = &pdev->dev;
+       dp->dpms_mode = DRM_MODE_DPMS_OFF;
+
+       dp->video_info = exynos_dp_dt_parse_pdata(&pdev->dev);
+       if (IS_ERR(dp->video_info))
+               return PTR_ERR(dp->video_info);
+
+       ret = exynos_dp_dt_parse_phydata(dp);
+       if (ret)
+               return ret;
+
+       ret = exynos_dp_dt_parse_panel(dp);
+       if (ret)
+               return ret;
+
+       dp->clock = devm_clk_get(&pdev->dev, "dp");
+       if (IS_ERR(dp->clock)) {
+               dev_err(&pdev->dev, "failed to get clock\n");
+               return PTR_ERR(dp->clock);
+       }
+
+       clk_prepare_enable(dp->clock);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+       dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(dp->reg_base))
+               return PTR_ERR(dp->reg_base);
+
+       dp->irq = platform_get_irq(pdev, 0);
+       if (dp->irq == -ENXIO) {
+               dev_err(&pdev->dev, "failed to get irq\n");
+               return -ENODEV;
+       }
+
+       INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
+
+       exynos_dp_phy_init(dp);
+
+       exynos_dp_init_dp(dp);
+
+       ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
+                               "exynos-dp", dp);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request irq\n");
+               return ret;
+       }
+       disable_irq(dp->irq);
+
+       exynos_dp_display.ctx = dp;
+
+       platform_set_drvdata(pdev, &exynos_dp_display);
+       exynos_drm_display_register(&exynos_dp_display);
+
+       return 0;
+}
+
+static int exynos_dp_remove(struct platform_device *pdev)
+{
+       struct exynos_drm_display *display = platform_get_drvdata(pdev);
+
+       exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
+       exynos_drm_display_unregister(&exynos_dp_display);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int exynos_dp_suspend(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct exynos_drm_display *display = platform_get_drvdata(pdev);
+
+       exynos_dp_dpms(display, DRM_MODE_DPMS_OFF);
+       return 0;
+}
+
+static int exynos_dp_resume(struct device *dev)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       struct exynos_drm_display *display = platform_get_drvdata(pdev);
+
+       exynos_dp_dpms(display, DRM_MODE_DPMS_ON);
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_dp_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
+};
+
+static const struct of_device_id exynos_dp_match[] = {
+       { .compatible = "samsung,exynos5-dp" },
+       {},
+};
+
+struct platform_driver dp_driver = {
+       .probe          = exynos_dp_probe,
+       .remove         = exynos_dp_remove,
+       .driver         = {
+               .name   = "exynos-dp",
+               .owner  = THIS_MODULE,
+               .pm     = &exynos_dp_pm_ops,
+               .of_match_table = exynos_dp_match,
+       },
+};
+
+MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC DP Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
new file mode 100644 (file)
index 0000000..d6a900d
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ * Header file for Samsung DP (Display Port) interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _EXYNOS_DP_CORE_H
+#define _EXYNOS_DP_CORE_H
+
+#include <drm/drm_crtc.h>
+#include <drm/exynos_drm.h>
+
+#define DP_TIMEOUT_LOOP_COUNT 100
+#define MAX_CR_LOOP 5
+#define MAX_EQ_LOOP 5
+
+enum link_rate_type {
+       LINK_RATE_1_62GBPS = 0x06,
+       LINK_RATE_2_70GBPS = 0x0a
+};
+
+enum link_lane_count_type {
+       LANE_COUNT1 = 1,
+       LANE_COUNT2 = 2,
+       LANE_COUNT4 = 4
+};
+
+enum link_training_state {
+       START,
+       CLOCK_RECOVERY,
+       EQUALIZER_TRAINING,
+       FINISHED,
+       FAILED
+};
+
+enum voltage_swing_level {
+       VOLTAGE_LEVEL_0,
+       VOLTAGE_LEVEL_1,
+       VOLTAGE_LEVEL_2,
+       VOLTAGE_LEVEL_3,
+};
+
+enum pre_emphasis_level {
+       PRE_EMPHASIS_LEVEL_0,
+       PRE_EMPHASIS_LEVEL_1,
+       PRE_EMPHASIS_LEVEL_2,
+       PRE_EMPHASIS_LEVEL_3,
+};
+
+enum pattern_set {
+       PRBS7,
+       D10_2,
+       TRAINING_PTN1,
+       TRAINING_PTN2,
+       DP_NONE
+};
+
+enum color_space {
+       COLOR_RGB,
+       COLOR_YCBCR422,
+       COLOR_YCBCR444
+};
+
+enum color_depth {
+       COLOR_6,
+       COLOR_8,
+       COLOR_10,
+       COLOR_12
+};
+
+enum color_coefficient {
+       COLOR_YCBCR601,
+       COLOR_YCBCR709
+};
+
+enum dynamic_range {
+       VESA,
+       CEA
+};
+
+enum pll_status {
+       PLL_UNLOCKED,
+       PLL_LOCKED
+};
+
+enum clock_recovery_m_value_type {
+       CALCULATED_M,
+       REGISTER_M
+};
+
+enum video_timing_recognition_type {
+       VIDEO_TIMING_FROM_CAPTURE,
+       VIDEO_TIMING_FROM_REGISTER
+};
+
+enum analog_power_block {
+       AUX_BLOCK,
+       CH0_BLOCK,
+       CH1_BLOCK,
+       CH2_BLOCK,
+       CH3_BLOCK,
+       ANALOG_TOTAL,
+       POWER_ALL
+};
+
+enum dp_irq_type {
+       DP_IRQ_TYPE_HP_CABLE_IN,
+       DP_IRQ_TYPE_HP_CABLE_OUT,
+       DP_IRQ_TYPE_HP_CHANGE,
+       DP_IRQ_TYPE_UNKNOWN,
+};
+
+struct video_info {
+       char *name;
+
+       bool h_sync_polarity;
+       bool v_sync_polarity;
+       bool interlaced;
+
+       enum color_space color_space;
+       enum dynamic_range dynamic_range;
+       enum color_coefficient ycbcr_coeff;
+       enum color_depth color_depth;
+
+       enum link_rate_type link_rate;
+       enum link_lane_count_type lane_count;
+};
+
+struct link_train {
+       int eq_loop;
+       int cr_loop[4];
+
+       u8 link_rate;
+       u8 lane_count;
+       u8 training_lane[4];
+
+       enum link_training_state lt_state;
+};
+
+struct exynos_dp_device {
+       struct device           *dev;
+       struct drm_device       *drm_dev;
+       struct drm_connector    connector;
+       struct drm_encoder      *encoder;
+       struct clk              *clock;
+       unsigned int            irq;
+       void __iomem            *reg_base;
+       void __iomem            *phy_addr;
+       unsigned int            enable_mask;
+
+       struct video_info       *video_info;
+       struct link_train       link_train;
+       struct work_struct      hotplug_work;
+       struct phy              *phy;
+       int                     dpms_mode;
+
+       struct exynos_drm_panel_info panel;
+};
+
+/* exynos_dp_reg.c */
+void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_stop_video(struct exynos_dp_device *dp);
+void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_init_analog_param(struct exynos_dp_device *dp);
+void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
+void exynos_dp_reset(struct exynos_dp_device *dp);
+void exynos_dp_swreset(struct exynos_dp_device *dp);
+void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
+enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
+void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
+                               enum analog_power_block block,
+                               bool enable);
+void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
+void exynos_dp_init_hpd(struct exynos_dp_device *dp);
+enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp);
+void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp);
+void exynos_dp_reset_aux(struct exynos_dp_device *dp);
+void exynos_dp_init_aux(struct exynos_dp_device *dp);
+int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
+void exynos_dp_enable_sw_function(struct exynos_dp_device *dp);
+int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp);
+int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
+                               unsigned int reg_addr,
+                               unsigned char data);
+int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
+                               unsigned int reg_addr,
+                               unsigned char *data);
+int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
+                               unsigned int reg_addr,
+                               unsigned int count,
+                               unsigned char data[]);
+int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
+                               unsigned int reg_addr,
+                               unsigned int count,
+                               unsigned char data[]);
+int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
+                               unsigned int device_addr,
+                               unsigned int reg_addr);
+int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
+                               unsigned int device_addr,
+                               unsigned int reg_addr,
+                               unsigned int *data);
+int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
+                               unsigned int device_addr,
+                               unsigned int reg_addr,
+                               unsigned int count,
+                               unsigned char edid[]);
+void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
+void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
+void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
+void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
+void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
+                                enum pattern_set pattern);
+void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level);
+void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
+                               u32 training_lane);
+void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
+                               u32 training_lane);
+void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
+                               u32 training_lane);
+void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
+                               u32 training_lane);
+u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
+u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
+void exynos_dp_reset_macro(struct exynos_dp_device *dp);
+void exynos_dp_init_video(struct exynos_dp_device *dp);
+
+void exynos_dp_set_video_color_format(struct exynos_dp_device *dp);
+int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp);
+void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
+                       enum clock_recovery_m_value_type type,
+                       u32 m_value,
+                       u32 n_value);
+void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type);
+void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable);
+void exynos_dp_start_video(struct exynos_dp_device *dp);
+int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp);
+void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp);
+void exynos_dp_enable_scrambling(struct exynos_dp_device *dp);
+void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
+
+/* I2C EDID Chip ID, Slave Address */
+#define I2C_EDID_DEVICE_ADDR                   0x50
+#define I2C_E_EDID_DEVICE_ADDR                 0x30
+
+#define EDID_BLOCK_LENGTH                      0x80
+#define EDID_HEADER_PATTERN                    0x00
+#define EDID_EXTENSION_FLAG                    0x7e
+#define EDID_CHECKSUM                          0x7f
+
+/* Definition for DPCD Register */
+#define DPCD_ADDR_DPCD_REV                     0x0000
+#define DPCD_ADDR_MAX_LINK_RATE                        0x0001
+#define DPCD_ADDR_MAX_LANE_COUNT               0x0002
+#define DPCD_ADDR_LINK_BW_SET                  0x0100
+#define DPCD_ADDR_LANE_COUNT_SET               0x0101
+#define DPCD_ADDR_TRAINING_PATTERN_SET         0x0102
+#define DPCD_ADDR_TRAINING_LANE0_SET           0x0103
+#define DPCD_ADDR_LANE0_1_STATUS               0x0202
+#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED    0x0204
+#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1       0x0206
+#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3       0x0207
+#define DPCD_ADDR_TEST_REQUEST                 0x0218
+#define DPCD_ADDR_TEST_RESPONSE                        0x0260
+#define DPCD_ADDR_TEST_EDID_CHECKSUM           0x0261
+#define DPCD_ADDR_SINK_POWER_STATE             0x0600
+
+/* DPCD_ADDR_MAX_LANE_COUNT */
+#define DPCD_ENHANCED_FRAME_CAP(x)             (((x) >> 7) & 0x1)
+#define DPCD_MAX_LANE_COUNT(x)                 ((x) & 0x1f)
+
+/* DPCD_ADDR_LANE_COUNT_SET */
+#define DPCD_ENHANCED_FRAME_EN                 (0x1 << 7)
+#define DPCD_LANE_COUNT_SET(x)                 ((x) & 0x1f)
+
+/* DPCD_ADDR_TRAINING_PATTERN_SET */
+#define DPCD_SCRAMBLING_DISABLED               (0x1 << 5)
+#define DPCD_SCRAMBLING_ENABLED                        (0x0 << 5)
+#define DPCD_TRAINING_PATTERN_2                        (0x2 << 0)
+#define DPCD_TRAINING_PATTERN_1                        (0x1 << 0)
+#define DPCD_TRAINING_PATTERN_DISABLED         (0x0 << 0)
+
+/* DPCD_ADDR_TRAINING_LANE0_SET */
+#define DPCD_MAX_PRE_EMPHASIS_REACHED          (0x1 << 5)
+#define DPCD_PRE_EMPHASIS_SET(x)               (((x) & 0x3) << 3)
+#define DPCD_PRE_EMPHASIS_GET(x)               (((x) >> 3) & 0x3)
+#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0      (0x0 << 3)
+#define DPCD_MAX_SWING_REACHED                 (0x1 << 2)
+#define DPCD_VOLTAGE_SWING_SET(x)              (((x) & 0x3) << 0)
+#define DPCD_VOLTAGE_SWING_GET(x)              (((x) >> 0) & 0x3)
+#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0     (0x0 << 0)
+
+/* DPCD_ADDR_LANE0_1_STATUS */
+#define DPCD_LANE_SYMBOL_LOCKED                        (0x1 << 2)
+#define DPCD_LANE_CHANNEL_EQ_DONE              (0x1 << 1)
+#define DPCD_LANE_CR_DONE                      (0x1 << 0)
+#define DPCD_CHANNEL_EQ_BITS                   (DPCD_LANE_CR_DONE|     \
+                                                DPCD_LANE_CHANNEL_EQ_DONE|\
+                                                DPCD_LANE_SYMBOL_LOCKED)
+
+/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
+#define DPCD_LINK_STATUS_UPDATED               (0x1 << 7)
+#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED    (0x1 << 6)
+#define DPCD_INTERLANE_ALIGN_DONE              (0x1 << 0)
+
+/* DPCD_ADDR_TEST_REQUEST */
+#define DPCD_TEST_EDID_READ                    (0x1 << 2)
+
+/* DPCD_ADDR_TEST_RESPONSE */
+#define DPCD_TEST_EDID_CHECKSUM_WRITE          (0x1 << 2)
+
+/* DPCD_ADDR_SINK_POWER_STATE */
+#define DPCD_SET_POWER_STATE_D0                        (0x1 << 0)
+#define DPCD_SET_POWER_STATE_D4                        (0x2 << 0)
+
+#endif /* _EXYNOS_DP_CORE_H */
diff --git a/drivers/gpu/drm/exynos/exynos_dp_reg.c b/drivers/gpu/drm/exynos/exynos_dp_reg.c
new file mode 100644 (file)
index 0000000..b70da50
--- /dev/null
@@ -0,0 +1,1243 @@
+/*
+ * Samsung DP (Display port) register interface driver.
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "exynos_dp_core.h"
+#include "exynos_dp_reg.h"
+
+#define COMMON_INT_MASK_1      0
+#define COMMON_INT_MASK_2      0
+#define COMMON_INT_MASK_3      0
+#define COMMON_INT_MASK_4      (HOTPLUG_CHG | HPD_LOST | PLUG)
+#define INT_STA_MASK           INT_HPD
+
+void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable)
+{
+       u32 reg;
+
+       if (enable) {
+               reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+               reg |= HDCP_VIDEO_MUTE;
+               writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+       } else {
+               reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+               reg &= ~HDCP_VIDEO_MUTE;
+               writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+       }
+}
+
+void exynos_dp_stop_video(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+       reg &= ~VIDEO_EN;
+       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+}
+
+void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable)
+{
+       u32 reg;
+
+       if (enable)
+               reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
+                       LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
+       else
+               reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
+                       LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
+
+       writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP);
+}
+
+void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = TX_TERMINAL_CTRL_50_OHM;
+       writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1);
+
+       reg = SEL_24M | TX_DVDD_BIT_1_0625V;
+       writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2);
+
+       reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
+       writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
+
+       reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
+               TX_CUR1_2X | TX_CUR_16_MA;
+       writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
+
+       reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
+               CH1_AMP_400_MV | CH0_AMP_400_MV;
+       writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL);
+}
+
+void exynos_dp_init_interrupt(struct exynos_dp_device *dp)
+{
+       /* Set interrupt pin assertion polarity as high */
+       writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL);
+
+       /* Clear pending regisers */
+       writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+       writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2);
+       writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3);
+       writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+       writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA);
+
+       /* 0:mask,1: unmask */
+       writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
+       writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
+       writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
+       writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
+       writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
+}
+
+void exynos_dp_reset(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       exynos_dp_stop_video(dp);
+       exynos_dp_enable_video_mute(dp, 0);
+
+       reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
+               AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
+               HDCP_FUNC_EN_N | SW_FUNC_EN_N;
+       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+
+       reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
+               SERDES_FIFO_FUNC_EN_N |
+               LS_CLK_DOMAIN_FUNC_EN_N;
+       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+
+       usleep_range(20, 30);
+
+       exynos_dp_lane_swap(dp, 0);
+
+       writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+       writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+       writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+       writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+
+       writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL);
+       writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL);
+
+       writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L);
+       writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H);
+
+       writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL);
+
+       writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST);
+
+       writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD);
+       writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN);
+
+       writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH);
+       writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH);
+
+       writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+}
+
+void exynos_dp_swreset(struct exynos_dp_device *dp)
+{
+       writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET);
+}
+
+void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       /* 0: mask, 1: unmask */
+       reg = COMMON_INT_MASK_1;
+       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
+
+       reg = COMMON_INT_MASK_2;
+       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
+
+       reg = COMMON_INT_MASK_3;
+       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
+
+       reg = COMMON_INT_MASK_4;
+       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
+
+       reg = INT_STA_MASK;
+       writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
+}
+
+enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+       if (reg & PLL_LOCK)
+               return PLL_LOCKED;
+       else
+               return PLL_UNLOCKED;
+}
+
+void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable)
+{
+       u32 reg;
+
+       if (enable) {
+               reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
+               reg |= DP_PLL_PD;
+               writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
+       } else {
+               reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
+               reg &= ~DP_PLL_PD;
+               writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
+       }
+}
+
+void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
+                               enum analog_power_block block,
+                               bool enable)
+{
+       u32 reg;
+
+       switch (block) {
+       case AUX_BLOCK:
+               if (enable) {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg |= AUX_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               } else {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg &= ~AUX_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               }
+               break;
+       case CH0_BLOCK:
+               if (enable) {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg |= CH0_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               } else {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg &= ~CH0_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               }
+               break;
+       case CH1_BLOCK:
+               if (enable) {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg |= CH1_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               } else {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg &= ~CH1_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               }
+               break;
+       case CH2_BLOCK:
+               if (enable) {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg |= CH2_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               } else {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg &= ~CH2_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               }
+               break;
+       case CH3_BLOCK:
+               if (enable) {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg |= CH3_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               } else {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg &= ~CH3_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               }
+               break;
+       case ANALOG_TOTAL:
+               if (enable) {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg |= DP_PHY_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               } else {
+                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
+                       reg &= ~DP_PHY_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               }
+               break;
+       case POWER_ALL:
+               if (enable) {
+                       reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
+                               CH1_PD | CH0_PD;
+                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
+               } else {
+                       writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD);
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
+{
+       u32 reg;
+       int timeout_loop = 0;
+
+       exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
+
+       reg = PLL_LOCK_CHG;
+       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+
+       reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+       reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
+       writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL);
+
+       /* Power up PLL */
+       if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+               exynos_dp_set_pll_power_down(dp, 0);
+
+               while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
+                       timeout_loop++;
+                       if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+                               dev_err(dp->dev, "failed to get pll lock status\n");
+                               return;
+                       }
+                       usleep_range(10, 20);
+               }
+       }
+
+       /* Enable Serdes FIFO function and Link symbol clock domain module */
+       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+       reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
+               | AUX_FUNC_EN_N);
+       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = HOTPLUG_CHG | HPD_LOST | PLUG;
+       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+
+       reg = INT_HPD;
+       writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
+}
+
+void exynos_dp_init_hpd(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       exynos_dp_clear_hotplug_interrupts(dp);
+
+       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+       reg &= ~(F_HPD | HPD_CTRL);
+       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+}
+
+enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       /* Parse hotplug interrupt status register */
+       reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
+
+       if (reg & PLUG)
+               return DP_IRQ_TYPE_HP_CABLE_IN;
+
+       if (reg & HPD_LOST)
+               return DP_IRQ_TYPE_HP_CABLE_OUT;
+
+       if (reg & HOTPLUG_CHG)
+               return DP_IRQ_TYPE_HP_CHANGE;
+
+       return DP_IRQ_TYPE_UNKNOWN;
+}
+
+void exynos_dp_reset_aux(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       /* Disable AUX channel module */
+       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+       reg |= AUX_FUNC_EN_N;
+       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+void exynos_dp_init_aux(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       /* Clear inerrupts related to AUX channel */
+       reg = RPLY_RECEIV | AUX_ERR;
+       writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
+
+       exynos_dp_reset_aux(dp);
+
+       /* Disable AUX transaction H/W retry */
+       reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)|
+               AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
+       writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ;
+
+       /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
+       reg = DEFER_CTRL_EN | DEFER_COUNT(1);
+       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL);
+
+       /* Enable AUX channel module */
+       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+       reg &= ~AUX_FUNC_EN_N;
+       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
+}
+
+int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+       if (reg & HPD_STATUS)
+               return 0;
+
+       return -EINVAL;
+}
+
+void exynos_dp_enable_sw_function(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+       reg &= ~SW_FUNC_EN_N;
+       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+}
+
+int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
+{
+       int reg;
+       int retval = 0;
+       int timeout_loop = 0;
+
+       /* Enable AUX CH operation */
+       reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+       reg |= AUX_EN;
+       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+
+       /* Is AUX CH command reply received? */
+       reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+       while (!(reg & RPLY_RECEIV)) {
+               timeout_loop++;
+               if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
+                       dev_err(dp->dev, "AUX CH command reply failed!\n");
+                       return -ETIMEDOUT;
+               }
+               reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+               usleep_range(10, 11);
+       }
+
+       /* Clear interrupt source for AUX CH command reply */
+       writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA);
+
+       /* Clear interrupt source for AUX CH access error */
+       reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
+       if (reg & AUX_ERR) {
+               writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA);
+               return -EREMOTEIO;
+       }
+
+       /* Check AUX CH error access status */
+       reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA);
+       if ((reg & AUX_STATUS_MASK) != 0) {
+               dev_err(dp->dev, "AUX CH error happens: %d\n\n",
+                       reg & AUX_STATUS_MASK);
+               return -EREMOTEIO;
+       }
+
+       return retval;
+}
+
+int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
+                               unsigned int reg_addr,
+                               unsigned char data)
+{
+       u32 reg;
+       int i;
+       int retval;
+
+       for (i = 0; i < 3; i++) {
+               /* Clear AUX CH data buffer */
+               reg = BUF_CLR;
+               writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+               /* Select DPCD device address */
+               reg = AUX_ADDR_7_0(reg_addr);
+               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+               reg = AUX_ADDR_15_8(reg_addr);
+               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+               reg = AUX_ADDR_19_16(reg_addr);
+               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+               /* Write data buffer */
+               reg = (unsigned int)data;
+               writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+               /*
+                * Set DisplayPort transaction and write 1 byte
+                * If bit 3 is 1, DisplayPort transaction.
+                * If Bit 3 is 0, I2C transaction.
+                */
+               reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+               writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+               /* Start AUX transaction */
+               retval = exynos_dp_start_aux_transaction(dp);
+               if (retval == 0)
+                       break;
+               else
+                       dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+                               __func__);
+       }
+
+       return retval;
+}
+
+int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
+                               unsigned int reg_addr,
+                               unsigned char *data)
+{
+       u32 reg;
+       int i;
+       int retval;
+
+       for (i = 0; i < 3; i++) {
+               /* Clear AUX CH data buffer */
+               reg = BUF_CLR;
+               writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+               /* Select DPCD device address */
+               reg = AUX_ADDR_7_0(reg_addr);
+               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+               reg = AUX_ADDR_15_8(reg_addr);
+               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+               reg = AUX_ADDR_19_16(reg_addr);
+               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+               /*
+                * Set DisplayPort transaction and read 1 byte
+                * If bit 3 is 1, DisplayPort transaction.
+                * If Bit 3 is 0, I2C transaction.
+                */
+               reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+               writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+               /* Start AUX transaction */
+               retval = exynos_dp_start_aux_transaction(dp);
+               if (retval == 0)
+                       break;
+               else
+                       dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+                               __func__);
+       }
+
+       /* Read data buffer */
+       reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+       *data = (unsigned char)(reg & 0xff);
+
+       return retval;
+}
+
+int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
+                               unsigned int reg_addr,
+                               unsigned int count,
+                               unsigned char data[])
+{
+       u32 reg;
+       unsigned int start_offset;
+       unsigned int cur_data_count;
+       unsigned int cur_data_idx;
+       int i;
+       int retval = 0;
+
+       /* Clear AUX CH data buffer */
+       reg = BUF_CLR;
+       writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+       start_offset = 0;
+       while (start_offset < count) {
+               /* Buffer size of AUX CH is 16 * 4bytes */
+               if ((count - start_offset) > 16)
+                       cur_data_count = 16;
+               else
+                       cur_data_count = count - start_offset;
+
+               for (i = 0; i < 3; i++) {
+                       /* Select DPCD device address */
+                       reg = AUX_ADDR_7_0(reg_addr + start_offset);
+                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+                       reg = AUX_ADDR_15_8(reg_addr + start_offset);
+                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+                       reg = AUX_ADDR_19_16(reg_addr + start_offset);
+                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+                       for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+                            cur_data_idx++) {
+                               reg = data[start_offset + cur_data_idx];
+                               writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0
+                                                         + 4 * cur_data_idx);
+                       }
+
+                       /*
+                        * Set DisplayPort transaction and write
+                        * If bit 3 is 1, DisplayPort transaction.
+                        * If Bit 3 is 0, I2C transaction.
+                        */
+                       reg = AUX_LENGTH(cur_data_count) |
+                               AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
+                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+                       /* Start AUX transaction */
+                       retval = exynos_dp_start_aux_transaction(dp);
+                       if (retval == 0)
+                               break;
+                       else
+                               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+                                       __func__);
+               }
+
+               start_offset += cur_data_count;
+       }
+
+       return retval;
+}
+
+int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
+                               unsigned int reg_addr,
+                               unsigned int count,
+                               unsigned char data[])
+{
+       u32 reg;
+       unsigned int start_offset;
+       unsigned int cur_data_count;
+       unsigned int cur_data_idx;
+       int i;
+       int retval = 0;
+
+       /* Clear AUX CH data buffer */
+       reg = BUF_CLR;
+       writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+       start_offset = 0;
+       while (start_offset < count) {
+               /* Buffer size of AUX CH is 16 * 4bytes */
+               if ((count - start_offset) > 16)
+                       cur_data_count = 16;
+               else
+                       cur_data_count = count - start_offset;
+
+               /* AUX CH Request Transaction process */
+               for (i = 0; i < 3; i++) {
+                       /* Select DPCD device address */
+                       reg = AUX_ADDR_7_0(reg_addr + start_offset);
+                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+                       reg = AUX_ADDR_15_8(reg_addr + start_offset);
+                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+                       reg = AUX_ADDR_19_16(reg_addr + start_offset);
+                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+                       /*
+                        * Set DisplayPort transaction and read
+                        * If bit 3 is 1, DisplayPort transaction.
+                        * If Bit 3 is 0, I2C transaction.
+                        */
+                       reg = AUX_LENGTH(cur_data_count) |
+                               AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
+                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+                       /* Start AUX transaction */
+                       retval = exynos_dp_start_aux_transaction(dp);
+                       if (retval == 0)
+                               break;
+                       else
+                               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+                                       __func__);
+               }
+
+               for (cur_data_idx = 0; cur_data_idx < cur_data_count;
+                   cur_data_idx++) {
+                       reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
+                                                + 4 * cur_data_idx);
+                       data[start_offset + cur_data_idx] =
+                               (unsigned char)reg;
+               }
+
+               start_offset += cur_data_count;
+       }
+
+       return retval;
+}
+
+int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
+                               unsigned int device_addr,
+                               unsigned int reg_addr)
+{
+       u32 reg;
+       int retval;
+
+       /* Set EDID device address */
+       reg = device_addr;
+       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
+       writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
+       writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
+
+       /* Set offset from base address of EDID device */
+       writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+       /*
+        * Set I2C transaction and write address
+        * If bit 3 is 1, DisplayPort transaction.
+        * If Bit 3 is 0, I2C transaction.
+        */
+       reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
+               AUX_TX_COMM_WRITE;
+       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+       /* Start AUX transaction */
+       retval = exynos_dp_start_aux_transaction(dp);
+       if (retval != 0)
+               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
+
+       return retval;
+}
+
+int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
+                               unsigned int device_addr,
+                               unsigned int reg_addr,
+                               unsigned int *data)
+{
+       u32 reg;
+       int i;
+       int retval;
+
+       for (i = 0; i < 3; i++) {
+               /* Clear AUX CH data buffer */
+               reg = BUF_CLR;
+               writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+               /* Select EDID device */
+               retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr);
+               if (retval != 0)
+                       continue;
+
+               /*
+                * Set I2C transaction and read data
+                * If bit 3 is 1, DisplayPort transaction.
+                * If Bit 3 is 0, I2C transaction.
+                */
+               reg = AUX_TX_COMM_I2C_TRANSACTION |
+                       AUX_TX_COMM_READ;
+               writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
+
+               /* Start AUX transaction */
+               retval = exynos_dp_start_aux_transaction(dp);
+               if (retval == 0)
+                       break;
+               else
+                       dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
+                               __func__);
+       }
+
+       /* Read data */
+       if (retval == 0)
+               *data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
+
+       return retval;
+}
+
+int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
+                               unsigned int device_addr,
+                               unsigned int reg_addr,
+                               unsigned int count,
+                               unsigned char edid[])
+{
+       u32 reg;
+       unsigned int i, j;
+       unsigned int cur_data_idx;
+       unsigned int defer = 0;
+       int retval = 0;
+
+       for (i = 0; i < count; i += 16) {
+               for (j = 0; j < 3; j++) {
+                       /* Clear AUX CH data buffer */
+                       reg = BUF_CLR;
+                       writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
+
+                       /* Set normal AUX CH command */
+                       reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+                       reg &= ~ADDR_ONLY;
+                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
+
+                       /*
+                        * If Rx sends defer, Tx sends only reads
+                        * request without sending address
+                        */
+                       if (!defer)
+                               retval = exynos_dp_select_i2c_device(dp,
+                                               device_addr, reg_addr + i);
+                       else
+                               defer = 0;
+
+                       if (retval == 0) {
+                               /*
+                                * Set I2C transaction and write data
+                                * If bit 3 is 1, DisplayPort transaction.
+                                * If Bit 3 is 0, I2C transaction.
+                                */
+                               reg = AUX_LENGTH(16) |
+                                       AUX_TX_COMM_I2C_TRANSACTION |
+                                       AUX_TX_COMM_READ;
+                               writel(reg, dp->reg_base +
+                                       EXYNOS_DP_AUX_CH_CTL_1);
+
+                               /* Start AUX transaction */
+                               retval = exynos_dp_start_aux_transaction(dp);
+                               if (retval == 0)
+                                       break;
+                               else
+                                       dev_dbg(dp->dev,
+                                               "%s: Aux Transaction fail!\n",
+                                               __func__);
+                       }
+                       /* Check if Rx sends defer */
+                       reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM);
+                       if (reg == AUX_RX_COMM_AUX_DEFER ||
+                               reg == AUX_RX_COMM_I2C_DEFER) {
+                               dev_err(dp->dev, "Defer: %d\n\n", reg);
+                               defer = 1;
+                       }
+               }
+
+               for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
+                       reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
+                                                + 4 * cur_data_idx);
+                       edid[i + cur_data_idx] = (unsigned char)reg;
+               }
+       }
+
+       return retval;
+}
+
+void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype)
+{
+       u32 reg;
+
+       reg = bwtype;
+       if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
+               writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET);
+}
+
+void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET);
+       *bwtype = reg;
+}
+
+void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count)
+{
+       u32 reg;
+
+       reg = count;
+       writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
+}
+
+void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
+       *count = reg;
+}
+
+void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable)
+{
+       u32 reg;
+
+       if (enable) {
+               reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+               reg |= ENHANCED;
+               writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+       } else {
+               reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+               reg &= ~ENHANCED;
+               writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+       }
+}
+
+void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
+                                enum pattern_set pattern)
+{
+       u32 reg;
+
+       switch (pattern) {
+       case PRBS7:
+               reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
+               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+               break;
+       case D10_2:
+               reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
+               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+               break;
+       case TRAINING_PTN1:
+               reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
+               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+               break;
+       case TRAINING_PTN2:
+               reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
+               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+               break;
+       case DP_NONE:
+               reg = SCRAMBLING_ENABLE |
+                       LINK_QUAL_PATTERN_SET_DISABLE |
+                       SW_TRAINING_PATTERN_SET_NORMAL;
+               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+               break;
+       default:
+               break;
+       }
+}
+
+void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+       reg &= ~PRE_EMPHASIS_SET_MASK;
+       reg |= level << PRE_EMPHASIS_SET_SHIFT;
+       writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+       reg &= ~PRE_EMPHASIS_SET_MASK;
+       reg |= level << PRE_EMPHASIS_SET_SHIFT;
+       writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+       reg &= ~PRE_EMPHASIS_SET_MASK;
+       reg |= level << PRE_EMPHASIS_SET_SHIFT;
+       writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+       reg &= ~PRE_EMPHASIS_SET_MASK;
+       reg |= level << PRE_EMPHASIS_SET_SHIFT;
+       writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
+                                       u32 training_lane)
+{
+       u32 reg;
+
+       reg = training_lane;
+       writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
+                                       u32 training_lane)
+{
+       u32 reg;
+
+       reg = training_lane;
+       writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
+                                       u32 training_lane)
+{
+       u32 reg;
+
+       reg = training_lane;
+       writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+}
+
+void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
+                                       u32 training_lane)
+{
+       u32 reg;
+
+       reg = training_lane;
+       writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+}
+
+u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
+       return reg;
+}
+
+u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
+       return reg;
+}
+
+u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
+       return reg;
+}
+
+u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
+       return reg;
+}
+
+void exynos_dp_reset_macro(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST);
+       reg |= MACRO_RST;
+       writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
+
+       /* 10 us is the minimum reset time. */
+       usleep_range(10, 20);
+
+       reg &= ~MACRO_RST;
+       writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
+}
+
+void exynos_dp_init_video(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
+       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
+
+       reg = 0x0;
+       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+       reg = CHA_CRI(4) | CHA_CTRL;
+       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+
+       reg = 0x0;
+       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+
+       reg = VID_HRES_TH(2) | VID_VRES_TH(0);
+       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
+}
+
+void exynos_dp_set_video_color_format(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       /* Configure the input color depth, color space, dynamic range */
+       reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) |
+               (dp->video_info->color_depth << IN_BPC_SHIFT) |
+               (dp->video_info->color_space << IN_COLOR_F_SHIFT);
+       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2);
+
+       /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
+       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
+       reg &= ~IN_YC_COEFFI_MASK;
+       if (dp->video_info->ycbcr_coeff)
+               reg |= IN_YC_COEFFI_ITU709;
+       else
+               reg |= IN_YC_COEFFI_ITU601;
+       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
+}
+
+int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
+
+       if (!(reg & DET_STA)) {
+               dev_dbg(dp->dev, "Input stream clock not detected.\n");
+               return -EINVAL;
+       }
+
+       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+
+       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
+       dev_dbg(dp->dev, "wait SYS_CTL_2.\n");
+
+       if (reg & CHA_STA) {
+               dev_dbg(dp->dev, "Input stream clk is changing\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
+               enum clock_recovery_m_value_type type,
+               u32 m_value,
+               u32 n_value)
+{
+       u32 reg;
+
+       if (type == REGISTER_M) {
+               reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+               reg |= FIX_M_VID;
+               writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+               reg = m_value & 0xff;
+               writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0);
+               reg = (m_value >> 8) & 0xff;
+               writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1);
+               reg = (m_value >> 16) & 0xff;
+               writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2);
+
+               reg = n_value & 0xff;
+               writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0);
+               reg = (n_value >> 8) & 0xff;
+               writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1);
+               reg = (n_value >> 16) & 0xff;
+               writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2);
+       } else  {
+               reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+               reg &= ~FIX_M_VID;
+               writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
+
+               writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0);
+               writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1);
+               writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2);
+       }
+}
+
+void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type)
+{
+       u32 reg;
+
+       if (type == VIDEO_TIMING_FROM_CAPTURE) {
+               reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+               reg &= ~FORMAT_SEL;
+               writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+       } else {
+               reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+               reg |= FORMAT_SEL;
+               writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+       }
+}
+
+void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable)
+{
+       u32 reg;
+
+       if (enable) {
+               reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+               reg &= ~VIDEO_MODE_MASK;
+               reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
+               writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+       } else {
+               reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+               reg &= ~VIDEO_MODE_MASK;
+               reg |= VIDEO_MODE_SLAVE_MODE;
+               writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+       }
+}
+
+void exynos_dp_start_video(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+       reg |= VIDEO_EN;
+       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
+}
+
+int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+
+       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
+       if (!(reg & STRM_VALID)) {
+               dev_dbg(dp->dev, "Input video stream is not detected.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+       reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
+       reg |= MASTER_VID_FUNC_EN_N;
+       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
+
+       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+       reg &= ~INTERACE_SCAN_CFG;
+       reg |= (dp->video_info->interlaced << 2);
+       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+       reg &= ~VSYNC_POLARITY_CFG;
+       reg |= (dp->video_info->v_sync_polarity << 1);
+       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+       reg &= ~HSYNC_POLARITY_CFG;
+       reg |= (dp->video_info->h_sync_polarity << 0);
+       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
+
+       reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
+       writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
+}
+
+void exynos_dp_enable_scrambling(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+       reg &= ~SCRAMBLING_DISABLE;
+       writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+}
+
+void exynos_dp_disable_scrambling(struct exynos_dp_device *dp)
+{
+       u32 reg;
+
+       reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+       reg |= SCRAMBLING_DISABLE;
+       writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
+}
diff --git a/drivers/gpu/drm/exynos/exynos_dp_reg.h b/drivers/gpu/drm/exynos/exynos_dp_reg.h
new file mode 100644 (file)
index 0000000..2e9bd0e
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Register definition file for Samsung DP driver
+ *
+ * Copyright (C) 2012 Samsung Electronics Co., Ltd.
+ * Author: Jingoo Han <jg1.han@samsung.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 _EXYNOS_DP_REG_H
+#define _EXYNOS_DP_REG_H
+
+#define EXYNOS_DP_TX_SW_RESET                  0x14
+#define EXYNOS_DP_FUNC_EN_1                    0x18
+#define EXYNOS_DP_FUNC_EN_2                    0x1C
+#define EXYNOS_DP_VIDEO_CTL_1                  0x20
+#define EXYNOS_DP_VIDEO_CTL_2                  0x24
+#define EXYNOS_DP_VIDEO_CTL_3                  0x28
+
+#define EXYNOS_DP_VIDEO_CTL_8                  0x3C
+#define EXYNOS_DP_VIDEO_CTL_10                 0x44
+
+#define EXYNOS_DP_LANE_MAP                     0x35C
+
+#define EXYNOS_DP_ANALOG_CTL_1                 0x370
+#define EXYNOS_DP_ANALOG_CTL_2                 0x374
+#define EXYNOS_DP_ANALOG_CTL_3                 0x378
+#define EXYNOS_DP_PLL_FILTER_CTL_1             0x37C
+#define EXYNOS_DP_TX_AMP_TUNING_CTL            0x380
+
+#define EXYNOS_DP_AUX_HW_RETRY_CTL             0x390
+
+#define EXYNOS_DP_COMMON_INT_STA_1             0x3C4
+#define EXYNOS_DP_COMMON_INT_STA_2             0x3C8
+#define EXYNOS_DP_COMMON_INT_STA_3             0x3CC
+#define EXYNOS_DP_COMMON_INT_STA_4             0x3D0
+#define EXYNOS_DP_INT_STA                      0x3DC
+#define EXYNOS_DP_COMMON_INT_MASK_1            0x3E0
+#define EXYNOS_DP_COMMON_INT_MASK_2            0x3E4
+#define EXYNOS_DP_COMMON_INT_MASK_3            0x3E8
+#define EXYNOS_DP_COMMON_INT_MASK_4            0x3EC
+#define EXYNOS_DP_INT_STA_MASK                 0x3F8
+#define EXYNOS_DP_INT_CTL                      0x3FC
+
+#define EXYNOS_DP_SYS_CTL_1                    0x600
+#define EXYNOS_DP_SYS_CTL_2                    0x604
+#define EXYNOS_DP_SYS_CTL_3                    0x608
+#define EXYNOS_DP_SYS_CTL_4                    0x60C
+
+#define EXYNOS_DP_PKT_SEND_CTL                 0x640
+#define EXYNOS_DP_HDCP_CTL                     0x648
+
+#define EXYNOS_DP_LINK_BW_SET                  0x680
+#define EXYNOS_DP_LANE_COUNT_SET               0x684
+#define EXYNOS_DP_TRAINING_PTN_SET             0x688
+#define EXYNOS_DP_LN0_LINK_TRAINING_CTL                0x68C
+#define EXYNOS_DP_LN1_LINK_TRAINING_CTL                0x690
+#define EXYNOS_DP_LN2_LINK_TRAINING_CTL                0x694
+#define EXYNOS_DP_LN3_LINK_TRAINING_CTL                0x698
+
+#define EXYNOS_DP_DEBUG_CTL                    0x6C0
+#define EXYNOS_DP_HPD_DEGLITCH_L               0x6C4
+#define EXYNOS_DP_HPD_DEGLITCH_H               0x6C8
+#define EXYNOS_DP_LINK_DEBUG_CTL               0x6E0
+
+#define EXYNOS_DP_M_VID_0                      0x700
+#define EXYNOS_DP_M_VID_1                      0x704
+#define EXYNOS_DP_M_VID_2                      0x708
+#define EXYNOS_DP_N_VID_0                      0x70C
+#define EXYNOS_DP_N_VID_1                      0x710
+#define EXYNOS_DP_N_VID_2                      0x714
+
+#define EXYNOS_DP_PLL_CTL                      0x71C
+#define EXYNOS_DP_PHY_PD                       0x720
+#define EXYNOS_DP_PHY_TEST                     0x724
+
+#define EXYNOS_DP_VIDEO_FIFO_THRD              0x730
+#define EXYNOS_DP_AUDIO_MARGIN                 0x73C
+
+#define EXYNOS_DP_M_VID_GEN_FILTER_TH          0x764
+#define EXYNOS_DP_M_AUD_GEN_FILTER_TH          0x778
+#define EXYNOS_DP_AUX_CH_STA                   0x780
+#define EXYNOS_DP_AUX_CH_DEFER_CTL             0x788
+#define EXYNOS_DP_AUX_RX_COMM                  0x78C
+#define EXYNOS_DP_BUFFER_DATA_CTL              0x790
+#define EXYNOS_DP_AUX_CH_CTL_1                 0x794
+#define EXYNOS_DP_AUX_ADDR_7_0                 0x798
+#define EXYNOS_DP_AUX_ADDR_15_8                        0x79C
+#define EXYNOS_DP_AUX_ADDR_19_16               0x7A0
+#define EXYNOS_DP_AUX_CH_CTL_2                 0x7A4
+
+#define EXYNOS_DP_BUF_DATA_0                   0x7C0
+
+#define EXYNOS_DP_SOC_GENERAL_CTL              0x800
+
+/* EXYNOS_DP_TX_SW_RESET */
+#define RESET_DP_TX                            (0x1 << 0)
+
+/* EXYNOS_DP_FUNC_EN_1 */
+#define MASTER_VID_FUNC_EN_N                   (0x1 << 7)
+#define SLAVE_VID_FUNC_EN_N                    (0x1 << 5)
+#define AUD_FIFO_FUNC_EN_N                     (0x1 << 4)
+#define AUD_FUNC_EN_N                          (0x1 << 3)
+#define HDCP_FUNC_EN_N                         (0x1 << 2)
+#define CRC_FUNC_EN_N                          (0x1 << 1)
+#define SW_FUNC_EN_N                           (0x1 << 0)
+
+/* EXYNOS_DP_FUNC_EN_2 */
+#define SSC_FUNC_EN_N                          (0x1 << 7)
+#define AUX_FUNC_EN_N                          (0x1 << 2)
+#define SERDES_FIFO_FUNC_EN_N                  (0x1 << 1)
+#define LS_CLK_DOMAIN_FUNC_EN_N                        (0x1 << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_1 */
+#define VIDEO_EN                               (0x1 << 7)
+#define HDCP_VIDEO_MUTE                                (0x1 << 6)
+
+/* EXYNOS_DP_VIDEO_CTL_1 */
+#define IN_D_RANGE_MASK                                (0x1 << 7)
+#define IN_D_RANGE_SHIFT                       (7)
+#define IN_D_RANGE_CEA                         (0x1 << 7)
+#define IN_D_RANGE_VESA                                (0x0 << 7)
+#define IN_BPC_MASK                            (0x7 << 4)
+#define IN_BPC_SHIFT                           (4)
+#define IN_BPC_12_BITS                         (0x3 << 4)
+#define IN_BPC_10_BITS                         (0x2 << 4)
+#define IN_BPC_8_BITS                          (0x1 << 4)
+#define IN_BPC_6_BITS                          (0x0 << 4)
+#define IN_COLOR_F_MASK                                (0x3 << 0)
+#define IN_COLOR_F_SHIFT                       (0)
+#define IN_COLOR_F_YCBCR444                    (0x2 << 0)
+#define IN_COLOR_F_YCBCR422                    (0x1 << 0)
+#define IN_COLOR_F_RGB                         (0x0 << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_3 */
+#define IN_YC_COEFFI_MASK                      (0x1 << 7)
+#define IN_YC_COEFFI_SHIFT                     (7)
+#define IN_YC_COEFFI_ITU709                    (0x1 << 7)
+#define IN_YC_COEFFI_ITU601                    (0x0 << 7)
+#define VID_CHK_UPDATE_TYPE_MASK               (0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_SHIFT              (4)
+#define VID_CHK_UPDATE_TYPE_1                  (0x1 << 4)
+#define VID_CHK_UPDATE_TYPE_0                  (0x0 << 4)
+
+/* EXYNOS_DP_VIDEO_CTL_8 */
+#define VID_HRES_TH(x)                         (((x) & 0xf) << 4)
+#define VID_VRES_TH(x)                         (((x) & 0xf) << 0)
+
+/* EXYNOS_DP_VIDEO_CTL_10 */
+#define FORMAT_SEL                             (0x1 << 4)
+#define INTERACE_SCAN_CFG                      (0x1 << 2)
+#define VSYNC_POLARITY_CFG                     (0x1 << 1)
+#define HSYNC_POLARITY_CFG                     (0x1 << 0)
+
+/* EXYNOS_DP_LANE_MAP */
+#define LANE3_MAP_LOGIC_LANE_0                 (0x0 << 6)
+#define LANE3_MAP_LOGIC_LANE_1                 (0x1 << 6)
+#define LANE3_MAP_LOGIC_LANE_2                 (0x2 << 6)
+#define LANE3_MAP_LOGIC_LANE_3                 (0x3 << 6)
+#define LANE2_MAP_LOGIC_LANE_0                 (0x0 << 4)
+#define LANE2_MAP_LOGIC_LANE_1                 (0x1 << 4)
+#define LANE2_MAP_LOGIC_LANE_2                 (0x2 << 4)
+#define LANE2_MAP_LOGIC_LANE_3                 (0x3 << 4)
+#define LANE1_MAP_LOGIC_LANE_0                 (0x0 << 2)
+#define LANE1_MAP_LOGIC_LANE_1                 (0x1 << 2)
+#define LANE1_MAP_LOGIC_LANE_2                 (0x2 << 2)
+#define LANE1_MAP_LOGIC_LANE_3                 (0x3 << 2)
+#define LANE0_MAP_LOGIC_LANE_0                 (0x0 << 0)
+#define LANE0_MAP_LOGIC_LANE_1                 (0x1 << 0)
+#define LANE0_MAP_LOGIC_LANE_2                 (0x2 << 0)
+#define LANE0_MAP_LOGIC_LANE_3                 (0x3 << 0)
+
+/* EXYNOS_DP_ANALOG_CTL_1 */
+#define TX_TERMINAL_CTRL_50_OHM                        (0x1 << 4)
+
+/* EXYNOS_DP_ANALOG_CTL_2 */
+#define SEL_24M                                        (0x1 << 3)
+#define TX_DVDD_BIT_1_0625V                    (0x4 << 0)
+
+/* EXYNOS_DP_ANALOG_CTL_3 */
+#define DRIVE_DVDD_BIT_1_0625V                 (0x4 << 5)
+#define VCO_BIT_600_MICRO                      (0x5 << 0)
+
+/* EXYNOS_DP_PLL_FILTER_CTL_1 */
+#define PD_RING_OSC                            (0x1 << 6)
+#define AUX_TERMINAL_CTRL_50_OHM               (0x2 << 4)
+#define TX_CUR1_2X                             (0x1 << 2)
+#define TX_CUR_16_MA                           (0x3 << 0)
+
+/* EXYNOS_DP_TX_AMP_TUNING_CTL */
+#define CH3_AMP_400_MV                         (0x0 << 24)
+#define CH2_AMP_400_MV                         (0x0 << 16)
+#define CH1_AMP_400_MV                         (0x0 << 8)
+#define CH0_AMP_400_MV                         (0x0 << 0)
+
+/* EXYNOS_DP_AUX_HW_RETRY_CTL */
+#define AUX_BIT_PERIOD_EXPECTED_DELAY(x)       (((x) & 0x7) << 8)
+#define AUX_HW_RETRY_INTERVAL_MASK             (0x3 << 3)
+#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3)
+#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3)
+#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS        (0x2 << 3)
+#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS        (0x3 << 3)
+#define AUX_HW_RETRY_COUNT_SEL(x)              (((x) & 0x7) << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_1 */
+#define VSYNC_DET                              (0x1 << 7)
+#define PLL_LOCK_CHG                           (0x1 << 6)
+#define SPDIF_ERR                              (0x1 << 5)
+#define SPDIF_UNSTBL                           (0x1 << 4)
+#define VID_FORMAT_CHG                         (0x1 << 3)
+#define AUD_CLK_CHG                            (0x1 << 2)
+#define VID_CLK_CHG                            (0x1 << 1)
+#define SW_INT                                 (0x1 << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_2 */
+#define ENC_EN_CHG                             (0x1 << 6)
+#define HW_BKSV_RDY                            (0x1 << 3)
+#define HW_SHA_DONE                            (0x1 << 2)
+#define HW_AUTH_STATE_CHG                      (0x1 << 1)
+#define HW_AUTH_DONE                           (0x1 << 0)
+
+/* EXYNOS_DP_COMMON_INT_STA_3 */
+#define AFIFO_UNDER                            (0x1 << 7)
+#define AFIFO_OVER                             (0x1 << 6)
+#define R0_CHK_FLAG                            (0x1 << 5)
+
+/* EXYNOS_DP_COMMON_INT_STA_4 */
+#define PSR_ACTIVE                             (0x1 << 7)
+#define PSR_INACTIVE                           (0x1 << 6)
+#define SPDIF_BI_PHASE_ERR                     (0x1 << 5)
+#define HOTPLUG_CHG                            (0x1 << 2)
+#define HPD_LOST                               (0x1 << 1)
+#define PLUG                                   (0x1 << 0)
+
+/* EXYNOS_DP_INT_STA */
+#define INT_HPD                                        (0x1 << 6)
+#define HW_TRAINING_FINISH                     (0x1 << 5)
+#define RPLY_RECEIV                            (0x1 << 1)
+#define AUX_ERR                                        (0x1 << 0)
+
+/* EXYNOS_DP_INT_CTL */
+#define SOFT_INT_CTRL                          (0x1 << 2)
+#define INT_POL1                               (0x1 << 1)
+#define INT_POL0                               (0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_1 */
+#define DET_STA                                        (0x1 << 2)
+#define FORCE_DET                              (0x1 << 1)
+#define DET_CTRL                               (0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_2 */
+#define CHA_CRI(x)                             (((x) & 0xf) << 4)
+#define CHA_STA                                        (0x1 << 2)
+#define FORCE_CHA                              (0x1 << 1)
+#define CHA_CTRL                               (0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_3 */
+#define HPD_STATUS                             (0x1 << 6)
+#define F_HPD                                  (0x1 << 5)
+#define HPD_CTRL                               (0x1 << 4)
+#define HDCP_RDY                               (0x1 << 3)
+#define STRM_VALID                             (0x1 << 2)
+#define F_VALID                                        (0x1 << 1)
+#define VALID_CTRL                             (0x1 << 0)
+
+/* EXYNOS_DP_SYS_CTL_4 */
+#define FIX_M_AUD                              (0x1 << 4)
+#define ENHANCED                               (0x1 << 3)
+#define FIX_M_VID                              (0x1 << 2)
+#define M_VID_UPDATE_CTRL                      (0x3 << 0)
+
+/* EXYNOS_DP_TRAINING_PTN_SET */
+#define SCRAMBLER_TYPE                         (0x1 << 9)
+#define HW_LINK_TRAINING_PATTERN               (0x1 << 8)
+#define SCRAMBLING_DISABLE                     (0x1 << 5)
+#define SCRAMBLING_ENABLE                      (0x0 << 5)
+#define LINK_QUAL_PATTERN_SET_MASK             (0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_PRBS7            (0x3 << 2)
+#define LINK_QUAL_PATTERN_SET_D10_2            (0x1 << 2)
+#define LINK_QUAL_PATTERN_SET_DISABLE          (0x0 << 2)
+#define SW_TRAINING_PATTERN_SET_MASK           (0x3 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN2           (0x2 << 0)
+#define SW_TRAINING_PATTERN_SET_PTN1           (0x1 << 0)
+#define SW_TRAINING_PATTERN_SET_NORMAL         (0x0 << 0)
+
+/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
+#define PRE_EMPHASIS_SET_MASK                  (0x3 << 3)
+#define PRE_EMPHASIS_SET_SHIFT                 (3)
+
+/* EXYNOS_DP_DEBUG_CTL */
+#define PLL_LOCK                               (0x1 << 4)
+#define F_PLL_LOCK                             (0x1 << 3)
+#define PLL_LOCK_CTRL                          (0x1 << 2)
+#define PN_INV                                 (0x1 << 0)
+
+/* EXYNOS_DP_PLL_CTL */
+#define DP_PLL_PD                              (0x1 << 7)
+#define DP_PLL_RESET                           (0x1 << 6)
+#define DP_PLL_LOOP_BIT_DEFAULT                        (0x1 << 4)
+#define DP_PLL_REF_BIT_1_1250V                 (0x5 << 0)
+#define DP_PLL_REF_BIT_1_2500V                 (0x7 << 0)
+
+/* EXYNOS_DP_PHY_PD */
+#define DP_PHY_PD                              (0x1 << 5)
+#define AUX_PD                                 (0x1 << 4)
+#define CH3_PD                                 (0x1 << 3)
+#define CH2_PD                                 (0x1 << 2)
+#define CH1_PD                                 (0x1 << 1)
+#define CH0_PD                                 (0x1 << 0)
+
+/* EXYNOS_DP_PHY_TEST */
+#define MACRO_RST                              (0x1 << 5)
+#define CH1_TEST                               (0x1 << 1)
+#define CH0_TEST                               (0x1 << 0)
+
+/* EXYNOS_DP_AUX_CH_STA */
+#define AUX_BUSY                               (0x1 << 4)
+#define AUX_STATUS_MASK                                (0xf << 0)
+
+/* EXYNOS_DP_AUX_CH_DEFER_CTL */
+#define DEFER_CTRL_EN                          (0x1 << 7)
+#define DEFER_COUNT(x)                         (((x) & 0x7f) << 0)
+
+/* EXYNOS_DP_AUX_RX_COMM */
+#define AUX_RX_COMM_I2C_DEFER                  (0x2 << 2)
+#define AUX_RX_COMM_AUX_DEFER                  (0x2 << 0)
+
+/* EXYNOS_DP_BUFFER_DATA_CTL */
+#define BUF_CLR                                        (0x1 << 7)
+#define BUF_DATA_COUNT(x)                      (((x) & 0x1f) << 0)
+
+/* EXYNOS_DP_AUX_CH_CTL_1 */
+#define AUX_LENGTH(x)                          (((x - 1) & 0xf) << 4)
+#define AUX_TX_COMM_MASK                       (0xf << 0)
+#define AUX_TX_COMM_DP_TRANSACTION             (0x1 << 3)
+#define AUX_TX_COMM_I2C_TRANSACTION            (0x0 << 3)
+#define AUX_TX_COMM_MOT                                (0x1 << 2)
+#define AUX_TX_COMM_WRITE                      (0x0 << 0)
+#define AUX_TX_COMM_READ                       (0x1 << 0)
+
+/* EXYNOS_DP_AUX_ADDR_7_0 */
+#define AUX_ADDR_7_0(x)                                (((x) >> 0) & 0xff)
+
+/* EXYNOS_DP_AUX_ADDR_15_8 */
+#define AUX_ADDR_15_8(x)                       (((x) >> 8) & 0xff)
+
+/* EXYNOS_DP_AUX_ADDR_19_16 */
+#define AUX_ADDR_19_16(x)                      (((x) >> 16) & 0x0f)
+
+/* EXYNOS_DP_AUX_CH_CTL_2 */
+#define ADDR_ONLY                              (0x1 << 1)
+#define AUX_EN                                 (0x1 << 0)
+
+/* EXYNOS_DP_SOC_GENERAL_CTL */
+#define AUDIO_MODE_SPDIF_MODE                  (0x1 << 8)
+#define AUDIO_MODE_MASTER_MODE                 (0x0 << 8)
+#define MASTER_VIDEO_INTERLACE_EN              (0x1 << 4)
+#define VIDEO_MASTER_CLK_SEL                   (0x1 << 2)
+#define VIDEO_MASTER_MODE_EN                   (0x1 << 1)
+#define VIDEO_MODE_MASK                                (0x1 << 0)
+#define VIDEO_MODE_SLAVE_MODE                  (0x1 << 0)
+#define VIDEO_MODE_MASTER_MODE                 (0x0 << 0)
+
+#endif /* _EXYNOS_DP_REG_H */
index e082efb..9a16dbe 100644 (file)
                                drm_connector)
 
 struct exynos_drm_connector {
-       struct drm_connector    drm_connector;
-       uint32_t                encoder_id;
-       struct exynos_drm_manager *manager;
-       uint32_t                dpms;
+       struct drm_connector            drm_connector;
+       uint32_t                        encoder_id;
+       struct exynos_drm_display       *display;
 };
 
 static int exynos_drm_connector_get_modes(struct drm_connector *connector)
 {
        struct exynos_drm_connector *exynos_connector =
                                        to_exynos_connector(connector);
-       struct exynos_drm_manager *manager = exynos_connector->manager;
-       struct exynos_drm_display_ops *display_ops = manager->display_ops;
+       struct exynos_drm_display *display = exynos_connector->display;
        struct edid *edid = NULL;
        unsigned int count = 0;
        int ret;
 
-       if (!display_ops) {
-               DRM_DEBUG_KMS("display_ops is null.\n");
-               return 0;
-       }
-
        /*
         * if get_edid() exists then get_edid() callback of hdmi side
         * is called to get edid data through i2c interface else
@@ -52,8 +45,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
         * P.S. in case of lcd panel, count is always 1 if success
         * because lcd panel has only one mode.
         */
-       if (display_ops->get_edid) {
-               edid = display_ops->get_edid(manager->dev, connector);
+       if (display->ops->get_edid) {
+               edid = display->ops->get_edid(display, connector);
                if (IS_ERR_OR_NULL(edid)) {
                        ret = PTR_ERR(edid);
                        edid = NULL;
@@ -76,8 +69,8 @@ static int exynos_drm_connector_get_modes(struct drm_connector *connector)
                        return 0;
                }
 
-               if (display_ops->get_panel)
-                       panel = display_ops->get_panel(manager->dev);
+               if (display->ops->get_panel)
+                       panel = display->ops->get_panel(display);
                else {
                        drm_mode_destroy(connector->dev, mode);
                        return 0;
@@ -106,20 +99,20 @@ static int exynos_drm_connector_mode_valid(struct drm_connector *connector,
 {
        struct exynos_drm_connector *exynos_connector =
                                        to_exynos_connector(connector);
-       struct exynos_drm_manager *manager = exynos_connector->manager;
-       struct exynos_drm_display_ops *display_ops = manager->display_ops;
+       struct exynos_drm_display *display = exynos_connector->display;
        int ret = MODE_BAD;
 
        DRM_DEBUG_KMS("%s\n", __FILE__);
 
-       if (display_ops && display_ops->check_mode)
-               if (!display_ops->check_mode(manager->dev, mode))
+       if (display->ops->check_mode)
+               if (!display->ops->check_mode(display, mode))
                        ret = MODE_OK;
 
        return ret;
 }
 
-struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector)
+static struct drm_encoder *exynos_drm_best_encoder(
+               struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct exynos_drm_connector *exynos_connector =
@@ -146,48 +139,12 @@ static struct drm_connector_helper_funcs exynos_connector_helper_funcs = {
        .best_encoder   = exynos_drm_best_encoder,
 };
 
-void exynos_drm_display_power(struct drm_connector *connector, int mode)
-{
-       struct drm_encoder *encoder = exynos_drm_best_encoder(connector);
-       struct exynos_drm_connector *exynos_connector;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-       struct exynos_drm_display_ops *display_ops = manager->display_ops;
-
-       exynos_connector = to_exynos_connector(connector);
-
-       if (exynos_connector->dpms == mode) {
-               DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
-               return;
-       }
-
-       if (display_ops && display_ops->power_on)
-               display_ops->power_on(manager->dev, mode);
-
-       exynos_connector->dpms = mode;
-}
-
-static void exynos_drm_connector_dpms(struct drm_connector *connector,
-                                       int mode)
-{
-       /*
-        * in case that drm_crtc_helper_set_mode() is called,
-        * encoder/crtc->funcs->dpms() will be just returned
-        * because they already were DRM_MODE_DPMS_ON so only
-        * exynos_drm_display_power() will be called.
-        */
-       drm_helper_connector_dpms(connector, mode);
-
-       exynos_drm_display_power(connector, mode);
-
-}
-
 static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
                                unsigned int max_width, unsigned int max_height)
 {
        struct exynos_drm_connector *exynos_connector =
                                        to_exynos_connector(connector);
-       struct exynos_drm_manager *manager = exynos_connector->manager;
-       struct exynos_drm_manager_ops *ops = manager->ops;
+       struct exynos_drm_display *display = exynos_connector->display;
        unsigned int width, height;
 
        width = max_width;
@@ -197,8 +154,8 @@ static int exynos_drm_connector_fill_modes(struct drm_connector *connector,
         * if specific driver want to find desired_mode using maxmum
         * resolution then get max width and height from that driver.
         */
-       if (ops && ops->get_max_resol)
-               ops->get_max_resol(manager->dev, &width, &height);
+       if (display->ops->get_max_resol)
+               display->ops->get_max_resol(display, &width, &height);
 
        return drm_helper_probe_single_connector_modes(connector, width,
                                                        height);
@@ -210,13 +167,11 @@ exynos_drm_connector_detect(struct drm_connector *connector, bool force)
 {
        struct exynos_drm_connector *exynos_connector =
                                        to_exynos_connector(connector);
-       struct exynos_drm_manager *manager = exynos_connector->manager;
-       struct exynos_drm_display_ops *display_ops =
-                                       manager->display_ops;
+       struct exynos_drm_display *display = exynos_connector->display;
        enum drm_connector_status status = connector_status_disconnected;
 
-       if (display_ops && display_ops->is_connected) {
-               if (display_ops->is_connected(manager->dev))
+       if (display->ops->is_connected) {
+               if (display->ops->is_connected(display))
                        status = connector_status_connected;
                else
                        status = connector_status_disconnected;
@@ -236,7 +191,7 @@ static void exynos_drm_connector_destroy(struct drm_connector *connector)
 }
 
 static struct drm_connector_funcs exynos_connector_funcs = {
-       .dpms           = exynos_drm_connector_dpms,
+       .dpms           = drm_helper_connector_dpms,
        .fill_modes     = exynos_drm_connector_fill_modes,
        .detect         = exynos_drm_connector_detect,
        .destroy        = exynos_drm_connector_destroy,
@@ -246,7 +201,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
                                                   struct drm_encoder *encoder)
 {
        struct exynos_drm_connector *exynos_connector;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
+       struct exynos_drm_display *display = exynos_drm_get_display(encoder);
        struct drm_connector *connector;
        int type;
        int err;
@@ -257,7 +212,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
 
        connector = &exynos_connector->drm_connector;
 
-       switch (manager->display_ops->type) {
+       switch (display->type) {
        case EXYNOS_DISPLAY_TYPE_HDMI:
                type = DRM_MODE_CONNECTOR_HDMIA;
                connector->interlace_allowed = true;
@@ -280,8 +235,7 @@ struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
                goto err_connector;
 
        exynos_connector->encoder_id = encoder->base.id;
-       exynos_connector->manager = manager;
-       exynos_connector->dpms = DRM_MODE_DPMS_OFF;
+       exynos_connector->display = display;
        connector->dpms = DRM_MODE_DPMS_OFF;
        connector->encoder = encoder;
 
index 547c6b5..4eb20d7 100644 (file)
@@ -17,8 +17,4 @@
 struct drm_connector *exynos_drm_connector_create(struct drm_device *dev,
                                                   struct drm_encoder *encoder);
 
-struct drm_encoder *exynos_drm_best_encoder(struct drm_connector *connector);
-
-void exynos_drm_display_power(struct drm_connector *connector, int mode);
-
 #endif
index 1bef6dc..0e9e06c 100644 (file)
 
 #include <drm/drmP.h>
 #include "exynos_drm_drv.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_drm_encoder.h"
-#include "exynos_drm_connector.h"
 #include "exynos_drm_fbdev.h"
 
 static LIST_HEAD(exynos_drm_subdrv_list);
+static LIST_HEAD(exynos_drm_manager_list);
+static LIST_HEAD(exynos_drm_display_list);
 
 static int exynos_drm_create_enc_conn(struct drm_device *dev,
-                                       struct exynos_drm_subdrv *subdrv)
+                                       struct exynos_drm_display *display)
 {
        struct drm_encoder *encoder;
-       struct drm_connector *connector;
+       struct exynos_drm_manager *manager;
        int ret;
+       unsigned long possible_crtcs = 0;
 
-       subdrv->manager->dev = subdrv->dev;
+       /* Find possible crtcs for this display */
+       list_for_each_entry(manager, &exynos_drm_manager_list, list)
+               if (manager->type == display->type)
+                       possible_crtcs |= 1 << manager->pipe;
 
        /* create and initialize a encoder for this sub driver. */
-       encoder = exynos_drm_encoder_create(dev, subdrv->manager,
-                       (1 << MAX_CRTC) - 1);
+       encoder = exynos_drm_encoder_create(dev, display, possible_crtcs);
        if (!encoder) {
                DRM_ERROR("failed to create encoder\n");
                return -EFAULT;
        }
 
-       /*
-        * create and initialize a connector for this sub driver and
-        * attach the encoder created above to the connector.
-        */
-       connector = exynos_drm_connector_create(dev, encoder);
-       if (!connector) {
-               DRM_ERROR("failed to create connector\n");
-               ret = -EFAULT;
+       display->encoder = encoder;
+
+       ret = display->ops->create_connector(display, encoder);
+       if (ret) {
+               DRM_ERROR("failed to create connector ret = %d\n", ret);
                goto err_destroy_encoder;
        }
 
-       subdrv->encoder = encoder;
-       subdrv->connector = connector;
-
        return 0;
 
 err_destroy_encoder:
@@ -58,21 +57,6 @@ err_destroy_encoder:
        return ret;
 }
 
-static void exynos_drm_destroy_enc_conn(struct exynos_drm_subdrv *subdrv)
-{
-       if (subdrv->encoder) {
-               struct drm_encoder *encoder = subdrv->encoder;
-               encoder->funcs->destroy(encoder);
-               subdrv->encoder = NULL;
-       }
-
-       if (subdrv->connector) {
-               struct drm_connector *connector = subdrv->connector;
-               connector->funcs->destroy(connector);
-               subdrv->connector = NULL;
-       }
-}
-
 static int exynos_drm_subdrv_probe(struct drm_device *dev,
                                        struct exynos_drm_subdrv *subdrv)
 {
@@ -104,10 +88,98 @@ static void exynos_drm_subdrv_remove(struct drm_device *dev,
                subdrv->remove(dev, subdrv->dev);
 }
 
+int exynos_drm_initialize_managers(struct drm_device *dev)
+{
+       struct exynos_drm_manager *manager, *n;
+       int ret, pipe = 0;
+
+       list_for_each_entry(manager, &exynos_drm_manager_list, list) {
+               if (manager->ops->initialize) {
+                       ret = manager->ops->initialize(manager, dev, pipe);
+                       if (ret) {
+                               DRM_ERROR("Mgr init [%d] failed with %d\n",
+                                               manager->type, ret);
+                               goto err;
+                       }
+               }
+
+               manager->drm_dev = dev;
+               manager->pipe = pipe++;
+
+               ret = exynos_drm_crtc_create(manager);
+               if (ret) {
+                       DRM_ERROR("CRTC create [%d] failed with %d\n",
+                                       manager->type, ret);
+                       goto err;
+               }
+       }
+       return 0;
+
+err:
+       list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list) {
+               if (pipe-- > 0)
+                       exynos_drm_manager_unregister(manager);
+               else
+                       list_del(&manager->list);
+       }
+       return ret;
+}
+
+void exynos_drm_remove_managers(struct drm_device *dev)
+{
+       struct exynos_drm_manager *manager, *n;
+
+       list_for_each_entry_safe(manager, n, &exynos_drm_manager_list, list)
+               exynos_drm_manager_unregister(manager);
+}
+
+int exynos_drm_initialize_displays(struct drm_device *dev)
+{
+       struct exynos_drm_display *display, *n;
+       int ret, initialized = 0;
+
+       list_for_each_entry(display, &exynos_drm_display_list, list) {
+               if (display->ops->initialize) {
+                       ret = display->ops->initialize(display, dev);
+                       if (ret) {
+                               DRM_ERROR("Display init [%d] failed with %d\n",
+                                               display->type, ret);
+                               goto err;
+                       }
+               }
+
+               initialized++;
+
+               ret = exynos_drm_create_enc_conn(dev, display);
+               if (ret) {
+                       DRM_ERROR("Encoder create [%d] failed with %d\n",
+                                       display->type, ret);
+                       goto err;
+               }
+       }
+       return 0;
+
+err:
+       list_for_each_entry_safe(display, n, &exynos_drm_display_list, list) {
+               if (initialized-- > 0)
+                       exynos_drm_display_unregister(display);
+               else
+                       list_del(&display->list);
+       }
+       return ret;
+}
+
+void exynos_drm_remove_displays(struct drm_device *dev)
+{
+       struct exynos_drm_display *display, *n;
+
+       list_for_each_entry_safe(display, n, &exynos_drm_display_list, list)
+               exynos_drm_display_unregister(display);
+}
+
 int exynos_drm_device_register(struct drm_device *dev)
 {
        struct exynos_drm_subdrv *subdrv, *n;
-       unsigned int fine_cnt = 0;
        int err;
 
        if (!dev)
@@ -120,30 +192,8 @@ int exynos_drm_device_register(struct drm_device *dev)
                        list_del(&subdrv->list);
                        continue;
                }
-
-               /*
-                * if manager is null then it means that this sub driver
-                * doesn't need encoder and connector.
-                */
-               if (!subdrv->manager) {
-                       fine_cnt++;
-                       continue;
-               }
-
-               err = exynos_drm_create_enc_conn(dev, subdrv);
-               if (err) {
-                       DRM_DEBUG("failed to create encoder and connector.\n");
-                       exynos_drm_subdrv_remove(dev, subdrv);
-                       list_del(&subdrv->list);
-                       continue;
-               }
-
-               fine_cnt++;
        }
 
-       if (!fine_cnt)
-               return -EINVAL;
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_register);
@@ -159,13 +209,44 @@ int exynos_drm_device_unregister(struct drm_device *dev)
 
        list_for_each_entry(subdrv, &exynos_drm_subdrv_list, list) {
                exynos_drm_subdrv_remove(dev, subdrv);
-               exynos_drm_destroy_enc_conn(subdrv);
        }
 
        return 0;
 }
 EXPORT_SYMBOL_GPL(exynos_drm_device_unregister);
 
+int exynos_drm_manager_register(struct exynos_drm_manager *manager)
+{
+       BUG_ON(!manager->ops);
+       list_add_tail(&manager->list, &exynos_drm_manager_list);
+       return 0;
+}
+
+int exynos_drm_manager_unregister(struct exynos_drm_manager *manager)
+{
+       if (manager->ops->remove)
+               manager->ops->remove(manager);
+
+       list_del(&manager->list);
+       return 0;
+}
+
+int exynos_drm_display_register(struct exynos_drm_display *display)
+{
+       BUG_ON(!display->ops);
+       list_add_tail(&display->list, &exynos_drm_display_list);
+       return 0;
+}
+
+int exynos_drm_display_unregister(struct exynos_drm_display *display)
+{
+       if (display->ops->remove)
+               display->ops->remove(display);
+
+       list_del(&display->list);
+       return 0;
+}
+
 int exynos_drm_subdrv_register(struct exynos_drm_subdrv *subdrv)
 {
        if (!subdrv)
index 6f3400f..e930d4f 100644 (file)
@@ -33,6 +33,7 @@ enum exynos_crtc_mode {
  *
  * @drm_crtc: crtc object.
  * @drm_plane: pointer of private plane object for this crtc
+ * @manager: the manager associated with this crtc
  * @pipe: a crtc index created at load() with a new crtc object creation
  *     and the crtc object would be set to private->crtc array
  *     to get a crtc object corresponding to this pipe from private->crtc
@@ -46,6 +47,7 @@ enum exynos_crtc_mode {
 struct exynos_drm_crtc {
        struct drm_crtc                 drm_crtc;
        struct drm_plane                *plane;
+       struct exynos_drm_manager       *manager;
        unsigned int                    pipe;
        unsigned int                    dpms;
        enum exynos_crtc_mode           mode;
@@ -56,6 +58,7 @@ struct exynos_drm_crtc {
 static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
 
        DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
 
@@ -71,7 +74,9 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
                drm_vblank_off(crtc->dev, exynos_crtc->pipe);
        }
 
-       exynos_drm_fn_encoder(crtc, &mode, exynos_drm_encoder_crtc_dpms);
+       if (manager->ops->dpms)
+               manager->ops->dpms(manager, mode);
+
        exynos_crtc->dpms = mode;
 }
 
@@ -83,9 +88,15 @@ static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
 static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
 
        exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+
        exynos_plane_commit(exynos_crtc->plane);
+
+       if (manager->ops->commit)
+               manager->ops->commit(manager);
+
        exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_ON);
 }
 
@@ -94,7 +105,12 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
                            const struct drm_display_mode *mode,
                            struct drm_display_mode *adjusted_mode)
 {
-       /* drm framework doesn't check NULL */
+       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
+
+       if (manager->ops->mode_fixup)
+               return manager->ops->mode_fixup(manager, mode, adjusted_mode);
+
        return true;
 }
 
@@ -104,10 +120,10 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
                          struct drm_framebuffer *old_fb)
 {
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
        struct drm_plane *plane = exynos_crtc->plane;
        unsigned int crtc_w;
        unsigned int crtc_h;
-       int pipe = exynos_crtc->pipe;
        int ret;
 
        /*
@@ -116,18 +132,19 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
         */
        memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
 
-       crtc_w = crtc->fb->width - x;
-       crtc_h = crtc->fb->height - y;
+       crtc_w = crtc->primary->fb->width - x;
+       crtc_h = crtc->primary->fb->height - y;
+
+       if (manager->ops->mode_set)
+               manager->ops->mode_set(manager, &crtc->mode);
 
-       ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+       ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h,
                                    x, y, crtc_w, crtc_h);
        if (ret)
                return ret;
 
        plane->crtc = crtc;
-       plane->fb = crtc->fb;
-
-       exynos_drm_fn_encoder(crtc, &pipe, exynos_drm_encoder_crtc_pipe);
+       plane->fb = crtc->primary->fb;
 
        return 0;
 }
@@ -147,10 +164,10 @@ static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
                return -EPERM;
        }
 
-       crtc_w = crtc->fb->width - x;
-       crtc_h = crtc->fb->height - y;
+       crtc_w = crtc->primary->fb->width - x;
+       crtc_h = crtc->primary->fb->height - y;
 
-       ret = exynos_plane_mode_set(plane, crtc, crtc->fb, 0, 0, crtc_w, crtc_h,
+       ret = exynos_plane_mode_set(plane, crtc, crtc->primary->fb, 0, 0, crtc_w, crtc_h,
                                    x, y, crtc_w, crtc_h);
        if (ret)
                return ret;
@@ -168,10 +185,19 @@ static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 
 static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
 {
-       struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+       struct drm_plane *plane;
+       int ret;
 
-       exynos_plane_dpms(exynos_crtc->plane, DRM_MODE_DPMS_OFF);
        exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+       drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) {
+               if (plane->crtc != crtc)
+                       continue;
+
+               ret = plane->funcs->disable_plane(plane);
+               if (ret)
+                       DRM_ERROR("Failed to disable plane %d\n", ret);
+       }
 }
 
 static struct drm_crtc_helper_funcs exynos_crtc_helper_funcs = {
@@ -192,7 +218,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct exynos_drm_private *dev_priv = dev->dev_private;
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-       struct drm_framebuffer *old_fb = crtc->fb;
+       struct drm_framebuffer *old_fb = crtc->primary->fb;
        int ret = -EINVAL;
 
        /* when the page flip is requested, crtc's dpms should be on */
@@ -223,11 +249,11 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
                atomic_set(&exynos_crtc->pending_flip, 1);
                spin_unlock_irq(&dev->event_lock);
 
-               crtc->fb = fb;
+               crtc->primary->fb = fb;
                ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y,
                                                    NULL);
                if (ret) {
-                       crtc->fb = old_fb;
+                       crtc->primary->fb = old_fb;
 
                        spin_lock_irq(&dev->event_lock);
                        drm_vblank_put(dev, exynos_crtc->pipe);
@@ -318,21 +344,24 @@ static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
        drm_object_attach_property(&crtc->base, prop, 0);
 }
 
-int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
+int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
 {
        struct exynos_drm_crtc *exynos_crtc;
-       struct exynos_drm_private *private = dev->dev_private;
+       struct exynos_drm_private *private = manager->drm_dev->dev_private;
        struct drm_crtc *crtc;
 
        exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
        if (!exynos_crtc)
                return -ENOMEM;
 
-       exynos_crtc->pipe = nr;
-       exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
        init_waitqueue_head(&exynos_crtc->pending_flip_queue);
        atomic_set(&exynos_crtc->pending_flip, 0);
-       exynos_crtc->plane = exynos_plane_init(dev, 1 << nr, true);
+
+       exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
+       exynos_crtc->manager = manager;
+       exynos_crtc->pipe = manager->pipe;
+       exynos_crtc->plane = exynos_plane_init(manager->drm_dev,
+                               1 << manager->pipe, true);
        if (!exynos_crtc->plane) {
                kfree(exynos_crtc);
                return -ENOMEM;
@@ -340,9 +369,9 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
 
        crtc = &exynos_crtc->drm_crtc;
 
-       private->crtc[nr] = crtc;
+       private->crtc[manager->pipe] = crtc;
 
-       drm_crtc_init(dev, crtc, &exynos_crtc_funcs);
+       drm_crtc_init(manager->drm_dev, crtc, &exynos_crtc_funcs);
        drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
 
        exynos_drm_crtc_attach_mode_property(crtc);
@@ -350,39 +379,41 @@ int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr)
        return 0;
 }
 
-int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc)
+int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
 {
        struct exynos_drm_private *private = dev->dev_private;
        struct exynos_drm_crtc *exynos_crtc =
-               to_exynos_crtc(private->crtc[crtc]);
+               to_exynos_crtc(private->crtc[pipe]);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
 
        if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
                return -EPERM;
 
-       exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
-                       exynos_drm_enable_vblank);
+       if (manager->ops->enable_vblank)
+               manager->ops->enable_vblank(manager);
 
        return 0;
 }
 
-void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc)
+void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
 {
        struct exynos_drm_private *private = dev->dev_private;
        struct exynos_drm_crtc *exynos_crtc =
-               to_exynos_crtc(private->crtc[crtc]);
+               to_exynos_crtc(private->crtc[pipe]);
+       struct exynos_drm_manager *manager = exynos_crtc->manager;
 
        if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
                return;
 
-       exynos_drm_fn_encoder(private->crtc[crtc], &crtc,
-                       exynos_drm_disable_vblank);
+       if (manager->ops->disable_vblank)
+               manager->ops->disable_vblank(manager);
 }
 
-void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
 {
        struct exynos_drm_private *dev_priv = dev->dev_private;
        struct drm_pending_vblank_event *e, *t;
-       struct drm_crtc *drm_crtc = dev_priv->crtc[crtc];
+       struct drm_crtc *drm_crtc = dev_priv->crtc[pipe];
        struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(drm_crtc);
        unsigned long flags;
 
@@ -391,15 +422,71 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc)
        list_for_each_entry_safe(e, t, &dev_priv->pageflip_event_list,
                        base.link) {
                /* if event's pipe isn't same as crtc then ignore it. */
-               if (crtc != e->pipe)
+               if (pipe != e->pipe)
                        continue;
 
                list_del(&e->base.link);
                drm_send_vblank_event(dev, -1, e);
-               drm_vblank_put(dev, crtc);
+               drm_vblank_put(dev, pipe);
                atomic_set(&exynos_crtc->pending_flip, 0);
                wake_up(&exynos_crtc->pending_flip_queue);
        }
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
 }
+
+void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+                       struct exynos_drm_overlay *overlay)
+{
+       struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+       if (manager->ops->win_mode_set)
+               manager->ops->win_mode_set(manager, overlay);
+}
+
+void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos)
+{
+       struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+       if (manager->ops->win_commit)
+               manager->ops->win_commit(manager, zpos);
+}
+
+void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos)
+{
+       struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+       if (manager->ops->win_enable)
+               manager->ops->win_enable(manager, zpos);
+}
+
+void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos)
+{
+       struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+
+       if (manager->ops->win_disable)
+               manager->ops->win_disable(manager, zpos);
+}
+
+void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
+{
+       struct exynos_drm_manager *manager;
+       struct drm_device *dev = fb->dev;
+       struct drm_crtc *crtc;
+
+       /*
+        * make sure that overlay data are updated to real hardware
+        * for all encoders.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               manager = to_exynos_crtc(crtc)->manager;
+
+               /*
+                * wait for vblank interrupt
+                * - this makes sure that overlay data are updated to
+                *      real hardware.
+                */
+               if (manager->ops->wait_for_vblank)
+                       manager->ops->wait_for_vblank(manager);
+       }
+}
index 3e197e6..c27b66c 100644 (file)
 #ifndef _EXYNOS_DRM_CRTC_H_
 #define _EXYNOS_DRM_CRTC_H_
 
-int exynos_drm_crtc_create(struct drm_device *dev, unsigned int nr);
-int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int crtc);
-void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int crtc);
-void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int crtc);
+struct drm_device;
+struct drm_crtc;
+struct exynos_drm_manager;
+struct exynos_drm_overlay;
+
+int exynos_drm_crtc_create(struct exynos_drm_manager *manager);
+int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
+void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
+
+void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
+                       struct exynos_drm_overlay *overlay);
+void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
+void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
+void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
 
 #endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dpi.c b/drivers/gpu/drm/exynos/exynos_drm_dpi.c
new file mode 100644 (file)
index 0000000..2b09c7c
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Exynos DRM Parallel output support.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * Contacts: Andrzej Hajda <a.hajda@samsung.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 <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+
+#include <linux/regulator/consumer.h>
+
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+#include "exynos_drm_drv.h"
+
+struct exynos_dpi {
+       struct device *dev;
+       struct device_node *panel_node;
+
+       struct drm_panel *panel;
+       struct drm_connector connector;
+       struct drm_encoder *encoder;
+
+       struct videomode *vm;
+       int dpms_mode;
+};
+
+#define connector_to_dpi(c) container_of(c, struct exynos_dpi, connector)
+
+static enum drm_connector_status
+exynos_dpi_detect(struct drm_connector *connector, bool force)
+{
+       struct exynos_dpi *ctx = connector_to_dpi(connector);
+
+       /* panels supported only by boot-loader are always connected */
+       if (!ctx->panel_node)
+               return connector_status_connected;
+
+       if (!ctx->panel) {
+               ctx->panel = of_drm_find_panel(ctx->panel_node);
+               if (ctx->panel)
+                       drm_panel_attach(ctx->panel, &ctx->connector);
+       }
+
+       if (ctx->panel)
+               return connector_status_connected;
+
+       return connector_status_disconnected;
+}
+
+static void exynos_dpi_connector_destroy(struct drm_connector *connector)
+{
+       drm_sysfs_connector_remove(connector);
+       drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs exynos_dpi_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = exynos_dpi_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = exynos_dpi_connector_destroy,
+};
+
+static int exynos_dpi_get_modes(struct drm_connector *connector)
+{
+       struct exynos_dpi *ctx = connector_to_dpi(connector);
+
+       /* fimd timings gets precedence over panel modes */
+       if (ctx->vm) {
+               struct drm_display_mode *mode;
+
+               mode = drm_mode_create(connector->dev);
+               if (!mode) {
+                       DRM_ERROR("failed to create a new display mode\n");
+                       return 0;
+               }
+               drm_display_mode_from_videomode(ctx->vm, mode);
+               mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+               drm_mode_probed_add(connector, mode);
+               return 1;
+       }
+
+       if (ctx->panel)
+               return ctx->panel->funcs->get_modes(ctx->panel);
+
+       return 0;
+}
+
+static int exynos_dpi_mode_valid(struct drm_connector *connector,
+                                struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static struct drm_encoder *
+exynos_dpi_best_encoder(struct drm_connector *connector)
+{
+       struct exynos_dpi *ctx = connector_to_dpi(connector);
+
+       return ctx->encoder;
+}
+
+static struct drm_connector_helper_funcs exynos_dpi_connector_helper_funcs = {
+       .get_modes = exynos_dpi_get_modes,
+       .mode_valid = exynos_dpi_mode_valid,
+       .best_encoder = exynos_dpi_best_encoder,
+};
+
+static int exynos_dpi_create_connector(struct exynos_drm_display *display,
+                                      struct drm_encoder *encoder)
+{
+       struct exynos_dpi *ctx = display->ctx;
+       struct drm_connector *connector = &ctx->connector;
+       int ret;
+
+       ctx->encoder = encoder;
+
+       if (ctx->panel_node)
+               connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+       else
+               connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+       ret = drm_connector_init(encoder->dev, connector,
+                                &exynos_dpi_connector_funcs,
+                                DRM_MODE_CONNECTOR_VGA);
+       if (ret) {
+               DRM_ERROR("failed to initialize connector with drm\n");
+               return ret;
+       }
+
+       drm_connector_helper_add(connector, &exynos_dpi_connector_helper_funcs);
+       drm_sysfs_connector_add(connector);
+       drm_mode_connector_attach_encoder(connector, encoder);
+
+       return 0;
+}
+
+static void exynos_dpi_poweron(struct exynos_dpi *ctx)
+{
+       if (ctx->panel)
+               drm_panel_enable(ctx->panel);
+}
+
+static void exynos_dpi_poweroff(struct exynos_dpi *ctx)
+{
+       if (ctx->panel)
+               drm_panel_disable(ctx->panel);
+}
+
+static void exynos_dpi_dpms(struct exynos_drm_display *display, int mode)
+{
+       struct exynos_dpi *ctx = display->ctx;
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               if (ctx->dpms_mode != DRM_MODE_DPMS_ON)
+                               exynos_dpi_poweron(ctx);
+                       break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               if (ctx->dpms_mode == DRM_MODE_DPMS_ON)
+                       exynos_dpi_poweroff(ctx);
+               break;
+       default:
+               break;
+       };
+       ctx->dpms_mode = mode;
+}
+
+static struct exynos_drm_display_ops exynos_dpi_display_ops = {
+       .create_connector = exynos_dpi_create_connector,
+       .dpms = exynos_dpi_dpms
+};
+
+static struct exynos_drm_display exynos_dpi_display = {
+       .type = EXYNOS_DISPLAY_TYPE_LCD,
+       .ops = &exynos_dpi_display_ops,
+};
+
+/* of_* functions will be removed after merge of of_graph patches */
+static struct device_node *
+of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg)
+{
+       struct device_node *np;
+
+       for_each_child_of_node(parent, np) {
+               u32 r;
+
+               if (!np->name || of_node_cmp(np->name, name))
+                       continue;
+
+               if (of_property_read_u32(np, "reg", &r) < 0)
+                       r = 0;
+
+               if (reg == r)
+                       break;
+       }
+
+       return np;
+}
+
+static struct device_node *of_graph_get_port_by_reg(struct device_node *parent,
+                                                   u32 reg)
+{
+       struct device_node *ports, *port;
+
+       ports = of_get_child_by_name(parent, "ports");
+       if (ports)
+               parent = ports;
+
+       port = of_get_child_by_name_reg(parent, "port", reg);
+
+       of_node_put(ports);
+
+       return port;
+}
+
+static struct device_node *
+of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg)
+{
+       return of_get_child_by_name_reg(port, "endpoint", reg);
+}
+
+static struct device_node *
+of_graph_get_remote_port_parent(const struct device_node *node)
+{
+       struct device_node *np;
+       unsigned int depth;
+
+       np = of_parse_phandle(node, "remote-endpoint", 0);
+
+       /* Walk 3 levels up only if there is 'ports' node. */
+       for (depth = 3; depth && np; depth--) {
+               np = of_get_next_parent(np);
+               if (depth == 2 && of_node_cmp(np->name, "ports"))
+                       break;
+       }
+       return np;
+}
+
+enum {
+       FIMD_PORT_IN0,
+       FIMD_PORT_IN1,
+       FIMD_PORT_IN2,
+       FIMD_PORT_RGB,
+       FIMD_PORT_WRB,
+};
+
+static struct device_node *exynos_dpi_of_find_panel_node(struct device *dev)
+{
+       struct device_node *np, *ep;
+
+       np = of_graph_get_port_by_reg(dev->of_node, FIMD_PORT_RGB);
+       if (!np)
+               return NULL;
+
+       ep = of_graph_get_endpoint_by_reg(np, 0);
+       of_node_put(np);
+       if (!ep)
+               return NULL;
+
+       np = of_graph_get_remote_port_parent(ep);
+       of_node_put(ep);
+
+       return np;
+}
+
+static int exynos_dpi_parse_dt(struct exynos_dpi *ctx)
+{
+       struct device *dev = ctx->dev;
+       struct device_node *dn = dev->of_node;
+       struct device_node *np;
+
+       ctx->panel_node = exynos_dpi_of_find_panel_node(dev);
+
+       np = of_get_child_by_name(dn, "display-timings");
+       if (np) {
+               struct videomode *vm;
+               int ret;
+
+               of_node_put(np);
+
+               vm = devm_kzalloc(dev, sizeof(*ctx->vm), GFP_KERNEL);
+               if (!vm)
+                       return -ENOMEM;
+
+               ret = of_get_videomode(dn, vm, 0);
+               if (ret < 0)
+                       return ret;
+
+               ctx->vm = vm;
+
+               return 0;
+       }
+
+       if (!ctx->panel_node)
+               return -EINVAL;
+
+       return 0;
+}
+
+int exynos_dpi_probe(struct device *dev)
+{
+       struct exynos_dpi *ctx;
+       int ret;
+
+       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       ctx->dev = dev;
+       exynos_dpi_display.ctx = ctx;
+       ctx->dpms_mode = DRM_MODE_DPMS_OFF;
+
+       ret = exynos_dpi_parse_dt(ctx);
+       if (ret < 0)
+               return ret;
+
+       exynos_drm_display_register(&exynos_dpi_display);
+
+       return 0;
+}
+
+int exynos_dpi_remove(struct device *dev)
+{
+       exynos_dpi_dpms(&exynos_dpi_display, DRM_MODE_DPMS_OFF);
+       exynos_drm_display_unregister(&exynos_dpi_display);
+
+       return 0;
+}
index c204b4e..2d27ba2 100644 (file)
@@ -11,6 +11,7 @@
  * option) any later version.
  */
 
+#include <linux/pm_runtime.h>
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 
@@ -53,6 +54,7 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
                return -ENOMEM;
 
        INIT_LIST_HEAD(&private->pageflip_event_list);
+       dev_set_drvdata(dev->dev, dev);
        dev->dev_private = (void *)private;
 
        /*
@@ -64,38 +66,36 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
        ret = drm_create_iommu_mapping(dev);
        if (ret < 0) {
                DRM_ERROR("failed to create iommu mapping.\n");
-               goto err_crtc;
+               goto err_free_private;
        }
 
        drm_mode_config_init(dev);
 
-       /* init kms poll for handling hpd */
-       drm_kms_helper_poll_init(dev);
-
        exynos_drm_mode_config_init(dev);
 
-       /*
-        * EXYNOS4 is enough to have two CRTCs and each crtc would be used
-        * without dependency of hardware.
-        */
-       for (nr = 0; nr < MAX_CRTC; nr++) {
-               ret = exynos_drm_crtc_create(dev, nr);
-               if (ret)
-                       goto err_release_iommu_mapping;
-       }
+       ret = exynos_drm_initialize_managers(dev);
+       if (ret)
+               goto err_mode_config_cleanup;
 
        for (nr = 0; nr < MAX_PLANE; nr++) {
                struct drm_plane *plane;
-               unsigned int possible_crtcs = (1 << MAX_CRTC) - 1;
+               unsigned long possible_crtcs = (1 << MAX_CRTC) - 1;
 
                plane = exynos_plane_init(dev, possible_crtcs, false);
                if (!plane)
-                       goto err_release_iommu_mapping;
+                       goto err_manager_cleanup;
        }
 
+       ret = exynos_drm_initialize_displays(dev);
+       if (ret)
+               goto err_manager_cleanup;
+
+       /* init kms poll for handling hpd */
+       drm_kms_helper_poll_init(dev);
+
        ret = drm_vblank_init(dev, MAX_CRTC);
        if (ret)
-               goto err_release_iommu_mapping;
+               goto err_display_cleanup;
 
        /*
         * probe sub drivers such as display controller and hdmi driver,
@@ -109,30 +109,25 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
        /* setup possible_clones. */
        exynos_drm_encoder_setup(dev);
 
-       /*
-        * create and configure fb helper and also exynos specific
-        * fbdev object.
-        */
-       ret = exynos_drm_fbdev_init(dev);
-       if (ret) {
-               DRM_ERROR("failed to initialize drm fbdev\n");
-               goto err_drm_device;
-       }
-
        drm_vblank_offdelay = VBLANK_OFF_DELAY;
 
        platform_set_drvdata(dev->platformdev, dev);
 
+       /* force connectors detection */
+       drm_helper_hpd_irq_event(dev);
+
        return 0;
 
-err_drm_device:
-       exynos_drm_device_unregister(dev);
 err_vblank:
        drm_vblank_cleanup(dev);
-err_release_iommu_mapping:
-       drm_release_iommu_mapping(dev);
-err_crtc:
+err_display_cleanup:
+       exynos_drm_remove_displays(dev);
+err_manager_cleanup:
+       exynos_drm_remove_managers(dev);
+err_mode_config_cleanup:
        drm_mode_config_cleanup(dev);
+       drm_release_iommu_mapping(dev);
+err_free_private:
        kfree(private);
 
        return ret;
@@ -144,6 +139,8 @@ static int exynos_drm_unload(struct drm_device *dev)
        exynos_drm_device_unregister(dev);
        drm_vblank_cleanup(dev);
        drm_kms_helper_poll_fini(dev);
+       exynos_drm_remove_displays(dev);
+       exynos_drm_remove_managers(dev);
        drm_mode_config_cleanup(dev);
 
        drm_release_iommu_mapping(dev);
@@ -158,6 +155,41 @@ static const struct file_operations exynos_drm_gem_fops = {
        .mmap = exynos_drm_gem_mmap_buffer,
 };
 
+static int exynos_drm_suspend(struct drm_device *dev, pm_message_t state)
+{
+       struct drm_connector *connector;
+
+       drm_modeset_lock_all(dev);
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               int old_dpms = connector->dpms;
+
+               if (connector->funcs->dpms)
+                       connector->funcs->dpms(connector, DRM_MODE_DPMS_OFF);
+
+               /* Set the old mode back to the connector for resume */
+               connector->dpms = old_dpms;
+       }
+       drm_modeset_unlock_all(dev);
+
+       return 0;
+}
+
+static int exynos_drm_resume(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+
+       drm_modeset_lock_all(dev);
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->funcs->dpms)
+                       connector->funcs->dpms(connector, connector->dpms);
+       }
+
+       drm_helper_resume_force_mode(dev);
+       drm_modeset_unlock_all(dev);
+
+       return 0;
+}
+
 static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_exynos_file_private *file_priv;
@@ -295,6 +327,8 @@ static struct drm_driver exynos_drm_driver = {
                                        DRIVER_GEM | DRIVER_PRIME,
        .load                   = exynos_drm_load,
        .unload                 = exynos_drm_unload,
+       .suspend                = exynos_drm_suspend,
+       .resume                 = exynos_drm_resume,
        .open                   = exynos_drm_open,
        .preclose               = exynos_drm_preclose,
        .lastclose              = exynos_drm_lastclose,
@@ -329,6 +363,9 @@ static int exynos_drm_platform_probe(struct platform_device *pdev)
        if (ret)
                return ret;
 
+       pm_runtime_enable(&pdev->dev);
+       pm_runtime_get_sync(&pdev->dev);
+
        return drm_platform_init(&exynos_drm_driver, pdev);
 }
 
@@ -339,12 +376,67 @@ static int exynos_drm_platform_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
+static int exynos_drm_sys_suspend(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+       pm_message_t message;
+
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       message.event = PM_EVENT_SUSPEND;
+       return exynos_drm_suspend(drm_dev, message);
+}
+
+static int exynos_drm_sys_resume(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       return exynos_drm_resume(drm_dev);
+}
+#endif
+
+#ifdef CONFIG_PM_RUNTIME
+static int exynos_drm_runtime_suspend(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+       pm_message_t message;
+
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       message.event = PM_EVENT_SUSPEND;
+       return exynos_drm_suspend(drm_dev, message);
+}
+
+static int exynos_drm_runtime_resume(struct device *dev)
+{
+       struct drm_device *drm_dev = dev_get_drvdata(dev);
+
+       if (!pm_runtime_suspended(dev))
+               return 0;
+
+       return exynos_drm_resume(drm_dev);
+}
+#endif
+
+static const struct dev_pm_ops exynos_drm_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(exynos_drm_sys_suspend, exynos_drm_sys_resume)
+       SET_RUNTIME_PM_OPS(exynos_drm_runtime_suspend,
+                       exynos_drm_runtime_resume, NULL)
+};
+
 static struct platform_driver exynos_drm_platform_driver = {
        .probe          = exynos_drm_platform_probe,
        .remove         = exynos_drm_platform_remove,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "exynos-drm",
+               .pm     = &exynos_drm_pm_ops,
        },
 };
 
@@ -352,6 +444,18 @@ static int __init exynos_drm_init(void)
 {
        int ret;
 
+#ifdef CONFIG_DRM_EXYNOS_DP
+       ret = platform_driver_register(&dp_driver);
+       if (ret < 0)
+               goto out_dp;
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_DSI
+       ret = platform_driver_register(&dsi_driver);
+       if (ret < 0)
+               goto out_dsi;
+#endif
+
 #ifdef CONFIG_DRM_EXYNOS_FIMD
        ret = platform_driver_register(&fimd_driver);
        if (ret < 0)
@@ -365,13 +469,6 @@ static int __init exynos_drm_init(void)
        ret = platform_driver_register(&mixer_driver);
        if (ret < 0)
                goto out_mixer;
-       ret = platform_driver_register(&exynos_drm_common_hdmi_driver);
-       if (ret < 0)
-               goto out_common_hdmi;
-
-       ret = exynos_platform_device_hdmi_register();
-       if (ret < 0)
-               goto out_common_hdmi_dev;
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_VIDI
@@ -464,10 +561,6 @@ out_vidi:
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_HDMI
-       exynos_platform_device_hdmi_unregister();
-out_common_hdmi_dev:
-       platform_driver_unregister(&exynos_drm_common_hdmi_driver);
-out_common_hdmi:
        platform_driver_unregister(&mixer_driver);
 out_mixer:
        platform_driver_unregister(&hdmi_driver);
@@ -477,6 +570,16 @@ out_hdmi:
 #ifdef CONFIG_DRM_EXYNOS_FIMD
        platform_driver_unregister(&fimd_driver);
 out_fimd:
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_DSI
+       platform_driver_unregister(&dsi_driver);
+out_dsi:
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_DP
+       platform_driver_unregister(&dp_driver);
+out_dp:
 #endif
        return ret;
 }
@@ -509,8 +612,6 @@ static void __exit exynos_drm_exit(void)
 #endif
 
 #ifdef CONFIG_DRM_EXYNOS_HDMI
-       exynos_platform_device_hdmi_unregister();
-       platform_driver_unregister(&exynos_drm_common_hdmi_driver);
        platform_driver_unregister(&mixer_driver);
        platform_driver_unregister(&hdmi_driver);
 #endif
@@ -522,6 +623,14 @@ static void __exit exynos_drm_exit(void)
 #ifdef CONFIG_DRM_EXYNOS_FIMD
        platform_driver_unregister(&fimd_driver);
 #endif
+
+#ifdef CONFIG_DRM_EXYNOS_DSI
+       platform_driver_unregister(&dsi_driver);
+#endif
+
+#ifdef CONFIG_DRM_EXYNOS_DP
+       platform_driver_unregister(&dp_driver);
+#endif
 }
 
 module_init(exynos_drm_init);
index a8f9dba..ce3e6a3 100644 (file)
@@ -53,22 +53,6 @@ enum exynos_drm_output_type {
        EXYNOS_DISPLAY_TYPE_VIDI,
 };
 
-/*
- * Exynos drm overlay ops structure.
- *
- * @mode_set: copy drm overlay info to hw specific overlay info.
- * @commit: apply hardware specific overlay data to registers.
- * @enable: enable hardware specific overlay.
- * @disable: disable hardware specific overlay.
- */
-struct exynos_drm_overlay_ops {
-       void (*mode_set)(struct device *subdrv_dev,
-                        struct exynos_drm_overlay *overlay);
-       void (*commit)(struct device *subdrv_dev, int zpos);
-       void (*enable)(struct device *subdrv_dev, int zpos);
-       void (*disable)(struct device *subdrv_dev, int zpos);
-};
-
 /*
  * Exynos drm common overlay structure.
  *
@@ -138,77 +122,110 @@ struct exynos_drm_overlay {
  * Exynos DRM Display Structure.
  *     - this structure is common to analog tv, digital tv and lcd panel.
  *
- * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
- * @is_connected: check for that display is connected or not.
- * @get_edid: get edid modes from display driver.
- * @get_panel: get panel object from display driver.
+ * @initialize: initializes the display with drm_dev
+ * @remove: cleans up the display for removal
+ * @mode_fixup: fix mode data comparing to hw specific display mode.
+ * @mode_set: convert drm_display_mode to hw specific display mode and
+ *           would be called by encoder->mode_set().
  * @check_mode: check if mode is valid or not.
- * @power_on: display device on or off.
+ * @dpms: display device on or off.
+ * @commit: apply changes to hw
  */
+struct exynos_drm_display;
 struct exynos_drm_display_ops {
+       int (*initialize)(struct exynos_drm_display *display,
+                               struct drm_device *drm_dev);
+       int (*create_connector)(struct exynos_drm_display *display,
+                               struct drm_encoder *encoder);
+       void (*remove)(struct exynos_drm_display *display);
+       void (*mode_fixup)(struct exynos_drm_display *display,
+                               struct drm_connector *connector,
+                               const struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode);
+       void (*mode_set)(struct exynos_drm_display *display,
+                               struct drm_display_mode *mode);
+       int (*check_mode)(struct exynos_drm_display *display,
+                               struct drm_display_mode *mode);
+       void (*dpms)(struct exynos_drm_display *display, int mode);
+       void (*commit)(struct exynos_drm_display *display);
+};
+
+/*
+ * Exynos drm display structure, maps 1:1 with an encoder/connector
+ *
+ * @list: the list entry for this manager
+ * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @encoder: encoder object this display maps to
+ * @connector: connector object this display maps to
+ * @ops: pointer to callbacks for exynos drm specific functionality
+ * @ctx: A pointer to the display's implementation specific context
+ */
+struct exynos_drm_display {
+       struct list_head list;
        enum exynos_drm_output_type type;
-       bool (*is_connected)(struct device *dev);
-       struct edid *(*get_edid)(struct device *dev,
-                       struct drm_connector *connector);
-       void *(*get_panel)(struct device *dev);
-       int (*check_mode)(struct device *dev, struct drm_display_mode *mode);
-       int (*power_on)(struct device *dev, int mode);
+       struct drm_encoder *encoder;
+       struct drm_connector *connector;
+       struct exynos_drm_display_ops *ops;
+       void *ctx;
 };
 
 /*
  * Exynos drm manager ops
  *
+ * @initialize: initializes the manager with drm_dev
+ * @remove: cleans up the manager for removal
  * @dpms: control device power.
- * @apply: set timing, vblank and overlay data to registers.
- * @mode_fixup: fix mode data comparing to hw specific display mode.
- * @mode_set: convert drm_display_mode to hw specific display mode and
- *           would be called by encoder->mode_set().
- * @get_max_resol: get maximum resolution to specific hardware.
+ * @mode_fixup: fix mode data before applying it
+ * @mode_set: set the given mode to the manager
  * @commit: set current hw specific display mode to hw.
  * @enable_vblank: specific driver callback for enabling vblank interrupt.
  * @disable_vblank: specific driver callback for disabling vblank interrupt.
  * @wait_for_vblank: wait for vblank interrupt to make sure that
  *     hardware overlay is updated.
+ * @win_mode_set: copy drm overlay info to hw specific overlay info.
+ * @win_commit: apply hardware specific overlay data to registers.
+ * @win_enable: enable hardware specific overlay.
+ * @win_disable: disable hardware specific overlay.
  */
+struct exynos_drm_manager;
 struct exynos_drm_manager_ops {
-       void (*dpms)(struct device *subdrv_dev, int mode);
-       void (*apply)(struct device *subdrv_dev);
-       void (*mode_fixup)(struct device *subdrv_dev,
-                               struct drm_connector *connector,
+       int (*initialize)(struct exynos_drm_manager *mgr,
+                               struct drm_device *drm_dev, int pipe);
+       void (*remove)(struct exynos_drm_manager *mgr);
+       void (*dpms)(struct exynos_drm_manager *mgr, int mode);
+       bool (*mode_fixup)(struct exynos_drm_manager *mgr,
                                const struct drm_display_mode *mode,
                                struct drm_display_mode *adjusted_mode);
-       void (*mode_set)(struct device *subdrv_dev, void *mode);
-       void (*get_max_resol)(struct device *subdrv_dev, unsigned int *width,
-                               unsigned int *height);
-       void (*commit)(struct device *subdrv_dev);
-       int (*enable_vblank)(struct device *subdrv_dev);
-       void (*disable_vblank)(struct device *subdrv_dev);
-       void (*wait_for_vblank)(struct device *subdrv_dev);
+       void (*mode_set)(struct exynos_drm_manager *mgr,
+                               const struct drm_display_mode *mode);
+       void (*commit)(struct exynos_drm_manager *mgr);
+       int (*enable_vblank)(struct exynos_drm_manager *mgr);
+       void (*disable_vblank)(struct exynos_drm_manager *mgr);
+       void (*wait_for_vblank)(struct exynos_drm_manager *mgr);
+       void (*win_mode_set)(struct exynos_drm_manager *mgr,
+                               struct exynos_drm_overlay *overlay);
+       void (*win_commit)(struct exynos_drm_manager *mgr, int zpos);
+       void (*win_enable)(struct exynos_drm_manager *mgr, int zpos);
+       void (*win_disable)(struct exynos_drm_manager *mgr, int zpos);
 };
 
 /*
- * Exynos drm common manager structure.
+ * Exynos drm common manager structure, maps 1:1 with a crtc
  *
- * @dev: pointer to device object for subdrv device driver.
- *     sub drivers such as display controller or hdmi driver,
- *     have their own device object.
- * @ops: pointer to callbacks for exynos drm specific framebuffer.
- *     these callbacks should be set by specific drivers such fimd
- *     or hdmi driver and are used to control hardware global registers.
- * @overlay_ops: pointer to callbacks for exynos drm specific framebuffer.
- *     these callbacks should be set by specific drivers such fimd
- *     or hdmi driver and are used to control hardware overlay reigsters.
- * @display: pointer to callbacks for exynos drm specific framebuffer.
- *     these callbacks should be set by specific drivers such fimd
- *     or hdmi driver and are used to control display devices such as
- *     analog tv, digital tv and lcd panel and also get timing data for them.
+ * @list: the list entry for this manager
+ * @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
+ * @drm_dev: pointer to the drm device
+ * @pipe: the pipe number for this crtc/manager
+ * @ops: pointer to callbacks for exynos drm specific functionality
+ * @ctx: A pointer to the manager's implementation specific context
  */
 struct exynos_drm_manager {
-       struct device *dev;
+       struct list_head list;
+       enum exynos_drm_output_type type;
+       struct drm_device *drm_dev;
        int pipe;
        struct exynos_drm_manager_ops *ops;
-       struct exynos_drm_overlay_ops *overlay_ops;
-       struct exynos_drm_display_ops *display_ops;
+       void *ctx;
 };
 
 struct exynos_drm_g2d_private {
@@ -271,14 +288,11 @@ struct exynos_drm_private {
  *     by probe callback.
  * @open: this would be called with drm device file open.
  * @close: this would be called with drm device file close.
- * @encoder: encoder object owned by this sub driver.
- * @connector: connector object owned by this sub driver.
  */
 struct exynos_drm_subdrv {
        struct list_head list;
        struct device *dev;
        struct drm_device *drm_dev;
-       struct exynos_drm_manager *manager;
 
        int (*probe)(struct drm_device *drm_dev, struct device *dev);
        void (*remove)(struct drm_device *drm_dev, struct device *dev);
@@ -286,9 +300,6 @@ struct exynos_drm_subdrv {
                        struct drm_file *file);
        void (*close)(struct drm_device *drm_dev, struct device *dev,
                        struct drm_file *file);
-
-       struct drm_encoder *encoder;
-       struct drm_connector *connector;
 };
 
 /*
@@ -303,6 +314,16 @@ int exynos_drm_device_register(struct drm_device *dev);
  */
 int exynos_drm_device_unregister(struct drm_device *dev);
 
+int exynos_drm_initialize_managers(struct drm_device *dev);
+void exynos_drm_remove_managers(struct drm_device *dev);
+int exynos_drm_initialize_displays(struct drm_device *dev);
+void exynos_drm_remove_displays(struct drm_device *dev);
+
+int exynos_drm_manager_register(struct exynos_drm_manager *manager);
+int exynos_drm_manager_unregister(struct exynos_drm_manager *manager);
+int exynos_drm_display_register(struct exynos_drm_display *display);
+int exynos_drm_display_unregister(struct exynos_drm_display *display);
+
 /*
  * this function would be called by sub drivers such as display controller
  * or hdmi driver to register this sub driver object to exynos drm driver
@@ -338,6 +359,16 @@ int exynos_platform_device_ipp_register(void);
  */
 void exynos_platform_device_ipp_unregister(void);
 
+#ifdef CONFIG_DRM_EXYNOS_DPI
+int exynos_dpi_probe(struct device *dev);
+int exynos_dpi_remove(struct device *dev);
+#else
+static inline int exynos_dpi_probe(struct device *dev) { return 0; }
+static inline int exynos_dpi_remove(struct device *dev) { return 0; }
+#endif
+
+extern struct platform_driver dp_driver;
+extern struct platform_driver dsi_driver;
 extern struct platform_driver fimd_driver;
 extern struct platform_driver hdmi_driver;
 extern struct platform_driver mixer_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dsi.c b/drivers/gpu/drm/exynos/exynos_drm_dsi.c
new file mode 100644 (file)
index 0000000..eb73e3b
--- /dev/null
@@ -0,0 +1,1524 @@
+/*
+ * Samsung SoC MIPI DSI Master driver.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ *
+ * Contacts: Tomasz Figa <t.figa@samsung.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 <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <linux/clk.h>
+#include <linux/irq.h>
+#include <linux/phy/phy.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+#include <video/videomode.h>
+
+#include "exynos_drm_drv.h"
+
+/* returns true iff both arguments logically differs */
+#define NEQV(a, b) (!(a) ^ !(b))
+
+#define DSIM_STATUS_REG                0x0     /* Status register */
+#define DSIM_SWRST_REG         0x4     /* Software reset register */
+#define DSIM_CLKCTRL_REG       0x8     /* Clock control register */
+#define DSIM_TIMEOUT_REG       0xc     /* Time out register */
+#define DSIM_CONFIG_REG                0x10    /* Configuration register */
+#define DSIM_ESCMODE_REG       0x14    /* Escape mode register */
+
+/* Main display image resolution register */
+#define DSIM_MDRESOL_REG       0x18
+#define DSIM_MVPORCH_REG       0x1c    /* Main display Vporch register */
+#define DSIM_MHPORCH_REG       0x20    /* Main display Hporch register */
+#define DSIM_MSYNC_REG         0x24    /* Main display sync area register */
+
+/* Sub display image resolution register */
+#define DSIM_SDRESOL_REG       0x28
+#define DSIM_INTSRC_REG                0x2c    /* Interrupt source register */
+#define DSIM_INTMSK_REG                0x30    /* Interrupt mask register */
+#define DSIM_PKTHDR_REG                0x34    /* Packet Header FIFO register */
+#define DSIM_PAYLOAD_REG       0x38    /* Payload FIFO register */
+#define DSIM_RXFIFO_REG                0x3c    /* Read FIFO register */
+#define DSIM_FIFOTHLD_REG      0x40    /* FIFO threshold level register */
+#define DSIM_FIFOCTRL_REG      0x44    /* FIFO status and control register */
+
+/* FIFO memory AC characteristic register */
+#define DSIM_PLLCTRL_REG       0x4c    /* PLL control register */
+#define DSIM_PLLTMR_REG                0x50    /* PLL timer register */
+#define DSIM_PHYACCHR_REG      0x54    /* D-PHY AC characteristic register */
+#define DSIM_PHYACCHR1_REG     0x58    /* D-PHY AC characteristic register1 */
+
+/* DSIM_STATUS */
+#define DSIM_STOP_STATE_DAT(x)         (((x) & 0xf) << 0)
+#define DSIM_STOP_STATE_CLK            (1 << 8)
+#define DSIM_TX_READY_HS_CLK           (1 << 10)
+#define DSIM_PLL_STABLE                        (1 << 31)
+
+/* DSIM_SWRST */
+#define DSIM_FUNCRST                   (1 << 16)
+#define DSIM_SWRST                     (1 << 0)
+
+/* DSIM_TIMEOUT */
+#define DSIM_LPDR_TIMEOUT(x)           ((x) << 0)
+#define DSIM_BTA_TIMEOUT(x)            ((x) << 16)
+
+/* DSIM_CLKCTRL */
+#define DSIM_ESC_PRESCALER(x)          (((x) & 0xffff) << 0)
+#define DSIM_ESC_PRESCALER_MASK                (0xffff << 0)
+#define DSIM_LANE_ESC_CLK_EN_CLK       (1 << 19)
+#define DSIM_LANE_ESC_CLK_EN_DATA(x)   (((x) & 0xf) << 20)
+#define DSIM_LANE_ESC_CLK_EN_DATA_MASK (0xf << 20)
+#define DSIM_BYTE_CLKEN                        (1 << 24)
+#define DSIM_BYTE_CLK_SRC(x)           (((x) & 0x3) << 25)
+#define DSIM_BYTE_CLK_SRC_MASK         (0x3 << 25)
+#define DSIM_PLL_BYPASS                        (1 << 27)
+#define DSIM_ESC_CLKEN                 (1 << 28)
+#define DSIM_TX_REQUEST_HSCLK          (1 << 31)
+
+/* DSIM_CONFIG */
+#define DSIM_LANE_EN_CLK               (1 << 0)
+#define DSIM_LANE_EN(x)                        (((x) & 0xf) << 1)
+#define DSIM_NUM_OF_DATA_LANE(x)       (((x) & 0x3) << 5)
+#define DSIM_SUB_PIX_FORMAT(x)         (((x) & 0x7) << 8)
+#define DSIM_MAIN_PIX_FORMAT_MASK      (0x7 << 12)
+#define DSIM_MAIN_PIX_FORMAT_RGB888    (0x7 << 12)
+#define DSIM_MAIN_PIX_FORMAT_RGB666    (0x6 << 12)
+#define DSIM_MAIN_PIX_FORMAT_RGB666_P  (0x5 << 12)
+#define DSIM_MAIN_PIX_FORMAT_RGB565    (0x4 << 12)
+#define DSIM_SUB_VC                    (((x) & 0x3) << 16)
+#define DSIM_MAIN_VC                   (((x) & 0x3) << 18)
+#define DSIM_HSA_MODE                  (1 << 20)
+#define DSIM_HBP_MODE                  (1 << 21)
+#define DSIM_HFP_MODE                  (1 << 22)
+#define DSIM_HSE_MODE                  (1 << 23)
+#define DSIM_AUTO_MODE                 (1 << 24)
+#define DSIM_VIDEO_MODE                        (1 << 25)
+#define DSIM_BURST_MODE                        (1 << 26)
+#define DSIM_SYNC_INFORM               (1 << 27)
+#define DSIM_EOT_DISABLE               (1 << 28)
+#define DSIM_MFLUSH_VS                 (1 << 29)
+
+/* DSIM_ESCMODE */
+#define DSIM_TX_TRIGGER_RST            (1 << 4)
+#define DSIM_TX_LPDT_LP                        (1 << 6)
+#define DSIM_CMD_LPDT_LP               (1 << 7)
+#define DSIM_FORCE_BTA                 (1 << 16)
+#define DSIM_FORCE_STOP_STATE          (1 << 20)
+#define DSIM_STOP_STATE_CNT(x)         (((x) & 0x7ff) << 21)
+#define DSIM_STOP_STATE_CNT_MASK       (0x7ff << 21)
+
+/* DSIM_MDRESOL */
+#define DSIM_MAIN_STAND_BY             (1 << 31)
+#define DSIM_MAIN_VRESOL(x)            (((x) & 0x7ff) << 16)
+#define DSIM_MAIN_HRESOL(x)            (((x) & 0X7ff) << 0)
+
+/* DSIM_MVPORCH */
+#define DSIM_CMD_ALLOW(x)              ((x) << 28)
+#define DSIM_STABLE_VFP(x)             ((x) << 16)
+#define DSIM_MAIN_VBP(x)               ((x) << 0)
+#define DSIM_CMD_ALLOW_MASK            (0xf << 28)
+#define DSIM_STABLE_VFP_MASK           (0x7ff << 16)
+#define DSIM_MAIN_VBP_MASK             (0x7ff << 0)
+
+/* DSIM_MHPORCH */
+#define DSIM_MAIN_HFP(x)               ((x) << 16)
+#define DSIM_MAIN_HBP(x)               ((x) << 0)
+#define DSIM_MAIN_HFP_MASK             ((0xffff) << 16)
+#define DSIM_MAIN_HBP_MASK             ((0xffff) << 0)
+
+/* DSIM_MSYNC */
+#define DSIM_MAIN_VSA(x)               ((x) << 22)
+#define DSIM_MAIN_HSA(x)               ((x) << 0)
+#define DSIM_MAIN_VSA_MASK             ((0x3ff) << 22)
+#define DSIM_MAIN_HSA_MASK             ((0xffff) << 0)
+
+/* DSIM_SDRESOL */
+#define DSIM_SUB_STANDY(x)             ((x) << 31)
+#define DSIM_SUB_VRESOL(x)             ((x) << 16)
+#define DSIM_SUB_HRESOL(x)             ((x) << 0)
+#define DSIM_SUB_STANDY_MASK           ((0x1) << 31)
+#define DSIM_SUB_VRESOL_MASK           ((0x7ff) << 16)
+#define DSIM_SUB_HRESOL_MASK           ((0x7ff) << 0)
+
+/* DSIM_INTSRC */
+#define DSIM_INT_PLL_STABLE            (1 << 31)
+#define DSIM_INT_SW_RST_RELEASE                (1 << 30)
+#define DSIM_INT_SFR_FIFO_EMPTY                (1 << 29)
+#define DSIM_INT_BTA                   (1 << 25)
+#define DSIM_INT_FRAME_DONE            (1 << 24)
+#define DSIM_INT_RX_TIMEOUT            (1 << 21)
+#define DSIM_INT_BTA_TIMEOUT           (1 << 20)
+#define DSIM_INT_RX_DONE               (1 << 18)
+#define DSIM_INT_RX_TE                 (1 << 17)
+#define DSIM_INT_RX_ACK                        (1 << 16)
+#define DSIM_INT_RX_ECC_ERR            (1 << 15)
+#define DSIM_INT_RX_CRC_ERR            (1 << 14)
+
+/* DSIM_FIFOCTRL */
+#define DSIM_RX_DATA_FULL              (1 << 25)
+#define DSIM_RX_DATA_EMPTY             (1 << 24)
+#define DSIM_SFR_HEADER_FULL           (1 << 23)
+#define DSIM_SFR_HEADER_EMPTY          (1 << 22)
+#define DSIM_SFR_PAYLOAD_FULL          (1 << 21)
+#define DSIM_SFR_PAYLOAD_EMPTY         (1 << 20)
+#define DSIM_I80_HEADER_FULL           (1 << 19)
+#define DSIM_I80_HEADER_EMPTY          (1 << 18)
+#define DSIM_I80_PAYLOAD_FULL          (1 << 17)
+#define DSIM_I80_PAYLOAD_EMPTY         (1 << 16)
+#define DSIM_SD_HEADER_FULL            (1 << 15)
+#define DSIM_SD_HEADER_EMPTY           (1 << 14)
+#define DSIM_SD_PAYLOAD_FULL           (1 << 13)
+#define DSIM_SD_PAYLOAD_EMPTY          (1 << 12)
+#define DSIM_MD_HEADER_FULL            (1 << 11)
+#define DSIM_MD_HEADER_EMPTY           (1 << 10)
+#define DSIM_MD_PAYLOAD_FULL           (1 << 9)
+#define DSIM_MD_PAYLOAD_EMPTY          (1 << 8)
+#define DSIM_RX_FIFO                   (1 << 4)
+#define DSIM_SFR_FIFO                  (1 << 3)
+#define DSIM_I80_FIFO                  (1 << 2)
+#define DSIM_SD_FIFO                   (1 << 1)
+#define DSIM_MD_FIFO                   (1 << 0)
+
+/* DSIM_PHYACCHR */
+#define DSIM_AFC_EN                    (1 << 14)
+#define DSIM_AFC_CTL(x)                        (((x) & 0x7) << 5)
+
+/* DSIM_PLLCTRL */
+#define DSIM_FREQ_BAND(x)              ((x) << 24)
+#define DSIM_PLL_EN                    (1 << 23)
+#define DSIM_PLL_P(x)                  ((x) << 13)
+#define DSIM_PLL_M(x)                  ((x) << 4)
+#define DSIM_PLL_S(x)                  ((x) << 1)
+
+#define DSI_MAX_BUS_WIDTH              4
+#define DSI_NUM_VIRTUAL_CHANNELS       4
+#define DSI_TX_FIFO_SIZE               2048
+#define DSI_RX_FIFO_SIZE               256
+#define DSI_XFER_TIMEOUT_MS            100
+#define DSI_RX_FIFO_EMPTY              0x30800002
+
+enum exynos_dsi_transfer_type {
+       EXYNOS_DSI_TX,
+       EXYNOS_DSI_RX,
+};
+
+struct exynos_dsi_transfer {
+       struct list_head list;
+       struct completion completed;
+       int result;
+       u8 data_id;
+       u8 data[2];
+       u16 flags;
+
+       const u8 *tx_payload;
+       u16 tx_len;
+       u16 tx_done;
+
+       u8 *rx_payload;
+       u16 rx_len;
+       u16 rx_done;
+};
+
+#define DSIM_STATE_ENABLED             BIT(0)
+#define DSIM_STATE_INITIALIZED         BIT(1)
+#define DSIM_STATE_CMD_LPM             BIT(2)
+
+struct exynos_dsi {
+       struct mipi_dsi_host dsi_host;
+       struct drm_connector connector;
+       struct drm_encoder *encoder;
+       struct device_node *panel_node;
+       struct drm_panel *panel;
+       struct device *dev;
+
+       void __iomem *reg_base;
+       struct phy *phy;
+       struct clk *pll_clk;
+       struct clk *bus_clk;
+       struct regulator_bulk_data supplies[2];
+       int irq;
+
+       u32 pll_clk_rate;
+       u32 burst_clk_rate;
+       u32 esc_clk_rate;
+       u32 lanes;
+       u32 mode_flags;
+       u32 format;
+       struct videomode vm;
+
+       int state;
+       struct drm_property *brightness;
+       struct completion completed;
+
+       spinlock_t transfer_lock; /* protects transfer_list */
+       struct list_head transfer_list;
+};
+
+#define host_to_dsi(host) container_of(host, struct exynos_dsi, dsi_host)
+#define connector_to_dsi(c) container_of(c, struct exynos_dsi, connector)
+
+static void exynos_dsi_wait_for_reset(struct exynos_dsi *dsi)
+{
+       if (wait_for_completion_timeout(&dsi->completed, msecs_to_jiffies(300)))
+               return;
+
+       dev_err(dsi->dev, "timeout waiting for reset\n");
+}
+
+static void exynos_dsi_reset(struct exynos_dsi *dsi)
+{
+       reinit_completion(&dsi->completed);
+       writel(DSIM_SWRST, dsi->reg_base + DSIM_SWRST_REG);
+}
+
+#ifndef MHZ
+#define MHZ    (1000*1000)
+#endif
+
+static unsigned long exynos_dsi_pll_find_pms(struct exynos_dsi *dsi,
+               unsigned long fin, unsigned long fout, u8 *p, u16 *m, u8 *s)
+{
+       unsigned long best_freq = 0;
+       u32 min_delta = 0xffffffff;
+       u8 p_min, p_max;
+       u8 _p, uninitialized_var(best_p);
+       u16 _m, uninitialized_var(best_m);
+       u8 _s, uninitialized_var(best_s);
+
+       p_min = DIV_ROUND_UP(fin, (12 * MHZ));
+       p_max = fin / (6 * MHZ);
+
+       for (_p = p_min; _p <= p_max; ++_p) {
+               for (_s = 0; _s <= 5; ++_s) {
+                       u64 tmp;
+                       u32 delta;
+
+                       tmp = (u64)fout * (_p << _s);
+                       do_div(tmp, fin);
+                       _m = tmp;
+                       if (_m < 41 || _m > 125)
+                               continue;
+
+                       tmp = (u64)_m * fin;
+                       do_div(tmp, _p);
+                       if (tmp < 500 * MHZ || tmp > 1000 * MHZ)
+                               continue;
+
+                       tmp = (u64)_m * fin;
+                       do_div(tmp, _p << _s);
+
+                       delta = abs(fout - tmp);
+                       if (delta < min_delta) {
+                               best_p = _p;
+                               best_m = _m;
+                               best_s = _s;
+                               min_delta = delta;
+                               best_freq = tmp;
+                       }
+               }
+       }
+
+       if (best_freq) {
+               *p = best_p;
+               *m = best_m;
+               *s = best_s;
+       }
+
+       return best_freq;
+}
+
+static unsigned long exynos_dsi_set_pll(struct exynos_dsi *dsi,
+                                       unsigned long freq)
+{
+       static const unsigned long freq_bands[] = {
+               100 * MHZ, 120 * MHZ, 160 * MHZ, 200 * MHZ,
+               270 * MHZ, 320 * MHZ, 390 * MHZ, 450 * MHZ,
+               510 * MHZ, 560 * MHZ, 640 * MHZ, 690 * MHZ,
+               770 * MHZ, 870 * MHZ, 950 * MHZ,
+       };
+       unsigned long fin, fout;
+       int timeout, band;
+       u8 p, s;
+       u16 m;
+       u32 reg;
+
+       clk_set_rate(dsi->pll_clk, dsi->pll_clk_rate);
+
+       fin = clk_get_rate(dsi->pll_clk);
+       if (!fin) {
+               dev_err(dsi->dev, "failed to get PLL clock frequency\n");
+               return 0;
+       }
+
+       dev_dbg(dsi->dev, "PLL input frequency: %lu\n", fin);
+
+       fout = exynos_dsi_pll_find_pms(dsi, fin, freq, &p, &m, &s);
+       if (!fout) {
+               dev_err(dsi->dev,
+                       "failed to find PLL PMS for requested frequency\n");
+               return -EFAULT;
+       }
+
+       for (band = 0; band < ARRAY_SIZE(freq_bands); ++band)
+               if (fout < freq_bands[band])
+                       break;
+
+       dev_dbg(dsi->dev, "PLL freq %lu, (p %d, m %d, s %d), band %d\n", fout,
+               p, m, s, band);
+
+       writel(500, dsi->reg_base + DSIM_PLLTMR_REG);
+
+       reg = DSIM_FREQ_BAND(band) | DSIM_PLL_EN
+                       | DSIM_PLL_P(p) | DSIM_PLL_M(m) | DSIM_PLL_S(s);
+       writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG);
+
+       timeout = 1000;
+       do {
+               if (timeout-- == 0) {
+                       dev_err(dsi->dev, "PLL failed to stabilize\n");
+                       return -EFAULT;
+               }
+               reg = readl(dsi->reg_base + DSIM_STATUS_REG);
+       } while ((reg & DSIM_PLL_STABLE) == 0);
+
+       return fout;
+}
+
+static int exynos_dsi_enable_clock(struct exynos_dsi *dsi)
+{
+       unsigned long hs_clk, byte_clk, esc_clk;
+       unsigned long esc_div;
+       u32 reg;
+
+       hs_clk = exynos_dsi_set_pll(dsi, dsi->burst_clk_rate);
+       if (!hs_clk) {
+               dev_err(dsi->dev, "failed to configure DSI PLL\n");
+               return -EFAULT;
+       }
+
+       byte_clk = hs_clk / 8;
+       esc_div = DIV_ROUND_UP(byte_clk, dsi->esc_clk_rate);
+       esc_clk = byte_clk / esc_div;
+
+       if (esc_clk > 20 * MHZ) {
+               ++esc_div;
+               esc_clk = byte_clk / esc_div;
+       }
+
+       dev_dbg(dsi->dev, "hs_clk = %lu, byte_clk = %lu, esc_clk = %lu\n",
+               hs_clk, byte_clk, esc_clk);
+
+       reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG);
+       reg &= ~(DSIM_ESC_PRESCALER_MASK | DSIM_LANE_ESC_CLK_EN_CLK
+                       | DSIM_LANE_ESC_CLK_EN_DATA_MASK | DSIM_PLL_BYPASS
+                       | DSIM_BYTE_CLK_SRC_MASK);
+       reg |= DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN
+                       | DSIM_ESC_PRESCALER(esc_div)
+                       | DSIM_LANE_ESC_CLK_EN_CLK
+                       | DSIM_LANE_ESC_CLK_EN_DATA(BIT(dsi->lanes) - 1)
+                       | DSIM_BYTE_CLK_SRC(0)
+                       | DSIM_TX_REQUEST_HSCLK;
+       writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG);
+
+       return 0;
+}
+
+static void exynos_dsi_disable_clock(struct exynos_dsi *dsi)
+{
+       u32 reg;
+
+       reg = readl(dsi->reg_base + DSIM_CLKCTRL_REG);
+       reg &= ~(DSIM_LANE_ESC_CLK_EN_CLK | DSIM_LANE_ESC_CLK_EN_DATA_MASK
+                       | DSIM_ESC_CLKEN | DSIM_BYTE_CLKEN);
+       writel(reg, dsi->reg_base + DSIM_CLKCTRL_REG);
+
+       reg = readl(dsi->reg_base + DSIM_PLLCTRL_REG);
+       reg &= ~DSIM_PLL_EN;
+       writel(reg, dsi->reg_base + DSIM_PLLCTRL_REG);
+}
+
+static int exynos_dsi_init_link(struct exynos_dsi *dsi)
+{
+       int timeout;
+       u32 reg;
+       u32 lanes_mask;
+
+       /* Initialize FIFO pointers */
+       reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG);
+       reg &= ~0x1f;
+       writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG);
+
+       usleep_range(9000, 11000);
+
+       reg |= 0x1f;
+       writel(reg, dsi->reg_base + DSIM_FIFOCTRL_REG);
+
+       usleep_range(9000, 11000);
+
+       /* DSI configuration */
+       reg = 0;
+
+       if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+               reg |= DSIM_VIDEO_MODE;
+
+               if (!(dsi->mode_flags & MIPI_DSI_MODE_VSYNC_FLUSH))
+                       reg |= DSIM_MFLUSH_VS;
+               if (!(dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET))
+                       reg |= DSIM_EOT_DISABLE;
+               if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE)
+                       reg |= DSIM_SYNC_INFORM;
+               if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
+                       reg |= DSIM_BURST_MODE;
+               if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_AUTO_VERT)
+                       reg |= DSIM_AUTO_MODE;
+               if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSE)
+                       reg |= DSIM_HSE_MODE;
+               if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HFP))
+                       reg |= DSIM_HFP_MODE;
+               if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HBP))
+                       reg |= DSIM_HBP_MODE;
+               if (!(dsi->mode_flags & MIPI_DSI_MODE_VIDEO_HSA))
+                       reg |= DSIM_HSA_MODE;
+       }
+
+       switch (dsi->format) {
+       case MIPI_DSI_FMT_RGB888:
+               reg |= DSIM_MAIN_PIX_FORMAT_RGB888;
+               break;
+       case MIPI_DSI_FMT_RGB666:
+               reg |= DSIM_MAIN_PIX_FORMAT_RGB666;
+               break;
+       case MIPI_DSI_FMT_RGB666_PACKED:
+               reg |= DSIM_MAIN_PIX_FORMAT_RGB666_P;
+               break;
+       case MIPI_DSI_FMT_RGB565:
+               reg |= DSIM_MAIN_PIX_FORMAT_RGB565;
+               break;
+       default:
+               dev_err(dsi->dev, "invalid pixel format\n");
+               return -EINVAL;
+       }
+
+       reg |= DSIM_NUM_OF_DATA_LANE(dsi->lanes - 1);
+
+       writel(reg, dsi->reg_base + DSIM_CONFIG_REG);
+
+       reg |= DSIM_LANE_EN_CLK;
+       writel(reg, dsi->reg_base + DSIM_CONFIG_REG);
+
+       lanes_mask = BIT(dsi->lanes) - 1;
+       reg |= DSIM_LANE_EN(lanes_mask);
+       writel(reg, dsi->reg_base + DSIM_CONFIG_REG);
+
+       /* Check clock and data lane state are stop state */
+       timeout = 100;
+       do {
+               if (timeout-- == 0) {
+                       dev_err(dsi->dev, "waiting for bus lanes timed out\n");
+                       return -EFAULT;
+               }
+
+               reg = readl(dsi->reg_base + DSIM_STATUS_REG);
+               if ((reg & DSIM_STOP_STATE_DAT(lanes_mask))
+                   != DSIM_STOP_STATE_DAT(lanes_mask))
+                       continue;
+       } while (!(reg & (DSIM_STOP_STATE_CLK | DSIM_TX_READY_HS_CLK)));
+
+       reg = readl(dsi->reg_base + DSIM_ESCMODE_REG);
+       reg &= ~DSIM_STOP_STATE_CNT_MASK;
+       reg |= DSIM_STOP_STATE_CNT(0xf);
+       writel(reg, dsi->reg_base + DSIM_ESCMODE_REG);
+
+       reg = DSIM_BTA_TIMEOUT(0xff) | DSIM_LPDR_TIMEOUT(0xffff);
+       writel(reg, dsi->reg_base + DSIM_TIMEOUT_REG);
+
+       return 0;
+}
+
+static void exynos_dsi_set_display_mode(struct exynos_dsi *dsi)
+{
+       struct videomode *vm = &dsi->vm;
+       u32 reg;
+
+       if (dsi->mode_flags & MIPI_DSI_MODE_VIDEO) {
+               reg = DSIM_CMD_ALLOW(0xf)
+                       | DSIM_STABLE_VFP(vm->vfront_porch)
+                       | DSIM_MAIN_VBP(vm->vback_porch);
+               writel(reg, dsi->reg_base + DSIM_MVPORCH_REG);
+
+               reg = DSIM_MAIN_HFP(vm->hfront_porch)
+                       | DSIM_MAIN_HBP(vm->hback_porch);
+               writel(reg, dsi->reg_base + DSIM_MHPORCH_REG);
+
+               reg = DSIM_MAIN_VSA(vm->vsync_len)
+                       | DSIM_MAIN_HSA(vm->hsync_len);
+               writel(reg, dsi->reg_base + DSIM_MSYNC_REG);
+       }
+
+       reg = DSIM_MAIN_HRESOL(vm->hactive) | DSIM_MAIN_VRESOL(vm->vactive);
+       writel(reg, dsi->reg_base + DSIM_MDRESOL_REG);
+
+       dev_dbg(dsi->dev, "LCD size = %dx%d\n", vm->hactive, vm->vactive);
+}
+
+static void exynos_dsi_set_display_enable(struct exynos_dsi *dsi, bool enable)
+{
+       u32 reg;
+
+       reg = readl(dsi->reg_base + DSIM_MDRESOL_REG);
+       if (enable)
+               reg |= DSIM_MAIN_STAND_BY;
+       else
+               reg &= ~DSIM_MAIN_STAND_BY;
+       writel(reg, dsi->reg_base + DSIM_MDRESOL_REG);
+}
+
+static int exynos_dsi_wait_for_hdr_fifo(struct exynos_dsi *dsi)
+{
+       int timeout = 2000;
+
+       do {
+               u32 reg = readl(dsi->reg_base + DSIM_FIFOCTRL_REG);
+
+               if (!(reg & DSIM_SFR_HEADER_FULL))
+                       return 0;
+
+               if (!cond_resched())
+                       usleep_range(950, 1050);
+       } while (--timeout);
+
+       return -ETIMEDOUT;
+}
+
+static void exynos_dsi_set_cmd_lpm(struct exynos_dsi *dsi, bool lpm)
+{
+       u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG);
+
+       if (lpm)
+               v |= DSIM_CMD_LPDT_LP;
+       else
+               v &= ~DSIM_CMD_LPDT_LP;
+
+       writel(v, dsi->reg_base + DSIM_ESCMODE_REG);
+}
+
+static void exynos_dsi_force_bta(struct exynos_dsi *dsi)
+{
+       u32 v = readl(dsi->reg_base + DSIM_ESCMODE_REG);
+
+       v |= DSIM_FORCE_BTA;
+       writel(v, dsi->reg_base + DSIM_ESCMODE_REG);
+}
+
+static void exynos_dsi_send_to_fifo(struct exynos_dsi *dsi,
+                                       struct exynos_dsi_transfer *xfer)
+{
+       struct device *dev = dsi->dev;
+       const u8 *payload = xfer->tx_payload + xfer->tx_done;
+       u16 length = xfer->tx_len - xfer->tx_done;
+       bool first = !xfer->tx_done;
+       u32 reg;
+
+       dev_dbg(dev, "< xfer %p: tx len %u, done %u, rx len %u, done %u\n",
+               xfer, xfer->tx_len, xfer->tx_done, xfer->rx_len, xfer->rx_done);
+
+       if (length > DSI_TX_FIFO_SIZE)
+               length = DSI_TX_FIFO_SIZE;
+
+       xfer->tx_done += length;
+
+       /* Send payload */
+       while (length >= 4) {
+               reg = (payload[3] << 24) | (payload[2] << 16)
+                                       | (payload[1] << 8) | payload[0];
+               writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG);
+               payload += 4;
+               length -= 4;
+       }
+
+       reg = 0;
+       switch (length) {
+       case 3:
+               reg |= payload[2] << 16;
+               /* Fall through */
+       case 2:
+               reg |= payload[1] << 8;
+               /* Fall through */
+       case 1:
+               reg |= payload[0];
+               writel(reg, dsi->reg_base + DSIM_PAYLOAD_REG);
+               break;
+       case 0:
+               /* Do nothing */
+               break;
+       }
+
+       /* Send packet header */
+       if (!first)
+               return;
+
+       reg = (xfer->data[1] << 16) | (xfer->data[0] << 8) | xfer->data_id;
+       if (exynos_dsi_wait_for_hdr_fifo(dsi)) {
+               dev_err(dev, "waiting for header FIFO timed out\n");
+               return;
+       }
+
+       if (NEQV(xfer->flags & MIPI_DSI_MSG_USE_LPM,
+                dsi->state & DSIM_STATE_CMD_LPM)) {
+               exynos_dsi_set_cmd_lpm(dsi, xfer->flags & MIPI_DSI_MSG_USE_LPM);
+               dsi->state ^= DSIM_STATE_CMD_LPM;
+       }
+
+       writel(reg, dsi->reg_base + DSIM_PKTHDR_REG);
+
+       if (xfer->flags & MIPI_DSI_MSG_REQ_ACK)
+               exynos_dsi_force_bta(dsi);
+}
+
+static void exynos_dsi_read_from_fifo(struct exynos_dsi *dsi,
+                                       struct exynos_dsi_transfer *xfer)
+{
+       u8 *payload = xfer->rx_payload + xfer->rx_done;
+       bool first = !xfer->rx_done;
+       struct device *dev = dsi->dev;
+       u16 length;
+       u32 reg;
+
+       if (first) {
+               reg = readl(dsi->reg_base + DSIM_RXFIFO_REG);
+
+               switch (reg & 0x3f) {
+               case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_2BYTE:
+               case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_2BYTE:
+                       if (xfer->rx_len >= 2) {
+                               payload[1] = reg >> 16;
+                               ++xfer->rx_done;
+                       }
+                       /* Fall through */
+               case MIPI_DSI_RX_GENERIC_SHORT_READ_RESPONSE_1BYTE:
+               case MIPI_DSI_RX_DCS_SHORT_READ_RESPONSE_1BYTE:
+                       payload[0] = reg >> 8;
+                       ++xfer->rx_done;
+                       xfer->rx_len = xfer->rx_done;
+                       xfer->result = 0;
+                       goto clear_fifo;
+               case MIPI_DSI_RX_ACKNOWLEDGE_AND_ERROR_REPORT:
+                       dev_err(dev, "DSI Error Report: 0x%04x\n",
+                               (reg >> 8) & 0xffff);
+                       xfer->result = 0;
+                       goto clear_fifo;
+               }
+
+               length = (reg >> 8) & 0xffff;
+               if (length > xfer->rx_len) {
+                       dev_err(dev,
+                               "response too long (%u > %u bytes), stripping\n",
+                               xfer->rx_len, length);
+                       length = xfer->rx_len;
+               } else if (length < xfer->rx_len)
+                       xfer->rx_len = length;
+       }
+
+       length = xfer->rx_len - xfer->rx_done;
+       xfer->rx_done += length;
+
+       /* Receive payload */
+       while (length >= 4) {
+               reg = readl(dsi->reg_base + DSIM_RXFIFO_REG);
+               payload[0] = (reg >>  0) & 0xff;
+               payload[1] = (reg >>  8) & 0xff;
+               payload[2] = (reg >> 16) & 0xff;
+               payload[3] = (reg >> 24) & 0xff;
+               payload += 4;
+               length -= 4;
+       }
+
+       if (length) {
+               reg = readl(dsi->reg_base + DSIM_RXFIFO_REG);
+               switch (length) {
+               case 3:
+                       payload[2] = (reg >> 16) & 0xff;
+                       /* Fall through */
+               case 2:
+                       payload[1] = (reg >> 8) & 0xff;
+                       /* Fall through */
+               case 1:
+                       payload[0] = reg & 0xff;
+               }
+       }
+
+       if (xfer->rx_done == xfer->rx_len)
+               xfer->result = 0;
+
+clear_fifo:
+       length = DSI_RX_FIFO_SIZE / 4;
+       do {
+               reg = readl(dsi->reg_base + DSIM_RXFIFO_REG);
+               if (reg == DSI_RX_FIFO_EMPTY)
+                       break;
+       } while (--length);
+}
+
+static void exynos_dsi_transfer_start(struct exynos_dsi *dsi)
+{
+       unsigned long flags;
+       struct exynos_dsi_transfer *xfer;
+       bool start = false;
+
+again:
+       spin_lock_irqsave(&dsi->transfer_lock, flags);
+
+       if (list_empty(&dsi->transfer_list)) {
+               spin_unlock_irqrestore(&dsi->transfer_lock, flags);
+               return;
+       }
+
+       xfer = list_first_entry(&dsi->transfer_list,
+                                       struct exynos_dsi_transfer, list);
+
+       spin_unlock_irqrestore(&dsi->transfer_lock, flags);
+
+       if (xfer->tx_len && xfer->tx_done == xfer->tx_len)
+               /* waiting for RX */
+               return;
+
+       exynos_dsi_send_to_fifo(dsi, xfer);
+
+       if (xfer->tx_len || xfer->rx_len)
+               return;
+
+       xfer->result = 0;
+       complete(&xfer->completed);
+
+       spin_lock_irqsave(&dsi->transfer_lock, flags);
+
+       list_del_init(&xfer->list);
+       start = !list_empty(&dsi->transfer_list);
+
+       spin_unlock_irqrestore(&dsi->transfer_lock, flags);
+
+       if (start)
+               goto again;
+}
+
+static bool exynos_dsi_transfer_finish(struct exynos_dsi *dsi)
+{
+       struct exynos_dsi_transfer *xfer;
+       unsigned long flags;
+       bool start = true;
+
+       spin_lock_irqsave(&dsi->transfer_lock, flags);
+
+       if (list_empty(&dsi->transfer_list)) {
+               spin_unlock_irqrestore(&dsi->transfer_lock, flags);
+               return false;
+       }
+
+       xfer = list_first_entry(&dsi->transfer_list,
+                                       struct exynos_dsi_transfer, list);
+
+       spin_unlock_irqrestore(&dsi->transfer_lock, flags);
+
+       dev_dbg(dsi->dev,
+               "> xfer %p, tx_len %u, tx_done %u, rx_len %u, rx_done %u\n",
+               xfer, xfer->tx_len, xfer->tx_done, xfer->rx_len, xfer->rx_done);
+
+       if (xfer->tx_done != xfer->tx_len)
+               return true;
+
+       if (xfer->rx_done != xfer->rx_len)
+               exynos_dsi_read_from_fifo(dsi, xfer);
+
+       if (xfer->rx_done != xfer->rx_len)
+               return true;
+
+       spin_lock_irqsave(&dsi->transfer_lock, flags);
+
+       list_del_init(&xfer->list);
+       start = !list_empty(&dsi->transfer_list);
+
+       spin_unlock_irqrestore(&dsi->transfer_lock, flags);
+
+       if (!xfer->rx_len)
+               xfer->result = 0;
+       complete(&xfer->completed);
+
+       return start;
+}
+
+static void exynos_dsi_remove_transfer(struct exynos_dsi *dsi,
+                                       struct exynos_dsi_transfer *xfer)
+{
+       unsigned long flags;
+       bool start;
+
+       spin_lock_irqsave(&dsi->transfer_lock, flags);
+
+       if (!list_empty(&dsi->transfer_list) &&
+           xfer == list_first_entry(&dsi->transfer_list,
+                                    struct exynos_dsi_transfer, list)) {
+               list_del_init(&xfer->list);
+               start = !list_empty(&dsi->transfer_list);
+               spin_unlock_irqrestore(&dsi->transfer_lock, flags);
+               if (start)
+                       exynos_dsi_transfer_start(dsi);
+               return;
+       }
+
+       list_del_init(&xfer->list);
+
+       spin_unlock_irqrestore(&dsi->transfer_lock, flags);
+}
+
+static int exynos_dsi_transfer(struct exynos_dsi *dsi,
+                                       struct exynos_dsi_transfer *xfer)
+{
+       unsigned long flags;
+       bool stopped;
+
+       xfer->tx_done = 0;
+       xfer->rx_done = 0;
+       xfer->result = -ETIMEDOUT;
+       init_completion(&xfer->completed);
+
+       spin_lock_irqsave(&dsi->transfer_lock, flags);
+
+       stopped = list_empty(&dsi->transfer_list);
+       list_add_tail(&xfer->list, &dsi->transfer_list);
+
+       spin_unlock_irqrestore(&dsi->transfer_lock, flags);
+
+       if (stopped)
+               exynos_dsi_transfer_start(dsi);
+
+       wait_for_completion_timeout(&xfer->completed,
+                                   msecs_to_jiffies(DSI_XFER_TIMEOUT_MS));
+       if (xfer->result == -ETIMEDOUT) {
+               exynos_dsi_remove_transfer(dsi, xfer);
+               dev_err(dsi->dev, "xfer timed out: %*ph %*ph\n", 2, xfer->data,
+                       xfer->tx_len, xfer->tx_payload);
+               return -ETIMEDOUT;
+       }
+
+       /* Also covers hardware timeout condition */
+       return xfer->result;
+}
+
+static irqreturn_t exynos_dsi_irq(int irq, void *dev_id)
+{
+       struct exynos_dsi *dsi = dev_id;
+       u32 status;
+
+       status = readl(dsi->reg_base + DSIM_INTSRC_REG);
+       if (!status) {
+               static unsigned long int j;
+               if (printk_timed_ratelimit(&j, 500))
+                       dev_warn(dsi->dev, "spurious interrupt\n");
+               return IRQ_HANDLED;
+       }
+       writel(status, dsi->reg_base + DSIM_INTSRC_REG);
+
+       if (status & DSIM_INT_SW_RST_RELEASE) {
+               u32 mask = ~(DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY);
+               writel(mask, dsi->reg_base + DSIM_INTMSK_REG);
+               complete(&dsi->completed);
+               return IRQ_HANDLED;
+       }
+
+       if (!(status & (DSIM_INT_RX_DONE | DSIM_INT_SFR_FIFO_EMPTY)))
+               return IRQ_HANDLED;
+
+       if (exynos_dsi_transfer_finish(dsi))
+               exynos_dsi_transfer_start(dsi);
+
+       return IRQ_HANDLED;
+}
+
+static int exynos_dsi_init(struct exynos_dsi *dsi)
+{
+       exynos_dsi_enable_clock(dsi);
+       exynos_dsi_reset(dsi);
+       enable_irq(dsi->irq);
+       exynos_dsi_wait_for_reset(dsi);
+       exynos_dsi_init_link(dsi);
+
+       return 0;
+}
+
+static int exynos_dsi_host_attach(struct mipi_dsi_host *host,
+                                 struct mipi_dsi_device *device)
+{
+       struct exynos_dsi *dsi = host_to_dsi(host);
+
+       dsi->lanes = device->lanes;
+       dsi->format = device->format;
+       dsi->mode_flags = device->mode_flags;
+       dsi->panel_node = device->dev.of_node;
+
+       if (dsi->connector.dev)
+               drm_helper_hpd_irq_event(dsi->connector.dev);
+
+       return 0;
+}
+
+static int exynos_dsi_host_detach(struct mipi_dsi_host *host,
+                                 struct mipi_dsi_device *device)
+{
+       struct exynos_dsi *dsi = host_to_dsi(host);
+
+       dsi->panel_node = NULL;
+
+       if (dsi->connector.dev)
+               drm_helper_hpd_irq_event(dsi->connector.dev);
+
+       return 0;
+}
+
+/* distinguish between short and long DSI packet types */
+static bool exynos_dsi_is_short_dsi_type(u8 type)
+{
+       return (type & 0x0f) <= 8;
+}
+
+static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host,
+                                      struct mipi_dsi_msg *msg)
+{
+       struct exynos_dsi *dsi = host_to_dsi(host);
+       struct exynos_dsi_transfer xfer;
+       int ret;
+
+       if (!(dsi->state & DSIM_STATE_INITIALIZED)) {
+               ret = exynos_dsi_init(dsi);
+               if (ret)
+                       return ret;
+               dsi->state |= DSIM_STATE_INITIALIZED;
+       }
+
+       if (msg->tx_len == 0)
+               return -EINVAL;
+
+       xfer.data_id = msg->type | (msg->channel << 6);
+
+       if (exynos_dsi_is_short_dsi_type(msg->type)) {
+               const char *tx_buf = msg->tx_buf;
+
+               if (msg->tx_len > 2)
+                       return -EINVAL;
+               xfer.tx_len = 0;
+               xfer.data[0] = tx_buf[0];
+               xfer.data[1] = (msg->tx_len == 2) ? tx_buf[1] : 0;
+       } else {
+               xfer.tx_len = msg->tx_len;
+               xfer.data[0] = msg->tx_len & 0xff;
+               xfer.data[1] = msg->tx_len >> 8;
+               xfer.tx_payload = msg->tx_buf;
+       }
+
+       xfer.rx_len = msg->rx_len;
+       xfer.rx_payload = msg->rx_buf;
+       xfer.flags = msg->flags;
+
+       ret = exynos_dsi_transfer(dsi, &xfer);
+       return (ret < 0) ? ret : xfer.rx_done;
+}
+
+static const struct mipi_dsi_host_ops exynos_dsi_ops = {
+       .attach = exynos_dsi_host_attach,
+       .detach = exynos_dsi_host_detach,
+       .transfer = exynos_dsi_host_transfer,
+};
+
+static int exynos_dsi_poweron(struct exynos_dsi *dsi)
+{
+       int ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
+       if (ret < 0) {
+               dev_err(dsi->dev, "cannot enable regulators %d\n", ret);
+               return ret;
+       }
+
+       ret = clk_prepare_enable(dsi->bus_clk);
+       if (ret < 0) {
+               dev_err(dsi->dev, "cannot enable bus clock %d\n", ret);
+               goto err_bus_clk;
+       }
+
+       ret = clk_prepare_enable(dsi->pll_clk);
+       if (ret < 0) {
+               dev_err(dsi->dev, "cannot enable pll clock %d\n", ret);
+               goto err_pll_clk;
+       }
+
+       ret = phy_power_on(dsi->phy);
+       if (ret < 0) {
+               dev_err(dsi->dev, "cannot enable phy %d\n", ret);
+               goto err_phy;
+       }
+
+       return 0;
+
+err_phy:
+       clk_disable_unprepare(dsi->pll_clk);
+err_pll_clk:
+       clk_disable_unprepare(dsi->bus_clk);
+err_bus_clk:
+       regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
+
+       return ret;
+}
+
+static void exynos_dsi_poweroff(struct exynos_dsi *dsi)
+{
+       int ret;
+
+       usleep_range(10000, 20000);
+
+       if (dsi->state & DSIM_STATE_INITIALIZED) {
+               dsi->state &= ~DSIM_STATE_INITIALIZED;
+
+               exynos_dsi_disable_clock(dsi);
+
+               disable_irq(dsi->irq);
+       }
+
+       dsi->state &= ~DSIM_STATE_CMD_LPM;
+
+       phy_power_off(dsi->phy);
+
+       clk_disable_unprepare(dsi->pll_clk);
+       clk_disable_unprepare(dsi->bus_clk);
+
+       ret = regulator_bulk_disable(ARRAY_SIZE(dsi->supplies), dsi->supplies);
+       if (ret < 0)
+               dev_err(dsi->dev, "cannot disable regulators %d\n", ret);
+}
+
+static int exynos_dsi_enable(struct exynos_dsi *dsi)
+{
+       int ret;
+
+       if (dsi->state & DSIM_STATE_ENABLED)
+               return 0;
+
+       ret = exynos_dsi_poweron(dsi);
+       if (ret < 0)
+               return ret;
+
+       ret = drm_panel_enable(dsi->panel);
+       if (ret < 0) {
+               exynos_dsi_poweroff(dsi);
+               return ret;
+       }
+
+       exynos_dsi_set_display_mode(dsi);
+       exynos_dsi_set_display_enable(dsi, true);
+
+       dsi->state |= DSIM_STATE_ENABLED;
+
+       return 0;
+}
+
+static void exynos_dsi_disable(struct exynos_dsi *dsi)
+{
+       if (!(dsi->state & DSIM_STATE_ENABLED))
+               return;
+
+       exynos_dsi_set_display_enable(dsi, false);
+       drm_panel_disable(dsi->panel);
+       exynos_dsi_poweroff(dsi);
+
+       dsi->state &= ~DSIM_STATE_ENABLED;
+}
+
+static void exynos_dsi_dpms(struct exynos_drm_display *display, int mode)
+{
+       struct exynos_dsi *dsi = display->ctx;
+
+       if (dsi->panel) {
+               switch (mode) {
+               case DRM_MODE_DPMS_ON:
+                       exynos_dsi_enable(dsi);
+                       break;
+               case DRM_MODE_DPMS_STANDBY:
+               case DRM_MODE_DPMS_SUSPEND:
+               case DRM_MODE_DPMS_OFF:
+                       exynos_dsi_disable(dsi);
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static enum drm_connector_status
+exynos_dsi_detect(struct drm_connector *connector, bool force)
+{
+       struct exynos_dsi *dsi = connector_to_dsi(connector);
+
+       if (!dsi->panel) {
+               dsi->panel = of_drm_find_panel(dsi->panel_node);
+               if (dsi->panel)
+                       drm_panel_attach(dsi->panel, &dsi->connector);
+       } else if (!dsi->panel_node) {
+               struct exynos_drm_display *display;
+
+               display = platform_get_drvdata(to_platform_device(dsi->dev));
+               exynos_dsi_dpms(display, DRM_MODE_DPMS_OFF);
+               drm_panel_detach(dsi->panel);
+               dsi->panel = NULL;
+       }
+
+       if (dsi->panel)
+               return connector_status_connected;
+
+       return connector_status_disconnected;
+}
+
+static void exynos_dsi_connector_destroy(struct drm_connector *connector)
+{
+}
+
+static struct drm_connector_funcs exynos_dsi_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = exynos_dsi_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = exynos_dsi_connector_destroy,
+};
+
+static int exynos_dsi_get_modes(struct drm_connector *connector)
+{
+       struct exynos_dsi *dsi = connector_to_dsi(connector);
+
+       if (dsi->panel)
+               return dsi->panel->funcs->get_modes(dsi->panel);
+
+       return 0;
+}
+
+static int exynos_dsi_mode_valid(struct drm_connector *connector,
+                                struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static struct drm_encoder *
+exynos_dsi_best_encoder(struct drm_connector *connector)
+{
+       struct exynos_dsi *dsi = connector_to_dsi(connector);
+
+       return dsi->encoder;
+}
+
+static struct drm_connector_helper_funcs exynos_dsi_connector_helper_funcs = {
+       .get_modes = exynos_dsi_get_modes,
+       .mode_valid = exynos_dsi_mode_valid,
+       .best_encoder = exynos_dsi_best_encoder,
+};
+
+static int exynos_dsi_create_connector(struct exynos_drm_display *display,
+                                      struct drm_encoder *encoder)
+{
+       struct exynos_dsi *dsi = display->ctx;
+       struct drm_connector *connector = &dsi->connector;
+       int ret;
+
+       dsi->encoder = encoder;
+
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+       ret = drm_connector_init(encoder->dev, connector,
+                                &exynos_dsi_connector_funcs,
+                                DRM_MODE_CONNECTOR_DSI);
+       if (ret) {
+               DRM_ERROR("Failed to initialize connector with drm\n");
+               return ret;
+       }
+
+       drm_connector_helper_add(connector, &exynos_dsi_connector_helper_funcs);
+       drm_sysfs_connector_add(connector);
+       drm_mode_connector_attach_encoder(connector, encoder);
+
+       return 0;
+}
+
+static void exynos_dsi_mode_set(struct exynos_drm_display *display,
+                        struct drm_display_mode *mode)
+{
+       struct exynos_dsi *dsi = display->ctx;
+       struct videomode *vm = &dsi->vm;
+
+       vm->hactive = mode->hdisplay;
+       vm->vactive = mode->vdisplay;
+       vm->vfront_porch = mode->vsync_start - mode->vdisplay;
+       vm->vback_porch = mode->vtotal - mode->vsync_end;
+       vm->vsync_len = mode->vsync_end - mode->vsync_start;
+       vm->hfront_porch = mode->hsync_start - mode->hdisplay;
+       vm->hback_porch = mode->htotal - mode->hsync_end;
+       vm->hsync_len = mode->hsync_end - mode->hsync_start;
+}
+
+static struct exynos_drm_display_ops exynos_dsi_display_ops = {
+       .create_connector = exynos_dsi_create_connector,
+       .mode_set = exynos_dsi_mode_set,
+       .dpms = exynos_dsi_dpms
+};
+
+static struct exynos_drm_display exynos_dsi_display = {
+       .type = EXYNOS_DISPLAY_TYPE_LCD,
+       .ops = &exynos_dsi_display_ops,
+};
+
+/* of_* functions will be removed after merge of of_graph patches */
+static struct device_node *
+of_get_child_by_name_reg(struct device_node *parent, const char *name, u32 reg)
+{
+       struct device_node *np;
+
+       for_each_child_of_node(parent, np) {
+               u32 r;
+
+               if (!np->name || of_node_cmp(np->name, name))
+                       continue;
+
+               if (of_property_read_u32(np, "reg", &r) < 0)
+                       r = 0;
+
+               if (reg == r)
+                       break;
+       }
+
+       return np;
+}
+
+static struct device_node *of_graph_get_port_by_reg(struct device_node *parent,
+                                                   u32 reg)
+{
+       struct device_node *ports, *port;
+
+       ports = of_get_child_by_name(parent, "ports");
+       if (ports)
+               parent = ports;
+
+       port = of_get_child_by_name_reg(parent, "port", reg);
+
+       of_node_put(ports);
+
+       return port;
+}
+
+static struct device_node *
+of_graph_get_endpoint_by_reg(struct device_node *port, u32 reg)
+{
+       return of_get_child_by_name_reg(port, "endpoint", reg);
+}
+
+static int exynos_dsi_of_read_u32(const struct device_node *np,
+                                 const char *propname, u32 *out_value)
+{
+       int ret = of_property_read_u32(np, propname, out_value);
+
+       if (ret < 0)
+               pr_err("%s: failed to get '%s' property\n", np->full_name,
+                      propname);
+
+       return ret;
+}
+
+enum {
+       DSI_PORT_IN,
+       DSI_PORT_OUT
+};
+
+static int exynos_dsi_parse_dt(struct exynos_dsi *dsi)
+{
+       struct device *dev = dsi->dev;
+       struct device_node *node = dev->of_node;
+       struct device_node *port, *ep;
+       int ret;
+
+       ret = exynos_dsi_of_read_u32(node, "samsung,pll-clock-frequency",
+                                    &dsi->pll_clk_rate);
+       if (ret < 0)
+               return ret;
+
+       port = of_graph_get_port_by_reg(node, DSI_PORT_OUT);
+       if (!port) {
+               dev_err(dev, "no output port specified\n");
+               return -EINVAL;
+       }
+
+       ep = of_graph_get_endpoint_by_reg(port, 0);
+       of_node_put(port);
+       if (!ep) {
+               dev_err(dev, "no endpoint specified in output port\n");
+               return -EINVAL;
+       }
+
+       ret = exynos_dsi_of_read_u32(ep, "samsung,burst-clock-frequency",
+                                    &dsi->burst_clk_rate);
+       if (ret < 0)
+               goto end;
+
+       ret = exynos_dsi_of_read_u32(ep, "samsung,esc-clock-frequency",
+                                    &dsi->esc_clk_rate);
+
+end:
+       of_node_put(ep);
+
+       return ret;
+}
+
+static int exynos_dsi_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct exynos_dsi *dsi;
+       int ret;
+
+       dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
+       if (!dsi) {
+               dev_err(&pdev->dev, "failed to allocate dsi object.\n");
+               return -ENOMEM;
+       }
+
+       init_completion(&dsi->completed);
+       spin_lock_init(&dsi->transfer_lock);
+       INIT_LIST_HEAD(&dsi->transfer_list);
+
+       dsi->dsi_host.ops = &exynos_dsi_ops;
+       dsi->dsi_host.dev = &pdev->dev;
+
+       dsi->dev = &pdev->dev;
+
+       ret = exynos_dsi_parse_dt(dsi);
+       if (ret)
+               return ret;
+
+       dsi->supplies[0].supply = "vddcore";
+       dsi->supplies[1].supply = "vddio";
+       ret = devm_regulator_bulk_get(&pdev->dev, ARRAY_SIZE(dsi->supplies),
+                                     dsi->supplies);
+       if (ret) {
+               dev_info(&pdev->dev, "failed to get regulators: %d\n", ret);
+               return -EPROBE_DEFER;
+       }
+
+       dsi->pll_clk = devm_clk_get(&pdev->dev, "pll_clk");
+       if (IS_ERR(dsi->pll_clk)) {
+               dev_info(&pdev->dev, "failed to get dsi pll input clock\n");
+               return -EPROBE_DEFER;
+       }
+
+       dsi->bus_clk = devm_clk_get(&pdev->dev, "bus_clk");
+       if (IS_ERR(dsi->bus_clk)) {
+               dev_info(&pdev->dev, "failed to get dsi bus clock\n");
+               return -EPROBE_DEFER;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dsi->reg_base = devm_ioremap_resource(&pdev->dev, res);
+       if (!dsi->reg_base) {
+               dev_err(&pdev->dev, "failed to remap io region\n");
+               return -EADDRNOTAVAIL;
+       }
+
+       dsi->phy = devm_phy_get(&pdev->dev, "dsim");
+       if (IS_ERR(dsi->phy)) {
+               dev_info(&pdev->dev, "failed to get dsim phy\n");
+               return -EPROBE_DEFER;
+       }
+
+       dsi->irq = platform_get_irq(pdev, 0);
+       if (dsi->irq < 0) {
+               dev_err(&pdev->dev, "failed to request dsi irq resource\n");
+               return dsi->irq;
+       }
+
+       irq_set_status_flags(dsi->irq, IRQ_NOAUTOEN);
+       ret = devm_request_threaded_irq(&pdev->dev, dsi->irq, NULL,
+                                       exynos_dsi_irq, IRQF_ONESHOT,
+                                       dev_name(&pdev->dev), dsi);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to request dsi irq\n");
+               return ret;
+       }
+
+       exynos_dsi_display.ctx = dsi;
+
+       platform_set_drvdata(pdev, &exynos_dsi_display);
+       exynos_drm_display_register(&exynos_dsi_display);
+
+       return mipi_dsi_host_register(&dsi->dsi_host);
+}
+
+static int exynos_dsi_remove(struct platform_device *pdev)
+{
+       struct exynos_dsi *dsi = exynos_dsi_display.ctx;
+
+       exynos_dsi_dpms(&exynos_dsi_display, DRM_MODE_DPMS_OFF);
+
+       exynos_drm_display_unregister(&exynos_dsi_display);
+       mipi_dsi_host_unregister(&dsi->dsi_host);
+
+       return 0;
+}
+
+#if CONFIG_PM_SLEEP
+static int exynos_dsi_resume(struct device *dev)
+{
+       struct exynos_dsi *dsi = exynos_dsi_display.ctx;
+
+       if (dsi->state & DSIM_STATE_ENABLED) {
+               dsi->state &= ~DSIM_STATE_ENABLED;
+               exynos_dsi_enable(dsi);
+       }
+
+       return 0;
+}
+
+static int exynos_dsi_suspend(struct device *dev)
+{
+       struct exynos_dsi *dsi = exynos_dsi_display.ctx;
+
+       if (dsi->state & DSIM_STATE_ENABLED) {
+               exynos_dsi_disable(dsi);
+               dsi->state |= DSIM_STATE_ENABLED;
+       }
+
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops exynos_dsi_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(exynos_dsi_suspend, exynos_dsi_resume)
+};
+
+static struct of_device_id exynos_dsi_of_match[] = {
+       { .compatible = "samsung,exynos4210-mipi-dsi" },
+       { }
+};
+
+struct platform_driver dsi_driver = {
+       .probe = exynos_dsi_probe,
+       .remove = exynos_dsi_remove,
+       .driver = {
+                  .name = "exynos-dsi",
+                  .owner = THIS_MODULE,
+                  .pm = &exynos_dsi_pm_ops,
+                  .of_match_table = exynos_dsi_of_match,
+       },
+};
+
+MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
+MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
+MODULE_DESCRIPTION("Samsung SoC MIPI DSI Master");
+MODULE_LICENSE("GPL v2");
index 06f1b2a..7e282e3 100644 (file)
@@ -17,7 +17,6 @@
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_encoder.h"
-#include "exynos_drm_connector.h"
 
 #define to_exynos_encoder(x)   container_of(x, struct exynos_drm_encoder,\
                                drm_encoder)
  * exynos specific encoder structure.
  *
  * @drm_encoder: encoder object.
- * @manager: specific encoder has its own manager to control a hardware
- *     appropriately and we can access a hardware drawing on this manager.
- * @dpms: store the encoder dpms value.
- * @updated: indicate whether overlay data updating is needed or not.
+ * @display: the display structure that maps to this encoder
  */
 struct exynos_drm_encoder {
-       struct drm_crtc                 *old_crtc;
        struct drm_encoder              drm_encoder;
-       struct exynos_drm_manager       *manager;
-       int                             dpms;
-       bool                            updated;
+       struct exynos_drm_display       *display;
 };
 
-static void exynos_drm_connector_power(struct drm_encoder *encoder, int mode)
-{
-       struct drm_device *dev = encoder->dev;
-       struct drm_connector *connector;
-
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (exynos_drm_best_encoder(connector) == encoder) {
-                       DRM_DEBUG_KMS("connector[%d] dpms[%d]\n",
-                                       connector->base.id, mode);
-
-                       exynos_drm_display_power(connector, mode);
-               }
-       }
-}
-
 static void exynos_drm_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
-       struct drm_device *dev = encoder->dev;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
        struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+       struct exynos_drm_display *display = exynos_encoder->display;
 
        DRM_DEBUG_KMS("encoder dpms: %d\n", mode);
 
-       if (exynos_encoder->dpms == mode) {
-               DRM_DEBUG_KMS("desired dpms mode is same as previous one.\n");
-               return;
-       }
-
-       mutex_lock(&dev->struct_mutex);
-
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               if (manager_ops && manager_ops->apply)
-                       if (!exynos_encoder->updated)
-                               manager_ops->apply(manager->dev);
-
-               exynos_drm_connector_power(encoder, mode);
-               exynos_encoder->dpms = mode;
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               exynos_drm_connector_power(encoder, mode);
-               exynos_encoder->dpms = mode;
-               exynos_encoder->updated = false;
-               break;
-       default:
-               DRM_ERROR("unspecified mode %d\n", mode);
-               break;
-       }
-
-       mutex_unlock(&dev->struct_mutex);
+       if (display->ops->dpms)
+               display->ops->dpms(display, mode);
 }
 
 static bool
@@ -100,87 +49,31 @@ exynos_drm_encoder_mode_fixup(struct drm_encoder *encoder,
                               struct drm_display_mode *adjusted_mode)
 {
        struct drm_device *dev = encoder->dev;
+       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+       struct exynos_drm_display *display = exynos_encoder->display;
        struct drm_connector *connector;
-       struct exynos_drm_manager *manager = exynos_drm_get_manager(encoder);
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder)
-                       if (manager_ops && manager_ops->mode_fixup)
-                               manager_ops->mode_fixup(manager->dev, connector,
-                                                       mode, adjusted_mode);
+               if (connector->encoder != encoder)
+                       continue;
+
+               if (display->ops->mode_fixup)
+                       display->ops->mode_fixup(display, connector, mode,
+                                       adjusted_mode);
        }
 
        return true;
 }
 
-static void disable_plane_to_crtc(struct drm_device *dev,
-                                               struct drm_crtc *old_crtc,
-                                               struct drm_crtc *new_crtc)
-{
-       struct drm_plane *plane;
-
-       /*
-        * if old_crtc isn't same as encoder->crtc then it means that
-        * user changed crtc id to another one so the plane to old_crtc
-        * should be disabled and plane->crtc should be set to new_crtc
-        * (encoder->crtc)
-        */
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-               if (plane->crtc == old_crtc) {
-                       /*
-                        * do not change below call order.
-                        *
-                        * plane->funcs->disable_plane call checks
-                        * if encoder->crtc is same as plane->crtc and if same
-                        * then overlay_ops->disable callback will be called
-                        * to diasble current hw overlay so plane->crtc should
-                        * have new_crtc because new_crtc was set to
-                        * encoder->crtc in advance.
-                        */
-                       plane->crtc = new_crtc;
-                       plane->funcs->disable_plane(plane);
-               }
-       }
-}
-
 static void exynos_drm_encoder_mode_set(struct drm_encoder *encoder,
                                         struct drm_display_mode *mode,
                                         struct drm_display_mode *adjusted_mode)
 {
-       struct drm_device *dev = encoder->dev;
-       struct drm_connector *connector;
-       struct exynos_drm_manager *manager;
-       struct exynos_drm_manager_ops *manager_ops;
-
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               if (connector->encoder == encoder) {
-                       struct exynos_drm_encoder *exynos_encoder;
-
-                       exynos_encoder = to_exynos_encoder(encoder);
-
-                       if (exynos_encoder->old_crtc != encoder->crtc &&
-                                       exynos_encoder->old_crtc) {
-
-                               /*
-                                * disable a plane to old crtc and change
-                                * crtc of the plane to new one.
-                                */
-                               disable_plane_to_crtc(dev,
-                                               exynos_encoder->old_crtc,
-                                               encoder->crtc);
-                       }
-
-                       manager = exynos_drm_get_manager(encoder);
-                       manager_ops = manager->ops;
-
-                       if (manager_ops && manager_ops->mode_set)
-                               manager_ops->mode_set(manager->dev,
-                                                       adjusted_mode);
+       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
+       struct exynos_drm_display *display = exynos_encoder->display;
 
-                       exynos_encoder->old_crtc = encoder->crtc;
-               }
-       }
+       if (display->ops->mode_set)
+               display->ops->mode_set(display, adjusted_mode);
 }
 
 static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
@@ -191,53 +84,15 @@ static void exynos_drm_encoder_prepare(struct drm_encoder *encoder)
 static void exynos_drm_encoder_commit(struct drm_encoder *encoder)
 {
        struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_manager *manager = exynos_encoder->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-
-       if (manager_ops && manager_ops->commit)
-               manager_ops->commit(manager->dev);
-
-       /*
-        * this will avoid one issue that overlay data is updated to
-        * real hardware two times.
-        * And this variable will be used to check if the data was
-        * already updated or not by exynos_drm_encoder_dpms function.
-        */
-       exynos_encoder->updated = true;
-
-       /*
-        * In case of setcrtc, there is no way to update encoder's dpms
-        * so update it here.
-        */
-       exynos_encoder->dpms = DRM_MODE_DPMS_ON;
-}
+       struct exynos_drm_display *display = exynos_encoder->display;
 
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb)
-{
-       struct exynos_drm_encoder *exynos_encoder;
-       struct exynos_drm_manager_ops *ops;
-       struct drm_device *dev = fb->dev;
-       struct drm_encoder *encoder;
+       if (display->ops->dpms)
+               display->ops->dpms(display, DRM_MODE_DPMS_ON);
 
-       /*
-        * make sure that overlay data are updated to real hardware
-        * for all encoders.
-        */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               exynos_encoder = to_exynos_encoder(encoder);
-               ops = exynos_encoder->manager->ops;
-
-               /*
-                * wait for vblank interrupt
-                * - this makes sure that overlay data are updated to
-                *      real hardware.
-                */
-               if (ops->wait_for_vblank)
-                       ops->wait_for_vblank(exynos_encoder->manager->dev);
-       }
+       if (display->ops->commit)
+               display->ops->commit(display);
 }
 
-
 static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
 {
        struct drm_plane *plane;
@@ -246,7 +101,7 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
        exynos_drm_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
 
        /* all planes connected to this encoder should be also disabled. */
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+       drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
                if (plane->crtc == encoder->crtc)
                        plane->funcs->disable_plane(plane);
        }
@@ -263,10 +118,7 @@ static struct drm_encoder_helper_funcs exynos_encoder_helper_funcs = {
 
 static void exynos_drm_encoder_destroy(struct drm_encoder *encoder)
 {
-       struct exynos_drm_encoder *exynos_encoder =
-               to_exynos_encoder(encoder);
-
-       exynos_encoder->manager->pipe = -1;
+       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
 
        drm_encoder_cleanup(encoder);
        kfree(exynos_encoder);
@@ -281,13 +133,12 @@ static unsigned int exynos_drm_encoder_clones(struct drm_encoder *encoder)
        struct drm_encoder *clone;
        struct drm_device *dev = encoder->dev;
        struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_display_ops *display_ops =
-                               exynos_encoder->manager->display_ops;
+       struct exynos_drm_display *display = exynos_encoder->display;
        unsigned int clone_mask = 0;
        int cnt = 0;
 
        list_for_each_entry(clone, &dev->mode_config.encoder_list, head) {
-               switch (display_ops->type) {
+               switch (display->type) {
                case EXYNOS_DISPLAY_TYPE_LCD:
                case EXYNOS_DISPLAY_TYPE_HDMI:
                case EXYNOS_DISPLAY_TYPE_VIDI:
@@ -311,24 +162,20 @@ void exynos_drm_encoder_setup(struct drm_device *dev)
 
 struct drm_encoder *
 exynos_drm_encoder_create(struct drm_device *dev,
-                          struct exynos_drm_manager *manager,
-                          unsigned int possible_crtcs)
+                          struct exynos_drm_display *display,
+                          unsigned long possible_crtcs)
 {
        struct drm_encoder *encoder;
        struct exynos_drm_encoder *exynos_encoder;
 
-       if (!manager || !possible_crtcs)
-               return NULL;
-
-       if (!manager->dev)
+       if (!possible_crtcs)
                return NULL;
 
        exynos_encoder = kzalloc(sizeof(*exynos_encoder), GFP_KERNEL);
        if (!exynos_encoder)
                return NULL;
 
-       exynos_encoder->dpms = DRM_MODE_DPMS_OFF;
-       exynos_encoder->manager = manager;
+       exynos_encoder->display = display;
        encoder = &exynos_encoder->drm_encoder;
        encoder->possible_crtcs = possible_crtcs;
 
@@ -344,149 +191,7 @@ exynos_drm_encoder_create(struct drm_device *dev,
        return encoder;
 }
 
-struct exynos_drm_manager *exynos_drm_get_manager(struct drm_encoder *encoder)
-{
-       return to_exynos_encoder(encoder)->manager;
-}
-
-void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
-                           void (*fn)(struct drm_encoder *, void *))
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_encoder *encoder;
-       struct exynos_drm_private *private = dev->dev_private;
-       struct exynos_drm_manager *manager;
-
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-               /*
-                * if crtc is detached from encoder, check pipe,
-                * otherwise check crtc attached to encoder
-                */
-               if (!encoder->crtc) {
-                       manager = to_exynos_encoder(encoder)->manager;
-                       if (manager->pipe < 0 ||
-                                       private->crtc[manager->pipe] != crtc)
-                               continue;
-               } else {
-                       if (encoder->crtc != crtc)
-                               continue;
-               }
-
-               fn(encoder, data);
-       }
-}
-
-void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       int crtc = *(int *)data;
-
-       if (manager->pipe != crtc)
-               return;
-
-       if (manager_ops->enable_vblank)
-               manager_ops->enable_vblank(manager->dev);
-}
-
-void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       int crtc = *(int *)data;
-
-       if (manager->pipe != crtc)
-               return;
-
-       if (manager_ops->disable_vblank)
-               manager_ops->disable_vblank(manager->dev);
-}
-
-void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_encoder *exynos_encoder = to_exynos_encoder(encoder);
-       struct exynos_drm_manager *manager = exynos_encoder->manager;
-       struct exynos_drm_manager_ops *manager_ops = manager->ops;
-       int mode = *(int *)data;
-
-       if (manager_ops && manager_ops->dpms)
-               manager_ops->dpms(manager->dev, mode);
-
-       /*
-        * if this condition is ok then it means that the crtc is already
-        * detached from encoder and last function for detaching is properly
-        * done, so clear pipe from manager to prevent repeated call.
-        */
-       if (mode > DRM_MODE_DPMS_ON) {
-               if (!encoder->crtc)
-                       manager->pipe = -1;
-       }
-}
-
-void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       int pipe = *(int *)data;
-
-       /*
-        * when crtc is detached from encoder, this pipe is used
-        * to select manager operation
-        */
-       manager->pipe = pipe;
-}
-
-void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
-       struct exynos_drm_overlay *overlay = data;
-
-       if (overlay_ops && overlay_ops->mode_set)
-               overlay_ops->mode_set(manager->dev, overlay);
-}
-
-void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data)
+struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder)
 {
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
-       int zpos = DEFAULT_ZPOS;
-
-       if (data)
-               zpos = *(int *)data;
-
-       if (overlay_ops && overlay_ops->commit)
-               overlay_ops->commit(manager->dev, zpos);
-}
-
-void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
-       int zpos = DEFAULT_ZPOS;
-
-       if (data)
-               zpos = *(int *)data;
-
-       if (overlay_ops && overlay_ops->enable)
-               overlay_ops->enable(manager->dev, zpos);
-}
-
-void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data)
-{
-       struct exynos_drm_manager *manager =
-               to_exynos_encoder(encoder)->manager;
-       struct exynos_drm_overlay_ops *overlay_ops = manager->overlay_ops;
-       int zpos = DEFAULT_ZPOS;
-
-       if (data)
-               zpos = *(int *)data;
-
-       if (overlay_ops && overlay_ops->disable)
-               overlay_ops->disable(manager->dev, zpos);
+       return to_exynos_encoder(encoder)->display;
 }
index 89e2fb0..b7a1620 100644 (file)
@@ -18,20 +18,8 @@ struct exynos_drm_manager;
 
 void exynos_drm_encoder_setup(struct drm_device *dev);
 struct drm_encoder *exynos_drm_encoder_create(struct drm_device *dev,
-                                              struct exynos_drm_manager *mgr,
-                                              unsigned int possible_crtcs);
-struct exynos_drm_manager *
-exynos_drm_get_manager(struct drm_encoder *encoder);
-void exynos_drm_fn_encoder(struct drm_crtc *crtc, void *data,
-                           void (*fn)(struct drm_encoder *, void *));
-void exynos_drm_enable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_disable_vblank(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_dpms(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_crtc_pipe(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_mode_set(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_commit(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_enable(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_plane_disable(struct drm_encoder *encoder, void *data);
-void exynos_drm_encoder_complete_scanout(struct drm_framebuffer *fb);
+                       struct exynos_drm_display *mgr,
+                       unsigned long possible_crtcs);
+struct exynos_drm_display *exynos_drm_get_display(struct drm_encoder *encoder);
 
 #endif
index ea39e0e..65a22ca 100644 (file)
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_fb.h"
+#include "exynos_drm_fbdev.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_iommu.h"
-#include "exynos_drm_encoder.h"
+#include "exynos_drm_crtc.h"
 
 #define to_exynos_fb(x)        container_of(x, struct exynos_drm_fb, fb)
 
@@ -71,7 +72,7 @@ static void exynos_drm_fb_destroy(struct drm_framebuffer *fb)
        unsigned int i;
 
        /* make sure that overlay data are updated before relesing fb. */
-       exynos_drm_encoder_complete_scanout(fb);
+       exynos_drm_crtc_complete_scanout(fb);
 
        drm_framebuffer_cleanup(fb);
 
@@ -300,6 +301,8 @@ static void exynos_drm_output_poll_changed(struct drm_device *dev)
 
        if (fb_helper)
                drm_fb_helper_hotplug_event(fb_helper);
+       else
+               exynos_drm_fbdev_init(dev);
 }
 
 static const struct drm_mode_config_funcs exynos_drm_mode_config_funcs = {
index e7c2f2d..addbf75 100644 (file)
@@ -90,7 +90,7 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
        /* RGB formats use only one buffer */
        buffer = exynos_drm_fb_buffer(fb, 0);
        if (!buffer) {
-               DRM_LOG_KMS("buffer is null.\n");
+               DRM_DEBUG_KMS("buffer is null.\n");
                return -EFAULT;
        }
 
@@ -237,6 +237,24 @@ static struct drm_fb_helper_funcs exynos_drm_fb_helper_funcs = {
        .fb_probe =     exynos_drm_fbdev_create,
 };
 
+bool exynos_drm_fbdev_is_anything_connected(struct drm_device *dev)
+{
+       struct drm_connector *connector;
+       bool ret = false;
+
+       mutex_lock(&dev->mode_config.mutex);
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (connector->status != connector_status_connected)
+                       continue;
+
+               ret = true;
+               break;
+       }
+       mutex_unlock(&dev->mode_config.mutex);
+
+       return ret;
+}
+
 int exynos_drm_fbdev_init(struct drm_device *dev)
 {
        struct exynos_drm_fbdev *fbdev;
@@ -248,6 +266,9 @@ int exynos_drm_fbdev_init(struct drm_device *dev)
        if (!dev->mode_config.num_crtc || !dev->mode_config.num_connector)
                return 0;
 
+       if (!exynos_drm_fbdev_is_anything_connected(dev))
+               return 0;
+
        fbdev = kzalloc(sizeof(*fbdev), GFP_KERNEL);
        if (!fbdev)
                return -ENOMEM;
index a20440c..40fd6cc 100644 (file)
@@ -62,7 +62,7 @@
 /* FIMD has totally five hardware windows. */
 #define WINDOWS_NR     5
 
-#define get_fimd_context(dev)  platform_get_drvdata(to_platform_device(dev))
+#define get_fimd_manager(mgr)  platform_get_drvdata(to_platform_device(dev))
 
 struct fimd_driver_data {
        unsigned int timing_base;
@@ -105,20 +105,18 @@ struct fimd_win_data {
 };
 
 struct fimd_context {
-       struct exynos_drm_subdrv        subdrv;
-       int                             irq;
-       struct drm_crtc                 *crtc;
+       struct device                   *dev;
+       struct drm_device               *drm_dev;
        struct clk                      *bus_clk;
        struct clk                      *lcd_clk;
        void __iomem                    *regs;
+       struct drm_display_mode         mode;
        struct fimd_win_data            win_data[WINDOWS_NR];
-       unsigned int                    clkdiv;
        unsigned int                    default_win;
        unsigned long                   irq_flags;
-       u32                             vidcon0;
        u32                             vidcon1;
        bool                            suspended;
-       struct mutex                    lock;
+       int                             pipe;
        wait_queue_head_t               wait_vsync_queue;
        atomic_t                        wait_vsync_event;
 
@@ -145,153 +143,147 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
        return (struct fimd_driver_data *)of_id->data;
 }
 
-static bool fimd_display_is_connected(struct device *dev)
+static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
+                       struct drm_device *drm_dev, int pipe)
 {
-       /* TODO. */
+       struct fimd_context *ctx = mgr->ctx;
 
-       return true;
-}
+       ctx->drm_dev = drm_dev;
+       ctx->pipe = pipe;
 
-static void *fimd_get_panel(struct device *dev)
-{
-       struct fimd_context *ctx = get_fimd_context(dev);
+       /*
+        * enable drm irq mode.
+        * - with irq_enabled = true, we can use the vblank feature.
+        *
+        * P.S. note that we wouldn't use drm irq handler but
+        *      just specific driver own one instead because
+        *      drm framework supports only one irq handler.
+        */
+       drm_dev->irq_enabled = true;
 
-       return &ctx->panel;
-}
+       /*
+        * with vblank_disable_allowed = true, vblank interrupt will be disabled
+        * by drm timer once a current process gives up ownership of
+        * vblank event.(after drm_vblank_put function is called)
+        */
+       drm_dev->vblank_disable_allowed = true;
 
-static int fimd_check_mode(struct device *dev, struct drm_display_mode *mode)
-{
-       /* TODO. */
+       /* attach this sub driver to iommu mapping if supported. */
+       if (is_drm_iommu_supported(ctx->drm_dev))
+               drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
 
        return 0;
 }
 
-static int fimd_display_power_on(struct device *dev, int mode)
+static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
 {
-       /* TODO */
+       struct fimd_context *ctx = mgr->ctx;
 
-       return 0;
+       /* detach this sub driver from iommu mapping if supported. */
+       if (is_drm_iommu_supported(ctx->drm_dev))
+               drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
 }
 
-static struct exynos_drm_display_ops fimd_display_ops = {
-       .type = EXYNOS_DISPLAY_TYPE_LCD,
-       .is_connected = fimd_display_is_connected,
-       .get_panel = fimd_get_panel,
-       .check_mode = fimd_check_mode,
-       .power_on = fimd_display_power_on,
-};
-
-static void fimd_dpms(struct device *subdrv_dev, int mode)
+static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
+               const struct drm_display_mode *mode)
 {
-       struct fimd_context *ctx = get_fimd_context(subdrv_dev);
+       unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
+       u32 clkdiv;
 
-       DRM_DEBUG_KMS("%d\n", mode);
+       /* Find the clock divider value that gets us closest to ideal_clk */
+       clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->lcd_clk), ideal_clk);
 
-       mutex_lock(&ctx->lock);
+       return (clkdiv < 0x100) ? clkdiv : 0xff;
+}
 
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               /*
-                * enable fimd hardware only if suspended status.
-                *
-                * P.S. fimd_dpms function would be called at booting time so
-                * clk_enable could be called double time.
-                */
-               if (ctx->suspended)
-                       pm_runtime_get_sync(subdrv_dev);
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               if (!ctx->suspended)
-                       pm_runtime_put_sync(subdrv_dev);
-               break;
-       default:
-               DRM_DEBUG_KMS("unspecified mode %d\n", mode);
-               break;
-       }
+static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
+               const struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       if (adjusted_mode->vrefresh == 0)
+               adjusted_mode->vrefresh = FIMD_DEFAULT_FRAMERATE;
 
-       mutex_unlock(&ctx->lock);
+       return true;
 }
 
-static void fimd_apply(struct device *subdrv_dev)
+static void fimd_mode_set(struct exynos_drm_manager *mgr,
+               const struct drm_display_mode *in_mode)
 {
-       struct fimd_context *ctx = get_fimd_context(subdrv_dev);
-       struct exynos_drm_manager *mgr = ctx->subdrv.manager;
-       struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
-       struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
-       struct fimd_win_data *win_data;
-       int i;
-
-       for (i = 0; i < WINDOWS_NR; i++) {
-               win_data = &ctx->win_data[i];
-               if (win_data->enabled && (ovl_ops && ovl_ops->commit))
-                       ovl_ops->commit(subdrv_dev, i);
-       }
+       struct fimd_context *ctx = mgr->ctx;
 
-       if (mgr_ops && mgr_ops->commit)
-               mgr_ops->commit(subdrv_dev);
+       drm_mode_copy(&ctx->mode, in_mode);
 }
 
-static void fimd_commit(struct device *dev)
+static void fimd_commit(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
-       struct exynos_drm_panel_info *panel = &ctx->panel;
-       struct videomode *vm = &panel->vm;
+       struct fimd_context *ctx = mgr->ctx;
+       struct drm_display_mode *mode = &ctx->mode;
        struct fimd_driver_data *driver_data;
-       u32 val;
+       u32 val, clkdiv, vidcon1;
+       int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
 
        driver_data = ctx->driver_data;
        if (ctx->suspended)
                return;
 
-       /* setup polarity values from machine code. */
-       writel(ctx->vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
+       /* nothing to do if we haven't set the mode yet */
+       if (mode->htotal == 0 || mode->vtotal == 0)
+               return;
+
+       /* setup polarity values */
+       vidcon1 = ctx->vidcon1;
+       if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+               vidcon1 |= VIDCON1_INV_VSYNC;
+       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+               vidcon1 |= VIDCON1_INV_HSYNC;
+       writel(vidcon1, ctx->regs + driver_data->timing_base + VIDCON1);
 
        /* setup vertical timing values. */
-       val = VIDTCON0_VBPD(vm->vback_porch - 1) |
-              VIDTCON0_VFPD(vm->vfront_porch - 1) |
-              VIDTCON0_VSPW(vm->vsync_len - 1);
+       vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+       vbpd = mode->crtc_vtotal - mode->crtc_vsync_end;
+       vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay;
+
+       val = VIDTCON0_VBPD(vbpd - 1) |
+               VIDTCON0_VFPD(vfpd - 1) |
+               VIDTCON0_VSPW(vsync_len - 1);
        writel(val, ctx->regs + driver_data->timing_base + VIDTCON0);
 
        /* setup horizontal timing values.  */
-       val = VIDTCON1_HBPD(vm->hback_porch - 1) |
-              VIDTCON1_HFPD(vm->hfront_porch - 1) |
-              VIDTCON1_HSPW(vm->hsync_len - 1);
+       hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+       hbpd = mode->crtc_htotal - mode->crtc_hsync_end;
+       hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay;
+
+       val = VIDTCON1_HBPD(hbpd - 1) |
+               VIDTCON1_HFPD(hfpd - 1) |
+               VIDTCON1_HSPW(hsync_len - 1);
        writel(val, ctx->regs + driver_data->timing_base + VIDTCON1);
 
        /* setup horizontal and vertical display size. */
-       val = VIDTCON2_LINEVAL(vm->vactive - 1) |
-              VIDTCON2_HOZVAL(vm->hactive - 1) |
-              VIDTCON2_LINEVAL_E(vm->vactive - 1) |
-              VIDTCON2_HOZVAL_E(vm->hactive - 1);
+       val = VIDTCON2_LINEVAL(mode->vdisplay - 1) |
+              VIDTCON2_HOZVAL(mode->hdisplay - 1) |
+              VIDTCON2_LINEVAL_E(mode->vdisplay - 1) |
+              VIDTCON2_HOZVAL_E(mode->hdisplay - 1);
        writel(val, ctx->regs + driver_data->timing_base + VIDTCON2);
 
-       /* setup clock source, clock divider, enable dma. */
-       val = ctx->vidcon0;
-       val &= ~(VIDCON0_CLKVAL_F_MASK | VIDCON0_CLKDIR);
-
-       if (ctx->driver_data->has_clksel) {
-               val &= ~VIDCON0_CLKSEL_MASK;
-               val |= VIDCON0_CLKSEL_LCD;
-       }
-
-       if (ctx->clkdiv > 1)
-               val |= VIDCON0_CLKVAL_F(ctx->clkdiv - 1) | VIDCON0_CLKDIR;
-       else
-               val &= ~VIDCON0_CLKDIR; /* 1:1 clock */
-
        /*
         * fields of register with prefix '_F' would be updated
         * at vsync(same as dma start)
         */
-       val |= VIDCON0_ENVID | VIDCON0_ENVID_F;
+       val = VIDCON0_ENVID | VIDCON0_ENVID_F;
+
+       if (ctx->driver_data->has_clksel)
+               val |= VIDCON0_CLKSEL_LCD;
+
+       clkdiv = fimd_calc_clkdiv(ctx, mode);
+       if (clkdiv > 1)
+               val |= VIDCON0_CLKVAL_F(clkdiv - 1) | VIDCON0_CLKDIR;
+
        writel(val, ctx->regs + VIDCON0);
 }
 
-static int fimd_enable_vblank(struct device *dev)
+static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *ctx = mgr->ctx;
        u32 val;
 
        if (ctx->suspended)
@@ -314,9 +306,9 @@ static int fimd_enable_vblank(struct device *dev)
        return 0;
 }
 
-static void fimd_disable_vblank(struct device *dev)
+static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *ctx = mgr->ctx;
        u32 val;
 
        if (ctx->suspended)
@@ -332,9 +324,9 @@ static void fimd_disable_vblank(struct device *dev)
        }
 }
 
-static void fimd_wait_for_vblank(struct device *dev)
+static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *ctx = mgr->ctx;
 
        if (ctx->suspended)
                return;
@@ -351,25 +343,16 @@ static void fimd_wait_for_vblank(struct device *dev)
                DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
-static struct exynos_drm_manager_ops fimd_manager_ops = {
-       .dpms = fimd_dpms,
-       .apply = fimd_apply,
-       .commit = fimd_commit,
-       .enable_vblank = fimd_enable_vblank,
-       .disable_vblank = fimd_disable_vblank,
-       .wait_for_vblank = fimd_wait_for_vblank,
-};
-
-static void fimd_win_mode_set(struct device *dev,
-                             struct exynos_drm_overlay *overlay)
+static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
+                       struct exynos_drm_overlay *overlay)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *ctx = mgr->ctx;
        struct fimd_win_data *win_data;
        int win;
        unsigned long offset;
 
        if (!overlay) {
-               dev_err(dev, "overlay is NULL\n");
+               DRM_ERROR("overlay is NULL\n");
                return;
        }
 
@@ -409,9 +392,8 @@ static void fimd_win_mode_set(struct device *dev,
                        overlay->fb_width, overlay->crtc_width);
 }
 
-static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
+static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
        struct fimd_win_data *win_data = &ctx->win_data[win];
        unsigned long val;
 
@@ -467,9 +449,8 @@ static void fimd_win_set_pixfmt(struct device *dev, unsigned int win)
        writel(val, ctx->regs + WINCON(win));
 }
 
-static void fimd_win_set_colkey(struct device *dev, unsigned int win)
+static void fimd_win_set_colkey(struct fimd_context *ctx, unsigned int win)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
        unsigned int keycon0 = 0, keycon1 = 0;
 
        keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
@@ -508,9 +489,9 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
        writel(val, ctx->regs + reg);
 }
 
-static void fimd_win_commit(struct device *dev, int zpos)
+static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *ctx = mgr->ctx;
        struct fimd_win_data *win_data;
        int win = zpos;
        unsigned long val, alpha, size;
@@ -528,6 +509,12 @@ static void fimd_win_commit(struct device *dev, int zpos)
 
        win_data = &ctx->win_data[win];
 
+       /* If suspended, enable this on resume */
+       if (ctx->suspended) {
+               win_data->resume = true;
+               return;
+       }
+
        /*
         * SHADOWCON/PRTCON register is used for enabling timing.
         *
@@ -605,11 +592,11 @@ static void fimd_win_commit(struct device *dev, int zpos)
                DRM_DEBUG_KMS("osd size = 0x%x\n", (unsigned int)val);
        }
 
-       fimd_win_set_pixfmt(dev, win);
+       fimd_win_set_pixfmt(ctx, win);
 
        /* hardware window 0 doesn't support color key. */
        if (win != 0)
-               fimd_win_set_colkey(dev, win);
+               fimd_win_set_colkey(ctx, win);
 
        /* wincon */
        val = readl(ctx->regs + WINCON(win));
@@ -628,9 +615,9 @@ static void fimd_win_commit(struct device *dev, int zpos)
        win_data->enabled = true;
 }
 
-static void fimd_win_disable(struct device *dev, int zpos)
+static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *ctx = mgr->ctx;
        struct fimd_win_data *win_data;
        int win = zpos;
        u32 val;
@@ -669,132 +656,6 @@ static void fimd_win_disable(struct device *dev, int zpos)
        win_data->enabled = false;
 }
 
-static struct exynos_drm_overlay_ops fimd_overlay_ops = {
-       .mode_set = fimd_win_mode_set,
-       .commit = fimd_win_commit,
-       .disable = fimd_win_disable,
-};
-
-static struct exynos_drm_manager fimd_manager = {
-       .pipe           = -1,
-       .ops            = &fimd_manager_ops,
-       .overlay_ops    = &fimd_overlay_ops,
-       .display_ops    = &fimd_display_ops,
-};
-
-static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
-{
-       struct fimd_context *ctx = (struct fimd_context *)dev_id;
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct drm_device *drm_dev = subdrv->drm_dev;
-       struct exynos_drm_manager *manager = subdrv->manager;
-       u32 val;
-
-       val = readl(ctx->regs + VIDINTCON1);
-
-       if (val & VIDINTCON1_INT_FRAME)
-               /* VSYNC interrupt */
-               writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
-
-       /* check the crtc is detached already from encoder */
-       if (manager->pipe < 0)
-               goto out;
-
-       drm_handle_vblank(drm_dev, manager->pipe);
-       exynos_drm_crtc_finish_pageflip(drm_dev, manager->pipe);
-
-       /* set wait vsync event to zero and wake up queue. */
-       if (atomic_read(&ctx->wait_vsync_event)) {
-               atomic_set(&ctx->wait_vsync_event, 0);
-               wake_up(&ctx->wait_vsync_queue);
-       }
-out:
-       return IRQ_HANDLED;
-}
-
-static int fimd_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
-{
-       /*
-        * enable drm irq mode.
-        * - with irq_enabled = true, we can use the vblank feature.
-        *
-        * P.S. note that we wouldn't use drm irq handler but
-        *      just specific driver own one instead because
-        *      drm framework supports only one irq handler.
-        */
-       drm_dev->irq_enabled = true;
-
-       /*
-        * with vblank_disable_allowed = true, vblank interrupt will be disabled
-        * by drm timer once a current process gives up ownership of
-        * vblank event.(after drm_vblank_put function is called)
-        */
-       drm_dev->vblank_disable_allowed = true;
-
-       /* attach this sub driver to iommu mapping if supported. */
-       if (is_drm_iommu_supported(drm_dev))
-               drm_iommu_attach_device(drm_dev, dev);
-
-       return 0;
-}
-
-static void fimd_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
-       /* detach this sub driver from iommu mapping if supported. */
-       if (is_drm_iommu_supported(drm_dev))
-               drm_iommu_detach_device(drm_dev, dev);
-}
-
-static int fimd_configure_clocks(struct fimd_context *ctx, struct device *dev)
-{
-       struct videomode *vm = &ctx->panel.vm;
-       unsigned long clk;
-
-       ctx->bus_clk = devm_clk_get(dev, "fimd");
-       if (IS_ERR(ctx->bus_clk)) {
-               dev_err(dev, "failed to get bus clock\n");
-               return PTR_ERR(ctx->bus_clk);
-       }
-
-       ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
-       if (IS_ERR(ctx->lcd_clk)) {
-               dev_err(dev, "failed to get lcd clock\n");
-               return PTR_ERR(ctx->lcd_clk);
-       }
-
-       clk = clk_get_rate(ctx->lcd_clk);
-       if (clk == 0) {
-               dev_err(dev, "error getting sclk_fimd clock rate\n");
-               return -EINVAL;
-       }
-
-       if (vm->pixelclock == 0) {
-               unsigned long c;
-               c = vm->hactive + vm->hback_porch + vm->hfront_porch +
-                   vm->hsync_len;
-               c *= vm->vactive + vm->vback_porch + vm->vfront_porch +
-                    vm->vsync_len;
-               vm->pixelclock = c * FIMD_DEFAULT_FRAMERATE;
-               if (vm->pixelclock == 0) {
-                       dev_err(dev, "incorrect display timings\n");
-                       return -EINVAL;
-               }
-               dev_warn(dev, "pixel clock recalculated to %luHz (%dHz frame rate)\n",
-                        vm->pixelclock, FIMD_DEFAULT_FRAMERATE);
-       }
-       ctx->clkdiv = DIV_ROUND_UP(clk, vm->pixelclock);
-       if (ctx->clkdiv > 256) {
-               dev_warn(dev, "calculated pixel clock divider too high (%u), lowered to 256\n",
-                        ctx->clkdiv);
-               ctx->clkdiv = 256;
-       }
-       vm->pixelclock = clk / ctx->clkdiv;
-       DRM_DEBUG_KMS("pixel clock = %lu, clkdiv = %d\n", vm->pixelclock,
-                     ctx->clkdiv);
-
-       return 0;
-}
-
 static void fimd_clear_win(struct fimd_context *ctx, int win)
 {
        writel(0, ctx->regs + WINCON(win));
@@ -808,111 +669,190 @@ static void fimd_clear_win(struct fimd_context *ctx, int win)
        fimd_shadow_protect_win(ctx, win, false);
 }
 
-static int fimd_clock(struct fimd_context *ctx, bool enable)
+static void fimd_window_suspend(struct exynos_drm_manager *mgr)
 {
-       if (enable) {
-               int ret;
-
-               ret = clk_prepare_enable(ctx->bus_clk);
-               if (ret < 0)
-                       return ret;
+       struct fimd_context *ctx = mgr->ctx;
+       struct fimd_win_data *win_data;
+       int i;
 
-               ret = clk_prepare_enable(ctx->lcd_clk);
-               if  (ret < 0) {
-                       clk_disable_unprepare(ctx->bus_clk);
-                       return ret;
-               }
-       } else {
-               clk_disable_unprepare(ctx->lcd_clk);
-               clk_disable_unprepare(ctx->bus_clk);
+       for (i = 0; i < WINDOWS_NR; i++) {
+               win_data = &ctx->win_data[i];
+               win_data->resume = win_data->enabled;
+               if (win_data->enabled)
+                       fimd_win_disable(mgr, i);
        }
-
-       return 0;
+       fimd_wait_for_vblank(mgr);
 }
 
-static void fimd_window_suspend(struct device *dev)
+static void fimd_window_resume(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *ctx = mgr->ctx;
        struct fimd_win_data *win_data;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
                win_data = &ctx->win_data[i];
-               win_data->resume = win_data->enabled;
-               fimd_win_disable(dev, i);
+               win_data->enabled = win_data->resume;
+               win_data->resume = false;
        }
-       fimd_wait_for_vblank(dev);
 }
 
-static void fimd_window_resume(struct device *dev)
+static void fimd_apply(struct exynos_drm_manager *mgr)
 {
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct fimd_context *ctx = mgr->ctx;
        struct fimd_win_data *win_data;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
                win_data = &ctx->win_data[i];
-               win_data->enabled = win_data->resume;
-               win_data->resume = false;
+               if (win_data->enabled)
+                       fimd_win_commit(mgr, i);
        }
+
+       fimd_commit(mgr);
 }
 
-static int fimd_activate(struct fimd_context *ctx, bool enable)
+static int fimd_poweron(struct exynos_drm_manager *mgr)
 {
-       struct device *dev = ctx->subdrv.dev;
-       if (enable) {
-               int ret;
+       struct fimd_context *ctx = mgr->ctx;
+       int ret;
 
-               ret = fimd_clock(ctx, true);
-               if (ret < 0)
-                       return ret;
+       if (!ctx->suspended)
+               return 0;
 
-               ctx->suspended = false;
+       ctx->suspended = false;
 
-               /* if vblank was enabled status, enable it again. */
-               if (test_and_clear_bit(0, &ctx->irq_flags))
-                       fimd_enable_vblank(dev);
+       pm_runtime_get_sync(ctx->dev);
 
-               fimd_window_resume(dev);
-       } else {
-               fimd_window_suspend(dev);
+       ret = clk_prepare_enable(ctx->bus_clk);
+       if (ret < 0) {
+               DRM_ERROR("Failed to prepare_enable the bus clk [%d]\n", ret);
+               goto bus_clk_err;
+       }
+
+       ret = clk_prepare_enable(ctx->lcd_clk);
+       if  (ret < 0) {
+               DRM_ERROR("Failed to prepare_enable the lcd clk [%d]\n", ret);
+               goto lcd_clk_err;
+       }
 
-               fimd_clock(ctx, false);
-               ctx->suspended = true;
+       /* if vblank was enabled status, enable it again. */
+       if (test_and_clear_bit(0, &ctx->irq_flags)) {
+               ret = fimd_enable_vblank(mgr);
+               if (ret) {
+                       DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
+                       goto enable_vblank_err;
+               }
        }
 
+       fimd_window_resume(mgr);
+
+       fimd_apply(mgr);
+
        return 0;
+
+enable_vblank_err:
+       clk_disable_unprepare(ctx->lcd_clk);
+lcd_clk_err:
+       clk_disable_unprepare(ctx->bus_clk);
+bus_clk_err:
+       ctx->suspended = true;
+       return ret;
 }
 
-static int fimd_get_platform_data(struct fimd_context *ctx, struct device *dev)
+static int fimd_poweroff(struct exynos_drm_manager *mgr)
 {
-       struct videomode *vm;
-       int ret;
+       struct fimd_context *ctx = mgr->ctx;
 
-       vm = &ctx->panel.vm;
-       ret = of_get_videomode(dev->of_node, vm, OF_USE_NATIVE_MODE);
-       if (ret) {
-               DRM_ERROR("failed: of_get_videomode() : %d\n", ret);
-               return ret;
-       }
+       if (ctx->suspended)
+               return 0;
 
-       if (vm->flags & DISPLAY_FLAGS_VSYNC_LOW)
-               ctx->vidcon1 |= VIDCON1_INV_VSYNC;
-       if (vm->flags & DISPLAY_FLAGS_HSYNC_LOW)
-               ctx->vidcon1 |= VIDCON1_INV_HSYNC;
-       if (vm->flags & DISPLAY_FLAGS_DE_LOW)
-               ctx->vidcon1 |= VIDCON1_INV_VDEN;
-       if (vm->flags & DISPLAY_FLAGS_PIXDATA_NEGEDGE)
-               ctx->vidcon1 |= VIDCON1_INV_VCLK;
+       /*
+        * We need to make sure that all windows are disabled before we
+        * suspend that connector. Otherwise we might try to scan from
+        * a destroyed buffer later.
+        */
+       fimd_window_suspend(mgr);
 
+       clk_disable_unprepare(ctx->lcd_clk);
+       clk_disable_unprepare(ctx->bus_clk);
+
+       pm_runtime_put_sync(ctx->dev);
+
+       ctx->suspended = true;
        return 0;
 }
 
+static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
+{
+       DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               fimd_poweron(mgr);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               fimd_poweroff(mgr);
+               break;
+       default:
+               DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+               break;
+       }
+}
+
+static struct exynos_drm_manager_ops fimd_manager_ops = {
+       .initialize = fimd_mgr_initialize,
+       .remove = fimd_mgr_remove,
+       .dpms = fimd_dpms,
+       .mode_fixup = fimd_mode_fixup,
+       .mode_set = fimd_mode_set,
+       .commit = fimd_commit,
+       .enable_vblank = fimd_enable_vblank,
+       .disable_vblank = fimd_disable_vblank,
+       .wait_for_vblank = fimd_wait_for_vblank,
+       .win_mode_set = fimd_win_mode_set,
+       .win_commit = fimd_win_commit,
+       .win_disable = fimd_win_disable,
+};
+
+static struct exynos_drm_manager fimd_manager = {
+       .type = EXYNOS_DISPLAY_TYPE_LCD,
+       .ops = &fimd_manager_ops,
+};
+
+static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
+{
+       struct fimd_context *ctx = (struct fimd_context *)dev_id;
+       u32 val;
+
+       val = readl(ctx->regs + VIDINTCON1);
+
+       if (val & VIDINTCON1_INT_FRAME)
+               /* VSYNC interrupt */
+               writel(VIDINTCON1_INT_FRAME, ctx->regs + VIDINTCON1);
+
+       /* check the crtc is detached already from encoder */
+       if (ctx->pipe < 0 || !ctx->drm_dev)
+               goto out;
+
+       drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+       exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+
+       /* set wait vsync event to zero and wake up queue. */
+       if (atomic_read(&ctx->wait_vsync_event)) {
+               atomic_set(&ctx->wait_vsync_event, 0);
+               wake_up(&ctx->wait_vsync_queue);
+       }
+out:
+       return IRQ_HANDLED;
+}
+
 static int fimd_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct fimd_context *ctx;
-       struct exynos_drm_subdrv *subdrv;
        struct resource *res;
        int win;
        int ret = -EINVAL;
@@ -924,13 +864,25 @@ static int fimd_probe(struct platform_device *pdev)
        if (!ctx)
                return -ENOMEM;
 
-       ret = fimd_get_platform_data(ctx, dev);
-       if (ret)
-               return ret;
+       ctx->dev = dev;
+       ctx->suspended = true;
 
-       ret = fimd_configure_clocks(ctx, dev);
-       if (ret)
-               return ret;
+       if (of_property_read_bool(dev->of_node, "samsung,invert-vden"))
+               ctx->vidcon1 |= VIDCON1_INV_VDEN;
+       if (of_property_read_bool(dev->of_node, "samsung,invert-vclk"))
+               ctx->vidcon1 |= VIDCON1_INV_VCLK;
+
+       ctx->bus_clk = devm_clk_get(dev, "fimd");
+       if (IS_ERR(ctx->bus_clk)) {
+               dev_err(dev, "failed to get bus clock\n");
+               return PTR_ERR(ctx->bus_clk);
+       }
+
+       ctx->lcd_clk = devm_clk_get(dev, "sclk_fimd");
+       if (IS_ERR(ctx->lcd_clk)) {
+               dev_err(dev, "failed to get lcd clock\n");
+               return PTR_ERR(ctx->lcd_clk);
+       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
@@ -944,9 +896,7 @@ static int fimd_probe(struct platform_device *pdev)
                return -ENXIO;
        }
 
-       ctx->irq = res->start;
-
-       ret = devm_request_irq(dev, ctx->irq, fimd_irq_handler,
+       ret = devm_request_irq(dev, res->start, fimd_irq_handler,
                                                        0, "drm_fimd", ctx);
        if (ret) {
                dev_err(dev, "irq request failed.\n");
@@ -957,112 +907,35 @@ static int fimd_probe(struct platform_device *pdev)
        init_waitqueue_head(&ctx->wait_vsync_queue);
        atomic_set(&ctx->wait_vsync_event, 0);
 
-       subdrv = &ctx->subdrv;
+       platform_set_drvdata(pdev, &fimd_manager);
 
-       subdrv->dev = dev;
-       subdrv->manager = &fimd_manager;
-       subdrv->probe = fimd_subdrv_probe;
-       subdrv->remove = fimd_subdrv_remove;
+       fimd_manager.ctx = ctx;
+       exynos_drm_manager_register(&fimd_manager);
 
-       mutex_init(&ctx->lock);
-
-       platform_set_drvdata(pdev, ctx);
+       exynos_dpi_probe(ctx->dev);
 
        pm_runtime_enable(dev);
-       pm_runtime_get_sync(dev);
 
        for (win = 0; win < WINDOWS_NR; win++)
                fimd_clear_win(ctx, win);
 
-       exynos_drm_subdrv_register(subdrv);
-
        return 0;
 }
 
 static int fimd_remove(struct platform_device *pdev)
 {
-       struct device *dev = &pdev->dev;
-       struct fimd_context *ctx = platform_get_drvdata(pdev);
-
-       exynos_drm_subdrv_unregister(&ctx->subdrv);
-
-       if (ctx->suspended)
-               goto out;
-
-       pm_runtime_set_suspended(dev);
-       pm_runtime_put_sync(dev);
-
-out:
-       pm_runtime_disable(dev);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int fimd_suspend(struct device *dev)
-{
-       struct fimd_context *ctx = get_fimd_context(dev);
+       struct exynos_drm_manager *mgr = platform_get_drvdata(pdev);
 
-       /*
-        * do not use pm_runtime_suspend(). if pm_runtime_suspend() is
-        * called here, an error would be returned by that interface
-        * because the usage_count of pm runtime is more than 1.
-        */
-       if (!pm_runtime_suspended(dev))
-               return fimd_activate(ctx, false);
+       exynos_dpi_remove(&pdev->dev);
 
-       return 0;
-}
+       exynos_drm_manager_unregister(&fimd_manager);
 
-static int fimd_resume(struct device *dev)
-{
-       struct fimd_context *ctx = get_fimd_context(dev);
+       fimd_dpms(mgr, DRM_MODE_DPMS_OFF);
 
-       /*
-        * if entered to sleep when lcd panel was on, the usage_count
-        * of pm runtime would still be 1 so in this case, fimd driver
-        * should be on directly not drawing on pm runtime interface.
-        */
-       if (!pm_runtime_suspended(dev)) {
-               int ret;
-
-               ret = fimd_activate(ctx, true);
-               if (ret < 0)
-                       return ret;
-
-               /*
-                * in case of dpms on(standby), fimd_apply function will
-                * be called by encoder's dpms callback to update fimd's
-                * registers but in case of sleep wakeup, it's not.
-                * so fimd_apply function should be called at here.
-                */
-               fimd_apply(dev);
-       }
+       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-static int fimd_runtime_suspend(struct device *dev)
-{
-       struct fimd_context *ctx = get_fimd_context(dev);
-
-       return fimd_activate(ctx, false);
-}
-
-static int fimd_runtime_resume(struct device *dev)
-{
-       struct fimd_context *ctx = get_fimd_context(dev);
-
-       return fimd_activate(ctx, true);
-}
-#endif
-
-static const struct dev_pm_ops fimd_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(fimd_suspend, fimd_resume)
-       SET_RUNTIME_PM_OPS(fimd_runtime_suspend, fimd_runtime_resume, NULL)
-};
 
 struct platform_driver fimd_driver = {
        .probe          = fimd_probe,
@@ -1070,7 +943,6 @@ struct platform_driver fimd_driver = {
        .driver         = {
                .name   = "exynos4-fb",
                .owner  = THIS_MODULE,
-               .pm     = &fimd_pm_ops,
                .of_match_table = fimd_driver_dt_match,
        },
 };
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.c b/drivers/gpu/drm/exynos/exynos_drm_hdmi.c
deleted file mode 100644 (file)
index 8548b97..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright (C) 2011 Samsung Electronics Co.Ltd
- * Authors:
- *     Inki Dae <inki.dae@samsung.com>
- *     Seung-Woo Kim <sw0312.kim@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#include <drm/drmP.h>
-
-#include <linux/kernel.h>
-#include <linux/wait.h>
-#include <linux/platform_device.h>
-#include <linux/pm_runtime.h>
-
-#include <drm/exynos_drm.h>
-
-#include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
-
-#define to_context(dev)                platform_get_drvdata(to_platform_device(dev))
-#define to_subdrv(dev)         to_context(dev)
-#define get_ctx_from_subdrv(subdrv)    container_of(subdrv,\
-                                       struct drm_hdmi_context, subdrv);
-
-/* platform device pointer for common drm hdmi device. */
-static struct platform_device *exynos_drm_hdmi_pdev;
-
-/* Common hdmi subdrv needs to access the hdmi and mixer though context.
-* These should be initialied by the repective drivers */
-static struct exynos_drm_hdmi_context *hdmi_ctx;
-static struct exynos_drm_hdmi_context *mixer_ctx;
-
-/* these callback points shoud be set by specific drivers. */
-static struct exynos_hdmi_ops *hdmi_ops;
-static struct exynos_mixer_ops *mixer_ops;
-
-struct drm_hdmi_context {
-       struct exynos_drm_subdrv        subdrv;
-       struct exynos_drm_hdmi_context  *hdmi_ctx;
-       struct exynos_drm_hdmi_context  *mixer_ctx;
-
-       bool    enabled[MIXER_WIN_NR];
-};
-
-int exynos_platform_device_hdmi_register(void)
-{
-       struct platform_device *pdev;
-
-       if (exynos_drm_hdmi_pdev)
-               return -EEXIST;
-
-       pdev = platform_device_register_simple(
-                       "exynos-drm-hdmi", -1, NULL, 0);
-       if (IS_ERR(pdev))
-               return PTR_ERR(pdev);
-
-       exynos_drm_hdmi_pdev = pdev;
-
-       return 0;
-}
-
-void exynos_platform_device_hdmi_unregister(void)
-{
-       if (exynos_drm_hdmi_pdev) {
-               platform_device_unregister(exynos_drm_hdmi_pdev);
-               exynos_drm_hdmi_pdev = NULL;
-       }
-}
-
-void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx)
-{
-       if (ctx)
-               hdmi_ctx = ctx;
-}
-
-void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx)
-{
-       if (ctx)
-               mixer_ctx = ctx;
-}
-
-void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops)
-{
-       if (ops)
-               hdmi_ops = ops;
-}
-
-void exynos_mixer_ops_register(struct exynos_mixer_ops *ops)
-{
-       if (ops)
-               mixer_ops = ops;
-}
-
-static bool drm_hdmi_is_connected(struct device *dev)
-{
-       struct drm_hdmi_context *ctx = to_context(dev);
-
-       if (hdmi_ops && hdmi_ops->is_connected)
-               return hdmi_ops->is_connected(ctx->hdmi_ctx->ctx);
-
-       return false;
-}
-
-static struct edid *drm_hdmi_get_edid(struct device *dev,
-                       struct drm_connector *connector)
-{
-       struct drm_hdmi_context *ctx = to_context(dev);
-
-       if (hdmi_ops && hdmi_ops->get_edid)
-               return hdmi_ops->get_edid(ctx->hdmi_ctx->ctx, connector);
-
-       return NULL;
-}
-
-static int drm_hdmi_check_mode(struct device *dev,
-               struct drm_display_mode *mode)
-{
-       struct drm_hdmi_context *ctx = to_context(dev);
-       int ret = 0;
-
-       /*
-       * Both, mixer and hdmi should be able to handle the requested mode.
-       * If any of the two fails, return mode as BAD.
-       */
-
-       if (mixer_ops && mixer_ops->check_mode)
-               ret = mixer_ops->check_mode(ctx->mixer_ctx->ctx, mode);
-
-       if (ret)
-               return ret;
-
-       if (hdmi_ops && hdmi_ops->check_mode)
-               return hdmi_ops->check_mode(ctx->hdmi_ctx->ctx, mode);
-
-       return 0;
-}
-
-static int drm_hdmi_power_on(struct device *dev, int mode)
-{
-       struct drm_hdmi_context *ctx = to_context(dev);
-
-       if (hdmi_ops && hdmi_ops->power_on)
-               return hdmi_ops->power_on(ctx->hdmi_ctx->ctx, mode);
-
-       return 0;
-}
-
-static struct exynos_drm_display_ops drm_hdmi_display_ops = {
-       .type = EXYNOS_DISPLAY_TYPE_HDMI,
-       .is_connected = drm_hdmi_is_connected,
-       .get_edid = drm_hdmi_get_edid,
-       .check_mode = drm_hdmi_check_mode,
-       .power_on = drm_hdmi_power_on,
-};
-
-static int drm_hdmi_enable_vblank(struct device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct exynos_drm_manager *manager = subdrv->manager;
-
-       if (mixer_ops && mixer_ops->enable_vblank)
-               return mixer_ops->enable_vblank(ctx->mixer_ctx->ctx,
-                                               manager->pipe);
-
-       return 0;
-}
-
-static void drm_hdmi_disable_vblank(struct device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       if (mixer_ops && mixer_ops->disable_vblank)
-               return mixer_ops->disable_vblank(ctx->mixer_ctx->ctx);
-}
-
-static void drm_hdmi_wait_for_vblank(struct device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       if (mixer_ops && mixer_ops->wait_for_vblank)
-               mixer_ops->wait_for_vblank(ctx->mixer_ctx->ctx);
-}
-
-static void drm_hdmi_mode_fixup(struct device *subdrv_dev,
-                               struct drm_connector *connector,
-                               const struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode)
-{
-       struct drm_display_mode *m;
-       int mode_ok;
-
-       drm_mode_set_crtcinfo(adjusted_mode, 0);
-
-       mode_ok = drm_hdmi_check_mode(subdrv_dev, adjusted_mode);
-
-       /* just return if user desired mode exists. */
-       if (mode_ok == 0)
-               return;
-
-       /*
-        * otherwise, find the most suitable mode among modes and change it
-        * to adjusted_mode.
-        */
-       list_for_each_entry(m, &connector->modes, head) {
-               mode_ok = drm_hdmi_check_mode(subdrv_dev, m);
-
-               if (mode_ok == 0) {
-                       struct drm_mode_object base;
-                       struct list_head head;
-
-                       DRM_INFO("desired mode doesn't exist so\n");
-                       DRM_INFO("use the most suitable mode among modes.\n");
-
-                       DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
-                               m->hdisplay, m->vdisplay, m->vrefresh);
-
-                       /* preserve display mode header while copying. */
-                       head = adjusted_mode->head;
-                       base = adjusted_mode->base;
-                       memcpy(adjusted_mode, m, sizeof(*m));
-                       adjusted_mode->head = head;
-                       adjusted_mode->base = base;
-                       break;
-               }
-       }
-}
-
-static void drm_hdmi_mode_set(struct device *subdrv_dev, void *mode)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       if (hdmi_ops && hdmi_ops->mode_set)
-               hdmi_ops->mode_set(ctx->hdmi_ctx->ctx, mode);
-}
-
-static void drm_hdmi_get_max_resol(struct device *subdrv_dev,
-                               unsigned int *width, unsigned int *height)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       if (hdmi_ops && hdmi_ops->get_max_resol)
-               hdmi_ops->get_max_resol(ctx->hdmi_ctx->ctx, width, height);
-}
-
-static void drm_hdmi_commit(struct device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       if (hdmi_ops && hdmi_ops->commit)
-               hdmi_ops->commit(ctx->hdmi_ctx->ctx);
-}
-
-static void drm_hdmi_dpms(struct device *subdrv_dev, int mode)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       if (mixer_ops && mixer_ops->dpms)
-               mixer_ops->dpms(ctx->mixer_ctx->ctx, mode);
-
-       if (hdmi_ops && hdmi_ops->dpms)
-               hdmi_ops->dpms(ctx->hdmi_ctx->ctx, mode);
-}
-
-static void drm_hdmi_apply(struct device *subdrv_dev)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-       int i;
-
-       for (i = 0; i < MIXER_WIN_NR; i++) {
-               if (!ctx->enabled[i])
-                       continue;
-               if (mixer_ops && mixer_ops->win_commit)
-                       mixer_ops->win_commit(ctx->mixer_ctx->ctx, i);
-       }
-
-       if (hdmi_ops && hdmi_ops->commit)
-               hdmi_ops->commit(ctx->hdmi_ctx->ctx);
-}
-
-static struct exynos_drm_manager_ops drm_hdmi_manager_ops = {
-       .dpms = drm_hdmi_dpms,
-       .apply = drm_hdmi_apply,
-       .enable_vblank = drm_hdmi_enable_vblank,
-       .disable_vblank = drm_hdmi_disable_vblank,
-       .wait_for_vblank = drm_hdmi_wait_for_vblank,
-       .mode_fixup = drm_hdmi_mode_fixup,
-       .mode_set = drm_hdmi_mode_set,
-       .get_max_resol = drm_hdmi_get_max_resol,
-       .commit = drm_hdmi_commit,
-};
-
-static void drm_mixer_mode_set(struct device *subdrv_dev,
-               struct exynos_drm_overlay *overlay)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-
-       if (mixer_ops && mixer_ops->win_mode_set)
-               mixer_ops->win_mode_set(ctx->mixer_ctx->ctx, overlay);
-}
-
-static void drm_mixer_commit(struct device *subdrv_dev, int zpos)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-       int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
-
-       if (win < 0 || win >= MIXER_WIN_NR) {
-               DRM_ERROR("mixer window[%d] is wrong\n", win);
-               return;
-       }
-
-       if (mixer_ops && mixer_ops->win_commit)
-               mixer_ops->win_commit(ctx->mixer_ctx->ctx, win);
-
-       ctx->enabled[win] = true;
-}
-
-static void drm_mixer_disable(struct device *subdrv_dev, int zpos)
-{
-       struct drm_hdmi_context *ctx = to_context(subdrv_dev);
-       int win = (zpos == DEFAULT_ZPOS) ? MIXER_DEFAULT_WIN : zpos;
-
-       if (win < 0 || win >= MIXER_WIN_NR) {
-               DRM_ERROR("mixer window[%d] is wrong\n", win);
-               return;
-       }
-
-       if (mixer_ops && mixer_ops->win_disable)
-               mixer_ops->win_disable(ctx->mixer_ctx->ctx, win);
-
-       ctx->enabled[win] = false;
-}
-
-static struct exynos_drm_overlay_ops drm_hdmi_overlay_ops = {
-       .mode_set = drm_mixer_mode_set,
-       .commit = drm_mixer_commit,
-       .disable = drm_mixer_disable,
-};
-
-static struct exynos_drm_manager hdmi_manager = {
-       .pipe           = -1,
-       .ops            = &drm_hdmi_manager_ops,
-       .overlay_ops    = &drm_hdmi_overlay_ops,
-       .display_ops    = &drm_hdmi_display_ops,
-};
-
-static int hdmi_subdrv_probe(struct drm_device *drm_dev,
-               struct device *dev)
-{
-       struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
-       struct drm_hdmi_context *ctx;
-
-       if (!hdmi_ctx) {
-               DRM_ERROR("hdmi context not initialized.\n");
-               return -EFAULT;
-       }
-
-       if (!mixer_ctx) {
-               DRM_ERROR("mixer context not initialized.\n");
-               return -EFAULT;
-       }
-
-       ctx = get_ctx_from_subdrv(subdrv);
-
-       if (!ctx) {
-               DRM_ERROR("no drm hdmi context.\n");
-               return -EFAULT;
-       }
-
-       ctx->hdmi_ctx = hdmi_ctx;
-       ctx->mixer_ctx = mixer_ctx;
-
-       ctx->hdmi_ctx->drm_dev = drm_dev;
-       ctx->mixer_ctx->drm_dev = drm_dev;
-
-       if (mixer_ops->iommu_on)
-               mixer_ops->iommu_on(ctx->mixer_ctx->ctx, true);
-
-       return 0;
-}
-
-static void hdmi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
-       struct drm_hdmi_context *ctx;
-       struct exynos_drm_subdrv *subdrv = to_subdrv(dev);
-
-       ctx = get_ctx_from_subdrv(subdrv);
-
-       if (mixer_ops->iommu_on)
-               mixer_ops->iommu_on(ctx->mixer_ctx->ctx, false);
-}
-
-static int exynos_drm_hdmi_probe(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct exynos_drm_subdrv *subdrv;
-       struct drm_hdmi_context *ctx;
-
-       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
-               return -ENOMEM;
-
-       subdrv = &ctx->subdrv;
-
-       subdrv->dev = dev;
-       subdrv->manager = &hdmi_manager;
-       subdrv->probe = hdmi_subdrv_probe;
-       subdrv->remove = hdmi_subdrv_remove;
-
-       platform_set_drvdata(pdev, subdrv);
-
-       exynos_drm_subdrv_register(subdrv);
-
-       return 0;
-}
-
-static int exynos_drm_hdmi_remove(struct platform_device *pdev)
-{
-       struct drm_hdmi_context *ctx = platform_get_drvdata(pdev);
-
-       exynos_drm_subdrv_unregister(&ctx->subdrv);
-
-       return 0;
-}
-
-struct platform_driver exynos_drm_common_hdmi_driver = {
-       .probe          = exynos_drm_hdmi_probe,
-       .remove         = exynos_drm_hdmi_remove,
-       .driver         = {
-               .name   = "exynos-drm-hdmi",
-               .owner  = THIS_MODULE,
-       },
-};
diff --git a/drivers/gpu/drm/exynos/exynos_drm_hdmi.h b/drivers/gpu/drm/exynos/exynos_drm_hdmi.h
deleted file mode 100644 (file)
index 724cab1..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-/* exynos_drm_hdmi.h
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
- * Authoer: Inki Dae <inki.dae@samsung.com>
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DRM_HDMI_H_
-#define _EXYNOS_DRM_HDMI_H_
-
-#define MIXER_WIN_NR           3
-#define MIXER_DEFAULT_WIN      0
-
-/*
- * exynos hdmi common context structure.
- *
- * @drm_dev: pointer to drm_device.
- * @ctx: pointer to the context of specific device driver.
- *     this context should be hdmi_context or mixer_context.
- */
-struct exynos_drm_hdmi_context {
-       struct drm_device       *drm_dev;
-       void                    *ctx;
-};
-
-struct exynos_hdmi_ops {
-       /* display */
-       bool (*is_connected)(void *ctx);
-       struct edid *(*get_edid)(void *ctx,
-                       struct drm_connector *connector);
-       int (*check_mode)(void *ctx, struct drm_display_mode *mode);
-       int (*power_on)(void *ctx, int mode);
-
-       /* manager */
-       void (*mode_set)(void *ctx, struct drm_display_mode *mode);
-       void (*get_max_resol)(void *ctx, unsigned int *width,
-                               unsigned int *height);
-       void (*commit)(void *ctx);
-       void (*dpms)(void *ctx, int mode);
-};
-
-struct exynos_mixer_ops {
-       /* manager */
-       int (*iommu_on)(void *ctx, bool enable);
-       int (*enable_vblank)(void *ctx, int pipe);
-       void (*disable_vblank)(void *ctx);
-       void (*wait_for_vblank)(void *ctx);
-       void (*dpms)(void *ctx, int mode);
-
-       /* overlay */
-       void (*win_mode_set)(void *ctx, struct exynos_drm_overlay *overlay);
-       void (*win_commit)(void *ctx, int zpos);
-       void (*win_disable)(void *ctx, int zpos);
-
-       /* display */
-       int (*check_mode)(void *ctx, struct drm_display_mode *mode);
-};
-
-void exynos_hdmi_drv_attach(struct exynos_drm_hdmi_context *ctx);
-void exynos_mixer_drv_attach(struct exynos_drm_hdmi_context *ctx);
-void exynos_hdmi_ops_register(struct exynos_hdmi_ops *ops);
-void exynos_mixer_ops_register(struct exynos_mixer_ops *ops);
-#endif
index fcb0652..8371cbd 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <drm/exynos_drm.h>
 #include "exynos_drm_drv.h"
-#include "exynos_drm_encoder.h"
+#include "exynos_drm_crtc.h"
 #include "exynos_drm_fb.h"
 #include "exynos_drm_gem.h"
 #include "exynos_drm_plane.h"
@@ -87,7 +87,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                struct exynos_drm_gem_buf *buffer = exynos_drm_fb_buffer(fb, i);
 
                if (!buffer) {
-                       DRM_LOG_KMS("buffer is null\n");
+                       DRM_DEBUG_KMS("buffer is null\n");
                        return -EFAULT;
                }
 
@@ -139,7 +139,7 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
                        overlay->crtc_x, overlay->crtc_y,
                        overlay->crtc_width, overlay->crtc_height);
 
-       exynos_drm_fn_encoder(crtc, overlay, exynos_drm_encoder_plane_mode_set);
+       exynos_drm_crtc_plane_mode_set(crtc, overlay);
 
        return 0;
 }
@@ -149,8 +149,7 @@ void exynos_plane_commit(struct drm_plane *plane)
        struct exynos_plane *exynos_plane = to_exynos_plane(plane);
        struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
 
-       exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-                       exynos_drm_encoder_plane_commit);
+       exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
 }
 
 void exynos_plane_dpms(struct drm_plane *plane, int mode)
@@ -162,17 +161,13 @@ void exynos_plane_dpms(struct drm_plane *plane, int mode)
                if (exynos_plane->enabled)
                        return;
 
-               exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-                               exynos_drm_encoder_plane_enable);
-
+               exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
                exynos_plane->enabled = true;
        } else {
                if (!exynos_plane->enabled)
                        return;
 
-               exynos_drm_fn_encoder(plane->crtc, &overlay->zpos,
-                               exynos_drm_encoder_plane_disable);
-
+               exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
                exynos_plane->enabled = false;
        }
 }
@@ -259,7 +254,7 @@ static void exynos_plane_attach_zpos_property(struct drm_plane *plane)
 }
 
 struct drm_plane *exynos_plane_init(struct drm_device *dev,
-                                   unsigned int possible_crtcs, bool priv)
+                                   unsigned long possible_crtcs, bool priv)
 {
        struct exynos_plane *exynos_plane;
        int err;
index 8831245..84d464c 100644 (file)
@@ -17,4 +17,4 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
 void exynos_plane_commit(struct drm_plane *plane);
 void exynos_plane_dpms(struct drm_plane *plane, int mode);
 struct drm_plane *exynos_plane_init(struct drm_device *dev,
-                                   unsigned int possible_crtcs, bool priv);
+                                   unsigned long possible_crtcs, bool priv);
index ddaaedd..7afead9 100644 (file)
@@ -28,7 +28,9 @@
 /* vidi has totally three virtual windows. */
 #define WINDOWS_NR             3
 
-#define get_vidi_context(dev)  platform_get_drvdata(to_platform_device(dev))
+#define get_vidi_mgr(dev)      platform_get_drvdata(to_platform_device(dev))
+#define ctx_from_connector(c)  container_of(c, struct vidi_context, \
+                                       connector)
 
 struct vidi_win_data {
        unsigned int            offset_x;
@@ -45,8 +47,10 @@ struct vidi_win_data {
 };
 
 struct vidi_context {
-       struct exynos_drm_subdrv        subdrv;
+       struct drm_device               *drm_dev;
        struct drm_crtc                 *crtc;
+       struct drm_encoder              *encoder;
+       struct drm_connector            connector;
        struct vidi_win_data            win_data[WINDOWS_NR];
        struct edid                     *raw_edid;
        unsigned int                    clkdiv;
@@ -58,6 +62,7 @@ struct vidi_context {
        bool                            direct_vblank;
        struct work_struct              work;
        struct mutex                    lock;
+       int                             pipe;
 };
 
 static const char fake_edid_info[] = {
@@ -85,126 +90,34 @@ static const char fake_edid_info[] = {
        0x00, 0x00, 0x00, 0x06
 };
 
-static bool vidi_display_is_connected(struct device *dev)
+static void vidi_apply(struct exynos_drm_manager *mgr)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
-
-       /*
-        * connection request would come from user side
-        * to do hotplug through specific ioctl.
-        */
-       return ctx->connected ? true : false;
-}
-
-static struct edid *vidi_get_edid(struct device *dev,
-                       struct drm_connector *connector)
-{
-       struct vidi_context *ctx = get_vidi_context(dev);
-       struct edid *edid;
-
-       /*
-        * the edid data comes from user side and it would be set
-        * to ctx->raw_edid through specific ioctl.
-        */
-       if (!ctx->raw_edid) {
-               DRM_DEBUG_KMS("raw_edid is null.\n");
-               return ERR_PTR(-EFAULT);
-       }
-
-       edid = drm_edid_duplicate(ctx->raw_edid);
-       if (!edid) {
-               DRM_DEBUG_KMS("failed to allocate edid\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       return edid;
-}
-
-static void *vidi_get_panel(struct device *dev)
-{
-       /* TODO. */
-
-       return NULL;
-}
-
-static int vidi_check_mode(struct device *dev, struct drm_display_mode *mode)
-{
-       /* TODO. */
-
-       return 0;
-}
-
-static int vidi_display_power_on(struct device *dev, int mode)
-{
-       /* TODO */
-
-       return 0;
-}
-
-static struct exynos_drm_display_ops vidi_display_ops = {
-       .type = EXYNOS_DISPLAY_TYPE_VIDI,
-       .is_connected = vidi_display_is_connected,
-       .get_edid = vidi_get_edid,
-       .get_panel = vidi_get_panel,
-       .check_mode = vidi_check_mode,
-       .power_on = vidi_display_power_on,
-};
-
-static void vidi_dpms(struct device *subdrv_dev, int mode)
-{
-       struct vidi_context *ctx = get_vidi_context(subdrv_dev);
-
-       DRM_DEBUG_KMS("%d\n", mode);
-
-       mutex_lock(&ctx->lock);
-
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-               /* TODO. */
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               /* TODO. */
-               break;
-       default:
-               DRM_DEBUG_KMS("unspecified mode %d\n", mode);
-               break;
-       }
-
-       mutex_unlock(&ctx->lock);
-}
-
-static void vidi_apply(struct device *subdrv_dev)
-{
-       struct vidi_context *ctx = get_vidi_context(subdrv_dev);
-       struct exynos_drm_manager *mgr = ctx->subdrv.manager;
+       struct vidi_context *ctx = mgr->ctx;
        struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
-       struct exynos_drm_overlay_ops *ovl_ops = mgr->overlay_ops;
        struct vidi_win_data *win_data;
        int i;
 
        for (i = 0; i < WINDOWS_NR; i++) {
                win_data = &ctx->win_data[i];
-               if (win_data->enabled && (ovl_ops && ovl_ops->commit))
-                       ovl_ops->commit(subdrv_dev, i);
+               if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
+                       mgr_ops->win_commit(mgr, i);
        }
 
        if (mgr_ops && mgr_ops->commit)
-               mgr_ops->commit(subdrv_dev);
+               mgr_ops->commit(mgr);
 }
 
-static void vidi_commit(struct device *dev)
+static void vidi_commit(struct exynos_drm_manager *mgr)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *ctx = mgr->ctx;
 
        if (ctx->suspended)
                return;
 }
 
-static int vidi_enable_vblank(struct device *dev)
+static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *ctx = mgr->ctx;
 
        if (ctx->suspended)
                return -EPERM;
@@ -217,16 +130,16 @@ static int vidi_enable_vblank(struct device *dev)
        /*
         * in case of page flip request, vidi_finish_pageflip function
         * will not be called because direct_vblank is true and then
-        * that function will be called by overlay_ops->commit callback
+        * that function will be called by manager_ops->win_commit callback
         */
        schedule_work(&ctx->work);
 
        return 0;
 }
 
-static void vidi_disable_vblank(struct device *dev)
+static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *ctx = mgr->ctx;
 
        if (ctx->suspended)
                return;
@@ -235,24 +148,16 @@ static void vidi_disable_vblank(struct device *dev)
                ctx->vblank_on = false;
 }
 
-static struct exynos_drm_manager_ops vidi_manager_ops = {
-       .dpms = vidi_dpms,
-       .apply = vidi_apply,
-       .commit = vidi_commit,
-       .enable_vblank = vidi_enable_vblank,
-       .disable_vblank = vidi_disable_vblank,
-};
-
-static void vidi_win_mode_set(struct device *dev,
-                             struct exynos_drm_overlay *overlay)
+static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
+                       struct exynos_drm_overlay *overlay)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *ctx = mgr->ctx;
        struct vidi_win_data *win_data;
        int win;
        unsigned long offset;
 
        if (!overlay) {
-               dev_err(dev, "overlay is NULL\n");
+               DRM_ERROR("overlay is NULL\n");
                return;
        }
 
@@ -296,9 +201,9 @@ static void vidi_win_mode_set(struct device *dev,
                        overlay->fb_width, overlay->crtc_width);
 }
 
-static void vidi_win_commit(struct device *dev, int zpos)
+static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *ctx = mgr->ctx;
        struct vidi_win_data *win_data;
        int win = zpos;
 
@@ -321,9 +226,9 @@ static void vidi_win_commit(struct device *dev, int zpos)
                schedule_work(&ctx->work);
 }
 
-static void vidi_win_disable(struct device *dev, int zpos)
+static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct vidi_context *ctx = mgr->ctx;
        struct vidi_win_data *win_data;
        int win = zpos;
 
@@ -339,98 +244,132 @@ static void vidi_win_disable(struct device *dev, int zpos)
        /* TODO. */
 }
 
-static struct exynos_drm_overlay_ops vidi_overlay_ops = {
-       .mode_set = vidi_win_mode_set,
-       .commit = vidi_win_commit,
-       .disable = vidi_win_disable,
-};
+static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
+{
+       struct vidi_context *ctx = mgr->ctx;
 
-static struct exynos_drm_manager vidi_manager = {
-       .pipe           = -1,
-       .ops            = &vidi_manager_ops,
-       .overlay_ops    = &vidi_overlay_ops,
-       .display_ops    = &vidi_display_ops,
-};
+       DRM_DEBUG_KMS("%s\n", __FILE__);
 
-static void vidi_fake_vblank_handler(struct work_struct *work)
-{
-       struct vidi_context *ctx = container_of(work, struct vidi_context,
-                                       work);
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct exynos_drm_manager *manager = subdrv->manager;
+       if (enable != false && enable != true)
+               return -EINVAL;
 
-       if (manager->pipe < 0)
-               return;
+       if (enable) {
+               ctx->suspended = false;
 
-       /* refresh rate is about 50Hz. */
-       usleep_range(16000, 20000);
+               /* if vblank was enabled status, enable it again. */
+               if (test_and_clear_bit(0, &ctx->irq_flags))
+                       vidi_enable_vblank(mgr);
+
+               vidi_apply(mgr);
+       } else {
+               ctx->suspended = true;
+       }
+
+       return 0;
+}
+
+static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
+{
+       struct vidi_context *ctx = mgr->ctx;
+
+       DRM_DEBUG_KMS("%d\n", mode);
 
        mutex_lock(&ctx->lock);
 
-       if (ctx->direct_vblank) {
-               drm_handle_vblank(subdrv->drm_dev, manager->pipe);
-               ctx->direct_vblank = false;
-               mutex_unlock(&ctx->lock);
-               return;
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+               vidi_power_on(mgr, true);
+               break;
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+               vidi_power_on(mgr, false);
+               break;
+       default:
+               DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+               break;
        }
 
        mutex_unlock(&ctx->lock);
-
-       exynos_drm_crtc_finish_pageflip(subdrv->drm_dev, manager->pipe);
 }
 
-static int vidi_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
+static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
+                       struct drm_device *drm_dev, int pipe)
 {
+       struct vidi_context *ctx = mgr->ctx;
+
+       DRM_ERROR("vidi initialize ct=%p dev=%p pipe=%d\n", ctx, drm_dev, pipe);
+
+       ctx->drm_dev = drm_dev;
+       ctx->pipe = pipe;
+
        /*
         * enable drm irq mode.
-        * - with irq_enabled = true, we can use the vblank feature.
+        * - with irq_enabled = 1, we can use the vblank feature.
         *
         * P.S. note that we wouldn't use drm irq handler but
         *      just specific driver own one instead because
         *      drm framework supports only one irq handler.
         */
-       drm_dev->irq_enabled = true;
+       drm_dev->irq_enabled = 1;
 
        /*
-        * with vblank_disable_allowed = true, vblank interrupt will be disabled
+        * with vblank_disable_allowed = 1, vblank interrupt will be disabled
         * by drm timer once a current process gives up ownership of
         * vblank event.(after drm_vblank_put function is called)
         */
-       drm_dev->vblank_disable_allowed = true;
+       drm_dev->vblank_disable_allowed = 1;
 
        return 0;
 }
 
-static void vidi_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
-{
-       /* TODO. */
-}
+static struct exynos_drm_manager_ops vidi_manager_ops = {
+       .initialize = vidi_mgr_initialize,
+       .dpms = vidi_dpms,
+       .commit = vidi_commit,
+       .enable_vblank = vidi_enable_vblank,
+       .disable_vblank = vidi_disable_vblank,
+       .win_mode_set = vidi_win_mode_set,
+       .win_commit = vidi_win_commit,
+       .win_disable = vidi_win_disable,
+};
 
-static int vidi_power_on(struct vidi_context *ctx, bool enable)
+static struct exynos_drm_manager vidi_manager = {
+       .type = EXYNOS_DISPLAY_TYPE_VIDI,
+       .ops = &vidi_manager_ops,
+};
+
+static void vidi_fake_vblank_handler(struct work_struct *work)
 {
-       struct exynos_drm_subdrv *subdrv = &ctx->subdrv;
-       struct device *dev = subdrv->dev;
+       struct vidi_context *ctx = container_of(work, struct vidi_context,
+                                       work);
 
-       if (enable) {
-               ctx->suspended = false;
+       if (ctx->pipe < 0)
+               return;
 
-               /* if vblank was enabled status, enable it again. */
-               if (test_and_clear_bit(0, &ctx->irq_flags))
-                       vidi_enable_vblank(dev);
+       /* refresh rate is about 50Hz. */
+       usleep_range(16000, 20000);
 
-               vidi_apply(dev);
-       } else {
-               ctx->suspended = true;
+       mutex_lock(&ctx->lock);
+
+       if (ctx->direct_vblank) {
+               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+               ctx->direct_vblank = false;
+               mutex_unlock(&ctx->lock);
+               return;
        }
 
-       return 0;
+       mutex_unlock(&ctx->lock);
+
+       exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
 }
 
 static int vidi_show_connection(struct device *dev,
                                struct device_attribute *attr, char *buf)
 {
        int rc;
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
+       struct vidi_context *ctx = mgr->ctx;
 
        mutex_lock(&ctx->lock);
 
@@ -445,7 +384,8 @@ static int vidi_store_connection(struct device *dev,
                                struct device_attribute *attr,
                                const char *buf, size_t len)
 {
-       struct vidi_context *ctx = get_vidi_context(dev);
+       struct exynos_drm_manager *mgr = get_vidi_mgr(dev);
+       struct vidi_context *ctx = mgr->ctx;
        int ret;
 
        ret = kstrtoint(buf, 0, &ctx->connected);
@@ -467,7 +407,7 @@ static int vidi_store_connection(struct device *dev,
 
        DRM_DEBUG_KMS("requested connection.\n");
 
-       drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
+       drm_helper_hpd_irq_event(ctx->drm_dev);
 
        return len;
 }
@@ -480,8 +420,7 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
 {
        struct vidi_context *ctx = NULL;
        struct drm_encoder *encoder;
-       struct exynos_drm_manager *manager;
-       struct exynos_drm_display_ops *display_ops;
+       struct exynos_drm_display *display;
        struct drm_exynos_vidi_connection *vidi = data;
 
        if (!vidi) {
@@ -496,11 +435,10 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
 
        list_for_each_entry(encoder, &drm_dev->mode_config.encoder_list,
                                                                head) {
-               manager = exynos_drm_get_manager(encoder);
-               display_ops = manager->display_ops;
+               display = exynos_drm_get_display(encoder);
 
-               if (display_ops->type == EXYNOS_DISPLAY_TYPE_VIDI) {
-                       ctx = get_vidi_context(manager->dev);
+               if (display->type == EXYNOS_DISPLAY_TYPE_VIDI) {
+                       ctx = display->ctx;
                        break;
                }
        }
@@ -539,16 +477,119 @@ int vidi_connection_ioctl(struct drm_device *drm_dev, void *data,
        }
 
        ctx->connected = vidi->connection;
-       drm_helper_hpd_irq_event(ctx->subdrv.drm_dev);
+       drm_helper_hpd_irq_event(ctx->drm_dev);
+
+       return 0;
+}
+
+static enum drm_connector_status vidi_detect(struct drm_connector *connector,
+                       bool force)
+{
+       struct vidi_context *ctx = ctx_from_connector(connector);
+
+       /*
+        * connection request would come from user side
+        * to do hotplug through specific ioctl.
+        */
+       return ctx->connected ? connector_status_connected :
+                       connector_status_disconnected;
+}
+
+static void vidi_connector_destroy(struct drm_connector *connector)
+{
+}
+
+static struct drm_connector_funcs vidi_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = vidi_detect,
+       .destroy = vidi_connector_destroy,
+};
+
+static int vidi_get_modes(struct drm_connector *connector)
+{
+       struct vidi_context *ctx = ctx_from_connector(connector);
+       struct edid *edid;
+       int edid_len;
+
+       /*
+        * the edid data comes from user side and it would be set
+        * to ctx->raw_edid through specific ioctl.
+        */
+       if (!ctx->raw_edid) {
+               DRM_DEBUG_KMS("raw_edid is null.\n");
+               return -EFAULT;
+       }
+
+       edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH;
+       edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL);
+       if (!edid) {
+               DRM_DEBUG_KMS("failed to allocate edid\n");
+               return -ENOMEM;
+       }
+
+       drm_mode_connector_update_edid_property(connector, edid);
+
+       return drm_add_edid_modes(connector, edid);
+}
+
+static int vidi_mode_valid(struct drm_connector *connector,
+                       struct drm_display_mode *mode)
+{
+       return MODE_OK;
+}
+
+static struct drm_encoder *vidi_best_encoder(struct drm_connector *connector)
+{
+       struct vidi_context *ctx = ctx_from_connector(connector);
+
+       return ctx->encoder;
+}
+
+static struct drm_connector_helper_funcs vidi_connector_helper_funcs = {
+       .get_modes = vidi_get_modes,
+       .mode_valid = vidi_mode_valid,
+       .best_encoder = vidi_best_encoder,
+};
+
+static int vidi_create_connector(struct exynos_drm_display *display,
+                               struct drm_encoder *encoder)
+{
+       struct vidi_context *ctx = display->ctx;
+       struct drm_connector *connector = &ctx->connector;
+       int ret;
+
+       ctx->encoder = encoder;
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+       ret = drm_connector_init(ctx->drm_dev, connector,
+                       &vidi_connector_funcs, DRM_MODE_CONNECTOR_VIRTUAL);
+       if (ret) {
+               DRM_ERROR("Failed to initialize connector with drm\n");
+               return ret;
+       }
+
+       drm_connector_helper_add(connector, &vidi_connector_helper_funcs);
+       drm_sysfs_connector_add(connector);
+       drm_mode_connector_attach_encoder(connector, encoder);
 
        return 0;
 }
 
+
+static struct exynos_drm_display_ops vidi_display_ops = {
+       .create_connector = vidi_create_connector,
+};
+
+static struct exynos_drm_display vidi_display = {
+       .type = EXYNOS_DISPLAY_TYPE_VIDI,
+       .ops = &vidi_display_ops,
+};
+
 static int vidi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct vidi_context *ctx;
-       struct exynos_drm_subdrv *subdrv;
        int ret;
 
        ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
@@ -559,21 +600,19 @@ static int vidi_probe(struct platform_device *pdev)
 
        INIT_WORK(&ctx->work, vidi_fake_vblank_handler);
 
-       subdrv = &ctx->subdrv;
-       subdrv->dev = dev;
-       subdrv->manager = &vidi_manager;
-       subdrv->probe = vidi_subdrv_probe;
-       subdrv->remove = vidi_subdrv_remove;
+       vidi_manager.ctx = ctx;
+       vidi_display.ctx = ctx;
 
        mutex_init(&ctx->lock);
 
-       platform_set_drvdata(pdev, ctx);
+       platform_set_drvdata(pdev, &vidi_manager);
 
        ret = device_create_file(dev, &dev_attr_connection);
        if (ret < 0)
                DRM_INFO("failed to create connection sysfs.\n");
 
-       exynos_drm_subdrv_register(subdrv);
+       exynos_drm_manager_register(&vidi_manager);
+       exynos_drm_display_register(&vidi_display);
 
        return 0;
 }
@@ -582,7 +621,8 @@ static int vidi_remove(struct platform_device *pdev)
 {
        struct vidi_context *ctx = platform_get_drvdata(pdev);
 
-       exynos_drm_subdrv_unregister(&ctx->subdrv);
+       exynos_drm_display_unregister(&vidi_display);
+       exynos_drm_manager_unregister(&vidi_manager);
 
        if (ctx->raw_edid != (struct edid *)fake_edid_info) {
                kfree(ctx->raw_edid);
@@ -592,32 +632,11 @@ static int vidi_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int vidi_suspend(struct device *dev)
-{
-       struct vidi_context *ctx = get_vidi_context(dev);
-
-       return vidi_power_on(ctx, false);
-}
-
-static int vidi_resume(struct device *dev)
-{
-       struct vidi_context *ctx = get_vidi_context(dev);
-
-       return vidi_power_on(ctx, true);
-}
-#endif
-
-static const struct dev_pm_ops vidi_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(vidi_suspend, vidi_resume)
-};
-
 struct platform_driver vidi_driver = {
        .probe          = vidi_probe,
        .remove         = vidi_remove,
        .driver         = {
                .name   = "exynos-drm-vidi",
                .owner  = THIS_MODULE,
-               .pm     = &vidi_pm_ops,
        },
 };
index c021ddc..9a6d652 100644 (file)
 #include <linux/regulator/consumer.h>
 #include <linux/io.h>
 #include <linux/of.h>
+#include <linux/i2c.h>
 #include <linux/of_gpio.h>
 #include <linux/hdmi.h>
 
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
-#include "exynos_drm_hdmi.h"
-
-#include "exynos_hdmi.h"
+#include "exynos_mixer.h"
 
 #include <linux/gpio.h>
 #include <media/s5p_hdmi.h>
 
-#define MAX_WIDTH              1920
-#define MAX_HEIGHT             1080
-#define get_hdmi_context(dev)  platform_get_drvdata(to_platform_device(dev))
+#define get_hdmi_display(dev)  platform_get_drvdata(to_platform_device(dev))
+#define ctx_from_connector(c)  container_of(c, struct hdmi_context, connector)
 
 /* AVI header and aspect ratio */
 #define HDMI_AVI_VERSION               0x02
 #define HDMI_AVI_LENGTH                0x0D
-#define AVI_PIC_ASPECT_RATIO_16_9      (2 << 4)
-#define AVI_SAME_AS_PIC_ASPECT_RATIO   8
 
 /* AUI header info */
 #define HDMI_AUI_VERSION       0x01
 #define HDMI_AUI_LENGTH        0x0A
+#define AVI_SAME_AS_PIC_ASPECT_RATIO 0x8
+#define AVI_4_3_CENTER_RATIO   0x9
+#define AVI_16_9_CENTER_RATIO  0xa
 
 enum hdmi_type {
        HDMI_TYPE13,
        HDMI_TYPE14,
 };
 
+struct hdmi_driver_data {
+       unsigned int type;
+       unsigned int is_apb_phy:1;
+};
+
 struct hdmi_resources {
        struct clk                      *hdmi;
        struct clk                      *sclk_hdmi;
@@ -162,6 +166,7 @@ struct hdmi_v14_conf {
 struct hdmi_conf_regs {
        int pixel_clock;
        int cea_video_id;
+       enum hdmi_picture_aspect aspect_ratio;
        union {
                struct hdmi_v13_conf v13_conf;
                struct hdmi_v14_conf v14_conf;
@@ -171,16 +176,17 @@ struct hdmi_conf_regs {
 struct hdmi_context {
        struct device                   *dev;
        struct drm_device               *drm_dev;
+       struct drm_connector            connector;
+       struct drm_encoder              *encoder;
        bool                            hpd;
        bool                            powered;
        bool                            dvi_mode;
        struct mutex                    hdmi_mutex;
 
        void __iomem                    *regs;
-       void                            *parent_ctx;
        int                             irq;
 
-       struct i2c_client               *ddc_port;
+       struct i2c_adapter              *ddc_adpt;
        struct i2c_client               *hdmiphy_port;
 
        /* current hdmiphy conf regs */
@@ -198,6 +204,14 @@ struct hdmiphy_config {
        u8 conf[32];
 };
 
+struct hdmi_driver_data exynos4212_hdmi_driver_data = {
+       .type   = HDMI_TYPE14,
+};
+
+struct hdmi_driver_data exynos5_hdmi_driver_data = {
+       .type   = HDMI_TYPE14,
+};
+
 /* list of phy config settings */
 static const struct hdmiphy_config hdmiphy_v13_configs[] = {
        {
@@ -302,6 +316,24 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
                        0x54, 0xbd, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
                },
        },
+       {
+               .pixel_clock = 71000000,
+               .conf = {
+                       0x01, 0x91, 0x1e, 0x15, 0x40, 0x3c, 0xce, 0x08,
+                       0x04, 0x20, 0xb2, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+                       0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+                       0x54, 0xad, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
+               },
+       },
+       {
+               .pixel_clock = 73250000,
+               .conf = {
+                       0x01, 0xd1, 0x1f, 0x15, 0x40, 0x18, 0xe9, 0x08,
+                       0x02, 0xa0, 0xb7, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+                       0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+                       0x54, 0xa8, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
+               },
+       },
        {
                .pixel_clock = 74176000,
                .conf = {
@@ -329,6 +361,15 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
                        0x54, 0x93, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
                },
        },
+       {
+               .pixel_clock = 88750000,
+               .conf = {
+                       0x01, 0x91, 0x25, 0x17, 0x40, 0x30, 0xfe, 0x08,
+                       0x06, 0x20, 0xde, 0xd8, 0x45, 0xa0, 0xac, 0x80,
+                       0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+                       0x54, 0x8a, 0x24, 0x01, 0x00, 0x00, 0x01, 0x80,
+               },
+       },
        {
                .pixel_clock = 106500000,
                .conf = {
@@ -347,6 +388,24 @@ static const struct hdmiphy_config hdmiphy_v14_configs[] = {
                        0x54, 0xc7, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
                },
        },
+       {
+               .pixel_clock = 115500000,
+               .conf = {
+                       0x01, 0xd1, 0x30, 0x1a, 0x40, 0x40, 0x10, 0x04,
+                       0x04, 0xa0, 0x21, 0xd9, 0x45, 0xa0, 0xac, 0x80,
+                       0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+                       0x54, 0xaa, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
+               },
+       },
+       {
+               .pixel_clock = 119000000,
+               .conf = {
+                       0x01, 0x91, 0x32, 0x14, 0x40, 0x60, 0xd8, 0x08,
+                       0x06, 0x20, 0x2a, 0xd9, 0x45, 0xa0, 0xac, 0x80,
+                       0x06, 0x80, 0x11, 0x04, 0x02, 0x22, 0x44, 0x86,
+                       0x54, 0x9d, 0x25, 0x03, 0x00, 0x00, 0x01, 0x80,
+               },
+       },
        {
                .pixel_clock = 146250000,
                .conf = {
@@ -668,7 +727,6 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
 {
        u32 hdr_sum;
        u8 chksum;
-       u32 aspect_ratio;
        u32 mod;
        u32 vic;
 
@@ -697,10 +755,28 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
                        AVI_ACTIVE_FORMAT_VALID |
                        AVI_UNDERSCANNED_DISPLAY_VALID);
 
-               aspect_ratio = AVI_PIC_ASPECT_RATIO_16_9;
-
-               hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2), aspect_ratio |
-                               AVI_SAME_AS_PIC_ASPECT_RATIO);
+               /*
+                * Set the aspect ratio as per the mode, mentioned in
+                * Table 9 AVI InfoFrame Data Byte 2 of CEA-861-D Standard
+                */
+               switch (hdata->mode_conf.aspect_ratio) {
+               case HDMI_PICTURE_ASPECT_4_3:
+                       hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
+                                       hdata->mode_conf.aspect_ratio |
+                                       AVI_4_3_CENTER_RATIO);
+                       break;
+               case HDMI_PICTURE_ASPECT_16_9:
+                       hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
+                                       hdata->mode_conf.aspect_ratio |
+                                       AVI_16_9_CENTER_RATIO);
+                       break;
+               case HDMI_PICTURE_ASPECT_NONE:
+               default:
+                       hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(2),
+                                       hdata->mode_conf.aspect_ratio |
+                                       AVI_SAME_AS_PIC_ASPECT_RATIO);
+                       break;
+               }
 
                vic = hdata->mode_conf.cea_video_id;
                hdmi_reg_writeb(hdata, HDMI_AVI_BYTE(4), vic);
@@ -728,31 +804,46 @@ static void hdmi_reg_infoframe(struct hdmi_context *hdata,
        }
 }
 
-static bool hdmi_is_connected(void *ctx)
+static enum drm_connector_status hdmi_detect(struct drm_connector *connector,
+                               bool force)
 {
-       struct hdmi_context *hdata = ctx;
+       struct hdmi_context *hdata = ctx_from_connector(connector);
+
+       return hdata->hpd ? connector_status_connected :
+                       connector_status_disconnected;
+}
 
-       return hdata->hpd;
+static void hdmi_connector_destroy(struct drm_connector *connector)
+{
 }
 
-static struct edid *hdmi_get_edid(void *ctx, struct drm_connector *connector)
+static struct drm_connector_funcs hdmi_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .detect = hdmi_detect,
+       .destroy = hdmi_connector_destroy,
+};
+
+static int hdmi_get_modes(struct drm_connector *connector)
 {
-       struct edid *raw_edid;
-       struct hdmi_context *hdata = ctx;
+       struct hdmi_context *hdata = ctx_from_connector(connector);
+       struct edid *edid;
 
-       if (!hdata->ddc_port)
-               return ERR_PTR(-ENODEV);
+       if (!hdata->ddc_adpt)
+               return -ENODEV;
 
-       raw_edid = drm_get_edid(connector, hdata->ddc_port->adapter);
-       if (!raw_edid)
-               return ERR_PTR(-ENODEV);
+       edid = drm_get_edid(connector, hdata->ddc_adpt);
+       if (!edid)
+               return -ENODEV;
 
-       hdata->dvi_mode = !drm_detect_hdmi_monitor(raw_edid);
+       hdata->dvi_mode = !drm_detect_hdmi_monitor(edid);
        DRM_DEBUG_KMS("%s : width[%d] x height[%d]\n",
                (hdata->dvi_mode ? "dvi monitor" : "hdmi monitor"),
-               raw_edid->width_cm, raw_edid->height_cm);
+               edid->width_cm, edid->height_cm);
 
-       return raw_edid;
+       drm_mode_connector_update_edid_property(connector, edid);
+
+       return drm_add_edid_modes(connector, edid);
 }
 
 static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
@@ -777,9 +868,10 @@ static int hdmi_find_phy_conf(struct hdmi_context *hdata, u32 pixel_clock)
        return -EINVAL;
 }
 
-static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
+static int hdmi_mode_valid(struct drm_connector *connector,
+                       struct drm_display_mode *mode)
 {
-       struct hdmi_context *hdata = ctx;
+       struct hdmi_context *hdata = ctx_from_connector(connector);
        int ret;
 
        DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d clock=%d\n",
@@ -787,12 +879,103 @@ static int hdmi_check_mode(void *ctx, struct drm_display_mode *mode)
                (mode->flags & DRM_MODE_FLAG_INTERLACE) ? true :
                false, mode->clock * 1000);
 
+       ret = mixer_check_mode(mode);
+       if (ret)
+               return MODE_BAD;
+
        ret = hdmi_find_phy_conf(hdata, mode->clock * 1000);
        if (ret < 0)
+               return MODE_BAD;
+
+       return MODE_OK;
+}
+
+static struct drm_encoder *hdmi_best_encoder(struct drm_connector *connector)
+{
+       struct hdmi_context *hdata = ctx_from_connector(connector);
+
+       return hdata->encoder;
+}
+
+static struct drm_connector_helper_funcs hdmi_connector_helper_funcs = {
+       .get_modes = hdmi_get_modes,
+       .mode_valid = hdmi_mode_valid,
+       .best_encoder = hdmi_best_encoder,
+};
+
+static int hdmi_create_connector(struct exynos_drm_display *display,
+                       struct drm_encoder *encoder)
+{
+       struct hdmi_context *hdata = display->ctx;
+       struct drm_connector *connector = &hdata->connector;
+       int ret;
+
+       hdata->encoder = encoder;
+       connector->interlace_allowed = true;
+       connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+       ret = drm_connector_init(hdata->drm_dev, connector,
+                       &hdmi_connector_funcs, DRM_MODE_CONNECTOR_HDMIA);
+       if (ret) {
+               DRM_ERROR("Failed to initialize connector with drm\n");
                return ret;
+       }
+
+       drm_connector_helper_add(connector, &hdmi_connector_helper_funcs);
+       drm_sysfs_connector_add(connector);
+       drm_mode_connector_attach_encoder(connector, encoder);
+
+       return 0;
+}
+
+static int hdmi_initialize(struct exynos_drm_display *display,
+                       struct drm_device *drm_dev)
+{
+       struct hdmi_context *hdata = display->ctx;
+
+       hdata->drm_dev = drm_dev;
+
        return 0;
 }
 
+static void hdmi_mode_fixup(struct exynos_drm_display *display,
+                               struct drm_connector *connector,
+                               const struct drm_display_mode *mode,
+                               struct drm_display_mode *adjusted_mode)
+{
+       struct drm_display_mode *m;
+       int mode_ok;
+
+       DRM_DEBUG_KMS("%s\n", __FILE__);
+
+       drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+       mode_ok = hdmi_mode_valid(connector, adjusted_mode);
+
+       /* just return if user desired mode exists. */
+       if (mode_ok == MODE_OK)
+               return;
+
+       /*
+        * otherwise, find the most suitable mode among modes and change it
+        * to adjusted_mode.
+        */
+       list_for_each_entry(m, &connector->modes, head) {
+               mode_ok = hdmi_mode_valid(connector, m);
+
+               if (mode_ok == MODE_OK) {
+                       DRM_INFO("desired mode doesn't exist so\n");
+                       DRM_INFO("use the most suitable mode among modes.\n");
+
+                       DRM_DEBUG_KMS("Adjusted Mode: [%d]x[%d] [%d]Hz\n",
+                               m->hdisplay, m->vdisplay, m->vrefresh);
+
+                       drm_mode_copy(adjusted_mode, m);
+                       break;
+               }
+       }
+}
+
 static void hdmi_set_acr(u32 freq, u8 *acr)
 {
        u32 n, cts;
@@ -1421,6 +1604,7 @@ static void hdmi_v13_mode_set(struct hdmi_context *hdata,
        hdata->mode_conf.cea_video_id =
                drm_match_cea_mode((struct drm_display_mode *)m);
        hdata->mode_conf.pixel_clock = m->clock * 1000;
+       hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
 
        hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
        hdmi_set_reg(core->h_v_line, 3, (m->htotal << 12) | m->vtotal);
@@ -1517,6 +1701,7 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
        hdata->mode_conf.cea_video_id =
                drm_match_cea_mode((struct drm_display_mode *)m);
        hdata->mode_conf.pixel_clock = m->clock * 1000;
+       hdata->mode_conf.aspect_ratio = m->picture_aspect_ratio;
 
        hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
        hdmi_set_reg(core->v_line, 2, m->vtotal);
@@ -1618,9 +1803,10 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
        hdmi_set_reg(tg->tg_3d, 1, 0x0);
 }
 
-static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
+static void hdmi_mode_set(struct exynos_drm_display *display,
+                       struct drm_display_mode *mode)
 {
-       struct hdmi_context *hdata = ctx;
+       struct hdmi_context *hdata = display->ctx;
        struct drm_display_mode *m = mode;
 
        DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%s\n",
@@ -1634,16 +1820,9 @@ static void hdmi_mode_set(void *ctx, struct drm_display_mode *mode)
                hdmi_v14_mode_set(hdata, mode);
 }
 
-static void hdmi_get_max_resol(void *ctx, unsigned int *width,
-                                       unsigned int *height)
-{
-       *width = MAX_WIDTH;
-       *height = MAX_HEIGHT;
-}
-
-static void hdmi_commit(void *ctx)
+static void hdmi_commit(struct exynos_drm_display *display)
 {
-       struct hdmi_context *hdata = ctx;
+       struct hdmi_context *hdata = display->ctx;
 
        mutex_lock(&hdata->hdmi_mutex);
        if (!hdata->powered) {
@@ -1655,8 +1834,9 @@ static void hdmi_commit(void *ctx)
        hdmi_conf_apply(hdata);
 }
 
-static void hdmi_poweron(struct hdmi_context *hdata)
+static void hdmi_poweron(struct exynos_drm_display *display)
 {
+       struct hdmi_context *hdata = display->ctx;
        struct hdmi_resources *res = &hdata->res;
 
        mutex_lock(&hdata->hdmi_mutex);
@@ -1669,6 +1849,8 @@ static void hdmi_poweron(struct hdmi_context *hdata)
 
        mutex_unlock(&hdata->hdmi_mutex);
 
+       pm_runtime_get_sync(hdata->dev);
+
        if (regulator_bulk_enable(res->regul_count, res->regul_bulk))
                DRM_DEBUG_KMS("failed to enable regulator bulk\n");
 
@@ -1677,10 +1859,12 @@ static void hdmi_poweron(struct hdmi_context *hdata)
        clk_prepare_enable(res->sclk_hdmi);
 
        hdmiphy_poweron(hdata);
+       hdmi_commit(display);
 }
 
-static void hdmi_poweroff(struct hdmi_context *hdata)
+static void hdmi_poweroff(struct exynos_drm_display *display)
 {
+       struct hdmi_context *hdata = display->ctx;
        struct hdmi_resources *res = &hdata->res;
 
        mutex_lock(&hdata->hdmi_mutex);
@@ -1700,30 +1884,27 @@ static void hdmi_poweroff(struct hdmi_context *hdata)
        clk_disable_unprepare(res->hdmiphy);
        regulator_bulk_disable(res->regul_count, res->regul_bulk);
 
-       mutex_lock(&hdata->hdmi_mutex);
+       pm_runtime_put_sync(hdata->dev);
 
+       mutex_lock(&hdata->hdmi_mutex);
        hdata->powered = false;
 
 out:
        mutex_unlock(&hdata->hdmi_mutex);
 }
 
-static void hdmi_dpms(void *ctx, int mode)
+static void hdmi_dpms(struct exynos_drm_display *display, int mode)
 {
-       struct hdmi_context *hdata = ctx;
-
        DRM_DEBUG_KMS("mode %d\n", mode);
 
        switch (mode) {
        case DRM_MODE_DPMS_ON:
-               if (pm_runtime_suspended(hdata->dev))
-                       pm_runtime_get_sync(hdata->dev);
+               hdmi_poweron(display);
                break;
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
        case DRM_MODE_DPMS_OFF:
-               if (!pm_runtime_suspended(hdata->dev))
-                       pm_runtime_put_sync(hdata->dev);
+               hdmi_poweroff(display);
                break;
        default:
                DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
@@ -1731,30 +1912,30 @@ static void hdmi_dpms(void *ctx, int mode)
        }
 }
 
-static struct exynos_hdmi_ops hdmi_ops = {
-       /* display */
-       .is_connected   = hdmi_is_connected,
-       .get_edid       = hdmi_get_edid,
-       .check_mode     = hdmi_check_mode,
-
-       /* manager */
+static struct exynos_drm_display_ops hdmi_display_ops = {
+       .initialize     = hdmi_initialize,
+       .create_connector = hdmi_create_connector,
+       .mode_fixup     = hdmi_mode_fixup,
        .mode_set       = hdmi_mode_set,
-       .get_max_resol  = hdmi_get_max_resol,
-       .commit         = hdmi_commit,
        .dpms           = hdmi_dpms,
+       .commit         = hdmi_commit,
+};
+
+static struct exynos_drm_display hdmi_display = {
+       .type = EXYNOS_DISPLAY_TYPE_HDMI,
+       .ops = &hdmi_display_ops,
 };
 
 static irqreturn_t hdmi_irq_thread(int irq, void *arg)
 {
-       struct exynos_drm_hdmi_context *ctx = arg;
-       struct hdmi_context *hdata = ctx->ctx;
+       struct hdmi_context *hdata = arg;
 
        mutex_lock(&hdata->hdmi_mutex);
        hdata->hpd = gpio_get_value(hdata->hpd_gpio);
        mutex_unlock(&hdata->hdmi_mutex);
 
-       if (ctx->drm_dev)
-               drm_helper_hpd_irq_event(ctx->drm_dev);
+       if (hdata->drm_dev)
+               drm_helper_hpd_irq_event(hdata->drm_dev);
 
        return IRQ_HANDLED;
 }
@@ -1830,20 +2011,6 @@ fail:
        return -ENODEV;
 }
 
-static struct i2c_client *hdmi_ddc, *hdmi_hdmiphy;
-
-void hdmi_attach_ddc_client(struct i2c_client *ddc)
-{
-       if (ddc)
-               hdmi_ddc = ddc;
-}
-
-void hdmi_attach_hdmiphy_client(struct i2c_client *hdmiphy)
-{
-       if (hdmiphy)
-               hdmi_hdmiphy = hdmiphy;
-}
-
 static struct s5p_hdmi_platform_data *drm_hdmi_dt_parse_pdata
                                        (struct device *dev)
 {
@@ -1871,10 +2038,10 @@ err_data:
 static struct of_device_id hdmi_match_types[] = {
        {
                .compatible = "samsung,exynos5-hdmi",
-               .data   = (void *)HDMI_TYPE14,
+               .data = &exynos5_hdmi_driver_data,
        }, {
                .compatible = "samsung,exynos4212-hdmi",
-               .data   = (void *)HDMI_TYPE14,
+               .data = &exynos4212_hdmi_driver_data,
        }, {
                /* end node */
        }
@@ -1883,11 +2050,12 @@ static struct of_device_id hdmi_match_types[] = {
 static int hdmi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx;
        struct hdmi_context *hdata;
        struct s5p_hdmi_platform_data *pdata;
        struct resource *res;
        const struct of_device_id *match;
+       struct device_node *ddc_node, *phy_node;
+       struct hdmi_driver_data *drv_data;
        int ret;
 
         if (!dev->of_node)
@@ -1897,25 +2065,20 @@ static int hdmi_probe(struct platform_device *pdev)
        if (!pdata)
                return -EINVAL;
 
-       drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx), GFP_KERNEL);
-       if (!drm_hdmi_ctx)
-               return -ENOMEM;
-
        hdata = devm_kzalloc(dev, sizeof(struct hdmi_context), GFP_KERNEL);
        if (!hdata)
                return -ENOMEM;
 
        mutex_init(&hdata->hdmi_mutex);
 
-       drm_hdmi_ctx->ctx = (void *)hdata;
-       hdata->parent_ctx = (void *)drm_hdmi_ctx;
-
-       platform_set_drvdata(pdev, drm_hdmi_ctx);
+       platform_set_drvdata(pdev, &hdmi_display);
 
        match = of_match_node(hdmi_match_types, dev->of_node);
        if (!match)
                return -ENODEV;
-       hdata->type = (enum hdmi_type)match->data;
+
+       drv_data = (struct hdmi_driver_data *)match->data;
+       hdata->type = drv_data->type;
 
        hdata->hpd_gpio = pdata->hpd_gpio;
        hdata->dev = dev;
@@ -1938,21 +2101,34 @@ static int hdmi_probe(struct platform_device *pdev)
        }
 
        /* DDC i2c driver */
-       if (i2c_add_driver(&ddc_driver)) {
-               DRM_ERROR("failed to register ddc i2c driver\n");
-               return -ENOENT;
+       ddc_node = of_parse_phandle(dev->of_node, "ddc", 0);
+       if (!ddc_node) {
+               DRM_ERROR("Failed to find ddc node in device tree\n");
+               return -ENODEV;
+       }
+       hdata->ddc_adpt = of_find_i2c_adapter_by_node(ddc_node);
+       if (!hdata->ddc_adpt) {
+               DRM_ERROR("Failed to get ddc i2c adapter by node\n");
+               return -ENODEV;
        }
 
-       hdata->ddc_port = hdmi_ddc;
+       /* Not support APB PHY yet. */
+       if (drv_data->is_apb_phy)
+               return -EPERM;
 
        /* hdmiphy i2c driver */
-       if (i2c_add_driver(&hdmiphy_driver)) {
-               DRM_ERROR("failed to register hdmiphy i2c driver\n");
-               ret = -ENOENT;
+       phy_node = of_parse_phandle(dev->of_node, "phy", 0);
+       if (!phy_node) {
+               DRM_ERROR("Failed to find hdmiphy node in device tree\n");
+               ret = -ENODEV;
+               goto err_ddc;
+       }
+       hdata->hdmiphy_port = of_find_i2c_device_by_node(phy_node);
+       if (!hdata->hdmiphy_port) {
+               DRM_ERROR("Failed to get hdmi phy i2c client from node\n");
+               ret = -ENODEV;
                goto err_ddc;
        }
-
-       hdata->hdmiphy_port = hdmi_hdmiphy;
 
        hdata->irq = gpio_to_irq(hdata->hpd_gpio);
        if (hdata->irq < 0) {
@@ -1966,119 +2142,45 @@ static int hdmi_probe(struct platform_device *pdev)
        ret = devm_request_threaded_irq(dev, hdata->irq, NULL,
                        hdmi_irq_thread, IRQF_TRIGGER_RISING |
                        IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                       "hdmi", drm_hdmi_ctx);
+                       "hdmi", hdata);
        if (ret) {
                DRM_ERROR("failed to register hdmi interrupt\n");
                goto err_hdmiphy;
        }
 
-       /* Attach HDMI Driver to common hdmi. */
-       exynos_hdmi_drv_attach(drm_hdmi_ctx);
-
-       /* register specific callbacks to common hdmi. */
-       exynos_hdmi_ops_register(&hdmi_ops);
-
        pm_runtime_enable(dev);
 
+       hdmi_display.ctx = hdata;
+       exynos_drm_display_register(&hdmi_display);
+
        return 0;
 
 err_hdmiphy:
-       i2c_del_driver(&hdmiphy_driver);
+       put_device(&hdata->hdmiphy_port->dev);
 err_ddc:
-       i2c_del_driver(&ddc_driver);
+       put_device(&hdata->ddc_adpt->dev);
        return ret;
 }
 
 static int hdmi_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
+       struct exynos_drm_display *display = get_hdmi_display(dev);
+       struct hdmi_context *hdata = display->ctx;
 
-       pm_runtime_disable(dev);
-
-       /* hdmiphy i2c driver */
-       i2c_del_driver(&hdmiphy_driver);
-       /* DDC i2c driver */
-       i2c_del_driver(&ddc_driver);
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int hdmi_suspend(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-       struct hdmi_context *hdata = ctx->ctx;
-
-       disable_irq(hdata->irq);
-
-       hdata->hpd = false;
-       if (ctx->drm_dev)
-               drm_helper_hpd_irq_event(ctx->drm_dev);
-
-       if (pm_runtime_suspended(dev)) {
-               DRM_DEBUG_KMS("Already suspended\n");
-               return 0;
-       }
-
-       hdmi_poweroff(hdata);
+       put_device(&hdata->hdmiphy_port->dev);
+       put_device(&hdata->ddc_adpt->dev);
+       pm_runtime_disable(&pdev->dev);
 
        return 0;
 }
 
-static int hdmi_resume(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-       struct hdmi_context *hdata = ctx->ctx;
-
-       hdata->hpd = gpio_get_value(hdata->hpd_gpio);
-
-       enable_irq(hdata->irq);
-
-       if (!pm_runtime_suspended(dev)) {
-               DRM_DEBUG_KMS("Already resumed\n");
-               return 0;
-       }
-
-       hdmi_poweron(hdata);
-
-       return 0;
-}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-static int hdmi_runtime_suspend(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-       struct hdmi_context *hdata = ctx->ctx;
-
-       hdmi_poweroff(hdata);
-
-       return 0;
-}
-
-static int hdmi_runtime_resume(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *ctx = get_hdmi_context(dev);
-       struct hdmi_context *hdata = ctx->ctx;
-
-       hdmi_poweron(hdata);
-
-       return 0;
-}
-#endif
-
-static const struct dev_pm_ops hdmi_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(hdmi_suspend, hdmi_resume)
-       SET_RUNTIME_PM_OPS(hdmi_runtime_suspend, hdmi_runtime_resume, NULL)
-};
-
 struct platform_driver hdmi_driver = {
        .probe          = hdmi_probe,
        .remove         = hdmi_remove,
        .driver         = {
                .name   = "exynos-hdmi",
                .owner  = THIS_MODULE,
-               .pm     = &hdmi_pm_ops,
                .of_match_table = hdmi_match_types,
        },
 };
index 2dfa48c..ce28881 100644 (file)
 
 #include "exynos_drm_drv.h"
 #include "exynos_drm_crtc.h"
-#include "exynos_drm_hdmi.h"
 #include "exynos_drm_iommu.h"
+#include "exynos_mixer.h"
 
-#define get_mixer_context(dev) platform_get_drvdata(to_platform_device(dev))
+#define get_mixer_manager(dev) platform_get_drvdata(to_platform_device(dev))
+
+#define MIXER_WIN_NR           3
+#define MIXER_DEFAULT_WIN      0
 
 struct hdmi_win_data {
        dma_addr_t              dma_addr;
@@ -82,6 +85,7 @@ enum mixer_version_id {
 };
 
 struct mixer_context {
+       struct platform_device *pdev;
        struct device           *dev;
        struct drm_device       *drm_dev;
        int                     pipe;
@@ -94,7 +98,6 @@ struct mixer_context {
        struct mixer_resources  mixer_res;
        struct hdmi_win_data    win_data[MIXER_WIN_NR];
        enum mixer_version_id   mxr_ver;
-       void                    *parent_ctx;
        wait_queue_head_t       wait_vsync_queue;
        atomic_t                wait_vsync_event;
 };
@@ -685,31 +688,196 @@ static void mixer_win_reset(struct mixer_context *ctx)
        spin_unlock_irqrestore(&res->reg_slock, flags);
 }
 
-static int mixer_iommu_on(void *ctx, bool enable)
+static irqreturn_t mixer_irq_handler(int irq, void *arg)
+{
+       struct mixer_context *ctx = arg;
+       struct mixer_resources *res = &ctx->mixer_res;
+       u32 val, base, shadow;
+
+       spin_lock(&res->reg_slock);
+
+       /* read interrupt status for handling and clearing flags for VSYNC */
+       val = mixer_reg_read(res, MXR_INT_STATUS);
+
+       /* handling VSYNC */
+       if (val & MXR_INT_STATUS_VSYNC) {
+               /* interlace scan need to check shadow register */
+               if (ctx->interlace) {
+                       base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
+                       shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
+                       if (base != shadow)
+                               goto out;
+
+                       base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
+                       shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
+                       if (base != shadow)
+                               goto out;
+               }
+
+               drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+               exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+
+               /* set wait vsync event to zero and wake up queue. */
+               if (atomic_read(&ctx->wait_vsync_event)) {
+                       atomic_set(&ctx->wait_vsync_event, 0);
+                       wake_up(&ctx->wait_vsync_queue);
+               }
+       }
+
+out:
+       /* clear interrupts */
+       if (~val & MXR_INT_EN_VSYNC) {
+               /* vsync interrupt use different bit for read and clear */
+               val &= ~MXR_INT_EN_VSYNC;
+               val |= MXR_INT_CLEAR_VSYNC;
+       }
+       mixer_reg_write(res, MXR_INT_STATUS, val);
+
+       spin_unlock(&res->reg_slock);
+
+       return IRQ_HANDLED;
+}
+
+static int mixer_resources_init(struct mixer_context *mixer_ctx)
 {
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx;
-       struct mixer_context *mdata = ctx;
-       struct drm_device *drm_dev;
+       struct device *dev = &mixer_ctx->pdev->dev;
+       struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
+       struct resource *res;
+       int ret;
 
-       drm_hdmi_ctx = mdata->parent_ctx;
-       drm_dev = drm_hdmi_ctx->drm_dev;
+       spin_lock_init(&mixer_res->reg_slock);
 
-       if (is_drm_iommu_supported(drm_dev)) {
-               if (enable)
-                       return drm_iommu_attach_device(drm_dev, mdata->dev);
+       mixer_res->mixer = devm_clk_get(dev, "mixer");
+       if (IS_ERR(mixer_res->mixer)) {
+               dev_err(dev, "failed to get clock 'mixer'\n");
+               return -ENODEV;
+       }
 
-               drm_iommu_detach_device(drm_dev, mdata->dev);
+       mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
+       if (IS_ERR(mixer_res->sclk_hdmi)) {
+               dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
+               return -ENODEV;
+       }
+       res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               return -ENXIO;
        }
+
+       mixer_res->mixer_regs = devm_ioremap(dev, res->start,
+                                                       resource_size(res));
+       if (mixer_res->mixer_regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               return -ENXIO;
+       }
+
+       res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(dev, "get interrupt resource failed.\n");
+               return -ENXIO;
+       }
+
+       ret = devm_request_irq(dev, res->start, mixer_irq_handler,
+                                               0, "drm_mixer", mixer_ctx);
+       if (ret) {
+               dev_err(dev, "request interrupt failed.\n");
+               return ret;
+       }
+       mixer_res->irq = res->start;
+
        return 0;
 }
 
-static int mixer_enable_vblank(void *ctx, int pipe)
+static int vp_resources_init(struct mixer_context *mixer_ctx)
 {
-       struct mixer_context *mixer_ctx = ctx;
-       struct mixer_resources *res = &mixer_ctx->mixer_res;
+       struct device *dev = &mixer_ctx->pdev->dev;
+       struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
+       struct resource *res;
+
+       mixer_res->vp = devm_clk_get(dev, "vp");
+       if (IS_ERR(mixer_res->vp)) {
+               dev_err(dev, "failed to get clock 'vp'\n");
+               return -ENODEV;
+       }
+       mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
+       if (IS_ERR(mixer_res->sclk_mixer)) {
+               dev_err(dev, "failed to get clock 'sclk_mixer'\n");
+               return -ENODEV;
+       }
+       mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
+       if (IS_ERR(mixer_res->sclk_dac)) {
+               dev_err(dev, "failed to get clock 'sclk_dac'\n");
+               return -ENODEV;
+       }
+
+       if (mixer_res->sclk_hdmi)
+               clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
+
+       res = platform_get_resource(mixer_ctx->pdev, IORESOURCE_MEM, 1);
+       if (res == NULL) {
+               dev_err(dev, "get memory resource failed.\n");
+               return -ENXIO;
+       }
 
+       mixer_res->vp_regs = devm_ioremap(dev, res->start,
+                                                       resource_size(res));
+       if (mixer_res->vp_regs == NULL) {
+               dev_err(dev, "register mapping failed.\n");
+               return -ENXIO;
+       }
+
+       return 0;
+}
+
+static int mixer_initialize(struct exynos_drm_manager *mgr,
+                       struct drm_device *drm_dev, int pipe)
+{
+       int ret;
+       struct mixer_context *mixer_ctx = mgr->ctx;
+
+       mixer_ctx->drm_dev = drm_dev;
        mixer_ctx->pipe = pipe;
 
+       /* acquire resources: regs, irqs, clocks */
+       ret = mixer_resources_init(mixer_ctx);
+       if (ret) {
+               DRM_ERROR("mixer_resources_init failed ret=%d\n", ret);
+               return ret;
+       }
+
+       if (mixer_ctx->vp_enabled) {
+               /* acquire vp resources: regs, irqs, clocks */
+               ret = vp_resources_init(mixer_ctx);
+               if (ret) {
+                       DRM_ERROR("vp_resources_init failed ret=%d\n", ret);
+                       return ret;
+               }
+       }
+
+       if (!is_drm_iommu_supported(mixer_ctx->drm_dev))
+               return 0;
+
+       return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
+}
+
+static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
+{
+       struct mixer_context *mixer_ctx = mgr->ctx;
+
+       if (is_drm_iommu_supported(mixer_ctx->drm_dev))
+               drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
+}
+
+static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
+{
+       struct mixer_context *mixer_ctx = mgr->ctx;
+       struct mixer_resources *res = &mixer_ctx->mixer_res;
+
+       if (!mixer_ctx->powered) {
+               mixer_ctx->int_en |= MXR_INT_EN_VSYNC;
+               return 0;
+       }
+
        /* enable vsync interrupt */
        mixer_reg_writemask(res, MXR_INT_EN, MXR_INT_EN_VSYNC,
                        MXR_INT_EN_VSYNC);
@@ -717,19 +885,19 @@ static int mixer_enable_vblank(void *ctx, int pipe)
        return 0;
 }
 
-static void mixer_disable_vblank(void *ctx)
+static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *mixer_ctx = ctx;
+       struct mixer_context *mixer_ctx = mgr->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
 
        /* disable vsync interrupt */
        mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
 }
 
-static void mixer_win_mode_set(void *ctx,
-                             struct exynos_drm_overlay *overlay)
+static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
+                       struct exynos_drm_overlay *overlay)
 {
-       struct mixer_context *mixer_ctx = ctx;
+       struct mixer_context *mixer_ctx = mgr->ctx;
        struct hdmi_win_data *win_data;
        int win;
 
@@ -778,9 +946,10 @@ static void mixer_win_mode_set(void *ctx,
        win_data->scan_flags = overlay->scan_flag;
 }
 
-static void mixer_win_commit(void *ctx, int win)
+static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct mixer_context *mixer_ctx = ctx;
+       struct mixer_context *mixer_ctx = mgr->ctx;
+       int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
 
        DRM_DEBUG_KMS("win: %d\n", win);
 
@@ -799,10 +968,11 @@ static void mixer_win_commit(void *ctx, int win)
        mixer_ctx->win_data[win].enabled = true;
 }
 
-static void mixer_win_disable(void *ctx, int win)
+static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
 {
-       struct mixer_context *mixer_ctx = ctx;
+       struct mixer_context *mixer_ctx = mgr->ctx;
        struct mixer_resources *res = &mixer_ctx->mixer_res;
+       int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
        unsigned long flags;
 
        DRM_DEBUG_KMS("win: %d\n", win);
@@ -826,32 +996,9 @@ static void mixer_win_disable(void *ctx, int win)
        mixer_ctx->win_data[win].enabled = false;
 }
 
-static int mixer_check_mode(void *ctx, struct drm_display_mode *mode)
+static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
 {
-       struct mixer_context *mixer_ctx = ctx;
-       u32 w, h;
-
-       w = mode->hdisplay;
-       h = mode->vdisplay;
-
-       DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
-               mode->hdisplay, mode->vdisplay, mode->vrefresh,
-               (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
-
-       if (mixer_ctx->mxr_ver == MXR_VER_0_0_0_16 ||
-               mixer_ctx->mxr_ver == MXR_VER_128_0_0_184)
-               return 0;
-
-       if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
-               (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
-               (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
-               return 0;
-
-       return -EINVAL;
-}
-static void mixer_wait_for_vblank(void *ctx)
-{
-       struct mixer_context *mixer_ctx = ctx;
+       struct mixer_context *mixer_ctx = mgr->ctx;
 
        mutex_lock(&mixer_ctx->mixer_mutex);
        if (!mixer_ctx->powered) {
@@ -872,21 +1019,23 @@ static void mixer_wait_for_vblank(void *ctx)
                DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
-static void mixer_window_suspend(struct mixer_context *ctx)
+static void mixer_window_suspend(struct exynos_drm_manager *mgr)
 {
+       struct mixer_context *ctx = mgr->ctx;
        struct hdmi_win_data *win_data;
        int i;
 
        for (i = 0; i < MIXER_WIN_NR; i++) {
                win_data = &ctx->win_data[i];
                win_data->resume = win_data->enabled;
-               mixer_win_disable(ctx, i);
+               mixer_win_disable(mgr, i);
        }
-       mixer_wait_for_vblank(ctx);
+       mixer_wait_for_vblank(mgr);
 }
 
-static void mixer_window_resume(struct mixer_context *ctx)
+static void mixer_window_resume(struct exynos_drm_manager *mgr)
 {
+       struct mixer_context *ctx = mgr->ctx;
        struct hdmi_win_data *win_data;
        int i;
 
@@ -894,11 +1043,14 @@ static void mixer_window_resume(struct mixer_context *ctx)
                win_data = &ctx->win_data[i];
                win_data->enabled = win_data->resume;
                win_data->resume = false;
+               if (win_data->enabled)
+                       mixer_win_commit(mgr, i);
        }
 }
 
-static void mixer_poweron(struct mixer_context *ctx)
+static void mixer_poweron(struct exynos_drm_manager *mgr)
 {
+       struct mixer_context *ctx = mgr->ctx;
        struct mixer_resources *res = &ctx->mixer_res;
 
        mutex_lock(&ctx->mixer_mutex);
@@ -909,6 +1061,8 @@ static void mixer_poweron(struct mixer_context *ctx)
        ctx->powered = true;
        mutex_unlock(&ctx->mixer_mutex);
 
+       pm_runtime_get_sync(ctx->dev);
+
        clk_prepare_enable(res->mixer);
        if (ctx->vp_enabled) {
                clk_prepare_enable(res->vp);
@@ -918,11 +1072,12 @@ static void mixer_poweron(struct mixer_context *ctx)
        mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
        mixer_win_reset(ctx);
 
-       mixer_window_resume(ctx);
+       mixer_window_resume(mgr);
 }
 
-static void mixer_poweroff(struct mixer_context *ctx)
+static void mixer_poweroff(struct exynos_drm_manager *mgr)
 {
+       struct mixer_context *ctx = mgr->ctx;
        struct mixer_resources *res = &ctx->mixer_res;
 
        mutex_lock(&ctx->mixer_mutex);
@@ -930,7 +1085,7 @@ static void mixer_poweroff(struct mixer_context *ctx)
                goto out;
        mutex_unlock(&ctx->mixer_mutex);
 
-       mixer_window_suspend(ctx);
+       mixer_window_suspend(mgr);
 
        ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
 
@@ -940,6 +1095,8 @@ static void mixer_poweroff(struct mixer_context *ctx)
                clk_disable_unprepare(res->sclk_mixer);
        }
 
+       pm_runtime_put_sync(ctx->dev);
+
        mutex_lock(&ctx->mixer_mutex);
        ctx->powered = false;
 
@@ -947,20 +1104,16 @@ out:
        mutex_unlock(&ctx->mixer_mutex);
 }
 
-static void mixer_dpms(void *ctx, int mode)
+static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
 {
-       struct mixer_context *mixer_ctx = ctx;
-
        switch (mode) {
        case DRM_MODE_DPMS_ON:
-               if (pm_runtime_suspended(mixer_ctx->dev))
-                       pm_runtime_get_sync(mixer_ctx->dev);
+               mixer_poweron(mgr);
                break;
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
        case DRM_MODE_DPMS_OFF:
-               if (!pm_runtime_suspended(mixer_ctx->dev))
-                       pm_runtime_put_sync(mixer_ctx->dev);
+               mixer_poweroff(mgr);
                break;
        default:
                DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
@@ -968,169 +1121,42 @@ static void mixer_dpms(void *ctx, int mode)
        }
 }
 
-static struct exynos_mixer_ops mixer_ops = {
-       /* manager */
-       .iommu_on               = mixer_iommu_on,
-       .enable_vblank          = mixer_enable_vblank,
-       .disable_vblank         = mixer_disable_vblank,
-       .wait_for_vblank        = mixer_wait_for_vblank,
-       .dpms                   = mixer_dpms,
-
-       /* overlay */
-       .win_mode_set           = mixer_win_mode_set,
-       .win_commit             = mixer_win_commit,
-       .win_disable            = mixer_win_disable,
-
-       /* display */
-       .check_mode             = mixer_check_mode,
-};
-
-static irqreturn_t mixer_irq_handler(int irq, void *arg)
-{
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx = arg;
-       struct mixer_context *ctx = drm_hdmi_ctx->ctx;
-       struct mixer_resources *res = &ctx->mixer_res;
-       u32 val, base, shadow;
-
-       spin_lock(&res->reg_slock);
-
-       /* read interrupt status for handling and clearing flags for VSYNC */
-       val = mixer_reg_read(res, MXR_INT_STATUS);
-
-       /* handling VSYNC */
-       if (val & MXR_INT_STATUS_VSYNC) {
-               /* interlace scan need to check shadow register */
-               if (ctx->interlace) {
-                       base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
-                       shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
-                       if (base != shadow)
-                               goto out;
-
-                       base = mixer_reg_read(res, MXR_GRAPHIC_BASE(1));
-                       shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(1));
-                       if (base != shadow)
-                               goto out;
-               }
-
-               drm_handle_vblank(drm_hdmi_ctx->drm_dev, ctx->pipe);
-               exynos_drm_crtc_finish_pageflip(drm_hdmi_ctx->drm_dev,
-                               ctx->pipe);
-
-               /* set wait vsync event to zero and wake up queue. */
-               if (atomic_read(&ctx->wait_vsync_event)) {
-                       atomic_set(&ctx->wait_vsync_event, 0);
-                       wake_up(&ctx->wait_vsync_queue);
-               }
-       }
-
-out:
-       /* clear interrupts */
-       if (~val & MXR_INT_EN_VSYNC) {
-               /* vsync interrupt use different bit for read and clear */
-               val &= ~MXR_INT_EN_VSYNC;
-               val |= MXR_INT_CLEAR_VSYNC;
-       }
-       mixer_reg_write(res, MXR_INT_STATUS, val);
-
-       spin_unlock(&res->reg_slock);
-
-       return IRQ_HANDLED;
-}
-
-static int mixer_resources_init(struct exynos_drm_hdmi_context *ctx,
-                               struct platform_device *pdev)
+/* Only valid for Mixer version 16.0.33.0 */
+int mixer_check_mode(struct drm_display_mode *mode)
 {
-       struct mixer_context *mixer_ctx = ctx->ctx;
-       struct device *dev = &pdev->dev;
-       struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
-       struct resource *res;
-       int ret;
-
-       spin_lock_init(&mixer_res->reg_slock);
-
-       mixer_res->mixer = devm_clk_get(dev, "mixer");
-       if (IS_ERR(mixer_res->mixer)) {
-               dev_err(dev, "failed to get clock 'mixer'\n");
-               return -ENODEV;
-       }
-
-       mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
-       if (IS_ERR(mixer_res->sclk_hdmi)) {
-               dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
-               return -ENODEV;
-       }
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               dev_err(dev, "get memory resource failed.\n");
-               return -ENXIO;
-       }
+       u32 w, h;
 
-       mixer_res->mixer_regs = devm_ioremap(dev, res->start,
-                                                       resource_size(res));
-       if (mixer_res->mixer_regs == NULL) {
-               dev_err(dev, "register mapping failed.\n");
-               return -ENXIO;
-       }
+       w = mode->hdisplay;
+       h = mode->vdisplay;
 
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (res == NULL) {
-               dev_err(dev, "get interrupt resource failed.\n");
-               return -ENXIO;
-       }
+       DRM_DEBUG_KMS("xres=%d, yres=%d, refresh=%d, intl=%d\n",
+               mode->hdisplay, mode->vdisplay, mode->vrefresh,
+               (mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
 
-       ret = devm_request_irq(dev, res->start, mixer_irq_handler,
-                                                       0, "drm_mixer", ctx);
-       if (ret) {
-               dev_err(dev, "request interrupt failed.\n");
-               return ret;
-       }
-       mixer_res->irq = res->start;
+       if ((w >= 464 && w <= 720 && h >= 261 && h <= 576) ||
+               (w >= 1024 && w <= 1280 && h >= 576 && h <= 720) ||
+               (w >= 1664 && w <= 1920 && h >= 936 && h <= 1080))
+               return 0;
 
-       return 0;
+       return -EINVAL;
 }
 
-static int vp_resources_init(struct exynos_drm_hdmi_context *ctx,
-                            struct platform_device *pdev)
-{
-       struct mixer_context *mixer_ctx = ctx->ctx;
-       struct device *dev = &pdev->dev;
-       struct mixer_resources *mixer_res = &mixer_ctx->mixer_res;
-       struct resource *res;
-
-       mixer_res->vp = devm_clk_get(dev, "vp");
-       if (IS_ERR(mixer_res->vp)) {
-               dev_err(dev, "failed to get clock 'vp'\n");
-               return -ENODEV;
-       }
-       mixer_res->sclk_mixer = devm_clk_get(dev, "sclk_mixer");
-       if (IS_ERR(mixer_res->sclk_mixer)) {
-               dev_err(dev, "failed to get clock 'sclk_mixer'\n");
-               return -ENODEV;
-       }
-       mixer_res->sclk_dac = devm_clk_get(dev, "sclk_dac");
-       if (IS_ERR(mixer_res->sclk_dac)) {
-               dev_err(dev, "failed to get clock 'sclk_dac'\n");
-               return -ENODEV;
-       }
-
-       if (mixer_res->sclk_hdmi)
-               clk_set_parent(mixer_res->sclk_mixer, mixer_res->sclk_hdmi);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
-       if (res == NULL) {
-               dev_err(dev, "get memory resource failed.\n");
-               return -ENXIO;
-       }
-
-       mixer_res->vp_regs = devm_ioremap(dev, res->start,
-                                                       resource_size(res));
-       if (mixer_res->vp_regs == NULL) {
-               dev_err(dev, "register mapping failed.\n");
-               return -ENXIO;
-       }
+static struct exynos_drm_manager_ops mixer_manager_ops = {
+       .initialize             = mixer_initialize,
+       .remove                 = mixer_mgr_remove,
+       .dpms                   = mixer_dpms,
+       .enable_vblank          = mixer_enable_vblank,
+       .disable_vblank         = mixer_disable_vblank,
+       .wait_for_vblank        = mixer_wait_for_vblank,
+       .win_mode_set           = mixer_win_mode_set,
+       .win_commit             = mixer_win_commit,
+       .win_disable            = mixer_win_disable,
+};
 
-       return 0;
-}
+static struct exynos_drm_manager mixer_manager = {
+       .type                   = EXYNOS_DISPLAY_TYPE_HDMI,
+       .ops                    = &mixer_manager_ops,
+};
 
 static struct mixer_drv_data exynos5420_mxr_drv_data = {
        .version = MXR_VER_128_0_0_184,
@@ -1177,21 +1203,16 @@ static struct of_device_id mixer_match_types[] = {
 static int mixer_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx;
        struct mixer_context *ctx;
        struct mixer_drv_data *drv;
-       int ret;
 
        dev_info(dev, "probe start\n");
 
-       drm_hdmi_ctx = devm_kzalloc(dev, sizeof(*drm_hdmi_ctx),
-                                                               GFP_KERNEL);
-       if (!drm_hdmi_ctx)
-               return -ENOMEM;
-
-       ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
-       if (!ctx)
+       ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx) {
+               DRM_ERROR("failed to alloc mixer context.\n");
                return -ENOMEM;
+       }
 
        mutex_init(&ctx->mixer_mutex);
 
@@ -1204,46 +1225,20 @@ static int mixer_probe(struct platform_device *pdev)
                        platform_get_device_id(pdev)->driver_data;
        }
 
+       ctx->pdev = pdev;
        ctx->dev = dev;
-       ctx->parent_ctx = (void *)drm_hdmi_ctx;
-       drm_hdmi_ctx->ctx = (void *)ctx;
        ctx->vp_enabled = drv->is_vp_enabled;
        ctx->mxr_ver = drv->version;
        init_waitqueue_head(&ctx->wait_vsync_queue);
        atomic_set(&ctx->wait_vsync_event, 0);
 
-       platform_set_drvdata(pdev, drm_hdmi_ctx);
-
-       /* acquire resources: regs, irqs, clocks */
-       ret = mixer_resources_init(drm_hdmi_ctx, pdev);
-       if (ret) {
-               DRM_ERROR("mixer_resources_init failed\n");
-               goto fail;
-       }
-
-       if (ctx->vp_enabled) {
-               /* acquire vp resources: regs, irqs, clocks */
-               ret = vp_resources_init(drm_hdmi_ctx, pdev);
-               if (ret) {
-                       DRM_ERROR("vp_resources_init failed\n");
-                       goto fail;
-               }
-       }
-
-       /* attach mixer driver to common hdmi. */
-       exynos_mixer_drv_attach(drm_hdmi_ctx);
-
-       /* register specific callback point to common hdmi. */
-       exynos_mixer_ops_register(&mixer_ops);
+       mixer_manager.ctx = ctx;
+       platform_set_drvdata(pdev, &mixer_manager);
+       exynos_drm_manager_register(&mixer_manager);
 
        pm_runtime_enable(dev);
 
        return 0;
-
-
-fail:
-       dev_info(dev, "probe failed\n");
-       return ret;
 }
 
 static int mixer_remove(struct platform_device *pdev)
@@ -1255,70 +1250,10 @@ static int mixer_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int mixer_suspend(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-       struct mixer_context *ctx = drm_hdmi_ctx->ctx;
-
-       if (pm_runtime_suspended(dev)) {
-               DRM_DEBUG_KMS("Already suspended\n");
-               return 0;
-       }
-
-       mixer_poweroff(ctx);
-
-       return 0;
-}
-
-static int mixer_resume(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-       struct mixer_context *ctx = drm_hdmi_ctx->ctx;
-
-       if (!pm_runtime_suspended(dev)) {
-               DRM_DEBUG_KMS("Already resumed\n");
-               return 0;
-       }
-
-       mixer_poweron(ctx);
-
-       return 0;
-}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-static int mixer_runtime_suspend(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-       struct mixer_context *ctx = drm_hdmi_ctx->ctx;
-
-       mixer_poweroff(ctx);
-
-       return 0;
-}
-
-static int mixer_runtime_resume(struct device *dev)
-{
-       struct exynos_drm_hdmi_context *drm_hdmi_ctx = get_mixer_context(dev);
-       struct mixer_context *ctx = drm_hdmi_ctx->ctx;
-
-       mixer_poweron(ctx);
-
-       return 0;
-}
-#endif
-
-static const struct dev_pm_ops mixer_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(mixer_suspend, mixer_resume)
-       SET_RUNTIME_PM_OPS(mixer_runtime_suspend, mixer_runtime_resume, NULL)
-};
-
 struct platform_driver mixer_driver = {
        .driver = {
                .name = "exynos-mixer",
                .owner = THIS_MODULE,
-               .pm = &mixer_pm_ops,
                .of_match_table = mixer_match_types,
        },
        .probe = mixer_probe,
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.h b/drivers/gpu/drm/exynos/exynos_mixer.h
new file mode 100644 (file)
index 0000000..3811e41
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _EXYNOS_MIXER_H_
+#define _EXYNOS_MIXER_H_
+
+/* This function returns 0 if the given timing is valid for the mixer */
+int mixer_check_mode(struct drm_display_mode *mode);
+
+#endif
index e9064dd..b153155 100644 (file)
@@ -13,9 +13,11 @@ gma500_gfx-y += \
          intel_i2c.o \
          intel_gmbus.o \
          mmu.o \
+         blitter.o \
          power.o \
          psb_drv.o \
          gma_display.o \
+         gma_device.o \
          psb_intel_display.o \
          psb_intel_lvds.o \
          psb_intel_modes.o \
diff --git a/drivers/gpu/drm/gma500/blitter.c b/drivers/gpu/drm/gma500/blitter.c
new file mode 100644 (file)
index 0000000..9cd54a6
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, Patrik Jakobsson
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * Authors: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
+ */
+
+#include "psb_drv.h"
+
+#include "blitter.h"
+#include "psb_reg.h"
+
+/* Wait for the blitter to be completely idle */
+int gma_blt_wait_idle(struct drm_psb_private *dev_priv)
+{
+       unsigned long stop = jiffies + HZ;
+       int busy = 1;
+
+       /* NOP for Cedarview */
+       if (IS_CDV(dev_priv->dev))
+               return 0;
+
+       /* First do a quick check */
+       if ((PSB_RSGX32(PSB_CR_2D_SOCIF) == _PSB_C2_SOCIF_EMPTY) &&
+           ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) & _PSB_C2B_STATUS_BUSY) == 0))
+               return 0;
+
+       do {
+               busy = (PSB_RSGX32(PSB_CR_2D_SOCIF) != _PSB_C2_SOCIF_EMPTY);
+       } while (busy && !time_after_eq(jiffies, stop));
+
+       if (busy)
+               return -EBUSY;
+
+       do {
+               busy = ((PSB_RSGX32(PSB_CR_2D_BLIT_STATUS) &
+                       _PSB_C2B_STATUS_BUSY) != 0);
+       } while (busy && !time_after_eq(jiffies, stop));
+
+       /* If still busy, we probably have a hang */
+       return (busy) ? -EBUSY : 0;
+}
diff --git a/drivers/gpu/drm/gma500/blitter.h b/drivers/gpu/drm/gma500/blitter.h
new file mode 100644 (file)
index 0000000..b83648d
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2014, Patrik Jakobsson
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * Authors: Patrik Jakobsson <patrik.r.jakobsson@gmail.com>
+ */
+
+#ifndef __BLITTER_H
+#define __BLITTER_H
+
+extern int gma_blt_wait_idle(struct drm_psb_private *dev_priv);
+
+#endif
index 5a9a6a3..3531f90 100644 (file)
@@ -26,6 +26,7 @@
 #include "psb_intel_reg.h"
 #include "intel_bios.h"
 #include "cdv_device.h"
+#include "gma_device.h"
 
 #define VGA_SR_INDEX           0x3c4
 #define VGA_SR_DATA            0x3c5
@@ -426,43 +427,6 @@ static int cdv_power_up(struct drm_device *dev)
        return 0;
 }
 
-/* FIXME ? - shared with Poulsbo */
-static void cdv_get_core_freq(struct drm_device *dev)
-{
-       uint32_t clock;
-       struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
-       struct drm_psb_private *dev_priv = dev->dev_private;
-
-       pci_write_config_dword(pci_root, 0xD0, 0xD0050300);
-       pci_read_config_dword(pci_root, 0xD4, &clock);
-       pci_dev_put(pci_root);
-
-       switch (clock & 0x07) {
-       case 0:
-               dev_priv->core_freq = 100;
-               break;
-       case 1:
-               dev_priv->core_freq = 133;
-               break;
-       case 2:
-               dev_priv->core_freq = 150;
-               break;
-       case 3:
-               dev_priv->core_freq = 178;
-               break;
-       case 4:
-               dev_priv->core_freq = 200;
-               break;
-       case 5:
-       case 6:
-       case 7:
-               dev_priv->core_freq = 266;
-               break;
-       default:
-               dev_priv->core_freq = 0;
-       }
-}
-
 static void cdv_hotplug_work_func(struct work_struct *work)
 {
         struct drm_psb_private *dev_priv = container_of(work, struct drm_psb_private,
@@ -618,7 +582,7 @@ static int cdv_chip_setup(struct drm_device *dev)
        if (pci_enable_msi(dev->pdev))
                dev_warn(dev->dev, "Enabling MSI failed!\n");
        dev_priv->regmap = cdv_regmap;
-       cdv_get_core_freq(dev);
+       gma_get_core_freq(dev);
        psb_intel_opregion_init(dev);
        psb_intel_init_bios(dev);
        cdv_hotplug_enable(dev, false);
index 661af49..c18268c 100644 (file)
@@ -81,13 +81,6 @@ static int cdv_intel_crt_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
-static bool cdv_intel_crt_mode_fixup(struct drm_encoder *encoder,
-                                const struct drm_display_mode *mode,
-                                struct drm_display_mode *adjusted_mode)
-{
-       return true;
-}
-
 static void cdv_intel_crt_mode_set(struct drm_encoder *encoder,
                               struct drm_display_mode *mode,
                               struct drm_display_mode *adjusted_mode)
@@ -224,7 +217,7 @@ static int cdv_intel_crt_set_property(struct drm_connector *connector,
 
 static const struct drm_encoder_helper_funcs cdv_intel_crt_helper_funcs = {
        .dpms = cdv_intel_crt_dpms,
-       .mode_fixup = cdv_intel_crt_mode_fixup,
+       .mode_fixup = gma_encoder_mode_fixup,
        .prepare = gma_encoder_prepare,
        .commit = gma_encoder_commit,
        .mode_set = cdv_intel_crt_mode_set,
index 8fbfa06..6672732 100644 (file)
@@ -412,8 +412,11 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit,
                                  int refclk,
                                  struct gma_clock_t *best_clock)
 {
+       struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
        struct gma_clock_t clock;
-       if (refclk == 27000) {
+
+       switch (refclk) {
+       case 27000:
                if (target < 200000) {
                        clock.p1 = 2;
                        clock.p2 = 10;
@@ -427,7 +430,9 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit,
                        clock.m1 = 0;
                        clock.m2 = 98;
                }
-       } else if (refclk == 100000) {
+               break;
+
+       case 100000:
                if (target < 200000) {
                        clock.p1 = 2;
                        clock.p2 = 10;
@@ -441,12 +446,13 @@ static bool cdv_intel_find_dp_pll(const struct gma_limit_t *limit,
                        clock.m1 = 0;
                        clock.m2 = 133;
                }
-       } else
+               break;
+
+       default:
                return false;
-       clock.m = clock.m2 + 2;
-       clock.p = clock.p1 * clock.p2;
-       clock.vco = (refclk * clock.m) / clock.n;
-       clock.dot = clock.vco / clock.p;
+       }
+
+       gma_crtc->clock_funcs->clock(refclk, &clock);
        memcpy(best_clock, &clock, sizeof(struct gma_clock_t));
        return true;
 }
@@ -463,54 +469,11 @@ static bool cdv_intel_pipe_enabled(struct drm_device *dev, int pipe)
        crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        gma_crtc = to_gma_crtc(crtc);
 
-       if (crtc->fb == NULL || !gma_crtc->active)
+       if (crtc->primary->fb == NULL || !gma_crtc->active)
                return false;
        return true;
 }
 
-static bool cdv_intel_single_pipe_active (struct drm_device *dev)
-{
-       uint32_t pipe_enabled = 0;
-
-       if (cdv_intel_pipe_enabled(dev, 0))
-               pipe_enabled |= FIFO_PIPEA;
-
-       if (cdv_intel_pipe_enabled(dev, 1))
-               pipe_enabled |= FIFO_PIPEB;
-
-
-       DRM_DEBUG_KMS("pipe enabled %x\n", pipe_enabled);
-
-       if (pipe_enabled == FIFO_PIPEA || pipe_enabled == FIFO_PIPEB)
-               return true;
-       else
-               return false;
-}
-
-static bool is_pipeb_lvds(struct drm_device *dev, struct drm_crtc *crtc)
-{
-       struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-       struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_connector *connector;
-
-       if (gma_crtc->pipe != 1)
-               return false;
-
-       list_for_each_entry(connector, &mode_config->connector_list, head) {
-               struct gma_encoder *gma_encoder =
-                                       gma_attached_encoder(connector);
-
-               if (!connector->encoder
-                   || connector->encoder->crtc != crtc)
-                       continue;
-
-               if (gma_encoder->type == INTEL_OUTPUT_LVDS)
-                       return true;
-       }
-
-       return false;
-}
-
 void cdv_disable_sr(struct drm_device *dev)
 {
        if (REG_READ(FW_BLC_SELF) & FW_BLC_SELF_EN) {
@@ -535,8 +498,10 @@ void cdv_disable_sr(struct drm_device *dev)
 void cdv_update_wm(struct drm_device *dev, struct drm_crtc *crtc)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
+       struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
 
-       if (cdv_intel_single_pipe_active(dev)) {
+       /* Is only one pipe enabled? */
+       if (cdv_intel_pipe_enabled(dev, 0) ^ cdv_intel_pipe_enabled(dev, 1)) {
                u32 fw;
 
                fw = REG_READ(DSPFW1);
@@ -557,7 +522,9 @@ void cdv_update_wm(struct drm_device *dev, struct drm_crtc *crtc)
 
                /* ignore FW4 */
 
-               if (is_pipeb_lvds(dev, crtc)) {
+               /* Is pipe b lvds ? */
+               if (gma_crtc->pipe == 1 &&
+                   gma_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)) {
                        REG_WRITE(DSPFW5, 0x00040330);
                } else {
                        fw = (3 << DSP_PLANE_B_FIFO_WM1_SHIFT) |
index 0490ce3..9ff30c2 100644 (file)
@@ -1693,7 +1693,7 @@ done:
                struct drm_crtc *crtc = encoder->base.crtc;
                drm_crtc_helper_set_mode(crtc, &crtc->mode,
                                         crtc->x, crtc->y,
-                                        crtc->fb);
+                                        crtc->primary->fb);
        }
 
        return 0;
index 1c0d723..b99084b 100644 (file)
@@ -89,13 +89,6 @@ static void cdv_hdmi_mode_set(struct drm_encoder *encoder,
        REG_READ(hdmi_priv->hdmi_reg);
 }
 
-static bool cdv_hdmi_mode_fixup(struct drm_encoder *encoder,
-                                 const struct drm_display_mode *mode,
-                                 struct drm_display_mode *adjusted_mode)
-{
-       return true;
-}
-
 static void cdv_hdmi_dpms(struct drm_encoder *encoder, int mode)
 {
        struct drm_device *dev = encoder->dev;
@@ -199,7 +192,7 @@ static int cdv_hdmi_set_property(struct drm_connector *connector,
                    crtc->saved_mode.vdisplay != 0) {
                        if (centre) {
                                if (!drm_crtc_helper_set_mode(encoder->crtc, &crtc->saved_mode,
-                                           encoder->crtc->x, encoder->crtc->y, encoder->crtc->fb))
+                                           encoder->crtc->x, encoder->crtc->y, encoder->crtc->primary->fb))
                                        return -1;
                        } else {
                                struct drm_encoder_helper_funcs *helpers
@@ -262,7 +255,7 @@ static void cdv_hdmi_destroy(struct drm_connector *connector)
 
 static const struct drm_encoder_helper_funcs cdv_hdmi_helper_funcs = {
        .dpms = cdv_hdmi_dpms,
-       .mode_fixup = cdv_hdmi_mode_fixup,
+       .mode_fixup = gma_encoder_mode_fixup,
        .prepare = gma_encoder_prepare,
        .mode_set = cdv_hdmi_mode_set,
        .commit = gma_encoder_commit,
index 20e08e6..8ecc920 100644 (file)
@@ -494,7 +494,7 @@ static int cdv_intel_lvds_set_property(struct drm_connector *connector,
                                                      &crtc->saved_mode,
                                                      encoder->crtc->x,
                                                      encoder->crtc->y,
-                                                     encoder->crtc->fb))
+                                                     encoder->crtc->primary->fb))
                                return -1;
                }
        } else if (!strcmp(property->name, "backlight") && encoder) {
@@ -712,6 +712,7 @@ void cdv_intel_lvds_init(struct drm_device *dev,
         * Attempt to get the fixed panel mode from DDC.  Assume that the
         * preferred mode is the right one.
         */
+       mutex_lock(&dev->mode_config.mutex);
        psb_intel_ddc_get_modes(connector,
                                &gma_encoder->ddc_bus->adapter);
        list_for_each_entry(scan, &connector->probed_modes, head) {
@@ -772,10 +773,12 @@ void cdv_intel_lvds_init(struct drm_device *dev,
        }
 
 out:
+       mutex_unlock(&dev->mode_config.mutex);
        drm_sysfs_connector_add(connector);
        return;
 
 failed_find:
+       mutex_unlock(&dev->mode_config.mutex);
        printk(KERN_ERR "Failed find\n");
        if (gma_encoder->ddc_bus)
                psb_intel_i2c_destroy(gma_encoder->ddc_bus);
index 94b3fec..e7fcc14 100644 (file)
@@ -319,7 +319,7 @@ static struct gtt_range *psbfb_alloc(struct drm_device *dev, int aligned_size)
 {
        struct gtt_range *backing;
        /* Begin by trying to use stolen memory backing */
-       backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1);
+       backing = psb_gtt_alloc_range(dev, aligned_size, "fb", 1, PAGE_SIZE);
        if (backing) {
                drm_gem_private_object_init(dev, &backing->gem, aligned_size);
                return backing;
index e2db48a..c707fa6 100644 (file)
@@ -62,9 +62,6 @@ int psb_gem_dumb_map_gtt(struct drm_file *file, struct drm_device *dev,
        int ret = 0;
        struct drm_gem_object *obj;
 
-       if (!(dev->driver->driver_features & DRIVER_GEM))
-               return -ENODEV;
-
        mutex_lock(&dev->struct_mutex);
 
        /* GEM does all our handle to object mapping */
@@ -98,8 +95,8 @@ unlock:
  *     it so that userspace can speak about it. This does the core work
  *     for the various methods that do/will create GEM objects for things
  */
-static int psb_gem_create(struct drm_file *file,
-       struct drm_device *dev, uint64_t size, uint32_t *handlep)
+int psb_gem_create(struct drm_file *file, struct drm_device *dev, u64 size,
+                  u32 *handlep, int stolen, u32 align)
 {
        struct gtt_range *r;
        int ret;
@@ -109,7 +106,7 @@ static int psb_gem_create(struct drm_file *file,
 
        /* Allocate our object - for now a direct gtt range which is not
           stolen memory backed */
-       r = psb_gtt_alloc_range(dev, size, "gem", 0);
+       r = psb_gtt_alloc_range(dev, size, "gem", 0, PAGE_SIZE);
        if (r == NULL) {
                dev_err(dev->dev, "no memory for %lld byte GEM object\n", size);
                return -ENOSPC;
@@ -153,7 +150,8 @@ int psb_gem_dumb_create(struct drm_file *file, struct drm_device *dev,
 {
        args->pitch = ALIGN(args->width * ((args->bpp + 7) / 8), 64);
        args->size = args->pitch * args->height;
-       return psb_gem_create(file, dev, args->size, &args->handle);
+       return psb_gem_create(file, dev, args->size, &args->handle, 0,
+                             PAGE_SIZE);
 }
 
 /**
@@ -229,47 +227,3 @@ fail:
                return VM_FAULT_SIGBUS;
        }
 }
-
-static int psb_gem_create_stolen(struct drm_file *file, struct drm_device *dev,
-                                               int size, u32 *handle)
-{
-       struct gtt_range *gtt = psb_gtt_alloc_range(dev, size, "gem", 1);
-       if (gtt == NULL)
-               return -ENOMEM;
-
-       drm_gem_private_object_init(dev, &gtt->gem, size);
-       if (drm_gem_handle_create(file, &gtt->gem, handle) == 0)
-               return 0;
-
-       drm_gem_object_release(&gtt->gem);
-       psb_gtt_free_range(dev, gtt);
-       return -ENOMEM;
-}
-
-/*
- *     GEM interfaces for our specific client
- */
-int psb_gem_create_ioctl(struct drm_device *dev, void *data,
-                                       struct drm_file *file)
-{
-       struct drm_psb_gem_create *args = data;
-       int ret;
-       if (args->flags & GMA_GEM_CREATE_STOLEN) {
-               ret = psb_gem_create_stolen(file, dev, args->size,
-                                                       &args->handle);
-               if (ret == 0)
-                       return 0;
-               /* Fall throguh */
-               args->flags &= ~GMA_GEM_CREATE_STOLEN;
-       }
-       return psb_gem_create(file, dev, args->size, &args->handle);
-}
-
-int psb_gem_mmap_ioctl(struct drm_device *dev, void *data,
-                                       struct drm_file *file)
-{
-       struct drm_psb_gem_mmap *args = data;
-       return dev->driver->dumb_map_offset(file, dev,
-                                               args->handle, &args->offset);
-}
-
diff --git a/drivers/gpu/drm/gma500/gem.h b/drivers/gpu/drm/gma500/gem.h
new file mode 100644 (file)
index 0000000..1381c51
--- /dev/null
@@ -0,0 +1,21 @@
+/**************************************************************************
+ * Copyright (c) 2014 Patrik Jakobsson
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ **************************************************************************/
+
+#ifndef _GEM_H
+#define _GEM_H
+
+extern int psb_gem_create(struct drm_file *file, struct drm_device *dev,
+                         u64 size, u32 *handlep, int stolen, u32 align);
+#endif
diff --git a/drivers/gpu/drm/gma500/gma_device.c b/drivers/gpu/drm/gma500/gma_device.c
new file mode 100644 (file)
index 0000000..4a295f9
--- /dev/null
@@ -0,0 +1,56 @@
+/**************************************************************************
+ * Copyright (c) 2011, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ **************************************************************************/
+
+#include <drm/drmP.h>
+#include "psb_drv.h"
+
+void gma_get_core_freq(struct drm_device *dev)
+{
+       uint32_t clock;
+       struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
+       struct drm_psb_private *dev_priv = dev->dev_private;
+
+       /*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/
+       /*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/
+
+       pci_write_config_dword(pci_root, 0xD0, 0xD0050300);
+       pci_read_config_dword(pci_root, 0xD4, &clock);
+       pci_dev_put(pci_root);
+
+       switch (clock & 0x07) {
+       case 0:
+               dev_priv->core_freq = 100;
+               break;
+       case 1:
+               dev_priv->core_freq = 133;
+               break;
+       case 2:
+               dev_priv->core_freq = 150;
+               break;
+       case 3:
+               dev_priv->core_freq = 178;
+               break;
+       case 4:
+               dev_priv->core_freq = 200;
+               break;
+       case 5:
+       case 6:
+       case 7:
+               dev_priv->core_freq = 266;
+               break;
+       default:
+               dev_priv->core_freq = 0;
+       }
+}
diff --git a/drivers/gpu/drm/gma500/gma_device.h b/drivers/gpu/drm/gma500/gma_device.h
new file mode 100644 (file)
index 0000000..e1dbb00
--- /dev/null
@@ -0,0 +1,21 @@
+/**************************************************************************
+ * Copyright (c) 2011, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ **************************************************************************/
+
+#ifndef _GMA_DEVICE_H
+#define _GMA_DEVICE_H
+
+extern void gma_get_core_freq(struct drm_device *dev);
+
+#endif
index 386de2c..9bb9bdd 100644 (file)
@@ -59,7 +59,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        struct drm_device *dev = crtc->dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
        struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-       struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
+       struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
        int pipe = gma_crtc->pipe;
        const struct psb_offset *map = &dev_priv->regmap[pipe];
        unsigned long start, offset;
@@ -70,7 +70,7 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return 0;
 
        /* no fb bound */
-       if (!crtc->fb) {
+       if (!crtc->primary->fb) {
                dev_err(dev->dev, "No FB bound\n");
                goto gma_pipe_cleaner;
        }
@@ -81,19 +81,19 @@ int gma_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        if (ret < 0)
                goto gma_pipe_set_base_exit;
        start = psbfb->gtt->offset;
-       offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
+       offset = y * crtc->primary->fb->pitches[0] + x * (crtc->primary->fb->bits_per_pixel / 8);
 
-       REG_WRITE(map->stride, crtc->fb->pitches[0]);
+       REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
 
        dspcntr = REG_READ(map->cntr);
        dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
                dspcntr |= DISPPLANE_8BPP;
                break;
        case 16:
-               if (crtc->fb->depth == 15)
+               if (crtc->primary->fb->depth == 15)
                        dspcntr |= DISPPLANE_15_16BPP;
                else
                        dspcntr |= DISPPLANE_16BPP;
@@ -485,6 +485,13 @@ int gma_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
        return 0;
 }
 
+bool gma_encoder_mode_fixup(struct drm_encoder *encoder,
+                           const struct drm_display_mode *mode,
+                           struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
 bool gma_crtc_mode_fixup(struct drm_crtc *crtc,
                         const struct drm_display_mode *mode,
                         struct drm_display_mode *adjusted_mode)
@@ -511,8 +518,8 @@ void gma_crtc_disable(struct drm_crtc *crtc)
 
        crtc_funcs->dpms(crtc, DRM_MODE_DPMS_OFF);
 
-       if (crtc->fb) {
-               gt = to_psb_fb(crtc->fb)->gtt;
+       if (crtc->primary->fb) {
+               gt = to_psb_fb(crtc->primary->fb)->gtt;
                psb_gtt_unpin(gt);
        }
 }
index 78b9f98..ed569d8 100644 (file)
@@ -90,6 +90,9 @@ extern void gma_crtc_restore(struct drm_crtc *crtc);
 extern void gma_encoder_prepare(struct drm_encoder *encoder);
 extern void gma_encoder_commit(struct drm_encoder *encoder);
 extern void gma_encoder_destroy(struct drm_encoder *encoder);
+extern bool gma_encoder_mode_fixup(struct drm_encoder *encoder,
+                                  const struct drm_display_mode *mode,
+                                  struct drm_display_mode *adjusted_mode);
 
 /* Common clock related functions */
 extern const struct gma_limit_t *gma_limit(struct drm_crtc *crtc, int refclk);
index 2db731f..592d205 100644 (file)
@@ -22,6 +22,7 @@
 #include <drm/drmP.h>
 #include <linux/shmem_fs.h>
 #include "psb_drv.h"
+#include "blitter.h"
 
 
 /*
@@ -105,11 +106,13 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r,
 
        /* Write our page entries into the GTT itself */
        for (i = r->roll; i < r->npage; i++) {
-               pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0);
+               pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]),
+                                      PSB_MMU_CACHED_MEMORY);
                iowrite32(pte, gtt_slot++);
        }
        for (i = 0; i < r->roll; i++) {
-               pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0);
+               pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]),
+                                      PSB_MMU_CACHED_MEMORY);
                iowrite32(pte, gtt_slot++);
        }
        /* Make sure all the entries are set before we return */
@@ -127,7 +130,7 @@ static int psb_gtt_insert(struct drm_device *dev, struct gtt_range *r,
  *     page table entries with the dummy page. This is protected via the gtt
  *     mutex which the caller must hold.
  */
-static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)
+void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
        u32 __iomem *gtt_slot;
@@ -137,7 +140,8 @@ static void psb_gtt_remove(struct drm_device *dev, struct gtt_range *r)
        WARN_ON(r->stolen);
 
        gtt_slot = psb_gtt_entry(dev, r);
-       pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page), 0);
+       pte = psb_gtt_mask_pte(page_to_pfn(dev_priv->scratch_page),
+                              PSB_MMU_CACHED_MEMORY);
 
        for (i = 0; i < r->npage; i++)
                iowrite32(pte, gtt_slot++);
@@ -176,11 +180,13 @@ void psb_gtt_roll(struct drm_device *dev, struct gtt_range *r, int roll)
        gtt_slot = psb_gtt_entry(dev, r);
 
        for (i = r->roll; i < r->npage; i++) {
-               pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0);
+               pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]),
+                                      PSB_MMU_CACHED_MEMORY);
                iowrite32(pte, gtt_slot++);
        }
        for (i = 0; i < r->roll; i++) {
-               pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]), 0);
+               pte = psb_gtt_mask_pte(page_to_pfn(r->pages[i]),
+                                      PSB_MMU_CACHED_MEMORY);
                iowrite32(pte, gtt_slot++);
        }
        ioread32(gtt_slot - 1);
@@ -240,6 +246,7 @@ int psb_gtt_pin(struct gtt_range *gt)
        int ret = 0;
        struct drm_device *dev = gt->gem.dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
+       u32 gpu_base = dev_priv->gtt.gatt_start;
 
        mutex_lock(&dev_priv->gtt_mutex);
 
@@ -252,6 +259,9 @@ int psb_gtt_pin(struct gtt_range *gt)
                        psb_gtt_detach_pages(gt);
                        goto out;
                }
+               psb_mmu_insert_pages(psb_mmu_get_default_pd(dev_priv->mmu),
+                                    gt->pages, (gpu_base + gt->offset),
+                                    gt->npage, 0, 0, PSB_MMU_CACHED_MEMORY);
        }
        gt->in_gart++;
 out:
@@ -274,16 +284,30 @@ void psb_gtt_unpin(struct gtt_range *gt)
 {
        struct drm_device *dev = gt->gem.dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
+       u32 gpu_base = dev_priv->gtt.gatt_start;
+       int ret;
 
+       /* While holding the gtt_mutex no new blits can be initiated */
        mutex_lock(&dev_priv->gtt_mutex);
 
+       /* Wait for any possible usage of the memory to be finished */
+       ret = gma_blt_wait_idle(dev_priv);
+       if (ret) {
+               DRM_ERROR("Failed to idle the blitter, unpin failed!");
+               goto out;
+       }
+
        WARN_ON(!gt->in_gart);
 
        gt->in_gart--;
        if (gt->in_gart == 0 && gt->stolen == 0) {
+               psb_mmu_remove_pages(psb_mmu_get_default_pd(dev_priv->mmu),
+                                    (gpu_base + gt->offset), gt->npage, 0, 0);
                psb_gtt_remove(dev, gt);
                psb_gtt_detach_pages(gt);
        }
+
+out:
        mutex_unlock(&dev_priv->gtt_mutex);
 }
 
@@ -306,7 +330,7 @@ void psb_gtt_unpin(struct gtt_range *gt)
  *     as in use.
  */
 struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len,
-                                               const char *name, int backed)
+                                     const char *name, int backed, u32 align)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
        struct gtt_range *gt;
@@ -334,7 +358,7 @@ struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len,
        /* Ensure this is set for non GEM objects */
        gt->gem.dev = dev;
        ret = allocate_resource(dev_priv->gtt_mem, &gt->resource,
-                               len, start, end, PAGE_SIZE, NULL, NULL);
+                               len, start, end, align, NULL, NULL);
        if (ret == 0) {
                gt->offset = gt->resource.start - r->start;
                return gt;
@@ -497,6 +521,7 @@ int psb_gtt_init(struct drm_device *dev, int resume)
        if (!resume)
                dev_priv->vram_addr = ioremap_wc(dev_priv->stolen_base,
                                                 stolen_size);
+
        if (!dev_priv->vram_addr) {
                dev_err(dev->dev, "Failure to map stolen base.\n");
                ret = -ENOMEM;
@@ -512,7 +537,7 @@ int psb_gtt_init(struct drm_device *dev, int resume)
        dev_dbg(dev->dev, "Set up %d stolen pages starting at 0x%08x, GTT offset %dK\n",
                num_pages, pfn_base << PAGE_SHIFT, 0);
        for (i = 0; i < num_pages; ++i) {
-               pte = psb_gtt_mask_pte(pfn_base + i, 0);
+               pte = psb_gtt_mask_pte(pfn_base + i, PSB_MMU_CACHED_MEMORY);
                iowrite32(pte, dev_priv->gtt_map + i);
        }
 
@@ -521,7 +546,7 @@ int psb_gtt_init(struct drm_device *dev, int resume)
         */
 
        pfn_base = page_to_pfn(dev_priv->scratch_page);
-       pte = psb_gtt_mask_pte(pfn_base, 0);
+       pte = psb_gtt_mask_pte(pfn_base, PSB_MMU_CACHED_MEMORY);
        for (; i < gtt_pages; ++i)
                iowrite32(pte, dev_priv->gtt_map + i);
 
index 6191d10..f5860a7 100644 (file)
@@ -53,7 +53,8 @@ struct gtt_range {
 };
 
 extern struct gtt_range *psb_gtt_alloc_range(struct drm_device *dev, int len,
-                                               const char *name, int backed);
+                                            const char *name, int backed,
+                                            u32 align);
 extern void psb_gtt_kref_put(struct gtt_range *gt);
 extern void psb_gtt_free_range(struct drm_device *dev, struct gtt_range *gt);
 extern int psb_gtt_pin(struct gtt_range *gt);
index 860a4ee..6e91b20 100644 (file)
@@ -287,7 +287,7 @@ static int mdfld_dsi_connector_set_property(struct drm_connector *connector,
                                                &gma_crtc->saved_mode,
                                                encoder->crtc->x,
                                                encoder->crtc->y,
-                                               encoder->crtc->fb))
+                                               encoder->crtc->primary->fb))
                                        goto set_prop_error;
                        } else {
                                struct drm_encoder_helper_funcs *funcs =
index 321c00a..8cc8a5a 100644 (file)
@@ -166,7 +166,7 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        struct drm_device *dev = crtc->dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
        struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-       struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
+       struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
        int pipe = gma_crtc->pipe;
        const struct psb_offset *map = &dev_priv->regmap[pipe];
        unsigned long start, offset;
@@ -178,12 +178,12 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        dev_dbg(dev->dev, "pipe = 0x%x.\n", pipe);
 
        /* no fb bound */
-       if (!crtc->fb) {
+       if (!crtc->primary->fb) {
                dev_dbg(dev->dev, "No FB bound\n");
                return 0;
        }
 
-       ret = check_fb(crtc->fb);
+       ret = check_fb(crtc->primary->fb);
        if (ret)
                return ret;
 
@@ -196,18 +196,18 @@ static int mdfld__intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                return 0;
 
        start = psbfb->gtt->offset;
-       offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
+       offset = y * crtc->primary->fb->pitches[0] + x * (crtc->primary->fb->bits_per_pixel / 8);
 
-       REG_WRITE(map->stride, crtc->fb->pitches[0]);
+       REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
        dspcntr = REG_READ(map->cntr);
        dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
                dspcntr |= DISPPLANE_8BPP;
                break;
        case 16:
-               if (crtc->fb->depth == 15)
+               if (crtc->primary->fb->depth == 15)
                        dspcntr |= DISPPLANE_15_16BPP;
                else
                        dspcntr |= DISPPLANE_16BPP;
@@ -700,7 +700,7 @@ static int mdfld_crtc_mode_set(struct drm_crtc *crtc,
        }
 #endif
 
-       ret = check_fb(crtc->fb);
+       ret = check_fb(crtc->primary->fb);
        if (ret)
                return ret;
 
index c3e67ba..0eaf11c 100644 (file)
@@ -18,6 +18,7 @@
 #include <drm/drmP.h>
 #include "psb_drv.h"
 #include "psb_reg.h"
+#include "mmu.h"
 
 /*
  * Code for the SGX MMU:
  * but on average it should be fast.
  */
 
-struct psb_mmu_driver {
-       /* protects driver- and pd structures. Always take in read mode
-        * before taking the page table spinlock.
-        */
-       struct rw_semaphore sem;
-
-       /* protects page tables, directory tables and pt tables.
-        * and pt structures.
-        */
-       spinlock_t lock;
-
-       atomic_t needs_tlbflush;
-
-       uint8_t __iomem *register_map;
-       struct psb_mmu_pd *default_pd;
-       /*uint32_t bif_ctrl;*/
-       int has_clflush;
-       int clflush_add;
-       unsigned long clflush_mask;
-
-       struct drm_psb_private *dev_priv;
-};
-
-struct psb_mmu_pd;
-
-struct psb_mmu_pt {
-       struct psb_mmu_pd *pd;
-       uint32_t index;
-       uint32_t count;
-       struct page *p;
-       uint32_t *v;
-};
-
-struct psb_mmu_pd {
-       struct psb_mmu_driver *driver;
-       int hw_context;
-       struct psb_mmu_pt **tables;
-       struct page *p;
-       struct page *dummy_pt;
-       struct page *dummy_page;
-       uint32_t pd_mask;
-       uint32_t invalid_pde;
-       uint32_t invalid_pte;
-};
-
 static inline uint32_t psb_mmu_pt_index(uint32_t offset)
 {
        return (offset >> PSB_PTE_SHIFT) & 0x3FF;
@@ -102,13 +58,13 @@ static inline uint32_t psb_mmu_pd_index(uint32_t offset)
        return offset >> PSB_PDE_SHIFT;
 }
 
+#if defined(CONFIG_X86)
 static inline void psb_clflush(void *addr)
 {
        __asm__ __volatile__("clflush (%0)\n" : : "r"(addr) : "memory");
 }
 
-static inline void psb_mmu_clflush(struct psb_mmu_driver *driver,
-                                  void *addr)
+static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr)
 {
        if (!driver->has_clflush)
                return;
@@ -117,62 +73,77 @@ static inline void psb_mmu_clflush(struct psb_mmu_driver *driver,
        psb_clflush(addr);
        mb();
 }
+#else
 
-static void psb_page_clflush(struct psb_mmu_driver *driver, struct page* page)
-{
-       uint32_t clflush_add = driver->clflush_add >> PAGE_SHIFT;
-       uint32_t clflush_count = PAGE_SIZE / clflush_add;
-       int i;
-       uint8_t *clf;
-
-       clf = kmap_atomic(page);
-       mb();
-       for (i = 0; i < clflush_count; ++i) {
-               psb_clflush(clf);
-               clf += clflush_add;
-       }
-       mb();
-       kunmap_atomic(clf);
+static inline void psb_mmu_clflush(struct psb_mmu_driver *driver, void *addr)
+{;
 }
 
-static void psb_pages_clflush(struct psb_mmu_driver *driver,
-                               struct page *page[], unsigned long num_pages)
-{
-       int i;
-
-       if (!driver->has_clflush)
-               return ;
+#endif
 
-       for (i = 0; i < num_pages; i++)
-               psb_page_clflush(driver, *page++);
-}
-
-static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver,
-                                   int force)
+static void psb_mmu_flush_pd_locked(struct psb_mmu_driver *driver, int force)
 {
+       struct drm_device *dev = driver->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
+
+       if (atomic_read(&driver->needs_tlbflush) || force) {
+               uint32_t val = PSB_RSGX32(PSB_CR_BIF_CTRL);
+               PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL);
+
+               /* Make sure data cache is turned off before enabling it */
+               wmb();
+               PSB_WSGX32(val & ~_PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL);
+               (void)PSB_RSGX32(PSB_CR_BIF_CTRL);
+               if (driver->msvdx_mmu_invaldc)
+                       atomic_set(driver->msvdx_mmu_invaldc, 1);
+       }
        atomic_set(&driver->needs_tlbflush, 0);
 }
 
+#if 0
 static void psb_mmu_flush_pd(struct psb_mmu_driver *driver, int force)
 {
        down_write(&driver->sem);
        psb_mmu_flush_pd_locked(driver, force);
        up_write(&driver->sem);
 }
+#endif
 
-void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot)
+void psb_mmu_flush(struct psb_mmu_driver *driver)
 {
-       if (rc_prot)
-               down_write(&driver->sem);
-       if (rc_prot)
-               up_write(&driver->sem);
+       struct drm_device *dev = driver->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       uint32_t val;
+
+       down_write(&driver->sem);
+       val = PSB_RSGX32(PSB_CR_BIF_CTRL);
+       if (atomic_read(&driver->needs_tlbflush))
+               PSB_WSGX32(val | _PSB_CB_CTRL_INVALDC, PSB_CR_BIF_CTRL);
+       else
+               PSB_WSGX32(val | _PSB_CB_CTRL_FLUSH, PSB_CR_BIF_CTRL);
+
+       /* Make sure data cache is turned off and MMU is flushed before
+          restoring bank interface control register */
+       wmb();
+       PSB_WSGX32(val & ~(_PSB_CB_CTRL_FLUSH | _PSB_CB_CTRL_INVALDC),
+                  PSB_CR_BIF_CTRL);
+       (void)PSB_RSGX32(PSB_CR_BIF_CTRL);
+
+       atomic_set(&driver->needs_tlbflush, 0);
+       if (driver->msvdx_mmu_invaldc)
+               atomic_set(driver->msvdx_mmu_invaldc, 1);
+       up_write(&driver->sem);
 }
 
 void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context)
 {
-       /*ttm_tt_cache_flush(&pd->p, 1);*/
-       psb_pages_clflush(pd->driver, &pd->p, 1);
+       struct drm_device *dev = pd->driver->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       uint32_t offset = (hw_context == 0) ? PSB_CR_BIF_DIR_LIST_BASE0 :
+                         PSB_CR_BIF_DIR_LIST_BASE1 + hw_context * 4;
+
        down_write(&pd->driver->sem);
+       PSB_WSGX32(page_to_pfn(pd->p) << PAGE_SHIFT, offset);
        wmb();
        psb_mmu_flush_pd_locked(pd->driver, 1);
        pd->hw_context = hw_context;
@@ -183,7 +154,6 @@ void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context)
 static inline unsigned long psb_pd_addr_end(unsigned long addr,
                                            unsigned long end)
 {
-
        addr = (addr + PSB_PDE_MASK + 1) & ~PSB_PDE_MASK;
        return (addr < end) ? addr : end;
 }
@@ -223,12 +193,10 @@ struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver,
                goto out_err3;
 
        if (!trap_pagefaults) {
-               pd->invalid_pde =
-                   psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt),
-                                    invalid_type);
-               pd->invalid_pte =
-                   psb_mmu_mask_pte(page_to_pfn(pd->dummy_page),
-                                    invalid_type);
+               pd->invalid_pde = psb_mmu_mask_pte(page_to_pfn(pd->dummy_pt),
+                                                  invalid_type);
+               pd->invalid_pte = psb_mmu_mask_pte(page_to_pfn(pd->dummy_page),
+                                                  invalid_type);
        } else {
                pd->invalid_pde = 0;
                pd->invalid_pte = 0;
@@ -279,12 +247,16 @@ static void psb_mmu_free_pt(struct psb_mmu_pt *pt)
 void psb_mmu_free_pagedir(struct psb_mmu_pd *pd)
 {
        struct psb_mmu_driver *driver = pd->driver;
+       struct drm_device *dev = driver->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
        struct psb_mmu_pt *pt;
        int i;
 
        down_write(&driver->sem);
-       if (pd->hw_context != -1)
+       if (pd->hw_context != -1) {
+               PSB_WSGX32(0, PSB_CR_BIF_DIR_LIST_BASE0 + pd->hw_context * 4);
                psb_mmu_flush_pd_locked(driver, 1);
+       }
 
        /* Should take the spinlock here, but we don't need to do that
           since we have the semaphore in write mode. */
@@ -331,7 +303,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd)
        for (i = 0; i < (PAGE_SIZE / sizeof(uint32_t)); ++i)
                *ptes++ = pd->invalid_pte;
 
-
+#if defined(CONFIG_X86)
        if (pd->driver->has_clflush && pd->hw_context != -1) {
                mb();
                for (i = 0; i < clflush_count; ++i) {
@@ -340,7 +312,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd)
                }
                mb();
        }
-
+#endif
        kunmap_atomic(v);
        spin_unlock(lock);
 
@@ -351,7 +323,7 @@ static struct psb_mmu_pt *psb_mmu_alloc_pt(struct psb_mmu_pd *pd)
        return pt;
 }
 
-static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
+struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
                                             unsigned long addr)
 {
        uint32_t index = psb_mmu_pd_index(addr);
@@ -383,7 +355,7 @@ static struct psb_mmu_pt *psb_mmu_pt_alloc_map_lock(struct psb_mmu_pd *pd,
                kunmap_atomic((void *) v);
 
                if (pd->hw_context != -1) {
-                       psb_mmu_clflush(pd->driver, (void *) &v[index]);
+                       psb_mmu_clflush(pd->driver, (void *)&v[index]);
                        atomic_set(&pd->driver->needs_tlbflush, 1);
                }
        }
@@ -420,8 +392,7 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt)
                pd->tables[pt->index] = NULL;
 
                if (pd->hw_context != -1) {
-                       psb_mmu_clflush(pd->driver,
-                                       (void *) &v[pt->index]);
+                       psb_mmu_clflush(pd->driver, (void *)&v[pt->index]);
                        atomic_set(&pd->driver->needs_tlbflush, 1);
                }
                kunmap_atomic(pt->v);
@@ -432,8 +403,8 @@ static void psb_mmu_pt_unmap_unlock(struct psb_mmu_pt *pt)
        spin_unlock(&pd->driver->lock);
 }
 
-static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt,
-                                  unsigned long addr, uint32_t pte)
+static inline void psb_mmu_set_pte(struct psb_mmu_pt *pt, unsigned long addr,
+                                  uint32_t pte)
 {
        pt->v[psb_mmu_pt_index(addr)] = pte;
 }
@@ -444,69 +415,50 @@ static inline void psb_mmu_invalidate_pte(struct psb_mmu_pt *pt,
        pt->v[psb_mmu_pt_index(addr)] = pt->pd->invalid_pte;
 }
 
-
-void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd,
-                       uint32_t mmu_offset, uint32_t gtt_start,
-                       uint32_t gtt_pages)
+struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver)
 {
-       uint32_t *v;
-       uint32_t start = psb_mmu_pd_index(mmu_offset);
-       struct psb_mmu_driver *driver = pd->driver;
-       int num_pages = gtt_pages;
+       struct psb_mmu_pd *pd;
 
        down_read(&driver->sem);
-       spin_lock(&driver->lock);
-
-       v = kmap_atomic(pd->p);
-       v += start;
-
-       while (gtt_pages--) {
-               *v++ = gtt_start | pd->pd_mask;
-               gtt_start += PAGE_SIZE;
-       }
-
-       /*ttm_tt_cache_flush(&pd->p, num_pages);*/
-       psb_pages_clflush(pd->driver, &pd->p, num_pages);
-       kunmap_atomic(v);
-       spin_unlock(&driver->lock);
-
-       if (pd->hw_context != -1)
-               atomic_set(&pd->driver->needs_tlbflush, 1);
+       pd = driver->default_pd;
+       up_read(&driver->sem);
 
-       up_read(&pd->driver->sem);
-       psb_mmu_flush_pd(pd->driver, 0);
+       return pd;
 }
 
-struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver *driver)
+/* Returns the physical address of the PD shared by sgx/msvdx */
+uint32_t psb_get_default_pd_addr(struct psb_mmu_driver *driver)
 {
        struct psb_mmu_pd *pd;
 
-       /* down_read(&driver->sem); */
-       pd = driver->default_pd;
-       /* up_read(&driver->sem); */
-
-       return pd;
+       pd = psb_mmu_get_default_pd(driver);
+       return page_to_pfn(pd->p) << PAGE_SHIFT;
 }
 
 void psb_mmu_driver_takedown(struct psb_mmu_driver *driver)
 {
+       struct drm_device *dev = driver->dev;
+       struct drm_psb_private *dev_priv = dev->dev_private;
+
+       PSB_WSGX32(driver->bif_ctrl, PSB_CR_BIF_CTRL);
        psb_mmu_free_pagedir(driver->default_pd);
        kfree(driver);
 }
 
-struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers,
-                                       int trap_pagefaults,
-                                       int invalid_type,
-                                       struct drm_psb_private *dev_priv)
+struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev,
+                                          int trap_pagefaults,
+                                          int invalid_type,
+                                          atomic_t *msvdx_mmu_invaldc)
 {
        struct psb_mmu_driver *driver;
+       struct drm_psb_private *dev_priv = dev->dev_private;
 
        driver = kmalloc(sizeof(*driver), GFP_KERNEL);
 
        if (!driver)
                return NULL;
-       driver->dev_priv = dev_priv;
 
+       driver->dev = dev;
        driver->default_pd = psb_mmu_alloc_pd(driver, trap_pagefaults,
                                              invalid_type);
        if (!driver->default_pd)
@@ -515,17 +467,24 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers,
        spin_lock_init(&driver->lock);
        init_rwsem(&driver->sem);
        down_write(&driver->sem);
-       driver->register_map = registers;
        atomic_set(&driver->needs_tlbflush, 1);
+       driver->msvdx_mmu_invaldc = msvdx_mmu_invaldc;
+
+       driver->bif_ctrl = PSB_RSGX32(PSB_CR_BIF_CTRL);
+       PSB_WSGX32(driver->bif_ctrl | _PSB_CB_CTRL_CLEAR_FAULT,
+                  PSB_CR_BIF_CTRL);
+       PSB_WSGX32(driver->bif_ctrl & ~_PSB_CB_CTRL_CLEAR_FAULT,
+                  PSB_CR_BIF_CTRL);
 
        driver->has_clflush = 0;
 
+#if defined(CONFIG_X86)
        if (boot_cpu_has(X86_FEATURE_CLFLUSH)) {
                uint32_t tfms, misc, cap0, cap4, clflush_size;
 
                /*
-                * clflush size is determined at kernel setup for x86_64
-                *  but not for i386. We have to do it here.
+                * clflush size is determined at kernel setup for x86_64 but not
+                * for i386. We have to do it here.
                 */
 
                cpuid(0x00000001, &tfms, &misc, &cap0, &cap4);
@@ -536,6 +495,7 @@ struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers,
                driver->clflush_mask = driver->clflush_add - 1;
                driver->clflush_mask = ~driver->clflush_mask;
        }
+#endif
 
        up_write(&driver->sem);
        return driver;
@@ -545,9 +505,9 @@ out_err1:
        return NULL;
 }
 
-static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd,
-                              unsigned long address, uint32_t num_pages,
-                              uint32_t desired_tile_stride,
+#if defined(CONFIG_X86)
+static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address,
+                              uint32_t num_pages, uint32_t desired_tile_stride,
                               uint32_t hw_tile_stride)
 {
        struct psb_mmu_pt *pt;
@@ -561,11 +521,8 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd,
        unsigned long clflush_add = pd->driver->clflush_add;
        unsigned long clflush_mask = pd->driver->clflush_mask;
 
-       if (!pd->driver->has_clflush) {
-               /*ttm_tt_cache_flush(&pd->p, num_pages);*/
-               psb_pages_clflush(pd->driver, &pd->p, num_pages);
+       if (!pd->driver->has_clflush)
                return;
-       }
 
        if (hw_tile_stride)
                rows = num_pages / desired_tile_stride;
@@ -586,10 +543,8 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd,
                        if (!pt)
                                continue;
                        do {
-                               psb_clflush(&pt->v
-                                           [psb_mmu_pt_index(addr)]);
-                       } while (addr +=
-                                clflush_add,
+                               psb_clflush(&pt->v[psb_mmu_pt_index(addr)]);
+                       } while (addr += clflush_add,
                                 (addr & clflush_mask) < next);
 
                        psb_mmu_pt_unmap_unlock(pt);
@@ -598,6 +553,14 @@ static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd,
        }
        mb();
 }
+#else
+static void psb_mmu_flush_ptes(struct psb_mmu_pd *pd, unsigned long address,
+                              uint32_t num_pages, uint32_t desired_tile_stride,
+                              uint32_t hw_tile_stride)
+{
+       drm_ttm_cache_flush();
+}
+#endif
 
 void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd,
                                 unsigned long address, uint32_t num_pages)
@@ -633,7 +596,7 @@ out:
        up_read(&pd->driver->sem);
 
        if (pd->hw_context != -1)
-               psb_mmu_flush(pd->driver, 0);
+               psb_mmu_flush(pd->driver);
 
        return;
 }
@@ -660,7 +623,7 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address,
        add = desired_tile_stride << PAGE_SHIFT;
        row_add = hw_tile_stride << PAGE_SHIFT;
 
-       /* down_read(&pd->driver->sem); */
+       down_read(&pd->driver->sem);
 
        /* Make sure we only need to flush this processor's cache */
 
@@ -688,10 +651,10 @@ void psb_mmu_remove_pages(struct psb_mmu_pd *pd, unsigned long address,
                psb_mmu_flush_ptes(pd, f_address, num_pages,
                                   desired_tile_stride, hw_tile_stride);
 
-       /* up_read(&pd->driver->sem); */
+       up_read(&pd->driver->sem);
 
        if (pd->hw_context != -1)
-               psb_mmu_flush(pd->driver, 0);
+               psb_mmu_flush(pd->driver);
 }
 
 int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn,
@@ -704,7 +667,7 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn,
        unsigned long end;
        unsigned long next;
        unsigned long f_address = address;
-       int ret = 0;
+       int ret = -ENOMEM;
 
        down_read(&pd->driver->sem);
 
@@ -726,6 +689,7 @@ int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd, uint32_t start_pfn,
                psb_mmu_pt_unmap_unlock(pt);
 
        } while (addr = next, next != end);
+       ret = 0;
 
 out:
        if (pd->hw_context != -1)
@@ -734,15 +698,15 @@ out:
        up_read(&pd->driver->sem);
 
        if (pd->hw_context != -1)
-               psb_mmu_flush(pd->driver, 1);
+               psb_mmu_flush(pd->driver);
 
-       return ret;
+       return 0;
 }
 
 int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
                         unsigned long address, uint32_t num_pages,
-                        uint32_t desired_tile_stride,
-                        uint32_t hw_tile_stride, int type)
+                        uint32_t desired_tile_stride, uint32_t hw_tile_stride,
+                        int type)
 {
        struct psb_mmu_pt *pt;
        uint32_t rows = 1;
@@ -754,7 +718,7 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
        unsigned long add;
        unsigned long row_add;
        unsigned long f_address = address;
-       int ret = 0;
+       int ret = -ENOMEM;
 
        if (hw_tile_stride) {
                if (num_pages % desired_tile_stride != 0)
@@ -777,14 +741,11 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
                do {
                        next = psb_pd_addr_end(addr, end);
                        pt = psb_mmu_pt_alloc_map_lock(pd, addr);
-                       if (!pt) {
-                               ret = -ENOMEM;
+                       if (!pt)
                                goto out;
-                       }
                        do {
-                               pte =
-                                   psb_mmu_mask_pte(page_to_pfn(*pages++),
-                                                    type);
+                               pte = psb_mmu_mask_pte(page_to_pfn(*pages++),
+                                                      type);
                                psb_mmu_set_pte(pt, addr, pte);
                                pt->count++;
                        } while (addr += PAGE_SIZE, addr < next);
@@ -794,6 +755,8 @@ int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
 
                address += row_add;
        }
+
+       ret = 0;
 out:
        if (pd->hw_context != -1)
                psb_mmu_flush_ptes(pd, f_address, num_pages,
@@ -802,7 +765,7 @@ out:
        up_read(&pd->driver->sem);
 
        if (pd->hw_context != -1)
-               psb_mmu_flush(pd->driver, 1);
+               psb_mmu_flush(pd->driver);
 
        return ret;
 }
diff --git a/drivers/gpu/drm/gma500/mmu.h b/drivers/gpu/drm/gma500/mmu.h
new file mode 100644 (file)
index 0000000..e89abec
--- /dev/null
@@ -0,0 +1,93 @@
+/**************************************************************************
+ * Copyright (c) 2007-2011, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ **************************************************************************/
+
+#ifndef __MMU_H
+#define __MMU_H
+
+struct psb_mmu_driver {
+       /* protects driver- and pd structures. Always take in read mode
+        * before taking the page table spinlock.
+        */
+       struct rw_semaphore sem;
+
+       /* protects page tables, directory tables and pt tables.
+        * and pt structures.
+        */
+       spinlock_t lock;
+
+       atomic_t needs_tlbflush;
+       atomic_t *msvdx_mmu_invaldc;
+       struct psb_mmu_pd *default_pd;
+       uint32_t bif_ctrl;
+       int has_clflush;
+       int clflush_add;
+       unsigned long clflush_mask;
+
+       struct drm_device *dev;
+};
+
+struct psb_mmu_pd;
+
+struct psb_mmu_pt {
+       struct psb_mmu_pd *pd;
+       uint32_t index;
+       uint32_t count;
+       struct page *p;
+       uint32_t *v;
+};
+
+struct psb_mmu_pd {
+       struct psb_mmu_driver *driver;
+       int hw_context;
+       struct psb_mmu_pt **tables;
+       struct page *p;
+       struct page *dummy_pt;
+       struct page *dummy_page;
+       uint32_t pd_mask;
+       uint32_t invalid_pde;
+       uint32_t invalid_pte;
+};
+
+extern struct psb_mmu_driver *psb_mmu_driver_init(struct drm_device *dev,
+                                                 int trap_pagefaults,
+                                                 int invalid_type,
+                                                 atomic_t *msvdx_mmu_invaldc);
+extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver);
+extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver
+                                                *driver);
+extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver,
+                                          int trap_pagefaults,
+                                          int invalid_type);
+extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd);
+extern void psb_mmu_flush(struct psb_mmu_driver *driver);
+extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd,
+                                       unsigned long address,
+                                       uint32_t num_pages);
+extern int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd,
+                                      uint32_t start_pfn,
+                                      unsigned long address,
+                                      uint32_t num_pages, int type);
+extern int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual,
+                                 unsigned long *pfn);
+extern void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context);
+extern int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
+                               unsigned long address, uint32_t num_pages,
+                               uint32_t desired_tile_stride,
+                               uint32_t hw_tile_stride, int type);
+extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd,
+                                unsigned long address, uint32_t num_pages,
+                                uint32_t desired_tile_stride,
+                                uint32_t hw_tile_stride);
+
+#endif
index 8195e85..2de216c 100644 (file)
@@ -599,7 +599,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
        struct gma_crtc *gma_crtc = to_gma_crtc(crtc);
-       struct psb_framebuffer *psbfb = to_psb_fb(crtc->fb);
+       struct psb_framebuffer *psbfb = to_psb_fb(crtc->primary->fb);
        int pipe = gma_crtc->pipe;
        const struct psb_offset *map = &dev_priv->regmap[pipe];
        unsigned long start, offset;
@@ -608,7 +608,7 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
        int ret = 0;
 
        /* no fb bound */
-       if (!crtc->fb) {
+       if (!crtc->primary->fb) {
                dev_dbg(dev->dev, "No FB bound\n");
                return 0;
        }
@@ -617,19 +617,19 @@ static int oaktrail_pipe_set_base(struct drm_crtc *crtc,
                return 0;
 
        start = psbfb->gtt->offset;
-       offset = y * crtc->fb->pitches[0] + x * (crtc->fb->bits_per_pixel / 8);
+       offset = y * crtc->primary->fb->pitches[0] + x * (crtc->primary->fb->bits_per_pixel / 8);
 
-       REG_WRITE(map->stride, crtc->fb->pitches[0]);
+       REG_WRITE(map->stride, crtc->primary->fb->pitches[0]);
 
        dspcntr = REG_READ(map->cntr);
        dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
                dspcntr |= DISPPLANE_8BPP;
                break;
        case 16:
-               if (crtc->fb->depth == 15)
+               if (crtc->primary->fb->depth == 15)
                        dspcntr |= DISPPLANE_15_16BPP;
                else
                        dspcntr |= DISPPLANE_16BPP;
index 3815314..cf018dd 100644 (file)
@@ -523,13 +523,6 @@ static int oaktrail_hdmi_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
-static bool oaktrail_hdmi_mode_fixup(struct drm_encoder *encoder,
-                                const struct drm_display_mode *mode,
-                                struct drm_display_mode *adjusted_mode)
-{
-       return true;
-}
-
 static enum drm_connector_status
 oaktrail_hdmi_detect(struct drm_connector *connector, bool force)
 {
@@ -608,7 +601,7 @@ static void oaktrail_hdmi_destroy(struct drm_connector *connector)
 
 static const struct drm_encoder_helper_funcs oaktrail_hdmi_helper_funcs = {
        .dpms = oaktrail_hdmi_dpms,
-       .mode_fixup = oaktrail_hdmi_mode_fixup,
+       .mode_fixup = gma_encoder_mode_fixup,
        .prepare = gma_encoder_prepare,
        .mode_set = oaktrail_hdmi_mode_set,
        .commit = gma_encoder_commit,
index 5e06978..9b09946 100644 (file)
@@ -359,6 +359,7 @@ void oaktrail_lvds_init(struct drm_device *dev,
         *    if closed, act like it's not there for now
         */
 
+       mutex_lock(&dev->mode_config.mutex);
        i2c_adap = i2c_get_adapter(dev_priv->ops->i2c_bus);
        if (i2c_adap == NULL)
                dev_err(dev->dev, "No ddc adapter available!\n");
@@ -401,10 +402,14 @@ void oaktrail_lvds_init(struct drm_device *dev,
        }
 
 out:
+       mutex_unlock(&dev->mode_config.mutex);
+
        drm_sysfs_connector_add(connector);
        return;
 
 failed_find:
+       mutex_unlock(&dev->mode_config.mutex);
+
        dev_dbg(dev->dev, "No LVDS modes found, disabling.\n");
        if (gma_encoder->ddc_bus)
                psb_intel_i2c_destroy(gma_encoder->ddc_bus);
index 13ec628..ab696ca 100644 (file)
@@ -173,10 +173,13 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
        return 0;
 }
 
-void psb_intel_opregion_asle_intr(struct drm_device *dev)
+static void psb_intel_opregion_asle_work(struct work_struct *work)
 {
-       struct drm_psb_private *dev_priv = dev->dev_private;
-       struct opregion_asle *asle = dev_priv->opregion.asle;
+       struct psb_intel_opregion *opregion =
+               container_of(work, struct psb_intel_opregion, asle_work);
+       struct drm_psb_private *dev_priv =
+               container_of(opregion, struct drm_psb_private, opregion);
+       struct opregion_asle *asle = opregion->asle;
        u32 asle_stat = 0;
        u32 asle_req;
 
@@ -190,9 +193,18 @@ void psb_intel_opregion_asle_intr(struct drm_device *dev)
        }
 
        if (asle_req & ASLE_SET_BACKLIGHT)
-               asle_stat |= asle_set_backlight(dev, asle->bclp);
+               asle_stat |= asle_set_backlight(dev_priv->dev, asle->bclp);
 
        asle->aslc = asle_stat;
+
+}
+
+void psb_intel_opregion_asle_intr(struct drm_device *dev)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+
+       if (dev_priv->opregion.asle)
+               schedule_work(&dev_priv->opregion.asle_work);
 }
 
 #define ASLE_ALS_EN    (1<<0)
@@ -282,6 +294,8 @@ void psb_intel_opregion_fini(struct drm_device *dev)
                unregister_acpi_notifier(&psb_intel_opregion_notifier);
        }
 
+       cancel_work_sync(&opregion->asle_work);
+
        /* just clear all opregion memory pointers now */
        iounmap(opregion->header);
        opregion->header = NULL;
@@ -304,6 +318,9 @@ int psb_intel_opregion_setup(struct drm_device *dev)
                DRM_DEBUG_DRIVER("ACPI Opregion not supported\n");
                return -ENOTSUPP;
        }
+
+       INIT_WORK(&opregion->asle_work, psb_intel_opregion_asle_work);
+
        DRM_DEBUG("OpRegion detected at 0x%8x\n", opregion_phy);
        base = acpi_os_ioremap(opregion_phy, 8*1024);
        if (!base)
index 23fb33f..07df7d4 100644 (file)
@@ -26,6 +26,7 @@
 #include "psb_intel_reg.h"
 #include "intel_bios.h"
 #include "psb_device.h"
+#include "gma_device.h"
 
 static int psb_output_init(struct drm_device *dev)
 {
@@ -257,45 +258,6 @@ static int psb_power_up(struct drm_device *dev)
        return 0;
 }
 
-static void psb_get_core_freq(struct drm_device *dev)
-{
-       uint32_t clock;
-       struct pci_dev *pci_root = pci_get_bus_and_slot(0, 0);
-       struct drm_psb_private *dev_priv = dev->dev_private;
-
-       /*pci_write_config_dword(pci_root, 0xD4, 0x00C32004);*/
-       /*pci_write_config_dword(pci_root, 0xD0, 0xE0033000);*/
-
-       pci_write_config_dword(pci_root, 0xD0, 0xD0050300);
-       pci_read_config_dword(pci_root, 0xD4, &clock);
-       pci_dev_put(pci_root);
-
-       switch (clock & 0x07) {
-       case 0:
-               dev_priv->core_freq = 100;
-               break;
-       case 1:
-               dev_priv->core_freq = 133;
-               break;
-       case 2:
-               dev_priv->core_freq = 150;
-               break;
-       case 3:
-               dev_priv->core_freq = 178;
-               break;
-       case 4:
-               dev_priv->core_freq = 200;
-               break;
-       case 5:
-       case 6:
-       case 7:
-               dev_priv->core_freq = 266;
-               break;
-       default:
-               dev_priv->core_freq = 0;
-       }
-}
-
 /* Poulsbo */
 static const struct psb_offset psb_regmap[2] = {
        {
@@ -352,7 +314,7 @@ static int psb_chip_setup(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
        dev_priv->regmap = psb_regmap;
-       psb_get_core_freq(dev);
+       gma_get_core_freq(dev);
        gma_intel_setup_gmbus(dev);
        psb_intel_opregion_init(dev);
        psb_intel_init_bios(dev);
index 1199180..b686e56 100644 (file)
@@ -21,7 +21,6 @@
 
 #include <drm/drmP.h>
 #include <drm/drm.h>
-#include <drm/gma_drm.h>
 #include "psb_drv.h"
 #include "framebuffer.h"
 #include "psb_reg.h"
 #include <acpi/video.h>
 #include <linux/module.h>
 
-static int drm_psb_trap_pagefaults;
-
-static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
-
-MODULE_PARM_DESC(trap_pagefaults, "Error and reset on MMU pagefaults");
-module_param_named(trap_pagefaults, drm_psb_trap_pagefaults, int, 0600);
-
+static struct drm_driver driver;
+static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent);
 
+/*
+ * The table below contains a mapping of the PCI vendor ID and the PCI Device ID
+ * to the different groups of PowerVR 5-series chip designs
+ *
+ * 0x8086 = Intel Corporation
+ *
+ * PowerVR SGX535    - Poulsbo    - Intel GMA 500, Intel Atom Z5xx
+ * PowerVR SGX535    - Moorestown - Intel GMA 600
+ * PowerVR SGX535    - Oaktrail   - Intel GMA 600, Intel Atom Z6xx, E6xx
+ * PowerVR SGX540    - Medfield   - Intel Atom Z2460
+ * PowerVR SGX544MP2 - Medfield   -
+ * PowerVR SGX545    - Cedartrail - Intel GMA 3600, Intel Atom D2500, N2600
+ * PowerVR SGX545    - Cedartrail - Intel GMA 3650, Intel Atom D2550, D2700,
+ *                                  N2800
+ */
 static DEFINE_PCI_DEVICE_TABLE(pciidlist) = {
        { 0x8086, 0x8108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops },
        { 0x8086, 0x8109, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &psb_chip_ops },
 #if defined(CONFIG_DRM_GMA600)
-       { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
-       { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
-       { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
-       { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
-       { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
-       { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
-       { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
-       { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
-       /* Atom E620 */
-       { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops},
+       { 0x8086, 0x4100, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
+       { 0x8086, 0x4101, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
+       { 0x8086, 0x4102, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
+       { 0x8086, 0x4103, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
+       { 0x8086, 0x4104, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
+       { 0x8086, 0x4105, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
+       { 0x8086, 0x4106, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
+       { 0x8086, 0x4107, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
+       { 0x8086, 0x4108, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &oaktrail_chip_ops },
 #endif
 #if defined(CONFIG_DRM_MEDFIELD)
-       {0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
-       {0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
-       {0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
-       {0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
-       {0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
-       {0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
-       {0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
-       {0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops},
+       { 0x8086, 0x0130, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops },
+       { 0x8086, 0x0131, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops },
+       { 0x8086, 0x0132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops },
+       { 0x8086, 0x0133, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops },
+       { 0x8086, 0x0134, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops },
+       { 0x8086, 0x0135, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops },
+       { 0x8086, 0x0136, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops },
+       { 0x8086, 0x0137, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &mdfld_chip_ops },
 #endif
 #if defined(CONFIG_DRM_GMA3600)
-       { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
-       { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops},
+       { 0x8086, 0x0be0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0be1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0be2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0be3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0be4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0be5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0be6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0be7, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0be8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0be9, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0bea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0beb, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0bec, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0bed, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0bee, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
+       { 0x8086, 0x0bef, PCI_ANY_ID, PCI_ANY_ID, 0, 0, (long) &cdv_chip_ops },
 #endif
        { 0, }
 };
@@ -95,59 +103,10 @@ MODULE_DEVICE_TABLE(pci, pciidlist);
 /*
  * Standard IOCTLs.
  */
-
-#define DRM_IOCTL_GMA_ADB      \
-               DRM_IOWR(DRM_GMA_ADB + DRM_COMMAND_BASE, uint32_t)
-#define DRM_IOCTL_GMA_MODE_OPERATION   \
-               DRM_IOWR(DRM_GMA_MODE_OPERATION + DRM_COMMAND_BASE, \
-                        struct drm_psb_mode_operation_arg)
-#define DRM_IOCTL_GMA_STOLEN_MEMORY    \
-               DRM_IOWR(DRM_GMA_STOLEN_MEMORY + DRM_COMMAND_BASE, \
-                        struct drm_psb_stolen_memory_arg)
-#define DRM_IOCTL_GMA_GAMMA    \
-               DRM_IOWR(DRM_GMA_GAMMA + DRM_COMMAND_BASE, \
-                        struct drm_psb_dpst_lut_arg)
-#define DRM_IOCTL_GMA_DPST_BL  \
-               DRM_IOWR(DRM_GMA_DPST_BL + DRM_COMMAND_BASE, \
-                        uint32_t)
-#define DRM_IOCTL_GMA_GET_PIPE_FROM_CRTC_ID    \
-               DRM_IOWR(DRM_GMA_GET_PIPE_FROM_CRTC_ID + DRM_COMMAND_BASE, \
-                        struct drm_psb_get_pipe_from_crtc_id_arg)
-#define DRM_IOCTL_GMA_GEM_CREATE       \
-               DRM_IOWR(DRM_GMA_GEM_CREATE + DRM_COMMAND_BASE, \
-                        struct drm_psb_gem_create)
-#define DRM_IOCTL_GMA_GEM_MMAP \
-               DRM_IOWR(DRM_GMA_GEM_MMAP + DRM_COMMAND_BASE, \
-                        struct drm_psb_gem_mmap)
-
-static int psb_adb_ioctl(struct drm_device *dev, void *data,
-                        struct drm_file *file_priv);
-static int psb_mode_operation_ioctl(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv);
-static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data,
-                                  struct drm_file *file_priv);
-static int psb_gamma_ioctl(struct drm_device *dev, void *data,
-                          struct drm_file *file_priv);
-static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data,
-                            struct drm_file *file_priv);
-
 static const struct drm_ioctl_desc psb_ioctls[] = {
-       DRM_IOCTL_DEF_DRV(GMA_ADB, psb_adb_ioctl, DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(GMA_MODE_OPERATION, psb_mode_operation_ioctl,
-                     DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(GMA_STOLEN_MEMORY, psb_stolen_memory_ioctl,
-                     DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(GMA_GAMMA, psb_gamma_ioctl, DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(GMA_DPST_BL, psb_dpst_bl_ioctl, DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(GMA_GET_PIPE_FROM_CRTC_ID,
-                                       psb_intel_get_pipe_from_crtc_id, 0),
-       DRM_IOCTL_DEF_DRV(GMA_GEM_CREATE, psb_gem_create_ioctl,
-                                               DRM_UNLOCKED | DRM_AUTH),
-       DRM_IOCTL_DEF_DRV(GMA_GEM_MMAP, psb_gem_mmap_ioctl,
-                                               DRM_UNLOCKED | DRM_AUTH),
 };
 
-static void psb_lastclose(struct drm_device *dev)
+static void psb_driver_lastclose(struct drm_device *dev)
 {
        int ret;
        struct drm_psb_private *dev_priv = dev->dev_private;
@@ -169,19 +128,14 @@ static int psb_do_init(struct drm_device *dev)
 
        uint32_t stolen_gtt;
 
-       int ret = -ENOMEM;
-
        if (pg->mmu_gatt_start & 0x0FFFFFFF) {
                dev_err(dev->dev, "Gatt must be 256M aligned. This is a bug.\n");
-               ret = -EINVAL;
-               goto out_err;
+               return -EINVAL;
        }
 
-
        stolen_gtt = (pg->stolen_size >> PAGE_SHIFT) * 4;
        stolen_gtt = (stolen_gtt + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       stolen_gtt =
-           (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages;
+       stolen_gtt = (stolen_gtt < pg->gtt_pages) ? stolen_gtt : pg->gtt_pages;
 
        dev_priv->gatt_free_offset = pg->mmu_gatt_start +
            (stolen_gtt << PAGE_SHIFT) * 1024;
@@ -192,23 +146,26 @@ static int psb_do_init(struct drm_device *dev)
        PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK0);
        PSB_WSGX32(0x00000000, PSB_CR_BIF_BANK1);
        PSB_RSGX32(PSB_CR_BIF_BANK1);
-       PSB_WSGX32(PSB_RSGX32(PSB_CR_BIF_CTRL) | _PSB_MMU_ER_MASK,
-                                                       PSB_CR_BIF_CTRL);
+
+       /* Do not bypass any MMU access, let them pagefault instead */
+       PSB_WSGX32((PSB_RSGX32(PSB_CR_BIF_CTRL) & ~_PSB_MMU_ER_MASK),
+                  PSB_CR_BIF_CTRL);
+       PSB_RSGX32(PSB_CR_BIF_CTRL);
+
        psb_spank(dev_priv);
 
        /* mmu_gatt ?? */
        PSB_WSGX32(pg->gatt_start, PSB_CR_BIF_TWOD_REQ_BASE);
+       PSB_RSGX32(PSB_CR_BIF_TWOD_REQ_BASE); /* Post */
+
        return 0;
-out_err:
-       return ret;
 }
 
 static int psb_driver_unload(struct drm_device *dev)
 {
        struct drm_psb_private *dev_priv = dev->dev_private;
 
-       /* Kill vblank etc here */
-
+       /* TODO: Kill vblank etc here */
 
        if (dev_priv) {
                if (dev_priv->backlight_device)
@@ -268,8 +225,7 @@ static int psb_driver_unload(struct drm_device *dev)
        return 0;
 }
 
-
-static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
+static int psb_driver_load(struct drm_device *dev, unsigned long flags)
 {
        struct drm_psb_private *dev_priv;
        unsigned long resource_start, resource_len;
@@ -277,15 +233,19 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
        int ret = -ENOMEM;
        struct drm_connector *connector;
        struct gma_encoder *gma_encoder;
+       struct psb_gtt *pg;
 
+       /* allocating and initializing driver private data */
        dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
        if (dev_priv == NULL)
                return -ENOMEM;
 
-       dev_priv->ops = (struct psb_ops *)chipset;
+       dev_priv->ops = (struct psb_ops *)flags;
        dev_priv->dev = dev;
        dev->dev_private = (void *) dev_priv;
 
+       pg = &dev_priv->gtt;
+
        pci_set_master(dev->pdev);
 
        dev_priv->num_pipe = dev_priv->ops->pipes;
@@ -347,9 +307,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
        if (ret)
                goto out_err;
 
-       dev_priv->mmu = psb_mmu_driver_init((void *)0,
-                                       drm_psb_trap_pagefaults, 0,
-                                       dev_priv);
+       dev_priv->mmu = psb_mmu_driver_init(dev, 1, 0, 0);
        if (!dev_priv->mmu)
                goto out_err;
 
@@ -357,18 +315,27 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
        if (!dev_priv->pf_pd)
                goto out_err;
 
-       psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0);
-       psb_mmu_set_pd_context(dev_priv->pf_pd, 1);
-
        ret = psb_do_init(dev);
        if (ret)
                return ret;
 
+       /* Add stolen memory to SGX MMU */
+       down_read(&pg->sem);
+       ret = psb_mmu_insert_pfn_sequence(psb_mmu_get_default_pd(dev_priv->mmu),
+                                         dev_priv->stolen_base >> PAGE_SHIFT,
+                                         pg->gatt_start,
+                                         pg->stolen_size >> PAGE_SHIFT, 0);
+       up_read(&pg->sem);
+
+       psb_mmu_set_pd_context(psb_mmu_get_default_pd(dev_priv->mmu), 0);
+       psb_mmu_set_pd_context(dev_priv->pf_pd, 1);
+
        PSB_WSGX32(0x20000000, PSB_CR_PDS_EXEC_BASE);
        PSB_WSGX32(0x30000000, PSB_CR_BIF_3D_REQ_BASE);
 
        acpi_video_register();
 
+       /* Setup vertical blanking handling */
        ret = drm_vblank_init(dev, dev_priv->num_pipe);
        if (ret)
                goto out_err;
@@ -390,9 +357,7 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
        drm_irq_install(dev);
 
        dev->vblank_disable_allowed = true;
-
        dev->max_vblank_count = 0xffffff; /* only 24 bits of frame count */
-
        dev->driver->get_vblank_counter = psb_get_vblank_counter;
 
        psb_modeset_init(dev);
@@ -416,11 +381,11 @@ static int psb_driver_load(struct drm_device *dev, unsigned long chipset)
                return ret;
        psb_intel_opregion_enable_asle(dev);
 #if 0
-       /*enable runtime pm at last*/
+       /* Enable runtime pm at last */
        pm_runtime_enable(&dev->pdev->dev);
        pm_runtime_set_active(&dev->pdev->dev);
 #endif
-       /*Intel drm driver load is done, continue doing pvr load*/
+       /* Intel drm driver load is done, continue doing pvr load */
        return 0;
 out_err:
        psb_driver_unload(dev);
@@ -442,161 +407,6 @@ static inline void get_brightness(struct backlight_device *bd)
 #endif
 }
 
-static int psb_dpst_bl_ioctl(struct drm_device *dev, void *data,
-                      struct drm_file *file_priv)
-{
-       struct drm_psb_private *dev_priv = psb_priv(dev);
-       uint32_t *arg = data;
-
-       dev_priv->blc_adj2 = *arg;
-       get_brightness(dev_priv->backlight_device);
-       return 0;
-}
-
-static int psb_adb_ioctl(struct drm_device *dev, void *data,
-                       struct drm_file *file_priv)
-{
-       struct drm_psb_private *dev_priv = psb_priv(dev);
-       uint32_t *arg = data;
-
-       dev_priv->blc_adj1 = *arg;
-       get_brightness(dev_priv->backlight_device);
-       return 0;
-}
-
-static int psb_gamma_ioctl(struct drm_device *dev, void *data,
-                          struct drm_file *file_priv)
-{
-       struct drm_psb_dpst_lut_arg *lut_arg = data;
-       struct drm_mode_object *obj;
-       struct drm_crtc *crtc;
-       struct drm_connector *connector;
-       struct gma_crtc *gma_crtc;
-       int i = 0;
-       int32_t obj_id;
-
-       obj_id = lut_arg->output_id;
-       obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_CONNECTOR);
-       if (!obj) {
-               dev_dbg(dev->dev, "Invalid Connector object.\n");
-               return -ENOENT;
-       }
-
-       connector = obj_to_connector(obj);
-       crtc = connector->encoder->crtc;
-       gma_crtc = to_gma_crtc(crtc);
-
-       for (i = 0; i < 256; i++)
-               gma_crtc->lut_adj[i] = lut_arg->lut[i];
-
-       gma_crtc_load_lut(crtc);
-
-       return 0;
-}
-
-static int psb_mode_operation_ioctl(struct drm_device *dev, void *data,
-                               struct drm_file *file_priv)
-{
-       uint32_t obj_id;
-       uint16_t op;
-       struct drm_mode_modeinfo *umode;
-       struct drm_display_mode *mode = NULL;
-       struct drm_psb_mode_operation_arg *arg;
-       struct drm_mode_object *obj;
-       struct drm_connector *connector;
-       struct drm_connector_helper_funcs *connector_funcs;
-       int ret = 0;
-       int resp = MODE_OK;
-
-       arg = (struct drm_psb_mode_operation_arg *)data;
-       obj_id = arg->obj_id;
-       op = arg->operation;
-
-       switch (op) {
-       case PSB_MODE_OPERATION_MODE_VALID:
-               umode = &arg->mode;
-
-               drm_modeset_lock_all(dev);
-
-               obj = drm_mode_object_find(dev, obj_id,
-                                       DRM_MODE_OBJECT_CONNECTOR);
-               if (!obj) {
-                       ret = -ENOENT;
-                       goto mode_op_out;
-               }
-
-               connector = obj_to_connector(obj);
-
-               mode = drm_mode_create(dev);
-               if (!mode) {
-                       ret = -ENOMEM;
-                       goto mode_op_out;
-               }
-
-               /* drm_crtc_convert_umode(mode, umode); */
-               {
-                       mode->clock = umode->clock;
-                       mode->hdisplay = umode->hdisplay;
-                       mode->hsync_start = umode->hsync_start;
-                       mode->hsync_end = umode->hsync_end;
-                       mode->htotal = umode->htotal;
-                       mode->hskew = umode->hskew;
-                       mode->vdisplay = umode->vdisplay;
-                       mode->vsync_start = umode->vsync_start;
-                       mode->vsync_end = umode->vsync_end;
-                       mode->vtotal = umode->vtotal;
-                       mode->vscan = umode->vscan;
-                       mode->vrefresh = umode->vrefresh;
-                       mode->flags = umode->flags;
-                       mode->type = umode->type;
-                       strncpy(mode->name, umode->name, DRM_DISPLAY_MODE_LEN);
-                       mode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
-               }
-
-               connector_funcs = (struct drm_connector_helper_funcs *)
-                                  connector->helper_private;
-
-               if (connector_funcs->mode_valid) {
-                       resp = connector_funcs->mode_valid(connector, mode);
-                       arg->data = resp;
-               }
-
-               /*do some clean up work*/
-               if (mode)
-                       drm_mode_destroy(dev, mode);
-mode_op_out:
-               drm_modeset_unlock_all(dev);
-               return ret;
-
-       default:
-               dev_dbg(dev->dev, "Unsupported psb mode operation\n");
-               return -EOPNOTSUPP;
-       }
-
-       return 0;
-}
-
-static int psb_stolen_memory_ioctl(struct drm_device *dev, void *data,
-                                  struct drm_file *file_priv)
-{
-       struct drm_psb_private *dev_priv = psb_priv(dev);
-       struct drm_psb_stolen_memory_arg *arg = data;
-
-       arg->base = dev_priv->stolen_base;
-       arg->size = dev_priv->vram_stolen_size;
-
-       return 0;
-}
-
-static int psb_driver_open(struct drm_device *dev, struct drm_file *priv)
-{
-       return 0;
-}
-
-static void psb_driver_close(struct drm_device *dev, struct drm_file *priv)
-{
-}
-
 static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd,
                               unsigned long arg)
 {
@@ -614,15 +424,21 @@ static long psb_unlocked_ioctl(struct file *filp, unsigned int cmd,
        /* FIXME: do we need to wrap the other side of this */
 }
 
-
-/* When a client dies:
+/*
+ * When a client dies:
  *    - Check for and clean up flipped page state
  */
 static void psb_driver_preclose(struct drm_device *dev, struct drm_file *priv)
 {
 }
 
-static void psb_remove(struct pci_dev *pdev)
+static int psb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       return drm_get_pci_dev(pdev, ent, &driver);
+}
+
+
+static void psb_pci_remove(struct pci_dev *pdev)
 {
        struct drm_device *dev = pci_get_drvdata(pdev);
        drm_put_dev(dev);
@@ -657,11 +473,12 @@ static const struct file_operations psb_gem_fops = {
 
 static struct drm_driver driver = {
        .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | \
-                          DRIVER_MODESET | DRIVER_GEM ,
+                          DRIVER_MODESET | DRIVER_GEM,
        .load = psb_driver_load,
        .unload = psb_driver_unload,
+       .lastclose = psb_driver_lastclose,
+       .preclose = psb_driver_preclose,
 
-       .ioctls = psb_ioctls,
        .num_ioctls = DRM_ARRAY_SIZE(psb_ioctls),
        .device_is_agp = psb_driver_device_is_agp,
        .irq_preinstall = psb_irq_preinstall,
@@ -671,40 +488,31 @@ static struct drm_driver driver = {
        .enable_vblank = psb_enable_vblank,
        .disable_vblank = psb_disable_vblank,
        .get_vblank_counter = psb_get_vblank_counter,
-       .lastclose = psb_lastclose,
-       .open = psb_driver_open,
-       .preclose = psb_driver_preclose,
-       .postclose = psb_driver_close,
 
        .gem_free_object = psb_gem_free_object,
        .gem_vm_ops = &psb_gem_vm_ops,
+
        .dumb_create = psb_gem_dumb_create,
        .dumb_map_offset = psb_gem_dumb_map_gtt,
        .dumb_destroy = drm_gem_dumb_destroy,
+       .ioctls = psb_ioctls,
        .fops = &psb_gem_fops,
        .name = DRIVER_NAME,
        .desc = DRIVER_DESC,
-       .date = PSB_DRM_DRIVER_DATE,
-       .major = PSB_DRM_DRIVER_MAJOR,
-       .minor = PSB_DRM_DRIVER_MINOR,
-       .patchlevel = PSB_DRM_DRIVER_PATCHLEVEL
+       .date = DRIVER_DATE,
+       .major = DRIVER_MAJOR,
+       .minor = DRIVER_MINOR,
+       .patchlevel = DRIVER_PATCHLEVEL
 };
 
 static struct pci_driver psb_pci_driver = {
        .name = DRIVER_NAME,
        .id_table = pciidlist,
-       .probe = psb_probe,
-       .remove = psb_remove,
-       .driver = {
-               .pm = &psb_pm_ops,
-       }
+       .probe = psb_pci_probe,
+       .remove = psb_pci_remove,
+       .driver.pm = &psb_pm_ops,
 };
 
-static int psb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-       return drm_get_pci_dev(pdev, ent, &driver);
-}
-
 static int __init psb_init(void)
 {
        return drm_pci_init(&driver, &psb_pci_driver);
@@ -718,6 +526,6 @@ static void __exit psb_exit(void)
 late_initcall(psb_init);
 module_exit(psb_exit);
 
-MODULE_AUTHOR("Alan Cox <alan@linux.intel.com> and others");
+MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE(DRIVER_LICENSE);
index 5ad6a03..55ebe2b 100644 (file)
 #include "power.h"
 #include "opregion.h"
 #include "oaktrail.h"
+#include "mmu.h"
+
+#define DRIVER_AUTHOR "Alan Cox <alan@linux.intel.com> and others"
+#define DRIVER_LICENSE "GPL"
+
+#define DRIVER_NAME "gma500"
+#define DRIVER_DESC "DRM driver for the Intel GMA500, GMA600, GMA3600, GMA3650"
+#define DRIVER_DATE "20140314"
+
+#define DRIVER_MAJOR 1
+#define DRIVER_MINOR 0
+#define DRIVER_PATCHLEVEL 0
 
 /* Append new drm mode definition here, align with libdrm definition */
 #define DRM_MODE_SCALE_NO_SCALE        2
@@ -49,21 +61,7 @@ enum {
 #define IS_MFLD(dev) (((dev)->pdev->device & 0xfff8) == 0x0130)
 #define IS_CDV(dev) (((dev)->pdev->device & 0xfff0) == 0x0be0)
 
-/*
- * Driver definitions
- */
-
-#define DRIVER_NAME "gma500"
-#define DRIVER_DESC "DRM driver for the Intel GMA500"
-
-#define PSB_DRM_DRIVER_DATE "2011-06-06"
-#define PSB_DRM_DRIVER_MAJOR 1
-#define PSB_DRM_DRIVER_MINOR 0
-#define PSB_DRM_DRIVER_PATCHLEVEL 0
-
-/*
- *     Hardware offsets
- */
+/* Hardware offsets */
 #define PSB_VDC_OFFSET          0x00000000
 #define PSB_VDC_SIZE            0x000080000
 #define MRST_MMIO_SIZE          0x0000C0000
@@ -71,16 +69,14 @@ enum {
 #define PSB_SGX_SIZE            0x8000
 #define PSB_SGX_OFFSET          0x00040000
 #define MRST_SGX_OFFSET                 0x00080000
-/*
- *     PCI resource identifiers
- */
+
+/* PCI resource identifiers */
 #define PSB_MMIO_RESOURCE       0
 #define PSB_AUX_RESOURCE        0
 #define PSB_GATT_RESOURCE       2
 #define PSB_GTT_RESOURCE        3
-/*
- *     PCI configuration
- */
+
+/* PCI configuration */
 #define PSB_GMCH_CTRL           0x52
 #define PSB_BSM                         0x5C
 #define _PSB_GMCH_ENABLED       0x4
@@ -88,37 +84,29 @@ enum {
 #define _PSB_PGETBL_ENABLED     0x00000001
 #define PSB_SGX_2D_SLAVE_PORT   0x4000
 
-/* To get rid of */
+/* TODO: To get rid of */
 #define PSB_TT_PRIV0_LIMIT      (256*1024*1024)
 #define PSB_TT_PRIV0_PLIMIT     (PSB_TT_PRIV0_LIMIT >> PAGE_SHIFT)
 
-/*
- *     SGX side MMU definitions (these can probably go)
- */
+/* SGX side MMU definitions (these can probably go) */
 
-/*
- *     Flags for external memory type field.
- */
+/* Flags for external memory type field */
 #define PSB_MMU_CACHED_MEMORY    0x0001        /* Bind to MMU only */
 #define PSB_MMU_RO_MEMORY        0x0002        /* MMU RO memory */
 #define PSB_MMU_WO_MEMORY        0x0004        /* MMU WO memory */
-/*
- *     PTE's and PDE's
- */
+
+/* PTE's and PDE's */
 #define PSB_PDE_MASK             0x003FFFFF
 #define PSB_PDE_SHIFT            22
 #define PSB_PTE_SHIFT            12
-/*
- *     Cache control
- */
+
+/* Cache control */
 #define PSB_PTE_VALID            0x0001        /* PTE / PDE valid */
 #define PSB_PTE_WO               0x0002        /* Write only */
 #define PSB_PTE_RO               0x0004        /* Read only */
 #define PSB_PTE_CACHED           0x0008        /* CPU cache coherent */
 
-/*
- *     VDC registers and bits
- */
+/* VDC registers and bits */
 #define PSB_MSVDX_CLOCKGATING    0x2064
 #define PSB_TOPAZ_CLOCKGATING    0x2068
 #define PSB_HWSTAM               0x2098
@@ -265,6 +253,7 @@ struct psb_intel_opregion {
        struct opregion_asle *asle;
        void *vbt;
        u32 __iomem *lid_state;
+       struct work_struct asle_work;
 };
 
 struct sdvo_device_mapping {
@@ -283,10 +272,7 @@ struct intel_gmbus {
        u32 reg0;
 };
 
-/*
- *     Register offset maps
- */
-
+/* Register offset maps */
 struct psb_offset {
        u32     fp0;
        u32     fp1;
@@ -320,9 +306,7 @@ struct psb_offset {
  *     update the register cache instead.
  */
 
-/*
- *     Common status for pipes.
- */
+/* Common status for pipes */
 struct psb_pipe {
        u32     fp0;
        u32     fp1;
@@ -482,35 +466,24 @@ struct drm_psb_private {
        struct psb_mmu_driver *mmu;
        struct psb_mmu_pd *pf_pd;
 
-       /*
-        * Register base
-        */
-
+       /* Register base */
        uint8_t __iomem *sgx_reg;
        uint8_t __iomem *vdc_reg;
        uint8_t __iomem *aux_reg; /* Auxillary vdc pipe regs */
        uint32_t gatt_free_offset;
 
-       /*
-        * Fencing / irq.
-        */
-
+       /* Fencing / irq */
        uint32_t vdc_irq_mask;
        uint32_t pipestat[PSB_NUM_PIPE];
 
        spinlock_t irqmask_lock;
 
-       /*
-        * Power
-        */
-
+       /* Power */
        bool suspended;
        bool display_power;
        int display_count;
 
-       /*
-        * Modesetting
-        */
+       /* Modesetting */
        struct psb_intel_mode_device mode_dev;
        bool modeset;   /* true if we have done the mode_device setup */
 
@@ -518,15 +491,10 @@ struct drm_psb_private {
        struct drm_crtc *pipe_to_crtc_mapping[PSB_NUM_PIPE];
        uint32_t num_pipe;
 
-       /*
-        * OSPM info (Power management base) (can go ?)
-        */
+       /* OSPM info (Power management base) (TODO: can go ?) */
        uint32_t ospm_base;
 
-       /*
-        * Sizes info
-        */
-
+       /* Sizes info */
        u32 fuse_reg_value;
        u32 video_device_fuse;
 
@@ -546,9 +514,7 @@ struct drm_psb_private {
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 
-       /*
-        * LVDS info
-        */
+       /* LVDS info */
        int backlight_duty_cycle;       /* restore backlight to this value */
        bool panel_wants_dither;
        struct drm_display_mode *panel_fixed_mode;
@@ -582,34 +548,23 @@ struct drm_psb_private {
        /* Oaktrail HDMI state */
        struct oaktrail_hdmi_dev *hdmi_priv;
        
-       /*
-        * Register state
-        */
-
+       /* Register state */
        struct psb_save_area regs;
 
        /* MSI reg save */
        uint32_t msi_addr;
        uint32_t msi_data;
 
-       /*
-        * Hotplug handling
-        */
-
+       /* Hotplug handling */
        struct work_struct hotplug_work;
 
-       /*
-        * LID-Switch
-        */
+       /* LID-Switch */
        spinlock_t lid_lock;
        struct timer_list lid_timer;
        struct psb_intel_opregion opregion;
        u32 lid_last_state;
 
-       /*
-        * Watchdog
-        */
-
+       /* Watchdog */
        uint32_t apm_reg;
        uint16_t apm_base;
 
@@ -629,9 +584,7 @@ struct drm_psb_private {
        /* 2D acceleration */
        spinlock_t lock_2d;
 
-       /*
-        * Panel brightness
-        */
+       /* Panel brightness */
        int brightness;
        int brightness_adjusted;
 
@@ -664,10 +617,7 @@ struct drm_psb_private {
 };
 
 
-/*
- *     Operations for each board type
- */
+/* Operations for each board type */
 struct psb_ops {
        const char *name;
        unsigned int accel_2d:1;
@@ -713,8 +663,6 @@ struct psb_ops {
 
 
 
-struct psb_mmu_driver;
-
 extern int drm_crtc_probe_output_modes(struct drm_device *dev, int, int);
 extern int drm_pick_crtcs(struct drm_device *dev);
 
@@ -723,52 +671,7 @@ static inline struct drm_psb_private *psb_priv(struct drm_device *dev)
        return (struct drm_psb_private *) dev->dev_private;
 }
 
-/*
- * MMU stuff.
- */
-
-extern struct psb_mmu_driver *psb_mmu_driver_init(uint8_t __iomem * registers,
-                                       int trap_pagefaults,
-                                       int invalid_type,
-                                       struct drm_psb_private *dev_priv);
-extern void psb_mmu_driver_takedown(struct psb_mmu_driver *driver);
-extern struct psb_mmu_pd *psb_mmu_get_default_pd(struct psb_mmu_driver
-                                                *driver);
-extern void psb_mmu_mirror_gtt(struct psb_mmu_pd *pd, uint32_t mmu_offset,
-                              uint32_t gtt_start, uint32_t gtt_pages);
-extern struct psb_mmu_pd *psb_mmu_alloc_pd(struct psb_mmu_driver *driver,
-                                          int trap_pagefaults,
-                                          int invalid_type);
-extern void psb_mmu_free_pagedir(struct psb_mmu_pd *pd);
-extern void psb_mmu_flush(struct psb_mmu_driver *driver, int rc_prot);
-extern void psb_mmu_remove_pfn_sequence(struct psb_mmu_pd *pd,
-                                       unsigned long address,
-                                       uint32_t num_pages);
-extern int psb_mmu_insert_pfn_sequence(struct psb_mmu_pd *pd,
-                                      uint32_t start_pfn,
-                                      unsigned long address,
-                                      uint32_t num_pages, int type);
-extern int psb_mmu_virtual_to_pfn(struct psb_mmu_pd *pd, uint32_t virtual,
-                                 unsigned long *pfn);
-
-/*
- * Enable / disable MMU for different requestors.
- */
-
-
-extern void psb_mmu_set_pd_context(struct psb_mmu_pd *pd, int hw_context);
-extern int psb_mmu_insert_pages(struct psb_mmu_pd *pd, struct page **pages,
-                               unsigned long address, uint32_t num_pages,
-                               uint32_t desired_tile_stride,
-                               uint32_t hw_tile_stride, int type);
-extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd,
-                                unsigned long address, uint32_t num_pages,
-                                uint32_t desired_tile_stride,
-                                uint32_t hw_tile_stride);
-/*
- *psb_irq.c
- */
-
+/* psb_irq.c */
 extern irqreturn_t psb_irq_handler(int irq, void *arg);
 extern int psb_irq_enable_dpst(struct drm_device *dev);
 extern int psb_irq_disable_dpst(struct drm_device *dev);
@@ -791,24 +694,17 @@ psb_disable_pipestat(struct drm_psb_private *dev_priv, int pipe, u32 mask);
 
 extern u32 psb_get_vblank_counter(struct drm_device *dev, int crtc);
 
-/*
- * framebuffer.c
- */
+/* framebuffer.c */
 extern int psbfb_probed(struct drm_device *dev);
 extern int psbfb_remove(struct drm_device *dev,
                        struct drm_framebuffer *fb);
-/*
- * accel_2d.c
- */
+/* accel_2d.c */
 extern void psbfb_copyarea(struct fb_info *info,
                                        const struct fb_copyarea *region);
 extern int psbfb_sync(struct fb_info *info);
 extern void psb_spank(struct drm_psb_private *dev_priv);
 
-/*
- * psb_reset.c
- */
-
+/* psb_reset.c */
 extern void psb_lid_timer_init(struct drm_psb_private *dev_priv);
 extern void psb_lid_timer_takedown(struct drm_psb_private *dev_priv);
 extern void psb_print_pagefault(struct drm_psb_private *dev_priv);
@@ -867,9 +763,7 @@ extern const struct psb_ops mdfld_chip_ops;
 /* cdv_device.c */
 extern const struct psb_ops cdv_chip_ops;
 
-/*
- * Debug print bits setting
- */
+/* Debug print bits setting */
 #define PSB_D_GENERAL (1 << 0)
 #define PSB_D_INIT    (1 << 1)
 #define PSB_D_IRQ     (1 << 2)
@@ -885,10 +779,7 @@ extern const struct psb_ops cdv_chip_ops;
 
 extern int drm_idle_check_interval;
 
-/*
- *     Utilities
- */
-
+/* Utilities */
 static inline u32 MRST_MSG_READ32(uint port, uint offset)
 {
        int mcr = (0xD0<<24) | (port << 16) | (offset << 8);
index c8841ac..87b50ba 100644 (file)
@@ -120,7 +120,7 @@ static int psb_intel_crtc_mode_set(struct drm_crtc *crtc,
        const struct gma_limit_t *limit;
 
        /* No scan out no play */
-       if (crtc->fb == NULL) {
+       if (crtc->primary->fb == NULL) {
                crtc_funcs->mode_set_base(crtc, x, y, old_fb);
                return 0;
        }
@@ -469,7 +469,8 @@ static void psb_intel_cursor_init(struct drm_device *dev,
                /* Allocate 4 pages of stolen mem for a hardware cursor. That
                 * is enough for the 64 x 64 ARGB cursors we support.
                 */
-               cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1);
+               cursor_gt = psb_gtt_alloc_range(dev, 4 * PAGE_SIZE, "cursor", 1,
+                                               PAGE_SIZE);
                if (!cursor_gt) {
                        gma_crtc->cursor_gt = NULL;
                        goto out;
@@ -554,33 +555,6 @@ void psb_intel_crtc_init(struct drm_device *dev, int pipe,
        gma_crtc->active = true;
 }
 
-int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
-                               struct drm_file *file_priv)
-{
-       struct drm_psb_private *dev_priv = dev->dev_private;
-       struct drm_psb_get_pipe_from_crtc_id_arg *pipe_from_crtc_id = data;
-       struct drm_mode_object *drmmode_obj;
-       struct gma_crtc *crtc;
-
-       if (!dev_priv) {
-               dev_err(dev->dev, "called with no initialization\n");
-               return -EINVAL;
-       }
-
-       drmmode_obj = drm_mode_object_find(dev, pipe_from_crtc_id->crtc_id,
-                       DRM_MODE_OBJECT_CRTC);
-
-       if (!drmmode_obj) {
-               dev_err(dev->dev, "no such CRTC id\n");
-               return -ENOENT;
-       }
-
-       crtc = to_gma_crtc(obj_to_crtc(drmmode_obj));
-       pipe_from_crtc_id->pipe = crtc->pipe;
-
-       return 0;
-}
-
 struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev, int pipe)
 {
        struct drm_crtc *crtc = NULL;
index dc2c8eb..336bd3a 100644 (file)
@@ -238,8 +238,6 @@ static inline struct gma_encoder *gma_attached_encoder(
 
 extern struct drm_display_mode *psb_intel_crtc_mode_get(struct drm_device *dev,
                                                    struct drm_crtc *crtc);
-extern int psb_intel_get_pipe_from_crtc_id(struct drm_device *dev, void *data,
-                               struct drm_file *file_priv);
 extern struct drm_crtc *psb_intel_get_crtc_from_pipe(struct drm_device *dev,
                                                 int pipe);
 extern struct drm_connector *psb_intel_sdvo_find(struct drm_device *dev,
index 32342f6..d7778d0 100644 (file)
@@ -614,7 +614,7 @@ int psb_intel_lvds_set_property(struct drm_connector *connector,
                                                      &crtc->saved_mode,
                                                      encoder->crtc->x,
                                                      encoder->crtc->y,
-                                                     encoder->crtc->fb))
+                                                     encoder->crtc->primary->fb))
                                goto set_prop_error;
                }
        } else if (!strcmp(property->name, "backlight")) {
@@ -777,6 +777,7 @@ void psb_intel_lvds_init(struct drm_device *dev,
         * Attempt to get the fixed panel mode from DDC.  Assume that the
         * preferred mode is the right one.
         */
+       mutex_lock(&dev->mode_config.mutex);
        psb_intel_ddc_get_modes(connector, &lvds_priv->ddc_bus->adapter);
        list_for_each_entry(scan, &connector->probed_modes, head) {
                if (scan->type & DRM_MODE_TYPE_PREFERRED) {
@@ -827,10 +828,12 @@ void psb_intel_lvds_init(struct drm_device *dev,
         * actually having one.
         */
 out:
+       mutex_unlock(&dev->mode_config.mutex);
        drm_sysfs_connector_add(connector);
        return;
 
 failed_find:
+       mutex_unlock(&dev->mode_config.mutex);
        if (lvds_priv->ddc_bus)
                psb_intel_i2c_destroy(lvds_priv->ddc_bus);
 failed_ddc:
index 07d3a9e..deeb082 100644 (file)
@@ -406,18 +406,18 @@ static void psb_intel_sdvo_debug_write(struct psb_intel_sdvo *psb_intel_sdvo, u8
        DRM_DEBUG_KMS("%s: W: %02X ",
                                SDVO_NAME(psb_intel_sdvo), cmd);
        for (i = 0; i < args_len; i++)
-               DRM_LOG_KMS("%02X ", ((u8 *)args)[i]);
+               DRM_DEBUG_KMS("%02X ", ((u8 *)args)[i]);
        for (; i < 8; i++)
-               DRM_LOG_KMS("   ");
+               DRM_DEBUG_KMS("   ");
        for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) {
                if (cmd == sdvo_cmd_names[i].cmd) {
-                       DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name);
+                       DRM_DEBUG_KMS("(%s)", sdvo_cmd_names[i].name);
                        break;
                }
        }
        if (i == ARRAY_SIZE(sdvo_cmd_names))
-               DRM_LOG_KMS("(%02X)", cmd);
-       DRM_LOG_KMS("\n");
+               DRM_DEBUG_KMS("(%02X)", cmd);
+       DRM_DEBUG_KMS("\n");
 }
 
 static const char *cmd_status_names[] = {
@@ -512,9 +512,9 @@ static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo,
        }
 
        if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-               DRM_LOG_KMS("(%s)", cmd_status_names[status]);
+               DRM_DEBUG_KMS("(%s)", cmd_status_names[status]);
        else
-               DRM_LOG_KMS("(??? %d)", status);
+               DRM_DEBUG_KMS("(??? %d)", status);
 
        if (status != SDVO_CMD_STATUS_SUCCESS)
                goto log_fail;
@@ -525,13 +525,13 @@ static bool psb_intel_sdvo_read_response(struct psb_intel_sdvo *psb_intel_sdvo,
                                          SDVO_I2C_RETURN_0 + i,
                                          &((u8 *)response)[i]))
                        goto log_fail;
-               DRM_LOG_KMS(" %02X", ((u8 *)response)[i]);
+               DRM_DEBUG_KMS(" %02X", ((u8 *)response)[i]);
        }
-       DRM_LOG_KMS("\n");
+       DRM_DEBUG_KMS("\n");
        return true;
 
 log_fail:
-       DRM_LOG_KMS("... failed\n");
+       DRM_DEBUG_KMS("... failed\n");
        return false;
 }
 
@@ -1844,7 +1844,7 @@ done:
        if (psb_intel_sdvo->base.base.crtc) {
                struct drm_crtc *crtc = psb_intel_sdvo->base.base.crtc;
                drm_crtc_helper_set_mode(crtc, &crtc->mode, crtc->x,
-                                        crtc->y, crtc->fb);
+                                        crtc->y, crtc->primary->fb);
        }
 
        return 0;
index f883f9e..624eb36 100644 (file)
@@ -200,11 +200,64 @@ static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat)
                mid_pipe_event_handler(dev, 1);
 }
 
+/*
+ * SGX interrupt handler
+ */
+static void psb_sgx_interrupt(struct drm_device *dev, u32 stat_1, u32 stat_2)
+{
+       struct drm_psb_private *dev_priv = dev->dev_private;
+       u32 val, addr;
+       int error = false;
+
+       if (stat_1 & _PSB_CE_TWOD_COMPLETE)
+               val = PSB_RSGX32(PSB_CR_2D_BLIT_STATUS);
+
+       if (stat_2 & _PSB_CE2_BIF_REQUESTER_FAULT) {
+               val = PSB_RSGX32(PSB_CR_BIF_INT_STAT);
+               addr = PSB_RSGX32(PSB_CR_BIF_FAULT);
+               if (val) {
+                       if (val & _PSB_CBI_STAT_PF_N_RW)
+                               DRM_ERROR("SGX MMU page fault:");
+                       else
+                               DRM_ERROR("SGX MMU read / write protection fault:");
+
+                       if (val & _PSB_CBI_STAT_FAULT_CACHE)
+                               DRM_ERROR("\tCache requestor");
+                       if (val & _PSB_CBI_STAT_FAULT_TA)
+                               DRM_ERROR("\tTA requestor");
+                       if (val & _PSB_CBI_STAT_FAULT_VDM)
+                               DRM_ERROR("\tVDM requestor");
+                       if (val & _PSB_CBI_STAT_FAULT_2D)
+                               DRM_ERROR("\t2D requestor");
+                       if (val & _PSB_CBI_STAT_FAULT_PBE)
+                               DRM_ERROR("\tPBE requestor");
+                       if (val & _PSB_CBI_STAT_FAULT_TSP)
+                               DRM_ERROR("\tTSP requestor");
+                       if (val & _PSB_CBI_STAT_FAULT_ISP)
+                               DRM_ERROR("\tISP requestor");
+                       if (val & _PSB_CBI_STAT_FAULT_USSEPDS)
+                               DRM_ERROR("\tUSSEPDS requestor");
+                       if (val & _PSB_CBI_STAT_FAULT_HOST)
+                               DRM_ERROR("\tHost requestor");
+
+                       DRM_ERROR("\tMMU failing address is 0x%08x.\n",
+                                 (unsigned int)addr);
+                       error = true;
+               }
+       }
+
+       /* Clear bits */
+       PSB_WSGX32(stat_1, PSB_CR_EVENT_HOST_CLEAR);
+       PSB_WSGX32(stat_2, PSB_CR_EVENT_HOST_CLEAR2);
+       PSB_RSGX32(PSB_CR_EVENT_HOST_CLEAR2);
+}
+
 irqreturn_t psb_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_psb_private *dev_priv = dev->dev_private;
        uint32_t vdc_stat, dsp_int = 0, sgx_int = 0, hotplug_int = 0;
+       u32 sgx_stat_1, sgx_stat_2;
        int handled = 0;
 
        spin_lock(&dev_priv->irqmask_lock);
@@ -233,14 +286,9 @@ irqreturn_t psb_irq_handler(int irq, void *arg)
        }
 
        if (sgx_int) {
-               /* Not expected - we have it masked, shut it up */
-               u32 s, s2;
-               s = PSB_RSGX32(PSB_CR_EVENT_STATUS);
-               s2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2);
-               PSB_WSGX32(s, PSB_CR_EVENT_HOST_CLEAR);
-               PSB_WSGX32(s2, PSB_CR_EVENT_HOST_CLEAR2);
-               /* if s & _PSB_CE_TWOD_COMPLETE we have 2D done but
-                  we may as well poll even if we add that ! */
+               sgx_stat_1 = PSB_RSGX32(PSB_CR_EVENT_STATUS);
+               sgx_stat_2 = PSB_RSGX32(PSB_CR_EVENT_STATUS2);
+               psb_sgx_interrupt(dev, sgx_stat_1, sgx_stat_2);
                handled = 1;
        }
 
@@ -269,8 +317,13 @@ void psb_irq_preinstall(struct drm_device *dev)
 
        spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
 
-       if (gma_power_is_on(dev))
+       if (gma_power_is_on(dev)) {
                PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
+               PSB_WVDC32(0x00000000, PSB_INT_MASK_R);
+               PSB_WVDC32(0x00000000, PSB_INT_ENABLE_R);
+               PSB_WSGX32(0x00000000, PSB_CR_EVENT_HOST_ENABLE);
+               PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE);
+       }
        if (dev->vblank[0].enabled)
                dev_priv->vdc_irq_mask |= _PSB_VSYNC_PIPEA_FLAG;
        if (dev->vblank[1].enabled)
@@ -286,7 +339,7 @@ void psb_irq_preinstall(struct drm_device *dev)
        /* Revisit this area - want per device masks ? */
        if (dev_priv->ops->hotplug)
                dev_priv->vdc_irq_mask |= _PSB_IRQ_DISP_HOTSYNC;
-       dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE;
+       dev_priv->vdc_irq_mask |= _PSB_IRQ_ASLE | _PSB_IRQ_SGX_FLAG;
 
        /* This register is safe even if display island is off */
        PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
@@ -295,12 +348,16 @@ void psb_irq_preinstall(struct drm_device *dev)
 
 int psb_irq_postinstall(struct drm_device *dev)
 {
-       struct drm_psb_private *dev_priv =
-           (struct drm_psb_private *) dev->dev_private;
+       struct drm_psb_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
 
+       /* Enable 2D and MMU fault interrupts */
+       PSB_WSGX32(_PSB_CE2_BIF_REQUESTER_FAULT, PSB_CR_EVENT_HOST_ENABLE2);
+       PSB_WSGX32(_PSB_CE_TWOD_COMPLETE, PSB_CR_EVENT_HOST_ENABLE);
+       PSB_RSGX32(PSB_CR_EVENT_HOST_ENABLE); /* Post */
+
        /* This register is safe even if display island is off */
        PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
        PSB_WVDC32(0xFFFFFFFF, PSB_HWSTAM);
index faa77f5..48af5ca 100644 (file)
@@ -19,6 +19,8 @@
 
 #include <linux/hdmi.h>
 #include <linux/module.h>
+#include <linux/irq.h>
+#include <sound/asoundef.h>
 
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
@@ -30,6 +32,7 @@
 
 struct tda998x_priv {
        struct i2c_client *cec;
+       struct i2c_client *hdmi;
        uint16_t rev;
        uint8_t current_page;
        int dpms;
@@ -38,6 +41,10 @@ struct tda998x_priv {
        u8 vip_cntrl_1;
        u8 vip_cntrl_2;
        struct tda998x_encoder_params params;
+
+       wait_queue_head_t wq_edid;
+       volatile int wq_edid_wait;
+       struct drm_encoder *encoder;
 };
 
 #define to_tda998x_priv(x)  ((struct tda998x_priv *)to_encoder_slave(x)->slave_priv)
@@ -120,6 +127,8 @@ struct tda998x_priv {
 # define VIP_CNTRL_5_CKCASE       (1 << 0)
 # define VIP_CNTRL_5_SP_CNT(x)    (((x) & 3) << 1)
 #define REG_MUX_AP                REG(0x00, 0x26)     /* read/write */
+# define MUX_AP_SELECT_I2S       0x64
+# define MUX_AP_SELECT_SPDIF     0x40
 #define REG_MUX_VP_VIP_OUT        REG(0x00, 0x27)     /* read/write */
 #define REG_MAT_CONTRL            REG(0x00, 0x80)     /* write */
 # define MAT_CONTRL_MAT_SC(x)     (((x) & 3) << 0)
@@ -197,10 +206,11 @@ struct tda998x_priv {
 #define REG_I2S_FORMAT            REG(0x00, 0xfc)     /* read/write */
 # define I2S_FORMAT(x)            (((x) & 3) << 0)
 #define REG_AIP_CLKSEL            REG(0x00, 0xfd)     /* write */
-# define AIP_CLKSEL_FS(x)         (((x) & 3) << 0)
-# define AIP_CLKSEL_CLK_POL(x)    (((x) & 1) << 2)
-# define AIP_CLKSEL_AIP(x)        (((x) & 7) << 3)
-
+# define AIP_CLKSEL_AIP_SPDIF    (0 << 3)
+# define AIP_CLKSEL_AIP_I2S      (1 << 3)
+# define AIP_CLKSEL_FS_ACLK      (0 << 0)
+# define AIP_CLKSEL_FS_MCLK      (1 << 0)
+# define AIP_CLKSEL_FS_FS64SPDIF  (2 << 0)
 
 /* Page 02h: PLL settings */
 #define REG_PLL_SERIAL_1          REG(0x02, 0x00)     /* read/write */
@@ -304,11 +314,16 @@ struct tda998x_priv {
 
 /* CEC registers: (not paged)
  */
+#define REG_CEC_INTSTATUS        0xee                /* read */
+# define CEC_INTSTATUS_CEC       (1 << 0)
+# define CEC_INTSTATUS_HDMI      (1 << 1)
 #define REG_CEC_FRO_IM_CLK_CTRL   0xfb                /* read/write */
 # define CEC_FRO_IM_CLK_CTRL_GHOST_DIS (1 << 7)
 # define CEC_FRO_IM_CLK_CTRL_ENA_OTP   (1 << 6)
 # define CEC_FRO_IM_CLK_CTRL_IMCLK_SEL (1 << 1)
 # define CEC_FRO_IM_CLK_CTRL_FRO_DIV   (1 << 0)
+#define REG_CEC_RXSHPDINTENA     0xfc                /* read/write */
+#define REG_CEC_RXSHPDINT        0xfd                /* read */
 #define REG_CEC_RXSHPDLEV         0xfe                /* read */
 # define CEC_RXSHPDLEV_RXSENS     (1 << 0)
 # define CEC_RXSHPDLEV_HPD        (1 << 1)
@@ -328,21 +343,21 @@ struct tda998x_priv {
 #define TDA19988                  0x0301
 
 static void
-cec_write(struct drm_encoder *encoder, uint16_t addr, uint8_t val)
+cec_write(struct tda998x_priv *priv, uint16_t addr, uint8_t val)
 {
-       struct i2c_client *client = to_tda998x_priv(encoder)->cec;
+       struct i2c_client *client = priv->cec;
        uint8_t buf[] = {addr, val};
        int ret;
 
-       ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
+       ret = i2c_master_send(client, buf, sizeof(buf));
        if (ret < 0)
                dev_err(&client->dev, "Error %d writing to cec:0x%x\n", ret, addr);
 }
 
 static uint8_t
-cec_read(struct drm_encoder *encoder, uint8_t addr)
+cec_read(struct tda998x_priv *priv, uint8_t addr)
 {
-       struct i2c_client *client = to_tda998x_priv(encoder)->cec;
+       struct i2c_client *client = priv->cec;
        uint8_t val;
        int ret;
 
@@ -361,32 +376,36 @@ fail:
        return 0;
 }
 
-static void
-set_page(struct drm_encoder *encoder, uint16_t reg)
+static int
+set_page(struct tda998x_priv *priv, uint16_t reg)
 {
-       struct tda998x_priv *priv = to_tda998x_priv(encoder);
-
        if (REG2PAGE(reg) != priv->current_page) {
-               struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+               struct i2c_client *client = priv->hdmi;
                uint8_t buf[] = {
                                REG_CURPAGE, REG2PAGE(reg)
                };
                int ret = i2c_master_send(client, buf, sizeof(buf));
-               if (ret < 0)
-                       dev_err(&client->dev, "Error %d writing to REG_CURPAGE\n", ret);
+               if (ret < 0) {
+                       dev_err(&client->dev, "setpage %04x err %d\n",
+                                       reg, ret);
+                       return ret;
+               }
 
                priv->current_page = REG2PAGE(reg);
        }
+       return 0;
 }
 
 static int
-reg_read_range(struct drm_encoder *encoder, uint16_t reg, char *buf, int cnt)
+reg_read_range(struct tda998x_priv *priv, uint16_t reg, char *buf, int cnt)
 {
-       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct i2c_client *client = priv->hdmi;
        uint8_t addr = REG2ADDR(reg);
        int ret;
 
-       set_page(encoder, reg);
+       ret = set_page(priv, reg);
+       if (ret < 0)
+               return ret;
 
        ret = i2c_master_send(client, &addr, sizeof(addr));
        if (ret < 0)
@@ -404,100 +423,147 @@ fail:
 }
 
 static void
-reg_write_range(struct drm_encoder *encoder, uint16_t reg, uint8_t *p, int cnt)
+reg_write_range(struct tda998x_priv *priv, uint16_t reg, uint8_t *p, int cnt)
 {
-       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct i2c_client *client = priv->hdmi;
        uint8_t buf[cnt+1];
        int ret;
 
        buf[0] = REG2ADDR(reg);
        memcpy(&buf[1], p, cnt);
 
-       set_page(encoder, reg);
+       ret = set_page(priv, reg);
+       if (ret < 0)
+               return;
 
        ret = i2c_master_send(client, buf, cnt + 1);
        if (ret < 0)
                dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
 }
 
-static uint8_t
-reg_read(struct drm_encoder *encoder, uint16_t reg)
+static int
+reg_read(struct tda998x_priv *priv, uint16_t reg)
 {
        uint8_t val = 0;
-       reg_read_range(encoder, reg, &val, sizeof(val));
+       int ret;
+
+       ret = reg_read_range(priv, reg, &val, sizeof(val));
+       if (ret < 0)
+               return ret;
        return val;
 }
 
 static void
-reg_write(struct drm_encoder *encoder, uint16_t reg, uint8_t val)
+reg_write(struct tda998x_priv *priv, uint16_t reg, uint8_t val)
 {
-       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct i2c_client *client = priv->hdmi;
        uint8_t buf[] = {REG2ADDR(reg), val};
        int ret;
 
-       set_page(encoder, reg);
+       ret = set_page(priv, reg);
+       if (ret < 0)
+               return;
 
-       ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
+       ret = i2c_master_send(client, buf, sizeof(buf));
        if (ret < 0)
                dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
 }
 
 static void
-reg_write16(struct drm_encoder *encoder, uint16_t reg, uint16_t val)
+reg_write16(struct tda998x_priv *priv, uint16_t reg, uint16_t val)
 {
-       struct i2c_client *client = drm_i2c_encoder_get_client(encoder);
+       struct i2c_client *client = priv->hdmi;
        uint8_t buf[] = {REG2ADDR(reg), val >> 8, val};
        int ret;
 
-       set_page(encoder, reg);
+       ret = set_page(priv, reg);
+       if (ret < 0)
+               return;
 
-       ret = i2c_master_send(client, buf, ARRAY_SIZE(buf));
+       ret = i2c_master_send(client, buf, sizeof(buf));
        if (ret < 0)
                dev_err(&client->dev, "Error %d writing to 0x%x\n", ret, reg);
 }
 
 static void
-reg_set(struct drm_encoder *encoder, uint16_t reg, uint8_t val)
+reg_set(struct tda998x_priv *priv, uint16_t reg, uint8_t val)
 {
-       reg_write(encoder, reg, reg_read(encoder, reg) | val);
+       int old_val;
+
+       old_val = reg_read(priv, reg);
+       if (old_val >= 0)
+               reg_write(priv, reg, old_val | val);
 }
 
 static void
-reg_clear(struct drm_encoder *encoder, uint16_t reg, uint8_t val)
+reg_clear(struct tda998x_priv *priv, uint16_t reg, uint8_t val)
 {
-       reg_write(encoder, reg, reg_read(encoder, reg) & ~val);
+       int old_val;
+
+       old_val = reg_read(priv, reg);
+       if (old_val >= 0)
+               reg_write(priv, reg, old_val & ~val);
 }
 
 static void
-tda998x_reset(struct drm_encoder *encoder)
+tda998x_reset(struct tda998x_priv *priv)
 {
        /* reset audio and i2c master: */
-       reg_set(encoder, REG_SOFTRESET, SOFTRESET_AUDIO | SOFTRESET_I2C_MASTER);
+       reg_write(priv, REG_SOFTRESET, SOFTRESET_AUDIO | SOFTRESET_I2C_MASTER);
        msleep(50);
-       reg_clear(encoder, REG_SOFTRESET, SOFTRESET_AUDIO | SOFTRESET_I2C_MASTER);
+       reg_write(priv, REG_SOFTRESET, 0);
        msleep(50);
 
        /* reset transmitter: */
-       reg_set(encoder, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
-       reg_clear(encoder, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
+       reg_set(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
+       reg_clear(priv, REG_MAIN_CNTRL0, MAIN_CNTRL0_SR);
 
        /* PLL registers common configuration */
-       reg_write(encoder, REG_PLL_SERIAL_1, 0x00);
-       reg_write(encoder, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1));
-       reg_write(encoder, REG_PLL_SERIAL_3, 0x00);
-       reg_write(encoder, REG_SERIALIZER,   0x00);
-       reg_write(encoder, REG_BUFFER_OUT,   0x00);
-       reg_write(encoder, REG_PLL_SCG1,     0x00);
-       reg_write(encoder, REG_AUDIO_DIV,    AUDIO_DIV_SERCLK_8);
-       reg_write(encoder, REG_SEL_CLK,      SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
-       reg_write(encoder, REG_PLL_SCGN1,    0xfa);
-       reg_write(encoder, REG_PLL_SCGN2,    0x00);
-       reg_write(encoder, REG_PLL_SCGR1,    0x5b);
-       reg_write(encoder, REG_PLL_SCGR2,    0x00);
-       reg_write(encoder, REG_PLL_SCG2,     0x10);
+       reg_write(priv, REG_PLL_SERIAL_1, 0x00);
+       reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(1));
+       reg_write(priv, REG_PLL_SERIAL_3, 0x00);
+       reg_write(priv, REG_SERIALIZER,   0x00);
+       reg_write(priv, REG_BUFFER_OUT,   0x00);
+       reg_write(priv, REG_PLL_SCG1,     0x00);
+       reg_write(priv, REG_AUDIO_DIV,    AUDIO_DIV_SERCLK_8);
+       reg_write(priv, REG_SEL_CLK,      SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
+       reg_write(priv, REG_PLL_SCGN1,    0xfa);
+       reg_write(priv, REG_PLL_SCGN2,    0x00);
+       reg_write(priv, REG_PLL_SCGR1,    0x5b);
+       reg_write(priv, REG_PLL_SCGR2,    0x00);
+       reg_write(priv, REG_PLL_SCG2,     0x10);
 
        /* Write the default value MUX register */
-       reg_write(encoder, REG_MUX_VP_VIP_OUT, 0x24);
+       reg_write(priv, REG_MUX_VP_VIP_OUT, 0x24);
+}
+
+/*
+ * only 2 interrupts may occur: screen plug/unplug and EDID read
+ */
+static irqreturn_t tda998x_irq_thread(int irq, void *data)
+{
+       struct tda998x_priv *priv = data;
+       u8 sta, cec, lvl, flag0, flag1, flag2;
+
+       if (!priv)
+               return IRQ_HANDLED;
+       sta = cec_read(priv, REG_CEC_INTSTATUS);
+       cec = cec_read(priv, REG_CEC_RXSHPDINT);
+       lvl = cec_read(priv, REG_CEC_RXSHPDLEV);
+       flag0 = reg_read(priv, REG_INT_FLAGS_0);
+       flag1 = reg_read(priv, REG_INT_FLAGS_1);
+       flag2 = reg_read(priv, REG_INT_FLAGS_2);
+       DRM_DEBUG_DRIVER(
+               "tda irq sta %02x cec %02x lvl %02x f0 %02x f1 %02x f2 %02x\n",
+               sta, cec, lvl, flag0, flag1, flag2);
+       if ((flag2 & INT_FLAGS_2_EDID_BLK_RD) && priv->wq_edid_wait) {
+               priv->wq_edid_wait = 0;
+               wake_up(&priv->wq_edid);
+       } else if (cec != 0) {                  /* HPD change */
+               if (priv->encoder && priv->encoder->dev)
+                       drm_helper_hpd_irq_event(priv->encoder->dev);
+       }
+       return IRQ_HANDLED;
 }
 
 static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes)
@@ -513,91 +579,88 @@ static uint8_t tda998x_cksum(uint8_t *buf, size_t bytes)
 #define PB(x) (HB(2) + 1 + (x))
 
 static void
-tda998x_write_if(struct drm_encoder *encoder, uint8_t bit, uint16_t addr,
+tda998x_write_if(struct tda998x_priv *priv, uint8_t bit, uint16_t addr,
                 uint8_t *buf, size_t size)
 {
        buf[PB(0)] = tda998x_cksum(buf, size);
 
-       reg_clear(encoder, REG_DIP_IF_FLAGS, bit);
-       reg_write_range(encoder, addr, buf, size);
-       reg_set(encoder, REG_DIP_IF_FLAGS, bit);
+       reg_clear(priv, REG_DIP_IF_FLAGS, bit);
+       reg_write_range(priv, addr, buf, size);
+       reg_set(priv, REG_DIP_IF_FLAGS, bit);
 }
 
 static void
-tda998x_write_aif(struct drm_encoder *encoder, struct tda998x_encoder_params *p)
+tda998x_write_aif(struct tda998x_priv *priv, struct tda998x_encoder_params *p)
 {
-       uint8_t buf[PB(5) + 1];
+       u8 buf[PB(HDMI_AUDIO_INFOFRAME_SIZE) + 1];
 
        memset(buf, 0, sizeof(buf));
-       buf[HB(0)] = 0x84;
+       buf[HB(0)] = HDMI_INFOFRAME_TYPE_AUDIO;
        buf[HB(1)] = 0x01;
-       buf[HB(2)] = 10;
+       buf[HB(2)] = HDMI_AUDIO_INFOFRAME_SIZE;
        buf[PB(1)] = p->audio_frame[1] & 0x07; /* CC */
        buf[PB(2)] = p->audio_frame[2] & 0x1c; /* SF */
        buf[PB(4)] = p->audio_frame[4];
        buf[PB(5)] = p->audio_frame[5] & 0xf8; /* DM_INH + LSV */
 
-       tda998x_write_if(encoder, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf,
+       tda998x_write_if(priv, DIP_IF_FLAGS_IF4, REG_IF4_HB0, buf,
                         sizeof(buf));
 }
 
 static void
-tda998x_write_avi(struct drm_encoder *encoder, struct drm_display_mode *mode)
+tda998x_write_avi(struct tda998x_priv *priv, struct drm_display_mode *mode)
 {
-       uint8_t buf[PB(13) + 1];
+       u8 buf[PB(HDMI_AVI_INFOFRAME_SIZE) + 1];
 
        memset(buf, 0, sizeof(buf));
-       buf[HB(0)] = 0x82;
+       buf[HB(0)] = HDMI_INFOFRAME_TYPE_AVI;
        buf[HB(1)] = 0x02;
-       buf[HB(2)] = 13;
+       buf[HB(2)] = HDMI_AVI_INFOFRAME_SIZE;
        buf[PB(1)] = HDMI_SCAN_MODE_UNDERSCAN;
+       buf[PB(2)] = HDMI_ACTIVE_ASPECT_PICTURE;
        buf[PB(3)] = HDMI_QUANTIZATION_RANGE_FULL << 2;
        buf[PB(4)] = drm_match_cea_mode(mode);
 
-       tda998x_write_if(encoder, DIP_IF_FLAGS_IF2, REG_IF2_HB0, buf,
+       tda998x_write_if(priv, DIP_IF_FLAGS_IF2, REG_IF2_HB0, buf,
                         sizeof(buf));
 }
 
-static void tda998x_audio_mute(struct drm_encoder *encoder, bool on)
+static void tda998x_audio_mute(struct tda998x_priv *priv, bool on)
 {
        if (on) {
-               reg_set(encoder, REG_SOFTRESET, SOFTRESET_AUDIO);
-               reg_clear(encoder, REG_SOFTRESET, SOFTRESET_AUDIO);
-               reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
+               reg_set(priv, REG_SOFTRESET, SOFTRESET_AUDIO);
+               reg_clear(priv, REG_SOFTRESET, SOFTRESET_AUDIO);
+               reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
        } else {
-               reg_clear(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
+               reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
        }
 }
 
 static void
-tda998x_configure_audio(struct drm_encoder *encoder,
+tda998x_configure_audio(struct tda998x_priv *priv,
                struct drm_display_mode *mode, struct tda998x_encoder_params *p)
 {
-       uint8_t buf[6], clksel_aip, clksel_fs, ca_i2s, cts_n, adiv;
+       uint8_t buf[6], clksel_aip, clksel_fs, cts_n, adiv;
        uint32_t n;
 
        /* Enable audio ports */
-       reg_write(encoder, REG_ENA_AP, p->audio_cfg);
-       reg_write(encoder, REG_ENA_ACLK, p->audio_clk_cfg);
+       reg_write(priv, REG_ENA_AP, p->audio_cfg);
+       reg_write(priv, REG_ENA_ACLK, p->audio_clk_cfg);
 
        /* Set audio input source */
        switch (p->audio_format) {
        case AFMT_SPDIF:
-               reg_write(encoder, REG_MUX_AP, 0x40);
-               clksel_aip = AIP_CLKSEL_AIP(0);
-               /* FS64SPDIF */
-               clksel_fs = AIP_CLKSEL_FS(2);
+               reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_SPDIF);
+               clksel_aip = AIP_CLKSEL_AIP_SPDIF;
+               clksel_fs = AIP_CLKSEL_FS_FS64SPDIF;
                cts_n = CTS_N_M(3) | CTS_N_K(3);
-               ca_i2s = 0;
                break;
 
        case AFMT_I2S:
-               reg_write(encoder, REG_MUX_AP, 0x64);
-               clksel_aip = AIP_CLKSEL_AIP(1);
-               /* ACLK */
-               clksel_fs = AIP_CLKSEL_FS(0);
+               reg_write(priv, REG_MUX_AP, MUX_AP_SELECT_I2S);
+               clksel_aip = AIP_CLKSEL_AIP_I2S;
+               clksel_fs = AIP_CLKSEL_FS_ACLK;
                cts_n = CTS_N_M(3) | CTS_N_K(3);
-               ca_i2s = CA_I2S_CA_I2S(0);
                break;
 
        default:
@@ -605,12 +668,10 @@ tda998x_configure_audio(struct drm_encoder *encoder,
                return;
        }
 
-       reg_write(encoder, REG_AIP_CLKSEL, clksel_aip);
-       reg_clear(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT);
-
-       /* Enable automatic CTS generation */
-       reg_clear(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_ACR_MAN);
-       reg_write(encoder, REG_CTS_N, cts_n);
+       reg_write(priv, REG_AIP_CLKSEL, clksel_aip);
+       reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_LAYOUT |
+                                       AIP_CNTRL_0_ACR_MAN);   /* auto CTS */
+       reg_write(priv, REG_CTS_N, cts_n);
 
        /*
         * Audio input somehow depends on HDMI line rate which is
@@ -619,11 +680,15 @@ tda998x_configure_audio(struct drm_encoder *encoder,
         * There is no detailed info in the datasheet, so we just
         * assume 100MHz requires larger divider.
         */
+       adiv = AUDIO_DIV_SERCLK_8;
        if (mode->clock > 100000)
-               adiv = AUDIO_DIV_SERCLK_16;
-       else
-               adiv = AUDIO_DIV_SERCLK_8;
-       reg_write(encoder, REG_AUDIO_DIV, adiv);
+               adiv++;                 /* AUDIO_DIV_SERCLK_16 */
+
+       /* S/PDIF asks for a larger divider */
+       if (p->audio_format == AFMT_SPDIF)
+               adiv++;                 /* AUDIO_DIV_SERCLK_16 or _32 */
+
+       reg_write(priv, REG_AUDIO_DIV, adiv);
 
        /*
         * This is the approximate value of N, which happens to be
@@ -638,28 +703,29 @@ tda998x_configure_audio(struct drm_encoder *encoder,
        buf[3] = n;
        buf[4] = n >> 8;
        buf[5] = n >> 16;
-       reg_write_range(encoder, REG_ACR_CTS_0, buf, 6);
+       reg_write_range(priv, REG_ACR_CTS_0, buf, 6);
 
        /* Set CTS clock reference */
-       reg_write(encoder, REG_AIP_CLKSEL, clksel_aip | clksel_fs);
+       reg_write(priv, REG_AIP_CLKSEL, clksel_aip | clksel_fs);
 
        /* Reset CTS generator */
-       reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
-       reg_clear(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
+       reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
+       reg_clear(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_CTS);
 
        /* Write the channel status */
-       buf[0] = 0x04;
+       buf[0] = IEC958_AES0_CON_NOT_COPYRIGHT;
        buf[1] = 0x00;
-       buf[2] = 0x00;
-       buf[3] = 0xf1;
-       reg_write_range(encoder, REG_CH_STAT_B(0), buf, 4);
+       buf[2] = IEC958_AES3_CON_FS_NOTID;
+       buf[3] = IEC958_AES4_CON_ORIGFS_NOTID |
+                       IEC958_AES4_CON_MAX_WORDLEN_24;
+       reg_write_range(priv, REG_CH_STAT_B(0), buf, 4);
 
-       tda998x_audio_mute(encoder, true);
-       mdelay(20);
-       tda998x_audio_mute(encoder, false);
+       tda998x_audio_mute(priv, true);
+       msleep(20);
+       tda998x_audio_mute(priv, false);
 
        /* Write the audio information packet */
-       tda998x_write_aif(encoder, p);
+       tda998x_write_aif(priv, p);
 }
 
 /* DRM encoder functions */
@@ -701,19 +767,19 @@ tda998x_encoder_dpms(struct drm_encoder *encoder, int mode)
        switch (mode) {
        case DRM_MODE_DPMS_ON:
                /* enable video ports, audio will be enabled later */
-               reg_write(encoder, REG_ENA_VP_0, 0xff);
-               reg_write(encoder, REG_ENA_VP_1, 0xff);
-               reg_write(encoder, REG_ENA_VP_2, 0xff);
+               reg_write(priv, REG_ENA_VP_0, 0xff);
+               reg_write(priv, REG_ENA_VP_1, 0xff);
+               reg_write(priv, REG_ENA_VP_2, 0xff);
                /* set muxing after enabling ports: */
-               reg_write(encoder, REG_VIP_CNTRL_0, priv->vip_cntrl_0);
-               reg_write(encoder, REG_VIP_CNTRL_1, priv->vip_cntrl_1);
-               reg_write(encoder, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
+               reg_write(priv, REG_VIP_CNTRL_0, priv->vip_cntrl_0);
+               reg_write(priv, REG_VIP_CNTRL_1, priv->vip_cntrl_1);
+               reg_write(priv, REG_VIP_CNTRL_2, priv->vip_cntrl_2);
                break;
        case DRM_MODE_DPMS_OFF:
                /* disable video ports */
-               reg_write(encoder, REG_ENA_VP_0, 0x00);
-               reg_write(encoder, REG_ENA_VP_1, 0x00);
-               reg_write(encoder, REG_ENA_VP_2, 0x00);
+               reg_write(priv, REG_ENA_VP_0, 0x00);
+               reg_write(priv, REG_ENA_VP_1, 0x00);
+               reg_write(priv, REG_ENA_VP_2, 0x00);
                break;
        }
 
@@ -831,110 +897,110 @@ tda998x_encoder_mode_set(struct drm_encoder *encoder,
        }
 
        /* mute the audio FIFO: */
-       reg_set(encoder, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
+       reg_set(priv, REG_AIP_CNTRL_0, AIP_CNTRL_0_RST_FIFO);
 
        /* set HDMI HDCP mode off: */
-       reg_set(encoder, REG_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
-       reg_clear(encoder, REG_TX33, TX33_HDMI);
+       reg_write(priv, REG_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
+       reg_clear(priv, REG_TX33, TX33_HDMI);
+       reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(0));
 
-       reg_write(encoder, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(0));
        /* no pre-filter or interpolator: */
-       reg_write(encoder, REG_HVF_CNTRL_0, HVF_CNTRL_0_PREFIL(0) |
+       reg_write(priv, REG_HVF_CNTRL_0, HVF_CNTRL_0_PREFIL(0) |
                        HVF_CNTRL_0_INTPOL(0));
-       reg_write(encoder, REG_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0));
-       reg_write(encoder, REG_VIP_CNTRL_4, VIP_CNTRL_4_BLANKIT(0) |
+       reg_write(priv, REG_VIP_CNTRL_5, VIP_CNTRL_5_SP_CNT(0));
+       reg_write(priv, REG_VIP_CNTRL_4, VIP_CNTRL_4_BLANKIT(0) |
                        VIP_CNTRL_4_BLC(0));
-       reg_clear(encoder, REG_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR);
 
-       reg_clear(encoder, REG_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IZ);
-       reg_clear(encoder, REG_PLL_SERIAL_3, PLL_SERIAL_3_SRL_DE);
-       reg_write(encoder, REG_SERIALIZER, 0);
-       reg_write(encoder, REG_HVF_CNTRL_1, HVF_CNTRL_1_VQR(0));
+       reg_clear(priv, REG_PLL_SERIAL_1, PLL_SERIAL_1_SRL_MAN_IZ);
+       reg_clear(priv, REG_PLL_SERIAL_3, PLL_SERIAL_3_SRL_CCIR |
+                                         PLL_SERIAL_3_SRL_DE);
+       reg_write(priv, REG_SERIALIZER, 0);
+       reg_write(priv, REG_HVF_CNTRL_1, HVF_CNTRL_1_VQR(0));
 
        /* TODO enable pixel repeat for pixel rates less than 25Msamp/s */
        rep = 0;
-       reg_write(encoder, REG_RPT_CNTRL, 0);
-       reg_write(encoder, REG_SEL_CLK, SEL_CLK_SEL_VRF_CLK(0) |
+       reg_write(priv, REG_RPT_CNTRL, 0);
+       reg_write(priv, REG_SEL_CLK, SEL_CLK_SEL_VRF_CLK(0) |
                        SEL_CLK_SEL_CLK1 | SEL_CLK_ENA_SC_CLK);
 
-       reg_write(encoder, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
+       reg_write(priv, REG_PLL_SERIAL_2, PLL_SERIAL_2_SRL_NOSC(div) |
                        PLL_SERIAL_2_SRL_PR(rep));
 
        /* set color matrix bypass flag: */
-       reg_set(encoder, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP);
+       reg_write(priv, REG_MAT_CONTRL, MAT_CONTRL_MAT_BP |
+                               MAT_CONTRL_MAT_SC(1));
 
        /* set BIAS tmds value: */
-       reg_write(encoder, REG_ANA_GENERAL, 0x09);
-
-       reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_MTHD);
+       reg_write(priv, REG_ANA_GENERAL, 0x09);
 
        /*
         * Sync on rising HSYNC/VSYNC
         */
-       reg_write(encoder, REG_VIP_CNTRL_3, 0);
-       reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_SYNC_HS);
+       reg = VIP_CNTRL_3_SYNC_HS;
 
        /*
         * TDA19988 requires high-active sync at input stage,
         * so invert low-active sync provided by master encoder here
         */
        if (mode->flags & DRM_MODE_FLAG_NHSYNC)
-               reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_H_TGL);
+               reg |= VIP_CNTRL_3_H_TGL;
        if (mode->flags & DRM_MODE_FLAG_NVSYNC)
-               reg_set(encoder, REG_VIP_CNTRL_3, VIP_CNTRL_3_V_TGL);
+               reg |= VIP_CNTRL_3_V_TGL;
+       reg_write(priv, REG_VIP_CNTRL_3, reg);
+
+       reg_write(priv, REG_VIDFORMAT, 0x00);
+       reg_write16(priv, REG_REFPIX_MSB, ref_pix);
+       reg_write16(priv, REG_REFLINE_MSB, ref_line);
+       reg_write16(priv, REG_NPIX_MSB, n_pix);
+       reg_write16(priv, REG_NLINE_MSB, n_line);
+       reg_write16(priv, REG_VS_LINE_STRT_1_MSB, vs1_line_s);
+       reg_write16(priv, REG_VS_PIX_STRT_1_MSB, vs1_pix_s);
+       reg_write16(priv, REG_VS_LINE_END_1_MSB, vs1_line_e);
+       reg_write16(priv, REG_VS_PIX_END_1_MSB, vs1_pix_e);
+       reg_write16(priv, REG_VS_LINE_STRT_2_MSB, vs2_line_s);
+       reg_write16(priv, REG_VS_PIX_STRT_2_MSB, vs2_pix_s);
+       reg_write16(priv, REG_VS_LINE_END_2_MSB, vs2_line_e);
+       reg_write16(priv, REG_VS_PIX_END_2_MSB, vs2_pix_e);
+       reg_write16(priv, REG_HS_PIX_START_MSB, hs_pix_s);
+       reg_write16(priv, REG_HS_PIX_STOP_MSB, hs_pix_e);
+       reg_write16(priv, REG_VWIN_START_1_MSB, vwin1_line_s);
+       reg_write16(priv, REG_VWIN_END_1_MSB, vwin1_line_e);
+       reg_write16(priv, REG_VWIN_START_2_MSB, vwin2_line_s);
+       reg_write16(priv, REG_VWIN_END_2_MSB, vwin2_line_e);
+       reg_write16(priv, REG_DE_START_MSB, de_pix_s);
+       reg_write16(priv, REG_DE_STOP_MSB, de_pix_e);
+
+       if (priv->rev == TDA19988) {
+               /* let incoming pixels fill the active space (if any) */
+               reg_write(priv, REG_ENABLE_SPACE, 0x00);
+       }
 
        /*
         * Always generate sync polarity relative to input sync and
         * revert input stage toggled sync at output stage
         */
-       reg = TBG_CNTRL_1_TGL_EN;
+       reg = TBG_CNTRL_1_DWIN_DIS | TBG_CNTRL_1_TGL_EN;
        if (mode->flags & DRM_MODE_FLAG_NHSYNC)
                reg |= TBG_CNTRL_1_H_TGL;
        if (mode->flags & DRM_MODE_FLAG_NVSYNC)
                reg |= TBG_CNTRL_1_V_TGL;
-       reg_write(encoder, REG_TBG_CNTRL_1, reg);
-
-       reg_write(encoder, REG_VIDFORMAT, 0x00);
-       reg_write16(encoder, REG_REFPIX_MSB, ref_pix);
-       reg_write16(encoder, REG_REFLINE_MSB, ref_line);
-       reg_write16(encoder, REG_NPIX_MSB, n_pix);
-       reg_write16(encoder, REG_NLINE_MSB, n_line);
-       reg_write16(encoder, REG_VS_LINE_STRT_1_MSB, vs1_line_s);
-       reg_write16(encoder, REG_VS_PIX_STRT_1_MSB, vs1_pix_s);
-       reg_write16(encoder, REG_VS_LINE_END_1_MSB, vs1_line_e);
-       reg_write16(encoder, REG_VS_PIX_END_1_MSB, vs1_pix_e);
-       reg_write16(encoder, REG_VS_LINE_STRT_2_MSB, vs2_line_s);
-       reg_write16(encoder, REG_VS_PIX_STRT_2_MSB, vs2_pix_s);
-       reg_write16(encoder, REG_VS_LINE_END_2_MSB, vs2_line_e);
-       reg_write16(encoder, REG_VS_PIX_END_2_MSB, vs2_pix_e);
-       reg_write16(encoder, REG_HS_PIX_START_MSB, hs_pix_s);
-       reg_write16(encoder, REG_HS_PIX_STOP_MSB, hs_pix_e);
-       reg_write16(encoder, REG_VWIN_START_1_MSB, vwin1_line_s);
-       reg_write16(encoder, REG_VWIN_END_1_MSB, vwin1_line_e);
-       reg_write16(encoder, REG_VWIN_START_2_MSB, vwin2_line_s);
-       reg_write16(encoder, REG_VWIN_END_2_MSB, vwin2_line_e);
-       reg_write16(encoder, REG_DE_START_MSB, de_pix_s);
-       reg_write16(encoder, REG_DE_STOP_MSB, de_pix_e);
-
-       if (priv->rev == TDA19988) {
-               /* let incoming pixels fill the active space (if any) */
-               reg_write(encoder, REG_ENABLE_SPACE, 0x00);
-       }
+       reg_write(priv, REG_TBG_CNTRL_1, reg);
 
        /* must be last register set: */
-       reg_clear(encoder, REG_TBG_CNTRL_0, TBG_CNTRL_0_SYNC_ONCE);
+       reg_write(priv, REG_TBG_CNTRL_0, 0);
 
        /* Only setup the info frames if the sink is HDMI */
        if (priv->is_hdmi_sink) {
                /* We need to turn HDMI HDCP stuff on to get audio through */
-               reg_clear(encoder, REG_TBG_CNTRL_1, TBG_CNTRL_1_DWIN_DIS);
-               reg_write(encoder, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(1));
-               reg_set(encoder, REG_TX33, TX33_HDMI);
+               reg &= ~TBG_CNTRL_1_DWIN_DIS;
+               reg_write(priv, REG_TBG_CNTRL_1, reg);
+               reg_write(priv, REG_ENC_CNTRL, ENC_CNTRL_CTL_CODE(1));
+               reg_set(priv, REG_TX33, TX33_HDMI);
 
-               tda998x_write_avi(encoder, adjusted_mode);
+               tda998x_write_avi(priv, adjusted_mode);
 
                if (priv->params.audio_cfg)
-                       tda998x_configure_audio(encoder, adjusted_mode,
+                       tda998x_configure_audio(priv, adjusted_mode,
                                                &priv->params);
        }
 }
@@ -943,7 +1009,9 @@ static enum drm_connector_status
 tda998x_encoder_detect(struct drm_encoder *encoder,
                      struct drm_connector *connector)
 {
-       uint8_t val = cec_read(encoder, REG_CEC_RXSHPDLEV);
+       struct tda998x_priv *priv = to_tda998x_priv(encoder);
+       uint8_t val = cec_read(priv, REG_CEC_RXSHPDLEV);
+
        return (val & CEC_RXSHPDLEV_HPD) ? connector_status_connected :
                        connector_status_disconnected;
 }
@@ -951,46 +1019,57 @@ tda998x_encoder_detect(struct drm_encoder *encoder,
 static int
 read_edid_block(struct drm_encoder *encoder, uint8_t *buf, int blk)
 {
+       struct tda998x_priv *priv = to_tda998x_priv(encoder);
        uint8_t offset, segptr;
        int ret, i;
 
-       /* enable EDID read irq: */
-       reg_set(encoder, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
-
        offset = (blk & 1) ? 128 : 0;
        segptr = blk / 2;
 
-       reg_write(encoder, REG_DDC_ADDR, 0xa0);
-       reg_write(encoder, REG_DDC_OFFS, offset);
-       reg_write(encoder, REG_DDC_SEGM_ADDR, 0x60);
-       reg_write(encoder, REG_DDC_SEGM, segptr);
+       reg_write(priv, REG_DDC_ADDR, 0xa0);
+       reg_write(priv, REG_DDC_OFFS, offset);
+       reg_write(priv, REG_DDC_SEGM_ADDR, 0x60);
+       reg_write(priv, REG_DDC_SEGM, segptr);
 
        /* enable reading EDID: */
-       reg_write(encoder, REG_EDID_CTRL, 0x1);
+       priv->wq_edid_wait = 1;
+       reg_write(priv, REG_EDID_CTRL, 0x1);
 
        /* flag must be cleared by sw: */
-       reg_write(encoder, REG_EDID_CTRL, 0x0);
+       reg_write(priv, REG_EDID_CTRL, 0x0);
 
        /* wait for block read to complete: */
-       for (i = 100; i > 0; i--) {
-               uint8_t val = reg_read(encoder, REG_INT_FLAGS_2);
-               if (val & INT_FLAGS_2_EDID_BLK_RD)
-                       break;
-               msleep(1);
+       if (priv->hdmi->irq) {
+               i = wait_event_timeout(priv->wq_edid,
+                                       !priv->wq_edid_wait,
+                                       msecs_to_jiffies(100));
+               if (i < 0) {
+                       dev_err(&priv->hdmi->dev, "read edid wait err %d\n", i);
+                       return i;
+               }
+       } else {
+               for (i = 10; i > 0; i--) {
+                       msleep(10);
+                       ret = reg_read(priv, REG_INT_FLAGS_2);
+                       if (ret < 0)
+                               return ret;
+                       if (ret & INT_FLAGS_2_EDID_BLK_RD)
+                               break;
+               }
        }
 
-       if (i == 0)
+       if (i == 0) {
+               dev_err(&priv->hdmi->dev, "read edid timeout\n");
                return -ETIMEDOUT;
+       }
 
-       ret = reg_read_range(encoder, REG_EDID_DATA_0, buf, EDID_LENGTH);
+       ret = reg_read_range(priv, REG_EDID_DATA_0, buf, EDID_LENGTH);
        if (ret != EDID_LENGTH) {
-               dev_err(encoder->dev->dev, "failed to read edid block %d: %d",
-                               blk, ret);
+               dev_err(&priv->hdmi->dev, "failed to read edid block %d: %d\n",
+                       blk, ret);
                return ret;
        }
 
-       reg_clear(encoder, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
-
        return 0;
 }
 
@@ -998,7 +1077,7 @@ static uint8_t *
 do_get_edid(struct drm_encoder *encoder)
 {
        struct tda998x_priv *priv = to_tda998x_priv(encoder);
-       int j = 0, valid_extensions = 0;
+       int j, valid_extensions = 0;
        uint8_t *block, *new;
        bool print_bad_edid = drm_debug & DRM_UT_KMS;
 
@@ -1006,7 +1085,7 @@ do_get_edid(struct drm_encoder *encoder)
                return NULL;
 
        if (priv->rev == TDA19988)
-               reg_clear(encoder, REG_TX4, TX4_PD_RAM);
+               reg_clear(priv, REG_TX4, TX4_PD_RAM);
 
        /* base block fetch */
        if (read_edid_block(encoder, block, 0))
@@ -1046,14 +1125,14 @@ do_get_edid(struct drm_encoder *encoder)
 
 done:
        if (priv->rev == TDA19988)
-               reg_set(encoder, REG_TX4, TX4_PD_RAM);
+               reg_set(priv, REG_TX4, TX4_PD_RAM);
 
        return block;
 
 fail:
        if (priv->rev == TDA19988)
-               reg_set(encoder, REG_TX4, TX4_PD_RAM);
-       dev_warn(encoder->dev->dev, "failed to read EDID\n");
+               reg_set(priv, REG_TX4, TX4_PD_RAM);
+       dev_warn(&priv->hdmi->dev, "failed to read EDID\n");
        kfree(block);
        return NULL;
 }
@@ -1080,7 +1159,13 @@ static int
 tda998x_encoder_create_resources(struct drm_encoder *encoder,
                                struct drm_connector *connector)
 {
-       DBG("");
+       struct tda998x_priv *priv = to_tda998x_priv(encoder);
+
+       if (priv->hdmi->irq)
+               connector->polled = DRM_CONNECTOR_POLL_HPD;
+       else
+               connector->polled = DRM_CONNECTOR_POLL_CONNECT |
+                       DRM_CONNECTOR_POLL_DISCONNECT;
        return 0;
 }
 
@@ -1099,6 +1184,13 @@ tda998x_encoder_destroy(struct drm_encoder *encoder)
 {
        struct tda998x_priv *priv = to_tda998x_priv(encoder);
        drm_i2c_encoder_destroy(encoder);
+
+       /* disable all IRQs and free the IRQ handler */
+       cec_write(priv, REG_CEC_RXSHPDINTENA, 0);
+       reg_clear(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
+       if (priv->hdmi->irq)
+               free_irq(priv->hdmi->irq, priv);
+
        if (priv->cec)
                i2c_unregister_device(priv->cec);
        kfree(priv);
@@ -1138,8 +1230,10 @@ tda998x_encoder_init(struct i2c_client *client,
                    struct drm_device *dev,
                    struct drm_encoder_slave *encoder_slave)
 {
-       struct drm_encoder *encoder = &encoder_slave->base;
        struct tda998x_priv *priv;
+       struct device_node *np = client->dev.of_node;
+       u32 video;
+       int rev_lo, rev_hi, ret;
 
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -1150,52 +1244,113 @@ tda998x_encoder_init(struct i2c_client *client,
        priv->vip_cntrl_2 = VIP_CNTRL_2_SWAP_E(4) | VIP_CNTRL_2_SWAP_F(5);
 
        priv->current_page = 0xff;
+       priv->hdmi = client;
        priv->cec = i2c_new_dummy(client->adapter, 0x34);
        if (!priv->cec) {
                kfree(priv);
                return -ENODEV;
        }
+
+       priv->encoder = &encoder_slave->base;
        priv->dpms = DRM_MODE_DPMS_OFF;
 
        encoder_slave->slave_priv = priv;
        encoder_slave->slave_funcs = &tda998x_encoder_funcs;
 
        /* wake up the device: */
-       cec_write(encoder, REG_CEC_ENAMODS,
+       cec_write(priv, REG_CEC_ENAMODS,
                        CEC_ENAMODS_EN_RXSENS | CEC_ENAMODS_EN_HDMI);
 
-       tda998x_reset(encoder);
+       tda998x_reset(priv);
 
        /* read version: */
-       priv->rev = reg_read(encoder, REG_VERSION_LSB) |
-                       reg_read(encoder, REG_VERSION_MSB) << 8;
+       rev_lo = reg_read(priv, REG_VERSION_LSB);
+       rev_hi = reg_read(priv, REG_VERSION_MSB);
+       if (rev_lo < 0 || rev_hi < 0) {
+               ret = rev_lo < 0 ? rev_lo : rev_hi;
+               goto fail;
+       }
+
+       priv->rev = rev_lo | rev_hi << 8;
 
        /* mask off feature bits: */
        priv->rev &= ~0x30; /* not-hdcp and not-scalar bit */
 
        switch (priv->rev) {
-       case TDA9989N2:  dev_info(dev->dev, "found TDA9989 n2");  break;
-       case TDA19989:   dev_info(dev->dev, "found TDA19989");    break;
-       case TDA19989N2: dev_info(dev->dev, "found TDA19989 n2"); break;
-       case TDA19988:   dev_info(dev->dev, "found TDA19988");    break;
+       case TDA9989N2:
+               dev_info(&client->dev, "found TDA9989 n2");
+               break;
+       case TDA19989:
+               dev_info(&client->dev, "found TDA19989");
+               break;
+       case TDA19989N2:
+               dev_info(&client->dev, "found TDA19989 n2");
+               break;
+       case TDA19988:
+               dev_info(&client->dev, "found TDA19988");
+               break;
        default:
-               DBG("found unsupported device: %04x", priv->rev);
+               dev_err(&client->dev, "found unsupported device: %04x\n",
+                       priv->rev);
                goto fail;
        }
 
        /* after reset, enable DDC: */
-       reg_write(encoder, REG_DDC_DISABLE, 0x00);
+       reg_write(priv, REG_DDC_DISABLE, 0x00);
 
        /* set clock on DDC channel: */
-       reg_write(encoder, REG_TX3, 39);
+       reg_write(priv, REG_TX3, 39);
 
        /* if necessary, disable multi-master: */
        if (priv->rev == TDA19989)
-               reg_set(encoder, REG_I2C_MASTER, I2C_MASTER_DIS_MM);
+               reg_set(priv, REG_I2C_MASTER, I2C_MASTER_DIS_MM);
 
-       cec_write(encoder, REG_CEC_FRO_IM_CLK_CTRL,
+       cec_write(priv, REG_CEC_FRO_IM_CLK_CTRL,
                        CEC_FRO_IM_CLK_CTRL_GHOST_DIS | CEC_FRO_IM_CLK_CTRL_IMCLK_SEL);
 
+       /* initialize the optional IRQ */
+       if (client->irq) {
+               int irqf_trigger;
+
+               /* init read EDID waitqueue */
+               init_waitqueue_head(&priv->wq_edid);
+
+               /* clear pending interrupts */
+               reg_read(priv, REG_INT_FLAGS_0);
+               reg_read(priv, REG_INT_FLAGS_1);
+               reg_read(priv, REG_INT_FLAGS_2);
+
+               irqf_trigger =
+                       irqd_get_trigger_type(irq_get_irq_data(client->irq));
+               ret = request_threaded_irq(client->irq, NULL,
+                                          tda998x_irq_thread,
+                                          irqf_trigger | IRQF_ONESHOT,
+                                          "tda998x", priv);
+               if (ret) {
+                       dev_err(&client->dev,
+                               "failed to request IRQ#%u: %d\n",
+                               client->irq, ret);
+                       goto fail;
+               }
+
+               /* enable HPD irq */
+               cec_write(priv, REG_CEC_RXSHPDINTENA, CEC_RXSHPDLEV_HPD);
+       }
+
+       /* enable EDID read irq: */
+       reg_set(priv, REG_INT_FLAGS_2, INT_FLAGS_2_EDID_BLK_RD);
+
+       if (!np)
+               return 0;               /* non-DT */
+
+       /* get the optional video properties */
+       ret = of_property_read_u32(np, "video-ports", &video);
+       if (ret == 0) {
+               priv->vip_cntrl_0 = video >> 16;
+               priv->vip_cntrl_1 = video >> 8;
+               priv->vip_cntrl_2 = video;
+       }
+
        return 0;
 
 fail:
@@ -1210,6 +1365,14 @@ fail:
        return -ENXIO;
 }
 
+#ifdef CONFIG_OF
+static const struct of_device_id tda998x_dt_ids[] = {
+       { .compatible = "nxp,tda998x", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tda998x_dt_ids);
+#endif
+
 static struct i2c_device_id tda998x_ids[] = {
        { "tda998x", 0 },
        { }
@@ -1222,6 +1385,7 @@ static struct drm_i2c_encoder_driver tda998x_driver = {
                .remove = tda998x_remove,
                .driver = {
                        .name = "tda998x",
+                       .of_match_table = of_match_ptr(tda998x_dt_ids),
                },
                .id_table = tda998x_ids,
        },
index 9fd44f5..b1445b7 100644 (file)
@@ -3,57 +3,69 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 ccflags-y := -Iinclude/drm
-i915-y := i915_drv.o i915_dma.o i915_irq.o \
-         i915_gpu_error.o \
+
+# Please keep these build lists sorted!
+
+# core driver code
+i915-y := i915_drv.o \
+         i915_params.o \
           i915_suspend.o \
-         i915_gem.o \
+         i915_sysfs.o \
+         intel_pm.o
+i915-$(CONFIG_COMPAT)   += i915_ioc32.o
+i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
+
+# GEM code
+i915-y += i915_cmd_parser.o \
          i915_gem_context.o \
          i915_gem_debug.o \
+         i915_gem_dmabuf.o \
          i915_gem_evict.o \
          i915_gem_execbuffer.o \
          i915_gem_gtt.o \
+         i915_gem.o \
          i915_gem_stolen.o \
          i915_gem_tiling.o \
-         i915_sysfs.o \
+         i915_gpu_error.o \
+         i915_irq.o \
          i915_trace_points.o \
-         i915_ums.o \
+         intel_ringbuffer.o \
+         intel_uncore.o
+
+# modesetting core code
+i915-y += intel_bios.o \
          intel_display.o \
-         intel_crt.o \
-         intel_lvds.o \
-         intel_dsi.o \
-         intel_dsi_cmd.o \
-         intel_dsi_pll.o \
-         intel_bios.o \
-         intel_ddi.o \
-         intel_dp.o \
-         intel_hdmi.o \
-         intel_sdvo.o \
          intel_modes.o \
-         intel_panel.o \
-         intel_pm.o \
-         intel_i2c.o \
-         intel_tv.o \
-         intel_dvo.o \
-         intel_ringbuffer.o \
          intel_overlay.o \
-         intel_sprite.o \
          intel_sideband.o \
-         intel_uncore.o \
+         intel_sprite.o
+i915-$(CONFIG_ACPI)            += intel_acpi.o intel_opregion.o
+i915-$(CONFIG_DRM_I915_FBDEV)  += intel_fbdev.o
+
+# modesetting output/encoder code
+i915-y += dvo_ch7017.o \
          dvo_ch7xxx.o \
-         dvo_ch7017.o \
          dvo_ivch.o \
-         dvo_tfp410.o \
-         dvo_sil164.o \
          dvo_ns2501.o \
-         i915_gem_dmabuf.o
-
-i915-$(CONFIG_COMPAT)   += i915_ioc32.o
-
-i915-$(CONFIG_ACPI)    += intel_acpi.o intel_opregion.o
-
-i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o
+         dvo_sil164.o \
+         dvo_tfp410.o \
+         intel_crt.o \
+         intel_ddi.o \
+         intel_dp.o \
+         intel_dsi_cmd.o \
+         intel_dsi.o \
+         intel_dsi_pll.o \
+         intel_dvo.o \
+         intel_hdmi.o \
+         intel_i2c.o \
+         intel_lvds.o \
+         intel_panel.o \
+         intel_sdvo.o \
+         intel_tv.o
 
-i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
+# legacy horrors
+i915-y += i915_dma.o \
+         i915_ums.o
 
 obj-$(CONFIG_DRM_I915)  += i915.o
 
index af42e94..a0f5bdd 100644 (file)
@@ -340,9 +340,9 @@ static void ch7xxx_dump_regs(struct intel_dvo_device *dvo)
        for (i = 0; i < CH7xxx_NUM_REGS; i++) {
                uint8_t val;
                if ((i % 8) == 0)
-                       DRM_LOG_KMS("\n %02X: ", i);
+                       DRM_DEBUG_KMS("\n %02X: ", i);
                ch7xxx_readb(dvo, i, &val);
-               DRM_LOG_KMS("%02X ", val);
+               DRM_DEBUG_KMS("%02X ", val);
        }
 }
 
index baaf65b..0f1865d 100644 (file)
@@ -377,41 +377,41 @@ static void ivch_dump_regs(struct intel_dvo_device *dvo)
        uint16_t val;
 
        ivch_read(dvo, VR00, &val);
-       DRM_LOG_KMS("VR00: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR00: 0x%04x\n", val);
        ivch_read(dvo, VR01, &val);
-       DRM_LOG_KMS("VR01: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR01: 0x%04x\n", val);
        ivch_read(dvo, VR30, &val);
-       DRM_LOG_KMS("VR30: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR30: 0x%04x\n", val);
        ivch_read(dvo, VR40, &val);
-       DRM_LOG_KMS("VR40: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR40: 0x%04x\n", val);
 
        /* GPIO registers */
        ivch_read(dvo, VR80, &val);
-       DRM_LOG_KMS("VR80: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR80: 0x%04x\n", val);
        ivch_read(dvo, VR81, &val);
-       DRM_LOG_KMS("VR81: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR81: 0x%04x\n", val);
        ivch_read(dvo, VR82, &val);
-       DRM_LOG_KMS("VR82: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR82: 0x%04x\n", val);
        ivch_read(dvo, VR83, &val);
-       DRM_LOG_KMS("VR83: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR83: 0x%04x\n", val);
        ivch_read(dvo, VR84, &val);
-       DRM_LOG_KMS("VR84: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR84: 0x%04x\n", val);
        ivch_read(dvo, VR85, &val);
-       DRM_LOG_KMS("VR85: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR85: 0x%04x\n", val);
        ivch_read(dvo, VR86, &val);
-       DRM_LOG_KMS("VR86: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR86: 0x%04x\n", val);
        ivch_read(dvo, VR87, &val);
-       DRM_LOG_KMS("VR87: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR87: 0x%04x\n", val);
        ivch_read(dvo, VR88, &val);
-       DRM_LOG_KMS("VR88: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR88: 0x%04x\n", val);
 
        /* Scratch register 0 - AIM Panel type */
        ivch_read(dvo, VR8E, &val);
-       DRM_LOG_KMS("VR8E: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR8E: 0x%04x\n", val);
 
        /* Scratch register 1 - Status register */
        ivch_read(dvo, VR8F, &val);
-       DRM_LOG_KMS("VR8F: 0x%04x\n", val);
+       DRM_DEBUG_KMS("VR8F: 0x%04x\n", val);
 }
 
 static void ivch_destroy(struct intel_dvo_device *dvo)
index 954acb2..8155ded 100644 (file)
@@ -490,15 +490,15 @@ static void ns2501_dump_regs(struct intel_dvo_device *dvo)
        uint8_t val;
 
        ns2501_readb(dvo, NS2501_FREQ_LO, &val);
-       DRM_LOG_KMS("NS2501_FREQ_LO: 0x%02x\n", val);
+       DRM_DEBUG_KMS("NS2501_FREQ_LO: 0x%02x\n", val);
        ns2501_readb(dvo, NS2501_FREQ_HI, &val);
-       DRM_LOG_KMS("NS2501_FREQ_HI: 0x%02x\n", val);
+       DRM_DEBUG_KMS("NS2501_FREQ_HI: 0x%02x\n", val);
        ns2501_readb(dvo, NS2501_REG8, &val);
-       DRM_LOG_KMS("NS2501_REG8: 0x%02x\n", val);
+       DRM_DEBUG_KMS("NS2501_REG8: 0x%02x\n", val);
        ns2501_readb(dvo, NS2501_REG9, &val);
-       DRM_LOG_KMS("NS2501_REG9: 0x%02x\n", val);
+       DRM_DEBUG_KMS("NS2501_REG9: 0x%02x\n", val);
        ns2501_readb(dvo, NS2501_REGC, &val);
-       DRM_LOG_KMS("NS2501_REGC: 0x%02x\n", val);
+       DRM_DEBUG_KMS("NS2501_REGC: 0x%02x\n", val);
 }
 
 static void ns2501_destroy(struct intel_dvo_device *dvo)
index 4debd32..7b3e9e9 100644 (file)
@@ -246,15 +246,15 @@ static void sil164_dump_regs(struct intel_dvo_device *dvo)
        uint8_t val;
 
        sil164_readb(dvo, SIL164_FREQ_LO, &val);
-       DRM_LOG_KMS("SIL164_FREQ_LO: 0x%02x\n", val);
+       DRM_DEBUG_KMS("SIL164_FREQ_LO: 0x%02x\n", val);
        sil164_readb(dvo, SIL164_FREQ_HI, &val);
-       DRM_LOG_KMS("SIL164_FREQ_HI: 0x%02x\n", val);
+       DRM_DEBUG_KMS("SIL164_FREQ_HI: 0x%02x\n", val);
        sil164_readb(dvo, SIL164_REG8, &val);
-       DRM_LOG_KMS("SIL164_REG8: 0x%02x\n", val);
+       DRM_DEBUG_KMS("SIL164_REG8: 0x%02x\n", val);
        sil164_readb(dvo, SIL164_REG9, &val);
-       DRM_LOG_KMS("SIL164_REG9: 0x%02x\n", val);
+       DRM_DEBUG_KMS("SIL164_REG9: 0x%02x\n", val);
        sil164_readb(dvo, SIL164_REGC, &val);
-       DRM_LOG_KMS("SIL164_REGC: 0x%02x\n", val);
+       DRM_DEBUG_KMS("SIL164_REGC: 0x%02x\n", val);
 }
 
 static void sil164_destroy(struct intel_dvo_device *dvo)
index e17f1b0..12ea4b1 100644 (file)
@@ -267,33 +267,33 @@ static void tfp410_dump_regs(struct intel_dvo_device *dvo)
        uint8_t val, val2;
 
        tfp410_readb(dvo, TFP410_REV, &val);
-       DRM_LOG_KMS("TFP410_REV: 0x%02X\n", val);
+       DRM_DEBUG_KMS("TFP410_REV: 0x%02X\n", val);
        tfp410_readb(dvo, TFP410_CTL_1, &val);
-       DRM_LOG_KMS("TFP410_CTL1: 0x%02X\n", val);
+       DRM_DEBUG_KMS("TFP410_CTL1: 0x%02X\n", val);
        tfp410_readb(dvo, TFP410_CTL_2, &val);
-       DRM_LOG_KMS("TFP410_CTL2: 0x%02X\n", val);
+       DRM_DEBUG_KMS("TFP410_CTL2: 0x%02X\n", val);
        tfp410_readb(dvo, TFP410_CTL_3, &val);
-       DRM_LOG_KMS("TFP410_CTL3: 0x%02X\n", val);
+       DRM_DEBUG_KMS("TFP410_CTL3: 0x%02X\n", val);
        tfp410_readb(dvo, TFP410_USERCFG, &val);
-       DRM_LOG_KMS("TFP410_USERCFG: 0x%02X\n", val);
+       DRM_DEBUG_KMS("TFP410_USERCFG: 0x%02X\n", val);
        tfp410_readb(dvo, TFP410_DE_DLY, &val);
-       DRM_LOG_KMS("TFP410_DE_DLY: 0x%02X\n", val);
+       DRM_DEBUG_KMS("TFP410_DE_DLY: 0x%02X\n", val);
        tfp410_readb(dvo, TFP410_DE_CTL, &val);
-       DRM_LOG_KMS("TFP410_DE_CTL: 0x%02X\n", val);
+       DRM_DEBUG_KMS("TFP410_DE_CTL: 0x%02X\n", val);
        tfp410_readb(dvo, TFP410_DE_TOP, &val);
-       DRM_LOG_KMS("TFP410_DE_TOP: 0x%02X\n", val);
+       DRM_DEBUG_KMS("TFP410_DE_TOP: 0x%02X\n", val);
        tfp410_readb(dvo, TFP410_DE_CNT_LO, &val);
        tfp410_readb(dvo, TFP410_DE_CNT_HI, &val2);
-       DRM_LOG_KMS("TFP410_DE_CNT: 0x%02X%02X\n", val2, val);
+       DRM_DEBUG_KMS("TFP410_DE_CNT: 0x%02X%02X\n", val2, val);
        tfp410_readb(dvo, TFP410_DE_LIN_LO, &val);
        tfp410_readb(dvo, TFP410_DE_LIN_HI, &val2);
-       DRM_LOG_KMS("TFP410_DE_LIN: 0x%02X%02X\n", val2, val);
+       DRM_DEBUG_KMS("TFP410_DE_LIN: 0x%02X%02X\n", val2, val);
        tfp410_readb(dvo, TFP410_H_RES_LO, &val);
        tfp410_readb(dvo, TFP410_H_RES_HI, &val2);
-       DRM_LOG_KMS("TFP410_H_RES: 0x%02X%02X\n", val2, val);
+       DRM_DEBUG_KMS("TFP410_H_RES: 0x%02X%02X\n", val2, val);
        tfp410_readb(dvo, TFP410_V_RES_LO, &val);
        tfp410_readb(dvo, TFP410_V_RES_HI, &val2);
-       DRM_LOG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val);
+       DRM_DEBUG_KMS("TFP410_V_RES: 0x%02X%02X\n", val2, val);
 }
 
 static void tfp410_destroy(struct intel_dvo_device *dvo)
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c
new file mode 100644 (file)
index 0000000..4cf6d02
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * 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.
+ *
+ * Authors:
+ *    Brad Volkin <bradley.d.volkin@intel.com>
+ *
+ */
+
+#include "i915_drv.h"
+
+/**
+ * DOC: i915 batch buffer command parser
+ *
+ * Motivation:
+ * Certain OpenGL features (e.g. transform feedback, performance monitoring)
+ * require userspace code to submit batches containing commands such as
+ * MI_LOAD_REGISTER_IMM to access various registers. Unfortunately, some
+ * generations of the hardware will noop these commands in "unsecure" batches
+ * (which includes all userspace batches submitted via i915) even though the
+ * commands may be safe and represent the intended programming model of the
+ * device.
+ *
+ * The software command parser is similar in operation to the command parsing
+ * done in hardware for unsecure batches. However, the software parser allows
+ * some operations that would be noop'd by hardware, if the parser determines
+ * the operation is safe, and submits the batch as "secure" to prevent hardware
+ * parsing.
+ *
+ * Threats:
+ * At a high level, the hardware (and software) checks attempt to prevent
+ * granting userspace undue privileges. There are three categories of privilege.
+ *
+ * First, commands which are explicitly defined as privileged or which should
+ * only be used by the kernel driver. The parser generally rejects such
+ * commands, though it may allow some from the drm master process.
+ *
+ * Second, commands which access registers. To support correct/enhanced
+ * userspace functionality, particularly certain OpenGL extensions, the parser
+ * provides a whitelist of registers which userspace may safely access (for both
+ * normal and drm master processes).
+ *
+ * Third, commands which access privileged memory (i.e. GGTT, HWS page, etc).
+ * The parser always rejects such commands.
+ *
+ * The majority of the problematic commands fall in the MI_* range, with only a
+ * few specific commands on each ring (e.g. PIPE_CONTROL and MI_FLUSH_DW).
+ *
+ * Implementation:
+ * Each ring maintains tables of commands and registers which the parser uses in
+ * scanning batch buffers submitted to that ring.
+ *
+ * Since the set of commands that the parser must check for is significantly
+ * smaller than the number of commands supported, the parser tables contain only
+ * those commands required by the parser. This generally works because command
+ * opcode ranges have standard command length encodings. So for commands that
+ * the parser does not need to check, it can easily skip them. This is
+ * implementated via a per-ring length decoding vfunc.
+ *
+ * Unfortunately, there are a number of commands that do not follow the standard
+ * length encoding for their opcode range, primarily amongst the MI_* commands.
+ * To handle this, the parser provides a way to define explicit "skip" entries
+ * in the per-ring command tables.
+ *
+ * Other command table entries map fairly directly to high level categories
+ * mentioned above: rejected, master-only, register whitelist. The parser
+ * implements a number of checks, including the privileged memory checks, via a
+ * general bitmasking mechanism.
+ */
+
+static u32 gen7_render_get_cmd_length_mask(u32 cmd_header)
+{
+       u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
+       u32 subclient =
+               (cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT;
+
+       if (client == INSTR_MI_CLIENT)
+               return 0x3F;
+       else if (client == INSTR_RC_CLIENT) {
+               if (subclient == INSTR_MEDIA_SUBCLIENT)
+                       return 0xFFFF;
+               else
+                       return 0xFF;
+       }
+
+       DRM_DEBUG_DRIVER("CMD: Abnormal rcs cmd length! 0x%08X\n", cmd_header);
+       return 0;
+}
+
+static u32 gen7_bsd_get_cmd_length_mask(u32 cmd_header)
+{
+       u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
+       u32 subclient =
+               (cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT;
+
+       if (client == INSTR_MI_CLIENT)
+               return 0x3F;
+       else if (client == INSTR_RC_CLIENT) {
+               if (subclient == INSTR_MEDIA_SUBCLIENT)
+                       return 0xFFF;
+               else
+                       return 0xFF;
+       }
+
+       DRM_DEBUG_DRIVER("CMD: Abnormal bsd cmd length! 0x%08X\n", cmd_header);
+       return 0;
+}
+
+static u32 gen7_blt_get_cmd_length_mask(u32 cmd_header)
+{
+       u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
+
+       if (client == INSTR_MI_CLIENT)
+               return 0x3F;
+       else if (client == INSTR_BC_CLIENT)
+               return 0xFF;
+
+       DRM_DEBUG_DRIVER("CMD: Abnormal blt cmd length! 0x%08X\n", cmd_header);
+       return 0;
+}
+
+static void validate_cmds_sorted(struct intel_ring_buffer *ring)
+{
+       int i;
+
+       if (!ring->cmd_tables || ring->cmd_table_count == 0)
+               return;
+
+       for (i = 0; i < ring->cmd_table_count; i++) {
+               const struct drm_i915_cmd_table *table = &ring->cmd_tables[i];
+               u32 previous = 0;
+               int j;
+
+               for (j = 0; j < table->count; j++) {
+                       const struct drm_i915_cmd_descriptor *desc =
+                               &table->table[i];
+                       u32 curr = desc->cmd.value & desc->cmd.mask;
+
+                       if (curr < previous)
+                               DRM_ERROR("CMD: table not sorted ring=%d table=%d entry=%d cmd=0x%08X prev=0x%08X\n",
+                                         ring->id, i, j, curr, previous);
+
+                       previous = curr;
+               }
+       }
+}
+
+static void check_sorted(int ring_id, const u32 *reg_table, int reg_count)
+{
+       int i;
+       u32 previous = 0;
+
+       for (i = 0; i < reg_count; i++) {
+               u32 curr = reg_table[i];
+
+               if (curr < previous)
+                       DRM_ERROR("CMD: table not sorted ring=%d entry=%d reg=0x%08X prev=0x%08X\n",
+                                 ring_id, i, curr, previous);
+
+               previous = curr;
+       }
+}
+
+static void validate_regs_sorted(struct intel_ring_buffer *ring)
+{
+       check_sorted(ring->id, ring->reg_table, ring->reg_count);
+       check_sorted(ring->id, ring->master_reg_table, ring->master_reg_count);
+}
+
+/**
+ * i915_cmd_parser_init_ring() - set cmd parser related fields for a ringbuffer
+ * @ring: the ringbuffer to initialize
+ *
+ * Optionally initializes fields related to batch buffer command parsing in the
+ * struct intel_ring_buffer based on whether the platform requires software
+ * command parsing.
+ */
+void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring)
+{
+       if (!IS_GEN7(ring->dev))
+               return;
+
+       switch (ring->id) {
+       case RCS:
+               ring->get_cmd_length_mask = gen7_render_get_cmd_length_mask;
+               break;
+       case VCS:
+               ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
+               break;
+       case BCS:
+               ring->get_cmd_length_mask = gen7_blt_get_cmd_length_mask;
+               break;
+       case VECS:
+               /* VECS can use the same length_mask function as VCS */
+               ring->get_cmd_length_mask = gen7_bsd_get_cmd_length_mask;
+               break;
+       default:
+               DRM_ERROR("CMD: cmd_parser_init with unknown ring: %d\n",
+                         ring->id);
+               BUG();
+       }
+
+       validate_cmds_sorted(ring);
+       validate_regs_sorted(ring);
+}
+
+static const struct drm_i915_cmd_descriptor*
+find_cmd_in_table(const struct drm_i915_cmd_table *table,
+                 u32 cmd_header)
+{
+       int i;
+
+       for (i = 0; i < table->count; i++) {
+               const struct drm_i915_cmd_descriptor *desc = &table->table[i];
+               u32 masked_cmd = desc->cmd.mask & cmd_header;
+               u32 masked_value = desc->cmd.value & desc->cmd.mask;
+
+               if (masked_cmd == masked_value)
+                       return desc;
+       }
+
+       return NULL;
+}
+
+/*
+ * Returns a pointer to a descriptor for the command specified by cmd_header.
+ *
+ * The caller must supply space for a default descriptor via the default_desc
+ * parameter. If no descriptor for the specified command exists in the ring's
+ * command parser tables, this function fills in default_desc based on the
+ * ring's default length encoding and returns default_desc.
+ */
+static const struct drm_i915_cmd_descriptor*
+find_cmd(struct intel_ring_buffer *ring,
+        u32 cmd_header,
+        struct drm_i915_cmd_descriptor *default_desc)
+{
+       u32 mask;
+       int i;
+
+       for (i = 0; i < ring->cmd_table_count; i++) {
+               const struct drm_i915_cmd_descriptor *desc;
+
+               desc = find_cmd_in_table(&ring->cmd_tables[i], cmd_header);
+               if (desc)
+                       return desc;
+       }
+
+       mask = ring->get_cmd_length_mask(cmd_header);
+       if (!mask)
+               return NULL;
+
+       BUG_ON(!default_desc);
+       default_desc->flags = CMD_DESC_SKIP;
+       default_desc->length.mask = mask;
+
+       return default_desc;
+}
+
+static bool valid_reg(const u32 *table, int count, u32 addr)
+{
+       if (table && count != 0) {
+               int i;
+
+               for (i = 0; i < count; i++) {
+                       if (table[i] == addr)
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+static u32 *vmap_batch(struct drm_i915_gem_object *obj)
+{
+       int i;
+       void *addr = NULL;
+       struct sg_page_iter sg_iter;
+       struct page **pages;
+
+       pages = drm_malloc_ab(obj->base.size >> PAGE_SHIFT, sizeof(*pages));
+       if (pages == NULL) {
+               DRM_DEBUG_DRIVER("Failed to get space for pages\n");
+               goto finish;
+       }
+
+       i = 0;
+       for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents, 0) {
+               pages[i] = sg_page_iter_page(&sg_iter);
+               i++;
+       }
+
+       addr = vmap(pages, i, 0, PAGE_KERNEL);
+       if (addr == NULL) {
+               DRM_DEBUG_DRIVER("Failed to vmap pages\n");
+               goto finish;
+       }
+
+finish:
+       if (pages)
+               drm_free_large(pages);
+       return (u32*)addr;
+}
+
+/**
+ * i915_needs_cmd_parser() - should a given ring use software command parsing?
+ * @ring: the ring in question
+ *
+ * Only certain platforms require software batch buffer command parsing, and
+ * only when enabled via module paramter.
+ *
+ * Return: true if the ring requires software command parsing
+ */
+bool i915_needs_cmd_parser(struct intel_ring_buffer *ring)
+{
+       /* No command tables indicates a platform without parsing */
+       if (!ring->cmd_tables)
+               return false;
+
+       return (i915.enable_cmd_parser == 1);
+}
+
+#define LENGTH_BIAS 2
+
+/**
+ * i915_parse_cmds() - parse a submitted batch buffer for privilege violations
+ * @ring: the ring on which the batch is to execute
+ * @batch_obj: the batch buffer in question
+ * @batch_start_offset: byte offset in the batch at which execution starts
+ * @is_master: is the submitting process the drm master?
+ *
+ * Parses the specified batch buffer looking for privilege violations as
+ * described in the overview.
+ *
+ * Return: non-zero if the parser finds violations or otherwise fails
+ */
+int i915_parse_cmds(struct intel_ring_buffer *ring,
+                   struct drm_i915_gem_object *batch_obj,
+                   u32 batch_start_offset,
+                   bool is_master)
+{
+       int ret = 0;
+       u32 *cmd, *batch_base, *batch_end;
+       struct drm_i915_cmd_descriptor default_desc = { 0 };
+       int needs_clflush = 0;
+
+       ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush);
+       if (ret) {
+               DRM_DEBUG_DRIVER("CMD: failed to prep read\n");
+               return ret;
+       }
+
+       batch_base = vmap_batch(batch_obj);
+       if (!batch_base) {
+               DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
+               i915_gem_object_unpin_pages(batch_obj);
+               return -ENOMEM;
+       }
+
+       if (needs_clflush)
+               drm_clflush_virt_range((char *)batch_base, batch_obj->base.size);
+
+       cmd = batch_base + (batch_start_offset / sizeof(*cmd));
+       batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end));
+
+       while (cmd < batch_end) {
+               const struct drm_i915_cmd_descriptor *desc;
+               u32 length;
+
+               if (*cmd == MI_BATCH_BUFFER_END)
+                       break;
+
+               desc = find_cmd(ring, *cmd, &default_desc);
+               if (!desc) {
+                       DRM_DEBUG_DRIVER("CMD: Unrecognized command: 0x%08X\n",
+                                        *cmd);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (desc->flags & CMD_DESC_FIXED)
+                       length = desc->length.fixed;
+               else
+                       length = ((*cmd & desc->length.mask) + LENGTH_BIAS);
+
+               if ((batch_end - cmd) < length) {
+                       DRM_DEBUG_DRIVER("CMD: Command length exceeds batch length: 0x%08X length=%d batchlen=%td\n",
+                                        *cmd,
+                                        length,
+                                        (unsigned long)(batch_end - cmd));
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (desc->flags & CMD_DESC_REJECT) {
+                       DRM_DEBUG_DRIVER("CMD: Rejected command: 0x%08X\n", *cmd);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if ((desc->flags & CMD_DESC_MASTER) && !is_master) {
+                       DRM_DEBUG_DRIVER("CMD: Rejected master-only command: 0x%08X\n",
+                                        *cmd);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               if (desc->flags & CMD_DESC_REGISTER) {
+                       u32 reg_addr = cmd[desc->reg.offset] & desc->reg.mask;
+
+                       if (!valid_reg(ring->reg_table,
+                                      ring->reg_count, reg_addr)) {
+                               if (!is_master ||
+                                   !valid_reg(ring->master_reg_table,
+                                              ring->master_reg_count,
+                                              reg_addr)) {
+                                       DRM_DEBUG_DRIVER("CMD: Rejected register 0x%08X in command: 0x%08X (ring=%d)\n",
+                                                        reg_addr,
+                                                        *cmd,
+                                                        ring->id);
+                                       ret = -EINVAL;
+                                       break;
+                               }
+                       }
+               }
+
+               if (desc->flags & CMD_DESC_BITMASK) {
+                       int i;
+
+                       for (i = 0; i < MAX_CMD_DESC_BITMASKS; i++) {
+                               u32 dword;
+
+                               if (desc->bits[i].mask == 0)
+                                       break;
+
+                               dword = cmd[desc->bits[i].offset] &
+                                       desc->bits[i].mask;
+
+                               if (dword != desc->bits[i].expected) {
+                                       DRM_DEBUG_DRIVER("CMD: Rejected command 0x%08X for bitmask 0x%08X (exp=0x%08X act=0x%08X) (ring=%d)\n",
+                                                        *cmd,
+                                                        desc->bits[i].mask,
+                                                        desc->bits[i].expected,
+                                                        dword, ring->id);
+                                       ret = -EINVAL;
+                                       break;
+                               }
+                       }
+
+                       if (ret)
+                               break;
+               }
+
+               cmd += length;
+       }
+
+       if (cmd >= batch_end) {
+               DRM_DEBUG_DRIVER("CMD: Got to the end of the buffer w/o a BBE cmd!\n");
+               ret = -EINVAL;
+       }
+
+       vunmap(batch_base);
+
+       i915_gem_object_unpin_pages(batch_obj);
+
+       return ret;
+}
index b2b46c5..195fe5b 100644 (file)
@@ -98,7 +98,7 @@ static const char *get_pin_flag(struct drm_i915_gem_object *obj)
 {
        if (obj->user_pin_count > 0)
                return "P";
-       else if (obj->pin_count > 0)
+       else if (i915_gem_obj_is_pinned(obj))
                return "p";
        else
                return " ";
@@ -123,6 +123,8 @@ static void
 describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
 {
        struct i915_vma *vma;
+       int pin_count = 0;
+
        seq_printf(m, "%pK: %s%s%s %8zdKiB %02x %02x %u %u %u%s%s%s",
                   &obj->base,
                   get_pin_flag(obj),
@@ -139,8 +141,10 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                   obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
        if (obj->base.name)
                seq_printf(m, " (name: %d)", obj->base.name);
-       if (obj->pin_count)
-               seq_printf(m, " (pinned x %d)", obj->pin_count);
+       list_for_each_entry(vma, &obj->vma_list, vma_link)
+               if (vma->pin_count > 0)
+                       pin_count++;
+               seq_printf(m, " (pinned x %d)", pin_count);
        if (obj->pin_display)
                seq_printf(m, " (display)");
        if (obj->fence_reg != I915_FENCE_REG_NONE)
@@ -295,28 +299,62 @@ static int i915_gem_stolen_list_info(struct seq_file *m, void *data)
 } while (0)
 
 struct file_stats {
+       struct drm_i915_file_private *file_priv;
        int count;
-       size_t total, active, inactive, unbound;
+       size_t total, unbound;
+       size_t global, shared;
+       size_t active, inactive;
 };
 
 static int per_file_stats(int id, void *ptr, void *data)
 {
        struct drm_i915_gem_object *obj = ptr;
        struct file_stats *stats = data;
+       struct i915_vma *vma;
 
        stats->count++;
        stats->total += obj->base.size;
 
-       if (i915_gem_obj_ggtt_bound(obj)) {
-               if (!list_empty(&obj->ring_list))
-                       stats->active += obj->base.size;
-               else
-                       stats->inactive += obj->base.size;
+       if (obj->base.name || obj->base.dma_buf)
+               stats->shared += obj->base.size;
+
+       if (USES_FULL_PPGTT(obj->base.dev)) {
+               list_for_each_entry(vma, &obj->vma_list, vma_link) {
+                       struct i915_hw_ppgtt *ppgtt;
+
+                       if (!drm_mm_node_allocated(&vma->node))
+                               continue;
+
+                       if (i915_is_ggtt(vma->vm)) {
+                               stats->global += obj->base.size;
+                               continue;
+                       }
+
+                       ppgtt = container_of(vma->vm, struct i915_hw_ppgtt, base);
+                       if (ppgtt->ctx && ppgtt->ctx->file_priv != stats->file_priv)
+                               continue;
+
+                       if (obj->ring) /* XXX per-vma statistic */
+                               stats->active += obj->base.size;
+                       else
+                               stats->inactive += obj->base.size;
+
+                       return 0;
+               }
        } else {
-               if (!list_empty(&obj->global_list))
-                       stats->unbound += obj->base.size;
+               if (i915_gem_obj_ggtt_bound(obj)) {
+                       stats->global += obj->base.size;
+                       if (obj->ring)
+                               stats->active += obj->base.size;
+                       else
+                               stats->inactive += obj->base.size;
+                       return 0;
+               }
        }
 
+       if (!list_empty(&obj->global_list))
+               stats->unbound += obj->base.size;
+
        return 0;
 }
 
@@ -407,6 +445,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
                struct task_struct *task;
 
                memset(&stats, 0, sizeof(stats));
+               stats.file_priv = file->driver_priv;
                idr_for_each(&file->object_idr, per_file_stats, &stats);
                /*
                 * Although we have a valid reference on file->pid, that does
@@ -416,12 +455,14 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
                 */
                rcu_read_lock();
                task = pid_task(file->pid, PIDTYPE_PID);
-               seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu unbound)\n",
+               seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n",
                           task ? task->comm : "<unknown>",
                           stats.count,
                           stats.total,
                           stats.active,
                           stats.inactive,
+                          stats.global,
+                          stats.shared,
                           stats.unbound);
                rcu_read_unlock();
        }
@@ -447,7 +488,7 @@ static int i915_gem_gtt_info(struct seq_file *m, void *data)
 
        total_obj_size = total_gtt_size = count = 0;
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
-               if (list == PINNED_LIST && obj->pin_count == 0)
+               if (list == PINNED_LIST && !i915_gem_obj_is_pinned(obj))
                        continue;
 
                seq_puts(m, "   ");
@@ -520,7 +561,7 @@ static int i915_gem_request_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;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
        struct drm_i915_gem_request *gem_request;
        int ret, count, i;
@@ -565,7 +606,7 @@ static int i915_gem_seqno_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;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
        int ret, i;
 
@@ -588,7 +629,7 @@ static int i915_interrupt_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;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
        int ret, i, pipe;
 
@@ -598,7 +639,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        intel_runtime_pm_get(dev_priv);
 
        if (INTEL_INFO(dev)->gen >= 8) {
-               int i;
                seq_printf(m, "Master Interrupt Control:\t%08x\n",
                           I915_READ(GEN8_MASTER_IRQ));
 
@@ -611,16 +651,16 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                                   i, I915_READ(GEN8_GT_IER(i)));
                }
 
-               for_each_pipe(i) {
+               for_each_pipe(pipe) {
                        seq_printf(m, "Pipe %c IMR:\t%08x\n",
-                                  pipe_name(i),
-                                  I915_READ(GEN8_DE_PIPE_IMR(i)));
+                                  pipe_name(pipe),
+                                  I915_READ(GEN8_DE_PIPE_IMR(pipe)));
                        seq_printf(m, "Pipe %c IIR:\t%08x\n",
-                                  pipe_name(i),
-                                  I915_READ(GEN8_DE_PIPE_IIR(i)));
+                                  pipe_name(pipe),
+                                  I915_READ(GEN8_DE_PIPE_IIR(pipe)));
                        seq_printf(m, "Pipe %c IER:\t%08x\n",
-                                  pipe_name(i),
-                                  I915_READ(GEN8_DE_PIPE_IER(i)));
+                                  pipe_name(pipe),
+                                  I915_READ(GEN8_DE_PIPE_IER(pipe)));
                }
 
                seq_printf(m, "Display Engine port interrupt mask:\t%08x\n",
@@ -712,8 +752,6 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                seq_printf(m, "Graphics Interrupt mask:         %08x\n",
                           I915_READ(GTIMR));
        }
-       seq_printf(m, "Interrupts received: %d\n",
-                  atomic_read(&dev_priv->irq_received));
        for_each_ring(ring, dev_priv, i) {
                if (INTEL_INFO(dev)->gen >= 6) {
                        seq_printf(m,
@@ -732,7 +770,7 @@ static int i915_gem_fence_regs_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;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int i, ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -761,7 +799,7 @@ static int i915_hws_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;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
        const u32 *hws;
        int i;
@@ -872,7 +910,7 @@ static int
 i915_next_seqno_get(void *data, u64 *val)
 {
        struct drm_device *dev = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -909,7 +947,7 @@ static int i915_rstdby_delays(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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;
        u16 crstanddelay;
        int ret;
 
@@ -932,7 +970,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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;
        int ret = 0;
 
        intel_runtime_pm_get(dev_priv);
@@ -1025,7 +1063,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                           max_freq * GT_FREQUENCY_MULTIPLIER);
 
                seq_printf(m, "Max overclocked frequency: %dMHz\n",
-                          dev_priv->rps.hw_max * GT_FREQUENCY_MULTIPLIER);
+                          dev_priv->rps.max_freq * GT_FREQUENCY_MULTIPLIER);
        } else if (IS_VALLEYVIEW(dev)) {
                u32 freq_sts, val;
 
@@ -1058,7 +1096,7 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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;
        u32 delayfreq;
        int ret, i;
 
@@ -1089,7 +1127,7 @@ static int i915_inttoext_table(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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;
        u32 inttoext;
        int ret, i;
 
@@ -1113,7 +1151,7 @@ static int ironlake_drpc_info(struct seq_file *m)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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;
        u32 rgvmodectl, rstdbyctl;
        u16 crstandvid;
        int ret;
@@ -1339,13 +1377,15 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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;
 
        if (!HAS_FBC(dev)) {
                seq_puts(m, "FBC unsupported on this chipset\n");
                return 0;
        }
 
+       intel_runtime_pm_get(dev_priv);
+
        if (intel_fbc_enabled(dev)) {
                seq_puts(m, "FBC enabled\n");
        } else {
@@ -1389,6 +1429,9 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
                }
                seq_putc(m, '\n');
        }
+
+       intel_runtime_pm_put(dev_priv);
+
        return 0;
 }
 
@@ -1403,11 +1446,15 @@ static int i915_ips_status(struct seq_file *m, void *unused)
                return 0;
        }
 
+       intel_runtime_pm_get(dev_priv);
+
        if (IS_BROADWELL(dev) || I915_READ(IPS_CTL) & IPS_ENABLE)
                seq_puts(m, "enabled\n");
        else
                seq_puts(m, "disabled\n");
 
+       intel_runtime_pm_put(dev_priv);
+
        return 0;
 }
 
@@ -1415,9 +1462,11 @@ static int i915_sr_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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;
        bool sr_enabled = false;
 
+       intel_runtime_pm_get(dev_priv);
+
        if (HAS_PCH_SPLIT(dev))
                sr_enabled = I915_READ(WM1_LP_ILK) & WM1_LP_SR_EN;
        else if (IS_CRESTLINE(dev) || IS_I945G(dev) || IS_I945GM(dev))
@@ -1427,6 +1476,8 @@ static int i915_sr_status(struct seq_file *m, void *unused)
        else if (IS_PINEVIEW(dev))
                sr_enabled = I915_READ(DSPFW3) & PINEVIEW_SELF_REFRESH_EN;
 
+       intel_runtime_pm_put(dev_priv);
+
        seq_printf(m, "self-refresh: %s\n",
                   sr_enabled ? "enabled" : "disabled");
 
@@ -1437,7 +1488,7 @@ static int i915_emon_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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;
        unsigned long temp, chipset, gfx;
        int ret;
 
@@ -1465,8 +1516,8 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       int ret;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
        int gpu_freq, ia_freq;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev))) {
@@ -1474,17 +1525,18 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
                return 0;
        }
 
+       intel_runtime_pm_get(dev_priv);
+
        flush_delayed_work(&dev_priv->rps.delayed_resume_work);
 
        ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
-               return ret;
-       intel_runtime_pm_get(dev_priv);
+               goto out;
 
        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;
+       for (gpu_freq = dev_priv->rps.min_freq_softlimit;
+            gpu_freq <= dev_priv->rps.max_freq_softlimit;
             gpu_freq++) {
                ia_freq = gpu_freq;
                sandybridge_pcode_read(dev_priv,
@@ -1496,17 +1548,18 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
                           ((ia_freq >> 8) & 0xff) * 100);
        }
 
-       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev_priv->rps.hw_lock);
 
-       return 0;
+out:
+       intel_runtime_pm_put(dev_priv);
+       return ret;
 }
 
 static int i915_gfxec(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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;
        int ret;
 
        ret = mutex_lock_interruptible(&dev->struct_mutex);
@@ -1526,7 +1579,7 @@ static int i915_opregion(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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 intel_opregion *opregion = &dev_priv->opregion;
        void *data = kmalloc(OPREGION_SIZE, GFP_KERNEL);
        int ret;
@@ -1600,7 +1653,7 @@ static int i915_context_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        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 intel_ring_buffer *ring;
        struct i915_hw_context *ctx;
        int ret, i;
@@ -1733,6 +1786,17 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
        return 0;
 }
 
+static int per_file_ctx(int id, void *ptr, void *data)
+{
+       struct i915_hw_context *ctx = ptr;
+       struct seq_file *m = data;
+       struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(ctx);
+
+       ppgtt->debug_dump(ppgtt, m);
+
+       return 0;
+}
+
 static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1744,7 +1808,7 @@ static void gen8_ppgtt_info(struct seq_file *m, struct drm_device *dev)
                return;
 
        seq_printf(m, "Page directories: %d\n", ppgtt->num_pd_pages);
-       seq_printf(m, "Page tables: %d\n", ppgtt->num_pt_pages);
+       seq_printf(m, "Page tables: %d\n", ppgtt->num_pd_entries);
        for_each_ring(ring, dev_priv, unused) {
                seq_printf(m, "%s\n", ring->name);
                for (i = 0; i < 4; i++) {
@@ -1762,6 +1826,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
+       struct drm_file *file;
        int i;
 
        if (INTEL_INFO(dev)->gen == 6)
@@ -1780,6 +1845,20 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
 
                seq_puts(m, "aliasing PPGTT:\n");
                seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
+
+               ppgtt->debug_dump(ppgtt, m);
+       } else
+               return;
+
+       list_for_each_entry_reverse(file, &dev->filelist, lhead) {
+               struct drm_i915_file_private *file_priv = file->driver_priv;
+               struct i915_hw_ppgtt *pvt_ppgtt;
+
+               pvt_ppgtt = ctx_to_ppgtt(file_priv->private_default_ctx);
+               seq_printf(m, "proc: %s\n",
+                          get_pid_task(file->pid, PIDTYPE_PID)->comm);
+               seq_puts(m, "  default context:\n");
+               idr_for_each(&file_priv->context_idr, per_file_ctx, m);
        }
        seq_printf(m, "ECOCHK: 0x%08x\n", I915_READ(GAM_ECOCHK));
 }
@@ -1892,6 +1971,47 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
        return 0;
 }
 
+static int i915_sink_crc(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+       struct intel_dp *intel_dp = NULL;
+       int ret;
+       u8 crc[6];
+
+       drm_modeset_lock_all(dev);
+       list_for_each_entry(connector, &dev->mode_config.connector_list,
+                           base.head) {
+
+               if (connector->base.dpms != DRM_MODE_DPMS_ON)
+                       continue;
+
+               if (!connector->base.encoder)
+                       continue;
+
+               encoder = to_intel_encoder(connector->base.encoder);
+               if (encoder->type != INTEL_OUTPUT_EDP)
+                       continue;
+
+               intel_dp = enc_to_intel_dp(&encoder->base);
+
+               ret = intel_dp_sink_crc(intel_dp, crc);
+               if (ret)
+                       goto out;
+
+               seq_printf(m, "%02x%02x%02x%02x%02x%02x\n",
+                          crc[0], crc[1], crc[2],
+                          crc[3], crc[4], crc[5]);
+               goto out;
+       }
+       ret = -ENODEV;
+out:
+       drm_modeset_unlock_all(dev);
+       return ret;
+}
+
 static int i915_energy_uJ(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = m->private;
@@ -1903,12 +2023,16 @@ static int i915_energy_uJ(struct seq_file *m, void *data)
        if (INTEL_INFO(dev)->gen < 6)
                return -ENODEV;
 
+       intel_runtime_pm_get(dev_priv);
+
        rdmsrl(MSR_RAPL_POWER_UNIT, power);
        power = (power & 0x1f00) >> 8;
        units = 1000000 / (1 << power); /* convert to uJ */
        power = I915_READ(MCH_SECP_NRG_STTS);
        power *= units;
 
+       intel_runtime_pm_put(dev_priv);
+
        seq_printf(m, "%llu", (long long unsigned)power);
 
        return 0;
@@ -1925,15 +2049,9 @@ static int i915_pc8_status(struct seq_file *m, void *unused)
                return 0;
        }
 
-       mutex_lock(&dev_priv->pc8.lock);
-       seq_printf(m, "Requirements met: %s\n",
-                  yesno(dev_priv->pc8.requirements_met));
-       seq_printf(m, "GPU idle: %s\n", yesno(dev_priv->pc8.gpu_idle));
-       seq_printf(m, "Disable count: %d\n", dev_priv->pc8.disable_count);
+       seq_printf(m, "GPU idle: %s\n", yesno(!dev_priv->mm.busy));
        seq_printf(m, "IRQs disabled: %s\n",
-                  yesno(dev_priv->pc8.irqs_disabled));
-       seq_printf(m, "Enabled: %s\n", yesno(dev_priv->pc8.enabled));
-       mutex_unlock(&dev_priv->pc8.lock);
+                  yesno(dev_priv->pm.irqs_disabled));
 
        return 0;
 }
@@ -1961,6 +2079,28 @@ static const char *power_domain_str(enum intel_display_power_domain domain)
                return "TRANSCODER_C";
        case POWER_DOMAIN_TRANSCODER_EDP:
                return "TRANSCODER_EDP";
+       case POWER_DOMAIN_PORT_DDI_A_2_LANES:
+               return "PORT_DDI_A_2_LANES";
+       case POWER_DOMAIN_PORT_DDI_A_4_LANES:
+               return "PORT_DDI_A_4_LANES";
+       case POWER_DOMAIN_PORT_DDI_B_2_LANES:
+               return "PORT_DDI_B_2_LANES";
+       case POWER_DOMAIN_PORT_DDI_B_4_LANES:
+               return "PORT_DDI_B_4_LANES";
+       case POWER_DOMAIN_PORT_DDI_C_2_LANES:
+               return "PORT_DDI_C_2_LANES";
+       case POWER_DOMAIN_PORT_DDI_C_4_LANES:
+               return "PORT_DDI_C_4_LANES";
+       case POWER_DOMAIN_PORT_DDI_D_2_LANES:
+               return "PORT_DDI_D_2_LANES";
+       case POWER_DOMAIN_PORT_DDI_D_4_LANES:
+               return "PORT_DDI_D_4_LANES";
+       case POWER_DOMAIN_PORT_DSI:
+               return "PORT_DSI";
+       case POWER_DOMAIN_PORT_CRT:
+               return "PORT_CRT";
+       case POWER_DOMAIN_PORT_OTHER:
+               return "PORT_OTHER";
        case POWER_DOMAIN_VGA:
                return "VGA";
        case POWER_DOMAIN_AUDIO:
@@ -2008,6 +2148,215 @@ static int i915_power_domain_info(struct seq_file *m, void *unused)
        return 0;
 }
 
+static void intel_seq_print_mode(struct seq_file *m, int tabs,
+                                struct drm_display_mode *mode)
+{
+       int i;
+
+       for (i = 0; i < tabs; i++)
+               seq_putc(m, '\t');
+
+       seq_printf(m, "id %d:\"%s\" freq %d clock %d hdisp %d hss %d hse %d htot %d vdisp %d vss %d vse %d vtot %d type 0x%x flags 0x%x\n",
+                  mode->base.id, mode->name,
+                  mode->vrefresh, mode->clock,
+                  mode->hdisplay, mode->hsync_start,
+                  mode->hsync_end, mode->htotal,
+                  mode->vdisplay, mode->vsync_start,
+                  mode->vsync_end, mode->vtotal,
+                  mode->type, mode->flags);
+}
+
+static void intel_encoder_info(struct seq_file *m,
+                              struct intel_crtc *intel_crtc,
+                              struct intel_encoder *intel_encoder)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_crtc *crtc = &intel_crtc->base;
+       struct intel_connector *intel_connector;
+       struct drm_encoder *encoder;
+
+       encoder = &intel_encoder->base;
+       seq_printf(m, "\tencoder %d: type: %s, connectors:\n",
+                  encoder->base.id, drm_get_encoder_name(encoder));
+       for_each_connector_on_encoder(dev, encoder, intel_connector) {
+               struct drm_connector *connector = &intel_connector->base;
+               seq_printf(m, "\t\tconnector %d: type: %s, status: %s",
+                          connector->base.id,
+                          drm_get_connector_name(connector),
+                          drm_get_connector_status_name(connector->status));
+               if (connector->status == connector_status_connected) {
+                       struct drm_display_mode *mode = &crtc->mode;
+                       seq_printf(m, ", mode:\n");
+                       intel_seq_print_mode(m, 2, mode);
+               } else {
+                       seq_putc(m, '\n');
+               }
+       }
+}
+
+static void intel_crtc_info(struct seq_file *m, struct intel_crtc *intel_crtc)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_crtc *crtc = &intel_crtc->base;
+       struct intel_encoder *intel_encoder;
+
+       seq_printf(m, "\tfb: %d, pos: %dx%d, size: %dx%d\n",
+                  crtc->primary->fb->base.id, crtc->x, crtc->y,
+                  crtc->primary->fb->width, crtc->primary->fb->height);
+       for_each_encoder_on_crtc(dev, crtc, intel_encoder)
+               intel_encoder_info(m, intel_crtc, intel_encoder);
+}
+
+static void intel_panel_info(struct seq_file *m, struct intel_panel *panel)
+{
+       struct drm_display_mode *mode = panel->fixed_mode;
+
+       seq_printf(m, "\tfixed mode:\n");
+       intel_seq_print_mode(m, 2, mode);
+}
+
+static void intel_dp_info(struct seq_file *m,
+                         struct intel_connector *intel_connector)
+{
+       struct intel_encoder *intel_encoder = intel_connector->encoder;
+       struct intel_dp *intel_dp = enc_to_intel_dp(&intel_encoder->base);
+
+       seq_printf(m, "\tDPCD rev: %x\n", intel_dp->dpcd[DP_DPCD_REV]);
+       seq_printf(m, "\taudio support: %s\n", intel_dp->has_audio ? "yes" :
+                  "no");
+       if (intel_encoder->type == INTEL_OUTPUT_EDP)
+               intel_panel_info(m, &intel_connector->panel);
+}
+
+static void intel_hdmi_info(struct seq_file *m,
+                           struct intel_connector *intel_connector)
+{
+       struct intel_encoder *intel_encoder = intel_connector->encoder;
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
+
+       seq_printf(m, "\taudio support: %s\n", intel_hdmi->has_audio ? "yes" :
+                  "no");
+}
+
+static void intel_lvds_info(struct seq_file *m,
+                           struct intel_connector *intel_connector)
+{
+       intel_panel_info(m, &intel_connector->panel);
+}
+
+static void intel_connector_info(struct seq_file *m,
+                                struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_encoder *intel_encoder = intel_connector->encoder;
+       struct drm_display_mode *mode;
+
+       seq_printf(m, "connector %d: type %s, status: %s\n",
+                  connector->base.id, drm_get_connector_name(connector),
+                  drm_get_connector_status_name(connector->status));
+       if (connector->status == connector_status_connected) {
+               seq_printf(m, "\tname: %s\n", connector->display_info.name);
+               seq_printf(m, "\tphysical dimensions: %dx%dmm\n",
+                          connector->display_info.width_mm,
+                          connector->display_info.height_mm);
+               seq_printf(m, "\tsubpixel order: %s\n",
+                          drm_get_subpixel_order_name(connector->display_info.subpixel_order));
+               seq_printf(m, "\tCEA rev: %d\n",
+                          connector->display_info.cea_rev);
+       }
+       if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+           intel_encoder->type == INTEL_OUTPUT_EDP)
+               intel_dp_info(m, intel_connector);
+       else if (intel_encoder->type == INTEL_OUTPUT_HDMI)
+               intel_hdmi_info(m, intel_connector);
+       else if (intel_encoder->type == INTEL_OUTPUT_LVDS)
+               intel_lvds_info(m, intel_connector);
+
+       seq_printf(m, "\tmodes:\n");
+       list_for_each_entry(mode, &connector->modes, head)
+               intel_seq_print_mode(m, 2, mode);
+}
+
+static bool cursor_active(struct drm_device *dev, int pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 state;
+
+       if (IS_845G(dev) || IS_I865G(dev))
+               state = I915_READ(_CURACNTR) & CURSOR_ENABLE;
+       else if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev))
+               state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
+       else
+               state = I915_READ(CURCNTR_IVB(pipe)) & CURSOR_MODE;
+
+       return state;
+}
+
+static bool cursor_position(struct drm_device *dev, int pipe, int *x, int *y)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pos;
+
+       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
+               pos = I915_READ(CURPOS_IVB(pipe));
+       else
+               pos = I915_READ(CURPOS(pipe));
+
+       *x = (pos >> CURSOR_X_SHIFT) & CURSOR_POS_MASK;
+       if (pos & (CURSOR_POS_SIGN << CURSOR_X_SHIFT))
+               *x = -*x;
+
+       *y = (pos >> CURSOR_Y_SHIFT) & CURSOR_POS_MASK;
+       if (pos & (CURSOR_POS_SIGN << CURSOR_Y_SHIFT))
+               *y = -*y;
+
+       return cursor_active(dev, pipe);
+}
+
+static int i915_display_info(struct seq_file *m, void *unused)
+{
+       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;
+       struct intel_crtc *crtc;
+       struct drm_connector *connector;
+
+       intel_runtime_pm_get(dev_priv);
+       drm_modeset_lock_all(dev);
+       seq_printf(m, "CRTC info\n");
+       seq_printf(m, "---------\n");
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+               bool active;
+               int x, y;
+
+               seq_printf(m, "CRTC %d: pipe: %c, active: %s\n",
+                          crtc->base.base.id, pipe_name(crtc->pipe),
+                          yesno(crtc->active));
+               if (crtc->active) {
+                       intel_crtc_info(m, crtc);
+
+                       active = cursor_position(dev, crtc->pipe, &x, &y);
+                       seq_printf(m, "\tcursor visible? %s, position (%d, %d), addr 0x%08x, active? %s\n",
+                                  yesno(crtc->cursor_visible),
+                                  x, y, crtc->cursor_addr,
+                                  yesno(active));
+               }
+       }
+
+       seq_printf(m, "\n");
+       seq_printf(m, "Connector info\n");
+       seq_printf(m, "--------------\n");
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               intel_connector_info(m, connector);
+       }
+       drm_modeset_unlock_all(dev);
+       intel_runtime_pm_put(dev_priv);
+
+       return 0;
+}
+
 struct pipe_crc_info {
        const char *name;
        struct drm_device *dev;
@@ -2332,8 +2681,6 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
        if (need_stable_symbols) {
                uint32_t tmp = I915_READ(PORT_DFT2_G4X);
 
-               WARN_ON(!IS_G4X(dev));
-
                tmp |= DC_BALANCE_RESET_VLV;
                if (pipe == PIPE_A)
                        tmp |= PIPE_A_SCRAMBLE_RESET;
@@ -2756,11 +3103,179 @@ static const struct file_operations i915_display_crc_ctl_fops = {
        .write = display_crc_ctl_write
 };
 
+static void wm_latency_show(struct seq_file *m, const uint16_t wm[5])
+{
+       struct drm_device *dev = m->private;
+       int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4;
+       int level;
+
+       drm_modeset_lock_all(dev);
+
+       for (level = 0; level < num_levels; level++) {
+               unsigned int latency = wm[level];
+
+               /* WM1+ latency values in 0.5us units */
+               if (level > 0)
+                       latency *= 5;
+
+               seq_printf(m, "WM%d %u (%u.%u usec)\n",
+                          level, wm[level],
+                          latency / 10, latency % 10);
+       }
+
+       drm_modeset_unlock_all(dev);
+}
+
+static int pri_wm_latency_show(struct seq_file *m, void *data)
+{
+       struct drm_device *dev = m->private;
+
+       wm_latency_show(m, to_i915(dev)->wm.pri_latency);
+
+       return 0;
+}
+
+static int spr_wm_latency_show(struct seq_file *m, void *data)
+{
+       struct drm_device *dev = m->private;
+
+       wm_latency_show(m, to_i915(dev)->wm.spr_latency);
+
+       return 0;
+}
+
+static int cur_wm_latency_show(struct seq_file *m, void *data)
+{
+       struct drm_device *dev = m->private;
+
+       wm_latency_show(m, to_i915(dev)->wm.cur_latency);
+
+       return 0;
+}
+
+static int pri_wm_latency_open(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+
+       if (!HAS_PCH_SPLIT(dev))
+               return -ENODEV;
+
+       return single_open(file, pri_wm_latency_show, dev);
+}
+
+static int spr_wm_latency_open(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+
+       if (!HAS_PCH_SPLIT(dev))
+               return -ENODEV;
+
+       return single_open(file, spr_wm_latency_show, dev);
+}
+
+static int cur_wm_latency_open(struct inode *inode, struct file *file)
+{
+       struct drm_device *dev = inode->i_private;
+
+       if (!HAS_PCH_SPLIT(dev))
+               return -ENODEV;
+
+       return single_open(file, cur_wm_latency_show, dev);
+}
+
+static ssize_t wm_latency_write(struct file *file, const char __user *ubuf,
+                               size_t len, loff_t *offp, uint16_t wm[5])
+{
+       struct seq_file *m = file->private_data;
+       struct drm_device *dev = m->private;
+       uint16_t new[5] = { 0 };
+       int num_levels = IS_HASWELL(dev) || IS_BROADWELL(dev) ? 5 : 4;
+       int level;
+       int ret;
+       char tmp[32];
+
+       if (len >= sizeof(tmp))
+               return -EINVAL;
+
+       if (copy_from_user(tmp, ubuf, len))
+               return -EFAULT;
+
+       tmp[len] = '\0';
+
+       ret = sscanf(tmp, "%hu %hu %hu %hu %hu", &new[0], &new[1], &new[2], &new[3], &new[4]);
+       if (ret != num_levels)
+               return -EINVAL;
+
+       drm_modeset_lock_all(dev);
+
+       for (level = 0; level < num_levels; level++)
+               wm[level] = new[level];
+
+       drm_modeset_unlock_all(dev);
+
+       return len;
+}
+
+
+static ssize_t pri_wm_latency_write(struct file *file, const char __user *ubuf,
+                                   size_t len, loff_t *offp)
+{
+       struct seq_file *m = file->private_data;
+       struct drm_device *dev = m->private;
+
+       return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.pri_latency);
+}
+
+static ssize_t spr_wm_latency_write(struct file *file, const char __user *ubuf,
+                                   size_t len, loff_t *offp)
+{
+       struct seq_file *m = file->private_data;
+       struct drm_device *dev = m->private;
+
+       return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.spr_latency);
+}
+
+static ssize_t cur_wm_latency_write(struct file *file, const char __user *ubuf,
+                                   size_t len, loff_t *offp)
+{
+       struct seq_file *m = file->private_data;
+       struct drm_device *dev = m->private;
+
+       return wm_latency_write(file, ubuf, len, offp, to_i915(dev)->wm.cur_latency);
+}
+
+static const struct file_operations i915_pri_wm_latency_fops = {
+       .owner = THIS_MODULE,
+       .open = pri_wm_latency_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .write = pri_wm_latency_write
+};
+
+static const struct file_operations i915_spr_wm_latency_fops = {
+       .owner = THIS_MODULE,
+       .open = spr_wm_latency_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .write = spr_wm_latency_write
+};
+
+static const struct file_operations i915_cur_wm_latency_fops = {
+       .owner = THIS_MODULE,
+       .open = cur_wm_latency_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+       .write = cur_wm_latency_write
+};
+
 static int
 i915_wedged_get(void *data, u64 *val)
 {
        struct drm_device *dev = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        *val = atomic_read(&dev_priv->gpu_error.reset_counter);
 
@@ -2772,9 +3287,8 @@ i915_wedged_set(void *data, u64 val)
 {
        struct drm_device *dev = data;
 
-       DRM_INFO("Manually setting wedged to %llu\n", val);
-       i915_handle_error(dev, val);
-
+       i915_handle_error(dev, val,
+                         "Manually setting wedged to %llu", val);
        return 0;
 }
 
@@ -2786,7 +3300,7 @@ static int
 i915_ring_stop_get(void *data, u64 *val)
 {
        struct drm_device *dev = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        *val = dev_priv->gpu_error.stop_rings;
 
@@ -2929,7 +3443,7 @@ i915_drop_caches_set(void *data, u64 val)
                list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
                        list_for_each_entry_safe(vma, x, &vm->inactive_list,
                                                 mm_list) {
-                               if (vma->obj->pin_count)
+                               if (vma->pin_count)
                                        continue;
 
                                ret = i915_vma_unbind(vma);
@@ -2963,7 +3477,7 @@ static int
 i915_max_freq_get(void *data, u64 *val)
 {
        struct drm_device *dev = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
@@ -2976,9 +3490,9 @@ i915_max_freq_get(void *data, u64 *val)
                return ret;
 
        if (IS_VALLEYVIEW(dev))
-               *val = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay);
+               *val = vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
        else
-               *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
+               *val = dev_priv->rps.max_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
@@ -2989,6 +3503,7 @@ i915_max_freq_set(void *data, u64 val)
 {
        struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 rp_state_cap, hw_max, hw_min;
        int ret;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
@@ -3007,14 +3522,29 @@ i915_max_freq_set(void *data, u64 val)
         */
        if (IS_VALLEYVIEW(dev)) {
                val = vlv_freq_opcode(dev_priv, val);
-               dev_priv->rps.max_delay = val;
-               valleyview_set_rps(dev, val);
+
+               hw_max = valleyview_rps_max_freq(dev_priv);
+               hw_min = valleyview_rps_min_freq(dev_priv);
        } else {
                do_div(val, GT_FREQUENCY_MULTIPLIER);
-               dev_priv->rps.max_delay = val;
-               gen6_set_rps(dev, val);
+
+               rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+               hw_max = dev_priv->rps.max_freq;
+               hw_min = (rp_state_cap >> 16) & 0xff;
+       }
+
+       if (val < hw_min || val > hw_max || val < dev_priv->rps.min_freq_softlimit) {
+               mutex_unlock(&dev_priv->rps.hw_lock);
+               return -EINVAL;
        }
 
+       dev_priv->rps.max_freq_softlimit = val;
+
+       if (IS_VALLEYVIEW(dev))
+               valleyview_set_rps(dev, val);
+       else
+               gen6_set_rps(dev, val);
+
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
@@ -3028,7 +3558,7 @@ static int
 i915_min_freq_get(void *data, u64 *val)
 {
        struct drm_device *dev = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
@@ -3041,9 +3571,9 @@ i915_min_freq_get(void *data, u64 *val)
                return ret;
 
        if (IS_VALLEYVIEW(dev))
-               *val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay);
+               *val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
        else
-               *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
+               *val = dev_priv->rps.min_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
@@ -3054,6 +3584,7 @@ i915_min_freq_set(void *data, u64 val)
 {
        struct drm_device *dev = data;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 rp_state_cap, hw_max, hw_min;
        int ret;
 
        if (!(IS_GEN6(dev) || IS_GEN7(dev)))
@@ -3072,13 +3603,29 @@ i915_min_freq_set(void *data, u64 val)
         */
        if (IS_VALLEYVIEW(dev)) {
                val = vlv_freq_opcode(dev_priv, val);
-               dev_priv->rps.min_delay = val;
-               valleyview_set_rps(dev, val);
+
+               hw_max = valleyview_rps_max_freq(dev_priv);
+               hw_min = valleyview_rps_min_freq(dev_priv);
        } else {
                do_div(val, GT_FREQUENCY_MULTIPLIER);
-               dev_priv->rps.min_delay = val;
-               gen6_set_rps(dev, val);
+
+               rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+               hw_max = dev_priv->rps.max_freq;
+               hw_min = (rp_state_cap >> 16) & 0xff;
+       }
+
+       if (val < hw_min || val > hw_max || val > dev_priv->rps.max_freq_softlimit) {
+               mutex_unlock(&dev_priv->rps.hw_lock);
+               return -EINVAL;
        }
+
+       dev_priv->rps.min_freq_softlimit = val;
+
+       if (IS_VALLEYVIEW(dev))
+               valleyview_set_rps(dev, val);
+       else
+               gen6_set_rps(dev, val);
+
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
@@ -3092,7 +3639,7 @@ static int
 i915_cache_sharing_get(void *data, u64 *val)
 {
        struct drm_device *dev = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 snpcr;
        int ret;
 
@@ -3152,7 +3699,6 @@ static int i915_forcewake_open(struct inode *inode, struct file *file)
        if (INTEL_INFO(dev)->gen < 6)
                return 0;
 
-       intel_runtime_pm_get(dev_priv);
        gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
        return 0;
@@ -3167,7 +3713,6 @@ static int i915_forcewake_release(struct inode *inode, struct file *file)
                return 0;
 
        gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
-       intel_runtime_pm_put(dev_priv);
 
        return 0;
 }
@@ -3248,9 +3793,11 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_dpio", i915_dpio_info, 0},
        {"i915_llc", i915_llc, 0},
        {"i915_edp_psr_status", i915_edp_psr_status, 0},
+       {"i915_sink_crc_eDP1", i915_sink_crc, 0},
        {"i915_energy_uJ", i915_energy_uJ, 0},
        {"i915_pc8_status", i915_pc8_status, 0},
        {"i915_power_domain_info", i915_power_domain_info, 0},
+       {"i915_display_info", i915_display_info, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
@@ -3269,6 +3816,9 @@ static const struct i915_debugfs_files {
        {"i915_error_state", &i915_error_state_fops},
        {"i915_next_seqno", &i915_next_seqno_fops},
        {"i915_display_crc_ctl", &i915_display_crc_ctl_fops},
+       {"i915_pri_wm_latency", &i915_pri_wm_latency_fops},
+       {"i915_spr_wm_latency", &i915_spr_wm_latency_fops},
+       {"i915_cur_wm_latency", &i915_cur_wm_latency_fops},
 };
 
 void intel_display_crc_init(struct drm_device *dev)
index 15a74f9..96177ee 100644 (file)
@@ -82,7 +82,7 @@ intel_read_legacy_status_page(struct drm_i915_private *dev_priv, int reg)
 
 void i915_update_dri1_breadcrumb(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv;
 
        /*
@@ -103,7 +103,7 @@ void i915_update_dri1_breadcrumb(struct drm_device *dev)
 
 static void i915_write_hws_pga(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 addr;
 
        addr = dev_priv->status_page_dmah->busaddr;
@@ -118,7 +118,7 @@ static void i915_write_hws_pga(struct drm_device *dev)
  */
 static void i915_free_hws(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = LP_RING(dev_priv);
 
        if (dev_priv->status_page_dmah) {
@@ -137,7 +137,7 @@ static void i915_free_hws(struct drm_device *dev)
 
 void i915_kernel_lost_context(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv;
        struct intel_ring_buffer *ring = LP_RING(dev_priv);
 
@@ -164,7 +164,7 @@ void i915_kernel_lost_context(struct drm_device * dev)
 
 static int i915_dma_cleanup(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
        /* Make sure interrupts are disabled here because the uninstall ioctl
@@ -188,7 +188,7 @@ static int i915_dma_cleanup(struct drm_device * dev)
 
 static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        int ret;
 
@@ -233,7 +233,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
 
 static int i915_dma_resume(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = LP_RING(dev_priv);
 
        DRM_DEBUG_DRIVER("%s\n", __func__);
@@ -357,7 +357,7 @@ static int validate_cmd(int cmd)
 
 static int i915_emit_cmds(struct drm_device * dev, int *buffer, int dwords)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int i, ret;
 
        if ((dwords+1) * sizeof(int) >= LP_RING(dev_priv)->size - 8)
@@ -431,7 +431,7 @@ i915_emit_box(struct drm_device *dev,
 
 static void i915_emit_breadcrumb(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
 
        dev_priv->dri1.counter++;
@@ -547,7 +547,7 @@ static int i915_dispatch_batchbuffer(struct drm_device * dev,
 
 static int i915_dispatch_flip(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv =
                dev->primary->master->driver_priv;
        int ret;
@@ -625,10 +625,9 @@ static int i915_flush_ioctl(struct drm_device *dev, void *data,
 static int i915_batchbuffer(struct drm_device *dev, void *data,
                            struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
-       drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
-           master_priv->sarea_priv;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv;
+       drm_i915_sarea_t *sarea_priv;
        drm_i915_batchbuffer_t *batch = data;
        int ret;
        struct drm_clip_rect *cliprects = NULL;
@@ -636,6 +635,9 @@ static int i915_batchbuffer(struct drm_device *dev, void *data,
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return -ENODEV;
 
+       master_priv = dev->primary->master->driver_priv;
+       sarea_priv = (drm_i915_sarea_t *) master_priv->sarea_priv;
+
        if (!dev_priv->dri1.allow_batchbuffer) {
                DRM_ERROR("Batchbuffer ioctl disabled\n");
                return -EINVAL;
@@ -681,10 +683,9 @@ fail_free:
 static int i915_cmdbuffer(struct drm_device *dev, void *data,
                          struct drm_file *file_priv)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
-       drm_i915_sarea_t *sarea_priv = (drm_i915_sarea_t *)
-           master_priv->sarea_priv;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_master_private *master_priv;
+       drm_i915_sarea_t *sarea_priv;
        drm_i915_cmdbuffer_t *cmdbuf = data;
        struct drm_clip_rect *cliprects = NULL;
        void *batch_data;
@@ -696,6 +697,9 @@ static int i915_cmdbuffer(struct drm_device *dev, void *data,
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return -ENODEV;
 
+       master_priv = dev->primary->master->driver_priv;
+       sarea_priv = (drm_i915_sarea_t *) master_priv->sarea_priv;
+
        RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
 
        if (cmdbuf->num_cliprects < 0)
@@ -749,7 +753,7 @@ fail_batch_free:
 
 static int i915_emit_irq(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
 
        i915_kernel_lost_context(dev);
@@ -775,7 +779,7 @@ static int i915_emit_irq(struct drm_device * dev)
 
 static int i915_wait_irq(struct drm_device * dev, int irq_nr)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
        int ret = 0;
        struct intel_ring_buffer *ring = LP_RING(dev_priv);
@@ -812,7 +816,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
 static int i915_irq_emit(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;
        drm_i915_irq_emit_t *emit = data;
        int result;
 
@@ -843,7 +847,7 @@ static int i915_irq_emit(struct drm_device *dev, void *data,
 static int i915_irq_wait(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;
        drm_i915_irq_wait_t *irqwait = data;
 
        if (drm_core_check_feature(dev, DRIVER_MODESET))
@@ -860,7 +864,7 @@ static int i915_irq_wait(struct drm_device *dev, void *data,
 static int i915_vblank_pipe_get(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;
        drm_i915_vblank_pipe_t *pipe = data;
 
        if (drm_core_check_feature(dev, DRIVER_MODESET))
@@ -921,7 +925,7 @@ static int i915_flip_bufs(struct drm_device *dev, void *data,
 static int i915_getparam(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;
        drm_i915_getparam_t *param = data;
        int value;
 
@@ -990,7 +994,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = HAS_WT(dev);
                break;
        case I915_PARAM_HAS_ALIASING_PPGTT:
-               value = dev_priv->mm.aliasing_ppgtt ? 1 : 0;
+               value = dev_priv->mm.aliasing_ppgtt || USES_FULL_PPGTT(dev);
                break;
        case I915_PARAM_HAS_WAIT_TIMEOUT:
                value = 1;
@@ -1029,7 +1033,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
 static int i915_setparam(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;
        drm_i915_setparam_t *param = data;
 
        if (!dev_priv) {
@@ -1064,7 +1068,7 @@ static int i915_setparam(struct drm_device *dev, void *data,
 static int i915_set_status_page(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;
        drm_i915_hws_addr_t *hws = data;
        struct intel_ring_buffer *ring;
 
@@ -1132,7 +1136,7 @@ static int i915_get_bridge_dev(struct drm_device *dev)
 static int
 intel_alloc_mchbar_resource(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp_lo, temp_hi = 0;
        u64 mchbar_addr;
@@ -1178,11 +1182,14 @@ intel_alloc_mchbar_resource(struct drm_device *dev)
 static void
 intel_setup_mchbar(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp;
        bool enabled;
 
+       if (IS_VALLEYVIEW(dev))
+               return;
+
        dev_priv->mchbar_need_disable = false;
 
        if (IS_I915G(dev) || IS_I915GM(dev)) {
@@ -1215,7 +1222,7 @@ intel_setup_mchbar(struct drm_device *dev)
 static void
 intel_teardown_mchbar(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int mchbar_reg = INTEL_INFO(dev)->gen >= 4 ? MCHBAR_I965 : MCHBAR_I915;
        u32 temp;
 
@@ -1317,12 +1324,12 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto cleanup_vga_switcheroo;
 
+       intel_power_domains_init_hw(dev_priv);
+
        ret = drm_irq_install(dev);
        if (ret)
                goto cleanup_gem_stolen;
 
-       intel_power_domains_init_hw(dev);
-
        /* Important: The output setup functions called by modeset_init need
         * working irqs for e.g. gmbus and dp aux transfers. */
        intel_modeset_init(dev);
@@ -1339,7 +1346,7 @@ static int i915_load_modeset_init(struct drm_device *dev)
        /* FIXME: do pre/post-mode set stuff in core KMS code */
        dev->vblank_disable_allowed = true;
        if (INTEL_INFO(dev)->num_pipes == 0) {
-               intel_display_power_put(dev, POWER_DOMAIN_VGA);
+               intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
                return 0;
        }
 
@@ -1374,10 +1381,10 @@ cleanup_gem:
        i915_gem_cleanup_ringbuffer(dev);
        i915_gem_context_fini(dev);
        mutex_unlock(&dev->struct_mutex);
-       i915_gem_cleanup_aliasing_ppgtt(dev);
+       WARN_ON(dev_priv->mm.aliasing_ppgtt);
        drm_mm_takedown(&dev_priv->gtt.base.mm);
 cleanup_power:
-       intel_display_power_put(dev, POWER_DOMAIN_VGA);
+       intel_display_power_put(dev_priv, POWER_DOMAIN_VGA);
        drm_irq_uninstall(dev);
 cleanup_gem_stolen:
        i915_gem_cleanup_stolen(dev);
@@ -1442,7 +1449,7 @@ static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
 
 static void i915_dump_device_info(struct drm_i915_private *dev_priv)
 {
-       const struct intel_device_info *info = dev_priv->info;
+       const struct intel_device_info *info = &dev_priv->info;
 
 #define PRINT_S(name) "%s"
 #define SEP_EMPTY
@@ -1459,6 +1466,62 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv)
 #undef SEP_COMMA
 }
 
+/*
+ * Determine various intel_device_info fields at runtime.
+ *
+ * Use it when either:
+ *   - it's judged too laborious to fill n static structures with the limit
+ *     when a simple if statement does the job,
+ *   - run-time checks (eg read fuse/strap registers) are needed.
+ *
+ * This function needs to be called:
+ *   - after the MMIO has been setup as we are reading registers,
+ *   - after the PCH has been detected,
+ *   - before the first usage of the fields it can tweak.
+ */
+static void intel_device_info_runtime_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_device_info *info;
+       enum pipe pipe;
+
+       info = (struct intel_device_info *)&dev_priv->info;
+
+       if (IS_VALLEYVIEW(dev))
+               for_each_pipe(pipe)
+                       info->num_sprites[pipe] = 2;
+       else
+               for_each_pipe(pipe)
+                       info->num_sprites[pipe] = 1;
+
+       if (i915.disable_display) {
+               DRM_INFO("Display disabled (module parameter)\n");
+               info->num_pipes = 0;
+       } else if (info->num_pipes > 0 &&
+                  (INTEL_INFO(dev)->gen == 7 || INTEL_INFO(dev)->gen == 8) &&
+                  !IS_VALLEYVIEW(dev)) {
+               u32 fuse_strap = I915_READ(FUSE_STRAP);
+               u32 sfuse_strap = I915_READ(SFUSE_STRAP);
+
+               /*
+                * SFUSE_STRAP is supposed to have a bit signalling the display
+                * is fused off. Unfortunately it seems that, at least in
+                * certain cases, fused off display means that PCH display
+                * reads don't land anywhere. In that case, we read 0s.
+                *
+                * On CPT/PPT, we can detect this case as SFUSE_STRAP_FUSE_LOCK
+                * should be set when taking over after the firmware.
+                */
+               if (fuse_strap & ILK_INTERNAL_DISPLAY_DISABLE ||
+                   sfuse_strap & SFUSE_STRAP_DISPLAY_DISABLED ||
+                   (dev_priv->pch_type == PCH_CPT &&
+                    !(sfuse_strap & SFUSE_STRAP_FUSE_LOCK))) {
+                       DRM_INFO("Display fused off, disabling\n");
+                       info->num_pipes = 0;
+               }
+       }
+}
+
 /**
  * i915_driver_load - setup chip and create an initial config
  * @dev: DRM device
@@ -1473,7 +1536,7 @@ static void i915_dump_device_info(struct drm_i915_private *dev_priv)
 int i915_driver_load(struct drm_device *dev, unsigned long flags)
 {
        struct drm_i915_private *dev_priv;
-       struct intel_device_info *info;
+       struct intel_device_info *info, *device_info;
        int ret = 0, mmio_bar, mmio_size;
        uint32_t aperture_size;
 
@@ -1496,7 +1559,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        dev->dev_private = (void *)dev_priv;
        dev_priv->dev = dev;
-       dev_priv->info = info;
+
+       /* copy initial configuration to dev_priv->info */
+       device_info = (struct intel_device_info *)&dev_priv->info;
+       *device_info = *info;
 
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->gpu_error.lock);
@@ -1545,8 +1611,6 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                goto put_bridge;
        }
 
-       intel_uncore_early_sanitize(dev);
-
        /* This must be called before any calls to HAS_PCH_* */
        intel_detect_pch(dev);
 
@@ -1635,9 +1699,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (!IS_I945G(dev) && !IS_I945GM(dev))
                pci_enable_msi(dev->pdev);
 
-       dev_priv->num_plane = 1;
-       if (IS_VALLEYVIEW(dev))
-               dev_priv->num_plane = 2;
+       intel_device_info_runtime_init(dev);
 
        if (INTEL_INFO(dev)->num_pipes) {
                ret = drm_vblank_init(dev, INTEL_INFO(dev)->num_pipes);
@@ -1645,7 +1707,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                        goto out_gem_unload;
        }
 
-       intel_power_domains_init(dev);
+       intel_power_domains_init(dev_priv);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                ret = i915_load_modeset_init(dev);
@@ -1674,7 +1736,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        return 0;
 
 out_power_well:
-       intel_power_domains_remove(dev);
+       intel_power_domains_remove(dev_priv);
        drm_vblank_cleanup(dev);
 out_gem_unload:
        if (dev_priv->mm.inactive_shrinker.scan_objects)
@@ -1724,8 +1786,8 @@ int i915_driver_unload(struct drm_device *dev)
        /* The i915.ko module is still not prepared to be loaded when
         * the power well is not enabled, so just enable it in case
         * we're going to unload/reload. */
-       intel_display_set_init_power(dev, true);
-       intel_power_domains_remove(dev);
+       intel_display_set_init_power(dev_priv, true);
+       intel_power_domains_remove(dev_priv);
 
        i915_teardown_sysfs(dev);
 
@@ -1761,8 +1823,6 @@ int i915_driver_unload(struct drm_device *dev)
        cancel_work_sync(&dev_priv->gpu_error.work);
        i915_destroy_error_state(dev);
 
-       cancel_delayed_work_sync(&dev_priv->pc8.enable_work);
-
        if (dev->pdev->msi_enabled)
                pci_disable_msi(dev->pdev);
 
@@ -1776,8 +1836,8 @@ int i915_driver_unload(struct drm_device *dev)
                i915_gem_free_all_phys_object(dev);
                i915_gem_cleanup_ringbuffer(dev);
                i915_gem_context_fini(dev);
+               WARN_ON(dev_priv->mm.aliasing_ppgtt);
                mutex_unlock(&dev->struct_mutex);
-               i915_gem_cleanup_aliasing_ppgtt(dev);
                i915_gem_cleanup_stolen(dev);
 
                if (!I915_NEED_GFX_HWS(dev))
@@ -1835,7 +1895,7 @@ int i915_driver_open(struct drm_device *dev, struct drm_file *file)
  */
 void i915_driver_lastclose(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        /* On gen6+ we refuse to init without kms enabled, but then the drm core
         * goes right around and calls lastclose. Check for this and don't clean
index ec7bb0f..82f4d1f 100644 (file)
 #include <linux/module.h>
 #include <drm/drm_crtc_helper.h>
 
-static int i915_modeset __read_mostly = -1;
-module_param_named(modeset, i915_modeset, int, 0400);
-MODULE_PARM_DESC(modeset,
-               "Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, "
-               "1=on, -1=force vga console preference [default])");
-
-unsigned int i915_fbpercrtc __always_unused = 0;
-module_param_named(fbpercrtc, i915_fbpercrtc, int, 0400);
-
-int i915_panel_ignore_lid __read_mostly = 1;
-module_param_named(panel_ignore_lid, i915_panel_ignore_lid, int, 0600);
-MODULE_PARM_DESC(panel_ignore_lid,
-               "Override lid status (0=autodetect, 1=autodetect disabled [default], "
-               "-1=force lid closed, -2=force lid open)");
-
-unsigned int i915_powersave __read_mostly = 1;
-module_param_named(powersave, i915_powersave, int, 0600);
-MODULE_PARM_DESC(powersave,
-               "Enable powersavings, fbc, downclocking, etc. (default: true)");
-
-int i915_semaphores __read_mostly = -1;
-module_param_named(semaphores, i915_semaphores, int, 0400);
-MODULE_PARM_DESC(semaphores,
-               "Use semaphores for inter-ring sync (default: -1 (use per-chip defaults))");
-
-int i915_enable_rc6 __read_mostly = -1;
-module_param_named(i915_enable_rc6, i915_enable_rc6, int, 0400);
-MODULE_PARM_DESC(i915_enable_rc6,
-               "Enable power-saving render C-state 6. "
-               "Different stages can be selected via bitmask values "
-               "(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). "
-               "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
-               "default: -1 (use per-chip default)");
-
-int i915_enable_fbc __read_mostly = -1;
-module_param_named(i915_enable_fbc, i915_enable_fbc, int, 0600);
-MODULE_PARM_DESC(i915_enable_fbc,
-               "Enable frame buffer compression for power savings "
-               "(default: -1 (use per-chip default))");
-
-unsigned int i915_lvds_downclock __read_mostly = 0;
-module_param_named(lvds_downclock, i915_lvds_downclock, int, 0400);
-MODULE_PARM_DESC(lvds_downclock,
-               "Use panel (LVDS/eDP) downclocking for power savings "
-               "(default: false)");
-
-int i915_lvds_channel_mode __read_mostly;
-module_param_named(lvds_channel_mode, i915_lvds_channel_mode, int, 0600);
-MODULE_PARM_DESC(lvds_channel_mode,
-                "Specify LVDS channel mode "
-                "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)");
-
-int i915_panel_use_ssc __read_mostly = -1;
-module_param_named(lvds_use_ssc, i915_panel_use_ssc, int, 0600);
-MODULE_PARM_DESC(lvds_use_ssc,
-               "Use Spread Spectrum Clock with panels [LVDS/eDP] "
-               "(default: auto from VBT)");
-
-int i915_vbt_sdvo_panel_type __read_mostly = -1;
-module_param_named(vbt_sdvo_panel_type, i915_vbt_sdvo_panel_type, int, 0600);
-MODULE_PARM_DESC(vbt_sdvo_panel_type,
-               "Override/Ignore selection of SDVO panel mode in the VBT "
-               "(-2=ignore, -1=auto [default], index in VBT BIOS table)");
-
-static bool i915_try_reset __read_mostly = true;
-module_param_named(reset, i915_try_reset, bool, 0600);
-MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)");
-
-bool i915_enable_hangcheck __read_mostly = true;
-module_param_named(enable_hangcheck, i915_enable_hangcheck, bool, 0644);
-MODULE_PARM_DESC(enable_hangcheck,
-               "Periodically check GPU activity for detecting hangs. "
-               "WARNING: Disabling this can cause system wide hangs. "
-               "(default: true)");
-
-int i915_enable_ppgtt __read_mostly = -1;
-module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0400);
-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 = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT);
-module_param_named(preliminary_hw_support, i915_preliminary_hw_support, int, 0600);
-MODULE_PARM_DESC(preliminary_hw_support,
-               "Enable preliminary hardware support.");
-
-int i915_disable_power_well __read_mostly = 1;
-module_param_named(disable_power_well, i915_disable_power_well, int, 0600);
-MODULE_PARM_DESC(disable_power_well,
-                "Disable the power well when possible (default: true)");
-
-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)");
-
-int i915_enable_pc8 __read_mostly = 1;
-module_param_named(enable_pc8, i915_enable_pc8, int, 0600);
-MODULE_PARM_DESC(enable_pc8, "Enable support for low power package C states (PC8+) (default: true)");
-
-int i915_pc8_timeout __read_mostly = 5000;
-module_param_named(pc8_timeout, i915_pc8_timeout, int, 0600);
-MODULE_PARM_DESC(pc8_timeout, "Number of msecs of idleness required to enter PC8+ (default: 5000)");
-
-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;
 
+#define GEN_DEFAULT_PIPEOFFSETS \
+       .pipe_offsets = { PIPE_A_OFFSET, PIPE_B_OFFSET, \
+                         PIPE_C_OFFSET, PIPE_EDP_OFFSET }, \
+       .trans_offsets = { TRANSCODER_A_OFFSET, TRANSCODER_B_OFFSET, \
+                          TRANSCODER_C_OFFSET, TRANSCODER_EDP_OFFSET }, \
+       .dpll_offsets = { DPLL_A_OFFSET, DPLL_B_OFFSET }, \
+       .dpll_md_offsets = { DPLL_A_MD_OFFSET, DPLL_B_MD_OFFSET }, \
+       .palette_offsets = { PALETTE_A_OFFSET, PALETTE_B_OFFSET }
+
+
 static const struct intel_device_info intel_i830_info = {
        .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_845g_info = {
        .gen = 2, .num_pipes = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_i85x_info = {
@@ -174,18 +70,21 @@ static const struct intel_device_info intel_i85x_info = {
        .has_overlay = 1, .overlay_needs_physical = 1,
        .has_fbc = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_i865g_info = {
        .gen = 2, .num_pipes = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_i915g_info = {
        .gen = 3, .is_i915g = 1, .cursor_needs_physical = 1, .num_pipes = 2,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 static const struct intel_device_info intel_i915gm_info = {
        .gen = 3, .is_mobile = 1, .num_pipes = 2,
@@ -194,11 +93,13 @@ static const struct intel_device_info intel_i915gm_info = {
        .supports_tv = 1,
        .has_fbc = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 static const struct intel_device_info intel_i945g_info = {
        .gen = 3, .has_hotplug = 1, .cursor_needs_physical = 1, .num_pipes = 2,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 static const struct intel_device_info intel_i945gm_info = {
        .gen = 3, .is_i945gm = 1, .is_mobile = 1, .num_pipes = 2,
@@ -207,6 +108,7 @@ static const struct intel_device_info intel_i945gm_info = {
        .supports_tv = 1,
        .has_fbc = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_i965g_info = {
@@ -214,6 +116,7 @@ static const struct intel_device_info intel_i965g_info = {
        .has_hotplug = 1,
        .has_overlay = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_i965gm_info = {
@@ -222,6 +125,7 @@ static const struct intel_device_info intel_i965gm_info = {
        .has_overlay = 1,
        .supports_tv = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_g33_info = {
@@ -229,12 +133,14 @@ static const struct intel_device_info intel_g33_info = {
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_overlay = 1,
        .ring_mask = RENDER_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_g45_info = {
        .gen = 4, .is_g4x = 1, .need_gfx_hws = 1, .num_pipes = 2,
        .has_pipe_cxsr = 1, .has_hotplug = 1,
        .ring_mask = RENDER_RING | BSD_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_gm45_info = {
@@ -243,18 +149,21 @@ static const struct intel_device_info intel_gm45_info = {
        .has_pipe_cxsr = 1, .has_hotplug = 1,
        .supports_tv = 1,
        .ring_mask = RENDER_RING | BSD_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_pineview_info = {
        .gen = 3, .is_g33 = 1, .is_pineview = 1, .is_mobile = 1, .num_pipes = 2,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_overlay = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_ironlake_d_info = {
        .gen = 5, .num_pipes = 2,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .ring_mask = RENDER_RING | BSD_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_ironlake_m_info = {
@@ -262,6 +171,7 @@ static const struct intel_device_info intel_ironlake_m_info = {
        .need_gfx_hws = 1, .has_hotplug = 1,
        .has_fbc = 1,
        .ring_mask = RENDER_RING | BSD_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_sandybridge_d_info = {
@@ -270,6 +180,7 @@ static const struct intel_device_info intel_sandybridge_d_info = {
        .has_fbc = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING,
        .has_llc = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_sandybridge_m_info = {
@@ -278,6 +189,7 @@ static const struct intel_device_info intel_sandybridge_m_info = {
        .has_fbc = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING,
        .has_llc = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 #define GEN7_FEATURES  \
@@ -290,18 +202,21 @@ static const struct intel_device_info intel_sandybridge_m_info = {
 static const struct intel_device_info intel_ivybridge_d_info = {
        GEN7_FEATURES,
        .is_ivybridge = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_ivybridge_m_info = {
        GEN7_FEATURES,
        .is_ivybridge = 1,
        .is_mobile = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_ivybridge_q_info = {
        GEN7_FEATURES,
        .is_ivybridge = 1,
        .num_pipes = 0, /* legal, last one wins */
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_valleyview_m_info = {
@@ -312,6 +227,7 @@ static const struct intel_device_info intel_valleyview_m_info = {
        .display_mmio_offset = VLV_DISPLAY_BASE,
        .has_fbc = 0, /* legal, last one wins */
        .has_llc = 0, /* legal, last one wins */
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_valleyview_d_info = {
@@ -321,6 +237,7 @@ static const struct intel_device_info intel_valleyview_d_info = {
        .display_mmio_offset = VLV_DISPLAY_BASE,
        .has_fbc = 0, /* legal, last one wins */
        .has_llc = 0, /* legal, last one wins */
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_haswell_d_info = {
@@ -329,6 +246,7 @@ static const struct intel_device_info intel_haswell_d_info = {
        .has_ddi = 1,
        .has_fpga_dbg = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_haswell_m_info = {
@@ -338,6 +256,7 @@ static const struct intel_device_info intel_haswell_m_info = {
        .has_ddi = 1,
        .has_fpga_dbg = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_broadwell_d_info = {
@@ -346,6 +265,8 @@ static const struct intel_device_info intel_broadwell_d_info = {
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
        .has_llc = 1,
        .has_ddi = 1,
+       .has_fbc = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 static const struct intel_device_info intel_broadwell_m_info = {
@@ -354,6 +275,8 @@ static const struct intel_device_info intel_broadwell_m_info = {
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
        .has_llc = 1,
        .has_ddi = 1,
+       .has_fbc = 1,
+       GEN_DEFAULT_PIPEOFFSETS,
 };
 
 /*
@@ -475,14 +398,12 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen < 6)
                return false;
 
+       if (i915.semaphores >= 0)
+               return i915.semaphores;
+
        /* Until we get further testing... */
-       if (IS_GEN8(dev)) {
-               WARN_ON(!i915_preliminary_hw_support);
+       if (IS_GEN8(dev))
                return false;
-       }
-
-       if (i915_semaphores >= 0)
-               return i915_semaphores;
 
 #ifdef CONFIG_INTEL_IOMMU
        /* Enable semaphores on SNB when IO remapping is off */
@@ -507,8 +428,7 @@ static int i915_drm_freeze(struct drm_device *dev)
 
        /* We do a lot of poking in a lot of registers, make sure they work
         * properly. */
-       hsw_disable_package_c8(dev_priv);
-       intel_display_set_init_power(dev, true);
+       intel_display_set_init_power(dev_priv, true);
 
        drm_kms_helper_poll_disable(dev);
 
@@ -546,11 +466,14 @@ static int i915_drm_freeze(struct drm_device *dev)
        i915_save_state(dev);
 
        intel_opregion_fini(dev);
+       intel_uncore_fini(dev);
 
        console_lock();
        intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED);
        console_unlock();
 
+       dev_priv->suspend_count++;
+
        return 0;
 }
 
@@ -614,14 +537,21 @@ static void intel_resume_hotplug(struct drm_device *dev)
        drm_helper_hpd_irq_event(dev);
 }
 
-static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
+static int i915_drm_thaw_early(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int error = 0;
 
        intel_uncore_early_sanitize(dev);
-
        intel_uncore_sanitize(dev);
+       intel_power_domains_init_hw(dev_priv);
+
+       return 0;
+}
+
+static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int error = 0;
 
        if (drm_core_check_feature(dev, DRIVER_MODESET) &&
            restore_gtt_mappings) {
@@ -630,14 +560,13 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
                mutex_unlock(&dev->struct_mutex);
        }
 
-       intel_power_domains_init_hw(dev);
-
        i915_restore_state(dev);
        intel_opregion_setup(dev);
 
        /* KMS EnterVT equivalent */
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                intel_init_pch_refclk(dev);
+               drm_mode_config_reset(dev);
 
                mutex_lock(&dev->struct_mutex);
 
@@ -650,7 +579,6 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
                intel_modeset_init_hw(dev);
 
                drm_modeset_lock_all(dev);
-               drm_mode_config_reset(dev);
                intel_modeset_setup_hw_state(dev, true);
                drm_modeset_unlock_all(dev);
 
@@ -680,10 +608,6 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
                schedule_work(&dev_priv->console_resume_work);
        }
 
-       /* Undo what we did at i915_drm_freeze so the refcount goes back to the
-        * expected level. */
-       hsw_enable_package_c8(dev_priv);
-
        mutex_lock(&dev_priv->modeset_restore_lock);
        dev_priv->modeset_restore = MODESET_DONE;
        mutex_unlock(&dev_priv->modeset_restore_lock);
@@ -700,19 +624,33 @@ static int i915_drm_thaw(struct drm_device *dev)
        return __i915_drm_thaw(dev, true);
 }
 
-int i915_resume(struct drm_device *dev)
+static int i915_resume_early(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret;
-
        if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
+       /*
+        * We have a resume ordering issue with the snd-hda driver also
+        * requiring our device to be power up. Due to the lack of a
+        * parent/child relationship we currently solve this with an early
+        * resume hook.
+        *
+        * FIXME: This should be solved with a special hdmi sink device or
+        * similar so that power domains can be employed.
+        */
        if (pci_enable_device(dev->pdev))
                return -EIO;
 
        pci_set_master(dev->pdev);
 
+       return i915_drm_thaw_early(dev);
+}
+
+int i915_resume(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
        /*
         * Platforms with opregion should have sane BIOS, older ones (gen3 and
         * earlier) need to restore the GTT mappings since the BIOS might clear
@@ -726,6 +664,14 @@ int i915_resume(struct drm_device *dev)
        return 0;
 }
 
+static int i915_resume_legacy(struct drm_device *dev)
+{
+       i915_resume_early(dev);
+       i915_resume(dev);
+
+       return 0;
+}
+
 /**
  * i915_reset - reset chip after a hang
  * @dev: drm device to reset
@@ -743,11 +689,11 @@ int i915_resume(struct drm_device *dev)
  */
 int i915_reset(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        bool simulated;
        int ret;
 
-       if (!i915_try_reset)
+       if (!i915.reset)
                return 0;
 
        mutex_lock(&dev->struct_mutex);
@@ -802,6 +748,17 @@ int i915_reset(struct drm_device *dev)
 
                drm_irq_uninstall(dev);
                drm_irq_install(dev);
+
+               /* rps/rc6 re-init is necessary to restore state lost after the
+                * reset and the re-install of drm irq. Skip for ironlake per
+                * previous concerns that it doesn't respond well to some forms
+                * of re-init after reset. */
+               if (INTEL_INFO(dev)->gen > 5) {
+                       mutex_lock(&dev->struct_mutex);
+                       intel_enable_gt_powersave(dev);
+                       mutex_unlock(&dev->struct_mutex);
+               }
+
                intel_hpd_init(dev);
        } else {
                mutex_unlock(&dev->struct_mutex);
@@ -815,7 +772,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        struct intel_device_info *intel_info =
                (struct intel_device_info *) ent->driver_data;
 
-       if (IS_PRELIMINARY_HW(intel_info) && !i915_preliminary_hw_support) {
+       if (IS_PRELIMINARY_HW(intel_info) && !i915.preliminary_hw_support) {
                DRM_INFO("This hardware requires preliminary hardware support.\n"
                         "See CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT, and/or modparam preliminary_hw_support\n");
                return -ENODEV;
@@ -846,7 +803,6 @@ static int i915_pm_suspend(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
-       int error;
 
        if (!drm_dev || !drm_dev->dev_private) {
                dev_err(dev, "DRM not initialized, aborting suspend.\n");
@@ -856,9 +812,25 @@ static int i915_pm_suspend(struct device *dev)
        if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       error = i915_drm_freeze(drm_dev);
-       if (error)
-               return error;
+       return i915_drm_freeze(drm_dev);
+}
+
+static int i915_pm_suspend_late(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+       /*
+        * We have a suspedn ordering issue with the snd-hda driver also
+        * requiring our device to be power up. Due to the lack of a
+        * parent/child relationship we currently solve this with an late
+        * suspend hook.
+        *
+        * FIXME: This should be solved with a special hdmi sink device or
+        * similar so that power domains can be employed.
+        */
+       if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+               return 0;
 
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3hot);
@@ -866,6 +838,14 @@ static int i915_pm_suspend(struct device *dev)
        return 0;
 }
 
+static int i915_pm_resume_early(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+       return i915_resume_early(drm_dev);
+}
+
 static int i915_pm_resume(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -887,6 +867,14 @@ static int i915_pm_freeze(struct device *dev)
        return i915_drm_freeze(drm_dev);
 }
 
+static int i915_pm_thaw_early(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct drm_device *drm_dev = pci_get_drvdata(pdev);
+
+       return i915_drm_thaw_early(drm_dev);
+}
+
 static int i915_pm_thaw(struct device *dev)
 {
        struct pci_dev *pdev = to_pci_dev(dev);
@@ -910,9 +898,13 @@ static int i915_runtime_suspend(struct device *device)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        WARN_ON(!HAS_RUNTIME_PM(dev));
+       assert_force_wake_inactive(dev_priv);
 
        DRM_DEBUG_KMS("Suspending device\n");
 
+       if (HAS_PC8(dev))
+               hsw_enable_pc8(dev_priv);
+
        i915_gem_release_all_mmaps(dev_priv);
 
        del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
@@ -927,6 +919,7 @@ static int i915_runtime_suspend(struct device *device)
         */
        intel_opregion_notify_adapter(dev, PCI_D1);
 
+       DRM_DEBUG_KMS("Device suspended\n");
        return 0;
 }
 
@@ -943,15 +936,23 @@ static int i915_runtime_resume(struct device *device)
        intel_opregion_notify_adapter(dev, PCI_D0);
        dev_priv->pm.suspended = false;
 
+       if (HAS_PC8(dev))
+               hsw_disable_pc8(dev_priv);
+
+       DRM_DEBUG_KMS("Device resumed\n");
        return 0;
 }
 
 static const struct dev_pm_ops i915_pm_ops = {
        .suspend = i915_pm_suspend,
+       .suspend_late = i915_pm_suspend_late,
+       .resume_early = i915_pm_resume_early,
        .resume = i915_pm_resume,
        .freeze = i915_pm_freeze,
+       .thaw_early = i915_pm_thaw_early,
        .thaw = i915_pm_thaw,
        .poweroff = i915_pm_poweroff,
+       .restore_early = i915_pm_resume_early,
        .restore = i915_pm_resume,
        .runtime_suspend = i915_runtime_suspend,
        .runtime_resume = i915_runtime_resume,
@@ -994,7 +995,7 @@ static struct drm_driver driver = {
 
        /* Used in place of i915_pm_ops for non-DRIVER_MODESET */
        .suspend = i915_suspend,
-       .resume = i915_resume,
+       .resume = i915_resume_legacy,
 
        .device_is_agp = i915_driver_device_is_agp,
        .master_create = i915_master_create,
@@ -1046,14 +1047,14 @@ static int __init i915_init(void)
         * the default behavior.
         */
 #if defined(CONFIG_DRM_I915_KMS)
-       if (i915_modeset != 0)
+       if (i915.modeset != 0)
                driver.driver_features |= DRIVER_MODESET;
 #endif
-       if (i915_modeset == 1)
+       if (i915.modeset == 1)
                driver.driver_features |= DRIVER_MODESET;
 
 #ifdef CONFIG_VGA_CONSOLE
-       if (vgacon_text_force() && i915_modeset == -1)
+       if (vgacon_text_force() && i915.modeset == -1)
                driver.driver_features &= ~DRIVER_MODESET;
 #endif
 
index df77e20..0905cd9 100644 (file)
@@ -58,7 +58,8 @@ enum pipe {
        PIPE_A = 0,
        PIPE_B,
        PIPE_C,
-       I915_MAX_PIPES
+       _PIPE_EDP,
+       I915_MAX_PIPES = _PIPE_EDP
 };
 #define pipe_name(p) ((p) + 'A')
 
@@ -66,7 +67,8 @@ enum transcoder {
        TRANSCODER_A = 0,
        TRANSCODER_B,
        TRANSCODER_C,
-       TRANSCODER_EDP = 0xF,
+       TRANSCODER_EDP,
+       I915_MAX_TRANSCODERS
 };
 #define transcoder_name(t) ((t) + 'A')
 
@@ -77,7 +79,7 @@ enum plane {
 };
 #define plane_name(p) ((p) + 'A')
 
-#define sprite_name(p, s) ((p) * dev_priv->num_plane + (s) + 'A')
+#define sprite_name(p, s) ((p) * INTEL_INFO(dev)->num_sprites[(p)] + (s) + 'A')
 
 enum port {
        PORT_A = 0,
@@ -112,6 +114,17 @@ enum intel_display_power_domain {
        POWER_DOMAIN_TRANSCODER_B,
        POWER_DOMAIN_TRANSCODER_C,
        POWER_DOMAIN_TRANSCODER_EDP,
+       POWER_DOMAIN_PORT_DDI_A_2_LANES,
+       POWER_DOMAIN_PORT_DDI_A_4_LANES,
+       POWER_DOMAIN_PORT_DDI_B_2_LANES,
+       POWER_DOMAIN_PORT_DDI_B_4_LANES,
+       POWER_DOMAIN_PORT_DDI_C_2_LANES,
+       POWER_DOMAIN_PORT_DDI_C_4_LANES,
+       POWER_DOMAIN_PORT_DDI_D_2_LANES,
+       POWER_DOMAIN_PORT_DDI_D_4_LANES,
+       POWER_DOMAIN_PORT_DSI,
+       POWER_DOMAIN_PORT_CRT,
+       POWER_DOMAIN_PORT_OTHER,
        POWER_DOMAIN_VGA,
        POWER_DOMAIN_AUDIO,
        POWER_DOMAIN_INIT,
@@ -119,8 +132,6 @@ enum intel_display_power_domain {
        POWER_DOMAIN_NUM,
 };
 
-#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1)
-
 #define POWER_DOMAIN_PIPE(pipe) ((pipe) + POWER_DOMAIN_PIPE_A)
 #define POWER_DOMAIN_PIPE_PANEL_FITTER(pipe) \
                ((pipe) + POWER_DOMAIN_PIPE_A_PANEL_FITTER)
@@ -128,14 +139,6 @@ enum intel_display_power_domain {
        ((tran) == TRANSCODER_EDP ? POWER_DOMAIN_TRANSCODER_EDP : \
         (tran) + POWER_DOMAIN_TRANSCODER_A)
 
-#define HSW_ALWAYS_ON_POWER_DOMAINS (          \
-       BIT(POWER_DOMAIN_PIPE_A) |              \
-       BIT(POWER_DOMAIN_TRANSCODER_EDP))
-#define BDW_ALWAYS_ON_POWER_DOMAINS (          \
-       BIT(POWER_DOMAIN_PIPE_A) |              \
-       BIT(POWER_DOMAIN_TRANSCODER_EDP) |      \
-       BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER))
-
 enum hpd_pin {
        HPD_NONE = 0,
        HPD_PORT_A = HPD_NONE, /* PORT_A is internal */
@@ -157,11 +160,16 @@ enum hpd_pin {
         I915_GEM_DOMAIN_VERTEX)
 
 #define for_each_pipe(p) for ((p) = 0; (p) < INTEL_INFO(dev)->num_pipes; (p)++)
+#define for_each_sprite(p, s) for ((s) = 0; (s) < INTEL_INFO(dev)->num_sprites[(p)]; (s)++)
 
 #define for_each_encoder_on_crtc(dev, __crtc, intel_encoder) \
        list_for_each_entry((intel_encoder), &(dev)->mode_config.encoder_list, base.head) \
                if ((intel_encoder)->base.crtc == (__crtc))
 
+#define for_each_connector_on_encoder(dev, __encoder, intel_connector) \
+       list_for_each_entry((intel_connector), &(dev)->mode_config.connector_list, base.head) \
+               if ((intel_connector)->base.encoder == (__encoder))
+
 struct drm_i915_private;
 
 enum intel_dpll_id {
@@ -295,53 +303,87 @@ struct intel_display_error_state;
 
 struct drm_i915_error_state {
        struct kref ref;
+       struct timeval time;
+
+       char error_msg[128];
+       u32 reset_count;
+       u32 suspend_count;
+
+       /* Generic register state */
        u32 eir;
        u32 pgtbl_er;
        u32 ier;
        u32 ccid;
        u32 derrmr;
        u32 forcewake;
-       bool waiting[I915_NUM_RINGS];
-       u32 pipestat[I915_MAX_PIPES];
-       u32 tail[I915_NUM_RINGS];
-       u32 head[I915_NUM_RINGS];
-       u32 ctl[I915_NUM_RINGS];
-       u32 ipeir[I915_NUM_RINGS];
-       u32 ipehr[I915_NUM_RINGS];
-       u32 instdone[I915_NUM_RINGS];
-       u32 acthd[I915_NUM_RINGS];
-       u32 semaphore_mboxes[I915_NUM_RINGS][I915_NUM_RINGS - 1];
-       u32 semaphore_seqno[I915_NUM_RINGS][I915_NUM_RINGS - 1];
-       u32 rc_psmi[I915_NUM_RINGS]; /* sleep state */
-       /* our own tracking of ring head and tail */
-       u32 cpu_ring_head[I915_NUM_RINGS];
-       u32 cpu_ring_tail[I915_NUM_RINGS];
        u32 error; /* gen6+ */
        u32 err_int; /* gen7 */
-       u32 bbstate[I915_NUM_RINGS];
-       u32 instpm[I915_NUM_RINGS];
-       u32 instps[I915_NUM_RINGS];
-       u32 extra_instdone[I915_NUM_INSTDONE_REG];
-       u32 seqno[I915_NUM_RINGS];
-       u64 bbaddr[I915_NUM_RINGS];
-       u32 fault_reg[I915_NUM_RINGS];
        u32 done_reg;
-       u32 faddr[I915_NUM_RINGS];
+       u32 gac_eco;
+       u32 gam_ecochk;
+       u32 gab_ctl;
+       u32 gfx_mode;
+       u32 extra_instdone[I915_NUM_INSTDONE_REG];
+       u32 pipestat[I915_MAX_PIPES];
        u64 fence[I915_MAX_NUM_FENCES];
-       struct timeval time;
+       struct intel_overlay_error_state *overlay;
+       struct intel_display_error_state *display;
+
        struct drm_i915_error_ring {
                bool valid;
+               /* Software tracked state */
+               bool waiting;
+               int hangcheck_score;
+               enum intel_ring_hangcheck_action hangcheck_action;
+               int num_requests;
+
+               /* our own tracking of ring head and tail */
+               u32 cpu_ring_head;
+               u32 cpu_ring_tail;
+
+               u32 semaphore_seqno[I915_NUM_RINGS - 1];
+
+               /* Register state */
+               u32 tail;
+               u32 head;
+               u32 ctl;
+               u32 hws;
+               u32 ipeir;
+               u32 ipehr;
+               u32 instdone;
+               u32 bbstate;
+               u32 instpm;
+               u32 instps;
+               u32 seqno;
+               u64 bbaddr;
+               u64 acthd;
+               u32 fault_reg;
+               u32 faddr;
+               u32 rc_psmi; /* sleep state */
+               u32 semaphore_mboxes[I915_NUM_RINGS - 1];
+
                struct drm_i915_error_object {
                        int page_count;
                        u32 gtt_offset;
                        u32 *pages[0];
-               } *ringbuffer, *batchbuffer, *ctx;
+               } *ringbuffer, *batchbuffer, *wa_batchbuffer, *ctx, *hws_page;
+
                struct drm_i915_error_request {
                        long jiffies;
                        u32 seqno;
                        u32 tail;
                } *requests;
-               int num_requests;
+
+               struct {
+                       u32 gfx_mode;
+                       union {
+                               u64 pdp[4];
+                               u32 pp_dir_base;
+                       };
+               } vm_info;
+
+               pid_t pid;
+               char comm[TASK_COMM_LEN];
        } ring[I915_NUM_RINGS];
        struct drm_i915_error_buffer {
                u32 size;
@@ -358,15 +400,13 @@ struct drm_i915_error_state {
                s32 ring:4;
                u32 cache_level:3;
        } **active_bo, **pinned_bo;
+
        u32 *active_bo_count, *pinned_bo_count;
-       struct intel_overlay_error_state *overlay;
-       struct intel_display_error_state *display;
-       int hangcheck_score[I915_NUM_RINGS];
-       enum intel_ring_hangcheck_action hangcheck_action[I915_NUM_RINGS];
 };
 
 struct intel_connector;
 struct intel_crtc_config;
+struct intel_plane_config;
 struct intel_crtc;
 struct intel_limit;
 struct dpll;
@@ -405,6 +445,8 @@ 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_plane_config)(struct intel_crtc *,
+                                struct intel_plane_config *);
        int (*crtc_mode_set)(struct drm_crtc *crtc,
                             int x, int y,
                             struct drm_framebuffer *old_fb);
@@ -420,8 +462,9 @@ struct drm_i915_display_funcs {
                          struct drm_framebuffer *fb,
                          struct drm_i915_gem_object *obj,
                          uint32_t flags);
-       int (*update_plane)(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-                           int x, int y);
+       int (*update_primary_plane)(struct drm_crtc *crtc,
+                                   struct drm_framebuffer *fb,
+                                   int x, int y);
        void (*hpd_irq_setup)(struct drm_device *dev);
        /* clock updates for mode set */
        /* cursor updates */
@@ -469,7 +512,7 @@ struct intel_uncore {
        unsigned fw_rendercount;
        unsigned fw_mediacount;
 
-       struct delayed_work force_wake_work;
+       struct timer_list force_wake_timer;
 };
 
 #define DEV_INFO_FOR_EACH_FLAG(func, sep) \
@@ -504,9 +547,16 @@ struct intel_uncore {
 struct intel_device_info {
        u32 display_mmio_offset;
        u8 num_pipes:3;
+       u8 num_sprites[I915_MAX_PIPES];
        u8 gen;
        u8 ring_mask; /* Rings supported by the HW */
        DEV_INFO_FOR_EACH_FLAG(DEFINE_FLAG, SEP_SEMICOLON);
+       /* Register offsets for the various display pipes and transcoders */
+       int pipe_offsets[I915_MAX_TRANSCODERS];
+       int trans_offsets[I915_MAX_TRANSCODERS];
+       int dpll_offsets[I915_MAX_PIPES];
+       int dpll_md_offsets[I915_MAX_PIPES];
+       int palette_offsets[I915_MAX_PIPES];
 };
 
 #undef DEFINE_FLAG
@@ -524,6 +574,57 @@ enum i915_cache_level {
 
 typedef uint32_t gen6_gtt_pte_t;
 
+/**
+ * A VMA represents a GEM BO that is bound into an address space. Therefore, a
+ * VMA's presence cannot be guaranteed before binding, or after unbinding the
+ * object into/from the address space.
+ *
+ * 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;
+
+       /** This object's place on the active/inactive lists */
+       struct list_head mm_list;
+
+       struct list_head vma_link; /* Link in the object's VMA list */
+
+       /** This vma's place in the batchbuffer or on the eviction list */
+       struct list_head exec_list;
+
+       /**
+        * Used for performing relocations during execbuffer insertion.
+        */
+       struct hlist_node exec_node;
+       unsigned long exec_handle;
+       struct drm_i915_gem_exec_object2 *exec_entry;
+
+       /**
+        * How many users have pinned this object in GTT space. The following
+        * users can each hold at most one reference: pwrite/pread, pin_ioctl
+        * (via user_pin_count), execbuffer (objects are not allowed multiple
+        * times for the same batchbuffer), and the framebuffer code. When
+        * switching/pageflipping, the framebuffer code has at most two buffers
+        * pinned per crtc.
+        *
+        * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
+        * bits with absolutely no headroom. So use 4 bits. */
+       unsigned int pin_count:4;
+#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
+
+       /** Unmap an object from an address space. This usually consists of
+        * setting the valid PTE entries to a reserved scratch page. */
+       void (*unbind_vma)(struct i915_vma *vma);
+       /* Map an object into an address space with the given cache flags. */
+#define GLOBAL_BIND (1<<0)
+       void (*bind_vma)(struct i915_vma *vma,
+                        enum i915_cache_level cache_level,
+                        u32 flags);
+};
+
 struct i915_address_space {
        struct drm_mm mm;
        struct drm_device *dev;
@@ -564,12 +665,12 @@ struct i915_address_space {
                                     enum i915_cache_level level,
                                     bool valid); /* Create a valid PTE */
        void (*clear_range)(struct i915_address_space *vm,
-                           unsigned int first_entry,
-                           unsigned int num_entries,
+                           uint64_t start,
+                           uint64_t length,
                            bool use_scratch);
        void (*insert_entries)(struct i915_address_space *vm,
                               struct sg_table *st,
-                              unsigned int first_entry,
+                              uint64_t start,
                               enum i915_cache_level cache_level);
        void (*cleanup)(struct i915_address_space *vm);
 };
@@ -603,55 +704,34 @@ struct i915_gtt {
 };
 #define gtt_total_entries(gtt) ((gtt).base.total >> PAGE_SHIFT)
 
+#define GEN8_LEGACY_PDPS 4
 struct i915_hw_ppgtt {
        struct i915_address_space base;
+       struct kref ref;
+       struct drm_mm_node node;
        unsigned num_pd_entries;
+       unsigned num_pd_pages; /* gen8+ */
        union {
                struct page **pt_pages;
-               struct page *gen8_pt_pages;
+               struct page **gen8_pt_pages[GEN8_LEGACY_PDPS];
        };
        struct page *pd_pages;
-       int num_pd_pages;
-       int num_pt_pages;
        union {
                uint32_t pd_offset;
-               dma_addr_t pd_dma_addr[4];
+               dma_addr_t pd_dma_addr[GEN8_LEGACY_PDPS];
        };
        union {
                dma_addr_t *pt_dma_addr;
                dma_addr_t *gen8_pt_dma_addr[4];
        };
-       int (*enable)(struct drm_device *dev);
-};
-
-/**
- * A VMA represents a GEM BO that is bound into an address space. Therefore, a
- * VMA's presence cannot be guaranteed before binding, or after unbinding the
- * object into/from the address space.
- *
- * 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;
-
-       /** This object's place on the active/inactive lists */
-       struct list_head mm_list;
 
-       struct list_head vma_link; /* Link in the object's VMA list */
-
-       /** This vma's place in the batchbuffer or on the eviction list */
-       struct list_head exec_list;
-
-       /**
-        * Used for performing relocations during execbuffer insertion.
-        */
-       struct hlist_node exec_node;
-       unsigned long exec_handle;
-       struct drm_i915_gem_exec_object2 *exec_entry;
+       struct i915_hw_context *ctx;
 
+       int (*enable)(struct i915_hw_ppgtt *ppgtt);
+       int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
+                        struct intel_ring_buffer *ring,
+                        bool synchronous);
+       void (*debug_dump)(struct i915_hw_ppgtt *ppgtt, struct seq_file *m);
 };
 
 struct i915_ctx_hang_stats {
@@ -676,9 +756,10 @@ struct i915_hw_context {
        bool is_initialized;
        uint8_t remap_slice;
        struct drm_i915_file_private *file_priv;
-       struct intel_ring_buffer *ring;
+       struct intel_ring_buffer *last_ring;
        struct drm_i915_gem_object *obj;
        struct i915_ctx_hang_stats hang_stats;
+       struct i915_address_space *vm;
 
        struct list_head link;
 };
@@ -831,11 +912,7 @@ struct i915_suspend_saved_registers {
        u32 savePFIT_CONTROL;
        u32 save_palette_a[256];
        u32 save_palette_b[256];
-       u32 saveDPFC_CB_BASE;
-       u32 saveFBC_CFB_BASE;
-       u32 saveFBC_LL_BASE;
        u32 saveFBC_CONTROL;
-       u32 saveFBC_CONTROL2;
        u32 saveIER;
        u32 saveIIR;
        u32 saveIMR;
@@ -905,15 +982,24 @@ struct intel_gen6_power_mgmt {
        struct work_struct work;
        u32 pm_iir;
 
-       /* The below variables an all the rps hw state are protected by
-        * dev->struct mutext. */
-       u8 cur_delay;
-       u8 min_delay;
-       u8 max_delay;
-       u8 rpe_delay;
-       u8 rp1_delay;
-       u8 rp0_delay;
-       u8 hw_max;
+       /* Frequencies are stored in potentially platform dependent multiples.
+        * In other words, *_freq needs to be multiplied by X to be interesting.
+        * Soft limits are those which are used for the dynamic reclocking done
+        * by the driver (raise frequencies under heavy loads, and lower for
+        * lighter loads). Hard limits are those imposed by the hardware.
+        *
+        * A distinction is made for overclocking, which is never enabled by
+        * default, and is considered to be above the hard limit if it's
+        * possible at all.
+        */
+       u8 cur_freq;            /* Current frequency (cached, may not == HW) */
+       u8 min_freq_softlimit;  /* Minimum frequency permitted by the driver */
+       u8 max_freq_softlimit;  /* Max frequency permitted by the driver */
+       u8 max_freq;            /* Maximum frequency, RP0 if not overclocking */
+       u8 min_freq;            /* AKA RPn. Minimum frequency */
+       u8 efficient_freq;      /* AKA RPe. Pre-determined balanced frequency */
+       u8 rp1_freq;            /* "less than" RP0 power/freqency */
+       u8 rp0_freq;            /* Non-overclocked max frequency. */
 
        int last_adj;
        enum { LOW_POWER, BETWEEN, HIGH_POWER } power;
@@ -953,6 +1039,36 @@ struct intel_ilk_power_mgmt {
        struct drm_i915_gem_object *renderctx;
 };
 
+struct drm_i915_private;
+struct i915_power_well;
+
+struct i915_power_well_ops {
+       /*
+        * Synchronize the well's hw state to match the current sw state, for
+        * example enable/disable it based on the current refcount. Called
+        * during driver init and resume time, possibly after first calling
+        * the enable/disable handlers.
+        */
+       void (*sync_hw)(struct drm_i915_private *dev_priv,
+                       struct i915_power_well *power_well);
+       /*
+        * Enable the well and resources that depend on it (for example
+        * interrupts located on the well). Called after the 0->1 refcount
+        * transition.
+        */
+       void (*enable)(struct drm_i915_private *dev_priv,
+                      struct i915_power_well *power_well);
+       /*
+        * Disable the well and resources that depend on it. Called after
+        * the 1->0 refcount transition.
+        */
+       void (*disable)(struct drm_i915_private *dev_priv,
+                       struct i915_power_well *power_well);
+       /* Returns the hw enabled state. */
+       bool (*is_enabled)(struct drm_i915_private *dev_priv,
+                          struct i915_power_well *power_well);
+};
+
 /* Power well structure for haswell */
 struct i915_power_well {
        const char *name;
@@ -960,11 +1076,8 @@ struct i915_power_well {
        /* power well enable/disable usage count */
        int count;
        unsigned long domains;
-       void *data;
-       void (*set)(struct drm_device *dev, struct i915_power_well *power_well,
-                   bool enable);
-       bool (*is_enabled)(struct drm_device *dev,
-                          struct i915_power_well *power_well);
+       unsigned long data;
+       const struct i915_power_well_ops *ops;
 };
 
 struct i915_power_domains {
@@ -1061,6 +1174,14 @@ struct i915_gem_mm {
         */
        bool interruptible;
 
+       /**
+        * Is the GPU currently considered idle, or busy executing userspace
+        * requests?  Whilst idle, we attempt to power down the hardware and
+        * display clocks. In order to reduce the effect on performance, there
+        * is a slight delay before we do so.
+        */
+       bool busy;
+
        /** Bit 6 swizzling required for X tiling */
        uint32_t bit_6_swizzle_x;
        /** Bit 6 swizzling required for Y tiling */
@@ -1226,44 +1347,19 @@ struct ilk_wm_values {
 };
 
 /*
- * This struct tracks the state needed for the Package C8+ feature.
- *
- * Package states C8 and deeper are really deep PC states that can only be
- * reached when all the devices on the system allow it, so even if the graphics
- * device allows PC8+, it doesn't mean the system will actually get to these
- * states.
- *
- * Our driver only allows PC8+ when all the outputs are disabled, the power well
- * is disabled and the GPU is idle. When these conditions are met, we manually
- * do the other conditions: disable the interrupts, clocks and switch LCPLL
- * refclk to Fclk.
- *
- * When we really reach PC8 or deeper states (not just when we allow it) we lose
- * the state of some registers, so when we come back from PC8+ we need to
- * restore this state. We don't get into PC8+ if we're not in RC6, so we don't
- * need to take care of the registers kept by RC6.
+ * This struct helps tracking the state needed for runtime PM, which puts the
+ * device in PCI D3 state. Notice that when this happens, nothing on the
+ * graphics device works, even register access, so we don't get interrupts nor
+ * anything else.
  *
- * The interrupt disabling is part of the requirements. We can only leave the
- * PCH HPD interrupts enabled. If we're in PC8+ and we get another interrupt we
- * can lock the machine.
+ * Every piece of our code that needs to actually touch the hardware needs to
+ * either call intel_runtime_pm_get or call intel_display_power_get with the
+ * appropriate power domain.
  *
- * Ideally every piece of our code that needs PC8+ disabled would call
- * hsw_disable_package_c8, which would increment disable_count and prevent the
- * system from reaching PC8+. But we don't have a symmetric way to do this for
- * everything, so we have the requirements_met and gpu_idle variables. When we
- * switch requirements_met or gpu_idle to true we decrease disable_count, and
- * increase it in the opposite case. The requirements_met variable is true when
- * all the CRTCs, encoders and the power well are disabled. The gpu_idle
- * variable is true when the GPU is idle.
- *
- * In addition to everything, we only actually enable PC8+ if disable_count
- * stays at zero for at least some seconds. This is implemented with the
- * enable_work variable. We do this so we don't enable/disable PC8 dozens of
- * consecutive times when all screens are disabled and some background app
- * queries the state of our connectors, or we have some application constantly
- * waking up to use the GPU. Only after the enable_work function actually
- * enables PC8+ the "enable" variable will become true, which means that it can
- * be false even if disable_count is 0.
+ * Our driver uses the autosuspend delay feature, which means we'll only really
+ * suspend if we stay with zero refcount for a certain amount of time. The
+ * default value is currently very conservative (see intel_init_runtime_pm), but
+ * it can be changed with the standard runtime PM files from sysfs.
  *
  * The irqs_disabled variable becomes true exactly after we disable the IRQs and
  * goes back to false exactly before we reenable the IRQs. We use this variable
@@ -1273,17 +1369,11 @@ struct ilk_wm_values {
  * inside struct regsave so when we restore the IRQs they will contain the
  * latest expected values.
  *
- * For more, read "Display Sequences for Package C8" on our documentation.
+ * For more, read the Documentation/power/runtime_pm.txt.
  */
-struct i915_package_c8 {
-       bool requirements_met;
-       bool gpu_idle;
+struct i915_runtime_pm {
+       bool suspended;
        bool irqs_disabled;
-       /* Only true after the delayed work task actually enables it. */
-       bool enabled;
-       int disable_count;
-       struct mutex lock;
-       struct delayed_work enable_work;
 
        struct {
                uint32_t deimr;
@@ -1294,10 +1384,6 @@ struct i915_package_c8 {
        } regsave;
 };
 
-struct i915_runtime_pm {
-       bool suspended;
-};
-
 enum intel_pipe_crc_source {
        INTEL_PIPE_CRC_SOURCE_NONE,
        INTEL_PIPE_CRC_SOURCE_PLANE1,
@@ -1332,7 +1418,7 @@ typedef struct drm_i915_private {
        struct drm_device *dev;
        struct kmem_cache *slab;
 
-       const struct intel_device_info *info;
+       const struct intel_device_info info;
 
        int relative_constants_mode;
 
@@ -1361,11 +1447,11 @@ typedef struct drm_i915_private {
        drm_dma_handle_t *status_page_dmah;
        struct resource mch_res;
 
-       atomic_t irq_received;
-
        /* protects the irq masks */
        spinlock_t irq_lock;
 
+       bool display_irqs_enabled;
+
        /* To control wakeup latency, e.g. for irq-driven dp aux transfers. */
        struct pm_qos_request pm_qos;
 
@@ -1379,6 +1465,8 @@ typedef struct drm_i915_private {
        };
        u32 gt_irq_mask;
        u32 pm_irq_mask;
+       u32 pm_rps_events;
+       u32 pipestat_irq_mask[I915_MAX_PIPES];
 
        struct work_struct hotplug_work;
        bool enable_hotplug_processing;
@@ -1394,8 +1482,6 @@ typedef struct drm_i915_private {
        u32 hpd_event_bits;
        struct timer_list hotplug_reenable_timer;
 
-       int num_plane;
-
        struct i915_fbc fbc;
        struct intel_opregion opregion;
        struct intel_vbt_data vbt;
@@ -1445,8 +1531,8 @@ typedef struct drm_i915_private {
 
        struct sdvo_device_mapping sdvo_mappings[2];
 
-       struct drm_crtc *plane_to_crtc_mapping[3];
-       struct drm_crtc *pipe_to_crtc_mapping[3];
+       struct drm_crtc *plane_to_crtc_mapping[I915_MAX_PIPES];
+       struct drm_crtc *pipe_to_crtc_mapping[I915_MAX_PIPES];
        wait_queue_head_t pending_flip_queue;
 
 #ifdef CONFIG_DEBUG_FS
@@ -1506,6 +1592,7 @@ typedef struct drm_i915_private {
 
        u32 fdi_rx_config;
 
+       u32 suspend_count;
        struct i915_suspend_saved_registers regfile;
 
        struct {
@@ -1525,8 +1612,6 @@ typedef struct drm_i915_private {
                struct ilk_wm_values hw;
        } wm;
 
-       struct i915_package_c8 pc8;
-
        struct i915_runtime_pm pm;
 
        /* Old dri1 support infrastructure, beware the dragons ya fools entering
@@ -1627,18 +1712,6 @@ struct drm_i915_gem_object {
         */
        unsigned int fence_dirty:1;
 
-       /** How many users have pinned this object in GTT space. The following
-        * users can each hold at most one reference: pwrite/pread, pin_ioctl
-        * (via user_pin_count), execbuffer (objects are not allowed multiple
-        * times for the same batchbuffer), and the framebuffer code. When
-        * switching/pageflipping, the framebuffer code has at most two buffers
-        * pinned per crtc.
-        *
-        * In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
-        * bits with absolutely no headroom. So use 4 bits. */
-       unsigned int pin_count:4;
-#define DRM_I915_GEM_OBJECT_MAX_PIN_COUNT 0xf
-
        /**
         * Is the object at the current location in the gtt mappable and
         * fenceable? Used to avoid costly recalculations.
@@ -1697,7 +1770,6 @@ struct drm_i915_gem_object {
        /** for phy allocated objects */
        struct drm_i915_gem_phys_object *phys_obj;
 };
-#define to_gem_object(obj) (&((struct drm_i915_gem_object *)(obj))->base)
 
 #define to_intel_bo(x) container_of(x, struct drm_i915_gem_object, base)
 
@@ -1743,6 +1815,7 @@ struct drm_i915_gem_request {
 
 struct drm_i915_file_private {
        struct drm_i915_private *dev_priv;
+       struct drm_file *file;
 
        struct {
                spinlock_t lock;
@@ -1751,11 +1824,95 @@ struct drm_i915_file_private {
        } mm;
        struct idr context_idr;
 
-       struct i915_ctx_hang_stats hang_stats;
+       struct i915_hw_context *private_default_ctx;
        atomic_t rps_wait_boost;
 };
 
-#define INTEL_INFO(dev)        (to_i915(dev)->info)
+/*
+ * A command that requires special handling by the command parser.
+ */
+struct drm_i915_cmd_descriptor {
+       /*
+        * Flags describing how the command parser processes the command.
+        *
+        * CMD_DESC_FIXED: The command has a fixed length if this is set,
+        *                 a length mask if not set
+        * CMD_DESC_SKIP: The command is allowed but does not follow the
+        *                standard length encoding for the opcode range in
+        *                which it falls
+        * CMD_DESC_REJECT: The command is never allowed
+        * CMD_DESC_REGISTER: The command should be checked against the
+        *                    register whitelist for the appropriate ring
+        * CMD_DESC_MASTER: The command is allowed if the submitting process
+        *                  is the DRM master
+        */
+       u32 flags;
+#define CMD_DESC_FIXED    (1<<0)
+#define CMD_DESC_SKIP     (1<<1)
+#define CMD_DESC_REJECT   (1<<2)
+#define CMD_DESC_REGISTER (1<<3)
+#define CMD_DESC_BITMASK  (1<<4)
+#define CMD_DESC_MASTER   (1<<5)
+
+       /*
+        * The command's unique identification bits and the bitmask to get them.
+        * This isn't strictly the opcode field as defined in the spec and may
+        * also include type, subtype, and/or subop fields.
+        */
+       struct {
+               u32 value;
+               u32 mask;
+       } cmd;
+
+       /*
+        * The command's length. The command is either fixed length (i.e. does
+        * not include a length field) or has a length field mask. The flag
+        * CMD_DESC_FIXED indicates a fixed length. Otherwise, the command has
+        * a length mask. All command entries in a command table must include
+        * length information.
+        */
+       union {
+               u32 fixed;
+               u32 mask;
+       } length;
+
+       /*
+        * Describes where to find a register address in the command to check
+        * against the ring's register whitelist. Only valid if flags has the
+        * CMD_DESC_REGISTER bit set.
+        */
+       struct {
+               u32 offset;
+               u32 mask;
+       } reg;
+
+#define MAX_CMD_DESC_BITMASKS 3
+       /*
+        * Describes command checks where a particular dword is masked and
+        * compared against an expected value. If the command does not match
+        * the expected value, the parser rejects it. Only valid if flags has
+        * the CMD_DESC_BITMASK bit set. Only entries where mask is non-zero
+        * are valid.
+        */
+       struct {
+               u32 offset;
+               u32 mask;
+               u32 expected;
+       } bits[MAX_CMD_DESC_BITMASKS];
+};
+
+/*
+ * A table of commands requiring special handling by the command parser.
+ *
+ * Each ring has an array of tables. Each table consists of an array of command
+ * descriptors, which must be sorted with command opcodes in ascending order.
+ */
+struct drm_i915_cmd_table {
+       const struct drm_i915_cmd_descriptor *table;
+       int count;
+};
+
+#define INTEL_INFO(dev)        (&to_i915(dev)->info)
 
 #define IS_I830(dev)           ((dev)->pdev->device == 0x3577)
 #define IS_845G(dev)           ((dev)->pdev->device == 0x2562)
@@ -1824,7 +1981,11 @@ struct drm_i915_file_private {
 #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
 
 #define HAS_HW_CONTEXTS(dev)   (INTEL_INFO(dev)->gen >= 6)
-#define HAS_ALIASING_PPGTT(dev)        (INTEL_INFO(dev)->gen >=6 && !IS_VALLEYVIEW(dev))
+#define HAS_ALIASING_PPGTT(dev)        (INTEL_INFO(dev)->gen >= 6 && !IS_VALLEYVIEW(dev))
+#define HAS_PPGTT(dev)         (INTEL_INFO(dev)->gen >= 7 && !IS_VALLEYVIEW(dev) \
+                                && !IS_BROADWELL(dev))
+#define USES_PPGTT(dev)                intel_enable_ppgtt(dev, false)
+#define USES_FULL_PPGTT(dev)   intel_enable_ppgtt(dev, true)
 
 #define HAS_OVERLAY(dev)               (INTEL_INFO(dev)->has_overlay)
 #define OVERLAY_NEEDS_PHYSICAL(dev)    (INTEL_INFO(dev)->overlay_needs_physical)
@@ -1887,32 +2048,40 @@ struct drm_i915_file_private {
 
 extern const struct drm_ioctl_desc i915_ioctls[];
 extern int i915_max_ioctl;
-extern unsigned int i915_fbpercrtc __always_unused;
-extern int i915_panel_ignore_lid __read_mostly;
-extern unsigned int i915_powersave __read_mostly;
-extern int i915_semaphores __read_mostly;
-extern unsigned int i915_lvds_downclock __read_mostly;
-extern int i915_lvds_channel_mode __read_mostly;
-extern int i915_panel_use_ssc __read_mostly;
-extern int i915_vbt_sdvo_panel_type __read_mostly;
-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 int i915_enable_pc8 __read_mostly;
-extern int i915_pc8_timeout __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);
 extern int i915_master_create(struct drm_device *dev, struct drm_master *master);
 extern void i915_master_destroy(struct drm_device *dev, struct drm_master *master);
 
+/* i915_params.c */
+struct i915_params {
+       int modeset;
+       int panel_ignore_lid;
+       unsigned int powersave;
+       int semaphores;
+       unsigned int lvds_downclock;
+       int lvds_channel_mode;
+       int panel_use_ssc;
+       int vbt_sdvo_panel_type;
+       int enable_rc6;
+       int enable_fbc;
+       int enable_ppgtt;
+       int enable_psr;
+       unsigned int preliminary_hw_support;
+       int disable_power_well;
+       int enable_ips;
+       int invert_brightness;
+       int enable_cmd_parser;
+       /* leave bools at the end to not create holes */
+       bool enable_hangcheck;
+       bool fastboot;
+       bool prefault_disable;
+       bool reset;
+       bool disable_display;
+};
+extern struct i915_params i915 __read_mostly;
+
                                /* i915_dma.c */
 void i915_update_dri1_breadcrumb(struct drm_device *dev);
 extern void i915_kernel_lost_context(struct drm_device * dev);
@@ -1943,8 +2112,12 @@ extern void intel_console_resume(struct work_struct *work);
 
 /* i915_irq.c */
 void i915_queue_hangcheck(struct drm_device *dev);
-void i915_handle_error(struct drm_device *dev, bool wedged);
+__printf(3, 4)
+void i915_handle_error(struct drm_device *dev, bool wedged,
+                      const char *fmt, ...);
 
+void gen6_set_pm_mask(struct drm_i915_private *dev_priv, u32 pm_iir,
+                                                       int new_delay);
 extern void intel_irq_init(struct drm_device *dev);
 extern void intel_hpd_init(struct drm_device *dev);
 
@@ -1955,10 +2128,15 @@ extern void intel_uncore_check_errors(struct drm_device *dev);
 extern void intel_uncore_fini(struct drm_device *dev);
 
 void
-i915_enable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask);
+i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                    u32 status_mask);
 
 void
-i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask);
+i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                     u32 status_mask);
+
+void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv);
+void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv);
 
 /* i915_gem.c */
 int i915_gem_init_ioctl(struct drm_device *dev, void *data,
@@ -2014,22 +2192,27 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
                         const struct drm_i915_gem_object_ops *ops);
 struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
                                                  size_t size);
+void i915_init_vm(struct drm_i915_private *dev_priv,
+                 struct i915_address_space *vm);
 void i915_gem_free_object(struct drm_gem_object *obj);
 void i915_gem_vma_destroy(struct i915_vma *vma);
 
+#define PIN_MAPPABLE 0x1
+#define PIN_NONBLOCK 0x2
+#define PIN_GLOBAL 0x4
 int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
                                     struct i915_address_space *vm,
                                     uint32_t alignment,
-                                    bool map_and_fenceable,
-                                    bool nonblocking);
-void i915_gem_object_unpin(struct drm_i915_gem_object *obj);
+                                    unsigned flags);
 int __must_check i915_vma_unbind(struct i915_vma *vma);
-int __must_check i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj);
 int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
 void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
 void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
 void i915_gem_lastclose(struct drm_device *dev);
 
+int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
+                                   int *needs_clflush);
+
 int __must_check i915_gem_object_get_pages(struct drm_i915_gem_object *obj);
 static inline struct page *i915_gem_object_get_page(struct drm_i915_gem_object *obj, int n)
 {
@@ -2096,8 +2279,10 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
        }
 }
 
+struct drm_i915_gem_request *
+i915_gem_find_active_request(struct intel_ring_buffer *ring);
+
 bool i915_gem_retire_requests(struct drm_device *dev);
-void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring);
 int __must_check i915_gem_check_wedge(struct i915_gpu_error *error,
                                      bool interruptible);
 static inline bool i915_reset_in_progress(struct i915_gpu_error *error)
@@ -2186,6 +2371,13 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
                                  struct i915_address_space *vm);
 
 struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj);
+static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
+       struct i915_vma *vma;
+       list_for_each_entry(vma, &obj->vma_list, vma_link)
+               if (vma->pin_count > 0)
+                       return true;
+       return false;
+}
 
 /* Some GGTT VM helpers */
 #define obj_to_ggtt(obj) \
@@ -2217,54 +2409,69 @@ i915_gem_obj_ggtt_size(struct drm_i915_gem_object *obj)
 static inline int __must_check
 i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj,
                      uint32_t alignment,
-                     bool map_and_fenceable,
-                     bool nonblocking)
+                     unsigned flags)
 {
-       return i915_gem_object_pin(obj, obj_to_ggtt(obj), alignment,
-                                  map_and_fenceable, nonblocking);
+       return i915_gem_object_pin(obj, obj_to_ggtt(obj), alignment, flags | PIN_GLOBAL);
 }
 
+static inline int
+i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj)
+{
+       return i915_vma_unbind(i915_gem_obj_to_ggtt(obj));
+}
+
+void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj);
+
 /* i915_gem_context.c */
+#define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base)
 int __must_check i915_gem_context_init(struct drm_device *dev);
 void i915_gem_context_fini(struct drm_device *dev);
+void i915_gem_context_reset(struct drm_device *dev);
+int i915_gem_context_open(struct drm_device *dev, struct drm_file *file);
+int i915_gem_context_enable(struct drm_i915_private *dev_priv);
 void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
 int i915_switch_context(struct intel_ring_buffer *ring,
-                       struct drm_file *file, int to_id);
+                       struct drm_file *file, struct i915_hw_context *to);
+struct i915_hw_context *
+i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
 void i915_gem_context_free(struct kref *ctx_ref);
 static inline void i915_gem_context_reference(struct i915_hw_context *ctx)
 {
-       kref_get(&ctx->ref);
+       if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev))
+               kref_get(&ctx->ref);
 }
 
 static inline void i915_gem_context_unreference(struct i915_hw_context *ctx)
 {
-       kref_put(&ctx->ref, i915_gem_context_free);
+       if (ctx->obj && HAS_HW_CONTEXTS(ctx->obj->base.dev))
+               kref_put(&ctx->ref, i915_gem_context_free);
+}
+
+static inline bool i915_gem_context_is_default(const struct i915_hw_context *c)
+{
+       return c->id == DEFAULT_CONTEXT_ID;
 }
 
-struct i915_ctx_hang_stats * __must_check
-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,
                                  struct drm_file *file);
 int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
                                   struct drm_file *file);
 
-/* i915_gem_gtt.c */
-void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev);
-void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
-                           struct drm_i915_gem_object *obj,
-                           enum i915_cache_level cache_level);
-void i915_ppgtt_unbind_object(struct i915_hw_ppgtt *ppgtt,
-                             struct drm_i915_gem_object *obj);
+/* i915_gem_evict.c */
+int __must_check i915_gem_evict_something(struct drm_device *dev,
+                                         struct i915_address_space *vm,
+                                         int min_size,
+                                         unsigned alignment,
+                                         unsigned cache_level,
+                                         unsigned flags);
+int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
+int i915_gem_evict_everything(struct drm_device *dev);
 
+/* i915_gem_gtt.c */
 void i915_check_and_clear_faults(struct drm_device *dev);
 void i915_gem_suspend_gtt_mappings(struct drm_device *dev);
 void i915_gem_restore_gtt_mappings(struct drm_device *dev);
 int __must_check i915_gem_gtt_prepare_object(struct drm_i915_gem_object *obj);
-void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
-                               enum i915_cache_level cache_level);
-void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj);
 void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj);
 void i915_gem_init_global_gtt(struct drm_device *dev);
 void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
@@ -2275,18 +2482,8 @@ static inline void i915_gem_chipset_flush(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen < 6)
                intel_gtt_chipset_flush();
 }
-
-
-/* i915_gem_evict.c */
-int __must_check i915_gem_evict_something(struct drm_device *dev,
-                                         struct i915_address_space *vm,
-                                         int min_size,
-                                         unsigned alignment,
-                                         unsigned cache_level,
-                                         bool mappable,
-                                         bool nonblock);
-int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
-int i915_gem_evict_everything(struct drm_device *dev);
+int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt);
+bool intel_enable_ppgtt(struct drm_device *dev, bool full);
 
 /* i915_gem_stolen.c */
 int i915_gem_init_stolen(struct drm_device *dev);
@@ -2305,7 +2502,7 @@ void i915_gem_object_release_stolen(struct drm_i915_gem_object *obj);
 /* i915_gem_tiling.c */
 static inline bool i915_gem_object_needs_bit17_swizzle(struct drm_i915_gem_object *obj)
 {
-       drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
 
        return dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_9_10_17 &&
                obj->tiling_mode != I915_TILING_NONE;
@@ -2343,7 +2540,8 @@ static inline void i915_error_state_buf_release(
 {
        kfree(eb->buf);
 }
-void i915_capture_error_state(struct drm_device *dev);
+void i915_capture_error_state(struct drm_device *dev, bool wedge,
+                             const char *error_msg);
 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);
@@ -2352,6 +2550,14 @@ 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_cmd_parser.c */
+void i915_cmd_parser_init_ring(struct intel_ring_buffer *ring);
+bool i915_needs_cmd_parser(struct intel_ring_buffer *ring);
+int i915_parse_cmds(struct intel_ring_buffer *ring,
+                   struct drm_i915_gem_object *batch_obj,
+                   u32 batch_start_offset,
+                   bool is_master);
+
 /* i915_suspend.c */
 extern int i915_save_state(struct drm_device *dev);
 extern int i915_restore_state(struct drm_device *dev);
@@ -2425,10 +2631,12 @@ extern void intel_modeset_suspend_hw(struct drm_device *dev);
 extern void intel_modeset_init(struct drm_device *dev);
 extern void intel_modeset_gem_init(struct drm_device *dev);
 extern void intel_modeset_cleanup(struct drm_device *dev);
+extern void intel_connector_unregister(struct intel_connector *);
 extern int intel_modeset_vga_set_state(struct drm_device *dev, bool state);
 extern void intel_modeset_setup_hw_state(struct drm_device *dev,
                                         bool force_restore);
 extern void i915_redisable_vga(struct drm_device *dev);
+extern void i915_redisable_vga_power_on(struct drm_device *dev);
 extern bool intel_fbc_enabled(struct drm_device *dev);
 extern void intel_disable_fbc(struct drm_device *dev);
 extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
@@ -2463,6 +2671,7 @@ 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, int fw_engine);
 void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine);
+void assert_force_wake_inactive(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);
@@ -2525,9 +2734,26 @@ void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine);
 #define I915_READ_NOTRACE(reg)         dev_priv->uncore.funcs.mmio_readl(dev_priv, (reg), false)
 #define I915_WRITE_NOTRACE(reg, val)   dev_priv->uncore.funcs.mmio_writel(dev_priv, (reg), (val), false)
 
+/* Be very careful with read/write 64-bit values. On 32-bit machines, they
+ * will be implemented using 2 32-bit writes in an arbitrary order with
+ * an arbitrary delay between them. This can cause the hardware to
+ * act upon the intermediate value, possibly leading to corruption and
+ * machine death. You have been warned.
+ */
 #define I915_WRITE64(reg, val) dev_priv->uncore.funcs.mmio_writeq(dev_priv, (reg), (val), true)
 #define I915_READ64(reg)       dev_priv->uncore.funcs.mmio_readq(dev_priv, (reg), true)
 
+#define I915_READ64_2x32(lower_reg, upper_reg) ({                      \
+               u32 upper = I915_READ(upper_reg);                       \
+               u32 lower = I915_READ(lower_reg);                       \
+               u32 tmp = I915_READ(upper_reg);                         \
+               if (upper != tmp) {                                     \
+                       upper = tmp;                                    \
+                       lower = I915_READ(lower_reg);                   \
+                       WARN_ON(I915_READ(upper_reg) != upper);         \
+               }                                                       \
+               (u64)upper << 32 | lower; })
+
 #define POSTING_READ(reg)      (void)I915_READ_NOTRACE(reg)
 #define POSTING_READ16(reg)    (void)I915_READ16_NOTRACE(reg)
 
@@ -2566,4 +2792,31 @@ timespec_to_jiffies_timeout(const struct timespec *value)
        return min_t(unsigned long, MAX_JIFFY_OFFSET, j + 1);
 }
 
+/*
+ * If you need to wait X milliseconds between events A and B, but event B
+ * doesn't happen exactly after event A, you record the timestamp (jiffies) of
+ * when event A happened, then just before event B you call this function and
+ * pass the timestamp as the first argument, and X as the second argument.
+ */
+static inline void
+wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
+{
+       unsigned long target_jiffies, tmp_jiffies, remaining_jiffies;
+
+       /*
+        * Don't re-read the value of "jiffies" every time since it may change
+        * behind our back and break the math.
+        */
+       tmp_jiffies = jiffies;
+       target_jiffies = timestamp_jiffies +
+                        msecs_to_jiffies_timeout(to_wait_ms);
+
+       if (time_after(target_jiffies, tmp_jiffies)) {
+               remaining_jiffies = target_jiffies - tmp_jiffies;
+               while (remaining_jiffies)
+                       remaining_jiffies =
+                           schedule_timeout_uninterruptible(remaining_jiffies);
+       }
+}
+
 #endif
index 00c8361..6370a76 100644 (file)
@@ -43,12 +43,6 @@ static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *o
 static __must_check int
 i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
                               bool readonly);
-static __must_check int
-i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
-                          struct i915_address_space *vm,
-                          unsigned alignment,
-                          bool map_and_fenceable,
-                          bool nonblocking);
 static int i915_gem_phys_pwrite(struct drm_device *dev,
                                struct drm_i915_gem_object *obj,
                                struct drm_i915_gem_pwrite *args,
@@ -67,6 +61,7 @@ static unsigned long i915_gem_inactive_scan(struct shrinker *shrinker,
 static unsigned long i915_gem_purge(struct drm_i915_private *dev_priv, long target);
 static unsigned long i915_gem_shrink_all(struct drm_i915_private *dev_priv);
 static void i915_gem_object_truncate(struct drm_i915_gem_object *obj);
+static void i915_gem_retire_requests_ring(struct intel_ring_buffer *ring);
 
 static bool cpu_cache_is_coherent(struct drm_device *dev,
                                  enum i915_cache_level level)
@@ -204,7 +199,7 @@ i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
        pinned = 0;
        mutex_lock(&dev->struct_mutex);
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
-               if (obj->pin_count)
+               if (i915_gem_obj_is_pinned(obj))
                        pinned += i915_gem_obj_ggtt_size(obj);
        mutex_unlock(&dev->struct_mutex);
 
@@ -332,6 +327,42 @@ __copy_from_user_swizzled(char *gpu_vaddr, int gpu_offset,
        return 0;
 }
 
+/*
+ * Pins the specified object's pages and synchronizes the object with
+ * GPU accesses. Sets needs_clflush to non-zero if the caller should
+ * flush the object from the CPU cache.
+ */
+int i915_gem_obj_prepare_shmem_read(struct drm_i915_gem_object *obj,
+                                   int *needs_clflush)
+{
+       int ret;
+
+       *needs_clflush = 0;
+
+       if (!obj->base.filp)
+               return -EINVAL;
+
+       if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) {
+               /* If we're not in the cpu read domain, set ourself into the gtt
+                * read domain and manually flush cachelines (if required). This
+                * optimizes for the case when the gpu will dirty the data
+                * anyway again before the next pread happens. */
+               *needs_clflush = !cpu_cache_is_coherent(obj->base.dev,
+                                                       obj->cache_level);
+               ret = i915_gem_object_wait_rendering(obj, true);
+               if (ret)
+                       return ret;
+       }
+
+       ret = i915_gem_object_get_pages(obj);
+       if (ret)
+               return ret;
+
+       i915_gem_object_pin_pages(obj);
+
+       return ret;
+}
+
 /* Per-page copy function for the shmem pread fastpath.
  * Flushes invalid cachelines before reading the target if
  * needs_clflush is set. */
@@ -429,23 +460,10 @@ i915_gem_shmem_pread(struct drm_device *dev,
 
        obj_do_bit17_swizzling = i915_gem_object_needs_bit17_swizzle(obj);
 
-       if (!(obj->base.read_domains & I915_GEM_DOMAIN_CPU)) {
-               /* If we're not in the cpu read domain, set ourself into the gtt
-                * read domain and manually flush cachelines (if required). This
-                * optimizes for the case when the gpu will dirty the data
-                * anyway again before the next pread happens. */
-               needs_clflush = !cpu_cache_is_coherent(dev, obj->cache_level);
-               ret = i915_gem_object_wait_rendering(obj, true);
-               if (ret)
-                       return ret;
-       }
-
-       ret = i915_gem_object_get_pages(obj);
+       ret = i915_gem_obj_prepare_shmem_read(obj, &needs_clflush);
        if (ret)
                return ret;
 
-       i915_gem_object_pin_pages(obj);
-
        offset = args->offset;
 
        for_each_sg_page(obj->pages->sgl, &sg_iter, obj->pages->nents,
@@ -476,7 +494,7 @@ i915_gem_shmem_pread(struct drm_device *dev,
 
                mutex_unlock(&dev->struct_mutex);
 
-               if (likely(!i915_prefault_disable) && !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
@@ -492,12 +510,10 @@ i915_gem_shmem_pread(struct drm_device *dev,
 
                mutex_lock(&dev->struct_mutex);
 
-next_page:
-               mark_page_accessed(page);
-
                if (ret)
                        goto out;
 
+next_page:
                remain -= page_length;
                user_data += page_length;
                offset += page_length;
@@ -599,13 +615,13 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
                         struct drm_i915_gem_pwrite *args,
                         struct drm_file *file)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        ssize_t remain;
        loff_t offset, page_base;
        char __user *user_data;
        int page_offset, page_length, ret;
 
-       ret = i915_gem_obj_ggtt_pin(obj, 0, true, true);
+       ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_MAPPABLE | PIN_NONBLOCK);
        if (ret)
                goto out;
 
@@ -651,7 +667,7 @@ i915_gem_gtt_pwrite_fast(struct drm_device *dev,
        }
 
 out_unpin:
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
 out:
        return ret;
 }
@@ -677,9 +693,8 @@ shmem_pwrite_fast(struct page *page, int shmem_page_offset, int page_length,
        if (needs_clflush_before)
                drm_clflush_virt_range(vaddr + shmem_page_offset,
                                       page_length);
-       ret = __copy_from_user_inatomic_nocache(vaddr + shmem_page_offset,
-                                               user_data,
-                                               page_length);
+       ret = __copy_from_user_inatomic(vaddr + shmem_page_offset,
+                                       user_data, page_length);
        if (needs_clflush_after)
                drm_clflush_virt_range(vaddr + shmem_page_offset,
                                       page_length);
@@ -813,13 +828,10 @@ i915_gem_shmem_pwrite(struct drm_device *dev,
 
                mutex_lock(&dev->struct_mutex);
 
-next_page:
-               set_page_dirty(page);
-               mark_page_accessed(page);
-
                if (ret)
                        goto out;
 
+next_page:
                remain -= page_length;
                user_data += page_length;
                offset += page_length;
@@ -868,7 +880,7 @@ i915_gem_pwrite_ioctl(struct drm_device *dev, void *data,
                       args->size))
                return -EFAULT;
 
-       if (likely(!i915_prefault_disable)) {
+       if (likely(!i915.prefault_disable)) {
                ret = fault_in_multipages_readable(to_user_ptr(args->data_ptr),
                                                   args->size);
                if (ret)
@@ -1014,7 +1026,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
                        struct timespec *timeout,
                        struct drm_i915_file_private *file_priv)
 {
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        const bool irq_test_in_progress =
                ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring);
        struct timespec before, now;
@@ -1022,14 +1035,14 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
        unsigned long timeout_expire;
        int ret;
 
-       WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n");
+       WARN(dev_priv->pm.irqs_disabled, "IRQs disabled\n");
 
        if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
                return 0;
 
        timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0;
 
-       if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) {
+       if (INTEL_INFO(dev)->gen >= 6 && can_wait_boost(file_priv)) {
                gen6_rps_boost(dev_priv);
                if (file_priv)
                        mod_delayed_work(dev_priv->wq,
@@ -1184,7 +1197,7 @@ i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
  */
 static __must_check int
 i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj,
-                                           struct drm_file *file,
+                                           struct drm_i915_file_private *file_priv,
                                            bool readonly)
 {
        struct drm_device *dev = obj->base.dev;
@@ -1211,7 +1224,7 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj,
 
        reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
        mutex_unlock(&dev->struct_mutex);
-       ret = __wait_seqno(ring, seqno, reset_counter, true, NULL, file->driver_priv);
+       ret = __wait_seqno(ring, seqno, reset_counter, true, NULL, file_priv);
        mutex_lock(&dev->struct_mutex);
        if (ret)
                return ret;
@@ -1260,7 +1273,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
         * We will repeat the flush holding the lock in the normal manner
         * to catch cases where we are gazumped.
         */
-       ret = i915_gem_object_wait_rendering__nonblocking(obj, file, !write_domain);
+       ret = i915_gem_object_wait_rendering__nonblocking(obj,
+                                                         file->driver_priv,
+                                                         !write_domain);
        if (ret)
                goto unref;
 
@@ -1374,7 +1389,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct drm_i915_gem_object *obj = to_intel_bo(vma->vm_private_data);
        struct drm_device *dev = obj->base.dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        pgoff_t page_offset;
        unsigned long pfn;
        int ret = 0;
@@ -1392,6 +1407,15 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 
        trace_i915_gem_object_fault(obj, page_offset, true, write);
 
+       /* Try to flush the object off the GPU first without holding the lock.
+        * Upon reacquiring the lock, we will perform our sanity checks and then
+        * repeat the flush holding the lock in the normal manner to catch cases
+        * where we are gazumped.
+        */
+       ret = i915_gem_object_wait_rendering__nonblocking(obj, NULL, !write);
+       if (ret)
+               goto unlock;
+
        /* Access to snoopable pages through the GTT is incoherent. */
        if (obj->cache_level != I915_CACHE_NONE && !HAS_LLC(dev)) {
                ret = -EINVAL;
@@ -1399,7 +1423,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        }
 
        /* Now bind it into the GTT if needed */
-       ret = i915_gem_obj_ggtt_pin(obj,  0, true, false);
+       ret = i915_gem_obj_ggtt_pin(obj, 0, PIN_MAPPABLE);
        if (ret)
                goto unlock;
 
@@ -1420,7 +1444,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        /* Finally, remap it using the new GTT offset */
        ret = vm_insert_pfn(vma, (unsigned long)vmf->virtual_address, pfn);
 unpin:
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
 unlock:
        mutex_unlock(&dev->struct_mutex);
 out:
@@ -1453,6 +1477,7 @@ out:
                ret = VM_FAULT_OOM;
                break;
        case -ENOSPC:
+       case -EFAULT:
                ret = VM_FAULT_SIGBUS;
                break;
        default:
@@ -1501,7 +1526,8 @@ i915_gem_release_mmap(struct drm_i915_gem_object *obj)
        if (!obj->fault_mappable)
                return;
 
-       drm_vma_node_unmap(&obj->base.vma_node, obj->base.dev->dev_mapping);
+       drm_vma_node_unmap(&obj->base.vma_node,
+                          obj->base.dev->anon_inode->i_mapping);
        obj->fault_mappable = false;
 }
 
@@ -1617,8 +1643,8 @@ i915_gem_mmap_gtt(struct drm_file *file,
        }
 
        if (obj->madv != I915_MADV_WILLNEED) {
-               DRM_ERROR("Attempting to mmap a purgeable buffer\n");
-               ret = -EINVAL;
+               DRM_DEBUG("Attempting to mmap a purgeable buffer\n");
+               ret = -EFAULT;
                goto out;
        }
 
@@ -1971,8 +1997,8 @@ i915_gem_object_get_pages(struct drm_i915_gem_object *obj)
                return 0;
 
        if (obj->madv != I915_MADV_WILLNEED) {
-               DRM_ERROR("Attempting to obtain a purgeable object\n");
-               return -EINVAL;
+               DRM_DEBUG("Attempting to obtain a purgeable object\n");
+               return -EFAULT;
        }
 
        BUG_ON(obj->pages_pin_count);
@@ -2035,13 +2061,17 @@ static void
 i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
 {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-       struct i915_address_space *ggtt_vm = &dev_priv->gtt.base;
-       struct i915_vma *vma = i915_gem_obj_to_vma(obj, ggtt_vm);
+       struct i915_address_space *vm;
+       struct i915_vma *vma;
 
        BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
        BUG_ON(!obj->active);
 
-       list_move_tail(&vma->mm_list, &ggtt_vm->inactive_list);
+       list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
+               vma = i915_gem_obj_to_vma(obj, vm);
+               if (vma && !list_empty(&vma->mm_list))
+                       list_move_tail(&vma->mm_list, &vm->inactive_list);
+       }
 
        list_del_init(&obj->ring_list);
        obj->ring = NULL;
@@ -2134,10 +2164,9 @@ int __i915_add_request(struct intel_ring_buffer *ring,
                       struct drm_i915_gem_object *obj,
                       u32 *out_seqno)
 {
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct drm_i915_gem_request *request;
        u32 request_ring_position, request_start;
-       int was_empty;
        int ret;
 
        request_start = intel_ring_get_tail(ring);
@@ -2188,7 +2217,6 @@ int __i915_add_request(struct intel_ring_buffer *ring,
                i915_gem_context_reference(request->ctx);
 
        request->emitted_jiffies = jiffies;
-       was_empty = list_empty(&ring->request_list);
        list_add_tail(&request->list, &ring->request_list);
        request->file_priv = NULL;
 
@@ -2209,13 +2237,11 @@ int __i915_add_request(struct intel_ring_buffer *ring,
        if (!dev_priv->ums.mm_suspended) {
                i915_queue_hangcheck(ring->dev);
 
-               if (was_empty) {
-                       cancel_delayed_work_sync(&dev_priv->mm.idle_work);
-                       queue_delayed_work(dev_priv->wq,
-                                          &dev_priv->mm.retire_work,
-                                          round_jiffies_up_relative(HZ));
-                       intel_mark_busy(dev_priv->dev);
-               }
+               cancel_delayed_work_sync(&dev_priv->mm.idle_work);
+               queue_delayed_work(dev_priv->wq,
+                                  &dev_priv->mm.retire_work,
+                                  round_jiffies_up_relative(HZ));
+               intel_mark_busy(dev_priv->dev);
        }
 
        if (out_seqno)
@@ -2237,125 +2263,46 @@ i915_gem_request_remove_from_client(struct drm_i915_gem_request *request)
        spin_unlock(&file_priv->mm.lock);
 }
 
-static bool i915_head_inside_object(u32 acthd, struct drm_i915_gem_object *obj,
-                                   struct i915_address_space *vm)
+static bool i915_context_is_banned(struct drm_i915_private *dev_priv,
+                                  const struct i915_hw_context *ctx)
 {
-       if (acthd >= i915_gem_obj_offset(obj, vm) &&
-           acthd < i915_gem_obj_offset(obj, vm) + obj->base.size)
-               return true;
+       unsigned long elapsed;
 
-       return false;
-}
+       elapsed = get_seconds() - ctx->hang_stats.guilty_ts;
 
-static bool i915_head_inside_request(const u32 acthd_unmasked,
-                                    const u32 request_start,
-                                    const u32 request_end)
-{
-       const u32 acthd = acthd_unmasked & HEAD_ADDR;
+       if (ctx->hang_stats.banned)
+               return true;
 
-       if (request_start < request_end) {
-               if (acthd >= request_start && acthd < request_end)
-                       return true;
-       } else if (request_start > request_end) {
-               if (acthd >= request_start || acthd < request_end)
+       if (elapsed <= DRM_I915_CTX_BAN_PERIOD) {
+               if (!i915_gem_context_is_default(ctx)) {
+                       DRM_DEBUG("context hanging too fast, banning!\n");
                        return true;
-       }
-
-       return false;
-}
-
-static struct i915_address_space *
-request_to_vm(struct drm_i915_gem_request *request)
-{
-       struct drm_i915_private *dev_priv = request->ring->dev->dev_private;
-       struct i915_address_space *vm;
-
-       vm = &dev_priv->gtt.base;
-
-       return vm;
-}
-
-static bool i915_request_guilty(struct drm_i915_gem_request *request,
-                               const u32 acthd, bool *inside)
-{
-       /* There is a possibility that unmasked head address
-        * pointing inside the ring, matches the batch_obj address range.
-        * However this is extremely unlikely.
-        */
-       if (request->batch_obj) {
-               if (i915_head_inside_object(acthd, request->batch_obj,
-                                           request_to_vm(request))) {
-                       *inside = true;
+               } else if (dev_priv->gpu_error.stop_rings == 0) {
+                       DRM_ERROR("gpu hanging too fast, banning!\n");
                        return true;
                }
        }
 
-       if (i915_head_inside_request(acthd, request->head, request->tail)) {
-               *inside = false;
-               return true;
-       }
-
        return false;
 }
 
-static bool i915_context_is_banned(const struct i915_ctx_hang_stats *hs)
+static void i915_set_reset_status(struct drm_i915_private *dev_priv,
+                                 struct i915_hw_context *ctx,
+                                 const bool guilty)
 {
-       const unsigned long elapsed = get_seconds() - hs->guilty_ts;
-
-       if (hs->banned)
-               return true;
-
-       if (elapsed <= DRM_I915_CTX_BAN_PERIOD) {
-               DRM_ERROR("context hanging too fast, declaring banned!\n");
-               return true;
-       }
-
-       return false;
-}
+       struct i915_ctx_hang_stats *hs;
 
-static void i915_set_reset_status(struct intel_ring_buffer *ring,
-                                 struct drm_i915_gem_request *request,
-                                 u32 acthd)
-{
-       struct i915_ctx_hang_stats *hs = NULL;
-       bool inside, guilty;
-       unsigned long offset = 0;
-
-       /* Innocent until proven guilty */
-       guilty = false;
-
-       if (request->batch_obj)
-               offset = i915_gem_obj_offset(request->batch_obj,
-                                            request_to_vm(request));
+       if (WARN_ON(!ctx))
+               return;
 
-       if (ring->hangcheck.action != HANGCHECK_WAIT &&
-           i915_request_guilty(request, acthd, &inside)) {
-               DRM_DEBUG("%s hung %s bo (0x%lx ctx %d) at 0x%x\n",
-                         ring->name,
-                         inside ? "inside" : "flushing",
-                         offset,
-                         request->ctx ? request->ctx->id : 0,
-                         acthd);
+       hs = &ctx->hang_stats;
 
-               guilty = true;
-       }
-
-       /* If contexts are disabled or this is the default context, use
-        * file_priv->reset_state
-        */
-       if (request->ctx && request->ctx->id != DEFAULT_CONTEXT_ID)
-               hs = &request->ctx->hang_stats;
-       else if (request->file_priv)
-               hs = &request->file_priv->hang_stats;
-
-       if (hs) {
-               if (guilty) {
-                       hs->banned = i915_context_is_banned(hs);
-                       hs->batch_active++;
-                       hs->guilty_ts = get_seconds();
-               } else {
-                       hs->batch_pending++;
-               }
+       if (guilty) {
+               hs->banned = i915_context_is_banned(dev_priv, ctx);
+               hs->batch_active++;
+               hs->guilty_ts = get_seconds();
+       } else {
+               hs->batch_pending++;
        }
 }
 
@@ -2370,19 +2317,41 @@ static void i915_gem_free_request(struct drm_i915_gem_request *request)
        kfree(request);
 }
 
-static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
-                                      struct intel_ring_buffer *ring)
+struct drm_i915_gem_request *
+i915_gem_find_active_request(struct intel_ring_buffer *ring)
 {
-       u32 completed_seqno = ring->get_seqno(ring, false);
-       u32 acthd = intel_ring_get_active_head(ring);
        struct drm_i915_gem_request *request;
+       u32 completed_seqno;
+
+       completed_seqno = ring->get_seqno(ring, false);
 
        list_for_each_entry(request, &ring->request_list, list) {
                if (i915_seqno_passed(completed_seqno, request->seqno))
                        continue;
 
-               i915_set_reset_status(ring, request, acthd);
+               return request;
        }
+
+       return NULL;
+}
+
+static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
+                                      struct intel_ring_buffer *ring)
+{
+       struct drm_i915_gem_request *request;
+       bool ring_hung;
+
+       request = i915_gem_find_active_request(ring);
+
+       if (request == NULL)
+               return;
+
+       ring_hung = ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG;
+
+       i915_set_reset_status(dev_priv, request->ctx, ring_hung);
+
+       list_for_each_entry_continue(request, &ring->request_list, list)
+               i915_set_reset_status(dev_priv, request->ctx, false);
 }
 
 static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
@@ -2456,13 +2425,15 @@ void i915_gem_reset(struct drm_device *dev)
 
        i915_gem_cleanup_ringbuffer(dev);
 
+       i915_gem_context_reset(dev);
+
        i915_gem_restore_fences(dev);
 }
 
 /**
  * This function clears the request list as sequence numbers are passed.
  */
-void
+static void
 i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
 {
        uint32_t seqno;
@@ -2474,6 +2445,24 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
 
        seqno = ring->get_seqno(ring, true);
 
+       /* Move any buffers on the active list that are no longer referenced
+        * by the ringbuffer to the flushing/inactive lists as appropriate,
+        * before we free the context associated with the requests.
+        */
+       while (!list_empty(&ring->active_list)) {
+               struct drm_i915_gem_object *obj;
+
+               obj = list_first_entry(&ring->active_list,
+                                     struct drm_i915_gem_object,
+                                     ring_list);
+
+               if (!i915_seqno_passed(seqno, obj->last_read_seqno))
+                       break;
+
+               i915_gem_object_move_to_inactive(obj);
+       }
+
+
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
 
@@ -2495,22 +2484,6 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
                i915_gem_free_request(request);
        }
 
-       /* Move any buffers on the active list that are no longer referenced
-        * by the ringbuffer to the flushing/inactive lists as appropriate.
-        */
-       while (!list_empty(&ring->active_list)) {
-               struct drm_i915_gem_object *obj;
-
-               obj = list_first_entry(&ring->active_list,
-                                     struct drm_i915_gem_object,
-                                     ring_list);
-
-               if (!i915_seqno_passed(seqno, obj->last_read_seqno))
-                       break;
-
-               i915_gem_object_move_to_inactive(obj);
-       }
-
        if (unlikely(ring->trace_irq_seqno &&
                     i915_seqno_passed(seqno, ring->trace_irq_seqno))) {
                ring->irq_put(ring);
@@ -2523,7 +2496,7 @@ i915_gem_retire_requests_ring(struct intel_ring_buffer *ring)
 bool
 i915_gem_retire_requests(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
        bool idle = true;
        int i;
@@ -2615,7 +2588,7 @@ i915_gem_object_flush_active(struct drm_i915_gem_object *obj)
 int
 i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_wait *args = data;
        struct drm_i915_gem_object *obj;
        struct intel_ring_buffer *ring = NULL;
@@ -2750,22 +2723,18 @@ static void i915_gem_object_finish_gtt(struct drm_i915_gem_object *obj)
 int i915_vma_unbind(struct i915_vma *vma)
 {
        struct drm_i915_gem_object *obj = vma->obj;
-       drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
        int ret;
 
-       /* For now we only ever use 1 vma per object */
-       WARN_ON(!list_is_singular(&obj->vma_list));
-
        if (list_empty(&vma->vma_link))
                return 0;
 
        if (!drm_mm_node_allocated(&vma->node)) {
                i915_gem_vma_destroy(vma);
-
                return 0;
        }
 
-       if (obj->pin_count)
+       if (vma->pin_count)
                return -EBUSY;
 
        BUG_ON(obj->pages == NULL);
@@ -2787,15 +2756,11 @@ int i915_vma_unbind(struct i915_vma *vma)
 
        trace_i915_vma_unbind(vma);
 
-       if (obj->has_global_gtt_mapping)
-               i915_gem_gtt_unbind_object(obj);
-       if (obj->has_aliasing_ppgtt_mapping) {
-               i915_ppgtt_unbind_object(dev_priv->mm.aliasing_ppgtt, obj);
-               obj->has_aliasing_ppgtt_mapping = 0;
-       }
+       vma->unbind_vma(vma);
+
        i915_gem_gtt_finish_object(obj);
 
-       list_del(&vma->mm_list);
+       list_del_init(&vma->mm_list);
        /* Avoid an unnecessary call to unbind on rebind. */
        if (i915_is_ggtt(vma->vm))
                obj->map_and_fenceable = true;
@@ -2817,35 +2782,15 @@ int i915_vma_unbind(struct i915_vma *vma)
        return 0;
 }
 
-/**
- * Unbinds an object from the global GTT aperture.
- */
-int
-i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj)
-{
-       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-       struct i915_address_space *ggtt = &dev_priv->gtt.base;
-
-       if (!i915_gem_obj_ggtt_bound(obj))
-               return 0;
-
-       if (obj->pin_count)
-               return -EBUSY;
-
-       BUG_ON(obj->pages == NULL);
-
-       return i915_vma_unbind(i915_gem_obj_to_vma(obj, ggtt));
-}
-
 int i915_gpu_idle(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
        int ret, i;
 
        /* Flush everything onto the inactive list. */
        for_each_ring(ring, dev_priv, i) {
-               ret = i915_switch_context(ring, NULL, DEFAULT_CONTEXT_ID);
+               ret = i915_switch_context(ring, NULL, ring->default_context);
                if (ret)
                        return ret;
 
@@ -2860,7 +2805,7 @@ int i915_gpu_idle(struct drm_device *dev)
 static void i965_write_fence_reg(struct drm_device *dev, int reg,
                                 struct drm_i915_gem_object *obj)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int fence_reg;
        int fence_pitch_shift;
 
@@ -2912,7 +2857,7 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
 static void i915_write_fence_reg(struct drm_device *dev, int reg,
                                 struct drm_i915_gem_object *obj)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val;
 
        if (obj) {
@@ -2956,7 +2901,7 @@ static void i915_write_fence_reg(struct drm_device *dev, int reg,
 static void i830_write_fence_reg(struct drm_device *dev, int reg,
                                struct drm_i915_gem_object *obj)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t val;
 
        if (obj) {
@@ -3259,18 +3204,17 @@ static void i915_gem_verify_gtt(struct drm_device *dev)
 /**
  * Finds free space in the GTT aperture and binds the object there.
  */
-static int
+static struct i915_vma *
 i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
                           struct i915_address_space *vm,
                           unsigned alignment,
-                          bool map_and_fenceable,
-                          bool nonblocking)
+                          unsigned flags)
 {
        struct drm_device *dev = obj->base.dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 size, fence_size, fence_alignment, unfenced_alignment;
        size_t gtt_max =
-               map_and_fenceable ? dev_priv->gtt.mappable_end : vm->total;
+               flags & PIN_MAPPABLE ? dev_priv->gtt.mappable_end : vm->total;
        struct i915_vma *vma;
        int ret;
 
@@ -3282,57 +3226,49 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
                                                     obj->tiling_mode, true);
        unfenced_alignment =
                i915_gem_get_gtt_alignment(dev,
-                                                   obj->base.size,
-                                                   obj->tiling_mode, false);
+                                          obj->base.size,
+                                          obj->tiling_mode, false);
 
        if (alignment == 0)
-               alignment = map_and_fenceable ? fence_alignment :
+               alignment = flags & PIN_MAPPABLE ? fence_alignment :
                                                unfenced_alignment;
-       if (map_and_fenceable && alignment & (fence_alignment - 1)) {
-               DRM_ERROR("Invalid object alignment requested %u\n", alignment);
-               return -EINVAL;
+       if (flags & PIN_MAPPABLE && alignment & (fence_alignment - 1)) {
+               DRM_DEBUG("Invalid object alignment requested %u\n", alignment);
+               return ERR_PTR(-EINVAL);
        }
 
-       size = map_and_fenceable ? fence_size : obj->base.size;
+       size = flags & PIN_MAPPABLE ? fence_size : obj->base.size;
 
        /* If the object is bigger than the entire aperture, reject it early
         * before evicting everything in a vain attempt to find space.
         */
        if (obj->base.size > gtt_max) {
-               DRM_ERROR("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n",
+               DRM_DEBUG("Attempting to bind an object larger than the aperture: object=%zd > %s aperture=%zu\n",
                          obj->base.size,
-                         map_and_fenceable ? "mappable" : "total",
+                         flags & PIN_MAPPABLE ? "mappable" : "total",
                          gtt_max);
-               return -E2BIG;
+               return ERR_PTR(-E2BIG);
        }
 
        ret = i915_gem_object_get_pages(obj);
        if (ret)
-               return ret;
+               return ERR_PTR(ret);
 
        i915_gem_object_pin_pages(obj);
 
-       BUG_ON(!i915_is_ggtt(vm));
-
        vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
-       if (IS_ERR(vma)) {
-               ret = PTR_ERR(vma);
+       if (IS_ERR(vma))
                goto err_unpin;
-       }
-
-       /* For now we only ever use 1 vma per object */
-       WARN_ON(!list_is_singular(&obj->vma_list));
 
 search_free:
        ret = drm_mm_insert_node_in_range_generic(&vm->mm, &vma->node,
                                                  size, alignment,
                                                  obj->cache_level, 0, gtt_max,
-                                                 DRM_MM_SEARCH_DEFAULT);
+                                                 DRM_MM_SEARCH_DEFAULT,
+                                                 DRM_MM_CREATE_DEFAULT);
        if (ret) {
                ret = i915_gem_evict_something(dev, vm, size, alignment,
-                                              obj->cache_level,
-                                              map_and_fenceable,
-                                              nonblocking);
+                                              obj->cache_level, flags);
                if (ret == 0)
                        goto search_free;
 
@@ -3363,19 +3299,23 @@ search_free:
                obj->map_and_fenceable = mappable && fenceable;
        }
 
-       WARN_ON(map_and_fenceable && !obj->map_and_fenceable);
+       WARN_ON(flags & PIN_MAPPABLE && !obj->map_and_fenceable);
+
+       trace_i915_vma_bind(vma, flags);
+       vma->bind_vma(vma, obj->cache_level,
+                     flags & (PIN_MAPPABLE | PIN_GLOBAL) ? GLOBAL_BIND : 0);
 
-       trace_i915_vma_bind(vma, map_and_fenceable);
        i915_gem_verify_gtt(dev);
-       return 0;
+       return vma;
 
 err_remove_node:
        drm_mm_remove_node(&vma->node);
 err_free_vma:
        i915_gem_vma_destroy(vma);
+       vma = ERR_PTR(ret);
 err_unpin:
        i915_gem_object_unpin_pages(obj);
-       return ret;
+       return vma;
 }
 
 bool
@@ -3470,7 +3410,7 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj,
 int
 i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 {
-       drm_i915_private_t *dev_priv = obj->base.dev->dev_private;
+       struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
        uint32_t old_write_domain, old_read_domains;
        int ret;
 
@@ -3528,25 +3468,22 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
                                    enum i915_cache_level cache_level)
 {
        struct drm_device *dev = obj->base.dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       struct i915_vma *vma;
+       struct i915_vma *vma, *next;
        int ret;
 
        if (obj->cache_level == cache_level)
                return 0;
 
-       if (obj->pin_count) {
+       if (i915_gem_obj_is_pinned(obj)) {
                DRM_DEBUG("can not change the cache level of pinned objects\n");
                return -EBUSY;
        }
 
-       list_for_each_entry(vma, &obj->vma_list, vma_link) {
+       list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) {
                if (!i915_gem_valid_gtt_space(dev, &vma->node, cache_level)) {
                        ret = i915_vma_unbind(vma);
                        if (ret)
                                return ret;
-
-                       break;
                }
        }
 
@@ -3567,11 +3504,10 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
                                return ret;
                }
 
-               if (obj->has_global_gtt_mapping)
-                       i915_gem_gtt_bind_object(obj, cache_level);
-               if (obj->has_aliasing_ppgtt_mapping)
-                       i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
-                                              obj, cache_level);
+               list_for_each_entry(vma, &obj->vma_list, vma_link)
+                       if (drm_mm_node_allocated(&vma->node))
+                               vma->bind_vma(vma, cache_level,
+                                             obj->has_global_gtt_mapping ? GLOBAL_BIND : 0);
        }
 
        list_for_each_entry(vma, &obj->vma_list, vma_link)
@@ -3695,7 +3631,7 @@ static bool is_pin_display(struct drm_i915_gem_object *obj)
         * subtracting the potential reference by the user, any pin_count
         * remains, it must be due to another use by the display engine.
         */
-       return obj->pin_count - !!obj->user_pin_count;
+       return i915_gem_obj_to_ggtt(obj)->pin_count - !!obj->user_pin_count;
 }
 
 /*
@@ -3740,7 +3676,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
         * (e.g. libkms for the bootup splash), we have to ensure that we
         * always use map_and_fenceable for all scanout buffers.
         */
-       ret = i915_gem_obj_ggtt_pin(obj, alignment, true, false);
+       ret = i915_gem_obj_ggtt_pin(obj, alignment, PIN_MAPPABLE);
        if (ret)
                goto err_unpin_display;
 
@@ -3769,7 +3705,7 @@ err_unpin_display:
 void
 i915_gem_object_unpin_from_display_plane(struct drm_i915_gem_object *obj)
 {
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
        obj->pin_display = is_pin_display(obj);
 }
 
@@ -3896,65 +3832,63 @@ int
 i915_gem_object_pin(struct drm_i915_gem_object *obj,
                    struct i915_address_space *vm,
                    uint32_t alignment,
-                   bool map_and_fenceable,
-                   bool nonblocking)
+                   unsigned flags)
 {
        struct i915_vma *vma;
        int ret;
 
-       if (WARN_ON(obj->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
-               return -EBUSY;
-
-       WARN_ON(map_and_fenceable && !i915_is_ggtt(vm));
+       if (WARN_ON(flags & (PIN_GLOBAL | PIN_MAPPABLE) && !i915_is_ggtt(vm)))
+               return -EINVAL;
 
        vma = i915_gem_obj_to_vma(obj, vm);
-
        if (vma) {
+               if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
+                       return -EBUSY;
+
                if ((alignment &&
                     vma->node.start & (alignment - 1)) ||
-                   (map_and_fenceable && !obj->map_and_fenceable)) {
-                       WARN(obj->pin_count,
+                   (flags & PIN_MAPPABLE && !obj->map_and_fenceable)) {
+                       WARN(vma->pin_count,
                             "bo is already pinned with incorrect alignment:"
                             " offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
                             " obj->map_and_fenceable=%d\n",
                             i915_gem_obj_offset(obj, vm), alignment,
-                            map_and_fenceable,
+                            flags & PIN_MAPPABLE,
                             obj->map_and_fenceable);
                        ret = i915_vma_unbind(vma);
                        if (ret)
                                return ret;
+
+                       vma = NULL;
                }
        }
 
-       if (!i915_gem_obj_bound(obj, vm)) {
-               struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
-
-               ret = i915_gem_object_bind_to_vm(obj, vm, alignment,
-                                                map_and_fenceable,
-                                                nonblocking);
-               if (ret)
-                       return ret;
-
-               if (!dev_priv->mm.aliasing_ppgtt)
-                       i915_gem_gtt_bind_object(obj, obj->cache_level);
+       if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
+               vma = i915_gem_object_bind_to_vm(obj, vm, alignment, flags);
+               if (IS_ERR(vma))
+                       return PTR_ERR(vma);
        }
 
-       if (!obj->has_global_gtt_mapping && map_and_fenceable)
-               i915_gem_gtt_bind_object(obj, obj->cache_level);
+       if (flags & PIN_GLOBAL && !obj->has_global_gtt_mapping)
+               vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
 
-       obj->pin_count++;
-       obj->pin_mappable |= map_and_fenceable;
+       vma->pin_count++;
+       if (flags & PIN_MAPPABLE)
+               obj->pin_mappable |= true;
 
        return 0;
 }
 
 void
-i915_gem_object_unpin(struct drm_i915_gem_object *obj)
+i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj)
 {
-       BUG_ON(obj->pin_count == 0);
-       BUG_ON(!i915_gem_obj_bound_any(obj));
+       struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
 
-       if (--obj->pin_count == 0)
+       BUG_ON(!vma);
+       BUG_ON(vma->pin_count == 0);
+       BUG_ON(!i915_gem_obj_ggtt_bound(obj));
+
+       if (--vma->pin_count == 0)
                obj->pin_mappable = false;
 }
 
@@ -3966,6 +3900,9 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
        struct drm_i915_gem_object *obj;
        int ret;
 
+       if (INTEL_INFO(dev)->gen >= 6)
+               return -ENODEV;
+
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                return ret;
@@ -3977,13 +3914,13 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
        }
 
        if (obj->madv != I915_MADV_WILLNEED) {
-               DRM_ERROR("Attempting to pin a purgeable buffer\n");
-               ret = -EINVAL;
+               DRM_DEBUG("Attempting to pin a purgeable buffer\n");
+               ret = -EFAULT;
                goto out;
        }
 
        if (obj->pin_filp != NULL && obj->pin_filp != file) {
-               DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n",
+               DRM_DEBUG("Already pinned in i915_gem_pin_ioctl(): %d\n",
                          args->handle);
                ret = -EINVAL;
                goto out;
@@ -3995,7 +3932,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
        }
 
        if (obj->user_pin_count == 0) {
-               ret = i915_gem_obj_ggtt_pin(obj, args->alignment, true, false);
+               ret = i915_gem_obj_ggtt_pin(obj, args->alignment, PIN_MAPPABLE);
                if (ret)
                        goto out;
        }
@@ -4030,7 +3967,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
        }
 
        if (obj->pin_filp != file) {
-               DRM_ERROR("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
+               DRM_DEBUG("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
                          args->handle);
                ret = -EINVAL;
                goto out;
@@ -4038,7 +3975,7 @@ i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
        obj->user_pin_count--;
        if (obj->user_pin_count == 0) {
                obj->pin_filp = NULL;
-               i915_gem_object_unpin(obj);
+               i915_gem_object_ggtt_unpin(obj);
        }
 
 out:
@@ -4118,7 +4055,7 @@ i915_gem_madvise_ioctl(struct drm_device *dev, void *data,
                goto unlock;
        }
 
-       if (obj->pin_count) {
+       if (i915_gem_obj_is_pinned(obj)) {
                ret = -EINVAL;
                goto out;
        }
@@ -4219,7 +4156,7 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
 {
        struct drm_i915_gem_object *obj = to_intel_bo(gem_obj);
        struct drm_device *dev = obj->base.dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_vma *vma, *next;
 
        intel_runtime_pm_get(dev_priv);
@@ -4229,12 +4166,11 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
        if (obj->phys_obj)
                i915_gem_detach_phys_object(dev, obj);
 
-       obj->pin_count = 0;
-       /* NB: 0 or 1 elements */
-       WARN_ON(!list_empty(&obj->vma_list) &&
-               !list_is_singular(&obj->vma_list));
        list_for_each_entry_safe(vma, next, &obj->vma_list, vma_link) {
-               int ret = i915_vma_unbind(vma);
+               int ret;
+
+               vma->pin_count = 0;
+               ret = i915_vma_unbind(vma);
                if (WARN_ON(ret == -ERESTARTSYS)) {
                        bool was_interruptible;
 
@@ -4283,41 +4219,6 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
        return NULL;
 }
 
-static 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);
-       INIT_LIST_HEAD(&vma->mm_list);
-       INIT_LIST_HEAD(&vma->exec_list);
-       vma->vm = vm;
-       vma->obj = obj;
-
-       /* Keep GGTT vmas first to make debug easier */
-       if (i915_is_ggtt(vm))
-               list_add(&vma->vma_link, &obj->vma_list);
-       else
-               list_add_tail(&vma->vma_link, &obj->vma_list);
-
-       return vma;
-}
-
-struct i915_vma *
-i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
-                                 struct i915_address_space *vm)
-{
-       struct i915_vma *vma;
-
-       vma = i915_gem_obj_to_vma(obj, vm);
-       if (!vma)
-               vma = __i915_gem_vma_create(obj, vm);
-
-       return vma;
-}
-
 void i915_gem_vma_destroy(struct i915_vma *vma)
 {
        WARN_ON(vma->node.allocated);
@@ -4334,7 +4235,7 @@ void i915_gem_vma_destroy(struct i915_vma *vma)
 int
 i915_gem_suspend(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret = 0;
 
        mutex_lock(&dev->struct_mutex);
@@ -4376,7 +4277,7 @@ err:
 int i915_gem_l3_remap(struct intel_ring_buffer *ring, int slice)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 reg_base = GEN7_L3LOG_BASE + (slice * 0x200);
        u32 *remap_info = dev_priv->l3_parity.remap_info[slice];
        int i, ret;
@@ -4406,7 +4307,7 @@ int i915_gem_l3_remap(struct intel_ring_buffer *ring, int slice)
 
 void i915_gem_init_swizzling(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (INTEL_INFO(dev)->gen < 5 ||
            dev_priv->mm.bit_6_swizzle_x == I915_BIT_6_SWIZZLE_NONE)
@@ -4494,7 +4395,7 @@ cleanup_render_ring:
 int
 i915_gem_init_hw(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret, i;
 
        if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
@@ -4508,9 +4409,15 @@ i915_gem_init_hw(struct drm_device *dev)
                           LOWER_SLICE_ENABLED : LOWER_SLICE_DISABLED);
 
        if (HAS_PCH_NOP(dev)) {
-               u32 temp = I915_READ(GEN7_MSG_CTL);
-               temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK);
-               I915_WRITE(GEN7_MSG_CTL, temp);
+               if (IS_IVYBRIDGE(dev)) {
+                       u32 temp = I915_READ(GEN7_MSG_CTL);
+                       temp &= ~(WAIT_FOR_PCH_FLR_ACK | WAIT_FOR_PCH_RESET_ACK);
+                       I915_WRITE(GEN7_MSG_CTL, temp);
+               } else if (INTEL_INFO(dev)->gen >= 7) {
+                       u32 temp = I915_READ(HSW_NDE_RSTWRN_OPT);
+                       temp &= ~RESET_PCH_HANDSHAKE_ENABLE;
+                       I915_WRITE(HSW_NDE_RSTWRN_OPT, temp);
+               }
        }
 
        i915_gem_init_swizzling(dev);
@@ -4523,25 +4430,23 @@ i915_gem_init_hw(struct drm_device *dev)
                i915_gem_l3_remap(&dev_priv->ring[RCS], i);
 
        /*
-        * XXX: There was some w/a described somewhere suggesting loading
-        * contexts before PPGTT.
+        * XXX: Contexts should only be initialized once. Doing a switch to the
+        * default context switch however is something we'd like to do after
+        * reset or thaw (the latter may not actually be necessary for HW, but
+        * goes with our code better). Context switching requires rings (for
+        * the do_switch), but before enabling PPGTT. So don't move this.
         */
-       ret = i915_gem_context_init(dev);
+       ret = i915_gem_context_enable(dev_priv);
        if (ret) {
-               i915_gem_cleanup_ringbuffer(dev);
-               DRM_ERROR("Context initialization failed %d\n", ret);
-               return ret;
-       }
-
-       if (dev_priv->mm.aliasing_ppgtt) {
-               ret = dev_priv->mm.aliasing_ppgtt->enable(dev);
-               if (ret) {
-                       i915_gem_cleanup_aliasing_ppgtt(dev);
-                       DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n");
-               }
+               DRM_ERROR("Context enable failed %d\n", ret);
+               goto err_out;
        }
 
        return 0;
+
+err_out:
+       i915_gem_cleanup_ringbuffer(dev);
+       return ret;
 }
 
 int i915_gem_init(struct drm_device *dev)
@@ -4560,10 +4465,18 @@ int i915_gem_init(struct drm_device *dev)
 
        i915_gem_init_global_gtt(dev);
 
+       ret = i915_gem_context_init(dev);
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
        ret = i915_gem_init_hw(dev);
        mutex_unlock(&dev->struct_mutex);
        if (ret) {
-               i915_gem_cleanup_aliasing_ppgtt(dev);
+               WARN_ON(dev_priv->mm.aliasing_ppgtt);
+               i915_gem_context_fini(dev);
+               drm_mm_takedown(&dev_priv->gtt.base.mm);
                return ret;
        }
 
@@ -4576,7 +4489,7 @@ int i915_gem_init(struct drm_device *dev)
 void
 i915_gem_cleanup_ringbuffer(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
        int i;
 
@@ -4658,20 +4571,22 @@ init_ring_lists(struct intel_ring_buffer *ring)
        INIT_LIST_HEAD(&ring->request_list);
 }
 
-static void i915_init_vm(struct drm_i915_private *dev_priv,
-                        struct i915_address_space *vm)
+void i915_init_vm(struct drm_i915_private *dev_priv,
+                 struct i915_address_space *vm)
 {
+       if (!i915_is_ggtt(vm))
+               drm_mm_init(&vm->mm, vm->start, vm->total);
        vm->dev = dev_priv->dev;
        INIT_LIST_HEAD(&vm->active_list);
        INIT_LIST_HEAD(&vm->inactive_list);
        INIT_LIST_HEAD(&vm->global_link);
-       list_add(&vm->global_link, &dev_priv->vm_list);
+       list_add_tail(&vm->global_link, &dev_priv->vm_list);
 }
 
 void
 i915_gem_load(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
        dev_priv->slab =
@@ -4738,7 +4653,7 @@ i915_gem_load(struct drm_device *dev)
 static int i915_gem_init_phys_object(struct drm_device *dev,
                                     int id, int size, int align)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_phys_object *phys_obj;
        int ret;
 
@@ -4770,7 +4685,7 @@ kfree_obj:
 
 static void i915_gem_free_phys_object(struct drm_device *dev, int id)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_phys_object *phys_obj;
 
        if (!dev_priv->mm.phys_objs[id - 1])
@@ -4837,7 +4752,7 @@ i915_gem_attach_phys_object(struct drm_device *dev,
                            int align)
 {
        struct address_space *mapping = file_inode(obj->base.filp)->i_mapping;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret = 0;
        int page_count;
        int i;
@@ -4950,6 +4865,7 @@ i915_gem_file_idle_work_handler(struct work_struct *work)
 int i915_gem_open(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_i915_file_private *file_priv;
+       int ret;
 
        DRM_DEBUG_DRIVER("\n");
 
@@ -4959,15 +4875,18 @@ int i915_gem_open(struct drm_device *dev, struct drm_file *file)
 
        file->driver_priv = file_priv;
        file_priv->dev_priv = dev->dev_private;
+       file_priv->file = file;
 
        spin_lock_init(&file_priv->mm.lock);
        INIT_LIST_HEAD(&file_priv->mm.request_list);
        INIT_DELAYED_WORK(&file_priv->mm.idle_work,
                          i915_gem_file_idle_work_handler);
 
-       idr_init(&file_priv->context_idr);
+       ret = i915_gem_context_open(dev, file);
+       if (ret)
+               kfree(file_priv);
 
-       return 0;
+       return ret;
 }
 
 static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
@@ -5014,7 +4933,7 @@ i915_gem_inactive_count(struct shrinker *shrinker, struct shrink_control *sc)
                if (obj->active)
                        continue;
 
-               if (obj->pin_count == 0 && obj->pages_pin_count == 0)
+               if (!i915_gem_obj_is_pinned(obj) && obj->pages_pin_count == 0)
                        count += obj->base.size >> PAGE_SHIFT;
        }
 
@@ -5031,7 +4950,8 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
        struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
 
-       if (vm == &dev_priv->mm.aliasing_ppgtt->base)
+       if (!dev_priv->mm.aliasing_ppgtt ||
+           vm == &dev_priv->mm.aliasing_ppgtt->base)
                vm = &dev_priv->gtt.base;
 
        BUG_ON(list_empty(&o->vma_list));
@@ -5072,7 +4992,8 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
        struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
 
-       if (vm == &dev_priv->mm.aliasing_ppgtt->base)
+       if (!dev_priv->mm.aliasing_ppgtt ||
+           vm == &dev_priv->mm.aliasing_ppgtt->base)
                vm = &dev_priv->gtt.base;
 
        BUG_ON(list_empty(&o->vma_list));
@@ -5127,7 +5048,7 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
                return NULL;
 
        vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link);
-       if (WARN_ON(vma->vm != obj_to_ggtt(obj)))
+       if (vma->vm != obj_to_ggtt(obj))
                return NULL;
 
        return vma;
index e08acab..6043062 100644 (file)
  * I've seen in a spec to date, and that was a workaround for a non-shipping
  * part. It should be safe to decrease this, but it's more future proof as is.
  */
-#define CONTEXT_ALIGN (64<<10)
+#define GEN6_CONTEXT_ALIGN (64<<10)
+#define GEN7_CONTEXT_ALIGN 4096
 
-static struct i915_hw_context *
-i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
-static int do_switch(struct i915_hw_context *to);
+static int do_switch(struct intel_ring_buffer *ring,
+                    struct i915_hw_context *to);
+
+static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
+{
+       struct drm_device *dev = ppgtt->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &ppgtt->base;
+
+       if (ppgtt == dev_priv->mm.aliasing_ppgtt ||
+           (list_empty(&vm->active_list) && list_empty(&vm->inactive_list))) {
+               ppgtt->base.cleanup(&ppgtt->base);
+               return;
+       }
+
+       /*
+        * Make sure vmas are unbound before we take down the drm_mm
+        *
+        * FIXME: Proper refcounting should take care of this, this shouldn't be
+        * needed at all.
+        */
+       if (!list_empty(&vm->active_list)) {
+               struct i915_vma *vma;
+
+               list_for_each_entry(vma, &vm->active_list, mm_list)
+                       if (WARN_ON(list_empty(&vma->vma_link) ||
+                                   list_is_singular(&vma->vma_link)))
+                               break;
+
+               i915_gem_evict_vm(&ppgtt->base, true);
+       } else {
+               i915_gem_retire_requests(dev);
+               i915_gem_evict_vm(&ppgtt->base, false);
+       }
+
+       ppgtt->base.cleanup(&ppgtt->base);
+}
+
+static void ppgtt_release(struct kref *kref)
+{
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(kref, struct i915_hw_ppgtt, ref);
+
+       do_ppgtt_cleanup(ppgtt);
+       kfree(ppgtt);
+}
+
+static size_t get_context_alignment(struct drm_device *dev)
+{
+       if (IS_GEN6(dev))
+               return GEN6_CONTEXT_ALIGN;
+
+       return GEN7_CONTEXT_ALIGN;
+}
 
 static int get_context_size(struct drm_device *dev)
 {
@@ -131,14 +183,44 @@ void i915_gem_context_free(struct kref *ctx_ref)
 {
        struct i915_hw_context *ctx = container_of(ctx_ref,
                                                   typeof(*ctx), ref);
+       struct i915_hw_ppgtt *ppgtt = NULL;
 
-       list_del(&ctx->link);
+       /* We refcount even the aliasing PPGTT to keep the code symmetric */
+       if (USES_PPGTT(ctx->obj->base.dev))
+               ppgtt = ctx_to_ppgtt(ctx);
+
+       /* XXX: Free up the object before tearing down the address space, in
+        * case we're bound in the PPGTT */
        drm_gem_object_unreference(&ctx->obj->base);
+
+       if (ppgtt)
+               kref_put(&ppgtt->ref, ppgtt_release);
+       list_del(&ctx->link);
        kfree(ctx);
 }
 
+static struct i915_hw_ppgtt *
+create_vm_for_ctx(struct drm_device *dev, struct i915_hw_context *ctx)
+{
+       struct i915_hw_ppgtt *ppgtt;
+       int ret;
+
+       ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+       if (!ppgtt)
+               return ERR_PTR(-ENOMEM);
+
+       ret = i915_gem_init_ppgtt(dev, ppgtt);
+       if (ret) {
+               kfree(ppgtt);
+               return ERR_PTR(ret);
+       }
+
+       ppgtt->ctx = ctx;
+       return ppgtt;
+}
+
 static struct i915_hw_context *
-create_hw_context(struct drm_device *dev,
+__create_hw_context(struct drm_device *dev,
                  struct drm_i915_file_private *file_priv)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -166,18 +248,13 @@ create_hw_context(struct drm_device *dev,
                        goto err_out;
        }
 
-       /* The ring associated with the context object is handled by the normal
-        * object tracking code. We give an initial ring value simple to pass an
-        * assertion in the context switch code.
-        */
-       ctx->ring = &dev_priv->ring[RCS];
        list_add_tail(&ctx->link, &dev_priv->context_list);
 
        /* Default context will never have a file_priv */
        if (file_priv == NULL)
                return ctx;
 
-       ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID + 1, 0,
+       ret = idr_alloc(&file_priv->context_idr, ctx, DEFAULT_CONTEXT_ID, 0,
                        GFP_KERNEL);
        if (ret < 0)
                goto err_out;
@@ -196,67 +273,136 @@ err_out:
        return ERR_PTR(ret);
 }
 
-static inline bool is_default_context(struct i915_hw_context *ctx)
-{
-       return (ctx == ctx->ring->default_context);
-}
-
 /**
  * The default context needs to exist per ring that uses contexts. It stores the
  * context state of the GPU for applications that don't utilize HW contexts, as
  * well as an idle case.
  */
-static int create_default_context(struct drm_i915_private *dev_priv)
+static struct i915_hw_context *
+i915_gem_create_context(struct drm_device *dev,
+                       struct drm_i915_file_private *file_priv,
+                       bool create_vm)
 {
+       const bool is_global_default_ctx = file_priv == NULL;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_hw_context *ctx;
-       int ret;
+       int ret = 0;
 
-       BUG_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
+       BUG_ON(!mutex_is_locked(&dev->struct_mutex));
 
-       ctx = create_hw_context(dev_priv->dev, NULL);
+       ctx = __create_hw_context(dev, file_priv);
        if (IS_ERR(ctx))
-               return PTR_ERR(ctx);
-
-       /* We may need to do things with the shrinker which require us to
-        * immediately switch back to the default context. This can cause a
-        * problem as pinning the default context also requires GTT space which
-        * may not be available. To avoid this we always pin the
-        * default context.
-        */
-       ret = i915_gem_obj_ggtt_pin(ctx->obj, CONTEXT_ALIGN, false, false);
-       if (ret) {
-               DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
-               goto err_destroy;
-       }
+               return ctx;
 
-       ret = do_switch(ctx);
-       if (ret) {
-               DRM_DEBUG_DRIVER("Switch failed %d\n", ret);
-               goto err_unpin;
+       if (is_global_default_ctx) {
+               /* We may need to do things with the shrinker which
+                * require us to immediately switch back to the default
+                * context. This can cause a problem as pinning the
+                * default context also requires GTT space which may not
+                * be available. To avoid this we always pin the default
+                * context.
+                */
+               ret = i915_gem_obj_ggtt_pin(ctx->obj,
+                                           get_context_alignment(dev), 0);
+               if (ret) {
+                       DRM_DEBUG_DRIVER("Couldn't pin %d\n", ret);
+                       goto err_destroy;
+               }
        }
 
-       dev_priv->ring[RCS].default_context = ctx;
+       if (create_vm) {
+               struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx);
+
+               if (IS_ERR_OR_NULL(ppgtt)) {
+                       DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
+                                        PTR_ERR(ppgtt));
+                       ret = PTR_ERR(ppgtt);
+                       goto err_unpin;
+               } else
+                       ctx->vm = &ppgtt->base;
+
+               /* This case is reserved for the global default context and
+                * should only happen once. */
+               if (is_global_default_ctx) {
+                       if (WARN_ON(dev_priv->mm.aliasing_ppgtt)) {
+                               ret = -EEXIST;
+                               goto err_unpin;
+                       }
+
+                       dev_priv->mm.aliasing_ppgtt = ppgtt;
+               }
+       } else if (USES_PPGTT(dev)) {
+               /* For platforms which only have aliasing PPGTT, we fake the
+                * address space and refcounting. */
+               ctx->vm = &dev_priv->mm.aliasing_ppgtt->base;
+               kref_get(&dev_priv->mm.aliasing_ppgtt->ref);
+       } else
+               ctx->vm = &dev_priv->gtt.base;
 
-       DRM_DEBUG_DRIVER("Default HW context loaded\n");
-       return 0;
+       return ctx;
 
 err_unpin:
-       i915_gem_object_unpin(ctx->obj);
+       if (is_global_default_ctx)
+               i915_gem_object_ggtt_unpin(ctx->obj);
 err_destroy:
        i915_gem_context_unreference(ctx);
-       return ret;
+       return ERR_PTR(ret);
+}
+
+void i915_gem_context_reset(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       int i;
+
+       if (!HAS_HW_CONTEXTS(dev))
+               return;
+
+       /* Prevent the hardware from restoring the last context (which hung) on
+        * the next switch */
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct i915_hw_context *dctx;
+               if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
+                       continue;
+
+               /* Do a fake switch to the default context */
+               ring = &dev_priv->ring[i];
+               dctx = ring->default_context;
+               if (WARN_ON(!dctx))
+                       continue;
+
+               if (!ring->last_context)
+                       continue;
+
+               if (ring->last_context == dctx)
+                       continue;
+
+               if (i == RCS) {
+                       WARN_ON(i915_gem_obj_ggtt_pin(dctx->obj,
+                                                     get_context_alignment(dev), 0));
+                       /* Fake a finish/inactive */
+                       dctx->obj->base.write_domain = 0;
+                       dctx->obj->active = 0;
+               }
+
+               i915_gem_context_unreference(ring->last_context);
+               i915_gem_context_reference(dctx);
+               ring->last_context = dctx;
+       }
 }
 
 int i915_gem_context_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret;
+       struct intel_ring_buffer *ring;
+       int i;
 
        if (!HAS_HW_CONTEXTS(dev))
                return 0;
 
-       /* If called from reset, or thaw... we've been here already */
-       if (dev_priv->ring[RCS].default_context)
+       /* Init should only be called once per module load. Eventually the
+        * restriction on the context_disabled check can be loosened. */
+       if (WARN_ON(dev_priv->ring[RCS].default_context))
                return 0;
 
        dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
@@ -266,11 +412,23 @@ int i915_gem_context_init(struct drm_device *dev)
                return -E2BIG;
        }
 
-       ret = create_default_context(dev_priv);
-       if (ret) {
-               DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %d\n",
-                                ret);
-               return ret;
+       dev_priv->ring[RCS].default_context =
+               i915_gem_create_context(dev, NULL, USES_PPGTT(dev));
+
+       if (IS_ERR_OR_NULL(dev_priv->ring[RCS].default_context)) {
+               DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %ld\n",
+                                PTR_ERR(dev_priv->ring[RCS].default_context));
+               return PTR_ERR(dev_priv->ring[RCS].default_context);
+       }
+
+       for (i = RCS + 1; i < I915_NUM_RINGS; i++) {
+               if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
+                       continue;
+
+               ring = &dev_priv->ring[i];
+
+               /* NB: RCS will hold a ref for all rings */
+               ring->default_context = dev_priv->ring[RCS].default_context;
        }
 
        DRM_DEBUG_DRIVER("HW context support initialized\n");
@@ -281,6 +439,7 @@ void i915_gem_context_fini(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
+       int i;
 
        if (!HAS_HW_CONTEXTS(dev))
                return;
@@ -300,59 +459,129 @@ void i915_gem_context_fini(struct drm_device *dev)
        if (dev_priv->ring[RCS].last_context == dctx) {
                /* Fake switch to NULL context */
                WARN_ON(dctx->obj->active);
-               i915_gem_object_unpin(dctx->obj);
+               i915_gem_object_ggtt_unpin(dctx->obj);
                i915_gem_context_unreference(dctx);
+               dev_priv->ring[RCS].last_context = NULL;
        }
 
-       i915_gem_object_unpin(dctx->obj);
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct intel_ring_buffer *ring = &dev_priv->ring[i];
+               if (!(INTEL_INFO(dev)->ring_mask & (1<<i)))
+                       continue;
+
+               if (ring->last_context)
+                       i915_gem_context_unreference(ring->last_context);
+
+               ring->default_context = NULL;
+               ring->last_context = NULL;
+       }
+
+       i915_gem_object_ggtt_unpin(dctx->obj);
        i915_gem_context_unreference(dctx);
-       dev_priv->ring[RCS].default_context = NULL;
-       dev_priv->ring[RCS].last_context = NULL;
+       dev_priv->mm.aliasing_ppgtt = NULL;
+}
+
+int i915_gem_context_enable(struct drm_i915_private *dev_priv)
+{
+       struct intel_ring_buffer *ring;
+       int ret, i;
+
+       if (!HAS_HW_CONTEXTS(dev_priv->dev))
+               return 0;
+
+       /* This is the only place the aliasing PPGTT gets enabled, which means
+        * it has to happen before we bail on reset */
+       if (dev_priv->mm.aliasing_ppgtt) {
+               struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+               ppgtt->enable(ppgtt);
+       }
+
+       /* FIXME: We should make this work, even in reset */
+       if (i915_reset_in_progress(&dev_priv->gpu_error))
+               return 0;
+
+       BUG_ON(!dev_priv->ring[RCS].default_context);
+
+       for_each_ring(ring, dev_priv, i) {
+               ret = do_switch(ring, ring->default_context);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
 }
 
 static int context_idr_cleanup(int id, void *p, void *data)
 {
        struct i915_hw_context *ctx = p;
 
-       BUG_ON(id == DEFAULT_CONTEXT_ID);
+       /* Ignore the default context because close will handle it */
+       if (i915_gem_context_is_default(ctx))
+               return 0;
 
        i915_gem_context_unreference(ctx);
        return 0;
 }
 
-struct i915_ctx_hang_stats *
-i915_gem_context_get_hang_stats(struct drm_device *dev,
-                               struct drm_file *file,
-                               u32 id)
+int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_i915_file_private *file_priv = file->driver_priv;
-       struct i915_hw_context *ctx;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (id == DEFAULT_CONTEXT_ID)
-               return &file_priv->hang_stats;
+       if (!HAS_HW_CONTEXTS(dev)) {
+               /* Cheat for hang stats */
+               file_priv->private_default_ctx =
+                       kzalloc(sizeof(struct i915_hw_context), GFP_KERNEL);
 
-       if (!HAS_HW_CONTEXTS(dev))
-               return ERR_PTR(-ENOENT);
+               if (file_priv->private_default_ctx == NULL)
+                       return -ENOMEM;
 
-       ctx = i915_gem_context_get(file->driver_priv, id);
-       if (ctx == NULL)
-               return ERR_PTR(-ENOENT);
+               file_priv->private_default_ctx->vm = &dev_priv->gtt.base;
+               return 0;
+       }
+
+       idr_init(&file_priv->context_idr);
 
-       return &ctx->hang_stats;
+       mutex_lock(&dev->struct_mutex);
+       file_priv->private_default_ctx =
+               i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
+       mutex_unlock(&dev->struct_mutex);
+
+       if (IS_ERR(file_priv->private_default_ctx)) {
+               idr_destroy(&file_priv->context_idr);
+               return PTR_ERR(file_priv->private_default_ctx);
+       }
+
+       return 0;
 }
 
 void i915_gem_context_close(struct drm_device *dev, struct drm_file *file)
 {
        struct drm_i915_file_private *file_priv = file->driver_priv;
 
+       if (!HAS_HW_CONTEXTS(dev)) {
+               kfree(file_priv->private_default_ctx);
+               return;
+       }
+
        idr_for_each(&file_priv->context_idr, context_idr_cleanup, NULL);
+       i915_gem_context_unreference(file_priv->private_default_ctx);
        idr_destroy(&file_priv->context_idr);
 }
 
-static struct i915_hw_context *
+struct i915_hw_context *
 i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id)
 {
-       return (struct i915_hw_context *)idr_find(&file_priv->context_idr, id);
+       struct i915_hw_context *ctx;
+
+       if (!HAS_HW_CONTEXTS(file_priv->dev_priv->dev))
+               return file_priv->private_default_ctx;
+
+       ctx = (struct i915_hw_context *)idr_find(&file_priv->context_idr, id);
+       if (!ctx)
+               return ERR_PTR(-ENOENT);
+
+       return ctx;
 }
 
 static inline int
@@ -390,7 +619,10 @@ mi_set_context(struct intel_ring_buffer *ring,
                        MI_SAVE_EXT_STATE_EN |
                        MI_RESTORE_EXT_STATE_EN |
                        hw_flags);
-       /* w/a: MI_SET_CONTEXT must always be followed by MI_NOOP */
+       /*
+        * w/a: MI_SET_CONTEXT must always be followed by MI_NOOP
+        * WaMiSetContext_Hang:snb,ivb,vlv
+        */
        intel_ring_emit(ring, MI_NOOP);
 
        if (IS_GEN7(ring->dev))
@@ -403,21 +635,30 @@ mi_set_context(struct intel_ring_buffer *ring,
        return ret;
 }
 
-static int do_switch(struct i915_hw_context *to)
+static int do_switch(struct intel_ring_buffer *ring,
+                    struct i915_hw_context *to)
 {
-       struct intel_ring_buffer *ring = to->ring;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct i915_hw_context *from = ring->last_context;
+       struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(to);
        u32 hw_flags = 0;
        int ret, i;
 
-       BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0);
+       if (from != NULL && ring == &dev_priv->ring[RCS]) {
+               BUG_ON(from->obj == NULL);
+               BUG_ON(!i915_gem_obj_is_pinned(from->obj));
+       }
 
-       if (from == to && !to->remap_slice)
+       if (from == to && from->last_ring == ring && !to->remap_slice)
                return 0;
 
-       ret = i915_gem_obj_ggtt_pin(to->obj, CONTEXT_ALIGN, false, false);
-       if (ret)
-               return ret;
+       /* Trying to pin first makes error handling easier. */
+       if (ring == &dev_priv->ring[RCS]) {
+               ret = i915_gem_obj_ggtt_pin(to->obj,
+                                           get_context_alignment(ring->dev), 0);
+               if (ret)
+                       return ret;
+       }
 
        /*
         * Pin can switch back to the default context if we end up calling into
@@ -426,6 +667,18 @@ static int do_switch(struct i915_hw_context *to)
         */
        from = ring->last_context;
 
+       if (USES_FULL_PPGTT(ring->dev)) {
+               ret = ppgtt->switch_mm(ppgtt, ring, false);
+               if (ret)
+                       goto unpin_out;
+       }
+
+       if (ring != &dev_priv->ring[RCS]) {
+               if (from)
+                       i915_gem_context_unreference(from);
+               goto done;
+       }
+
        /*
         * Clear this page out of any CPU caches for coherent swap-in/out. Note
         * that thanks to write = false in this call and us not setting any gpu
@@ -435,22 +688,21 @@ static int do_switch(struct i915_hw_context *to)
         * XXX: We need a real interface to do this instead of trickery.
         */
        ret = i915_gem_object_set_to_gtt_domain(to->obj, false);
-       if (ret) {
-               i915_gem_object_unpin(to->obj);
-               return ret;
-       }
+       if (ret)
+               goto unpin_out;
 
-       if (!to->obj->has_global_gtt_mapping)
-               i915_gem_gtt_bind_object(to->obj, to->obj->cache_level);
+       if (!to->obj->has_global_gtt_mapping) {
+               struct i915_vma *vma = i915_gem_obj_to_vma(to->obj,
+                                                          &dev_priv->gtt.base);
+               vma->bind_vma(vma, to->obj->cache_level, GLOBAL_BIND);
+       }
 
-       if (!to->is_initialized || is_default_context(to))
+       if (!to->is_initialized || i915_gem_context_is_default(to))
                hw_flags |= MI_RESTORE_INHIBIT;
 
        ret = mi_set_context(ring, to, hw_flags);
-       if (ret) {
-               i915_gem_object_unpin(to->obj);
-               return ret;
-       }
+       if (ret)
+               goto unpin_out;
 
        for (i = 0; i < MAX_L3_SLICES; i++) {
                if (!(to->remap_slice & (1<<i)))
@@ -484,22 +736,30 @@ static int do_switch(struct i915_hw_context *to)
                BUG_ON(from->obj->ring != ring);
 
                /* obj is kept alive until the next request by its active ref */
-               i915_gem_object_unpin(from->obj);
+               i915_gem_object_ggtt_unpin(from->obj);
                i915_gem_context_unreference(from);
        }
 
+       to->is_initialized = true;
+
+done:
        i915_gem_context_reference(to);
        ring->last_context = to;
-       to->is_initialized = true;
+       to->last_ring = ring;
 
        return 0;
+
+unpin_out:
+       if (ring->id == RCS)
+               i915_gem_object_ggtt_unpin(to->obj);
+       return ret;
 }
 
 /**
  * i915_switch_context() - perform a GPU context switch.
  * @ring: ring for which we'll execute the context switch
  * @file_priv: file_priv associated with the context, may be NULL
- * @id: context id number
+ * @to: the context to switch to
  *
  * The context life cycle is simple. The context refcount is incremented and
  * decremented by 1 and create and destroy. If the context is in use by the GPU,
@@ -508,31 +768,21 @@ static int do_switch(struct i915_hw_context *to)
  */
 int i915_switch_context(struct intel_ring_buffer *ring,
                        struct drm_file *file,
-                       int to_id)
+                       struct i915_hw_context *to)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       struct i915_hw_context *to;
-
-       if (!HAS_HW_CONTEXTS(ring->dev))
-               return 0;
 
        WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
 
-       if (ring != &dev_priv->ring[RCS])
-               return 0;
-
-       if (to_id == DEFAULT_CONTEXT_ID) {
-               to = ring->default_context;
-       } else {
-               if (file == NULL)
-                       return -EINVAL;
+       BUG_ON(file && to == NULL);
 
-               to = i915_gem_context_get(file->driver_priv, to_id);
-               if (to == NULL)
-                       return -ENOENT;
+       /* We have the fake context */
+       if (!HAS_HW_CONTEXTS(ring->dev)) {
+               ring->last_context = to;
+               return 0;
        }
 
-       return do_switch(to);
+       return do_switch(ring, to);
 }
 
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
@@ -543,9 +793,6 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
        struct i915_hw_context *ctx;
        int ret;
 
-       if (!(dev->driver->driver_features & DRIVER_GEM))
-               return -ENODEV;
-
        if (!HAS_HW_CONTEXTS(dev))
                return -ENODEV;
 
@@ -553,7 +800,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
        if (ret)
                return ret;
 
-       ctx = create_hw_context(dev, file_priv);
+       ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
        mutex_unlock(&dev->struct_mutex);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
@@ -572,17 +819,17 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
        struct i915_hw_context *ctx;
        int ret;
 
-       if (!(dev->driver->driver_features & DRIVER_GEM))
-               return -ENODEV;
+       if (args->ctx_id == DEFAULT_CONTEXT_ID)
+               return -ENOENT;
 
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                return ret;
 
        ctx = i915_gem_context_get(file_priv, args->ctx_id);
-       if (!ctx) {
+       if (IS_ERR(ctx)) {
                mutex_unlock(&dev->struct_mutex);
-               return -ENOENT;
+               return PTR_ERR(ctx);
        }
 
        idr_remove(&ctx->file_priv->context_idr, ctx->id);
index 775d506..f462d1b 100644 (file)
@@ -34,7 +34,7 @@ int
 i915_verify_lists(struct drm_device *dev)
 {
        static int warned;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
        int err = 0;
 
index 2ca280f..75fca63 100644 (file)
@@ -36,7 +36,7 @@
 static bool
 mark_free(struct i915_vma *vma, struct list_head *unwind)
 {
-       if (vma->obj->pin_count)
+       if (vma->pin_count)
                return false;
 
        if (WARN_ON(!list_empty(&vma->exec_list)))
@@ -46,18 +46,37 @@ mark_free(struct i915_vma *vma, struct list_head *unwind)
        return drm_mm_scan_add_block(&vma->node);
 }
 
+/**
+ * i915_gem_evict_something - Evict vmas to make room for binding a new one
+ * @dev: drm_device
+ * @vm: address space to evict from
+ * @size: size of the desired free space
+ * @alignment: alignment constraint of the desired free space
+ * @cache_level: cache_level for the desired space
+ * @mappable: whether the free space must be mappable
+ * @nonblocking: whether evicting active objects is allowed or not
+ *
+ * This function will try to evict vmas until a free space satisfying the
+ * requirements is found. Callers must check first whether any such hole exists
+ * already before calling this function.
+ *
+ * This function is used by the object/vma binding code.
+ *
+ * To clarify: This is for freeing up virtual address space, not for freeing
+ * memory in e.g. the shrinker.
+ */
 int
 i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm,
                         int min_size, unsigned alignment, unsigned cache_level,
-                        bool mappable, bool nonblocking)
+                        unsigned flags)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct list_head eviction_list, unwind_list;
        struct i915_vma *vma;
        int ret = 0;
        int pass = 0;
 
-       trace_i915_gem_evict(dev, min_size, alignment, mappable);
+       trace_i915_gem_evict(dev, min_size, alignment, flags);
 
        /*
         * The goal is to evict objects and amalgamate space in LRU order.
@@ -83,7 +102,7 @@ i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm,
         */
 
        INIT_LIST_HEAD(&unwind_list);
-       if (mappable) {
+       if (flags & PIN_MAPPABLE) {
                BUG_ON(!i915_is_ggtt(vm));
                drm_mm_init_scan_with_range(&vm->mm, min_size,
                                            alignment, cache_level, 0,
@@ -98,7 +117,7 @@ search_again:
                        goto found;
        }
 
-       if (nonblocking)
+       if (flags & PIN_NONBLOCK)
                goto none;
 
        /* Now merge in the soon-to-be-expired objects... */
@@ -122,7 +141,7 @@ none:
        /* Can we unpin some objects such as idle hw contents,
         * or pending flips?
         */
-       if (nonblocking)
+       if (flags & PIN_NONBLOCK)
                return -ENOSPC;
 
        /* Only idle the GPU and repeat the search once */
@@ -177,19 +196,19 @@ found:
 }
 
 /**
- * i915_gem_evict_vm - Try to free up VM space
+ * i915_gem_evict_vm - Evict all idle vmas from a vm
  *
- * @vm: Address space to evict from
+ * @vm: Address space to cleanse
  * @do_idle: Boolean directing whether to idle first.
  *
- * VM eviction is about freeing up virtual address space. If one wants fine
- * grained eviction, they should see evict something for more details. In terms
- * of freeing up actual system memory, this function may not accomplish the
- * desired result. An object may be shared in multiple address space, and this
- * function will not assert those objects be freed.
+ * This function evicts all idles vmas from a vm. If all unpinned vmas should be
+ * evicted the @do_idle needs to be set to true.
  *
- * Using do_idle will result in a more complete eviction because it retires, and
- * inactivates current BOs.
+ * This is used by the execbuf code as a last-ditch effort to defragment the
+ * address space.
+ *
+ * To clarify: This is for freeing up virtual address space, not for freeing
+ * memory in e.g. the shrinker.
  */
 int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
 {
@@ -207,16 +226,24 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
        }
 
        list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list)
-               if (vma->obj->pin_count == 0)
+               if (vma->pin_count == 0)
                        WARN_ON(i915_vma_unbind(vma));
 
        return 0;
 }
 
+/**
+ * i915_gem_evict_everything - Try to evict all objects
+ * @dev: Device to evict objects for
+ *
+ * This functions tries to evict all gem objects from all address spaces. Used
+ * by the shrinker as a last-ditch effort and for suspend, before releasing the
+ * backing storage of all unbound objects.
+ */
 int
 i915_gem_evict_everything(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_address_space *vm;
        bool lists_empty = true;
        int ret;
index d269ecf..7447160 100644 (file)
@@ -91,6 +91,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
               struct i915_address_space *vm,
               struct drm_file *file)
 {
+       struct drm_i915_private *dev_priv = vm->dev->dev_private;
        struct drm_i915_gem_object *obj;
        struct list_head objects;
        int i, ret;
@@ -125,6 +126,20 @@ eb_lookup_vmas(struct eb_vmas *eb,
        i = 0;
        while (!list_empty(&objects)) {
                struct i915_vma *vma;
+               struct i915_address_space *bind_vm = vm;
+
+               if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT &&
+                   USES_FULL_PPGTT(vm->dev)) {
+                       ret = -EINVAL;
+                       goto err;
+               }
+
+               /* If we have secure dispatch, or the userspace assures us that
+                * they know what they're doing, use the GGTT VM.
+                */
+               if (((args->flags & I915_EXEC_SECURE) &&
+                   (i == (args->buffer_count - 1))))
+                       bind_vm = &dev_priv->gtt.base;
 
                obj = list_first_entry(&objects,
                                       struct drm_i915_gem_object,
@@ -138,7 +153,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
                 * from the (obj, vm) we don't run the risk of creating
                 * duplicated vmas for the same vm.
                 */
-               vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
+               vma = i915_gem_obj_lookup_or_create_vma(obj, bind_vm);
                if (IS_ERR(vma)) {
                        DRM_DEBUG("Failed to lookup VMA\n");
                        ret = PTR_ERR(vma);
@@ -217,7 +232,7 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
                i915_gem_object_unpin_fence(obj);
 
        if (entry->flags & __EXEC_OBJECT_HAS_PIN)
-               i915_gem_object_unpin(obj);
+               vma->pin_count--;
 
        entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN);
 }
@@ -327,8 +342,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
 static int
 i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                                   struct eb_vmas *eb,
-                                  struct drm_i915_gem_relocation_entry *reloc,
-                                  struct i915_address_space *vm)
+                                  struct drm_i915_gem_relocation_entry *reloc)
 {
        struct drm_device *dev = obj->base.dev;
        struct drm_gem_object *target_obj;
@@ -352,8 +366,10 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        if (unlikely(IS_GEN6(dev) &&
            reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
            !target_i915_obj->has_global_gtt_mapping)) {
-               i915_gem_gtt_bind_object(target_i915_obj,
-                                        target_i915_obj->cache_level);
+               struct i915_vma *vma =
+                       list_first_entry(&target_i915_obj->vma_list,
+                                        typeof(*vma), vma_link);
+               vma->bind_vma(vma, target_i915_obj->cache_level, GLOBAL_BIND);
        }
 
        /* Validate that the target is in a valid r/w GPU domain */
@@ -451,8 +467,7 @@ i915_gem_execbuffer_relocate_vma(struct i915_vma *vma,
                do {
                        u64 offset = r->presumed_offset;
 
-                       ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r,
-                                                                vma->vm);
+                       ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, r);
                        if (ret)
                                return ret;
 
@@ -481,8 +496,7 @@ i915_gem_execbuffer_relocate_vma_slow(struct i915_vma *vma,
        int i, ret;
 
        for (i = 0; i < entry->relocation_count; i++) {
-               ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i],
-                                                        vma->vm);
+               ret = i915_gem_execbuffer_relocate_entry(vma->obj, eb, &relocs[i]);
                if (ret)
                        return ret;
        }
@@ -527,21 +541,26 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
                                struct intel_ring_buffer *ring,
                                bool *need_reloc)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct drm_i915_gem_object *obj = vma->obj;
        struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
        bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
-       bool need_fence, need_mappable;
-       struct drm_i915_gem_object *obj = vma->obj;
+       bool need_fence;
+       unsigned flags;
        int ret;
 
+       flags = 0;
+
        need_fence =
                has_fenced_gpu_access &&
                entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
                obj->tiling_mode != I915_TILING_NONE;
-       need_mappable = need_fence || need_reloc_mappable(vma);
+       if (need_fence || need_reloc_mappable(vma))
+               flags |= PIN_MAPPABLE;
 
-       ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, need_mappable,
-                                 false);
+       if (entry->flags & EXEC_OBJECT_NEEDS_GTT)
+               flags |= PIN_GLOBAL;
+
+       ret = i915_gem_object_pin(obj, vma->vm, entry->alignment, flags);
        if (ret)
                return ret;
 
@@ -560,14 +579,6 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
                }
        }
 
-       /* Ensure ppgtt mapping exists if needed */
-       if (dev_priv->mm.aliasing_ppgtt && !obj->has_aliasing_ppgtt_mapping) {
-               i915_ppgtt_bind_object(dev_priv->mm.aliasing_ppgtt,
-                                      obj, obj->cache_level);
-
-               obj->has_aliasing_ppgtt_mapping = 1;
-       }
-
        if (entry->offset != vma->node.start) {
                entry->offset = vma->node.start;
                *need_reloc = true;
@@ -578,10 +589,6 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
                obj->base.pending_write_domain = I915_GEM_DOMAIN_RENDER;
        }
 
-       if (entry->flags & EXEC_OBJECT_NEEDS_GTT &&
-           !obj->has_global_gtt_mapping)
-               i915_gem_gtt_bind_object(obj, obj->cache_level);
-
        return 0;
 }
 
@@ -891,7 +898,7 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
                if (!access_ok(VERIFY_WRITE, ptr, length))
                        return -EFAULT;
 
-               if (likely(!i915_prefault_disable)) {
+               if (likely(!i915.prefault_disable)) {
                        if (fault_in_multipages_readable(ptr, length))
                                return -EFAULT;
                }
@@ -900,22 +907,27 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
        return 0;
 }
 
-static int
+static struct i915_hw_context *
 i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
-                         const u32 ctx_id)
+                         struct intel_ring_buffer *ring, const u32 ctx_id)
 {
+       struct i915_hw_context *ctx = NULL;
        struct i915_ctx_hang_stats *hs;
 
-       hs = i915_gem_context_get_hang_stats(dev, file, ctx_id);
-       if (IS_ERR(hs))
-               return PTR_ERR(hs);
+       if (ring->id != RCS && ctx_id != DEFAULT_CONTEXT_ID)
+               return ERR_PTR(-EINVAL);
+
+       ctx = i915_gem_context_get(file->driver_priv, ctx_id);
+       if (IS_ERR(ctx))
+               return ctx;
 
+       hs = &ctx->hang_stats;
        if (hs->banned) {
                DRM_DEBUG("Context %u tried to submit while banned\n", ctx_id);
-               return -EIO;
+               return ERR_PTR(-EIO);
        }
 
-       return 0;
+       return ctx;
 }
 
 static void
@@ -939,7 +951,9 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
                if (obj->base.write_domain) {
                        obj->dirty = 1;
                        obj->last_write_seqno = intel_ring_get_seqno(ring);
-                       if (obj->pin_count) /* check for potential scanout */
+                       /* check for potential scanout */
+                       if (i915_gem_obj_ggtt_bound(obj) &&
+                           i915_gem_obj_to_ggtt(obj)->pin_count)
                                intel_mark_fb_busy(obj, ring);
                }
 
@@ -964,7 +978,7 @@ static int
 i915_reset_gen7_sol_offsets(struct drm_device *dev,
                            struct intel_ring_buffer *ring)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int ret, i;
 
        if (!IS_GEN7(dev) || ring != &dev_priv->ring[RCS])
@@ -989,16 +1003,17 @@ static int
 i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                       struct drm_file *file,
                       struct drm_i915_gem_execbuffer2 *args,
-                      struct drm_i915_gem_exec_object2 *exec,
-                      struct i915_address_space *vm)
+                      struct drm_i915_gem_exec_object2 *exec)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct eb_vmas *eb;
        struct drm_i915_gem_object *batch_obj;
        struct drm_clip_rect *cliprects = NULL;
        struct intel_ring_buffer *ring;
+       struct i915_hw_context *ctx;
+       struct i915_address_space *vm;
        const u32 ctx_id = i915_execbuffer2_get_context_id(*args);
-       u32 exec_start, exec_len;
+       u32 exec_start = args->batch_start_offset, exec_len;
        u32 mask, flags;
        int ret, mode, i;
        bool need_relocs;
@@ -1020,41 +1035,17 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        if (args->flags & I915_EXEC_IS_PINNED)
                flags |= I915_DISPATCH_PINNED;
 
-       switch (args->flags & I915_EXEC_RING_MASK) {
-       case I915_EXEC_DEFAULT:
-       case I915_EXEC_RENDER:
-               ring = &dev_priv->ring[RCS];
-               break;
-       case I915_EXEC_BSD:
-               ring = &dev_priv->ring[VCS];
-               if (ctx_id != DEFAULT_CONTEXT_ID) {
-                       DRM_DEBUG("Ring %s doesn't support contexts\n",
-                                 ring->name);
-                       return -EPERM;
-               }
-               break;
-       case I915_EXEC_BLT:
-               ring = &dev_priv->ring[BCS];
-               if (ctx_id != DEFAULT_CONTEXT_ID) {
-                       DRM_DEBUG("Ring %s doesn't support contexts\n",
-                                 ring->name);
-                       return -EPERM;
-               }
-               break;
-       case I915_EXEC_VEBOX:
-               ring = &dev_priv->ring[VECS];
-               if (ctx_id != DEFAULT_CONTEXT_ID) {
-                       DRM_DEBUG("Ring %s doesn't support contexts\n",
-                                 ring->name);
-                       return -EPERM;
-               }
-               break;
-
-       default:
+       if ((args->flags & I915_EXEC_RING_MASK) > I915_NUM_RINGS) {
                DRM_DEBUG("execbuf with unknown ring: %d\n",
                          (int)(args->flags & I915_EXEC_RING_MASK));
                return -EINVAL;
        }
+
+       if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT)
+               ring = &dev_priv->ring[RCS];
+       else
+               ring = &dev_priv->ring[(args->flags & I915_EXEC_RING_MASK) - 1];
+
        if (!intel_ring_initialized(ring)) {
                DRM_DEBUG("execbuf with invalid ring: %d\n",
                          (int)(args->flags & I915_EXEC_RING_MASK));
@@ -1136,11 +1127,18 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto pre_mutex_err;
        }
 
-       ret = i915_gem_validate_context(dev, file, ctx_id);
-       if (ret) {
+       ctx = i915_gem_validate_context(dev, file, ring, ctx_id);
+       if (IS_ERR(ctx)) {
                mutex_unlock(&dev->struct_mutex);
+               ret = PTR_ERR(ctx);
                goto pre_mutex_err;
-       }
+       } 
+
+       i915_gem_context_reference(ctx);
+
+       vm = ctx->vm;
+       if (!USES_FULL_PPGTT(dev))
+               vm = &dev_priv->gtt.base;
 
        eb = eb_create(args);
        if (eb == NULL) {
@@ -1184,17 +1182,46 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        }
        batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
 
+       if (i915_needs_cmd_parser(ring)) {
+               ret = i915_parse_cmds(ring,
+                                     batch_obj,
+                                     args->batch_start_offset,
+                                     file->is_master);
+               if (ret)
+                       goto err;
+
+               /*
+                * XXX: Actually do this when enabling batch copy...
+                *
+                * Set the DISPATCH_SECURE bit to remove the NON_SECURE bit
+                * from MI_BATCH_BUFFER_START commands issued in the
+                * dispatch_execbuffer implementations. We specifically don't
+                * want that set when the command parser is enabled.
+                */
+       }
+
        /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
         * batch" bit. Hence we need to pin secure batches into the global gtt.
         * hsw should have this fixed, but bdw mucks it up again. */
-       if (flags & I915_DISPATCH_SECURE && !batch_obj->has_global_gtt_mapping)
-               i915_gem_gtt_bind_object(batch_obj, batch_obj->cache_level);
+       if (flags & I915_DISPATCH_SECURE &&
+           !batch_obj->has_global_gtt_mapping) {
+               /* When we have multiple VMs, we'll need to make sure that we
+                * allocate space first */
+               struct i915_vma *vma = i915_gem_obj_to_ggtt(batch_obj);
+               BUG_ON(!vma);
+               vma->bind_vma(vma, batch_obj->cache_level, GLOBAL_BIND);
+       }
+
+       if (flags & I915_DISPATCH_SECURE)
+               exec_start += i915_gem_obj_ggtt_offset(batch_obj);
+       else
+               exec_start += i915_gem_obj_offset(batch_obj, vm);
 
        ret = i915_gem_execbuffer_move_to_gpu(ring, &eb->vmas);
        if (ret)
                goto err;
 
-       ret = i915_switch_context(ring, file, ctx_id);
+       ret = i915_switch_context(ring, file, ctx);
        if (ret)
                goto err;
 
@@ -1219,8 +1246,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                        goto err;
        }
 
-       exec_start = i915_gem_obj_offset(batch_obj, vm) +
-               args->batch_start_offset;
+
        exec_len = args->batch_len;
        if (cliprects) {
                for (i = 0; i < args->num_cliprects; i++) {
@@ -1249,6 +1275,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
 
 err:
+       /* the request owns the ref now */
+       i915_gem_context_unreference(ctx);
        eb_destroy(eb);
 
        mutex_unlock(&dev->struct_mutex);
@@ -1270,7 +1298,6 @@ int
 i915_gem_execbuffer(struct drm_device *dev, void *data,
                    struct drm_file *file)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_execbuffer *args = data;
        struct drm_i915_gem_execbuffer2 exec2;
        struct drm_i915_gem_exec_object *exec_list = NULL;
@@ -1326,8 +1353,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
        exec2.flags = I915_EXEC_RENDER;
        i915_execbuffer2_set_context_id(exec2, 0);
 
-       ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list,
-                                    &dev_priv->gtt.base);
+       ret = i915_gem_do_execbuffer(dev, data, file, &exec2, exec2_list);
        if (!ret) {
                /* Copy the new buffer offsets back to the user's exec list. */
                for (i = 0; i < args->buffer_count; i++)
@@ -1353,7 +1379,6 @@ int
 i915_gem_execbuffer2(struct drm_device *dev, void *data,
                     struct drm_file *file)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_execbuffer2 *args = data;
        struct drm_i915_gem_exec_object2 *exec2_list = NULL;
        int ret;
@@ -1384,8 +1409,7 @@ i915_gem_execbuffer2(struct drm_device *dev, void *data,
                return -EFAULT;
        }
 
-       ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list,
-                                    &dev_priv->gtt.base);
+       ret = i915_gem_do_execbuffer(dev, data, file, args, exec2_list);
        if (!ret) {
                /* Copy the new buffer offsets back to the user's exec list. */
                ret = copy_to_user(to_user_ptr(args->buffers_ptr),
index d278be1..ab5e93c 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright © 2010 Daniel Vetter
+ * Copyright © 2011-2014 Intel Corporation
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
  *
  */
 
+#include <linux/seq_file.h>
 #include <drm/drmP.h>
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 #include "i915_trace.h"
 #include "intel_drv.h"
 
+static void gen8_setup_private_ppat(struct drm_i915_private *dev_priv);
+
+bool intel_enable_ppgtt(struct drm_device *dev, bool full)
+{
+       if (i915.enable_ppgtt == 0 || !HAS_ALIASING_PPGTT(dev))
+               return false;
+
+       if (i915.enable_ppgtt == 1 && full)
+               return false;
+
+#ifdef CONFIG_INTEL_IOMMU
+       /* Disable ppgtt on SNB if VT-d is on. */
+       if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped) {
+               DRM_INFO("Disabling PPGTT because VT-d is on\n");
+               return false;
+       }
+#endif
+
+       /* Full ppgtt disabled by default for now due to issues. */
+       if (full)
+               return false; /* HAS_PPGTT(dev) */
+       else
+               return HAS_ALIASING_PPGTT(dev);
+}
+
 #define GEN6_PPGTT_PD_ENTRIES 512
 #define I915_PPGTT_PT_ENTRIES (PAGE_SIZE / sizeof(gen6_gtt_pte_t))
 typedef uint64_t gen8_gtt_pte_t;
@@ -63,13 +90,31 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
 
 #define GEN8_PTES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_gtt_pte_t))
 #define GEN8_PDES_PER_PAGE             (PAGE_SIZE / sizeof(gen8_ppgtt_pde_t))
-#define GEN8_LEGACY_PDPS               4
+
+/* GEN8 legacy style addressis defined as a 3 level page table:
+ * 31:30 | 29:21 | 20:12 |  11:0
+ * PDPE  |  PDE  |  PTE  | offset
+ * The difference as compared to normal x86 3 level page table is the PDPEs are
+ * programmed via register.
+ */
+#define GEN8_PDPE_SHIFT                        30
+#define GEN8_PDPE_MASK                 0x3
+#define GEN8_PDE_SHIFT                 21
+#define GEN8_PDE_MASK                  0x1ff
+#define GEN8_PTE_SHIFT                 12
+#define GEN8_PTE_MASK                  0x1ff
 
 #define PPAT_UNCACHED_INDEX            (_PAGE_PWT | _PAGE_PCD)
 #define PPAT_CACHED_PDE_INDEX          0 /* WB LLC */
 #define PPAT_CACHED_INDEX              _PAGE_PAT /* WB LLCeLLC */
 #define PPAT_DISPLAY_ELLC_INDEX                _PAGE_PCD /* WT eLLC */
 
+static void ppgtt_bind_vma(struct i915_vma *vma,
+                          enum i915_cache_level cache_level,
+                          u32 flags);
+static void ppgtt_unbind_vma(struct i915_vma *vma);
+static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt);
+
 static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
                                             enum i915_cache_level level,
                                             bool valid)
@@ -199,12 +244,19 @@ static gen6_gtt_pte_t iris_pte_encode(dma_addr_t addr,
 
 /* Broadwell Page Directory Pointer Descriptors */
 static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry,
-                          uint64_t val)
+                          uint64_t val, bool synchronous)
 {
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
        int ret;
 
        BUG_ON(entry >= 4);
 
+       if (synchronous) {
+               I915_WRITE(GEN8_RING_PDP_UDW(ring, entry), val >> 32);
+               I915_WRITE(GEN8_RING_PDP_LDW(ring, entry), (u32)val);
+               return 0;
+       }
+
        ret = intel_ring_begin(ring, 6);
        if (ret)
                return ret;
@@ -220,216 +272,357 @@ static int gen8_write_pdp(struct intel_ring_buffer *ring, unsigned entry,
        return 0;
 }
 
-static int gen8_ppgtt_enable(struct drm_device *dev)
+static int gen8_mm_switch(struct i915_hw_ppgtt *ppgtt,
+                         struct intel_ring_buffer *ring,
+                         bool synchronous)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
-       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-       int i, j, ret;
+       int i, ret;
 
        /* bit of a hack to find the actual last used pd */
        int used_pd = ppgtt->num_pd_entries / GEN8_PDES_PER_PAGE;
 
-       for_each_ring(ring, dev_priv, j) {
-               I915_WRITE(RING_MODE_GEN7(ring),
-                          _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-       }
-
        for (i = used_pd - 1; i >= 0; i--) {
                dma_addr_t addr = ppgtt->pd_dma_addr[i];
-               for_each_ring(ring, dev_priv, j) {
-                       ret = gen8_write_pdp(ring, i, addr);
-                       if (ret)
-                               goto err_out;
-               }
+               ret = gen8_write_pdp(ring, i, addr, synchronous);
+               if (ret)
+                       return ret;
        }
-       return 0;
 
-err_out:
-       for_each_ring(ring, dev_priv, j)
-               I915_WRITE(RING_MODE_GEN7(ring),
-                          _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE));
-       return ret;
+       return 0;
 }
 
 static void gen8_ppgtt_clear_range(struct i915_address_space *vm,
-                                  unsigned first_entry,
-                                  unsigned num_entries,
+                                  uint64_t start,
+                                  uint64_t length,
                                   bool use_scratch)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
        gen8_gtt_pte_t *pt_vaddr, scratch_pte;
-       unsigned act_pt = first_entry / GEN8_PTES_PER_PAGE;
-       unsigned first_pte = first_entry % GEN8_PTES_PER_PAGE;
+       unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK;
+       unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK;
+       unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK;
+       unsigned num_entries = length >> PAGE_SHIFT;
        unsigned last_pte, i;
 
        scratch_pte = gen8_pte_encode(ppgtt->base.scratch.addr,
                                      I915_CACHE_LLC, use_scratch);
 
        while (num_entries) {
-               struct page *page_table = &ppgtt->gen8_pt_pages[act_pt];
+               struct page *page_table = ppgtt->gen8_pt_pages[pdpe][pde];
 
-               last_pte = first_pte + num_entries;
+               last_pte = pte + num_entries;
                if (last_pte > GEN8_PTES_PER_PAGE)
                        last_pte = GEN8_PTES_PER_PAGE;
 
                pt_vaddr = kmap_atomic(page_table);
 
-               for (i = first_pte; i < last_pte; i++)
+               for (i = pte; i < last_pte; i++) {
                        pt_vaddr[i] = scratch_pte;
+                       num_entries--;
+               }
 
                kunmap_atomic(pt_vaddr);
 
-               num_entries -= last_pte - first_pte;
-               first_pte = 0;
-               act_pt++;
+               pte = 0;
+               if (++pde == GEN8_PDES_PER_PAGE) {
+                       pdpe++;
+                       pde = 0;
+               }
        }
 }
 
 static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
                                      struct sg_table *pages,
-                                     unsigned first_entry,
+                                     uint64_t start,
                                      enum i915_cache_level cache_level)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
        gen8_gtt_pte_t *pt_vaddr;
-       unsigned act_pt = first_entry / GEN8_PTES_PER_PAGE;
-       unsigned act_pte = first_entry % GEN8_PTES_PER_PAGE;
+       unsigned pdpe = start >> GEN8_PDPE_SHIFT & GEN8_PDPE_MASK;
+       unsigned pde = start >> GEN8_PDE_SHIFT & GEN8_PDE_MASK;
+       unsigned pte = start >> GEN8_PTE_SHIFT & GEN8_PTE_MASK;
        struct sg_page_iter sg_iter;
 
        pt_vaddr = NULL;
+
        for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
+               if (WARN_ON(pdpe >= GEN8_LEGACY_PDPS))
+                       break;
+
                if (pt_vaddr == NULL)
-                       pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]);
+                       pt_vaddr = kmap_atomic(ppgtt->gen8_pt_pages[pdpe][pde]);
 
-               pt_vaddr[act_pte] =
+               pt_vaddr[pte] =
                        gen8_pte_encode(sg_page_iter_dma_address(&sg_iter),
                                        cache_level, true);
-               if (++act_pte == GEN8_PTES_PER_PAGE) {
+               if (++pte == GEN8_PTES_PER_PAGE) {
                        kunmap_atomic(pt_vaddr);
                        pt_vaddr = NULL;
-                       act_pt++;
-                       act_pte = 0;
+                       if (++pde == GEN8_PDES_PER_PAGE) {
+                               pdpe++;
+                               pde = 0;
+                       }
+                       pte = 0;
                }
        }
        if (pt_vaddr)
                kunmap_atomic(pt_vaddr);
 }
 
+static void gen8_free_page_tables(struct page **pt_pages)
+{
+       int i;
+
+       if (pt_pages == NULL)
+               return;
+
+       for (i = 0; i < GEN8_PDES_PER_PAGE; i++)
+               if (pt_pages[i])
+                       __free_pages(pt_pages[i], 0);
+}
+
+static void gen8_ppgtt_free(const struct i915_hw_ppgtt *ppgtt)
+{
+       int i;
+
+       for (i = 0; i < ppgtt->num_pd_pages; i++) {
+               gen8_free_page_tables(ppgtt->gen8_pt_pages[i]);
+               kfree(ppgtt->gen8_pt_pages[i]);
+               kfree(ppgtt->gen8_pt_dma_addr[i]);
+       }
+
+       __free_pages(ppgtt->pd_pages, get_order(ppgtt->num_pd_pages << PAGE_SHIFT));
+}
+
+static void gen8_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt)
+{
+       struct pci_dev *hwdev = ppgtt->base.dev->pdev;
+       int i, j;
+
+       for (i = 0; i < ppgtt->num_pd_pages; i++) {
+               /* TODO: In the future we'll support sparse mappings, so this
+                * will have to change. */
+               if (!ppgtt->pd_dma_addr[i])
+                       continue;
+
+               pci_unmap_page(hwdev, ppgtt->pd_dma_addr[i], PAGE_SIZE,
+                              PCI_DMA_BIDIRECTIONAL);
+
+               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
+                       dma_addr_t addr = ppgtt->gen8_pt_dma_addr[i][j];
+                       if (addr)
+                               pci_unmap_page(hwdev, addr, PAGE_SIZE,
+                                              PCI_DMA_BIDIRECTIONAL);
+               }
+       }
+}
+
 static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
-       int i, j;
 
+       list_del(&vm->global_link);
        drm_mm_takedown(&vm->mm);
 
-       for (i = 0; i < ppgtt->num_pd_pages ; i++) {
-               if (ppgtt->pd_dma_addr[i]) {
-                       pci_unmap_page(ppgtt->base.dev->pdev,
-                                      ppgtt->pd_dma_addr[i],
-                                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       gen8_ppgtt_unmap_pages(ppgtt);
+       gen8_ppgtt_free(ppgtt);
+}
 
-                       for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
-                               dma_addr_t addr = ppgtt->gen8_pt_dma_addr[i][j];
-                               if (addr)
-                                       pci_unmap_page(ppgtt->base.dev->pdev,
-                                                      addr,
-                                                      PAGE_SIZE,
-                                                      PCI_DMA_BIDIRECTIONAL);
+static struct page **__gen8_alloc_page_tables(void)
+{
+       struct page **pt_pages;
+       int i;
 
-                       }
-               }
-               kfree(ppgtt->gen8_pt_dma_addr[i]);
+       pt_pages = kcalloc(GEN8_PDES_PER_PAGE, sizeof(struct page *), GFP_KERNEL);
+       if (!pt_pages)
+               return ERR_PTR(-ENOMEM);
+
+       for (i = 0; i < GEN8_PDES_PER_PAGE; i++) {
+               pt_pages[i] = alloc_page(GFP_KERNEL);
+               if (!pt_pages[i])
+                       goto bail;
        }
 
-       __free_pages(ppgtt->gen8_pt_pages, get_order(ppgtt->num_pt_pages << PAGE_SHIFT));
-       __free_pages(ppgtt->pd_pages, get_order(ppgtt->num_pd_pages << PAGE_SHIFT));
+       return pt_pages;
+
+bail:
+       gen8_free_page_tables(pt_pages);
+       kfree(pt_pages);
+       return ERR_PTR(-ENOMEM);
 }
 
-/**
- * GEN8 legacy ppgtt programming is accomplished through 4 PDP registers with a
- * net effect resembling a 2-level page table in normal x86 terms. Each PDP
- * represents 1GB of memory
- * 4 * 512 * 512 * 4096 = 4GB legacy 32b address space.
- *
- * TODO: Do something with the size parameter
- **/
-static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
+static int gen8_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt,
+                                          const int max_pdp)
 {
-       struct page *pt_pages;
-       int i, j, ret = -ENOMEM;
-       const int max_pdp = DIV_ROUND_UP(size, 1 << 30);
-       const int num_pt_pages = GEN8_PDES_PER_PAGE * max_pdp;
+       struct page **pt_pages[GEN8_LEGACY_PDPS];
+       int i, ret;
 
-       if (size % (1<<30))
-               DRM_INFO("Pages will be wasted unless GTT size (%llu) is divisible by 1GB\n", size);
+       for (i = 0; i < max_pdp; i++) {
+               pt_pages[i] = __gen8_alloc_page_tables();
+               if (IS_ERR(pt_pages[i])) {
+                       ret = PTR_ERR(pt_pages[i]);
+                       goto unwind_out;
+               }
+       }
 
-       /* FIXME: split allocation into smaller pieces. For now we only ever do
-        * this once, but with full PPGTT, the multiple contiguous allocations
-        * will be bad.
+       /* NB: Avoid touching gen8_pt_pages until last to keep the allocation,
+        * "atomic" - for cleanup purposes.
         */
+       for (i = 0; i < max_pdp; i++)
+               ppgtt->gen8_pt_pages[i] = pt_pages[i];
+
+       return 0;
+
+unwind_out:
+       while (i--) {
+               gen8_free_page_tables(pt_pages[i]);
+               kfree(pt_pages[i]);
+       }
+
+       return ret;
+}
+
+static int gen8_ppgtt_allocate_dma(struct i915_hw_ppgtt *ppgtt)
+{
+       int i;
+
+       for (i = 0; i < ppgtt->num_pd_pages; i++) {
+               ppgtt->gen8_pt_dma_addr[i] = kcalloc(GEN8_PDES_PER_PAGE,
+                                                    sizeof(dma_addr_t),
+                                                    GFP_KERNEL);
+               if (!ppgtt->gen8_pt_dma_addr[i])
+                       return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int gen8_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt,
+                                               const int max_pdp)
+{
        ppgtt->pd_pages = alloc_pages(GFP_KERNEL, get_order(max_pdp << PAGE_SHIFT));
        if (!ppgtt->pd_pages)
                return -ENOMEM;
 
-       pt_pages = alloc_pages(GFP_KERNEL, get_order(num_pt_pages << PAGE_SHIFT));
-       if (!pt_pages) {
+       ppgtt->num_pd_pages = 1 << get_order(max_pdp << PAGE_SHIFT);
+       BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPS);
+
+       return 0;
+}
+
+static int gen8_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt,
+                           const int max_pdp)
+{
+       int ret;
+
+       ret = gen8_ppgtt_allocate_page_directories(ppgtt, max_pdp);
+       if (ret)
+               return ret;
+
+       ret = gen8_ppgtt_allocate_page_tables(ppgtt, max_pdp);
+       if (ret) {
                __free_pages(ppgtt->pd_pages, get_order(max_pdp << PAGE_SHIFT));
-               return -ENOMEM;
+               return ret;
        }
 
-       ppgtt->gen8_pt_pages = pt_pages;
-       ppgtt->num_pd_pages = 1 << get_order(max_pdp << PAGE_SHIFT);
-       ppgtt->num_pt_pages = 1 << get_order(num_pt_pages << PAGE_SHIFT);
        ppgtt->num_pd_entries = max_pdp * GEN8_PDES_PER_PAGE;
-       ppgtt->enable = gen8_ppgtt_enable;
-       ppgtt->base.clear_range = gen8_ppgtt_clear_range;
-       ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
-       ppgtt->base.cleanup = gen8_ppgtt_cleanup;
-       ppgtt->base.start = 0;
-       ppgtt->base.total = ppgtt->num_pt_pages * GEN8_PTES_PER_PAGE * PAGE_SIZE;
 
-       BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPS);
+       ret = gen8_ppgtt_allocate_dma(ppgtt);
+       if (ret)
+               gen8_ppgtt_free(ppgtt);
 
-       /*
-        * - Create a mapping for the page directories.
-        * - For each page directory:
-        *      allocate space for page table mappings.
-        *      map each page table
-        */
-       for (i = 0; i < max_pdp; i++) {
-               dma_addr_t temp;
-               temp = pci_map_page(ppgtt->base.dev->pdev,
-                                   &ppgtt->pd_pages[i], 0,
-                                   PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
-               if (pci_dma_mapping_error(ppgtt->base.dev->pdev, temp))
-                       goto err_out;
+       return ret;
+}
 
-               ppgtt->pd_dma_addr[i] = temp;
+static int gen8_ppgtt_setup_page_directories(struct i915_hw_ppgtt *ppgtt,
+                                            const int pd)
+{
+       dma_addr_t pd_addr;
+       int ret;
 
-               ppgtt->gen8_pt_dma_addr[i] = kmalloc(sizeof(dma_addr_t) * GEN8_PDES_PER_PAGE, GFP_KERNEL);
-               if (!ppgtt->gen8_pt_dma_addr[i])
-                       goto err_out;
+       pd_addr = pci_map_page(ppgtt->base.dev->pdev,
+                              &ppgtt->pd_pages[pd], 0,
+                              PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
 
-               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
-                       struct page *p = &pt_pages[i * GEN8_PDES_PER_PAGE + j];
-                       temp = pci_map_page(ppgtt->base.dev->pdev,
-                                           p, 0, PAGE_SIZE,
-                                           PCI_DMA_BIDIRECTIONAL);
+       ret = pci_dma_mapping_error(ppgtt->base.dev->pdev, pd_addr);
+       if (ret)
+               return ret;
 
-                       if (pci_dma_mapping_error(ppgtt->base.dev->pdev, temp))
-                               goto err_out;
+       ppgtt->pd_dma_addr[pd] = pd_addr;
 
-                       ppgtt->gen8_pt_dma_addr[i][j] = temp;
+       return 0;
+}
+
+static int gen8_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt,
+                                       const int pd,
+                                       const int pt)
+{
+       dma_addr_t pt_addr;
+       struct page *p;
+       int ret;
+
+       p = ppgtt->gen8_pt_pages[pd][pt];
+       pt_addr = pci_map_page(ppgtt->base.dev->pdev,
+                              p, 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+       ret = pci_dma_mapping_error(ppgtt->base.dev->pdev, pt_addr);
+       if (ret)
+               return ret;
+
+       ppgtt->gen8_pt_dma_addr[pd][pt] = pt_addr;
+
+       return 0;
+}
+
+/**
+ * GEN8 legacy ppgtt programming is accomplished through a max 4 PDP registers
+ * with a net effect resembling a 2-level page table in normal x86 terms. Each
+ * PDP represents 1GB of memory 4 * 512 * 512 * 4096 = 4GB legacy 32b address
+ * space.
+ *
+ * FIXME: split allocation into smaller pieces. For now we only ever do this
+ * once, but with full PPGTT, the multiple contiguous allocations will be bad.
+ * TODO: Do something with the size parameter
+ */
+static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
+{
+       const int max_pdp = DIV_ROUND_UP(size, 1 << 30);
+       const int min_pt_pages = GEN8_PDES_PER_PAGE * max_pdp;
+       int i, j, ret;
+
+       if (size % (1<<30))
+               DRM_INFO("Pages will be wasted unless GTT size (%llu) is divisible by 1GB\n", size);
+
+       /* 1. Do all our allocations for page directories and page tables. */
+       ret = gen8_ppgtt_alloc(ppgtt, max_pdp);
+       if (ret)
+               return ret;
+
+       /*
+        * 2. Create DMA mappings for the page directories and page tables.
+        */
+       for (i = 0; i < max_pdp; i++) {
+               ret = gen8_ppgtt_setup_page_directories(ppgtt, i);
+               if (ret)
+                       goto bail;
+
+               for (j = 0; j < GEN8_PDES_PER_PAGE; j++) {
+                       ret = gen8_ppgtt_setup_page_tables(ppgtt, i, j);
+                       if (ret)
+                               goto bail;
                }
        }
 
-       /* For now, the PPGTT helper functions all require that the PDEs are
+       /*
+        * 3. Map all the page directory entires to point to the page tables
+        * we've allocated.
+        *
+        * For now, the PPGTT helper functions all require that the PDEs are
         * plugged in correctly. So we do that now/here. For aliasing PPGTT, we
-        * will never need to touch the PDEs again */
+        * will never need to touch the PDEs again.
+        */
        for (i = 0; i < max_pdp; i++) {
                gen8_ppgtt_pde_t *pd_vaddr;
                pd_vaddr = kmap_atomic(&ppgtt->pd_pages[i]);
@@ -441,23 +634,85 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
                kunmap_atomic(pd_vaddr);
        }
 
-       ppgtt->base.clear_range(&ppgtt->base, 0,
-                               ppgtt->num_pd_entries * GEN8_PTES_PER_PAGE,
-                               true);
+       ppgtt->enable = gen8_ppgtt_enable;
+       ppgtt->switch_mm = gen8_mm_switch;
+       ppgtt->base.clear_range = gen8_ppgtt_clear_range;
+       ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
+       ppgtt->base.cleanup = gen8_ppgtt_cleanup;
+       ppgtt->base.start = 0;
+       ppgtt->base.total = ppgtt->num_pd_entries * GEN8_PTES_PER_PAGE * PAGE_SIZE;
+
+       ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true);
 
        DRM_DEBUG_DRIVER("Allocated %d pages for page directories (%d wasted)\n",
                         ppgtt->num_pd_pages, ppgtt->num_pd_pages - max_pdp);
        DRM_DEBUG_DRIVER("Allocated %d pages for page tables (%lld wasted)\n",
-                        ppgtt->num_pt_pages,
-                        (ppgtt->num_pt_pages - num_pt_pages) +
-                        size % (1<<30));
+                        ppgtt->num_pd_entries,
+                        (ppgtt->num_pd_entries - min_pt_pages) + size % (1<<30));
        return 0;
 
-err_out:
-       ppgtt->base.cleanup(&ppgtt->base);
+bail:
+       gen8_ppgtt_unmap_pages(ppgtt);
+       gen8_ppgtt_free(ppgtt);
        return ret;
 }
 
+static void gen6_dump_ppgtt(struct i915_hw_ppgtt *ppgtt, struct seq_file *m)
+{
+       struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
+       struct i915_address_space *vm = &ppgtt->base;
+       gen6_gtt_pte_t __iomem *pd_addr;
+       gen6_gtt_pte_t scratch_pte;
+       uint32_t pd_entry;
+       int pte, pde;
+
+       scratch_pte = vm->pte_encode(vm->scratch.addr, I915_CACHE_LLC, true);
+
+       pd_addr = (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm +
+               ppgtt->pd_offset / sizeof(gen6_gtt_pte_t);
+
+       seq_printf(m, "  VM %p (pd_offset %x-%x):\n", vm,
+                  ppgtt->pd_offset, ppgtt->pd_offset + ppgtt->num_pd_entries);
+       for (pde = 0; pde < ppgtt->num_pd_entries; pde++) {
+               u32 expected;
+               gen6_gtt_pte_t *pt_vaddr;
+               dma_addr_t pt_addr = ppgtt->pt_dma_addr[pde];
+               pd_entry = readl(pd_addr + pde);
+               expected = (GEN6_PDE_ADDR_ENCODE(pt_addr) | GEN6_PDE_VALID);
+
+               if (pd_entry != expected)
+                       seq_printf(m, "\tPDE #%d mismatch: Actual PDE: %x Expected PDE: %x\n",
+                                  pde,
+                                  pd_entry,
+                                  expected);
+               seq_printf(m, "\tPDE: %x\n", pd_entry);
+
+               pt_vaddr = kmap_atomic(ppgtt->pt_pages[pde]);
+               for (pte = 0; pte < I915_PPGTT_PT_ENTRIES; pte+=4) {
+                       unsigned long va =
+                               (pde * PAGE_SIZE * I915_PPGTT_PT_ENTRIES) +
+                               (pte * PAGE_SIZE);
+                       int i;
+                       bool found = false;
+                       for (i = 0; i < 4; i++)
+                               if (pt_vaddr[pte + i] != scratch_pte)
+                                       found = true;
+                       if (!found)
+                               continue;
+
+                       seq_printf(m, "\t\t0x%lx [%03d,%04d]: =", va, pde, pte);
+                       for (i = 0; i < 4; i++) {
+                               if (pt_vaddr[pte + i] != scratch_pte)
+                                       seq_printf(m, " %08x", pt_vaddr[pte + i]);
+                               else
+                                       seq_puts(m, "  SCRATCH ");
+                       }
+                       seq_puts(m, "\n");
+               }
+               kunmap_atomic(pt_vaddr);
+       }
+}
+
 static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
 {
        struct drm_i915_private *dev_priv = ppgtt->base.dev->dev_private;
@@ -480,73 +735,235 @@ static void gen6_write_pdes(struct i915_hw_ppgtt *ppgtt)
        readl(pd_addr);
 }
 
-static int gen6_ppgtt_enable(struct drm_device *dev)
+static uint32_t get_pd_offset(struct i915_hw_ppgtt *ppgtt)
+{
+       BUG_ON(ppgtt->pd_offset & 0x3f);
+
+       return (ppgtt->pd_offset / 64) << 16;
+}
+
+static int hsw_mm_switch(struct i915_hw_ppgtt *ppgtt,
+                        struct intel_ring_buffer *ring,
+                        bool synchronous)
+{
+       struct drm_device *dev = ppgtt->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       /* If we're in reset, we can assume the GPU is sufficiently idle to
+        * manually frob these bits. Ideally we could use the ring functions,
+        * except our error handling makes it quite difficult (can't use
+        * intel_ring_begin, ring->flush, or intel_ring_advance)
+        *
+        * FIXME: We should try not to special case reset
+        */
+       if (synchronous ||
+           i915_reset_in_progress(&dev_priv->gpu_error)) {
+               WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
+               I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
+               I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
+               POSTING_READ(RING_PP_DIR_BASE(ring));
+               return 0;
+       }
+
+       /* NB: TLBs must be flushed and invalidated before a switch */
+       ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+       if (ret)
+               return ret;
+
+       ret = intel_ring_begin(ring, 6);
+       if (ret)
+               return ret;
+
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
+       intel_ring_emit(ring, RING_PP_DIR_DCLV(ring));
+       intel_ring_emit(ring, PP_DIR_DCLV_2G);
+       intel_ring_emit(ring, RING_PP_DIR_BASE(ring));
+       intel_ring_emit(ring, get_pd_offset(ppgtt));
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
+
+       return 0;
+}
+
+static int gen7_mm_switch(struct i915_hw_ppgtt *ppgtt,
+                         struct intel_ring_buffer *ring,
+                         bool synchronous)
+{
+       struct drm_device *dev = ppgtt->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       /* If we're in reset, we can assume the GPU is sufficiently idle to
+        * manually frob these bits. Ideally we could use the ring functions,
+        * except our error handling makes it quite difficult (can't use
+        * intel_ring_begin, ring->flush, or intel_ring_advance)
+        *
+        * FIXME: We should try not to special case reset
+        */
+       if (synchronous ||
+           i915_reset_in_progress(&dev_priv->gpu_error)) {
+               WARN_ON(ppgtt != dev_priv->mm.aliasing_ppgtt);
+               I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
+               I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
+               POSTING_READ(RING_PP_DIR_BASE(ring));
+               return 0;
+       }
+
+       /* NB: TLBs must be flushed and invalidated before a switch */
+       ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+       if (ret)
+               return ret;
+
+       ret = intel_ring_begin(ring, 6);
+       if (ret)
+               return ret;
+
+       intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(2));
+       intel_ring_emit(ring, RING_PP_DIR_DCLV(ring));
+       intel_ring_emit(ring, PP_DIR_DCLV_2G);
+       intel_ring_emit(ring, RING_PP_DIR_BASE(ring));
+       intel_ring_emit(ring, get_pd_offset(ppgtt));
+       intel_ring_emit(ring, MI_NOOP);
+       intel_ring_advance(ring);
+
+       /* XXX: RCS is the only one to auto invalidate the TLBs? */
+       if (ring->id != RCS) {
+               ret = ring->flush(ring, I915_GEM_GPU_DOMAINS, I915_GEM_GPU_DOMAINS);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
+                         struct intel_ring_buffer *ring,
+                         bool synchronous)
+{
+       struct drm_device *dev = ppgtt->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!synchronous)
+               return 0;
+
+       I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
+       I915_WRITE(RING_PP_DIR_BASE(ring), get_pd_offset(ppgtt));
+
+       POSTING_READ(RING_PP_DIR_DCLV(ring));
+
+       return 0;
+}
+
+static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
-       uint32_t pd_offset;
+       struct drm_device *dev = ppgtt->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
-       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-       int i;
+       int j, ret;
 
-       BUG_ON(ppgtt->pd_offset & 0x3f);
+       for_each_ring(ring, dev_priv, j) {
+               I915_WRITE(RING_MODE_GEN7(ring),
+                          _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
 
-       gen6_write_pdes(ppgtt);
+               /* We promise to do a switch later with FULL PPGTT. If this is
+                * aliasing, this is the one and only switch we'll do */
+               if (USES_FULL_PPGTT(dev))
+                       continue;
 
-       pd_offset = ppgtt->pd_offset;
-       pd_offset /= 64; /* in cachelines, */
-       pd_offset <<= 16;
+               ret = ppgtt->switch_mm(ppgtt, ring, true);
+               if (ret)
+                       goto err_out;
+       }
 
-       if (INTEL_INFO(dev)->gen == 6) {
-               uint32_t ecochk, gab_ctl, ecobits;
+       return 0;
 
-               ecobits = I915_READ(GAC_ECO_BITS);
-               I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
-                                        ECOBITS_PPGTT_CACHE64B);
+err_out:
+       for_each_ring(ring, dev_priv, j)
+               I915_WRITE(RING_MODE_GEN7(ring),
+                          _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE));
+       return ret;
+}
 
-               gab_ctl = I915_READ(GAB_CTL);
-               I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
+static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+{
+       struct drm_device *dev = ppgtt->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       uint32_t ecochk, ecobits;
+       int i;
 
-               ecochk = I915_READ(GAM_ECOCHK);
-               I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT |
-                                      ECOCHK_PPGTT_CACHE64B);
-               I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-       } else if (INTEL_INFO(dev)->gen >= 7) {
-               uint32_t ecochk, ecobits;
+       ecobits = I915_READ(GAC_ECO_BITS);
+       I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B);
 
-               ecobits = I915_READ(GAC_ECO_BITS);
-               I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_PPGTT_CACHE64B);
+       ecochk = I915_READ(GAM_ECOCHK);
+       if (IS_HASWELL(dev)) {
+               ecochk |= ECOCHK_PPGTT_WB_HSW;
+       } else {
+               ecochk |= ECOCHK_PPGTT_LLC_IVB;
+               ecochk &= ~ECOCHK_PPGTT_GFDT_IVB;
+       }
+       I915_WRITE(GAM_ECOCHK, ecochk);
 
-               ecochk = I915_READ(GAM_ECOCHK);
-               if (IS_HASWELL(dev)) {
-                       ecochk |= ECOCHK_PPGTT_WB_HSW;
-               } else {
-                       ecochk |= ECOCHK_PPGTT_LLC_IVB;
-                       ecochk &= ~ECOCHK_PPGTT_GFDT_IVB;
-               }
-               I915_WRITE(GAM_ECOCHK, ecochk);
+       for_each_ring(ring, dev_priv, i) {
+               int ret;
                /* GFX_MODE is per-ring on gen7+ */
+               I915_WRITE(RING_MODE_GEN7(ring),
+                          _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+
+               /* We promise to do a switch later with FULL PPGTT. If this is
+                * aliasing, this is the one and only switch we'll do */
+               if (USES_FULL_PPGTT(dev))
+                       continue;
+
+               ret = ppgtt->switch_mm(ppgtt, ring, true);
+               if (ret)
+                       return ret;
        }
 
-       for_each_ring(ring, dev_priv, i) {
-               if (INTEL_INFO(dev)->gen >= 7)
-                       I915_WRITE(RING_MODE_GEN7(ring),
-                                  _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+       return 0;
+}
 
-               I915_WRITE(RING_PP_DIR_DCLV(ring), PP_DIR_DCLV_2G);
-               I915_WRITE(RING_PP_DIR_BASE(ring), pd_offset);
+static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+{
+       struct drm_device *dev = ppgtt->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ring_buffer *ring;
+       uint32_t ecochk, gab_ctl, ecobits;
+       int i;
+
+       ecobits = I915_READ(GAC_ECO_BITS);
+       I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
+                  ECOBITS_PPGTT_CACHE64B);
+
+       gab_ctl = I915_READ(GAB_CTL);
+       I915_WRITE(GAB_CTL, gab_ctl | GAB_CTL_CONT_AFTER_PAGEFAULT);
+
+       ecochk = I915_READ(GAM_ECOCHK);
+       I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B);
+
+       I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
+
+       for_each_ring(ring, dev_priv, i) {
+               int ret = ppgtt->switch_mm(ppgtt, ring, true);
+               if (ret)
+                       return ret;
        }
+
        return 0;
 }
 
 /* PPGTT support for Sandybdrige/Gen6 and later */
 static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
-                                  unsigned first_entry,
-                                  unsigned num_entries,
+                                  uint64_t start,
+                                  uint64_t length,
                                   bool use_scratch)
 {
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
        gen6_gtt_pte_t *pt_vaddr, scratch_pte;
+       unsigned first_entry = start >> PAGE_SHIFT;
+       unsigned num_entries = length >> PAGE_SHIFT;
        unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
        unsigned first_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        unsigned last_pte, i;
@@ -573,12 +990,13 @@ static void gen6_ppgtt_clear_range(struct i915_address_space *vm,
 
 static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                                      struct sg_table *pages,
-                                     unsigned first_entry,
+                                     uint64_t start,
                                      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 first_entry = start >> PAGE_SHIFT;
        unsigned act_pt = first_entry / I915_PPGTT_PT_ENTRIES;
        unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        struct sg_page_iter sg_iter;
@@ -602,65 +1020,130 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
                kunmap_atomic(pt_vaddr);
 }
 
-static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
+static void gen6_ppgtt_unmap_pages(struct i915_hw_ppgtt *ppgtt)
 {
-       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->base.dev->pdev,
                                       ppgtt->pt_dma_addr[i],
                                       4096, PCI_DMA_BIDIRECTIONAL);
        }
+}
+
+static void gen6_ppgtt_free(struct i915_hw_ppgtt *ppgtt)
+{
+       int i;
 
        kfree(ppgtt->pt_dma_addr);
        for (i = 0; i < ppgtt->num_pd_entries; i++)
                __free_page(ppgtt->pt_pages[i]);
        kfree(ppgtt->pt_pages);
-       kfree(ppgtt);
 }
 
-static int gen6_ppgtt_init(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);
+
+       list_del(&vm->global_link);
+       drm_mm_takedown(&ppgtt->base.mm);
+       drm_mm_remove_node(&ppgtt->node);
+
+       gen6_ppgtt_unmap_pages(ppgtt);
+       gen6_ppgtt_free(ppgtt);
+}
+
+static int gen6_ppgtt_allocate_page_directories(struct i915_hw_ppgtt *ppgtt)
+{
+#define GEN6_PD_ALIGN (PAGE_SIZE * 16)
+#define GEN6_PD_SIZE (GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE)
        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;
-       int ret = -ENOMEM;
+       bool retried = false;
+       int ret;
 
-       /* ppgtt PDEs reside in the global gtt pagetable, which has 512*1024
-        * entries. For aliasing ppgtt support we just steal them at the end for
-        * now. */
-       first_pd_entry_in_global_pt = gtt_total_entries(dev_priv->gtt);
+       /* PPGTT PDEs reside in the GGTT and consists of 512 entries. The
+        * allocator works in address space sizes, so it's multiplied by page
+        * size. We allocate at the top of the GTT to avoid fragmentation.
+        */
+       BUG_ON(!drm_mm_initialized(&dev_priv->gtt.base.mm));
+alloc:
+       ret = drm_mm_insert_node_in_range_generic(&dev_priv->gtt.base.mm,
+                                                 &ppgtt->node, GEN6_PD_SIZE,
+                                                 GEN6_PD_ALIGN, 0,
+                                                 0, dev_priv->gtt.base.total,
+                                                 DRM_MM_SEARCH_DEFAULT,
+                                                 DRM_MM_CREATE_DEFAULT);
+       if (ret == -ENOSPC && !retried) {
+               ret = i915_gem_evict_something(dev, &dev_priv->gtt.base,
+                                              GEN6_PD_SIZE, GEN6_PD_ALIGN,
+                                              I915_CACHE_NONE, 0);
+               if (ret)
+                       return ret;
+
+               retried = true;
+               goto alloc;
+       }
+
+       if (ppgtt->node.start < dev_priv->gtt.mappable_end)
+               DRM_DEBUG("Forced to use aperture for PDEs\n");
 
-       ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode;
        ppgtt->num_pd_entries = GEN6_PPGTT_PD_ENTRIES;
-       ppgtt->enable = gen6_ppgtt_enable;
-       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->base.start = 0;
-       ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE;
+       return ret;
+}
+
+static int gen6_ppgtt_allocate_page_tables(struct i915_hw_ppgtt *ppgtt)
+{
+       int i;
+
        ppgtt->pt_pages = kcalloc(ppgtt->num_pd_entries, sizeof(struct page *),
                                  GFP_KERNEL);
+
        if (!ppgtt->pt_pages)
                return -ENOMEM;
 
        for (i = 0; i < ppgtt->num_pd_entries; i++) {
                ppgtt->pt_pages[i] = alloc_page(GFP_KERNEL);
-               if (!ppgtt->pt_pages[i])
-                       goto err_pt_alloc;
+               if (!ppgtt->pt_pages[i]) {
+                       gen6_ppgtt_free(ppgtt);
+                       return -ENOMEM;
+               }
+       }
+
+       return 0;
+}
+
+static int gen6_ppgtt_alloc(struct i915_hw_ppgtt *ppgtt)
+{
+       int ret;
+
+       ret = gen6_ppgtt_allocate_page_directories(ppgtt);
+       if (ret)
+               return ret;
+
+       ret = gen6_ppgtt_allocate_page_tables(ppgtt);
+       if (ret) {
+               drm_mm_remove_node(&ppgtt->node);
+               return ret;
        }
 
        ppgtt->pt_dma_addr = kcalloc(ppgtt->num_pd_entries, sizeof(dma_addr_t),
                                     GFP_KERNEL);
-       if (!ppgtt->pt_dma_addr)
-               goto err_pt_alloc;
+       if (!ppgtt->pt_dma_addr) {
+               drm_mm_remove_node(&ppgtt->node);
+               gen6_ppgtt_free(ppgtt);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int gen6_ppgtt_setup_page_tables(struct i915_hw_ppgtt *ppgtt)
+{
+       struct drm_device *dev = ppgtt->base.dev;
+       int i;
 
        for (i = 0; i < ppgtt->num_pd_entries; i++) {
                dma_addr_t pt_addr;
@@ -669,48 +1152,71 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
                                       PCI_DMA_BIDIRECTIONAL);
 
                if (pci_dma_mapping_error(dev->pdev, pt_addr)) {
-                       ret = -EIO;
-                       goto err_pd_pin;
-
+                       gen6_ppgtt_unmap_pages(ppgtt);
+                       return -EIO;
                }
+
                ppgtt->pt_dma_addr[i] = pt_addr;
        }
 
-       ppgtt->base.clear_range(&ppgtt->base, 0,
-                               ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES, true);
+       return 0;
+}
 
-       ppgtt->pd_offset = first_pd_entry_in_global_pt * sizeof(gen6_gtt_pte_t);
+static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
+{
+       struct drm_device *dev = ppgtt->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
 
-       return 0;
+       ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode;
+       if (IS_GEN6(dev)) {
+               ppgtt->enable = gen6_ppgtt_enable;
+               ppgtt->switch_mm = gen6_mm_switch;
+       } else if (IS_HASWELL(dev)) {
+               ppgtt->enable = gen7_ppgtt_enable;
+               ppgtt->switch_mm = hsw_mm_switch;
+       } else if (IS_GEN7(dev)) {
+               ppgtt->enable = gen7_ppgtt_enable;
+               ppgtt->switch_mm = gen7_mm_switch;
+       } else
+               BUG();
 
-err_pd_pin:
-       if (ppgtt->pt_dma_addr) {
-               for (i--; i >= 0; i--)
-                       pci_unmap_page(dev->pdev, ppgtt->pt_dma_addr[i],
-                                      4096, PCI_DMA_BIDIRECTIONAL);
-       }
-err_pt_alloc:
-       kfree(ppgtt->pt_dma_addr);
-       for (i = 0; i < ppgtt->num_pd_entries; i++) {
-               if (ppgtt->pt_pages[i])
-                       __free_page(ppgtt->pt_pages[i]);
+       ret = gen6_ppgtt_alloc(ppgtt);
+       if (ret)
+               return ret;
+
+       ret = gen6_ppgtt_setup_page_tables(ppgtt);
+       if (ret) {
+               gen6_ppgtt_free(ppgtt);
+               return ret;
        }
-       kfree(ppgtt->pt_pages);
 
-       return ret;
+       ppgtt->base.clear_range = gen6_ppgtt_clear_range;
+       ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
+       ppgtt->base.cleanup = gen6_ppgtt_cleanup;
+       ppgtt->base.start = 0;
+       ppgtt->base.total =  ppgtt->num_pd_entries * I915_PPGTT_PT_ENTRIES * PAGE_SIZE;
+       ppgtt->debug_dump = gen6_dump_ppgtt;
+
+       ppgtt->pd_offset =
+               ppgtt->node.start / PAGE_SIZE * sizeof(gen6_gtt_pte_t);
+
+       ppgtt->base.clear_range(&ppgtt->base, 0, ppgtt->base.total, true);
+
+       DRM_DEBUG_DRIVER("Allocated pde space (%ldM) at GTT entry: %lx\n",
+                        ppgtt->node.size >> 20,
+                        ppgtt->node.start / PAGE_SIZE);
+
+       return 0;
 }
 
-static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
+int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_hw_ppgtt *ppgtt;
-       int ret;
-
-       ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
-       if (!ppgtt)
-               return -ENOMEM;
+       int ret = 0;
 
        ppgtt->base.dev = dev;
+       ppgtt->base.scratch = dev_priv->gtt.base.scratch;
 
        if (INTEL_INFO(dev)->gen < 8)
                ret = gen6_ppgtt_init(ppgtt);
@@ -719,45 +1225,37 @@ static int i915_gem_init_aliasing_ppgtt(struct drm_device *dev)
        else
                BUG();
 
-       if (ret)
-               kfree(ppgtt);
-       else {
-               dev_priv->mm.aliasing_ppgtt = ppgtt;
+       if (!ret) {
+               struct drm_i915_private *dev_priv = dev->dev_private;
+               kref_init(&ppgtt->ref);
                drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
                            ppgtt->base.total);
+               i915_init_vm(dev_priv, &ppgtt->base);
+               if (INTEL_INFO(dev)->gen < 8) {
+                       gen6_write_pdes(ppgtt);
+                       DRM_DEBUG("Adding PPGTT at offset %x\n",
+                                 ppgtt->pd_offset << 10);
+               }
        }
 
        return ret;
 }
 
-void i915_gem_cleanup_aliasing_ppgtt(struct drm_device *dev)
+static void
+ppgtt_bind_vma(struct i915_vma *vma,
+              enum i915_cache_level cache_level,
+              u32 flags)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-
-       if (!ppgtt)
-               return;
-
-       ppgtt->base.cleanup(&ppgtt->base);
-       dev_priv->mm.aliasing_ppgtt = NULL;
+       vma->vm->insert_entries(vma->vm, vma->obj->pages, vma->node.start,
+                               cache_level);
 }
 
-void i915_ppgtt_bind_object(struct i915_hw_ppgtt *ppgtt,
-                           struct drm_i915_gem_object *obj,
-                           enum i915_cache_level cache_level)
+static void ppgtt_unbind_vma(struct i915_vma *vma)
 {
-       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->base.clear_range(&ppgtt->base,
-                               i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT,
-                               obj->base.size >> PAGE_SHIFT,
-                               true);
+       vma->vm->clear_range(vma->vm,
+                            vma->node.start,
+                            vma->obj->base.size,
+                            true);
 }
 
 extern int intel_iommu_gfx_mapped;
@@ -840,8 +1338,8 @@ void i915_gem_suspend_gtt_mappings(struct drm_device *dev)
        i915_check_and_clear_faults(dev);
 
        dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
-                                      dev_priv->gtt.base.start / PAGE_SIZE,
-                                      dev_priv->gtt.base.total / PAGE_SIZE,
+                                      dev_priv->gtt.base.start,
+                                      dev_priv->gtt.base.total,
                                       true);
 }
 
@@ -849,18 +1347,46 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
+       struct i915_address_space *vm;
 
        i915_check_and_clear_faults(dev);
 
        /* First fill our portion of the GTT with scratch pages */
        dev_priv->gtt.base.clear_range(&dev_priv->gtt.base,
-                                      dev_priv->gtt.base.start / PAGE_SIZE,
-                                      dev_priv->gtt.base.total / PAGE_SIZE,
+                                      dev_priv->gtt.base.start,
+                                      dev_priv->gtt.base.total,
                                       true);
 
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
+               struct i915_vma *vma = i915_gem_obj_to_vma(obj,
+                                                          &dev_priv->gtt.base);
+               if (!vma)
+                       continue;
+
                i915_gem_clflush_object(obj, obj->pin_display);
-               i915_gem_gtt_bind_object(obj, obj->cache_level);
+               /* The bind_vma code tries to be smart about tracking mappings.
+                * Unfortunately above, we've just wiped out the mappings
+                * without telling our object about it. So we need to fake it.
+                */
+               obj->has_global_gtt_mapping = 0;
+               vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
+       }
+
+
+       if (INTEL_INFO(dev)->gen >= 8) {
+               gen8_setup_private_ppat(dev_priv);
+               return;
+       }
+
+       list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
+               /* TODO: Perhaps it shouldn't be gen6 specific */
+               if (i915_is_ggtt(vm)) {
+                       if (dev_priv->mm.aliasing_ppgtt)
+                               gen6_write_pdes(dev_priv->mm.aliasing_ppgtt);
+                       continue;
+               }
+
+               gen6_write_pdes(container_of(vm, struct i915_hw_ppgtt, base));
        }
 
        i915_gem_chipset_flush(dev);
@@ -891,10 +1417,11 @@ static inline void gen8_set_pte(void __iomem *addr, gen8_gtt_pte_t pte)
 
 static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
                                     struct sg_table *st,
-                                    unsigned int first_entry,
+                                    uint64_t start,
                                     enum i915_cache_level level)
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
+       unsigned first_entry = start >> PAGE_SHIFT;
        gen8_gtt_pte_t __iomem *gtt_entries =
                (gen8_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
@@ -936,10 +1463,11 @@ static void gen8_ggtt_insert_entries(struct i915_address_space *vm,
  */
 static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
                                     struct sg_table *st,
-                                    unsigned int first_entry,
+                                    uint64_t start,
                                     enum i915_cache_level level)
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
+       unsigned first_entry = start >> PAGE_SHIFT;
        gen6_gtt_pte_t __iomem *gtt_entries =
                (gen6_gtt_pte_t __iomem *)dev_priv->gtt.gsm + first_entry;
        int i = 0;
@@ -971,11 +1499,13 @@ static void gen6_ggtt_insert_entries(struct i915_address_space *vm,
 }
 
 static void gen8_ggtt_clear_range(struct i915_address_space *vm,
-                                 unsigned int first_entry,
-                                 unsigned int num_entries,
+                                 uint64_t start,
+                                 uint64_t length,
                                  bool use_scratch)
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
+       unsigned first_entry = start >> PAGE_SHIFT;
+       unsigned num_entries = length >> PAGE_SHIFT;
        gen8_gtt_pte_t scratch_pte, __iomem *gtt_base =
                (gen8_gtt_pte_t __iomem *) dev_priv->gtt.gsm + first_entry;
        const int max_entries = gtt_total_entries(dev_priv->gtt) - first_entry;
@@ -995,11 +1525,13 @@ static void gen8_ggtt_clear_range(struct i915_address_space *vm,
 }
 
 static void gen6_ggtt_clear_range(struct i915_address_space *vm,
-                                 unsigned int first_entry,
-                                 unsigned int num_entries,
+                                 uint64_t start,
+                                 uint64_t length,
                                  bool use_scratch)
 {
        struct drm_i915_private *dev_priv = vm->dev->dev_private;
+       unsigned first_entry = start >> PAGE_SHIFT;
+       unsigned num_entries = length >> PAGE_SHIFT;
        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;
@@ -1017,53 +1549,103 @@ static void gen6_ggtt_clear_range(struct i915_address_space *vm,
        readl(gtt_base);
 }
 
-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)
+
+static void i915_ggtt_bind_vma(struct i915_vma *vma,
+                              enum i915_cache_level cache_level,
+                              u32 unused)
 {
+       const unsigned long entry = vma->node.start >> PAGE_SHIFT;
        unsigned int flags = (cache_level == I915_CACHE_NONE) ?
                AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
 
-       intel_gtt_insert_sg_entries(st, pg_start, flags);
-
+       BUG_ON(!i915_is_ggtt(vma->vm));
+       intel_gtt_insert_sg_entries(vma->obj->pages, entry, flags);
+       vma->obj->has_global_gtt_mapping = 1;
 }
 
 static void i915_ggtt_clear_range(struct i915_address_space *vm,
-                                 unsigned int first_entry,
-                                 unsigned int num_entries,
+                                 uint64_t start,
+                                 uint64_t length,
                                  bool unused)
 {
+       unsigned first_entry = start >> PAGE_SHIFT;
+       unsigned num_entries = length >> PAGE_SHIFT;
        intel_gtt_clear_range(first_entry, num_entries);
 }
 
+static void i915_ggtt_unbind_vma(struct i915_vma *vma)
+{
+       const unsigned int first = vma->node.start >> PAGE_SHIFT;
+       const unsigned int size = vma->obj->base.size >> PAGE_SHIFT;
+
+       BUG_ON(!i915_is_ggtt(vma->vm));
+       vma->obj->has_global_gtt_mapping = 0;
+       intel_gtt_clear_range(first, size);
+}
 
-void i915_gem_gtt_bind_object(struct drm_i915_gem_object *obj,
-                             enum i915_cache_level cache_level)
+static void ggtt_bind_vma(struct i915_vma *vma,
+                         enum i915_cache_level cache_level,
+                         u32 flags)
 {
-       struct drm_device *dev = obj->base.dev;
+       struct drm_device *dev = vma->vm->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       const unsigned long entry = i915_gem_obj_ggtt_offset(obj) >> PAGE_SHIFT;
+       struct drm_i915_gem_object *obj = vma->obj;
 
-       dev_priv->gtt.base.insert_entries(&dev_priv->gtt.base, obj->pages,
-                                         entry,
-                                         cache_level);
+       /* If there is no aliasing PPGTT, or the caller needs a global mapping,
+        * or we have a global mapping already but the cacheability flags have
+        * changed, set the global PTEs.
+        *
+        * If there is an aliasing PPGTT it is anecdotally faster, so use that
+        * instead if none of the above hold true.
+        *
+        * NB: A global mapping should only be needed for special regions like
+        * "gtt mappable", SNB errata, or if specified via special execbuf
+        * flags. At all other times, the GPU will use the aliasing PPGTT.
+        */
+       if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) {
+               if (!obj->has_global_gtt_mapping ||
+                   (cache_level != obj->cache_level)) {
+                       vma->vm->insert_entries(vma->vm, obj->pages,
+                                               vma->node.start,
+                                               cache_level);
+                       obj->has_global_gtt_mapping = 1;
+               }
+       }
 
-       obj->has_global_gtt_mapping = 1;
+       if (dev_priv->mm.aliasing_ppgtt &&
+           (!obj->has_aliasing_ppgtt_mapping ||
+            (cache_level != obj->cache_level))) {
+               struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
+               appgtt->base.insert_entries(&appgtt->base,
+                                           vma->obj->pages,
+                                           vma->node.start,
+                                           cache_level);
+               vma->obj->has_aliasing_ppgtt_mapping = 1;
+       }
 }
 
-void i915_gem_gtt_unbind_object(struct drm_i915_gem_object *obj)
+static void ggtt_unbind_vma(struct i915_vma *vma)
 {
-       struct drm_device *dev = obj->base.dev;
+       struct drm_device *dev = vma->vm->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.base.clear_range(&dev_priv->gtt.base,
-                                      entry,
-                                      obj->base.size >> PAGE_SHIFT,
-                                      true);
+       struct drm_i915_gem_object *obj = vma->obj;
+
+       if (obj->has_global_gtt_mapping) {
+               vma->vm->clear_range(vma->vm,
+                                    vma->node.start,
+                                    obj->base.size,
+                                    true);
+               obj->has_global_gtt_mapping = 0;
+       }
 
-       obj->has_global_gtt_mapping = 0;
+       if (obj->has_aliasing_ppgtt_mapping) {
+               struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
+               appgtt->base.clear_range(&appgtt->base,
+                                        vma->node.start,
+                                        obj->base.size,
+                                        true);
+               obj->has_aliasing_ppgtt_mapping = 0;
+       }
 }
 
 void i915_gem_gtt_finish_object(struct drm_i915_gem_object *obj)
@@ -1145,29 +1727,14 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
 
        /* Clear any non-preallocated blocks */
        drm_mm_for_each_hole(entry, &ggtt_vm->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);
-               ggtt_vm->clear_range(ggtt_vm, hole_start / PAGE_SIZE, count, true);
+               ggtt_vm->clear_range(ggtt_vm, hole_start,
+                                    hole_end - hole_start, true);
        }
 
        /* And finally clear the reserved guard page */
-       ggtt_vm->clear_range(ggtt_vm, end / PAGE_SIZE - 1, 1, true);
-}
-
-static bool
-intel_enable_ppgtt(struct drm_device *dev)
-{
-       if (i915_enable_ppgtt >= 0)
-               return i915_enable_ppgtt;
-
-#ifdef CONFIG_INTEL_IOMMU
-       /* Disable ppgtt on SNB if VT-d is on. */
-       if (INTEL_INFO(dev)->gen == 6 && intel_iommu_gfx_mapped)
-               return false;
-#endif
-
-       return true;
+       ggtt_vm->clear_range(ggtt_vm, end - PAGE_SIZE, PAGE_SIZE, true);
 }
 
 void i915_gem_init_global_gtt(struct drm_device *dev)
@@ -1178,26 +1745,6 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
        gtt_size = dev_priv->gtt.base.total;
        mappable_size = dev_priv->gtt.mappable_end;
 
-       if (intel_enable_ppgtt(dev) && HAS_ALIASING_PPGTT(dev)) {
-               int ret;
-
-               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 -= GEN6_PPGTT_PD_ENTRIES * PAGE_SIZE;
-               }
-
-               i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
-
-               ret = i915_gem_init_aliasing_ppgtt(dev);
-               if (!ret)
-                       return;
-
-               DRM_ERROR("Aliased PPGTT setup failed %d\n", ret);
-               drm_mm_takedown(&dev_priv->gtt.base.mm);
-               if (INTEL_INFO(dev)->gen < 8)
-                       gtt_size += GEN6_PPGTT_PD_ENTRIES*PAGE_SIZE;
-       }
        i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
 
@@ -1252,11 +1799,6 @@ static inline unsigned int gen8_get_total_gtt_size(u16 bdw_gmch_ctl)
        bdw_gmch_ctl &= BDW_GMCH_GGMS_MASK;
        if (bdw_gmch_ctl)
                bdw_gmch_ctl = 1 << bdw_gmch_ctl;
-       if (bdw_gmch_ctl > 4) {
-               WARN_ON(!i915_preliminary_hw_support);
-               return 4<<20;
-       }
-
        return bdw_gmch_ctl << 20;
 }
 
@@ -1438,7 +1980,6 @@ static int i915_gmch_probe(struct drm_device *dev,
 
        dev_priv->gtt.do_idle_maps = needs_idle_maps(dev_priv->dev);
        dev_priv->gtt.base.clear_range = i915_ggtt_clear_range;
-       dev_priv->gtt.base.insert_entries = i915_ggtt_insert_entries;
 
        if (unlikely(dev_priv->gtt.do_idle_maps))
                DRM_INFO("applying Ironlake quirks for intel_iommu\n");
@@ -1493,3 +2034,62 @@ int i915_gem_gtt_init(struct drm_device *dev)
 
        return 0;
 }
+
+static 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);
+       INIT_LIST_HEAD(&vma->mm_list);
+       INIT_LIST_HEAD(&vma->exec_list);
+       vma->vm = vm;
+       vma->obj = obj;
+
+       switch (INTEL_INFO(vm->dev)->gen) {
+       case 8:
+       case 7:
+       case 6:
+               if (i915_is_ggtt(vm)) {
+                       vma->unbind_vma = ggtt_unbind_vma;
+                       vma->bind_vma = ggtt_bind_vma;
+               } else {
+                       vma->unbind_vma = ppgtt_unbind_vma;
+                       vma->bind_vma = ppgtt_bind_vma;
+               }
+               break;
+       case 5:
+       case 4:
+       case 3:
+       case 2:
+               BUG_ON(!i915_is_ggtt(vm));
+               vma->unbind_vma = i915_ggtt_unbind_vma;
+               vma->bind_vma = i915_ggtt_bind_vma;
+               break;
+       default:
+               BUG();
+       }
+
+       /* Keep GGTT vmas first to make debug easier */
+       if (i915_is_ggtt(vm))
+               list_add(&vma->vma_link, &obj->vma_list);
+       else
+               list_add_tail(&vma->vma_link, &obj->vma_list);
+
+       return vma;
+}
+
+struct i915_vma *
+i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
+                                 struct i915_address_space *vm)
+{
+       struct i915_vma *vma;
+
+       vma = i915_gem_obj_to_vma(obj, vm);
+       if (!vma)
+               vma = __i915_gem_vma_create(obj, vm);
+
+       return vma;
+}
index 28d24ca..62ef55b 100644 (file)
@@ -215,7 +215,7 @@ int i915_gem_init_stolen(struct drm_device *dev)
        int bios_reserved = 0;
 
 #ifdef CONFIG_INTEL_IOMMU
-       if (intel_iommu_gfx_mapped) {
+       if (intel_iommu_gfx_mapped && INTEL_INFO(dev)->gen < 8) {
                DRM_INFO("DMAR active, disabling use of stolen memory\n");
                return 0;
        }
index b139053..cb150e8 100644 (file)
@@ -87,7 +87,7 @@
 void
 i915_gem_detect_bit_6_swizzle(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t swizzle_x = I915_BIT_6_SWIZZLE_UNKNOWN;
        uint32_t swizzle_y = I915_BIT_6_SWIZZLE_UNKNOWN;
 
@@ -294,7 +294,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                   struct drm_file *file)
 {
        struct drm_i915_gem_set_tiling *args = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
        int ret = 0;
 
@@ -308,7 +308,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       if (obj->pin_count || obj->framebuffer_references) {
+       if (i915_gem_obj_is_pinned(obj) || obj->framebuffer_references) {
                drm_gem_object_unreference_unlocked(&obj->base);
                return -EBUSY;
        }
@@ -415,7 +415,7 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
                   struct drm_file *file)
 {
        struct drm_i915_gem_get_tiling *args = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj;
 
        obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
index 990cf8f..12f1d43 100644 (file)
@@ -238,50 +238,61 @@ static const char *hangcheck_action_to_str(enum intel_ring_hangcheck_action a)
 
 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)
+                                 struct drm_i915_error_ring *ring)
 {
-       BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */
-       if (!error->ring[ring].valid)
+       if (!ring->valid)
                return;
 
-       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]);
+       err_printf(m, "  HEAD: 0x%08x\n", ring->head);
+       err_printf(m, "  TAIL: 0x%08x\n", ring->tail);
+       err_printf(m, "  CTL: 0x%08x\n", ring->ctl);
+       err_printf(m, "  HWS: 0x%08x\n", ring->hws);
+       err_printf(m, "  ACTHD: 0x%08x %08x\n", (u32)(ring->acthd>>32), (u32)ring->acthd);
+       err_printf(m, "  IPEIR: 0x%08x\n", ring->ipeir);
+       err_printf(m, "  IPEHR: 0x%08x\n", ring->ipehr);
+       err_printf(m, "  INSTDONE: 0x%08x\n", ring->instdone);
        if (INTEL_INFO(dev)->gen >= 4) {
-               err_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr[ring]);
-               err_printf(m, "  BB_STATE: 0x%08x\n", error->bbstate[ring]);
-               err_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
+               err_printf(m, "  BBADDR: 0x%08x %08x\n", (u32)(ring->bbaddr>>32), (u32)ring->bbaddr);
+               err_printf(m, "  BB_STATE: 0x%08x\n", ring->bbstate);
+               err_printf(m, "  INSTPS: 0x%08x\n", ring->instps);
        }
-       err_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
-       err_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
+       err_printf(m, "  INSTPM: 0x%08x\n", ring->instpm);
+       err_printf(m, "  FADDR: 0x%08x\n", ring->faddr);
        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, "  RC PSMI: 0x%08x\n", ring->rc_psmi);
+               err_printf(m, "  FAULT_REG: 0x%08x\n", ring->fault_reg);
                err_printf(m, "  SYNC_0: 0x%08x [last synced 0x%08x]\n",
-                          error->semaphore_mboxes[ring][0],
-                          error->semaphore_seqno[ring][0]);
+                          ring->semaphore_mboxes[0],
+                          ring->semaphore_seqno[0]);
                err_printf(m, "  SYNC_1: 0x%08x [last synced 0x%08x]\n",
-                          error->semaphore_mboxes[ring][1],
-                          error->semaphore_seqno[ring][1]);
+                          ring->semaphore_mboxes[1],
+                          ring->semaphore_seqno[1]);
                if (HAS_VEBOX(dev)) {
                        err_printf(m, "  SYNC_2: 0x%08x [last synced 0x%08x]\n",
-                                  error->semaphore_mboxes[ring][2],
-                                  error->semaphore_seqno[ring][2]);
+                                  ring->semaphore_mboxes[2],
+                                  ring->semaphore_seqno[2]);
                }
        }
-       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]);
+       if (USES_PPGTT(dev)) {
+               err_printf(m, "  GFX_MODE: 0x%08x\n", ring->vm_info.gfx_mode);
+
+               if (INTEL_INFO(dev)->gen >= 8) {
+                       int i;
+                       for (i = 0; i < 4; i++)
+                               err_printf(m, "  PDP%d: 0x%016llx\n",
+                                          i, ring->vm_info.pdp[i]);
+               } else {
+                       err_printf(m, "  PP_DIR_BASE: 0x%08x\n",
+                                  ring->vm_info.pp_dir_base);
+               }
+       }
+       err_printf(m, "  seqno: 0x%08x\n", ring->seqno);
+       err_printf(m, "  waiting: %s\n", yesno(ring->waiting));
+       err_printf(m, "  ring->head: 0x%08x\n", ring->cpu_ring_head);
+       err_printf(m, "  ring->tail: 0x%08x\n", ring->cpu_ring_tail);
        err_printf(m, "  hangcheck: %s [%d]\n",
-                  hangcheck_action_to_str(error->hangcheck_action[ring]),
-                  error->hangcheck_score[ring]);
+                  hangcheck_action_to_str(ring->hangcheck_action),
+                  ring->hangcheck_score);
 }
 
 void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
@@ -293,22 +304,54 @@ void i915_error_printf(struct drm_i915_error_state_buf *e, const char *f, ...)
        va_end(args);
 }
 
+static void print_error_obj(struct drm_i915_error_state_buf *m,
+                           struct drm_i915_error_object *obj)
+{
+       int page, offset, elt;
+
+       for (page = offset = 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;
+               }
+       }
+}
+
 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_private *dev_priv = dev->dev_private;
        struct drm_i915_error_state *error = error_priv->error;
-       int i, j, page, offset, elt;
+       int i, j, offset, elt;
+       int max_hangcheck_score;
 
        if (!error) {
                err_printf(m, "no error state collected\n");
                goto out;
        }
 
+       err_printf(m, "%s\n", error->error_msg);
        err_printf(m, "Time: %ld s %ld us\n", error->time.tv_sec,
                   error->time.tv_usec);
        err_printf(m, "Kernel: " UTS_RELEASE "\n");
+       max_hangcheck_score = 0;
+       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+               if (error->ring[i].hangcheck_score > max_hangcheck_score)
+                       max_hangcheck_score = error->ring[i].hangcheck_score;
+       }
+       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+               if (error->ring[i].hangcheck_score == max_hangcheck_score &&
+                   error->ring[i].pid != -1) {
+                       err_printf(m, "Active process (on ring %s): %s [%d]\n",
+                                  ring_str(i),
+                                  error->ring[i].comm,
+                                  error->ring[i].pid);
+               }
+       }
+       err_printf(m, "Reset count: %u\n", error->reset_count);
+       err_printf(m, "Suspend count: %u\n", error->suspend_count);
        err_printf(m, "PCI ID: 0x%04x\n", dev->pdev->device);
        err_printf(m, "EIR: 0x%08x\n", error->eir);
        err_printf(m, "IER: 0x%08x\n", error->ier);
@@ -333,8 +376,10 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        if (INTEL_INFO(dev)->gen == 7)
                err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
 
-       for (i = 0; i < ARRAY_SIZE(error->ring); i++)
-               i915_ring_error_state(m, dev, error, i);
+       for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
+               err_printf(m, "%s command stream:\n", ring_str(i));
+               i915_ring_error_state(m, dev, &error->ring[i]);
+       }
 
        if (error->active_bo)
                print_error_buffers(m, "Active",
@@ -349,18 +394,23 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        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 = error->ring[i].batchbuffer;
+               if (obj) {
+                       err_puts(m, dev_priv->ring[i].name);
+                       if (error->ring[i].pid != -1)
+                               err_printf(m, " (submitted by %s [%d])",
+                                          error->ring[i].comm,
+                                          error->ring[i].pid);
+                       err_printf(m, " --- gtt_offset = 0x%08x\n",
                                   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;
-                               }
-                       }
+                       print_error_obj(m, obj);
+               }
+
+               obj = error->ring[i].wa_batchbuffer;
+               if (obj) {
+                       err_printf(m, "%s (w/a) --- gtt_offset = 0x%08x\n",
+                                  dev_priv->ring[i].name, obj->gtt_offset);
+                       print_error_obj(m, obj);
                }
 
                if (error->ring[i].num_requests) {
@@ -379,14 +429,22 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                        err_printf(m, "%s --- ringbuffer = 0x%08x\n",
                                   dev_priv->ring[i].name,
                                   obj->gtt_offset);
+                       print_error_obj(m, obj);
+               }
+
+               if ((obj = error->ring[i].hws_page)) {
+                       err_printf(m, "%s --- HW Status = 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;
-                               }
+                       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;
                        }
                }
 
@@ -472,6 +530,7 @@ static void i915_error_state_free(struct kref *error_ref)
        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].hws_page);
                i915_error_object_free(error->ring[i].ctx);
                kfree(error->ring[i].requests);
        }
@@ -485,6 +544,7 @@ static void i915_error_state_free(struct kref *error_ref)
 static struct drm_i915_error_object *
 i915_error_object_create_sized(struct drm_i915_private *dev_priv,
                               struct drm_i915_gem_object *src,
+                              struct i915_address_space *vm,
                               const int num_pages)
 {
        struct drm_i915_error_object *dst;
@@ -498,7 +558,7 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
        if (dst == NULL)
                return NULL;
 
-       reloc_offset = dst->gtt_offset = i915_gem_obj_ggtt_offset(src);
+       reloc_offset = dst->gtt_offset = i915_gem_obj_offset(src, vm);
        for (i = 0; i < num_pages; i++) {
                unsigned long flags;
                void *d;
@@ -508,8 +568,10 @@ i915_error_object_create_sized(struct drm_i915_private *dev_priv,
                        goto unwind;
 
                local_irq_save(flags);
-               if (reloc_offset < dev_priv->gtt.mappable_end &&
-                   src->has_global_gtt_mapping) {
+               if (src->cache_level == I915_CACHE_NONE &&
+                   reloc_offset < dev_priv->gtt.mappable_end &&
+                   src->has_global_gtt_mapping &&
+                   i915_is_ggtt(vm)) {
                        void __iomem *s;
 
                        /* Simply ignore tiling or any overlapping fence.
@@ -559,8 +621,12 @@ unwind:
        kfree(dst);
        return NULL;
 }
-#define i915_error_object_create(dev_priv, src) \
-       i915_error_object_create_sized((dev_priv), (src), \
+#define i915_error_object_create(dev_priv, src, vm) \
+       i915_error_object_create_sized((dev_priv), (src), (vm), \
+                                      (src)->base.size>>PAGE_SHIFT)
+
+#define i915_error_ggtt_object_create(dev_priv, src) \
+       i915_error_object_create_sized((dev_priv), (src), &(dev_priv)->gtt.base, \
                                       (src)->base.size>>PAGE_SHIFT)
 
 static void capture_bo(struct drm_i915_error_buffer *err,
@@ -575,7 +641,7 @@ static void capture_bo(struct drm_i915_error_buffer *err,
        err->write_domain = obj->base.write_domain;
        err->fence_reg = obj->fence_reg;
        err->pinned = 0;
-       if (obj->pin_count > 0)
+       if (i915_gem_obj_is_pinned(obj))
                err->pinned = 1;
        if (obj->user_pin_count > 0)
                err->pinned = -1;
@@ -608,7 +674,7 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
        int i = 0;
 
        list_for_each_entry(obj, head, global_list) {
-               if (obj->pin_count == 0)
+               if (!i915_gem_obj_is_pinned(obj))
                        continue;
 
                capture_bo(err++, obj);
@@ -619,6 +685,39 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
        return i;
 }
 
+/* Generate a semi-unique error code. The code is not meant to have meaning, The
+ * code's only purpose is to try to prevent false duplicated bug reports by
+ * grossly estimating a GPU error state.
+ *
+ * TODO Ideally, hashing the batchbuffer would be a very nice way to determine
+ * the hang if we could strip the GTT offset information from it.
+ *
+ * It's only a small step better than a random number in its current form.
+ */
+static uint32_t i915_error_generate_code(struct drm_i915_private *dev_priv,
+                                        struct drm_i915_error_state *error,
+                                        int *ring_id)
+{
+       uint32_t error_code = 0;
+       int i;
+
+       /* IPEHR would be an ideal way to detect errors, as it's the gross
+        * measure of "the command that hung." However, has some very common
+        * synchronization commands which almost always appear in the case
+        * strictly a client bug. Use instdone to differentiate those some.
+        */
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               if (error->ring[i].hangcheck_action == HANGCHECK_HUNG) {
+                       if (ring_id)
+                               *ring_id = i;
+
+                       return error->ring[i].ipehr ^ error->ring[i].instdone;
+               }
+       }
+
+       return error_code;
+}
+
 static void i915_gem_record_fences(struct drm_device *dev,
                                   struct drm_i915_error_state *error)
 {
@@ -652,107 +751,114 @@ static void i915_gem_record_fences(struct drm_device *dev,
        }
 }
 
-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;
-       struct i915_vma *vma;
-       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->scratch.obj;
-               if (obj != NULL &&
-                   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(vm, &dev_priv->vm_list, global_link) {
-               list_for_each_entry(vma, &vm->active_list, mm_list) {
-                       obj = vma->obj;
-                       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 intel_ring_buffer *ring,
+                                  struct drm_i915_error_ring *ering)
 {
        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]
+               ering->rc_psmi = I915_READ(ring->mmio_base + 0x50);
+               ering->fault_reg = I915_READ(RING_FAULT_REG(ring));
+               ering->semaphore_mboxes[0]
                        = I915_READ(RING_SYNC_0(ring->mmio_base));
-               error->semaphore_mboxes[ring->id][1]
+               ering->semaphore_mboxes[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];
+               ering->semaphore_seqno[0] = ring->sync_seqno[0];
+               ering->semaphore_seqno[1] = ring->sync_seqno[1];
        }
 
        if (HAS_VEBOX(dev)) {
-               error->semaphore_mboxes[ring->id][2] =
+               ering->semaphore_mboxes[2] =
                        I915_READ(RING_SYNC_2(ring->mmio_base));
-               error->semaphore_seqno[ring->id][2] = ring->sync_seqno[2];
+               ering->semaphore_seqno[2] = ring->sync_seqno[2];
        }
 
        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));
-               error->bbaddr[ring->id] = I915_READ(RING_BBADDR(ring->mmio_base));
+               ering->faddr = I915_READ(RING_DMA_FADD(ring->mmio_base));
+               ering->ipeir = I915_READ(RING_IPEIR(ring->mmio_base));
+               ering->ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
+               ering->instdone = I915_READ(RING_INSTDONE(ring->mmio_base));
+               ering->instps = I915_READ(RING_INSTPS(ring->mmio_base));
+               ering->bbaddr = I915_READ(RING_BBADDR(ring->mmio_base));
                if (INTEL_INFO(dev)->gen >= 8)
-                       error->bbaddr[ring->id] |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32;
-               error->bbstate[ring->id] = I915_READ(RING_BBSTATE(ring->mmio_base));
+                       ering->bbaddr |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32;
+               ering->bbstate = I915_READ(RING_BBSTATE(ring->mmio_base));
        } 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);
+               ering->faddr = I915_READ(DMA_FADD_I8XX);
+               ering->ipeir = I915_READ(IPEIR);
+               ering->ipehr = I915_READ(IPEHR);
+               ering->instdone = I915_READ(INSTDONE);
+       }
+
+       ering->waiting = waitqueue_active(&ring->irq_queue);
+       ering->instpm = I915_READ(RING_INSTPM(ring->mmio_base));
+       ering->seqno = ring->get_seqno(ring, false);
+       ering->acthd = intel_ring_get_active_head(ring);
+       ering->head = I915_READ_HEAD(ring);
+       ering->tail = I915_READ_TAIL(ring);
+       ering->ctl = I915_READ_CTL(ring);
+
+       if (I915_NEED_GFX_HWS(dev)) {
+               int mmio;
+
+               if (IS_GEN7(dev)) {
+                       switch (ring->id) {
+                       default:
+                       case RCS:
+                               mmio = RENDER_HWS_PGA_GEN7;
+                               break;
+                       case BCS:
+                               mmio = BLT_HWS_PGA_GEN7;
+                               break;
+                       case VCS:
+                               mmio = BSD_HWS_PGA_GEN7;
+                               break;
+                       case VECS:
+                               mmio = VEBOX_HWS_PGA_GEN7;
+                               break;
+                       }
+               } else if (IS_GEN6(ring->dev)) {
+                       mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
+               } else {
+                       /* XXX: gen8 returns to sanity */
+                       mmio = RING_HWS_PGA(ring->mmio_base);
+               }
+
+               ering->hws = I915_READ(mmio);
        }
 
-       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);
+       ering->cpu_ring_head = ring->head;
+       ering->cpu_ring_tail = ring->tail;
+
+       ering->hangcheck_score = ring->hangcheck.score;
+       ering->hangcheck_action = ring->hangcheck.action;
+
+       if (USES_PPGTT(dev)) {
+               int i;
 
-       error->cpu_ring_head[ring->id] = ring->head;
-       error->cpu_ring_tail[ring->id] = ring->tail;
+               ering->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(ring));
 
-       error->hangcheck_score[ring->id] = ring->hangcheck.score;
-       error->hangcheck_action[ring->id] = ring->hangcheck.action;
+               switch (INTEL_INFO(dev)->gen) {
+               case 8:
+                       for (i = 0; i < 4; i++) {
+                               ering->vm_info.pdp[i] =
+                                       I915_READ(GEN8_RING_PDP_UDW(ring, i));
+                               ering->vm_info.pdp[i] <<= 32;
+                               ering->vm_info.pdp[i] |=
+                                       I915_READ(GEN8_RING_PDP_LDW(ring, i));
+                       }
+                       break;
+               case 7:
+                       ering->vm_info.pp_dir_base =
+                               I915_READ(RING_PP_DIR_BASE(ring));
+                       break;
+               case 6:
+                       ering->vm_info.pp_dir_base =
+                               I915_READ(RING_PP_DIR_BASE_READ(ring));
+                       break;
+               }
+       }
 }
 
 
@@ -770,7 +876,9 @@ static void i915_gem_record_active_context(struct intel_ring_buffer *ring,
        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);
+                                                                   obj,
+                                                                   &dev_priv->gtt.base,
+                                                                   1);
                        break;
                }
        }
@@ -791,14 +899,48 @@ static void i915_gem_record_rings(struct drm_device *dev,
 
                error->ring[i].valid = true;
 
-               i915_record_ring_state(dev, error, ring);
+               i915_record_ring_state(dev, ring, &error->ring[i]);
 
-               error->ring[i].batchbuffer =
-                       i915_error_first_batchbuffer(dev_priv, ring);
+               error->ring[i].pid = -1;
+               request = i915_gem_find_active_request(ring);
+               if (request) {
+                       /* We need to copy these to an anonymous buffer
+                        * as the simplest method to avoid being overwritten
+                        * by userspace.
+                        */
+                       error->ring[i].batchbuffer =
+                               i915_error_object_create(dev_priv,
+                                                        request->batch_obj,
+                                                        request->ctx ?
+                                                        request->ctx->vm :
+                                                        &dev_priv->gtt.base);
+
+                       if (HAS_BROKEN_CS_TLB(dev_priv->dev) &&
+                           ring->scratch.obj)
+                               error->ring[i].wa_batchbuffer =
+                                       i915_error_ggtt_object_create(dev_priv,
+                                                            ring->scratch.obj);
+
+                       if (request->file_priv) {
+                               struct task_struct *task;
+
+                               rcu_read_lock();
+                               task = pid_task(request->file_priv->file->pid,
+                                               PIDTYPE_PID);
+                               if (task) {
+                                       strcpy(error->ring[i].comm, task->comm);
+                                       error->ring[i].pid = task->pid;
+                               }
+                               rcu_read_unlock();
+                       }
+               }
 
                error->ring[i].ringbuffer =
-                       i915_error_object_create(dev_priv, ring->obj);
+                       i915_error_ggtt_object_create(dev_priv, ring->obj);
 
+               if (ring->status_page.obj)
+                       error->ring[i].hws_page =
+                               i915_error_ggtt_object_create(dev_priv, ring->status_page.obj);
 
                i915_gem_record_active_context(ring, error, &error->ring[i]);
 
@@ -845,7 +987,7 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
                i++;
        error->active_bo_count[ndx] = i;
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
-               if (obj->pin_count)
+               if (i915_gem_obj_is_pinned(obj))
                        i++;
        error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx];
 
@@ -879,11 +1021,6 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
        list_for_each_entry(vm, &dev_priv->vm_list, global_link)
                cnt++;
 
-       if (WARN(cnt > 1, "Multiple VMs not yet supported\n"))
-               cnt = 1;
-
-       vm = &dev_priv->gtt.base;
-
        error->active_bo = kcalloc(cnt, sizeof(*error->active_bo), GFP_ATOMIC);
        error->pinned_bo = kcalloc(cnt, sizeof(*error->pinned_bo), GFP_ATOMIC);
        error->active_bo_count = kcalloc(cnt, sizeof(*error->active_bo_count),
@@ -895,6 +1032,108 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
                i915_gem_capture_vm(dev_priv, error, vm, i++);
 }
 
+/* Capture all registers which don't fit into another category. */
+static void i915_capture_reg_state(struct drm_i915_private *dev_priv,
+                                  struct drm_i915_error_state *error)
+{
+       struct drm_device *dev = dev_priv->dev;
+       int pipe;
+
+       /* General organization
+        * 1. Registers specific to a single generation
+        * 2. Registers which belong to multiple generations
+        * 3. Feature specific registers.
+        * 4. Everything else
+        * Please try to follow the order.
+        */
+
+       /* 1: Registers specific to a single generation */
+       if (IS_VALLEYVIEW(dev)) {
+               error->ier = I915_READ(GTIER) | I915_READ(VLV_IER);
+               error->forcewake = I915_READ(FORCEWAKE_VLV);
+       }
+
+       if (IS_GEN7(dev))
+               error->err_int = I915_READ(GEN7_ERR_INT);
+
+       if (IS_GEN6(dev)) {
+               error->forcewake = I915_READ(FORCEWAKE);
+               error->gab_ctl = I915_READ(GAB_CTL);
+               error->gfx_mode = I915_READ(GFX_MODE);
+       }
+
+       if (IS_GEN2(dev))
+               error->ier = I915_READ16(IER);
+
+       /* 2: Registers which belong to multiple generations */
+       if (INTEL_INFO(dev)->gen >= 7)
+               error->forcewake = I915_READ(FORCEWAKE_MT);
+
+       if (INTEL_INFO(dev)->gen >= 6) {
+               error->derrmr = I915_READ(DERRMR);
+               error->error = I915_READ(ERROR_GEN6);
+               error->done_reg = I915_READ(DONE_REG);
+       }
+
+       /* 3: Feature specific registers */
+       if (IS_GEN6(dev) || IS_GEN7(dev)) {
+               error->gam_ecochk = I915_READ(GAM_ECOCHK);
+               error->gac_eco = I915_READ(GAC_ECO_BITS);
+       }
+
+       /* 4: Everything else */
+       if (HAS_HW_CONTEXTS(dev))
+               error->ccid = I915_READ(CCID);
+
+       if (HAS_PCH_SPLIT(dev))
+               error->ier = I915_READ(DEIER) | I915_READ(GTIER);
+       else {
+               error->ier = I915_READ(IER);
+               for_each_pipe(pipe)
+                       error->pipestat[pipe] = I915_READ(PIPESTAT(pipe));
+       }
+
+       /* 4: Everything else */
+       error->eir = I915_READ(EIR);
+       error->pgtbl_er = I915_READ(PGTBL_ER);
+
+       i915_get_extra_instdone(dev, error->extra_instdone);
+}
+
+static void i915_error_capture_msg(struct drm_device *dev,
+                                  struct drm_i915_error_state *error,
+                                  bool wedged,
+                                  const char *error_msg)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 ecode;
+       int ring_id = -1, len;
+
+       ecode = i915_error_generate_code(dev_priv, error, &ring_id);
+
+       len = scnprintf(error->error_msg, sizeof(error->error_msg),
+                       "GPU HANG: ecode %d:0x%08x", ring_id, ecode);
+
+       if (ring_id != -1 && error->ring[ring_id].pid != -1)
+               len += scnprintf(error->error_msg + len,
+                                sizeof(error->error_msg) - len,
+                                ", in %s [%d]",
+                                error->ring[ring_id].comm,
+                                error->ring[ring_id].pid);
+
+       scnprintf(error->error_msg + len, sizeof(error->error_msg) - len,
+                 ", reason: %s, action: %s",
+                 error_msg,
+                 wedged ? "reset" : "continue");
+}
+
+static void i915_capture_gen_state(struct drm_i915_private *dev_priv,
+                                  struct drm_i915_error_state *error)
+{
+       error->reset_count = i915_reset_count(&dev_priv->gpu_error);
+       error->suspend_count = dev_priv->suspend_count;
+}
+
 /**
  * i915_capture_error_state - capture an error record for later analysis
  * @dev: drm device
@@ -904,18 +1143,13 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
  * out a structure which becomes available in debugfs for user level tools
  * to pick up.
  */
-void i915_capture_error_state(struct drm_device *dev)
+void i915_capture_error_state(struct drm_device *dev, bool wedged,
+                             const char *error_msg)
 {
+       static bool warned;
        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);
@@ -924,52 +1158,10 @@ void i915_capture_error_state(struct drm_device *dev)
                return;
        }
 
-       DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n",
-                dev->primary->index);
-       DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n");
-       DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n");
-       DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n");
-       DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n");
-
        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_capture_gen_state(dev_priv, error);
+       i915_capture_reg_state(dev_priv, error);
        i915_gem_capture_buffers(dev_priv, error);
        i915_gem_record_fences(dev, error);
        i915_gem_record_rings(dev, error);
@@ -979,6 +1171,9 @@ void i915_capture_error_state(struct drm_device *dev)
        error->overlay = intel_overlay_capture_error_state(dev);
        error->display = intel_display_capture_error_state(dev);
 
+       i915_error_capture_msg(dev, error, wedged, error_msg);
+       DRM_INFO("%s\n", error->error_msg);
+
        spin_lock_irqsave(&dev_priv->gpu_error.lock, flags);
        if (dev_priv->gpu_error.first_error == NULL) {
                dev_priv->gpu_error.first_error = error;
@@ -986,8 +1181,19 @@ void i915_capture_error_state(struct drm_device *dev)
        }
        spin_unlock_irqrestore(&dev_priv->gpu_error.lock, flags);
 
-       if (error)
+       if (error) {
                i915_error_state_free(&error->ref);
+               return;
+       }
+
+       if (!warned) {
+               DRM_INFO("GPU hangs can indicate a bug anywhere in the entire gfx stack, including userspace.\n");
+               DRM_INFO("Please file a _new_ bug report on bugs.freedesktop.org against DRI -> DRM/Intel\n");
+               DRM_INFO("drm/i915 developers can then reassign to the right component if it's not a kernel issue.\n");
+               DRM_INFO("The gpu crash dump is required to analyze gpu hangs, so please always attach it.\n");
+               DRM_INFO("GPU crash dump saved to /sys/class/drm/card%d/error\n", dev->primary->index);
+               warned = true;
+       }
 }
 
 void i915_error_state_get(struct drm_device *dev,
index d554169..7753249 100644 (file)
@@ -82,13 +82,13 @@ static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
 
 /* For display hotplug interrupt */
 static void
-ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
+ironlake_enable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pc8.irqs_disabled) {
+       if (dev_priv->pm.irqs_disabled) {
                WARN(1, "IRQs disabled\n");
-               dev_priv->pc8.regsave.deimr &= ~mask;
+               dev_priv->pm.regsave.deimr &= ~mask;
                return;
        }
 
@@ -100,13 +100,13 @@ ironlake_enable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
 }
 
 static void
-ironlake_disable_display_irq(drm_i915_private_t *dev_priv, u32 mask)
+ironlake_disable_display_irq(struct drm_i915_private *dev_priv, u32 mask)
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pc8.irqs_disabled) {
+       if (dev_priv->pm.irqs_disabled) {
                WARN(1, "IRQs disabled\n");
-               dev_priv->pc8.regsave.deimr |= mask;
+               dev_priv->pm.regsave.deimr |= mask;
                return;
        }
 
@@ -129,10 +129,10 @@ static void ilk_update_gt_irq(struct drm_i915_private *dev_priv,
 {
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pc8.irqs_disabled) {
+       if (dev_priv->pm.irqs_disabled) {
                WARN(1, "IRQs disabled\n");
-               dev_priv->pc8.regsave.gtimr &= ~interrupt_mask;
-               dev_priv->pc8.regsave.gtimr |= (~enabled_irq_mask &
+               dev_priv->pm.regsave.gtimr &= ~interrupt_mask;
+               dev_priv->pm.regsave.gtimr |= (~enabled_irq_mask &
                                                interrupt_mask);
                return;
        }
@@ -167,10 +167,10 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pc8.irqs_disabled) {
+       if (dev_priv->pm.irqs_disabled) {
                WARN(1, "IRQs disabled\n");
-               dev_priv->pc8.regsave.gen6_pmimr &= ~interrupt_mask;
-               dev_priv->pc8.regsave.gen6_pmimr |= (~enabled_irq_mask &
+               dev_priv->pm.regsave.gen6_pmimr &= ~interrupt_mask;
+               dev_priv->pm.regsave.gen6_pmimr |= (~enabled_irq_mask &
                                                     interrupt_mask);
                return;
        }
@@ -232,6 +232,18 @@ static bool cpt_can_enable_serr_int(struct drm_device *dev)
        return true;
 }
 
+static void i9xx_clear_fifo_underrun(struct drm_device *dev, enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 reg = PIPESTAT(pipe);
+       u32 pipestat = I915_READ(reg) & 0x7fff0000;
+
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       I915_WRITE(reg, pipestat | PIPE_FIFO_UNDERRUN_STATUS);
+       POSTING_READ(reg);
+}
+
 static void ironlake_set_fifo_underrun_reporting(struct drm_device *dev,
                                                 enum pipe pipe, bool enable)
 {
@@ -301,11 +313,11 @@ static void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if (dev_priv->pc8.irqs_disabled &&
+       if (dev_priv->pm.irqs_disabled &&
            (interrupt_mask & SDE_HOTPLUG_MASK_CPT)) {
                WARN(1, "IRQs disabled\n");
-               dev_priv->pc8.regsave.sdeimr &= ~interrupt_mask;
-               dev_priv->pc8.regsave.sdeimr |= (~enabled_irq_mask &
+               dev_priv->pm.regsave.sdeimr &= ~interrupt_mask;
+               dev_priv->pm.regsave.sdeimr |= (~enabled_irq_mask &
                                                 interrupt_mask);
                return;
        }
@@ -375,16 +387,15 @@ static void cpt_set_fifo_underrun_reporting(struct drm_device *dev,
  *
  * Returns the previous state of underrun reporting.
  */
-bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
-                                          enum pipe pipe, bool enable)
+bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+                                            enum pipe pipe, bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       unsigned long flags;
        bool ret;
 
-       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       assert_spin_locked(&dev_priv->irq_lock);
 
        ret = !intel_crtc->cpu_fifo_underrun_disabled;
 
@@ -393,7 +404,9 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
 
        intel_crtc->cpu_fifo_underrun_disabled = !enable;
 
-       if (IS_GEN5(dev) || IS_GEN6(dev))
+       if (enable && (INTEL_INFO(dev)->gen < 5 || IS_VALLEYVIEW(dev)))
+               i9xx_clear_fifo_underrun(dev, pipe);
+       else 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, pipe, enable);
@@ -401,10 +414,33 @@ bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
                broadwell_set_fifo_underrun_reporting(dev, pipe, enable);
 
 done:
+       return ret;
+}
+
+bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+                                          enum pipe pipe, bool enable)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+       bool ret;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       ret = __intel_set_cpu_fifo_underrun_reporting(dev, pipe, enable);
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
        return ret;
 }
 
+static bool __cpu_fifo_underrun_reporting_enabled(struct drm_device *dev,
+                                                 enum pipe pipe)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       return !intel_crtc->cpu_fifo_underrun_disabled;
+}
+
 /**
  * intel_set_pch_fifo_underrun_reporting - enable/disable FIFO underrun messages
  * @dev: drm device
@@ -458,45 +494,109 @@ done:
 }
 
 
-void
-i915_enable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask)
+static void
+__i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                      u32 enable_mask, u32 status_mask)
 {
        u32 reg = PIPESTAT(pipe);
-       u32 pipestat = I915_READ(reg) & 0x7fff0000;
+       u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if ((pipestat & mask) == mask)
+       if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
+                        status_mask & ~PIPESTAT_INT_STATUS_MASK))
                return;
 
+       if ((pipestat & enable_mask) == enable_mask)
+               return;
+
+       dev_priv->pipestat_irq_mask[pipe] |= status_mask;
+
        /* Enable the interrupt, clear any pending status */
-       pipestat |= mask | (mask >> 16);
+       pipestat |= enable_mask | status_mask;
        I915_WRITE(reg, pipestat);
        POSTING_READ(reg);
 }
 
-void
-i915_disable_pipestat(drm_i915_private_t *dev_priv, enum pipe pipe, u32 mask)
+static void
+__i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                       u32 enable_mask, u32 status_mask)
 {
        u32 reg = PIPESTAT(pipe);
-       u32 pipestat = I915_READ(reg) & 0x7fff0000;
+       u32 pipestat = I915_READ(reg) & PIPESTAT_INT_ENABLE_MASK;
 
        assert_spin_locked(&dev_priv->irq_lock);
 
-       if ((pipestat & mask) == 0)
+       if (WARN_ON_ONCE(enable_mask & ~PIPESTAT_INT_ENABLE_MASK ||
+                        status_mask & ~PIPESTAT_INT_STATUS_MASK))
+               return;
+
+       if ((pipestat & enable_mask) == 0)
                return;
 
-       pipestat &= ~mask;
+       dev_priv->pipestat_irq_mask[pipe] &= ~status_mask;
+
+       pipestat &= ~enable_mask;
        I915_WRITE(reg, pipestat);
        POSTING_READ(reg);
 }
 
+static u32 vlv_get_pipestat_enable_mask(struct drm_device *dev, u32 status_mask)
+{
+       u32 enable_mask = status_mask << 16;
+
+       /*
+        * On pipe A we don't support the PSR interrupt yet, on pipe B the
+        * same bit MBZ.
+        */
+       if (WARN_ON_ONCE(status_mask & PIPE_A_PSR_STATUS_VLV))
+               return 0;
+
+       enable_mask &= ~(PIPE_FIFO_UNDERRUN_STATUS |
+                        SPRITE0_FLIP_DONE_INT_EN_VLV |
+                        SPRITE1_FLIP_DONE_INT_EN_VLV);
+       if (status_mask & SPRITE0_FLIP_DONE_INT_STATUS_VLV)
+               enable_mask |= SPRITE0_FLIP_DONE_INT_EN_VLV;
+       if (status_mask & SPRITE1_FLIP_DONE_INT_STATUS_VLV)
+               enable_mask |= SPRITE1_FLIP_DONE_INT_EN_VLV;
+
+       return enable_mask;
+}
+
+void
+i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                    u32 status_mask)
+{
+       u32 enable_mask;
+
+       if (IS_VALLEYVIEW(dev_priv->dev))
+               enable_mask = vlv_get_pipestat_enable_mask(dev_priv->dev,
+                                                          status_mask);
+       else
+               enable_mask = status_mask << 16;
+       __i915_enable_pipestat(dev_priv, pipe, enable_mask, status_mask);
+}
+
+void
+i915_disable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
+                     u32 status_mask)
+{
+       u32 enable_mask;
+
+       if (IS_VALLEYVIEW(dev_priv->dev))
+               enable_mask = vlv_get_pipestat_enable_mask(dev_priv->dev,
+                                                          status_mask);
+       else
+               enable_mask = status_mask << 16;
+       __i915_disable_pipestat(dev_priv, pipe, enable_mask, status_mask);
+}
+
 /**
  * i915_enable_asle_pipestat - enable ASLE pipestat for OpRegion
  */
 static void i915_enable_asle_pipestat(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
        if (!dev_priv->opregion.asle || !IS_MOBILE(dev))
@@ -504,10 +604,10 @@ static void i915_enable_asle_pipestat(struct drm_device *dev)
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
-       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_LEGACY_BLC_EVENT_STATUS);
        if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, PIPE_A,
-                                    PIPE_LEGACY_BLC_EVENT_ENABLE);
+                                    PIPE_LEGACY_BLC_EVENT_STATUS);
 
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
@@ -524,7 +624,7 @@ static void i915_enable_asle_pipestat(struct drm_device *dev)
 static int
 i915_pipe_enabled(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                /* Locking is horribly broken here, but whatever. */
@@ -548,7 +648,7 @@ static u32 i8xx_get_vblank_counter(struct drm_device *dev, int pipe)
  */
 static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long high_frame;
        unsigned long low_frame;
        u32 high1, high2, low, pixel, vbl_start;
@@ -604,7 +704,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
 
 static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int reg = PIPE_FRMCOUNT_GM45(pipe);
 
        if (!i915_pipe_enabled(dev, pipe)) {
@@ -859,8 +959,8 @@ static bool intel_hpd_irq_event(struct drm_device *dev,
 
 static void i915_hotplug_work_func(struct work_struct *work)
 {
-       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
-                                                   hotplug_work);
+       struct drm_i915_private *dev_priv =
+               container_of(work, struct drm_i915_private, hotplug_work);
        struct drm_device *dev = dev_priv->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_connector *intel_connector;
@@ -928,9 +1028,14 @@ static void i915_hotplug_work_func(struct work_struct *work)
                drm_kms_helper_hotplug_event(dev);
 }
 
+static void intel_hpd_irq_uninstall(struct drm_i915_private *dev_priv)
+{
+       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+}
+
 static void ironlake_rps_change_irq_handler(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 busy_up, busy_down, max_avg, min_avg;
        u8 new_delay;
 
@@ -981,8 +1086,8 @@ static void notify_ring(struct drm_device *dev,
 
 static void gen6_pm_rps_work(struct work_struct *work)
 {
-       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
-                                                   rps.work);
+       struct drm_i915_private *dev_priv =
+               container_of(work, struct drm_i915_private, rps.work);
        u32 pm_iir;
        int new_delay, adj;
 
@@ -990,13 +1095,13 @@ static void gen6_pm_rps_work(struct work_struct *work)
        pm_iir = dev_priv->rps.pm_iir;
        dev_priv->rps.pm_iir = 0;
        /* Make sure not to corrupt PMIMR state used by ringbuffer code */
-       snb_enable_pm_irq(dev_priv, GEN6_PM_RPS_EVENTS);
+       snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
        spin_unlock_irq(&dev_priv->irq_lock);
 
        /* Make sure we didn't queue anything we're not going to process. */
-       WARN_ON(pm_iir & ~GEN6_PM_RPS_EVENTS);
+       WARN_ON(pm_iir & ~dev_priv->pm_rps_events);
 
-       if ((pm_iir & GEN6_PM_RPS_EVENTS) == 0)
+       if ((pm_iir & dev_priv->pm_rps_events) == 0)
                return;
 
        mutex_lock(&dev_priv->rps.hw_lock);
@@ -1007,36 +1112,38 @@ static void gen6_pm_rps_work(struct work_struct *work)
                        adj *= 2;
                else
                        adj = 1;
-               new_delay = dev_priv->rps.cur_delay + adj;
+               new_delay = dev_priv->rps.cur_freq + adj;
 
                /*
                 * For better performance, jump directly
                 * to RPe if we're below it.
                 */
-               if (new_delay < dev_priv->rps.rpe_delay)
-                       new_delay = dev_priv->rps.rpe_delay;
+               if (new_delay < dev_priv->rps.efficient_freq)
+                       new_delay = dev_priv->rps.efficient_freq;
        } else if (pm_iir & GEN6_PM_RP_DOWN_TIMEOUT) {
-               if (dev_priv->rps.cur_delay > dev_priv->rps.rpe_delay)
-                       new_delay = dev_priv->rps.rpe_delay;
+               if (dev_priv->rps.cur_freq > dev_priv->rps.efficient_freq)
+                       new_delay = dev_priv->rps.efficient_freq;
                else
-                       new_delay = dev_priv->rps.min_delay;
+                       new_delay = dev_priv->rps.min_freq_softlimit;
                adj = 0;
        } else if (pm_iir & GEN6_PM_RP_DOWN_THRESHOLD) {
                if (adj < 0)
                        adj *= 2;
                else
                        adj = -1;
-               new_delay = dev_priv->rps.cur_delay + adj;
+               new_delay = dev_priv->rps.cur_freq + adj;
        } else { /* unknown event */
-               new_delay = dev_priv->rps.cur_delay;
+               new_delay = dev_priv->rps.cur_freq;
        }
 
        /* sysfs frequency interfaces may have snuck in while servicing the
         * interrupt
         */
        new_delay = clamp_t(int, new_delay,
-                           dev_priv->rps.min_delay, dev_priv->rps.max_delay);
-       dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay;
+                           dev_priv->rps.min_freq_softlimit,
+                           dev_priv->rps.max_freq_softlimit);
+
+       dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_freq;
 
        if (IS_VALLEYVIEW(dev_priv->dev))
                valleyview_set_rps(dev_priv->dev, new_delay);
@@ -1058,8 +1165,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
  */
 static void ivybridge_parity_work(struct work_struct *work)
 {
-       drm_i915_private_t *dev_priv = container_of(work, drm_i915_private_t,
-                                                   l3_parity.error_work);
+       struct drm_i915_private *dev_priv =
+               container_of(work, struct drm_i915_private, l3_parity.error_work);
        u32 error_status, row, bank, subbank;
        char *parity_event[6];
        uint32_t misccpctl;
@@ -1131,7 +1238,7 @@ out:
 
 static void ivybridge_parity_error_irq_handler(struct drm_device *dev, u32 iir)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (!HAS_L3_DPF(dev))
                return;
@@ -1177,8 +1284,8 @@ static void snb_gt_irq_handler(struct drm_device *dev,
        if (gt_iir & (GT_BLT_CS_ERROR_INTERRUPT |
                      GT_BSD_CS_ERROR_INTERRUPT |
                      GT_RENDER_CS_MASTER_ERROR_INTERRUPT)) {
-               DRM_ERROR("GT error interrupt 0x%08x\n", gt_iir);
-               i915_handle_error(dev, false);
+               i915_handle_error(dev, false, "GT error interrupt 0x%08x",
+                                 gt_iir);
        }
 
        if (gt_iir & GT_PARITY_ERROR(dev))
@@ -1242,13 +1349,16 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
                                         u32 hotplug_trigger,
                                         const u32 *hpd)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
        bool storm_detected = false;
 
        if (!hotplug_trigger)
                return;
 
+       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
+                         hotplug_trigger);
+
        spin_lock(&dev_priv->irq_lock);
        for (i = 1; i < HPD_NUM_PINS; i++) {
 
@@ -1295,14 +1405,14 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
 
 static void gmbus_irq_handler(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        wake_up_all(&dev_priv->gmbus_wait_queue);
 }
 
 static void dp_aux_irq_handler(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        wake_up_all(&dev_priv->gmbus_wait_queue);
 }
@@ -1408,10 +1518,10 @@ static void i9xx_pipe_crc_irq_handler(struct drm_device *dev, enum pipe pipe)
  * the work queue. */
 static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
 {
-       if (pm_iir & GEN6_PM_RPS_EVENTS) {
+       if (pm_iir & dev_priv->pm_rps_events) {
                spin_lock(&dev_priv->irq_lock);
-               dev_priv->rps.pm_iir |= pm_iir & GEN6_PM_RPS_EVENTS;
-               snb_disable_pm_irq(dev_priv, pm_iir & GEN6_PM_RPS_EVENTS);
+               dev_priv->rps.pm_iir |= pm_iir & dev_priv->pm_rps_events;
+               snb_disable_pm_irq(dev_priv, pm_iir & dev_priv->pm_rps_events);
                spin_unlock(&dev_priv->irq_lock);
 
                queue_work(dev_priv->wq, &dev_priv->rps.work);
@@ -1422,23 +1532,89 @@ static void gen6_rps_irq_handler(struct drm_i915_private *dev_priv, u32 pm_iir)
                        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);
+                       i915_handle_error(dev_priv->dev, false,
+                                         "VEBOX CS error interrupt 0x%08x",
+                                         pm_iir);
                }
        }
 }
 
+static void valleyview_pipestat_irq_handler(struct drm_device *dev, u32 iir)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 pipe_stats[I915_MAX_PIPES] = { };
+       int pipe;
+
+       spin_lock(&dev_priv->irq_lock);
+       for_each_pipe(pipe) {
+               int reg;
+               u32 mask, iir_bit = 0;
+
+               /*
+                * PIPESTAT bits get signalled even when the interrupt is
+                * disabled with the mask bits, and some of the status bits do
+                * not generate interrupts at all (like the underrun bit). Hence
+                * we need to be careful that we only handle what we want to
+                * handle.
+                */
+               mask = 0;
+               if (__cpu_fifo_underrun_reporting_enabled(dev, pipe))
+                       mask |= PIPE_FIFO_UNDERRUN_STATUS;
+
+               switch (pipe) {
+               case PIPE_A:
+                       iir_bit = I915_DISPLAY_PIPE_A_EVENT_INTERRUPT;
+                       break;
+               case PIPE_B:
+                       iir_bit = I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+                       break;
+               }
+               if (iir & iir_bit)
+                       mask |= dev_priv->pipestat_irq_mask[pipe];
+
+               if (!mask)
+                       continue;
+
+               reg = PIPESTAT(pipe);
+               mask |= PIPESTAT_INT_ENABLE_MASK;
+               pipe_stats[pipe] = I915_READ(reg) & mask;
+
+               /*
+                * Clear the PIPE*STAT regs before the IIR
+                */
+               if (pipe_stats[pipe] & (PIPE_FIFO_UNDERRUN_STATUS |
+                                       PIPESTAT_INT_STATUS_MASK))
+                       I915_WRITE(reg, pipe_stats[pipe]);
+       }
+       spin_unlock(&dev_priv->irq_lock);
+
+       for_each_pipe(pipe) {
+               if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
+                       drm_handle_vblank(dev, pipe);
+
+               if (pipe_stats[pipe] & PLANE_FLIP_DONE_INT_STATUS_VLV) {
+                       intel_prepare_page_flip(dev, pipe);
+                       intel_finish_page_flip(dev, pipe);
+               }
+
+               if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
+                       i9xx_pipe_crc_irq_handler(dev, pipe);
+
+               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                   intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                       DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+       }
+
+       if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
+               gmbus_irq_handler(dev);
+}
+
 static irqreturn_t valleyview_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;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 iir, gt_iir, pm_iir;
        irqreturn_t ret = IRQ_NONE;
-       unsigned long irqflags;
-       int pipe;
-       u32 pipe_stats[I915_MAX_PIPES];
-
-       atomic_inc(&dev_priv->irq_received);
 
        while (true) {
                iir = I915_READ(VLV_IIR);
@@ -1452,44 +1628,13 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
                snb_gt_irq_handler(dev, dev_priv, gt_iir);
 
-               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-               for_each_pipe(pipe) {
-                       int reg = PIPESTAT(pipe);
-                       pipe_stats[pipe] = I915_READ(reg);
-
-                       /*
-                        * Clear the PIPE*STAT regs before the IIR
-                        */
-                       if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
-                               I915_WRITE(reg, pipe_stats[pipe]);
-                       }
-               }
-               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-
-               for_each_pipe(pipe) {
-                       if (pipe_stats[pipe] & PIPE_START_VBLANK_INTERRUPT_STATUS)
-                               drm_handle_vblank(dev, pipe);
-
-                       if (pipe_stats[pipe] & PLANE_FLIPDONE_INT_STATUS_VLV) {
-                               intel_prepare_page_flip(dev, pipe);
-                               intel_finish_page_flip(dev, pipe);
-                       }
-
-                       if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
-                               i9xx_pipe_crc_irq_handler(dev, pipe);
-               }
+               valleyview_pipestat_irq_handler(dev, iir);
 
                /* Consume port.  Then clear IIR or we'll miss events */
                if (iir & I915_DISPLAY_PORT_INTERRUPT) {
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
                        u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
-                       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
-                                        hotplug_status);
-
                        intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 
                        if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
@@ -1499,8 +1644,6 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
                        I915_READ(PORT_HOTPLUG_STAT);
                }
 
-               if (pipe_stats[0] & PIPE_GMBUS_INTERRUPT_STATUS)
-                       gmbus_irq_handler(dev);
 
                if (pm_iir)
                        gen6_rps_irq_handler(dev_priv, pm_iir);
@@ -1516,7 +1659,7 @@ out:
 
 static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
        u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK;
 
@@ -1559,12 +1702,12 @@ static void ibx_irq_handler(struct drm_device *dev, u32 pch_iir)
        if (pch_iir & SDE_TRANSA_FIFO_UNDER)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder A FIFO underrun\n");
 
        if (pch_iir & SDE_TRANSB_FIFO_UNDER)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder B FIFO underrun\n");
 }
 
 static void ivb_err_int_handler(struct drm_device *dev)
@@ -1580,8 +1723,8 @@ static void ivb_err_int_handler(struct drm_device *dev)
                if (err_int & ERR_INT_FIFO_UNDERRUN(pipe)) {
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
                                                                  false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
                }
 
                if (err_int & ERR_INT_PIPE_CRC_DONE(pipe)) {
@@ -1606,24 +1749,24 @@ static void cpt_serr_int_handler(struct drm_device *dev)
        if (serr_int & SERR_INT_TRANS_A_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_A,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder A FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder A FIFO underrun\n");
 
        if (serr_int & SERR_INT_TRANS_B_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_B,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder B FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder B FIFO underrun\n");
 
        if (serr_int & SERR_INT_TRANS_C_FIFO_UNDERRUN)
                if (intel_set_pch_fifo_underrun_reporting(dev, TRANSCODER_C,
                                                          false))
-                       DRM_DEBUG_DRIVER("PCH transcoder C FIFO underrun\n");
+                       DRM_ERROR("PCH transcoder C FIFO underrun\n");
 
        I915_WRITE(SERR_INT, serr_int);
 }
 
 static void cpt_irq_handler(struct drm_device *dev, u32 pch_iir)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
        u32 hotplug_trigger = pch_iir & SDE_HOTPLUG_MASK_CPT;
 
@@ -1678,8 +1821,8 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 
                if (de_iir & DE_PIPE_FIFO_UNDERRUN(pipe))
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
 
                if (de_iir & DE_PIPE_CRC_DONE(pipe))
                        i9xx_pipe_crc_irq_handler(dev, pipe);
@@ -1711,7 +1854,7 @@ static void ilk_display_irq_handler(struct drm_device *dev, u32 de_iir)
 static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum pipe i;
+       enum pipe pipe;
 
        if (de_iir & DE_ERR_INT_IVB)
                ivb_err_int_handler(dev);
@@ -1722,14 +1865,14 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
        if (de_iir & DE_GSE_IVB)
                intel_opregion_asle_intr(dev);
 
-       for_each_pipe(i) {
-               if (de_iir & (DE_PIPE_VBLANK_IVB(i)))
-                       drm_handle_vblank(dev, i);
+       for_each_pipe(pipe) {
+               if (de_iir & (DE_PIPE_VBLANK_IVB(pipe)))
+                       drm_handle_vblank(dev, pipe);
 
                /* plane/pipes map 1:1 on ilk+ */
-               if (de_iir & DE_PLANE_FLIP_DONE_IVB(i)) {
-                       intel_prepare_page_flip(dev, i);
-                       intel_finish_page_flip_plane(dev, i);
+               if (de_iir & DE_PLANE_FLIP_DONE_IVB(pipe)) {
+                       intel_prepare_page_flip(dev, pipe);
+                       intel_finish_page_flip_plane(dev, pipe);
                }
        }
 
@@ -1747,12 +1890,10 @@ static void ivb_display_irq_handler(struct drm_device *dev, u32 de_iir)
 static irqreturn_t ironlake_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;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 de_iir, gt_iir, de_ier, sde_ier = 0;
        irqreturn_t ret = IRQ_NONE;
 
-       atomic_inc(&dev_priv->irq_received);
-
        /* We get interrupts on unclaimed registers, so check for this before we
         * do any I915_{READ,WRITE}. */
        intel_uncore_check_errors(dev);
@@ -1821,8 +1962,6 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
        uint32_t tmp = 0;
        enum pipe pipe;
 
-       atomic_inc(&dev_priv->irq_received);
-
        master_ctl = I915_READ(GEN8_MASTER_IRQ);
        master_ctl &= ~GEN8_MASTER_IRQ_CONTROL;
        if (!master_ctl)
@@ -1884,8 +2023,8 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
                if (pipe_iir & GEN8_PIPE_FIFO_UNDERRUN) {
                        if (intel_set_cpu_fifo_underrun_reporting(dev, pipe,
                                                                  false))
-                               DRM_DEBUG_DRIVER("Pipe %c FIFO underrun\n",
-                                                pipe_name(pipe));
+                               DRM_ERROR("Pipe %c FIFO underrun\n",
+                                         pipe_name(pipe));
                }
 
                if (pipe_iir & GEN8_DE_PIPE_IRQ_FAULT_ERRORS) {
@@ -1962,8 +2101,8 @@ 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_i915_private *dev_priv =
+               container_of(error, struct drm_i915_private, gpu_error);
        struct drm_device *dev = dev_priv->dev;
        char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
        char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
@@ -2127,11 +2266,18 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
  * so userspace knows something bad happened (should trigger collection
  * of a ring dump etc.).
  */
-void i915_handle_error(struct drm_device *dev, bool wedged)
+void i915_handle_error(struct drm_device *dev, bool wedged,
+                      const char *fmt, ...)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       va_list args;
+       char error_msg[80];
 
-       i915_capture_error_state(dev);
+       va_start(args, fmt);
+       vscnprintf(error_msg, sizeof(error_msg), fmt, args);
+       va_end(args);
+
+       i915_capture_error_state(dev, wedged, error_msg);
        i915_report_and_clear_eir(dev);
 
        if (wedged) {
@@ -2165,7 +2311,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged)
 
 static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_i915_gem_object *obj;
@@ -2197,8 +2343,8 @@ static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, in
        } else {
                int dspaddr = DSPADDR(intel_crtc->plane);
                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);
+                                                       crtc->y * crtc->primary->fb->pitches[0] +
+                                                       crtc->x * crtc->primary->fb->bits_per_pixel/8);
        }
 
        spin_unlock_irqrestore(&dev->event_lock, flags);
@@ -2214,7 +2360,7 @@ static void __always_unused i915_pageflip_stall_check(struct drm_device *dev, in
  */
 static int i915_enable_vblank(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
        if (!i915_pipe_enabled(dev, pipe))
@@ -2223,13 +2369,13 @@ static int i915_enable_vblank(struct drm_device *dev, int pipe)
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        if (INTEL_INFO(dev)->gen >= 4)
                i915_enable_pipestat(dev_priv, pipe,
-                                    PIPE_START_VBLANK_INTERRUPT_ENABLE);
+                                    PIPE_START_VBLANK_INTERRUPT_STATUS);
        else
                i915_enable_pipestat(dev_priv, pipe,
-                                    PIPE_VBLANK_INTERRUPT_ENABLE);
+                                    PIPE_VBLANK_INTERRUPT_STATUS);
 
        /* maintain vblank delivery even in deep C-states */
-       if (dev_priv->info->gen == 3)
+       if (INTEL_INFO(dev)->gen == 3)
                I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_AGPBUSY_DIS));
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -2238,7 +2384,7 @@ static int i915_enable_vblank(struct drm_device *dev, int pipe)
 
 static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
        uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
                                                     DE_PIPE_VBLANK(pipe);
@@ -2255,22 +2401,15 @@ static int ironlake_enable_vblank(struct drm_device *dev, int pipe)
 
 static int valleyview_enable_vblank(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
-       u32 imr;
 
        if (!i915_pipe_enabled(dev, pipe))
                return -EINVAL;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       imr = I915_READ(VLV_IMR);
-       if (pipe == PIPE_A)
-               imr &= ~I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
-       else
-               imr &= ~I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-       I915_WRITE(VLV_IMR, imr);
        i915_enable_pipestat(dev_priv, pipe,
-                            PIPE_START_VBLANK_INTERRUPT_ENABLE);
+                            PIPE_START_VBLANK_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        return 0;
@@ -2297,22 +2436,22 @@ static int gen8_enable_vblank(struct drm_device *dev, int pipe)
  */
 static void i915_disable_vblank(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-       if (dev_priv->info->gen == 3)
+       if (INTEL_INFO(dev)->gen == 3)
                I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_AGPBUSY_DIS));
 
        i915_disable_pipestat(dev_priv, pipe,
-                             PIPE_VBLANK_INTERRUPT_ENABLE |
-                             PIPE_START_VBLANK_INTERRUPT_ENABLE);
+                             PIPE_VBLANK_INTERRUPT_STATUS |
+                             PIPE_START_VBLANK_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
 static void ironlake_disable_vblank(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
        uint32_t bit = (INTEL_INFO(dev)->gen >= 7) ? DE_PIPE_VBLANK_IVB(pipe) :
                                                     DE_PIPE_VBLANK(pipe);
@@ -2324,19 +2463,12 @@ static void ironlake_disable_vblank(struct drm_device *dev, int pipe)
 
 static void valleyview_disable_vblank(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
-       u32 imr;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        i915_disable_pipestat(dev_priv, pipe,
-                             PIPE_START_VBLANK_INTERRUPT_ENABLE);
-       imr = I915_READ(VLV_IMR);
-       if (pipe == PIPE_A)
-               imr |= I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT;
-       else
-               imr |= I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-       I915_WRITE(VLV_IMR, imr);
+                             PIPE_START_VBLANK_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
@@ -2373,29 +2505,43 @@ static struct intel_ring_buffer *
 semaphore_waits_for(struct intel_ring_buffer *ring, u32 *seqno)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       u32 cmd, ipehr, acthd, acthd_min;
+       u32 cmd, ipehr, head;
+       int i;
 
        ipehr = I915_READ(RING_IPEHR(ring->mmio_base));
        if ((ipehr & ~(0x3 << 16)) !=
            (MI_SEMAPHORE_MBOX | MI_SEMAPHORE_COMPARE | MI_SEMAPHORE_REGISTER))
                return NULL;
 
-       /* ACTHD is likely pointing to the dword after the actual command,
-        * so scan backwards until we find the MBOX.
+       /*
+        * HEAD is likely pointing to the dword after the actual command,
+        * so scan backwards until we find the MBOX. But limit it to just 3
+        * dwords. Note that we don't care about ACTHD here since that might
+        * point at at batch, and semaphores are always emitted into the
+        * ringbuffer itself.
         */
-       acthd = intel_ring_get_active_head(ring) & HEAD_ADDR;
-       acthd_min = max((int)acthd - 3 * 4, 0);
-       do {
-               cmd = ioread32(ring->virtual_start + acthd);
+       head = I915_READ_HEAD(ring) & HEAD_ADDR;
+
+       for (i = 4; i; --i) {
+               /*
+                * Be paranoid and presume the hw has gone off into the wild -
+                * our ring is smaller than what the hardware (and hence
+                * HEAD_ADDR) allows. Also handles wrap-around.
+                */
+               head &= ring->size - 1;
+
+               /* This here seems to blow up */
+               cmd = ioread32(ring->virtual_start + head);
                if (cmd == ipehr)
                        break;
 
-               acthd -= 4;
-               if (acthd < acthd_min)
-                       return NULL;
-       } while (1);
+               head -= 4;
+       }
 
-       *seqno = ioread32(ring->virtual_start+acthd+4)+1;
+       if (!i)
+               return NULL;
+
+       *seqno = ioread32(ring->virtual_start + head + 4) + 1;
        return &dev_priv->ring[(ring->id + (((ipehr >> 17) & 1) + 1)) % 3];
 }
 
@@ -2429,7 +2575,7 @@ static void semaphore_clear_deadlocks(struct drm_i915_private *dev_priv)
 }
 
 static enum intel_ring_hangcheck_action
-ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
+ring_stuck(struct intel_ring_buffer *ring, u64 acthd)
 {
        struct drm_device *dev = ring->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2448,9 +2594,9 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
         */
        tmp = I915_READ_CTL(ring);
        if (tmp & RING_WAIT) {
-               DRM_ERROR("Kicking stuck wait on %s\n",
-                         ring->name);
-               i915_handle_error(dev, false);
+               i915_handle_error(dev, false,
+                                 "Kicking stuck wait on %s",
+                                 ring->name);
                I915_WRITE_CTL(ring, tmp);
                return HANGCHECK_KICK;
        }
@@ -2460,9 +2606,9 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
                default:
                        return HANGCHECK_HUNG;
                case 1:
-                       DRM_ERROR("Kicking stuck semaphore on %s\n",
-                                 ring->name);
-                       i915_handle_error(dev, false);
+                       i915_handle_error(dev, false,
+                                         "Kicking stuck semaphore on %s",
+                                         ring->name);
                        I915_WRITE_CTL(ring, tmp);
                        return HANGCHECK_KICK;
                case 0:
@@ -2484,7 +2630,7 @@ ring_stuck(struct intel_ring_buffer *ring, u32 acthd)
 static void i915_hangcheck_elapsed(unsigned long data)
 {
        struct drm_device *dev = (struct drm_device *)data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring;
        int i;
        int busy_count = 0, rings_hung = 0;
@@ -2492,13 +2638,13 @@ static void i915_hangcheck_elapsed(unsigned long data)
 #define BUSY 1
 #define KICK 5
 #define HUNG 20
-#define FIRE 30
 
-       if (!i915_enable_hangcheck)
+       if (!i915.enable_hangcheck)
                return;
 
        for_each_ring(ring, dev_priv, i) {
-               u32 seqno, acthd;
+               u64 acthd;
+               u32 seqno;
                bool busy = true;
 
                semaphore_clear_deadlocks(dev_priv);
@@ -2576,7 +2722,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
        }
 
        for_each_ring(ring, dev_priv, i) {
-               if (ring->hangcheck.score > FIRE) {
+               if (ring->hangcheck.score >= HANGCHECK_SCORE_RING_HUNG) {
                        DRM_INFO("%s on %s\n",
                                 stuck[i] ? "stuck" : "no progress",
                                 ring->name);
@@ -2585,7 +2731,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
        }
 
        if (rings_hung)
-               return i915_handle_error(dev, true);
+               return i915_handle_error(dev, true, "Ring hung");
 
        if (busy_count)
                /* Reset timer case chip hangs without another request
@@ -2596,7 +2742,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
 void i915_queue_hangcheck(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       if (!i915_enable_hangcheck)
+       if (!i915.enable_hangcheck)
                return;
 
        mod_timer(&dev_priv->gpu_error.hangcheck_timer,
@@ -2643,9 +2789,7 @@ static void gen5_gt_irq_preinstall(struct drm_device *dev)
 */
 static void ironlake_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);
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        I915_WRITE(HWSTAM, 0xeffe);
 
@@ -2660,11 +2804,9 @@ static void ironlake_irq_preinstall(struct drm_device *dev)
 
 static void valleyview_irq_preinstall(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        /* VLV magic */
        I915_WRITE(VLV_IMR, 0);
        I915_WRITE(RING_IMR(RENDER_RING_BASE), 0);
@@ -2694,8 +2836,6 @@ static void gen8_irq_preinstall(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(GEN8_MASTER_IRQ, 0);
        POSTING_READ(GEN8_MASTER_IRQ);
 
@@ -2740,7 +2880,7 @@ static void gen8_irq_preinstall(struct drm_device *dev)
 
 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_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *intel_encoder;
        u32 hotplug_irqs, hotplug, enabled_irqs = 0;
@@ -2775,7 +2915,7 @@ static void ibx_hpd_irq_setup(struct drm_device *dev)
 
 static void ibx_irq_postinstall(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 mask;
 
        if (HAS_PCH_NOP(dev))
@@ -2821,7 +2961,7 @@ static void gen5_gt_irq_postinstall(struct drm_device *dev)
        POSTING_READ(GTIER);
 
        if (INTEL_INFO(dev)->gen >= 6) {
-               pm_irqs |= GEN6_PM_RPS_EVENTS;
+               pm_irqs |= dev_priv->pm_rps_events;
 
                if (HAS_VEBOX(dev))
                        pm_irqs |= PM_VEBOX_USER_INTERRUPT;
@@ -2837,7 +2977,7 @@ static void gen5_gt_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;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 display_mask, extra_mask;
 
        if (INTEL_INFO(dev)->gen >= 7) {
@@ -2885,44 +3025,113 @@ static int ironlake_irq_postinstall(struct drm_device *dev)
        return 0;
 }
 
+static void valleyview_display_irqs_install(struct drm_i915_private *dev_priv)
+{
+       u32 pipestat_mask;
+       u32 iir_mask;
+
+       pipestat_mask = PIPESTAT_INT_STATUS_MASK |
+                       PIPE_FIFO_UNDERRUN_STATUS;
+
+       I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask);
+       I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask);
+       POSTING_READ(PIPESTAT(PIPE_A));
+
+       pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
+                       PIPE_CRC_DONE_INTERRUPT_STATUS;
+
+       i915_enable_pipestat(dev_priv, PIPE_A, pipestat_mask |
+                                              PIPE_GMBUS_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_B, pipestat_mask);
+
+       iir_mask = I915_DISPLAY_PORT_INTERRUPT |
+                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+       dev_priv->irq_mask &= ~iir_mask;
+
+       I915_WRITE(VLV_IIR, iir_mask);
+       I915_WRITE(VLV_IIR, iir_mask);
+       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+       I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
+       POSTING_READ(VLV_IER);
+}
+
+static void valleyview_display_irqs_uninstall(struct drm_i915_private *dev_priv)
+{
+       u32 pipestat_mask;
+       u32 iir_mask;
+
+       iir_mask = I915_DISPLAY_PORT_INTERRUPT |
+                  I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
+                  I915_DISPLAY_PIPE_B_EVENT_INTERRUPT;
+
+       dev_priv->irq_mask |= iir_mask;
+       I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
+       I915_WRITE(VLV_IMR, dev_priv->irq_mask);
+       I915_WRITE(VLV_IIR, iir_mask);
+       I915_WRITE(VLV_IIR, iir_mask);
+       POSTING_READ(VLV_IIR);
+
+       pipestat_mask = PLANE_FLIP_DONE_INT_STATUS_VLV |
+                       PIPE_CRC_DONE_INTERRUPT_STATUS;
+
+       i915_disable_pipestat(dev_priv, PIPE_A, pipestat_mask |
+                                               PIPE_GMBUS_INTERRUPT_STATUS);
+       i915_disable_pipestat(dev_priv, PIPE_B, pipestat_mask);
+
+       pipestat_mask = PIPESTAT_INT_STATUS_MASK |
+                       PIPE_FIFO_UNDERRUN_STATUS;
+       I915_WRITE(PIPESTAT(PIPE_A), pipestat_mask);
+       I915_WRITE(PIPESTAT(PIPE_B), pipestat_mask);
+       POSTING_READ(PIPESTAT(PIPE_A));
+}
+
+void valleyview_enable_display_irqs(struct drm_i915_private *dev_priv)
+{
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       if (dev_priv->display_irqs_enabled)
+               return;
+
+       dev_priv->display_irqs_enabled = true;
+
+       if (dev_priv->dev->irq_enabled)
+               valleyview_display_irqs_install(dev_priv);
+}
+
+void valleyview_disable_display_irqs(struct drm_i915_private *dev_priv)
+{
+       assert_spin_locked(&dev_priv->irq_lock);
+
+       if (!dev_priv->display_irqs_enabled)
+               return;
+
+       dev_priv->display_irqs_enabled = false;
+
+       if (dev_priv->dev->irq_enabled)
+               valleyview_display_irqs_uninstall(dev_priv);
+}
+
 static int valleyview_irq_postinstall(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
-       u32 enable_mask;
-       u32 pipestat_enable = PLANE_FLIP_DONE_INT_EN_VLV |
-               PIPE_CRC_DONE_ENABLE;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
-       enable_mask = I915_DISPLAY_PORT_INTERRUPT;
-       enable_mask |= I915_DISPLAY_PIPE_A_EVENT_INTERRUPT |
-               I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
-               I915_DISPLAY_PIPE_B_EVENT_INTERRUPT |
-               I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-
-       /*
-        *Leave vblank interrupts masked initially.  enable/disable will
-        * toggle them based on usage.
-        */
-       dev_priv->irq_mask = (~enable_mask) |
-               I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT |
-               I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
+       dev_priv->irq_mask = ~0;
 
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        POSTING_READ(PORT_HOTPLUG_EN);
 
        I915_WRITE(VLV_IMR, dev_priv->irq_mask);
-       I915_WRITE(VLV_IER, enable_mask);
+       I915_WRITE(VLV_IER, ~dev_priv->irq_mask);
        I915_WRITE(VLV_IIR, 0xffffffff);
-       I915_WRITE(PIPESTAT(0), 0xffff);
-       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, PIPE_A, pipestat_enable);
-       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_EVENT_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_B, pipestat_enable);
+       if (dev_priv->display_irqs_enabled)
+               valleyview_display_irqs_install(dev_priv);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        I915_WRITE(VLV_IIR, 0xffffffff);
@@ -3018,8 +3227,6 @@ static void gen8_irq_uninstall(struct drm_device *dev)
        if (!dev_priv)
                return;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(GEN8_MASTER_IRQ, 0);
 
 #define GEN8_IRQ_FINI_NDX(type, which) do { \
@@ -3054,13 +3261,14 @@ static void gen8_irq_uninstall(struct drm_device *dev)
 
 static void valleyview_irq_uninstall(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long irqflags;
        int pipe;
 
        if (!dev_priv)
                return;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        for_each_pipe(pipe)
                I915_WRITE(PIPESTAT(pipe), 0xffff);
@@ -3068,8 +3276,14 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
        I915_WRITE(HWSTAM, 0xffffffff);
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
-       for_each_pipe(pipe)
-               I915_WRITE(PIPESTAT(pipe), 0xffff);
+
+       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+       if (dev_priv->display_irqs_enabled)
+               valleyview_display_irqs_uninstall(dev_priv);
+       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+
+       dev_priv->irq_mask = 0;
+
        I915_WRITE(VLV_IIR, 0xffffffff);
        I915_WRITE(VLV_IMR, 0xffffffff);
        I915_WRITE(VLV_IER, 0x0);
@@ -3078,12 +3292,12 @@ static void valleyview_irq_uninstall(struct drm_device *dev)
 
 static void ironlake_irq_uninstall(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (!dev_priv)
                return;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        I915_WRITE(HWSTAM, 0xffffffff);
 
@@ -3109,11 +3323,9 @@ static void ironlake_irq_uninstall(struct drm_device *dev)
 
 static void i8xx_irq_preinstall(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        for_each_pipe(pipe)
                I915_WRITE(PIPESTAT(pipe), 0);
        I915_WRITE16(IMR, 0xffff);
@@ -3123,7 +3335,7 @@ static void i8xx_irq_preinstall(struct drm_device * dev)
 
 static int i8xx_irq_postinstall(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
        I915_WRITE16(EMR,
@@ -3148,8 +3360,8 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
        /* 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, PIPE_A, PIPE_CRC_DONE_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        return 0;
@@ -3161,7 +3373,7 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
 static bool i8xx_handle_vblank(struct drm_device *dev,
                               int plane, int pipe, u32 iir)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
 
        if (!drm_handle_vblank(dev, pipe))
@@ -3189,7 +3401,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
 static irqreturn_t i8xx_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;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u16 iir, new_iir;
        u32 pipe_stats[2];
        unsigned long irqflags;
@@ -3198,8 +3410,6 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
-       atomic_inc(&dev_priv->irq_received);
-
        iir = I915_READ16(IIR);
        if (iir == 0)
                return IRQ_NONE;
@@ -3212,7 +3422,9 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                 */
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       i915_handle_error(dev, false);
+                       i915_handle_error(dev, false,
+                                         "Command parser error, iir 0x%08x",
+                                         iir);
 
                for_each_pipe(pipe) {
                        int reg = PIPESTAT(pipe);
@@ -3221,12 +3433,8 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                        /*
                         * Clear the PIPE*STAT regs before the IIR
                         */
-                       if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
+                       if (pipe_stats[pipe] & 0x8000ffff)
                                I915_WRITE(reg, pipe_stats[pipe]);
-                       }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
@@ -3249,6 +3457,10 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                iir = new_iir;
@@ -3259,7 +3471,7 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
 
 static void i8xx_irq_uninstall(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
        for_each_pipe(pipe) {
@@ -3274,11 +3486,9 @@ static void i8xx_irq_uninstall(struct drm_device * dev)
 
 static void i915_irq_preinstall(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
                I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -3294,7 +3504,7 @@ static void i915_irq_preinstall(struct drm_device * dev)
 
 static int i915_irq_postinstall(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 enable_mask;
        unsigned long irqflags;
 
@@ -3335,8 +3545,8 @@ static int i915_irq_postinstall(struct drm_device *dev)
        /* 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, PIPE_A, PIPE_CRC_DONE_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        return 0;
@@ -3348,7 +3558,7 @@ static int i915_irq_postinstall(struct drm_device *dev)
 static bool i915_handle_vblank(struct drm_device *dev,
                               int plane, int pipe, u32 iir)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
 
        if (!drm_handle_vblank(dev, pipe))
@@ -3376,7 +3586,7 @@ static bool i915_handle_vblank(struct drm_device *dev,
 static irqreturn_t i915_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;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 iir, new_iir, pipe_stats[I915_MAX_PIPES];
        unsigned long irqflags;
        u32 flip_mask =
@@ -3384,8 +3594,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
        int pipe, ret = IRQ_NONE;
 
-       atomic_inc(&dev_priv->irq_received);
-
        iir = I915_READ(IIR);
        do {
                bool irq_received = (iir & ~flip_mask) != 0;
@@ -3398,7 +3606,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                 */
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       i915_handle_error(dev, false);
+                       i915_handle_error(dev, false,
+                                         "Command parser error, iir 0x%08x",
+                                         iir);
 
                for_each_pipe(pipe) {
                        int reg = PIPESTAT(pipe);
@@ -3406,9 +3616,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        /* Clear the PIPE*STAT regs before the IIR */
                        if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
                                I915_WRITE(reg, pipe_stats[pipe]);
                                irq_received = true;
                        }
@@ -3424,9 +3631,6 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
                        u32 hotplug_status = I915_READ(PORT_HOTPLUG_STAT);
                        u32 hotplug_trigger = hotplug_status & HOTPLUG_INT_STATUS_I915;
 
-                       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
-                                 hotplug_status);
-
                        intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
@@ -3453,6 +3657,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
+
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
                }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
@@ -3484,10 +3692,10 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
 static void i915_irq_uninstall(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        if (I915_HAS_HOTPLUG(dev)) {
                I915_WRITE(PORT_HOTPLUG_EN, 0);
@@ -3508,11 +3716,9 @@ static void i915_irq_uninstall(struct drm_device * dev)
 
 static void i965_irq_preinstall(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
-       atomic_set(&dev_priv->irq_received, 0);
-
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
 
@@ -3526,7 +3732,7 @@ static void i965_irq_preinstall(struct drm_device * dev)
 
 static int i965_irq_postinstall(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 enable_mask;
        u32 error_mask;
        unsigned long irqflags;
@@ -3551,9 +3757,9 @@ static int i965_irq_postinstall(struct drm_device *dev)
        /* 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, PIPE_A, PIPE_GMBUS_EVENT_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_ENABLE);
-       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_ENABLE);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_GMBUS_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_A, PIPE_CRC_DONE_INTERRUPT_STATUS);
+       i915_enable_pipestat(dev_priv, PIPE_B, PIPE_CRC_DONE_INTERRUPT_STATUS);
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 
        /*
@@ -3585,7 +3791,7 @@ static int i965_irq_postinstall(struct drm_device *dev)
 
 static void i915_hpd_irq_setup(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct intel_encoder *intel_encoder;
        u32 hotplug_en;
@@ -3617,25 +3823,21 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
 static irqreturn_t i965_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;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 iir, new_iir;
        u32 pipe_stats[I915_MAX_PIPES];
        unsigned long irqflags;
-       int irq_received;
        int ret = IRQ_NONE, pipe;
        u32 flip_mask =
                I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
                I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
 
-       atomic_inc(&dev_priv->irq_received);
-
        iir = I915_READ(IIR);
 
        for (;;) {
+               bool irq_received = (iir & ~flip_mask) != 0;
                bool blc_event = false;
 
-               irq_received = (iir & ~flip_mask) != 0;
-
                /* Can't rely on pipestat interrupt bit in iir as it might
                 * have been cleared after the pipestat interrupt was received.
                 * It doesn't set the bit in iir again, but it still produces
@@ -3643,7 +3845,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                 */
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
                if (iir & I915_RENDER_COMMAND_PARSER_ERROR_INTERRUPT)
-                       i915_handle_error(dev, false);
+                       i915_handle_error(dev, false,
+                                         "Command parser error, iir 0x%08x",
+                                         iir);
 
                for_each_pipe(pipe) {
                        int reg = PIPESTAT(pipe);
@@ -3653,11 +3857,8 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                         * Clear the PIPE*STAT regs before the IIR
                         */
                        if (pipe_stats[pipe] & 0x8000ffff) {
-                               if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS)
-                                       DRM_DEBUG_DRIVER("pipe %c underrun\n",
-                                                        pipe_name(pipe));
                                I915_WRITE(reg, pipe_stats[pipe]);
-                               irq_received = 1;
+                               irq_received = true;
                        }
                }
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
@@ -3674,9 +3875,6 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                                                                  HOTPLUG_INT_STATUS_G4X :
                                                                  HOTPLUG_INT_STATUS_I915);
 
-                       DRM_DEBUG_DRIVER("hotplug event received, stat 0x%08x\n",
-                                 hotplug_status);
-
                        intel_hpd_irq_handler(dev, hotplug_trigger,
                                              IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915);
 
@@ -3706,8 +3904,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
-               }
 
+                       if (pipe_stats[pipe] & PIPE_FIFO_UNDERRUN_STATUS &&
+                           intel_set_cpu_fifo_underrun_reporting(dev, pipe, false))
+                               DRM_ERROR("pipe %c underrun\n", pipe_name(pipe));
+               }
 
                if (blc_event || (iir & I915_ASLE_INTERRUPT))
                        intel_opregion_asle_intr(dev);
@@ -3740,13 +3941,13 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
 
 static void i965_irq_uninstall(struct drm_device * dev)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *) dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        int pipe;
 
        if (!dev_priv)
                return;
 
-       del_timer_sync(&dev_priv->hotplug_reenable_timer);
+       intel_hpd_irq_uninstall(dev_priv);
 
        I915_WRITE(PORT_HOTPLUG_EN, 0);
        I915_WRITE(PORT_HOTPLUG_STAT, I915_READ(PORT_HOTPLUG_STAT));
@@ -3763,9 +3964,9 @@ static void i965_irq_uninstall(struct drm_device * dev)
        I915_WRITE(IIR, I915_READ(IIR));
 }
 
-static void i915_reenable_hotplug_timer_func(unsigned long data)
+static void intel_hpd_irq_reenable(unsigned long data)
 {
-       drm_i915_private_t *dev_priv = (drm_i915_private_t *)data;
+       struct drm_i915_private *dev_priv = (struct drm_i915_private *)data;
        struct drm_device *dev = dev_priv->dev;
        struct drm_mode_config *mode_config = &dev->mode_config;
        unsigned long irqflags;
@@ -3807,10 +4008,13 @@ void intel_irq_init(struct drm_device *dev)
        INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
        INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
 
+       /* Let's track the enabled rps events */
+       dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
+
        setup_timer(&dev_priv->gpu_error.hangcheck_timer,
                    i915_hangcheck_elapsed,
                    (unsigned long) dev);
-       setup_timer(&dev_priv->hotplug_reenable_timer, i915_reenable_hotplug_timer_func,
+       setup_timer(&dev_priv->hotplug_reenable_timer, intel_hpd_irq_reenable,
                    (unsigned long) dev_priv);
 
        pm_qos_add_request(&dev_priv->pm_qos, PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
@@ -3906,32 +4110,32 @@ void intel_hpd_init(struct drm_device *dev)
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-/* Disable interrupts so we can allow Package C8+. */
-void hsw_pc8_disable_interrupts(struct drm_device *dev)
+/* Disable interrupts so we can allow runtime PM. */
+void hsw_runtime_pm_disable_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
-       dev_priv->pc8.regsave.deimr = I915_READ(DEIMR);
-       dev_priv->pc8.regsave.sdeimr = I915_READ(SDEIMR);
-       dev_priv->pc8.regsave.gtimr = I915_READ(GTIMR);
-       dev_priv->pc8.regsave.gtier = I915_READ(GTIER);
-       dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR);
+       dev_priv->pm.regsave.deimr = I915_READ(DEIMR);
+       dev_priv->pm.regsave.sdeimr = I915_READ(SDEIMR);
+       dev_priv->pm.regsave.gtimr = I915_READ(GTIMR);
+       dev_priv->pm.regsave.gtier = I915_READ(GTIER);
+       dev_priv->pm.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR);
 
        ironlake_disable_display_irq(dev_priv, 0xffffffff);
        ibx_disable_display_interrupt(dev_priv, 0xffffffff);
        ilk_disable_gt_irq(dev_priv, 0xffffffff);
        snb_disable_pm_irq(dev_priv, 0xffffffff);
 
-       dev_priv->pc8.irqs_disabled = true;
+       dev_priv->pm.irqs_disabled = true;
 
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
 
-/* Restore interrupts so we can recover from Package C8+. */
-void hsw_pc8_restore_interrupts(struct drm_device *dev)
+/* Restore interrupts so we can recover from runtime PM. */
+void hsw_runtime_pm_restore_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
@@ -3951,13 +4155,13 @@ void hsw_pc8_restore_interrupts(struct drm_device *dev)
        val = I915_READ(GEN6_PMIMR);
        WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val);
 
-       dev_priv->pc8.irqs_disabled = false;
+       dev_priv->pm.irqs_disabled = false;
 
-       ironlake_enable_display_irq(dev_priv, ~dev_priv->pc8.regsave.deimr);
-       ibx_enable_display_interrupt(dev_priv, ~dev_priv->pc8.regsave.sdeimr);
-       ilk_enable_gt_irq(dev_priv, ~dev_priv->pc8.regsave.gtimr);
-       snb_enable_pm_irq(dev_priv, ~dev_priv->pc8.regsave.gen6_pmimr);
-       I915_WRITE(GTIER, dev_priv->pc8.regsave.gtier);
+       ironlake_enable_display_irq(dev_priv, ~dev_priv->pm.regsave.deimr);
+       ibx_enable_display_interrupt(dev_priv, ~dev_priv->pm.regsave.sdeimr);
+       ilk_enable_gt_irq(dev_priv, ~dev_priv->pm.regsave.gtimr);
+       snb_enable_pm_irq(dev_priv, ~dev_priv->pm.regsave.gen6_pmimr);
+       I915_WRITE(GTIER, dev_priv->pm.regsave.gtier);
 
        spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
 }
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
new file mode 100644 (file)
index 0000000..d1d7980
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright © 2014 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, sub license, 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"
+
+struct i915_params i915 __read_mostly = {
+       .modeset = -1,
+       .panel_ignore_lid = 1,
+       .powersave = 1,
+       .semaphores = -1,
+       .lvds_downclock = 0,
+       .lvds_channel_mode = 0,
+       .panel_use_ssc = -1,
+       .vbt_sdvo_panel_type = -1,
+       .enable_rc6 = -1,
+       .enable_fbc = -1,
+       .enable_hangcheck = true,
+       .enable_ppgtt = -1,
+       .enable_psr = 0,
+       .preliminary_hw_support = IS_ENABLED(CONFIG_DRM_I915_PRELIMINARY_HW_SUPPORT),
+       .disable_power_well = 1,
+       .enable_ips = 1,
+       .fastboot = 0,
+       .prefault_disable = 0,
+       .reset = true,
+       .invert_brightness = 0,
+       .disable_display = 0,
+       .enable_cmd_parser = 0,
+};
+
+module_param_named(modeset, i915.modeset, int, 0400);
+MODULE_PARM_DESC(modeset,
+       "Use kernel modesetting [KMS] (0=DRM_I915_KMS from .config, "
+       "1=on, -1=force vga console preference [default])");
+
+module_param_named(panel_ignore_lid, i915.panel_ignore_lid, int, 0600);
+MODULE_PARM_DESC(panel_ignore_lid,
+       "Override lid status (0=autodetect, 1=autodetect disabled [default], "
+       "-1=force lid closed, -2=force lid open)");
+
+module_param_named(powersave, i915.powersave, int, 0600);
+MODULE_PARM_DESC(powersave,
+       "Enable powersavings, fbc, downclocking, etc. (default: true)");
+
+module_param_named(semaphores, i915.semaphores, int, 0400);
+MODULE_PARM_DESC(semaphores,
+       "Use semaphores for inter-ring sync "
+       "(default: -1 (use per-chip defaults))");
+
+module_param_named(enable_rc6, i915.enable_rc6, int, 0400);
+MODULE_PARM_DESC(enable_rc6,
+       "Enable power-saving render C-state 6. "
+       "Different stages can be selected via bitmask values "
+       "(0 = disable; 1 = enable rc6; 2 = enable deep rc6; 4 = enable deepest rc6). "
+       "For example, 3 would enable rc6 and deep rc6, and 7 would enable everything. "
+       "default: -1 (use per-chip default)");
+
+module_param_named(enable_fbc, i915.enable_fbc, int, 0600);
+MODULE_PARM_DESC(enable_fbc,
+       "Enable frame buffer compression for power savings "
+       "(default: -1 (use per-chip default))");
+
+module_param_named(lvds_downclock, i915.lvds_downclock, int, 0400);
+MODULE_PARM_DESC(lvds_downclock,
+       "Use panel (LVDS/eDP) downclocking for power savings "
+       "(default: false)");
+
+module_param_named(lvds_channel_mode, i915.lvds_channel_mode, int, 0600);
+MODULE_PARM_DESC(lvds_channel_mode,
+        "Specify LVDS channel mode "
+        "(0=probe BIOS [default], 1=single-channel, 2=dual-channel)");
+
+module_param_named(lvds_use_ssc, i915.panel_use_ssc, int, 0600);
+MODULE_PARM_DESC(lvds_use_ssc,
+       "Use Spread Spectrum Clock with panels [LVDS/eDP] "
+       "(default: auto from VBT)");
+
+module_param_named(vbt_sdvo_panel_type, i915.vbt_sdvo_panel_type, int, 0600);
+MODULE_PARM_DESC(vbt_sdvo_panel_type,
+       "Override/Ignore selection of SDVO panel mode in the VBT "
+       "(-2=ignore, -1=auto [default], index in VBT BIOS table)");
+
+module_param_named(reset, i915.reset, bool, 0600);
+MODULE_PARM_DESC(reset, "Attempt GPU resets (default: true)");
+
+module_param_named(enable_hangcheck, i915.enable_hangcheck, bool, 0644);
+MODULE_PARM_DESC(enable_hangcheck,
+       "Periodically check GPU activity for detecting hangs. "
+       "WARNING: Disabling this can cause system wide hangs. "
+       "(default: true)");
+
+module_param_named(enable_ppgtt, i915.enable_ppgtt, int, 0400);
+MODULE_PARM_DESC(enable_ppgtt,
+       "Override PPGTT usage. "
+       "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
+
+module_param_named(enable_psr, i915.enable_psr, int, 0600);
+MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
+
+module_param_named(preliminary_hw_support, i915.preliminary_hw_support, int, 0600);
+MODULE_PARM_DESC(preliminary_hw_support,
+       "Enable preliminary hardware support.");
+
+module_param_named(disable_power_well, i915.disable_power_well, int, 0600);
+MODULE_PARM_DESC(disable_power_well,
+       "Disable the power well when possible (default: true)");
+
+module_param_named(enable_ips, i915.enable_ips, int, 0600);
+MODULE_PARM_DESC(enable_ips, "Enable IPS (default: true)");
+
+module_param_named(fastboot, i915.fastboot, bool, 0600);
+MODULE_PARM_DESC(fastboot,
+       "Try to skip unnecessary mode sets at boot time (default: false)");
+
+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.");
+
+module_param_named(invert_brightness, i915.invert_brightness, int, 0600);
+MODULE_PARM_DESC(invert_brightness,
+       "Invert backlight brightness "
+       "(-1 force normal, 0 machine defaults, 1 force inversion), please "
+       "report PCI device ID, subsystem vendor and subsystem device ID "
+       "to dri-devel@lists.freedesktop.org, if your machine needs it. "
+       "It will then be included in an upcoming module version.");
+
+module_param_named(disable_display, i915.disable_display, bool, 0600);
+MODULE_PARM_DESC(disable_display, "Disable display (default: false)");
+
+module_param_named(enable_cmd_parser, i915.enable_cmd_parser, int, 0600);
+MODULE_PARM_DESC(enable_cmd_parser,
+                "Enable command parsing (1=enabled, 0=disabled [default])");
index a48b7ca..9f5b18d 100644 (file)
@@ -26,7 +26,6 @@
 #define _I915_REG_H_
 
 #define _PIPE(pipe, a, b) ((a) + (pipe)*((b)-(a)))
-#define _PIPE_INC(pipe, base, inc) ((base) + (pipe)*(inc))
 #define _TRANSCODER(tran, a, b) ((a) + (tran)*((b)-(a)))
 
 #define _PORT(port, a, b) ((a) + (port)*((b)-(a)))
@@ -73,7 +72,8 @@
 #define   I915_GC_RENDER_CLOCK_166_MHZ (0 << 0)
 #define   I915_GC_RENDER_CLOCK_200_MHZ (1 << 0)
 #define   I915_GC_RENDER_CLOCK_333_MHZ (4 << 0)
-#define LBB    0xf4
+#define PCI_LBPC 0xf4 /* legacy/combination backlight modes, also called LBB */
+
 
 /* Graphics reset regs */
 #define I965_GDRST 0xc0 /* PCI config register */
 #define VGA_CR_INDEX_CGA 0x3d4
 #define VGA_CR_DATA_CGA 0x3d5
 
+/*
+ * Instruction field definitions used by the command parser
+ */
+#define INSTR_CLIENT_SHIFT      29
+#define INSTR_CLIENT_MASK       0xE0000000
+#define   INSTR_MI_CLIENT       0x0
+#define   INSTR_BC_CLIENT       0x2
+#define   INSTR_RC_CLIENT       0x3
+#define INSTR_SUBCLIENT_SHIFT   27
+#define INSTR_SUBCLIENT_MASK    0x18000000
+#define   INSTR_MEDIA_SUBCLIENT 0x2
+
 /*
  * Memory interface instructions used by the kernel
  */
 #define   DSPFREQSTAT_MASK                     (0x3 << DSPFREQSTAT_SHIFT)
 #define   DSPFREQGUAR_SHIFT                    14
 #define   DSPFREQGUAR_MASK                     (0x3 << DSPFREQGUAR_SHIFT)
+
+/* See the PUNIT HAS v0.8 for the below bits */
+enum punit_power_well {
+       PUNIT_POWER_WELL_RENDER                 = 0,
+       PUNIT_POWER_WELL_MEDIA                  = 1,
+       PUNIT_POWER_WELL_DISP2D                 = 3,
+       PUNIT_POWER_WELL_DPIO_CMN_BC            = 5,
+       PUNIT_POWER_WELL_DPIO_TX_B_LANES_01     = 6,
+       PUNIT_POWER_WELL_DPIO_TX_B_LANES_23     = 7,
+       PUNIT_POWER_WELL_DPIO_TX_C_LANES_01     = 8,
+       PUNIT_POWER_WELL_DPIO_TX_C_LANES_23     = 9,
+       PUNIT_POWER_WELL_DPIO_RX0               = 10,
+       PUNIT_POWER_WELL_DPIO_RX1               = 11,
+
+       PUNIT_POWER_WELL_NUM,
+};
+
 #define PUNIT_REG_PWRGT_CTRL                   0x60
 #define PUNIT_REG_PWRGT_STATUS                 0x61
-#define          PUNIT_CLK_GATE                        1
-#define          PUNIT_PWR_RESET                       2
-#define          PUNIT_PWR_GATE                        3
-#define          RENDER_PWRGT                          (PUNIT_PWR_GATE << 0)
-#define          MEDIA_PWRGT                           (PUNIT_PWR_GATE << 2)
-#define          DISP2D_PWRGT                          (PUNIT_PWR_GATE << 6)
+#define   PUNIT_PWRGT_MASK(power_well)         (3 << ((power_well) * 2))
+#define   PUNIT_PWRGT_PWR_ON(power_well)       (0 << ((power_well) * 2))
+#define   PUNIT_PWRGT_CLK_GATE(power_well)     (1 << ((power_well) * 2))
+#define   PUNIT_PWRGT_RESET(power_well)                (2 << ((power_well) * 2))
+#define   PUNIT_PWRGT_PWR_GATE(power_well)     (3 << ((power_well) * 2))
 
 #define PUNIT_REG_GPU_LFM                      0xd3
 #define PUNIT_REG_GPU_FREQ_REQ                 0xd4
 #define BLT_HWS_PGA_GEN7       (0x04280)
 #define VEBOX_HWS_PGA_GEN7     (0x04380)
 #define RING_ACTHD(base)       ((base)+0x74)
+#define RING_ACTHD_UDW(base)   ((base)+0x5c)
 #define RING_NOPID(base)       ((base)+0x94)
 #define RING_IMR(base)         ((base)+0xa8)
 #define RING_TIMESTAMP(base)   ((base)+0x358)
 #define RING_INSTPS(base)      ((base)+0x70)
 #define RING_DMA_FADD(base)    ((base)+0x78)
 #define RING_INSTPM(base)      ((base)+0xc0)
+#define RING_MI_MODE(base)     ((base)+0x9c)
 #define INSTPS         0x02070 /* 965+ only */
 #define INSTDONE1      0x0207c /* 965+ only */
 #define ACTHD_I965     0x02074
 #define _3D_CHICKEN3   0x02090
 #define  _3D_CHICKEN_SF_DISABLE_OBJEND_CULL            (1 << 10)
 #define  _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL         (1 << 5)
-#define  _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x)      ((x)<<1)
+#define  _3D_CHICKEN_SDE_LIMIT_FIFO_POLY_DEPTH(x)      ((x)<<1) /* gen8+ */
+#define  _3D_CHICKEN3_SF_DISABLE_PIPELINED_ATTR_FETCH  (1 << 1) /* gen6 */
 
 #define MI_MODE                0x0209c
 # define VS_TIMER_DISPATCH                             (1 << 6)
 # define MI_FLUSH_ENABLE                               (1 << 12)
 # define ASYNC_FLIP_PERF_DISABLE                       (1 << 14)
+# define MODE_IDLE                                     (1 << 9)
 
 #define GEN6_GT_MODE   0x20d0
-#define   GEN6_GT_MODE_HI                              (1 << 9)
+#define GEN7_GT_MODE   0x7008
+#define   GEN6_WIZ_HASHING(hi, lo)                     (((hi) << 9) | ((lo) << 7))
+#define   GEN6_WIZ_HASHING_8x8                         GEN6_WIZ_HASHING(0, 0)
+#define   GEN6_WIZ_HASHING_8x4                         GEN6_WIZ_HASHING(0, 1)
+#define   GEN6_WIZ_HASHING_16x4                                GEN6_WIZ_HASHING(1, 0)
+#define   GEN6_WIZ_HASHING_MASK                                (GEN6_WIZ_HASHING(1, 1) << 16)
 #define   GEN6_TD_FOUR_ROW_DISPATCH_DISABLE            (1 << 5)
 
 #define GFX_MODE       0x02520
 #define   ECO_GATING_CX_ONLY   (1<<3)
 #define   ECO_FLIP_DONE                (1<<0)
 
+#define CACHE_MODE_0_GEN7      0x7000 /* IVB+ */
+#define   HIZ_RAW_STALL_OPT_DISABLE (1<<2)
 #define CACHE_MODE_1           0x7004 /* IVB+ */
-#define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE (1<<6)
+#define   PIXEL_SUBSPAN_COLLECT_OPT_DISABLE    (1<<6)
+#define   GEN8_4x4_STC_OPTIMIZATION_DISABLE    (1<<6)
 
 #define GEN6_BLITTER_ECOSKPD   0x221d0
 #define   GEN6_BLITTER_LOCK_SHIFT                      16
 #define   GEN6_BLITTER_FBC_NOTIFY                      (1<<3)
 
+#define GEN6_RC_SLEEP_PSMI_CONTROL     0x2050
+#define   GEN8_RC_SEMA_IDLE_MSG_DISABLE        (1 << 12)
+
 #define GEN6_BSD_SLEEP_PSMI_CONTROL    0x12050
 #define   GEN6_BSD_SLEEP_MSG_DISABLE   (1 << 0)
 #define   GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2)
 #define   FBC_CTL_IDLE_LINE    (2<<2)
 #define   FBC_CTL_IDLE_DEBUG   (3<<2)
 #define   FBC_CTL_CPU_FENCE    (1<<1)
-#define   FBC_CTL_PLANEA       (0<<0)
-#define   FBC_CTL_PLANEB       (1<<0)
-#define FBC_FENCE_OFF          0x0321b
+#define   FBC_CTL_PLANE(plane) ((plane)<<0)
+#define FBC_FENCE_OFF          0x03218 /* BSpec typo has 321Bh */
 #define FBC_TAG                        0x03300
 
 #define FBC_LL_SIZE            (1536)
 #define DPFC_CB_BASE           0x3200
 #define DPFC_CONTROL           0x3208
 #define   DPFC_CTL_EN          (1<<31)
-#define   DPFC_CTL_PLANEA      (0<<30)
-#define   DPFC_CTL_PLANEB      (1<<30)
-#define   IVB_DPFC_CTL_PLANE_SHIFT     (29)
+#define   DPFC_CTL_PLANE(plane)        ((plane)<<30)
+#define   IVB_DPFC_CTL_PLANE(plane)    ((plane)<<29)
 #define   DPFC_CTL_FENCE_EN    (1<<29)
 #define   IVB_DPFC_CTL_FENCE_EN        (1<<28)
 #define   DPFC_CTL_PERSISTENT_MODE     (1<<25)
 #define   FBC_REND_NUKE                (1<<2)
 #define   FBC_REND_CACHE_CLEAN (1<<1)
 
-#define _HSW_PIPE_SLICE_CHICKEN_1_A    0x420B0
-#define _HSW_PIPE_SLICE_CHICKEN_1_B    0x420B4
-#define   HSW_BYPASS_FBC_QUEUE         (1<<22)
-#define HSW_PIPE_SLICE_CHICKEN_1(pipe) _PIPE(pipe, + \
-                                            _HSW_PIPE_SLICE_CHICKEN_1_A, + \
-                                            _HSW_PIPE_SLICE_CHICKEN_1_B)
-
 /*
  * GPIO regs
  */
 /*
  * Clock control & power management
  */
+#define DPLL_A_OFFSET 0x6014
+#define DPLL_B_OFFSET 0x6018
+#define DPLL(pipe) (dev_priv->info.dpll_offsets[pipe] + \
+                   dev_priv->info.display_mmio_offset)
 
 #define VGA0   0x6000
 #define VGA1   0x6004
 #define   VGA1_PD_P1_DIV_2     (1 << 13)
 #define   VGA1_PD_P1_SHIFT     8
 #define   VGA1_PD_P1_MASK      (0x1f << 8)
-#define _DPLL_A        (dev_priv->info->display_mmio_offset + 0x6014)
-#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_SDVO_HIGH_SPEED         (1 << 30)
 #define   DPLL_DVO_2X_MODE             (1 << 30)
 #define   SDVO_MULTIPLIER_MASK                 0x000000ff
 #define   SDVO_MULTIPLIER_SHIFT_HIRES          4
 #define   SDVO_MULTIPLIER_SHIFT_VGA            0
-#define _DPLL_A_MD (dev_priv->info->display_mmio_offset + 0x601c) /* 965+ only */
+
+#define DPLL_A_MD_OFFSET 0x601c /* 965+ only */
+#define DPLL_B_MD_OFFSET 0x6020 /* 965+ only */
+#define DPLL_MD(pipe) (dev_priv->info.dpll_md_offsets[pipe] + \
+                      dev_priv->info.display_mmio_offset)
+
 /*
  * UDI pixel divider, controlling how many pixels are stuffed into a packet.
  *
  */
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_MASK      0x0000003f
 #define   DPLL_MD_VGA_UDI_MULTIPLIER_SHIFT     0
-#define _DPLL_B_MD (dev_priv->info->display_mmio_offset + 0x6020) /* 965+ only */
-#define DPLL_MD(pipe) _PIPE(pipe, _DPLL_A_MD, _DPLL_B_MD)
 
 #define _FPA0  0x06040
 #define _FPA1  0x06044
 #define  DSTATE_PLL_D3_OFF                     (1<<3)
 #define  DSTATE_GFX_CLOCK_GATING               (1<<1)
 #define  DSTATE_DOT_CLOCK_GATING               (1<<0)
-#define DSPCLK_GATE_D  (dev_priv->info->display_mmio_offset + 0x6200)
+#define DSPCLK_GATE_D  (dev_priv->info.display_mmio_offset + 0x6200)
 # define DPUNIT_B_CLOCK_GATE_DISABLE           (1 << 30) /* 965 */
 # define VSUNIT_CLOCK_GATE_DISABLE             (1 << 29) /* 965 */
 # define VRHUNIT_CLOCK_GATE_DISABLE            (1 << 28) /* 965 */
 /*
  * Palette regs
  */
-
-#define _PALETTE_A             (dev_priv->info->display_mmio_offset + 0xa000)
-#define _PALETTE_B             (dev_priv->info->display_mmio_offset + 0xa800)
-#define PALETTE(pipe) _PIPE(pipe, _PALETTE_A, _PALETTE_B)
+#define PALETTE_A_OFFSET 0xa000
+#define PALETTE_B_OFFSET 0xa800
+#define PALETTE(pipe) (dev_priv->info.palette_offsets[pipe] + \
+                      dev_priv->info.display_mmio_offset)
 
 /* MCH MMIO space */
 
  */
 
 /* Pipe A CRC regs */
-#define _PIPE_CRC_CTL_A                (dev_priv->info->display_mmio_offset + 0x60050)
+#define _PIPE_CRC_CTL_A                        0x60050
 #define   PIPE_CRC_ENABLE              (1 << 31)
 /* ivb+ source selection */
 #define   PIPE_CRC_SOURCE_PRIMARY_IVB  (0 << 29)
 #define _PIPE_CRC_RES_4_A_IVB          0x60070
 #define _PIPE_CRC_RES_5_A_IVB          0x60074
 
-#define _PIPE_CRC_RES_RED_A            (dev_priv->info->display_mmio_offset + 0x60060)
-#define _PIPE_CRC_RES_GREEN_A          (dev_priv->info->display_mmio_offset + 0x60064)
-#define _PIPE_CRC_RES_BLUE_A           (dev_priv->info->display_mmio_offset + 0x60068)
-#define _PIPE_CRC_RES_RES1_A_I915      (dev_priv->info->display_mmio_offset + 0x6006c)
-#define _PIPE_CRC_RES_RES2_A_G4X       (dev_priv->info->display_mmio_offset + 0x60080)
+#define _PIPE_CRC_RES_RED_A            0x60060
+#define _PIPE_CRC_RES_GREEN_A          0x60064
+#define _PIPE_CRC_RES_BLUE_A           0x60068
+#define _PIPE_CRC_RES_RES1_A_I915      0x6006c
+#define _PIPE_CRC_RES_RES2_A_G4X       0x60080
 
 /* Pipe B CRC regs */
 #define _PIPE_CRC_RES_1_B_IVB          0x61064
 #define _PIPE_CRC_RES_4_B_IVB          0x61070
 #define _PIPE_CRC_RES_5_B_IVB          0x61074
 
-#define PIPE_CRC_CTL(pipe)     _PIPE_INC(pipe, _PIPE_CRC_CTL_A, 0x01000)
+#define PIPE_CRC_CTL(pipe) _TRANSCODER2(pipe, _PIPE_CRC_CTL_A)
 #define PIPE_CRC_RES_1_IVB(pipe)       \
-       _PIPE(pipe, _PIPE_CRC_RES_1_A_IVB, _PIPE_CRC_RES_1_B_IVB)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_1_A_IVB)
 #define PIPE_CRC_RES_2_IVB(pipe)       \
-       _PIPE(pipe, _PIPE_CRC_RES_2_A_IVB, _PIPE_CRC_RES_2_B_IVB)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_2_A_IVB)
 #define PIPE_CRC_RES_3_IVB(pipe)       \
-       _PIPE(pipe, _PIPE_CRC_RES_3_A_IVB, _PIPE_CRC_RES_3_B_IVB)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_3_A_IVB)
 #define PIPE_CRC_RES_4_IVB(pipe)       \
-       _PIPE(pipe, _PIPE_CRC_RES_4_A_IVB, _PIPE_CRC_RES_4_B_IVB)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_4_A_IVB)
 #define PIPE_CRC_RES_5_IVB(pipe)       \
-       _PIPE(pipe, _PIPE_CRC_RES_5_A_IVB, _PIPE_CRC_RES_5_B_IVB)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_5_A_IVB)
 
 #define PIPE_CRC_RES_RED(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_RED_A, 0x01000)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_RED_A)
 #define PIPE_CRC_RES_GREEN(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_GREEN_A, 0x01000)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_GREEN_A)
 #define PIPE_CRC_RES_BLUE(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_BLUE_A, 0x01000)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_BLUE_A)
 #define PIPE_CRC_RES_RES1_I915(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_RES1_A_I915, 0x01000)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_RES1_A_I915)
 #define PIPE_CRC_RES_RES2_G4X(pipe) \
-       _PIPE_INC(pipe, _PIPE_CRC_RES_RES2_A_G4X, 0x01000)
+       _TRANSCODER2(pipe, _PIPE_CRC_RES_RES2_A_G4X)
 
 /* Pipe A timing regs */
-#define _HTOTAL_A      (dev_priv->info->display_mmio_offset + 0x60000)
-#define _HBLANK_A      (dev_priv->info->display_mmio_offset + 0x60004)
-#define _HSYNC_A       (dev_priv->info->display_mmio_offset + 0x60008)
-#define _VTOTAL_A      (dev_priv->info->display_mmio_offset + 0x6000c)
-#define _VBLANK_A      (dev_priv->info->display_mmio_offset + 0x60010)
-#define _VSYNC_A       (dev_priv->info->display_mmio_offset + 0x60014)
-#define _PIPEASRC      (dev_priv->info->display_mmio_offset + 0x6001c)
-#define _BCLRPAT_A     (dev_priv->info->display_mmio_offset + 0x60020)
-#define _VSYNCSHIFT_A  (dev_priv->info->display_mmio_offset + 0x60028)
+#define _HTOTAL_A      0x60000
+#define _HBLANK_A      0x60004
+#define _HSYNC_A       0x60008
+#define _VTOTAL_A      0x6000c
+#define _VBLANK_A      0x60010
+#define _VSYNC_A       0x60014
+#define _PIPEASRC      0x6001c
+#define _BCLRPAT_A     0x60020
+#define _VSYNCSHIFT_A  0x60028
 
 /* Pipe B timing regs */
-#define _HTOTAL_B      (dev_priv->info->display_mmio_offset + 0x61000)
-#define _HBLANK_B      (dev_priv->info->display_mmio_offset + 0x61004)
-#define _HSYNC_B       (dev_priv->info->display_mmio_offset + 0x61008)
-#define _VTOTAL_B      (dev_priv->info->display_mmio_offset + 0x6100c)
-#define _VBLANK_B      (dev_priv->info->display_mmio_offset + 0x61010)
-#define _VSYNC_B       (dev_priv->info->display_mmio_offset + 0x61014)
-#define _PIPEBSRC      (dev_priv->info->display_mmio_offset + 0x6101c)
-#define _BCLRPAT_B     (dev_priv->info->display_mmio_offset + 0x61020)
-#define _VSYNCSHIFT_B  (dev_priv->info->display_mmio_offset + 0x61028)
-
-#define HTOTAL(trans) _TRANSCODER(trans, _HTOTAL_A, _HTOTAL_B)
-#define HBLANK(trans) _TRANSCODER(trans, _HBLANK_A, _HBLANK_B)
-#define HSYNC(trans) _TRANSCODER(trans, _HSYNC_A, _HSYNC_B)
-#define VTOTAL(trans) _TRANSCODER(trans, _VTOTAL_A, _VTOTAL_B)
-#define VBLANK(trans) _TRANSCODER(trans, _VBLANK_A, _VBLANK_B)
-#define VSYNC(trans) _TRANSCODER(trans, _VSYNC_A, _VSYNC_B)
-#define BCLRPAT(pipe) _PIPE(pipe, _BCLRPAT_A, _BCLRPAT_B)
-#define VSYNCSHIFT(trans) _TRANSCODER(trans, _VSYNCSHIFT_A, _VSYNCSHIFT_B)
+#define _HTOTAL_B      0x61000
+#define _HBLANK_B      0x61004
+#define _HSYNC_B       0x61008
+#define _VTOTAL_B      0x6100c
+#define _VBLANK_B      0x61010
+#define _VSYNC_B       0x61014
+#define _PIPEBSRC      0x6101c
+#define _BCLRPAT_B     0x61020
+#define _VSYNCSHIFT_B  0x61028
+
+#define TRANSCODER_A_OFFSET 0x60000
+#define TRANSCODER_B_OFFSET 0x61000
+#define TRANSCODER_C_OFFSET 0x62000
+#define TRANSCODER_EDP_OFFSET 0x6f000
+
+#define _TRANSCODER2(pipe, reg) (dev_priv->info.trans_offsets[(pipe)] - \
+       dev_priv->info.trans_offsets[TRANSCODER_A] + (reg) + \
+       dev_priv->info.display_mmio_offset)
+
+#define HTOTAL(trans) _TRANSCODER2(trans, _HTOTAL_A)
+#define HBLANK(trans) _TRANSCODER2(trans, _HBLANK_A)
+#define HSYNC(trans) _TRANSCODER2(trans, _HSYNC_A)
+#define VTOTAL(trans) _TRANSCODER2(trans, _VTOTAL_A)
+#define VBLANK(trans) _TRANSCODER2(trans, _VBLANK_A)
+#define VSYNC(trans) _TRANSCODER2(trans, _VSYNC_A)
+#define BCLRPAT(trans) _TRANSCODER2(trans, _BCLRPAT_A)
+#define VSYNCSHIFT(trans) _TRANSCODER2(trans, _VSYNCSHIFT_A)
+#define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC)
 
 /* HSW+ eDP PSR registers */
 #define EDP_PSR_BASE(dev)                       (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
 
 
 /* Hotplug control (945+ only) */
-#define PORT_HOTPLUG_EN                (dev_priv->info->display_mmio_offset + 0x61110)
+#define PORT_HOTPLUG_EN                (dev_priv->info.display_mmio_offset + 0x61110)
 #define   PORTB_HOTPLUG_INT_EN                 (1 << 29)
 #define   PORTC_HOTPLUG_INT_EN                 (1 << 28)
 #define   PORTD_HOTPLUG_INT_EN                 (1 << 27)
 #define CRT_HOTPLUG_DETECT_VOLTAGE_325MV       (0 << 2)
 #define CRT_HOTPLUG_DETECT_VOLTAGE_475MV       (1 << 2)
 
-#define PORT_HOTPLUG_STAT      (dev_priv->info->display_mmio_offset + 0x61114)
+#define PORT_HOTPLUG_STAT      (dev_priv->info.display_mmio_offset + 0x61114)
 /*
  * HDMI/DP bits are gen4+
  *
 #define VIDEO_DIP_CTL          0x61170
 /* Pre HSW: */
 #define   VIDEO_DIP_ENABLE             (1 << 31)
-#define   VIDEO_DIP_PORT_B             (1 << 29)
-#define   VIDEO_DIP_PORT_C             (2 << 29)
-#define   VIDEO_DIP_PORT_D             (3 << 29)
+#define   VIDEO_DIP_PORT(port)         ((port) << 29)
 #define   VIDEO_DIP_PORT_MASK          (3 << 29)
 #define   VIDEO_DIP_ENABLE_GCP         (1 << 25)
 #define   VIDEO_DIP_ENABLE_AVI         (1 << 21)
 #define PP_DIVISOR     0x61210
 
 /* Panel fitting */
-#define PFIT_CONTROL   (dev_priv->info->display_mmio_offset + 0x61230)
+#define PFIT_CONTROL   (dev_priv->info.display_mmio_offset + 0x61230)
 #define   PFIT_ENABLE          (1 << 31)
 #define   PFIT_PIPE_MASK       (3 << 29)
 #define   PFIT_PIPE_SHIFT      29
 #define   PFIT_SCALING_PROGRAMMED (1 << 26)
 #define   PFIT_SCALING_PILLAR  (2 << 26)
 #define   PFIT_SCALING_LETTER  (3 << 26)
-#define PFIT_PGM_RATIOS        (dev_priv->info->display_mmio_offset + 0x61234)
+#define PFIT_PGM_RATIOS        (dev_priv->info.display_mmio_offset + 0x61234)
 /* Pre-965 */
 #define                PFIT_VERT_SCALE_SHIFT           20
 #define                PFIT_VERT_SCALE_MASK            0xfff00000
 #define                PFIT_HORIZ_SCALE_SHIFT_965      0
 #define                PFIT_HORIZ_SCALE_MASK_965       0x00001fff
 
-#define PFIT_AUTO_RATIOS (dev_priv->info->display_mmio_offset + 0x61238)
+#define PFIT_AUTO_RATIOS (dev_priv->info.display_mmio_offset + 0x61238)
 
-#define _VLV_BLC_PWM_CTL2_A (dev_priv->info->display_mmio_offset + 0x61250)
-#define _VLV_BLC_PWM_CTL2_B (dev_priv->info->display_mmio_offset + 0x61350)
+#define _VLV_BLC_PWM_CTL2_A (dev_priv->info.display_mmio_offset + 0x61250)
+#define _VLV_BLC_PWM_CTL2_B (dev_priv->info.display_mmio_offset + 0x61350)
 #define VLV_BLC_PWM_CTL2(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL2_A, \
                                     _VLV_BLC_PWM_CTL2_B)
 
-#define _VLV_BLC_PWM_CTL_A (dev_priv->info->display_mmio_offset + 0x61254)
-#define _VLV_BLC_PWM_CTL_B (dev_priv->info->display_mmio_offset + 0x61354)
+#define _VLV_BLC_PWM_CTL_A (dev_priv->info.display_mmio_offset + 0x61254)
+#define _VLV_BLC_PWM_CTL_B (dev_priv->info.display_mmio_offset + 0x61354)
 #define VLV_BLC_PWM_CTL(pipe) _PIPE(pipe, _VLV_BLC_PWM_CTL_A, \
                                    _VLV_BLC_PWM_CTL_B)
 
-#define _VLV_BLC_HIST_CTL_A (dev_priv->info->display_mmio_offset + 0x61260)
-#define _VLV_BLC_HIST_CTL_B (dev_priv->info->display_mmio_offset + 0x61360)
+#define _VLV_BLC_HIST_CTL_A (dev_priv->info.display_mmio_offset + 0x61260)
+#define _VLV_BLC_HIST_CTL_B (dev_priv->info.display_mmio_offset + 0x61360)
 #define VLV_BLC_HIST_CTL(pipe) _PIPE(pipe, _VLV_BLC_HIST_CTL_A, \
                                     _VLV_BLC_HIST_CTL_B)
 
 /* Backlight control */
-#define BLC_PWM_CTL2   (dev_priv->info->display_mmio_offset + 0x61250) /* 965+ only */
+#define BLC_PWM_CTL2   (dev_priv->info.display_mmio_offset + 0x61250) /* 965+ only */
 #define   BLM_PWM_ENABLE               (1 << 31)
 #define   BLM_COMBINATION_MODE         (1 << 30) /* gen4 only */
 #define   BLM_PIPE_SELECT              (1 << 29)
 #define   BLM_PHASE_IN_COUNT_MASK      (0xff << 8)
 #define   BLM_PHASE_IN_INCR_SHIFT      (0)
 #define   BLM_PHASE_IN_INCR_MASK       (0xff << 0)
-#define BLC_PWM_CTL    (dev_priv->info->display_mmio_offset + 0x61254)
+#define BLC_PWM_CTL    (dev_priv->info.display_mmio_offset + 0x61254)
 /*
  * This is the most significant 15 bits of the number of backlight cycles in a
  * complete cycle of the modulated backlight control.
 #define   BACKLIGHT_DUTY_CYCLE_MASK_PNV                (0xfffe)
 #define   BLM_POLARITY_PNV                     (1 << 0) /* pnv only */
 
-#define BLC_HIST_CTL   (dev_priv->info->display_mmio_offset + 0x61260)
+#define BLC_HIST_CTL   (dev_priv->info.display_mmio_offset + 0x61260)
 
 /* New registers for PCH-split platforms. Safe where new bits show up, the
  * register layout machtes with gen4 BLC_PWM_CTL[12]. */
 /* Display & cursor control */
 
 /* Pipe A */
-#define _PIPEADSL              (dev_priv->info->display_mmio_offset + 0x70000)
+#define _PIPEADSL              0x70000
 #define   DSL_LINEMASK_GEN2    0x00000fff
 #define   DSL_LINEMASK_GEN3    0x00001fff
-#define _PIPEACONF             (dev_priv->info->display_mmio_offset + 0x70008)
+#define _PIPEACONF             0x70008
 #define   PIPECONF_ENABLE      (1<<31)
 #define   PIPECONF_DISABLE     0
 #define   PIPECONF_DOUBLE_WIDE (1<<30)
 #define   PIPECONF_DITHER_TYPE_ST1 (1<<2)
 #define   PIPECONF_DITHER_TYPE_ST2 (2<<2)
 #define   PIPECONF_DITHER_TYPE_TEMP (3<<2)
-#define _PIPEASTAT             (dev_priv->info->display_mmio_offset + 0x70024)
+#define _PIPEASTAT             0x70024
 #define   PIPE_FIFO_UNDERRUN_STATUS            (1UL<<31)
-#define   SPRITE1_FLIPDONE_INT_EN_VLV          (1UL<<30)
+#define   SPRITE1_FLIP_DONE_INT_EN_VLV         (1UL<<30)
 #define   PIPE_CRC_ERROR_ENABLE                        (1UL<<29)
 #define   PIPE_CRC_DONE_ENABLE                 (1UL<<28)
 #define   PIPE_GMBUS_EVENT_ENABLE              (1UL<<27)
 #define   PIPE_LEGACY_BLC_EVENT_ENABLE         (1UL<<22)
 #define   PIPE_ODD_FIELD_INTERRUPT_ENABLE      (1UL<<21)
 #define   PIPE_EVEN_FIELD_INTERRUPT_ENABLE     (1UL<<20)
+#define   PIPE_B_PSR_INTERRUPT_ENABLE_VLV      (1UL<<19)
 #define   PIPE_HOTPLUG_TV_INTERRUPT_ENABLE     (1UL<<18) /* pre-965 */
 #define   PIPE_START_VBLANK_INTERRUPT_ENABLE   (1UL<<18) /* 965 or later */
 #define   PIPE_VBLANK_INTERRUPT_ENABLE         (1UL<<17)
 #define   PIPEA_HBLANK_INT_EN_VLV              (1UL<<16)
 #define   PIPE_OVERLAY_UPDATED_ENABLE          (1UL<<16)
-#define   SPRITE1_FLIPDONE_INT_STATUS_VLV      (1UL<<15)
-#define   SPRITE0_FLIPDONE_INT_STATUS_VLV      (1UL<<14)
+#define   SPRITE1_FLIP_DONE_INT_STATUS_VLV     (1UL<<15)
+#define   SPRITE0_FLIP_DONE_INT_STATUS_VLV     (1UL<<14)
 #define   PIPE_CRC_ERROR_INTERRUPT_STATUS      (1UL<<13)
 #define   PIPE_CRC_DONE_INTERRUPT_STATUS       (1UL<<12)
 #define   PIPE_GMBUS_INTERRUPT_STATUS          (1UL<<11)
-#define   PLANE_FLIPDONE_INT_STATUS_VLV                (1UL<<10)
+#define   PLANE_FLIP_DONE_INT_STATUS_VLV       (1UL<<10)
 #define   PIPE_HOTPLUG_INTERRUPT_STATUS                (1UL<<10)
 #define   PIPE_VSYNC_INTERRUPT_STATUS          (1UL<<9)
 #define   PIPE_DISPLAY_LINE_COMPARE_STATUS     (1UL<<8)
 #define   PIPE_DPST_EVENT_STATUS               (1UL<<7)
 #define   PIPE_LEGACY_BLC_EVENT_STATUS         (1UL<<6)
+#define   PIPE_A_PSR_STATUS_VLV                        (1UL<<6)
 #define   PIPE_ODD_FIELD_INTERRUPT_STATUS      (1UL<<5)
 #define   PIPE_EVEN_FIELD_INTERRUPT_STATUS     (1UL<<4)
+#define   PIPE_B_PSR_STATUS_VLV                        (1UL<<3)
 #define   PIPE_HOTPLUG_TV_INTERRUPT_STATUS     (1UL<<2) /* pre-965 */
 #define   PIPE_START_VBLANK_INTERRUPT_STATUS   (1UL<<2) /* 965 or later */
 #define   PIPE_VBLANK_INTERRUPT_STATUS         (1UL<<1)
 #define   PIPE_OVERLAY_UPDATED_STATUS          (1UL<<0)
 
-#define PIPESRC(pipe) _PIPE(pipe, _PIPEASRC, _PIPEBSRC)
-#define PIPECONF(tran) _TRANSCODER(tran, _PIPEACONF, _PIPEBCONF)
-#define PIPEDSL(pipe)  _PIPE(pipe, _PIPEADSL, _PIPEBDSL)
-#define PIPEFRAME(pipe) _PIPE(pipe, _PIPEAFRAMEHIGH, _PIPEBFRAMEHIGH)
-#define PIPEFRAMEPIXEL(pipe)  _PIPE(pipe, _PIPEAFRAMEPIXEL, _PIPEBFRAMEPIXEL)
-#define PIPESTAT(pipe) _PIPE(pipe, _PIPEASTAT, _PIPEBSTAT)
+#define PIPESTAT_INT_ENABLE_MASK               0x7fff0000
+#define PIPESTAT_INT_STATUS_MASK               0x0000ffff
+
+#define PIPE_A_OFFSET  0x70000
+#define PIPE_B_OFFSET  0x71000
+#define PIPE_C_OFFSET  0x72000
+/*
+ * There's actually no pipe EDP. Some pipe registers have
+ * simply shifted from the pipe to the transcoder, while
+ * keeping their original offset. Thus we need PIPE_EDP_OFFSET
+ * to access such registers in transcoder EDP.
+ */
+#define PIPE_EDP_OFFSET        0x7f000
+
+#define _PIPE2(pipe, reg) (dev_priv->info.pipe_offsets[pipe] - \
+       dev_priv->info.pipe_offsets[PIPE_A] + (reg) + \
+       dev_priv->info.display_mmio_offset)
+
+#define PIPECONF(pipe) _PIPE2(pipe, _PIPEACONF)
+#define PIPEDSL(pipe)  _PIPE2(pipe, _PIPEADSL)
+#define PIPEFRAME(pipe) _PIPE2(pipe, _PIPEAFRAMEHIGH)
+#define PIPEFRAMEPIXEL(pipe)  _PIPE2(pipe, _PIPEAFRAMEPIXEL)
+#define PIPESTAT(pipe) _PIPE2(pipe, _PIPEASTAT)
 
 #define _PIPE_MISC_A                   0x70030
 #define _PIPE_MISC_B                   0x71030
 #define   PIPEMISC_DITHER_ENABLE       (1<<4)
 #define   PIPEMISC_DITHER_TYPE_MASK    (3<<2)
 #define   PIPEMISC_DITHER_TYPE_SP      (0<<2)
-#define PIPEMISC(pipe) _PIPE(pipe, _PIPE_MISC_A, _PIPE_MISC_B)
+#define PIPEMISC(pipe) _PIPE2(pipe, _PIPE_MISC_A)
 
 #define VLV_DPFLIPSTAT                         (VLV_DISPLAY_BASE + 0x70028)
 #define   PIPEB_LINE_COMPARE_INT_EN            (1<<29)
 #define   PIPEB_HLINE_INT_EN                   (1<<28)
 #define   PIPEB_VBLANK_INT_EN                  (1<<27)
-#define   SPRITED_FLIPDONE_INT_EN              (1<<26)
-#define   SPRITEC_FLIPDONE_INT_EN              (1<<25)
-#define   PLANEB_FLIPDONE_INT_EN               (1<<24)
+#define   SPRITED_FLIP_DONE_INT_EN             (1<<26)
+#define   SPRITEC_FLIP_DONE_INT_EN             (1<<25)
+#define   PLANEB_FLIP_DONE_INT_EN              (1<<24)
 #define   PIPEA_LINE_COMPARE_INT_EN            (1<<21)
 #define   PIPEA_HLINE_INT_EN                   (1<<20)
 #define   PIPEA_VBLANK_INT_EN                  (1<<19)
-#define   SPRITEB_FLIPDONE_INT_EN              (1<<18)
-#define   SPRITEA_FLIPDONE_INT_EN              (1<<17)
+#define   SPRITEB_FLIP_DONE_INT_EN             (1<<18)
+#define   SPRITEA_FLIP_DONE_INT_EN             (1<<17)
 #define   PLANEA_FLIPDONE_INT_EN               (1<<16)
 
 #define DPINVGTT                               (VLV_DISPLAY_BASE + 0x7002c) /* VLV only */
 #define   DSPARB_BEND_SHIFT    9 /* on 855 */
 #define   DSPARB_AEND_SHIFT    0
 
-#define DSPFW1                 (dev_priv->info->display_mmio_offset + 0x70034)
+#define DSPFW1                 (dev_priv->info.display_mmio_offset + 0x70034)
 #define   DSPFW_SR_SHIFT       23
 #define   DSPFW_SR_MASK                (0x1ff<<23)
 #define   DSPFW_CURSORB_SHIFT  16
 #define   DSPFW_PLANEB_SHIFT   8
 #define   DSPFW_PLANEB_MASK    (0x7f<<8)
 #define   DSPFW_PLANEA_MASK    (0x7f)
-#define DSPFW2                 (dev_priv->info->display_mmio_offset + 0x70038)
+#define DSPFW2                 (dev_priv->info.display_mmio_offset + 0x70038)
 #define   DSPFW_CURSORA_MASK   0x00003f00
 #define   DSPFW_CURSORA_SHIFT  8
 #define   DSPFW_PLANEC_MASK    (0x7f)
-#define DSPFW3                 (dev_priv->info->display_mmio_offset + 0x7003c)
+#define DSPFW3                 (dev_priv->info.display_mmio_offset + 0x7003c)
 #define   DSPFW_HPLL_SR_EN     (1<<31)
 #define   DSPFW_CURSOR_SR_SHIFT        24
 #define   PINEVIEW_SELF_REFRESH_EN     (1<<30)
 #define   DSPFW_HPLL_CURSOR_SHIFT      16
 #define   DSPFW_HPLL_CURSOR_MASK       (0x3f<<16)
 #define   DSPFW_HPLL_SR_MASK           (0x1ff)
-#define DSPFW4                 (dev_priv->info->display_mmio_offset + 0x70070)
-#define DSPFW7                 (dev_priv->info->display_mmio_offset + 0x7007c)
+#define DSPFW4                 (dev_priv->info.display_mmio_offset + 0x70070)
+#define DSPFW7                 (dev_priv->info.display_mmio_offset + 0x7007c)
 
 /* drain latency register values*/
 #define DRAIN_LATENCY_PRECISION_32     32
 #define   PIPE_PIXEL_MASK         0x00ffffff
 #define   PIPE_PIXEL_SHIFT        0
 /* GM45+ just has to be different */
-#define _PIPEA_FRMCOUNT_GM45   (dev_priv->info->display_mmio_offset + 0x70040)
-#define _PIPEA_FLIPCOUNT_GM45  (dev_priv->info->display_mmio_offset + 0x70044)
+#define _PIPEA_FRMCOUNT_GM45   (dev_priv->info.display_mmio_offset + 0x70040)
+#define _PIPEA_FLIPCOUNT_GM45  (dev_priv->info.display_mmio_offset + 0x70044)
 #define PIPE_FRMCOUNT_GM45(pipe) _PIPE(pipe, _PIPEA_FRMCOUNT_GM45, _PIPEB_FRMCOUNT_GM45)
 
 /* Cursor A & B regs */
-#define _CURACNTR              (dev_priv->info->display_mmio_offset + 0x70080)
+#define _CURACNTR              (dev_priv->info.display_mmio_offset + 0x70080)
 /* Old style CUR*CNTR flags (desktop 8xx) */
 #define   CURSOR_ENABLE                0x80000000
 #define   CURSOR_GAMMA_ENABLE  0x40000000
 /* New style CUR*CNTR flags */
 #define   CURSOR_MODE          0x27
 #define   CURSOR_MODE_DISABLE   0x00
+#define   CURSOR_MODE_128_32B_AX 0x02
+#define   CURSOR_MODE_256_32B_AX 0x03
 #define   CURSOR_MODE_64_32B_AX 0x07
+#define   CURSOR_MODE_128_ARGB_AX ((1 << 5) | CURSOR_MODE_128_32B_AX)
+#define   CURSOR_MODE_256_ARGB_AX ((1 << 5) | CURSOR_MODE_256_32B_AX)
 #define   CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX)
 #define   MCURSOR_PIPE_SELECT  (1 << 28)
 #define   MCURSOR_PIPE_A       0x00
 #define   MCURSOR_PIPE_B       (1 << 28)
 #define   MCURSOR_GAMMA_ENABLE  (1 << 26)
 #define   CURSOR_TRICKLE_FEED_DISABLE  (1 << 14)
-#define _CURABASE              (dev_priv->info->display_mmio_offset + 0x70084)
-#define _CURAPOS               (dev_priv->info->display_mmio_offset + 0x70088)
+#define _CURABASE              (dev_priv->info.display_mmio_offset + 0x70084)
+#define _CURAPOS               (dev_priv->info.display_mmio_offset + 0x70088)
 #define   CURSOR_POS_MASK       0x007FF
 #define   CURSOR_POS_SIGN       0x8000
 #define   CURSOR_X_SHIFT        0
 #define   CURSOR_Y_SHIFT        16
 #define CURSIZE                        0x700a0
-#define _CURBCNTR              (dev_priv->info->display_mmio_offset + 0x700c0)
-#define _CURBBASE              (dev_priv->info->display_mmio_offset + 0x700c4)
-#define _CURBPOS               (dev_priv->info->display_mmio_offset + 0x700c8)
+#define _CURBCNTR              (dev_priv->info.display_mmio_offset + 0x700c0)
+#define _CURBBASE              (dev_priv->info.display_mmio_offset + 0x700c4)
+#define _CURBPOS               (dev_priv->info.display_mmio_offset + 0x700c8)
 
 #define _CURBCNTR_IVB          0x71080
 #define _CURBBASE_IVB          0x71084
 #define CURPOS_IVB(pipe) _PIPE(pipe, _CURAPOS, _CURBPOS_IVB)
 
 /* Display A control */
-#define _DSPACNTR                (dev_priv->info->display_mmio_offset + 0x70180)
+#define _DSPACNTR                              0x70180
 #define   DISPLAY_PLANE_ENABLE                 (1<<31)
 #define   DISPLAY_PLANE_DISABLE                        0
 #define   DISPPLANE_GAMMA_ENABLE               (1<<30)
 #define   DISPPLANE_STEREO_POLARITY_SECOND     (1<<18)
 #define   DISPPLANE_TRICKLE_FEED_DISABLE       (1<<14) /* Ironlake */
 #define   DISPPLANE_TILED                      (1<<10)
-#define _DSPAADDR              (dev_priv->info->display_mmio_offset + 0x70184)
-#define _DSPASTRIDE            (dev_priv->info->display_mmio_offset + 0x70188)
-#define _DSPAPOS               (dev_priv->info->display_mmio_offset + 0x7018C) /* reserved */
-#define _DSPASIZE              (dev_priv->info->display_mmio_offset + 0x70190)
-#define _DSPASURF              (dev_priv->info->display_mmio_offset + 0x7019C) /* 965+ only */
-#define _DSPATILEOFF           (dev_priv->info->display_mmio_offset + 0x701A4) /* 965+ only */
-#define _DSPAOFFSET            (dev_priv->info->display_mmio_offset + 0x701A4) /* HSW */
-#define _DSPASURFLIVE          (dev_priv->info->display_mmio_offset + 0x701AC)
-
-#define DSPCNTR(plane) _PIPE(plane, _DSPACNTR, _DSPBCNTR)
-#define DSPADDR(plane) _PIPE(plane, _DSPAADDR, _DSPBADDR)
-#define DSPSTRIDE(plane) _PIPE(plane, _DSPASTRIDE, _DSPBSTRIDE)
-#define DSPPOS(plane) _PIPE(plane, _DSPAPOS, _DSPBPOS)
-#define DSPSIZE(plane) _PIPE(plane, _DSPASIZE, _DSPBSIZE)
-#define DSPSURF(plane) _PIPE(plane, _DSPASURF, _DSPBSURF)
-#define DSPTILEOFF(plane) _PIPE(plane, _DSPATILEOFF, _DSPBTILEOFF)
+#define _DSPAADDR                              0x70184
+#define _DSPASTRIDE                            0x70188
+#define _DSPAPOS                               0x7018C /* reserved */
+#define _DSPASIZE                              0x70190
+#define _DSPASURF                              0x7019C /* 965+ only */
+#define _DSPATILEOFF                           0x701A4 /* 965+ only */
+#define _DSPAOFFSET                            0x701A4 /* HSW */
+#define _DSPASURFLIVE                          0x701AC
+
+#define DSPCNTR(plane) _PIPE2(plane, _DSPACNTR)
+#define DSPADDR(plane) _PIPE2(plane, _DSPAADDR)
+#define DSPSTRIDE(plane) _PIPE2(plane, _DSPASTRIDE)
+#define DSPPOS(plane) _PIPE2(plane, _DSPAPOS)
+#define DSPSIZE(plane) _PIPE2(plane, _DSPASIZE)
+#define DSPSURF(plane) _PIPE2(plane, _DSPASURF)
+#define DSPTILEOFF(plane) _PIPE2(plane, _DSPATILEOFF)
 #define DSPLINOFF(plane) DSPADDR(plane)
-#define DSPOFFSET(plane) _PIPE(plane, _DSPAOFFSET, _DSPBOFFSET)
-#define DSPSURFLIVE(plane) _PIPE(plane, _DSPASURFLIVE, _DSPBSURFLIVE)
+#define DSPOFFSET(plane) _PIPE2(plane, _DSPAOFFSET)
+#define DSPSURFLIVE(plane) _PIPE2(plane, _DSPASURFLIVE)
 
 /* Display/Sprite base address macros */
 #define DISP_BASEADDR_MASK     (0xfffff000)
 #define I915_HI_DISPBASE(val)  (val & DISP_BASEADDR_MASK)
 
 /* VBIOS flags */
-#define SWF00                  (dev_priv->info->display_mmio_offset + 0x71410)
-#define SWF01                  (dev_priv->info->display_mmio_offset + 0x71414)
-#define SWF02                  (dev_priv->info->display_mmio_offset + 0x71418)
-#define SWF03                  (dev_priv->info->display_mmio_offset + 0x7141c)
-#define SWF04                  (dev_priv->info->display_mmio_offset + 0x71420)
-#define SWF05                  (dev_priv->info->display_mmio_offset + 0x71424)
-#define SWF06                  (dev_priv->info->display_mmio_offset + 0x71428)
-#define SWF10                  (dev_priv->info->display_mmio_offset + 0x70410)
-#define SWF11                  (dev_priv->info->display_mmio_offset + 0x70414)
-#define SWF14                  (dev_priv->info->display_mmio_offset + 0x71420)
-#define SWF30                  (dev_priv->info->display_mmio_offset + 0x72414)
-#define SWF31                  (dev_priv->info->display_mmio_offset + 0x72418)
-#define SWF32                  (dev_priv->info->display_mmio_offset + 0x7241c)
+#define SWF00                  (dev_priv->info.display_mmio_offset + 0x71410)
+#define SWF01                  (dev_priv->info.display_mmio_offset + 0x71414)
+#define SWF02                  (dev_priv->info.display_mmio_offset + 0x71418)
+#define SWF03                  (dev_priv->info.display_mmio_offset + 0x7141c)
+#define SWF04                  (dev_priv->info.display_mmio_offset + 0x71420)
+#define SWF05                  (dev_priv->info.display_mmio_offset + 0x71424)
+#define SWF06                  (dev_priv->info.display_mmio_offset + 0x71428)
+#define SWF10                  (dev_priv->info.display_mmio_offset + 0x70410)
+#define SWF11                  (dev_priv->info.display_mmio_offset + 0x70414)
+#define SWF14                  (dev_priv->info.display_mmio_offset + 0x71420)
+#define SWF30                  (dev_priv->info.display_mmio_offset + 0x72414)
+#define SWF31                  (dev_priv->info.display_mmio_offset + 0x72418)
+#define SWF32                  (dev_priv->info.display_mmio_offset + 0x7241c)
 
 /* Pipe B */
-#define _PIPEBDSL              (dev_priv->info->display_mmio_offset + 0x71000)
-#define _PIPEBCONF             (dev_priv->info->display_mmio_offset + 0x71008)
-#define _PIPEBSTAT             (dev_priv->info->display_mmio_offset + 0x71024)
+#define _PIPEBDSL              (dev_priv->info.display_mmio_offset + 0x71000)
+#define _PIPEBCONF             (dev_priv->info.display_mmio_offset + 0x71008)
+#define _PIPEBSTAT             (dev_priv->info.display_mmio_offset + 0x71024)
 #define _PIPEBFRAMEHIGH                0x71040
 #define _PIPEBFRAMEPIXEL       0x71044
-#define _PIPEB_FRMCOUNT_GM45   (dev_priv->info->display_mmio_offset + 0x71040)
-#define _PIPEB_FLIPCOUNT_GM45  (dev_priv->info->display_mmio_offset + 0x71044)
+#define _PIPEB_FRMCOUNT_GM45   (dev_priv->info.display_mmio_offset + 0x71040)
+#define _PIPEB_FLIPCOUNT_GM45  (dev_priv->info.display_mmio_offset + 0x71044)
 
 
 /* Display B control */
-#define _DSPBCNTR              (dev_priv->info->display_mmio_offset + 0x71180)
+#define _DSPBCNTR              (dev_priv->info.display_mmio_offset + 0x71180)
 #define   DISPPLANE_ALPHA_TRANS_ENABLE         (1<<15)
 #define   DISPPLANE_ALPHA_TRANS_DISABLE                0
 #define   DISPPLANE_SPRITE_ABOVE_DISPLAY       0
 #define   DISPPLANE_SPRITE_ABOVE_OVERLAY       (1)
-#define _DSPBADDR              (dev_priv->info->display_mmio_offset + 0x71184)
-#define _DSPBSTRIDE            (dev_priv->info->display_mmio_offset + 0x71188)
-#define _DSPBPOS               (dev_priv->info->display_mmio_offset + 0x7118C)
-#define _DSPBSIZE              (dev_priv->info->display_mmio_offset + 0x71190)
-#define _DSPBSURF              (dev_priv->info->display_mmio_offset + 0x7119C)
-#define _DSPBTILEOFF           (dev_priv->info->display_mmio_offset + 0x711A4)
-#define _DSPBOFFSET            (dev_priv->info->display_mmio_offset + 0x711A4)
-#define _DSPBSURFLIVE          (dev_priv->info->display_mmio_offset + 0x711AC)
+#define _DSPBADDR              (dev_priv->info.display_mmio_offset + 0x71184)
+#define _DSPBSTRIDE            (dev_priv->info.display_mmio_offset + 0x71188)
+#define _DSPBPOS               (dev_priv->info.display_mmio_offset + 0x7118C)
+#define _DSPBSIZE              (dev_priv->info.display_mmio_offset + 0x71190)
+#define _DSPBSURF              (dev_priv->info.display_mmio_offset + 0x7119C)
+#define _DSPBTILEOFF           (dev_priv->info.display_mmio_offset + 0x711A4)
+#define _DSPBOFFSET            (dev_priv->info.display_mmio_offset + 0x711A4)
+#define _DSPBSURFLIVE          (dev_priv->info.display_mmio_offset + 0x711AC)
 
 /* Sprite A control */
 #define _DVSACNTR              0x72180
 #define  FDI_PLL_FREQ_DISABLE_COUNT_LIMIT_MASK  0xff
 
 
-#define _PIPEA_DATA_M1           (dev_priv->info->display_mmio_offset + 0x60030)
+#define _PIPEA_DATA_M1         0x60030
 #define  PIPE_DATA_M1_OFFSET    0
-#define _PIPEA_DATA_N1           (dev_priv->info->display_mmio_offset + 0x60034)
+#define _PIPEA_DATA_N1         0x60034
 #define  PIPE_DATA_N1_OFFSET    0
 
-#define _PIPEA_DATA_M2           (dev_priv->info->display_mmio_offset + 0x60038)
+#define _PIPEA_DATA_M2         0x60038
 #define  PIPE_DATA_M2_OFFSET    0
-#define _PIPEA_DATA_N2           (dev_priv->info->display_mmio_offset + 0x6003c)
+#define _PIPEA_DATA_N2         0x6003c
 #define  PIPE_DATA_N2_OFFSET    0
 
-#define _PIPEA_LINK_M1           (dev_priv->info->display_mmio_offset + 0x60040)
+#define _PIPEA_LINK_M1         0x60040
 #define  PIPE_LINK_M1_OFFSET    0
-#define _PIPEA_LINK_N1           (dev_priv->info->display_mmio_offset + 0x60044)
+#define _PIPEA_LINK_N1         0x60044
 #define  PIPE_LINK_N1_OFFSET    0
 
-#define _PIPEA_LINK_M2           (dev_priv->info->display_mmio_offset + 0x60048)
+#define _PIPEA_LINK_M2         0x60048
 #define  PIPE_LINK_M2_OFFSET    0
-#define _PIPEA_LINK_N2           (dev_priv->info->display_mmio_offset + 0x6004c)
+#define _PIPEA_LINK_N2         0x6004c
 #define  PIPE_LINK_N2_OFFSET    0
 
 /* PIPEB timing regs are same start from 0x61000 */
 
-#define _PIPEB_DATA_M1           (dev_priv->info->display_mmio_offset + 0x61030)
-#define _PIPEB_DATA_N1           (dev_priv->info->display_mmio_offset + 0x61034)
-
-#define _PIPEB_DATA_M2           (dev_priv->info->display_mmio_offset + 0x61038)
-#define _PIPEB_DATA_N2           (dev_priv->info->display_mmio_offset + 0x6103c)
-
-#define _PIPEB_LINK_M1           (dev_priv->info->display_mmio_offset + 0x61040)
-#define _PIPEB_LINK_N1           (dev_priv->info->display_mmio_offset + 0x61044)
-
-#define _PIPEB_LINK_M2           (dev_priv->info->display_mmio_offset + 0x61048)
-#define _PIPEB_LINK_N2           (dev_priv->info->display_mmio_offset + 0x6104c)
-
-#define PIPE_DATA_M1(tran) _TRANSCODER(tran, _PIPEA_DATA_M1, _PIPEB_DATA_M1)
-#define PIPE_DATA_N1(tran) _TRANSCODER(tran, _PIPEA_DATA_N1, _PIPEB_DATA_N1)
-#define PIPE_DATA_M2(tran) _TRANSCODER(tran, _PIPEA_DATA_M2, _PIPEB_DATA_M2)
-#define PIPE_DATA_N2(tran) _TRANSCODER(tran, _PIPEA_DATA_N2, _PIPEB_DATA_N2)
-#define PIPE_LINK_M1(tran) _TRANSCODER(tran, _PIPEA_LINK_M1, _PIPEB_LINK_M1)
-#define PIPE_LINK_N1(tran) _TRANSCODER(tran, _PIPEA_LINK_N1, _PIPEB_LINK_N1)
-#define PIPE_LINK_M2(tran) _TRANSCODER(tran, _PIPEA_LINK_M2, _PIPEB_LINK_M2)
-#define PIPE_LINK_N2(tran) _TRANSCODER(tran, _PIPEA_LINK_N2, _PIPEB_LINK_N2)
+#define _PIPEB_DATA_M1         0x61030
+#define _PIPEB_DATA_N1         0x61034
+#define _PIPEB_DATA_M2         0x61038
+#define _PIPEB_DATA_N2         0x6103c
+#define _PIPEB_LINK_M1         0x61040
+#define _PIPEB_LINK_N1         0x61044
+#define _PIPEB_LINK_M2         0x61048
+#define _PIPEB_LINK_N2         0x6104c
+
+#define PIPE_DATA_M1(tran) _TRANSCODER2(tran, _PIPEA_DATA_M1)
+#define PIPE_DATA_N1(tran) _TRANSCODER2(tran, _PIPEA_DATA_N1)
+#define PIPE_DATA_M2(tran) _TRANSCODER2(tran, _PIPEA_DATA_M2)
+#define PIPE_DATA_N2(tran) _TRANSCODER2(tran, _PIPEA_DATA_N2)
+#define PIPE_LINK_M1(tran) _TRANSCODER2(tran, _PIPEA_LINK_M1)
+#define PIPE_LINK_N1(tran) _TRANSCODER2(tran, _PIPEA_LINK_N1)
+#define PIPE_LINK_M2(tran) _TRANSCODER2(tran, _PIPEA_LINK_M2)
+#define PIPE_LINK_N2(tran) _TRANSCODER2(tran, _PIPEA_LINK_N2)
 
 /* CPU panel fitter */
 /* IVB+ has 3 fitters, 0 is 7x5 capable, the other two only 3x3 */
 #define  ILK_ELPIN_409_SELECT  (1 << 25)
 #define  ILK_DPARB_GATE        (1<<22)
 #define  ILK_VSDPFD_FULL       (1<<21)
-#define ILK_DISPLAY_CHICKEN_FUSES      0x42014
-#define  ILK_INTERNAL_GRAPHICS_DISABLE (1<<31)
-#define  ILK_INTERNAL_DISPLAY_DISABLE  (1<<30)
-#define  ILK_DISPLAY_DEBUG_DISABLE     (1<<29)
-#define  ILK_HDCP_DISABLE              (1<<25)
-#define  ILK_eDP_A_DISABLE             (1<<24)
-#define  ILK_DESKTOP                   (1<<23)
+#define FUSE_STRAP                     0x42014
+#define  ILK_INTERNAL_GRAPHICS_DISABLE (1 << 31)
+#define  ILK_INTERNAL_DISPLAY_DISABLE  (1 << 30)
+#define  ILK_DISPLAY_DEBUG_DISABLE     (1 << 29)
+#define  ILK_HDCP_DISABLE              (1 << 25)
+#define  ILK_eDP_A_DISABLE             (1 << 24)
+#define  HSW_CDCLK_LIMIT               (1 << 24)
+#define  ILK_DESKTOP                   (1 << 23)
 
 #define ILK_DSPCLK_GATE_D                      0x42020
 #define   ILK_VRHUNIT_CLOCK_GATE_DISABLE       (1 << 28)
 
 #define _CHICKEN_PIPESL_1_A    0x420b0
 #define _CHICKEN_PIPESL_1_B    0x420b4
-#define  DPRS_MASK_VBLANK_SRD  (1 << 0)
+#define  HSW_FBCQ_DIS                  (1 << 22)
+#define  BDW_DPRS_MASK_VBLANK_SRD      (1 << 0)
 #define CHICKEN_PIPESL_1(pipe) _PIPE(pipe, _CHICKEN_PIPESL_1_A, _CHICKEN_PIPESL_1_B)
 
 #define DISP_ARB_CTL   0x45000
 #define GEN7_MSG_CTL   0x45010
 #define  WAIT_FOR_PCH_RESET_ACK                (1<<1)
 #define  WAIT_FOR_PCH_FLR_ACK          (1<<0)
+#define HSW_NDE_RSTWRN_OPT     0x46408
+#define  RESET_PCH_HANDSHAKE_ENABLE    (1<<4)
 
 /* GEN7 chicken */
 #define GEN7_COMMON_SLICE_CHICKEN1             0x7010
 #define COMMON_SLICE_CHICKEN2                  0x7014
 # define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE  (1<<0)
 
+#define GEN7_L3SQCREG1                         0xB010
+#define  VLV_B0_WA_L3SQCREG1_VALUE             0x00D30000
+
 #define GEN7_L3CNTLREG1                                0xB01C
-#define  GEN7_WA_FOR_GEN7_L3_CONTROL                   0x3C4FFF8C
+#define  GEN7_WA_FOR_GEN7_L3_CONTROL                   0x3C47FF8C
 #define  GEN7_L3AGDIS                          (1<<19)
 
 #define GEN7_L3_CHICKEN_MODE_REGISTER          0xB030
 #define HSW_SCRATCH1                           0xb038
 #define  HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE  (1<<27)
 
-#define HSW_FUSE_STRAP         0x42014
-#define  HSW_CDCLK_LIMIT       (1 << 24)
-
 /* PCH */
 
 /* south display engine interrupt: IBX */
 #define HSW_VIDEO_DIP_GCP_B            0x61210
 
 #define HSW_TVIDEO_DIP_CTL(trans) \
-        _TRANSCODER(trans, HSW_VIDEO_DIP_CTL_A, HSW_VIDEO_DIP_CTL_B)
+        _TRANSCODER2(trans, HSW_VIDEO_DIP_CTL_A)
 #define HSW_TVIDEO_DIP_AVI_DATA(trans) \
-        _TRANSCODER(trans, HSW_VIDEO_DIP_AVI_DATA_A, HSW_VIDEO_DIP_AVI_DATA_B)
+        _TRANSCODER2(trans, HSW_VIDEO_DIP_AVI_DATA_A)
 #define HSW_TVIDEO_DIP_VS_DATA(trans) \
-        _TRANSCODER(trans, HSW_VIDEO_DIP_VS_DATA_A, HSW_VIDEO_DIP_VS_DATA_B)
+        _TRANSCODER2(trans, HSW_VIDEO_DIP_VS_DATA_A)
 #define HSW_TVIDEO_DIP_SPD_DATA(trans) \
-        _TRANSCODER(trans, HSW_VIDEO_DIP_SPD_DATA_A, HSW_VIDEO_DIP_SPD_DATA_B)
+        _TRANSCODER2(trans, HSW_VIDEO_DIP_SPD_DATA_A)
 #define HSW_TVIDEO_DIP_GCP(trans) \
-       _TRANSCODER(trans, HSW_VIDEO_DIP_GCP_A, HSW_VIDEO_DIP_GCP_B)
+       _TRANSCODER2(trans, HSW_VIDEO_DIP_GCP_A)
 #define HSW_TVIDEO_DIP_VSC_DATA(trans) \
-        _TRANSCODER(trans, HSW_VIDEO_DIP_VSC_DATA_A, HSW_VIDEO_DIP_VSC_DATA_B)
+        _TRANSCODER2(trans, HSW_VIDEO_DIP_VSC_DATA_A)
 
 #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)
+       _PIPE2(trans, HSW_STEREO_3D_CTL_A)
 
 #define _PCH_TRANS_HTOTAL_B          0xe1000
 #define _PCH_TRANS_HBLANK_B          0xe1004
 #define GEN7_UCGCTL4                           0x940c
 #define  GEN7_L3BANK2X_CLOCK_GATE_DISABLE      (1<<25)
 
+#define GEN8_UCGCTL6                           0x9430
+#define   GEN8_SDEUNIT_CLOCK_GATE_DISABLE      (1<<14)
+
 #define GEN6_RPNSWREQ                          0xA008
 #define   GEN6_TURBO_DISABLE                   (1<<31)
 #define   GEN6_FREQUENCY(x)                    ((x)<<25)
                                                 GEN6_PM_RP_DOWN_THRESHOLD | \
                                                 GEN6_PM_RP_DOWN_TIMEOUT)
 
+#define VLV_GTLC_SURVIVABILITY_REG              0x130098
+#define VLV_GFX_CLK_STATUS_BIT                 (1<<3)
+#define VLV_GFX_CLK_FORCE_ON_BIT               (1<<2)
+
 #define GEN6_GT_GFX_RC6_LOCKED                 0x138104
 #define VLV_COUNTER_CONTROL                    0x138104
 #define   VLV_COUNT_RANGE_HIGH                 (1<<15)
 #define   GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE  (1<<10)
 #define   GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE (1<<3)
 
+#define GEN8_ROW_CHICKEN               0xe4f0
+#define   PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE        (1<<8)
+#define   STALL_DOP_GATING_DISABLE             (1<<5)
+
 #define GEN7_ROW_CHICKEN2              0xe4f4
 #define GEN7_ROW_CHICKEN2_GT2          0xf4f4
 #define   DOP_CLOCK_GATING_DISABLE     (1<<0)
 #define   GEN8_CENTROID_PIXEL_OPT_DIS  (1<<8)
 #define   GEN8_SAMPLER_POWER_BYPASS_DIS        (1<<1)
 
-#define G4X_AUD_VID_DID                        (dev_priv->info->display_mmio_offset + 0x62020)
+#define G4X_AUD_VID_DID                        (dev_priv->info.display_mmio_offset + 0x62020)
 #define INTEL_AUDIO_DEVCL              0x808629FB
 #define INTEL_AUDIO_DEVBLC             0x80862801
 #define INTEL_AUDIO_DEVCTG             0x80862802
 #define TRANS_DDI_FUNC_CTL_B           0x61400
 #define TRANS_DDI_FUNC_CTL_C           0x62400
 #define TRANS_DDI_FUNC_CTL_EDP         0x6F400
-#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER(tran, TRANS_DDI_FUNC_CTL_A, \
-                                                  TRANS_DDI_FUNC_CTL_B)
+#define TRANS_DDI_FUNC_CTL(tran) _TRANSCODER2(tran, TRANS_DDI_FUNC_CTL_A)
+
 #define  TRANS_DDI_FUNC_ENABLE         (1<<31)
 /* Those bits are ignored by pipe EDP since it can only connect to DDI A */
 #define  TRANS_DDI_PORT_MASK           (7<<28)
 #define  SPLL_PLL_ENABLE               (1<<31)
 #define  SPLL_PLL_SSC                  (1<<28)
 #define  SPLL_PLL_NON_SSC              (2<<28)
+#define  SPLL_PLL_LCPLL                        (3<<28)
+#define  SPLL_PLL_REF_MASK             (3<<28)
 #define  SPLL_PLL_FREQ_810MHz          (0<<26)
 #define  SPLL_PLL_FREQ_1350MHz         (1<<26)
+#define  SPLL_PLL_FREQ_2700MHz         (2<<26)
+#define  SPLL_PLL_FREQ_MASK            (3<<26)
 
 /* WRPLL */
 #define WRPLL_CTL1                     0x46040
 #define  WRPLL_PLL_SELECT_LCPLL_2700   (0x03<<28)
 /* WRPLL divider programming */
 #define  WRPLL_DIVIDER_REFERENCE(x)    ((x)<<0)
+#define  WRPLL_DIVIDER_REF_MASK                (0xff)
 #define  WRPLL_DIVIDER_POST(x)         ((x)<<8)
+#define  WRPLL_DIVIDER_POST_MASK       (0x3f<<8)
+#define  WRPLL_DIVIDER_POST_SHIFT      8
 #define  WRPLL_DIVIDER_FEEDBACK(x)     ((x)<<16)
+#define  WRPLL_DIVIDER_FB_SHIFT                16
+#define  WRPLL_DIVIDER_FB_MASK         (0xff<<16)
 
 /* Port clock selection */
 #define PORT_CLK_SEL_A                 0x46100
 #define  PORT_CLK_SEL_WRPLL1           (4<<29)
 #define  PORT_CLK_SEL_WRPLL2           (5<<29)
 #define  PORT_CLK_SEL_NONE             (7<<29)
+#define  PORT_CLK_SEL_MASK             (7<<29)
 
 /* Transcoder clock selection */
 #define TRANS_CLK_SEL_A                        0x46140
 #define  TRANS_CLK_SEL_DISABLED                (0x0<<29)
 #define  TRANS_CLK_SEL_PORT(x)         ((x+1)<<29)
 
-#define _TRANSA_MSA_MISC               0x60410
-#define _TRANSB_MSA_MISC               0x61410
-#define TRANS_MSA_MISC(tran) _TRANSCODER(tran, _TRANSA_MSA_MISC, \
-                                              _TRANSB_MSA_MISC)
+#define TRANSA_MSA_MISC                        0x60410
+#define TRANSB_MSA_MISC                        0x61410
+#define TRANSC_MSA_MISC                        0x62410
+#define TRANS_EDP_MSA_MISC             0x6f410
+#define TRANS_MSA_MISC(tran) _TRANSCODER2(tran, TRANSA_MSA_MISC)
+
 #define  TRANS_MSA_SYNC_CLK            (1<<0)
 #define  TRANS_MSA_6_BPC               (0<<5)
 #define  TRANS_MSA_8_BPC               (1<<5)
 
 /* SFUSE_STRAP */
 #define SFUSE_STRAP                    0xc2014
+#define  SFUSE_STRAP_FUSE_LOCK         (1<<13)
+#define  SFUSE_STRAP_DISPLAY_DISABLED  (1<<7)
 #define  SFUSE_STRAP_DDIB_DETECTED     (1<<2)
 #define  SFUSE_STRAP_DDIC_DETECTED     (1<<1)
 #define  SFUSE_STRAP_DDID_DETECTED     (1<<0)
 #define MIPI_READ_DATA_VALID(pipe)     _PIPE(pipe, _MIPIA_READ_DATA_VALID, _MIPIB_READ_DATA_VALID)
 #define  READ_DATA_VALID(n)                            (1 << (n))
 
+/* For UMS only (deprecated): */
+#define _PALETTE_A (dev_priv->info.display_mmio_offset + 0xa000)
+#define _PALETTE_B (dev_priv->info.display_mmio_offset + 0xa800)
+#define _DPLL_A (dev_priv->info.display_mmio_offset + 0x6014)
+#define _DPLL_B (dev_priv->info.display_mmio_offset + 0x6018)
+#define _DPLL_A_MD (dev_priv->info.display_mmio_offset + 0x601c)
+#define _DPLL_B_MD (dev_priv->info.display_mmio_offset + 0x6020)
+
 #endif /* _I915_REG_H_ */
index 8150fdc..56785e8 100644 (file)
@@ -236,19 +236,9 @@ static void i915_save_display(struct drm_device *dev)
                dev_priv->regfile.savePP_DIVISOR = I915_READ(PP_DIVISOR);
        }
 
-       /* Only regfile.save FBC state on the platform that supports FBC */
-       if (HAS_FBC(dev)) {
-               if (HAS_PCH_SPLIT(dev)) {
-                       dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE);
-               } else if (IS_GM45(dev)) {
-                       dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(DPFC_CB_BASE);
-               } else {
-                       dev_priv->regfile.saveFBC_CFB_BASE = I915_READ(FBC_CFB_BASE);
-                       dev_priv->regfile.saveFBC_LL_BASE = I915_READ(FBC_LL_BASE);
-                       dev_priv->regfile.saveFBC_CONTROL2 = I915_READ(FBC_CONTROL2);
-                       dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL);
-               }
-       }
+       /* save FBC interval */
+       if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
+               dev_priv->regfile.saveFBC_CONTROL = I915_READ(FBC_CONTROL);
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_save_vga(dev);
@@ -300,18 +290,10 @@ static void i915_restore_display(struct drm_device *dev)
 
        /* only restore FBC info on the platform that supports FBC*/
        intel_disable_fbc(dev);
-       if (HAS_FBC(dev)) {
-               if (HAS_PCH_SPLIT(dev)) {
-                       I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE);
-               } else if (IS_GM45(dev)) {
-                       I915_WRITE(DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE);
-               } else {
-                       I915_WRITE(FBC_CFB_BASE, dev_priv->regfile.saveFBC_CFB_BASE);
-                       I915_WRITE(FBC_LL_BASE, dev_priv->regfile.saveFBC_LL_BASE);
-                       I915_WRITE(FBC_CONTROL2, dev_priv->regfile.saveFBC_CONTROL2);
-                       I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL);
-               }
-       }
+
+       /* restore FBC interval */
+       if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
+               I915_WRITE(FBC_CONTROL, dev_priv->regfile.saveFBC_CONTROL);
 
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_restore_vga(dev);
@@ -324,10 +306,6 @@ int i915_save_state(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
-       if (INTEL_INFO(dev)->gen <= 4)
-               pci_read_config_byte(dev->pdev, LBB,
-                                    &dev_priv->regfile.saveLBB);
-
        mutex_lock(&dev->struct_mutex);
 
        i915_save_display(dev);
@@ -377,10 +355,6 @@ int i915_restore_state(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int i;
 
-       if (INTEL_INFO(dev)->gen <= 4)
-               pci_write_config_byte(dev->pdev, LBB,
-                                     dev_priv->regfile.saveLBB);
-
        mutex_lock(&dev->struct_mutex);
 
        i915_gem_restore_fences(dev);
index 33bcae3..9c57029 100644 (file)
@@ -269,7 +269,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
                freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
                ret = vlv_gpu_freq(dev_priv, (freq >> 8) & 0xff);
        } else {
-               ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
+               ret = dev_priv->rps.cur_freq * GT_FREQUENCY_MULTIPLIER;
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
 
@@ -284,7 +284,7 @@ static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        return snprintf(buf, PAGE_SIZE, "%d\n",
-                       vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay));
+                       vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
 }
 
 static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
@@ -298,9 +298,9 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute
 
        mutex_lock(&dev_priv->rps.hw_lock);
        if (IS_VALLEYVIEW(dev_priv->dev))
-               ret = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay);
+               ret = vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
        else
-               ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
+               ret = dev_priv->rps.max_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return snprintf(buf, PAGE_SIZE, "%d\n", ret);
@@ -313,7 +313,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
        struct drm_minor *minor = dev_to_drm_minor(kdev);
        struct drm_device *dev = minor->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 val, rp_state_cap, hw_max, hw_min, non_oc_max;
+       u32 val;
        ssize_t ret;
 
        ret = kstrtou32(buf, 0, &val);
@@ -324,38 +324,34 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
 
        mutex_lock(&dev_priv->rps.hw_lock);
 
-       if (IS_VALLEYVIEW(dev_priv->dev)) {
+       if (IS_VALLEYVIEW(dev_priv->dev))
                val = vlv_freq_opcode(dev_priv, val);
-
-               hw_max = valleyview_rps_max_freq(dev_priv);
-               hw_min = valleyview_rps_min_freq(dev_priv);
-               non_oc_max = hw_max;
-       } else {
+       else
                val /= GT_FREQUENCY_MULTIPLIER;
 
-               rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
-               hw_max = dev_priv->rps.hw_max;
-               non_oc_max = (rp_state_cap & 0xff);
-               hw_min = ((rp_state_cap & 0xff0000) >> 16);
-       }
-
-       if (val < hw_min || val > hw_max ||
-           val < dev_priv->rps.min_delay) {
+       if (val < dev_priv->rps.min_freq ||
+           val > dev_priv->rps.max_freq ||
+           val < dev_priv->rps.min_freq_softlimit) {
                mutex_unlock(&dev_priv->rps.hw_lock);
                return -EINVAL;
        }
 
-       if (val > non_oc_max)
+       if (val > dev_priv->rps.rp0_freq)
                DRM_DEBUG("User requested overclocking to %d\n",
                          val * GT_FREQUENCY_MULTIPLIER);
 
-       dev_priv->rps.max_delay = val;
+       dev_priv->rps.max_freq_softlimit = val;
 
-       if (dev_priv->rps.cur_delay > val) {
+       if (dev_priv->rps.cur_freq > val) {
                if (IS_VALLEYVIEW(dev))
                        valleyview_set_rps(dev, val);
                else
                        gen6_set_rps(dev, val);
+       } else if (!IS_VALLEYVIEW(dev)) {
+               /* We still need gen6_set_rps to process the new max_delay and
+                * update the interrupt limits even though frequency request is
+                * unchanged. */
+               gen6_set_rps(dev, dev_priv->rps.cur_freq);
        }
 
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -374,9 +370,9 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute
 
        mutex_lock(&dev_priv->rps.hw_lock);
        if (IS_VALLEYVIEW(dev_priv->dev))
-               ret = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay);
+               ret = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
        else
-               ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
+               ret = dev_priv->rps.min_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return snprintf(buf, PAGE_SIZE, "%d\n", ret);
@@ -389,7 +385,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
        struct drm_minor *minor = dev_to_drm_minor(kdev);
        struct drm_device *dev = minor->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 val, rp_state_cap, hw_max, hw_min;
+       u32 val;
        ssize_t ret;
 
        ret = kstrtou32(buf, 0, &val);
@@ -400,31 +396,30 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
 
        mutex_lock(&dev_priv->rps.hw_lock);
 
-       if (IS_VALLEYVIEW(dev)) {
+       if (IS_VALLEYVIEW(dev))
                val = vlv_freq_opcode(dev_priv, val);
-
-               hw_max = valleyview_rps_max_freq(dev_priv);
-               hw_min = valleyview_rps_min_freq(dev_priv);
-       } else {
+       else
                val /= GT_FREQUENCY_MULTIPLIER;
 
-               rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
-               hw_max = dev_priv->rps.hw_max;
-               hw_min = ((rp_state_cap & 0xff0000) >> 16);
-       }
-
-       if (val < hw_min || val > hw_max || val > dev_priv->rps.max_delay) {
+       if (val < dev_priv->rps.min_freq ||
+           val > dev_priv->rps.max_freq ||
+           val > dev_priv->rps.max_freq_softlimit) {
                mutex_unlock(&dev_priv->rps.hw_lock);
                return -EINVAL;
        }
 
-       dev_priv->rps.min_delay = val;
+       dev_priv->rps.min_freq_softlimit = val;
 
-       if (dev_priv->rps.cur_delay < val) {
+       if (dev_priv->rps.cur_freq < val) {
                if (IS_VALLEYVIEW(dev))
                        valleyview_set_rps(dev, val);
                else
                        gen6_set_rps(dev, val);
+       } else if (!IS_VALLEYVIEW(dev)) {
+               /* We still need gen6_set_rps to process the new min_delay and
+                * update the interrupt limits even though frequency request is
+                * unchanged. */
+               gen6_set_rps(dev, dev_priv->rps.cur_freq);
        }
 
        mutex_unlock(&dev_priv->rps.hw_lock);
index 6e580c9..23c26f1 100644 (file)
@@ -34,15 +34,15 @@ TRACE_EVENT(i915_gem_object_create,
 );
 
 TRACE_EVENT(i915_vma_bind,
-           TP_PROTO(struct i915_vma *vma, bool mappable),
-           TP_ARGS(vma, mappable),
+           TP_PROTO(struct i915_vma *vma, unsigned flags),
+           TP_ARGS(vma, flags),
 
            TP_STRUCT__entry(
                             __field(struct drm_i915_gem_object *, obj)
                             __field(struct i915_address_space *, vm)
                             __field(u32, offset)
                             __field(u32, size)
-                            __field(bool, mappable)
+                            __field(unsigned, flags)
                             ),
 
            TP_fast_assign(
@@ -50,12 +50,12 @@ TRACE_EVENT(i915_vma_bind,
                           __entry->vm = vma->vm;
                           __entry->offset = vma->node.start;
                           __entry->size = vma->node.size;
-                          __entry->mappable = mappable;
+                          __entry->flags = flags;
                           ),
 
            TP_printk("obj=%p, offset=%08x size=%x%s vm=%p",
                      __entry->obj, __entry->offset, __entry->size,
-                     __entry->mappable ? ", mappable" : "",
+                     __entry->flags & PIN_MAPPABLE ? ", mappable" : "",
                      __entry->vm)
 );
 
@@ -196,26 +196,26 @@ DEFINE_EVENT(i915_gem_object, i915_gem_object_destroy,
 );
 
 TRACE_EVENT(i915_gem_evict,
-           TP_PROTO(struct drm_device *dev, u32 size, u32 align, bool mappable),
-           TP_ARGS(dev, size, align, mappable),
+           TP_PROTO(struct drm_device *dev, u32 size, u32 align, unsigned flags),
+           TP_ARGS(dev, size, align, flags),
 
            TP_STRUCT__entry(
                             __field(u32, dev)
                             __field(u32, size)
                             __field(u32, align)
-                            __field(bool, mappable)
+                            __field(unsigned, flags)
                            ),
 
            TP_fast_assign(
                           __entry->dev = dev->primary->index;
                           __entry->size = size;
                           __entry->align = align;
-                          __entry->mappable = mappable;
+                          __entry->flags = flags;
                          ),
 
            TP_printk("dev=%d, size=%d, align=%d %s",
                      __entry->dev, __entry->size, __entry->align,
-                     __entry->mappable ? ", mappable" : "")
+                     __entry->flags & PIN_MAPPABLE ? ", mappable" : "")
 );
 
 TRACE_EVENT(i915_gem_evict_everything,
@@ -238,14 +238,16 @@ TRACE_EVENT(i915_gem_evict_vm,
            TP_ARGS(vm),
 
            TP_STRUCT__entry(
+                            __field(u32, dev)
                             __field(struct i915_address_space *, vm)
                            ),
 
            TP_fast_assign(
+                          __entry->dev = vm->dev->primary->index;
                           __entry->vm = vm;
                          ),
 
-           TP_printk("dev=%d, vm=%p", __entry->vm->dev->primary->index, __entry->vm)
+           TP_printk("dev=%d, vm=%p", __entry->dev, __entry->vm)
 );
 
 TRACE_EVENT(i915_gem_ring_sync_to,
index caa18e8..480da59 100644 (file)
@@ -271,6 +271,10 @@ void i915_save_display_reg(struct drm_device *dev)
        /* FIXME: regfile.save TV & SDVO state */
 
        /* Backlight */
+       if (INTEL_INFO(dev)->gen <= 4)
+               pci_read_config_byte(dev->pdev, PCI_LBPC,
+                                    &dev_priv->regfile.saveLBB);
+
        if (HAS_PCH_SPLIT(dev)) {
                dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1);
                dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
@@ -293,6 +297,10 @@ void i915_restore_display_reg(struct drm_device *dev)
        int i;
 
        /* Backlight */
+       if (INTEL_INFO(dev)->gen <= 4)
+               pci_write_config_byte(dev->pdev, PCI_LBPC,
+                                     dev_priv->regfile.saveLBB);
+
        if (HAS_PCH_SPLIT(dev)) {
                I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL);
                I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
index f220419..4867f4c 100644 (file)
@@ -259,7 +259,7 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
                        downclock = dvo_timing->clock;
        }
 
-       if (downclock < panel_dvo_timing->clock && i915_lvds_downclock) {
+       if (downclock < panel_dvo_timing->clock && i915.lvds_downclock) {
                dev_priv->lvds_downclock_avail = 1;
                dev_priv->lvds_downclock = downclock * 10;
                DRM_DEBUG_KMS("LVDS downclock is found in VBT. "
@@ -318,7 +318,7 @@ parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
        struct drm_display_mode *panel_fixed_mode;
        int index;
 
-       index = i915_vbt_sdvo_panel_type;
+       index = i915.vbt_sdvo_panel_type;
        if (index == -2) {
                DRM_DEBUG_KMS("Ignore SDVO panel mode from BIOS VBT tables.\n");
                return;
@@ -599,14 +599,14 @@ parse_mipi(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
 {
        struct bdb_mipi *mipi;
 
-       mipi = find_section(bdb, BDB_MIPI);
+       mipi = find_section(bdb, BDB_MIPI_CONFIG);
        if (!mipi) {
                DRM_DEBUG_KMS("No MIPI BDB found");
                return;
        }
 
        /* XXX: add more info */
-       dev_priv->vbt.dsi.panel_id = mipi->panel_id;
+       dev_priv->vbt.dsi.panel_id = MIPI_DSI_GENERIC_PANEL_ID;
 }
 
 static void parse_ddi_port(struct drm_i915_private *dev_priv, enum port port,
index 282de5e..83b7629 100644 (file)
@@ -104,7 +104,8 @@ struct vbios_data {
 #define BDB_LVDS_LFP_DATA       42
 #define BDB_LVDS_BACKLIGHT      43
 #define BDB_LVDS_POWER          44
-#define BDB_MIPI                50
+#define BDB_MIPI_CONFIG                 52
+#define BDB_MIPI_SEQUENCE       53
 #define BDB_SKIP               254 /* VBIOS private block, ignore */
 
 struct bdb_general_features {
@@ -711,44 +712,159 @@ int intel_parse_bios(struct drm_device *dev);
 #define DVO_PORT_DPD   9
 #define DVO_PORT_DPA   10
 
-/* MIPI DSI panel info */
-struct bdb_mipi {
-       u16 panel_id;
-       u16 bridge_revision;
-
-       /* General params */
-       u32 dithering:1;
-       u32 bpp_pixel_format:1;
-       u32 rsvd1:1;
-       u32 dphy_valid:1;
-       u32 resvd2:28;
+/* Block 52 contains MIPI Panel info
+ * 6 such enteries will there. Index into correct
+ * entery is based on the panel_index in #40 LFP
+ */
+#define MAX_MIPI_CONFIGURATIONS        6
 
-       u16 port_info;
-       u16 rsvd3:2;
-       u16 num_lanes:2;
-       u16 rsvd4:12;
+#define MIPI_DSI_UNDEFINED_PANEL_ID    0
+#define MIPI_DSI_GENERIC_PANEL_ID      1
 
-       /* DSI config */
-       u16 virt_ch_num:2;
-       u16 vtm:2;
-       u16 rsvd5:12;
+struct mipi_config {
+       u16 panel_id;
 
-       u32 dsi_clock;
+       /* General Params */
+       u32 enable_dithering:1;
+       u32 rsvd1:1;
+       u32 is_bridge:1;
+
+       u32 panel_arch_type:2;
+       u32 is_cmd_mode:1;
+
+#define NON_BURST_SYNC_PULSE   0x1
+#define NON_BURST_SYNC_EVENTS  0x2
+#define BURST_MODE             0x3
+       u32 video_transfer_mode:2;
+
+       u32 cabc_supported:1;
+       u32 pwm_blc:1;
+
+       /* Bit 13:10 */
+#define PIXEL_FORMAT_RGB565                    0x1
+#define PIXEL_FORMAT_RGB666                    0x2
+#define PIXEL_FORMAT_RGB666_LOOSELY_PACKED     0x3
+#define PIXEL_FORMAT_RGB888                    0x4
+       u32 videomode_color_format:4;
+
+       /* Bit 15:14 */
+#define ENABLE_ROTATION_0      0x0
+#define ENABLE_ROTATION_90     0x1
+#define ENABLE_ROTATION_180    0x2
+#define ENABLE_ROTATION_270    0x3
+       u32 rotation:2;
+       u32 bta_enabled:1;
+       u32 rsvd2:15;
+
+       /* 2 byte Port Description */
+#define DUAL_LINK_NOT_SUPPORTED        0
+#define DUAL_LINK_FRONT_BACK   1
+#define DUAL_LINK_PIXEL_ALT    2
+       u16 dual_link:2;
+       u16 lane_cnt:2;
+       u16 rsvd3:12;
+
+       u16 rsvd4;
+
+       u8 rsvd5[5];
+       u32 dsi_ddr_clk;
        u32 bridge_ref_clk;
-       u16 rsvd_pwr;
 
-       /* Dphy Params */
-       u32 prepare_cnt:5;
-       u32 rsvd6:3;
+#define  BYTE_CLK_SEL_20MHZ            0
+#define  BYTE_CLK_SEL_10MHZ            1
+#define  BYTE_CLK_SEL_5MHZ             2
+       u8 byte_clk_sel:2;
+
+       u8 rsvd6:6;
+
+       /* DPHY Flags */
+       u16 dphy_param_valid:1;
+       u16 eot_pkt_disabled:1;
+       u16 enable_clk_stop:1;
+       u16 rsvd7:13;
+
+       u32 hs_tx_timeout;
+       u32 lp_rx_timeout;
+       u32 turn_around_timeout;
+       u32 device_reset_timer;
+       u32 master_init_timer;
+       u32 dbi_bw_timer;
+       u32 lp_byte_clk_val;
+
+       /*  4 byte Dphy Params */
+       u32 prepare_cnt:6;
+       u32 rsvd8:2;
        u32 clk_zero_cnt:8;
        u32 trail_cnt:5;
-       u32 rsvd7:3;
+       u32 rsvd9:3;
        u32 exit_zero_cnt:6;
-       u32 rsvd8:2;
+       u32 rsvd10:2;
 
-       u32 hl_switch_cnt;
-       u32 lp_byte_clk;
        u32 clk_lane_switch_cnt;
+       u32 hl_switch_cnt;
+
+       u32 rsvd11[6];
+
+       /* timings based on dphy spec */
+       u8 tclk_miss;
+       u8 tclk_post;
+       u8 rsvd12;
+       u8 tclk_pre;
+       u8 tclk_prepare;
+       u8 tclk_settle;
+       u8 tclk_term_enable;
+       u8 tclk_trail;
+       u16 tclk_prepare_clkzero;
+       u8 rsvd13;
+       u8 td_term_enable;
+       u8 teot;
+       u8 ths_exit;
+       u8 ths_prepare;
+       u16 ths_prepare_hszero;
+       u8 rsvd14;
+       u8 ths_settle;
+       u8 ths_skip;
+       u8 ths_trail;
+       u8 tinit;
+       u8 tlpx;
+       u8 rsvd15[3];
+
+       /* GPIOs */
+       u8 panel_enable;
+       u8 bl_enable;
+       u8 pwm_enable;
+       u8 reset_r_n;
+       u8 pwr_down_r;
+       u8 stdby_r_n;
+
 } __packed;
 
+/* Block 52 contains MIPI configuration block
+ * 6 * bdb_mipi_config, followed by 6 pps data
+ * block below
+ *
+ * all delays has a unit of 100us
+ */
+struct mipi_pps_data {
+       u16 panel_on_delay;
+       u16 bl_enable_delay;
+       u16 bl_disable_delay;
+       u16 panel_off_delay;
+       u16 panel_power_cycle_delay;
+};
+
+struct bdb_mipi_config {
+       struct mipi_config config[MAX_MIPI_CONFIGURATIONS];
+       struct mipi_pps_data pps[MAX_MIPI_CONFIGURATIONS];
+};
+
+/* Block 53 contains MIPI sequences as needed by the panel
+ * for enabling it. This block can be variable in size and
+ * can be maximum of 6 blocks
+ */
+struct bdb_mipi_sequence {
+       u8 version;
+       u8 data[0];
+};
+
 #endif /* _I830_BIOS_H_ */
index e2e39e6..aa5a3dc 100644 (file)
@@ -68,8 +68,13 @@ static bool intel_crt_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_crt *crt = intel_encoder_to_crt(encoder);
+       enum intel_display_power_domain power_domain;
        u32 tmp;
 
+       power_domain = intel_display_port_power_domain(encoder);
+       if (!intel_display_power_enabled(dev_priv, power_domain))
+               return false;
+
        tmp = I915_READ(crt->adpa_reg);
 
        if (!(tmp & ADPA_DAC_ENABLE))
@@ -262,6 +267,10 @@ static bool intel_crt_compute_config(struct intel_encoder *encoder,
        if (HAS_PCH_LPT(dev))
                pipe_config->pipe_bpp = 24;
 
+       /* FDI must always be 2.7 GHz */
+       if (HAS_DDI(dev))
+               pipe_config->port_clock = 135000 * 2;
+
        return true;
 }
 
@@ -630,14 +639,22 @@ static enum drm_connector_status
 intel_crt_detect(struct drm_connector *connector, bool force)
 {
        struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crt *crt = intel_attached_crt(connector);
+       struct intel_encoder *intel_encoder = &crt->base;
+       enum intel_display_power_domain power_domain;
        enum drm_connector_status status;
        struct intel_load_detect_pipe tmp;
 
+       intel_runtime_pm_get(dev_priv);
+
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s] force=%d\n",
                      connector->base.id, drm_get_connector_name(connector),
                      force);
 
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
        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
@@ -645,23 +662,30 @@ intel_crt_detect(struct drm_connector *connector, bool force)
                 */
                if (intel_crt_detect_hotplug(connector)) {
                        DRM_DEBUG_KMS("CRT detected via hotplug\n");
-                       return connector_status_connected;
+                       status = connector_status_connected;
+                       goto out;
                } else
                        DRM_DEBUG_KMS("CRT not detected via hotplug\n");
        }
 
-       if (intel_crt_detect_ddc(connector))
-               return connector_status_connected;
+       if (intel_crt_detect_ddc(connector)) {
+               status = connector_status_connected;
+               goto out;
+       }
 
        /* Load detection is broken on HPD capable machines. Whoever wants a
         * broken monitor (without edid) to work behind a broken kvm (that fails
         * to have the right resistors for HP detection) needs to fix this up.
         * For now just bail out. */
-       if (I915_HAS_HOTPLUG(dev))
-               return connector_status_disconnected;
+       if (I915_HAS_HOTPLUG(dev)) {
+               status = connector_status_disconnected;
+               goto out;
+       }
 
-       if (!force)
-               return connector->status;
+       if (!force) {
+               status = connector->status;
+               goto out;
+       }
 
        /* for pre-945g platforms use load detect */
        if (intel_get_load_detect_pipe(connector, NULL, &tmp)) {
@@ -673,6 +697,10 @@ intel_crt_detect(struct drm_connector *connector, bool force)
        } else
                status = connector_status_unknown;
 
+out:
+       intel_display_power_put(dev_priv, power_domain);
+       intel_runtime_pm_put(dev_priv);
+
        return status;
 }
 
@@ -686,17 +714,28 @@ static int intel_crt_get_modes(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crt *crt = intel_attached_crt(connector);
+       struct intel_encoder *intel_encoder = &crt->base;
+       enum intel_display_power_domain power_domain;
        int ret;
        struct i2c_adapter *i2c;
 
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
        i2c = intel_gmbus_get_adapter(dev_priv, dev_priv->vbt.crt_ddc_pin);
        ret = intel_crt_ddc_get_modes(connector, i2c);
        if (ret || !IS_G4X(dev))
-               return ret;
+               goto out;
 
        /* Try to probe digital port for output in DVI-I -> VGA mode. */
        i2c = intel_gmbus_get_adapter(dev_priv, GMBUS_PORT_DPB);
-       return intel_crt_ddc_get_modes(connector, i2c);
+       ret = intel_crt_ddc_get_modes(connector, i2c);
+
+out:
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 static int intel_crt_set_property(struct drm_connector *connector,
@@ -765,6 +804,14 @@ static const struct dmi_system_id intel_no_crt[] = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
                },
        },
+       {
+               .callback = intel_no_crt_dmi_callback,
+               .ident = "DELL XPS 8700",
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "XPS 8700"),
+               },
+       },
        { }
 };
 
@@ -800,7 +847,7 @@ void intel_crt_init(struct drm_device *dev)
        intel_connector_attach_encoder(intel_connector, &crt->base);
 
        crt->base.type = INTEL_OUTPUT_ANALOG;
-       crt->base.cloneable = true;
+       crt->base.cloneable = (1 << INTEL_OUTPUT_DVO) | (1 << INTEL_OUTPUT_HDMI);
        if (IS_I830(dev))
                crt->base.crtc_mask = (1 << 0);
        else
@@ -833,6 +880,7 @@ 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;
+       intel_connector->unregister = intel_connector_unregister;
 
        drm_connector_helper_add(connector, &intel_crt_connector_helper_funcs);
 
@@ -857,4 +905,6 @@ void intel_crt_init(struct drm_device *dev)
 
                dev_priv->fdi_rx_config = I915_READ(_FDI_RXA_CTL) & fdi_config;
        }
+
+       intel_crt_reset(connector);
 }
index 234ac5f..0ad4e96 100644 (file)
@@ -633,6 +633,97 @@ static void wrpll_update_rnp(uint64_t freq2k, unsigned budget,
        /* Otherwise a < c && b >= d, do nothing */
 }
 
+static int intel_ddi_calc_wrpll_link(struct drm_i915_private *dev_priv,
+                                    int reg)
+{
+       int refclk = LC_FREQ;
+       int n, p, r;
+       u32 wrpll;
+
+       wrpll = I915_READ(reg);
+       switch (wrpll & SPLL_PLL_REF_MASK) {
+       case SPLL_PLL_SSC:
+       case SPLL_PLL_NON_SSC:
+               /*
+                * We could calculate spread here, but our checking
+                * code only cares about 5% accuracy, and spread is a max of
+                * 0.5% downspread.
+                */
+               refclk = 135;
+               break;
+       case SPLL_PLL_LCPLL:
+               refclk = LC_FREQ;
+               break;
+       default:
+               WARN(1, "bad wrpll refclk\n");
+               return 0;
+       }
+
+       r = wrpll & WRPLL_DIVIDER_REF_MASK;
+       p = (wrpll & WRPLL_DIVIDER_POST_MASK) >> WRPLL_DIVIDER_POST_SHIFT;
+       n = (wrpll & WRPLL_DIVIDER_FB_MASK) >> WRPLL_DIVIDER_FB_SHIFT;
+
+       /* Convert to KHz, p & r have a fixed point portion */
+       return (refclk * n * 100) / (p * r);
+}
+
+static void intel_ddi_clock_get(struct intel_encoder *encoder,
+                               struct intel_crtc_config *pipe_config)
+{
+       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       enum port port = intel_ddi_get_encoder_port(encoder);
+       int link_clock = 0;
+       u32 val, pll;
+
+       val = I915_READ(PORT_CLK_SEL(port));
+       switch (val & PORT_CLK_SEL_MASK) {
+       case PORT_CLK_SEL_LCPLL_810:
+               link_clock = 81000;
+               break;
+       case PORT_CLK_SEL_LCPLL_1350:
+               link_clock = 135000;
+               break;
+       case PORT_CLK_SEL_LCPLL_2700:
+               link_clock = 270000;
+               break;
+       case PORT_CLK_SEL_WRPLL1:
+               link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL1);
+               break;
+       case PORT_CLK_SEL_WRPLL2:
+               link_clock = intel_ddi_calc_wrpll_link(dev_priv, WRPLL_CTL2);
+               break;
+       case PORT_CLK_SEL_SPLL:
+               pll = I915_READ(SPLL_CTL) & SPLL_PLL_FREQ_MASK;
+               if (pll == SPLL_PLL_FREQ_810MHz)
+                       link_clock = 81000;
+               else if (pll == SPLL_PLL_FREQ_1350MHz)
+                       link_clock = 135000;
+               else if (pll == SPLL_PLL_FREQ_2700MHz)
+                       link_clock = 270000;
+               else {
+                       WARN(1, "bad spll freq\n");
+                       return;
+               }
+               break;
+       default:
+               WARN(1, "bad port clock sel\n");
+               return;
+       }
+
+       pipe_config->port_clock = link_clock * 2;
+
+       if (pipe_config->has_pch_encoder)
+               pipe_config->adjusted_mode.crtc_clock =
+                       intel_dotclock_calculate(pipe_config->port_clock,
+                                                &pipe_config->fdi_m_n);
+       else if (pipe_config->has_dp_encoder)
+               pipe_config->adjusted_mode.crtc_clock =
+                       intel_dotclock_calculate(pipe_config->port_clock,
+                                                &pipe_config->dp_m_n);
+       else
+               pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+}
+
 static void
 intel_ddi_calculate_wrpll(int clock /* in Hz */,
                          unsigned *r2_out, unsigned *n2_out, unsigned *p_out)
@@ -1017,8 +1108,13 @@ bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector)
        enum port port = intel_ddi_get_encoder_port(intel_encoder);
        enum pipe pipe = 0;
        enum transcoder cpu_transcoder;
+       enum intel_display_power_domain power_domain;
        uint32_t tmp;
 
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       if (!intel_display_power_enabled(dev_priv, power_domain))
+               return false;
+
        if (!intel_encoder->get_hw_state(intel_encoder, &pipe))
                return false;
 
@@ -1054,9 +1150,14 @@ bool intel_ddi_get_hw_state(struct intel_encoder *encoder,
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum port port = intel_ddi_get_encoder_port(encoder);
+       enum intel_display_power_domain power_domain;
        u32 tmp;
        int i;
 
+       power_domain = intel_display_port_power_domain(encoder);
+       if (!intel_display_power_enabled(dev_priv, power_domain))
+               return false;
+
        tmp = I915_READ(DDI_BUF_CTL(port));
 
        if (!(tmp & DDI_BUF_CTL_ENABLE))
@@ -1200,7 +1301,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 
        if (type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-               ironlake_edp_panel_on(intel_dp);
+               intel_edp_panel_on(intel_dp);
        }
 
        WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE);
@@ -1244,8 +1345,8 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
-               ironlake_edp_panel_vdd_on(intel_dp);
-               ironlake_edp_panel_off(intel_dp);
+               intel_edp_panel_vdd_on(intel_dp);
+               intel_edp_panel_off(intel_dp);
        }
 
        I915_WRITE(PORT_CLK_SEL(port), PORT_CLK_SEL_NONE);
@@ -1280,7 +1381,7 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
                if (port == PORT_A)
                        intel_dp_stop_link_train(intel_dp);
 
-               ironlake_edp_backlight_on(intel_dp);
+               intel_edp_backlight_on(intel_dp);
                intel_edp_psr_enable(intel_dp);
        }
 
@@ -1313,7 +1414,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
 
                intel_edp_psr_disable(intel_dp);
-               ironlake_edp_backlight_off(intel_dp);
+               intel_edp_backlight_off(intel_dp);
        }
 }
 
@@ -1325,7 +1426,7 @@ int intel_ddi_get_cdclk_freq(struct drm_i915_private *dev_priv)
 
        if (lcpll & LCPLL_CD_SOURCE_FCLK) {
                return 800000;
-       } else if (I915_READ(HSW_FUSE_STRAP) & HSW_CDCLK_LIMIT) {
+       } else if (I915_READ(FUSE_STRAP) & HSW_CDCLK_LIMIT) {
                return 450000;
        } else if (freq == LCPLL_CLK_FREQ_450) {
                return 450000;
@@ -1510,6 +1611,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
                              pipe_config->pipe_bpp, dev_priv->vbt.edp_bpp);
                dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp;
        }
+
+       intel_ddi_clock_get(encoder, pipe_config);
 }
 
 static void intel_ddi_destroy(struct drm_encoder *encoder)
@@ -1620,7 +1723,7 @@ void intel_ddi_init(struct drm_device *dev, enum port port)
 
        intel_encoder->type = INTEL_OUTPUT_UNKNOWN;
        intel_encoder->crtc_mask =  (1 << 0) | (1 << 1) | (1 << 2);
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        intel_encoder->hot_plug = intel_ddi_hot_plug;
 
        if (init_dp)
index 9b8a7c7..dae976f 100644 (file)
@@ -51,7 +51,10 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc,
 
 static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
                          int x, int y, struct drm_framebuffer *old_fb);
-
+static int intel_framebuffer_init(struct drm_device *dev,
+                                 struct intel_framebuffer *ifb,
+                                 struct drm_mode_fb_cmd2 *mode_cmd,
+                                 struct drm_i915_gem_object *obj);
 
 typedef struct {
        int     min, max;
@@ -738,10 +741,10 @@ bool intel_crtc_active(struct drm_crtc *crtc)
         * We can ditch the adjusted_mode.crtc_clock check as soon
         * as Haswell has gained clock readout/fastboot support.
         *
-        * We can ditch the crtc->fb check as soon as we can
+        * We can ditch the crtc->primary->fb check as soon as we can
         * properly reconstruct framebuffers.
         */
-       return intel_crtc->active && crtc->fb &&
+       return intel_crtc->active && crtc->primary->fb &&
                intel_crtc->config.adjusted_mode.crtc_clock;
 }
 
@@ -1030,7 +1033,7 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
        u32 val;
 
        /* ILK FDI PLL is always enabled */
-       if (dev_priv->info->gen == 5)
+       if (INTEL_INFO(dev_priv->dev)->gen == 5)
                return;
 
        /* On Haswell, DDI ports are responsible for the FDI PLL setup */
@@ -1119,7 +1122,7 @@ void assert_pipe(struct drm_i915_private *dev_priv,
        if (pipe == PIPE_A && dev_priv->quirks & QUIRK_PIPEA_FORCE)
                state = true;
 
-       if (!intel_display_power_enabled(dev_priv->dev,
+       if (!intel_display_power_enabled(dev_priv,
                                POWER_DOMAIN_TRANSCODER(cpu_transcoder))) {
                cur_state = false;
        } else {
@@ -1163,7 +1166,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
        if (INTEL_INFO(dev)->gen >= 4) {
                reg = DSPCNTR(pipe);
                val = I915_READ(reg);
-               WARN((val & DISPLAY_PLANE_ENABLE),
+               WARN(val & DISPLAY_PLANE_ENABLE,
                     "plane %c assertion failure, should be disabled but not\n",
                     plane_name(pipe));
                return;
@@ -1185,27 +1188,27 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
                                    enum pipe pipe)
 {
        struct drm_device *dev = dev_priv->dev;
-       int reg, i;
+       int reg, sprite;
        u32 val;
 
        if (IS_VALLEYVIEW(dev)) {
-               for (i = 0; i < dev_priv->num_plane; i++) {
-                       reg = SPCNTR(pipe, i);
+               for_each_sprite(pipe, sprite) {
+                       reg = SPCNTR(pipe, sprite);
                        val = I915_READ(reg);
-                       WARN((val & SP_ENABLE),
+                       WARN(val & SP_ENABLE,
                             "sprite %c assertion failure, should be off on pipe %c but is still active\n",
-                            sprite_name(pipe, i), pipe_name(pipe));
+                            sprite_name(pipe, sprite), pipe_name(pipe));
                }
        } else if (INTEL_INFO(dev)->gen >= 7) {
                reg = SPRCTL(pipe);
                val = I915_READ(reg);
-               WARN((val & SPRITE_ENABLE),
+               WARN(val & SPRITE_ENABLE,
                     "sprite %c assertion failure, should be off on pipe %c but is still active\n",
                     plane_name(pipe), pipe_name(pipe));
        } else if (INTEL_INFO(dev)->gen >= 5) {
                reg = DVSCNTR(pipe);
                val = I915_READ(reg);
-               WARN((val & DVS_ENABLE),
+               WARN(val & DVS_ENABLE,
                     "sprite %c assertion failure, should be off on pipe %c but is still active\n",
                     plane_name(pipe), pipe_name(pipe));
        }
@@ -1443,7 +1446,7 @@ static void i9xx_enable_pll(struct intel_crtc *crtc)
        assert_pipe_disabled(dev_priv, crtc->pipe);
 
        /* No really, not for ILK+ */
-       BUG_ON(dev_priv->info->gen >= 5);
+       BUG_ON(INTEL_INFO(dev)->gen >= 5);
 
        /* PLL is protected by panel, make sure we can write it */
        if (IS_MOBILE(dev) && !IS_I830(dev))
@@ -1549,11 +1552,12 @@ void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
  */
 static void ironlake_enable_shared_dpll(struct intel_crtc *crtc)
 {
-       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
 
        /* PCH PLLs only available on ILK, SNB and IVB */
-       BUG_ON(dev_priv->info->gen < 5);
+       BUG_ON(INTEL_INFO(dev)->gen < 5);
        if (WARN_ON(pll == NULL))
                return;
 
@@ -1578,11 +1582,12 @@ static void ironlake_enable_shared_dpll(struct intel_crtc *crtc)
 
 static void intel_disable_shared_dpll(struct intel_crtc *crtc)
 {
-       struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_shared_dpll *pll = intel_crtc_to_shared_dpll(crtc);
 
        /* PCH only available on ILK+ */
-       BUG_ON(dev_priv->info->gen < 5);
+       BUG_ON(INTEL_INFO(dev)->gen < 5);
        if (WARN_ON(pll == NULL))
               return;
 
@@ -1617,7 +1622,7 @@ static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
        uint32_t reg, val, pipeconf_val;
 
        /* PCH only available on ILK+ */
-       BUG_ON(dev_priv->info->gen < 5);
+       BUG_ON(INTEL_INFO(dev)->gen < 5);
 
        /* Make sure PCH DPLL is enabled */
        assert_shared_dpll_enabled(dev_priv,
@@ -1670,7 +1675,7 @@ static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
        u32 val, pipeconf_val;
 
        /* PCH only available on ILK+ */
-       BUG_ON(dev_priv->info->gen < 5);
+       BUG_ON(INTEL_INFO(dev_priv->dev)->gen < 5);
 
        /* FDI must be feeding us bits for PCH ports */
        assert_fdi_tx_enabled(dev_priv, (enum pipe) cpu_transcoder);
@@ -1744,21 +1749,16 @@ static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv)
 
 /**
  * intel_enable_pipe - enable a pipe, asserting requirements
- * @dev_priv: i915 private structure
- * @pipe: pipe to enable
- * @pch_port: on ILK+, is this pipe driving a PCH port or not
+ * @crtc: crtc responsible for the pipe
  *
- * Enable @pipe, making sure that various hardware specific requirements
+ * Enable @crtc's pipe, making sure that various hardware specific requirements
  * are met, if applicable, e.g. PLL enabled, LVDS pairs enabled, etc.
- *
- * @pipe should be %PIPE_A or %PIPE_B.
- *
- * Will wait until the pipe is actually running (i.e. first vblank) before
- * returning.
  */
-static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
-                             bool pch_port, bool dsi)
+static void intel_enable_pipe(struct intel_crtc *crtc)
 {
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe = crtc->pipe;
        enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
                                                                      pipe);
        enum pipe pch_transcoder;
@@ -1780,12 +1780,12 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
         * need the check.
         */
        if (!HAS_PCH_SPLIT(dev_priv->dev))
-               if (dsi)
+               if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DSI))
                        assert_dsi_pll_enabled(dev_priv);
                else
                        assert_pll_enabled(dev_priv, pipe);
        else {
-               if (pch_port) {
+               if (crtc->config.has_pch_encoder) {
                        /* if driving the PCH, we need FDI enabled */
                        assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder);
                        assert_fdi_tx_pll_enabled(dev_priv,
@@ -1796,11 +1796,24 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
 
        reg = PIPECONF(cpu_transcoder);
        val = I915_READ(reg);
-       if (val & PIPECONF_ENABLE)
+       if (val & PIPECONF_ENABLE) {
+               WARN_ON(!(pipe == PIPE_A &&
+                         dev_priv->quirks & QUIRK_PIPEA_FORCE));
                return;
+       }
 
        I915_WRITE(reg, val | PIPECONF_ENABLE);
-       intel_wait_for_vblank(dev_priv->dev, pipe);
+       POSTING_READ(reg);
+
+       /*
+        * There's no guarantee the pipe will really start running now. It
+        * depends on the Gen, the output type and the relative order between
+        * pipe and plane enabling. Avoid waiting on HSW+ since it's not
+        * necessary.
+        * TODO: audit the previous gens.
+        */
+       if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
+               intel_wait_for_vblank(dev_priv->dev, pipe);
 }
 
 /**
@@ -1851,22 +1864,23 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
 void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
                               enum plane plane)
 {
-       u32 reg = dev_priv->info->gen >= 4 ? DSPSURF(plane) : DSPADDR(plane);
+       struct drm_device *dev = dev_priv->dev;
+       u32 reg = INTEL_INFO(dev)->gen >= 4 ? DSPSURF(plane) : DSPADDR(plane);
 
        I915_WRITE(reg, I915_READ(reg));
        POSTING_READ(reg);
 }
 
 /**
- * intel_enable_primary_plane - enable the primary plane on a given pipe
+ * intel_enable_primary_hw_plane - enable the primary plane on a given pipe
  * @dev_priv: i915 private structure
  * @plane: plane to enable
  * @pipe: pipe being fed
  *
  * Enable @plane on @pipe, making sure that @pipe is running first.
  */
-static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
-                                      enum plane plane, enum pipe pipe)
+static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
+                                         enum plane plane, enum pipe pipe)
 {
        struct intel_crtc *intel_crtc =
                to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
@@ -1891,15 +1905,15 @@ static void intel_enable_primary_plane(struct drm_i915_private *dev_priv,
 }
 
 /**
- * intel_disable_primary_plane - disable the primary plane
+ * intel_disable_primary_hw_plane - disable the primary hardware plane
  * @dev_priv: i915 private structure
  * @plane: plane to disable
  * @pipe: pipe consuming the data
  *
  * Disable @plane; should be an independent operation.
  */
-static void intel_disable_primary_plane(struct drm_i915_private *dev_priv,
-                                       enum plane plane, enum pipe pipe)
+static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
+                                          enum plane plane, enum pipe pipe)
 {
        struct intel_crtc *intel_crtc =
                to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
@@ -1929,6 +1943,14 @@ static bool need_vtd_wa(struct drm_device *dev)
        return false;
 }
 
+static int intel_align_height(struct drm_device *dev, int height, bool tiled)
+{
+       int tile_height;
+
+       tile_height = tiled ? (IS_GEN2(dev) ? 16 : 8) : 1;
+       return ALIGN(height, tile_height);
+}
+
 int
 intel_pin_and_fence_fb_obj(struct drm_device *dev,
                           struct drm_i915_gem_object *obj,
@@ -2025,8 +2047,114 @@ unsigned long intel_gen4_compute_page_offset(int *x, int *y,
        }
 }
 
-static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
-                            int x, int y)
+int intel_format_to_fourcc(int format)
+{
+       switch (format) {
+       case DISPPLANE_8BPP:
+               return DRM_FORMAT_C8;
+       case DISPPLANE_BGRX555:
+               return DRM_FORMAT_XRGB1555;
+       case DISPPLANE_BGRX565:
+               return DRM_FORMAT_RGB565;
+       default:
+       case DISPPLANE_BGRX888:
+               return DRM_FORMAT_XRGB8888;
+       case DISPPLANE_RGBX888:
+               return DRM_FORMAT_XBGR8888;
+       case DISPPLANE_BGRX101010:
+               return DRM_FORMAT_XRGB2101010;
+       case DISPPLANE_RGBX101010:
+               return DRM_FORMAT_XBGR2101010;
+       }
+}
+
+static bool intel_alloc_plane_obj(struct intel_crtc *crtc,
+                                 struct intel_plane_config *plane_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_gem_object *obj = NULL;
+       struct drm_mode_fb_cmd2 mode_cmd = { 0 };
+       u32 base = plane_config->base;
+
+       if (plane_config->size == 0)
+               return false;
+
+       obj = i915_gem_object_create_stolen_for_preallocated(dev, base, base,
+                                                            plane_config->size);
+       if (!obj)
+               return false;
+
+       if (plane_config->tiled) {
+               obj->tiling_mode = I915_TILING_X;
+               obj->stride = crtc->base.primary->fb->pitches[0];
+       }
+
+       mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format;
+       mode_cmd.width = crtc->base.primary->fb->width;
+       mode_cmd.height = crtc->base.primary->fb->height;
+       mode_cmd.pitches[0] = crtc->base.primary->fb->pitches[0];
+
+       mutex_lock(&dev->struct_mutex);
+
+       if (intel_framebuffer_init(dev, to_intel_framebuffer(crtc->base.primary->fb),
+                                  &mode_cmd, obj)) {
+               DRM_DEBUG_KMS("intel fb init failed\n");
+               goto out_unref_obj;
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       DRM_DEBUG_KMS("plane fb obj %p\n", obj);
+       return true;
+
+out_unref_obj:
+       drm_gem_object_unreference(&obj->base);
+       mutex_unlock(&dev->struct_mutex);
+       return false;
+}
+
+static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
+                                struct intel_plane_config *plane_config)
+{
+       struct drm_device *dev = intel_crtc->base.dev;
+       struct drm_crtc *c;
+       struct intel_crtc *i;
+       struct intel_framebuffer *fb;
+
+       if (!intel_crtc->base.primary->fb)
+               return;
+
+       if (intel_alloc_plane_obj(intel_crtc, plane_config))
+               return;
+
+       kfree(intel_crtc->base.primary->fb);
+       intel_crtc->base.primary->fb = NULL;
+
+       /*
+        * Failed to alloc the obj, check to see if we should share
+        * an fb with another CRTC instead
+        */
+       list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
+               i = to_intel_crtc(c);
+
+               if (c == &intel_crtc->base)
+                       continue;
+
+               if (!i->active || !c->primary->fb)
+                       continue;
+
+               fb = to_intel_framebuffer(c->primary->fb);
+               if (i915_gem_obj_ggtt_offset(fb->obj) == plane_config->base) {
+                       drm_framebuffer_reference(c->primary->fb);
+                       intel_crtc->base.primary->fb = c->primary->fb;
+                       break;
+               }
+       }
+}
+
+static int i9xx_update_primary_plane(struct drm_crtc *crtc,
+                                    struct drm_framebuffer *fb,
+                                    int x, int y)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2125,8 +2253,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        return 0;
 }
 
-static int ironlake_update_plane(struct drm_crtc *crtc,
-                                struct drm_framebuffer *fb, int x, int y)
+static int ironlake_update_primary_plane(struct drm_crtc *crtc,
+                                        struct drm_framebuffer *fb,
+                                        int x, int y)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2230,7 +2359,7 @@ intel_pipe_set_base_atomic(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                dev_priv->display.disable_fbc(dev);
        intel_increase_pllclock(crtc);
 
-       return dev_priv->display.update_plane(crtc, fb, x, y);
+       return dev_priv->display.update_primary_plane(crtc, fb, x, y);
 }
 
 void intel_display_handle_reset(struct drm_device *dev)
@@ -2267,11 +2396,13 @@ void intel_display_handle_reset(struct drm_device *dev)
                /*
                 * FIXME: Once we have proper support for primary planes (and
                 * disabling them without disabling the entire crtc) allow again
-                * a NULL crtc->fb.
+                * a NULL crtc->primary->fb.
                 */
-               if (intel_crtc->active && crtc->fb)
-                       dev_priv->display.update_plane(crtc, crtc->fb,
-                                                      crtc->x, crtc->y);
+               if (intel_crtc->active && crtc->primary->fb)
+                       dev_priv->display.update_primary_plane(crtc,
+                                                              crtc->primary->fb,
+                                                              crtc->x,
+                                                              crtc->y);
                mutex_unlock(&crtc->mutex);
        }
 }
@@ -2299,31 +2430,23 @@ intel_finish_fb(struct drm_framebuffer *old_fb)
        return ret;
 }
 
-static void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y)
+static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_master_private *master_priv;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       unsigned long flags;
+       bool pending;
 
-       if (!dev->primary->master)
-               return;
+       if (i915_reset_in_progress(&dev_priv->gpu_error) ||
+           intel_crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter))
+               return false;
 
-       master_priv = dev->primary->master->driver_priv;
-       if (!master_priv->sarea_priv)
-               return;
+       spin_lock_irqsave(&dev->event_lock, flags);
+       pending = to_intel_crtc(crtc)->unpin_work != NULL;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       switch (intel_crtc->pipe) {
-       case 0:
-               master_priv->sarea_priv->pipeA_x = x;
-               master_priv->sarea_priv->pipeA_y = y;
-               break;
-       case 1:
-               master_priv->sarea_priv->pipeB_x = x;
-               master_priv->sarea_priv->pipeB_y = y;
-               break;
-       default:
-               break;
-       }
+       return pending;
 }
 
 static int
@@ -2336,6 +2459,11 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        struct drm_framebuffer *old_fb;
        int ret;
 
+       if (intel_crtc_has_pending_flip(crtc)) {
+               DRM_ERROR("pipe is still busy with an old pageflip\n");
+               return -EBUSY;
+       }
+
        /* no fb bound */
        if (!fb) {
                DRM_ERROR("No FB bound\n");
@@ -2353,8 +2481,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        ret = intel_pin_and_fence_fb_obj(dev,
                                         to_intel_framebuffer(fb)->obj,
                                         NULL);
+       mutex_unlock(&dev->struct_mutex);
        if (ret != 0) {
-               mutex_unlock(&dev->struct_mutex);
                DRM_ERROR("pin & fence failed\n");
                return ret;
        }
@@ -2372,7 +2500,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
         * whether the platform allows pfit disable with pipe active, and only
         * then update the pipesrc and pfit state, even on the flip path.
         */
-       if (i915_fastboot) {
+       if (i915.fastboot) {
                const struct drm_display_mode *adjusted_mode =
                        &intel_crtc->config.adjusted_mode;
 
@@ -2390,31 +2518,33 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                intel_crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay;
        }
 
-       ret = dev_priv->display.update_plane(crtc, fb, x, y);
+       ret = dev_priv->display.update_primary_plane(crtc, fb, x, y);
        if (ret) {
+               mutex_lock(&dev->struct_mutex);
                intel_unpin_fb_obj(to_intel_framebuffer(fb)->obj);
                mutex_unlock(&dev->struct_mutex);
                DRM_ERROR("failed to update base address\n");
                return ret;
        }
 
-       old_fb = crtc->fb;
-       crtc->fb = fb;
+       old_fb = crtc->primary->fb;
+       crtc->primary->fb = fb;
        crtc->x = x;
        crtc->y = y;
 
        if (old_fb) {
                if (intel_crtc->active && old_fb != fb)
                        intel_wait_for_vblank(dev, intel_crtc->pipe);
+               mutex_lock(&dev->struct_mutex);
                intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
+               mutex_unlock(&dev->struct_mutex);
        }
 
+       mutex_lock(&dev->struct_mutex);
        intel_update_fbc(dev);
        intel_edp_psr_update(dev);
        mutex_unlock(&dev->struct_mutex);
 
-       intel_crtc_update_sarea_pos(crtc, x, y);
-
        return 0;
 }
 
@@ -2963,25 +3093,6 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc)
        udelay(100);
 }
 
-static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       unsigned long flags;
-       bool pending;
-
-       if (i915_reset_in_progress(&dev_priv->gpu_error) ||
-           intel_crtc->reset_counter != atomic_read(&dev_priv->gpu_error.reset_counter))
-               return false;
-
-       spin_lock_irqsave(&dev->event_lock, flags);
-       pending = to_intel_crtc(crtc)->unpin_work != NULL;
-       spin_unlock_irqrestore(&dev->event_lock, flags);
-
-       return pending;
-}
-
 bool intel_has_pending_fb_unpin(struct drm_device *dev)
 {
        struct intel_crtc *crtc;
@@ -3011,7 +3122,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (crtc->fb == NULL)
+       if (crtc->primary->fb == NULL)
                return;
 
        WARN_ON(waitqueue_active(&dev_priv->pending_flip_queue));
@@ -3020,7 +3131,7 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
                   !intel_crtc_has_pending_flip(crtc));
 
        mutex_lock(&dev->struct_mutex);
-       intel_finish_fb(crtc->fb);
+       intel_finish_fb(crtc->primary->fb);
        mutex_unlock(&dev->struct_mutex);
 }
 
@@ -3425,22 +3536,28 @@ static void intel_enable_planes(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        enum pipe pipe = to_intel_crtc(crtc)->pipe;
+       struct drm_plane *plane;
        struct intel_plane *intel_plane;
 
-       list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+       drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
+               intel_plane = to_intel_plane(plane);
                if (intel_plane->pipe == pipe)
                        intel_plane_restore(&intel_plane->base);
+       }
 }
 
 static void intel_disable_planes(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        enum pipe pipe = to_intel_crtc(crtc)->pipe;
+       struct drm_plane *plane;
        struct intel_plane *intel_plane;
 
-       list_for_each_entry(intel_plane, &dev->mode_config.plane_list, base.head)
+       drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
+               intel_plane = to_intel_plane(plane);
                if (intel_plane->pipe == pipe)
                        intel_plane_disable(&intel_plane->base);
+       }
 }
 
 void hsw_enable_ips(struct intel_crtc *crtc)
@@ -3587,9 +3704,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        intel_crtc_load_lut(crtc);
 
        intel_update_watermarks(crtc);
-       intel_enable_pipe(dev_priv, pipe,
-                         intel_crtc->config.has_pch_encoder, false);
-       intel_enable_primary_plane(dev_priv, plane, pipe);
+       intel_enable_pipe(intel_crtc);
+       intel_enable_primary_hw_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
 
@@ -3631,7 +3747,7 @@ static void haswell_crtc_enable_planes(struct drm_crtc *crtc)
        int pipe = intel_crtc->pipe;
        int plane = intel_crtc->plane;
 
-       intel_enable_primary_plane(dev_priv, plane, pipe);
+       intel_enable_primary_hw_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
 
@@ -3661,7 +3777,7 @@ static void haswell_crtc_disable_planes(struct drm_crtc *crtc)
 
        intel_crtc_update_cursor(crtc, false);
        intel_disable_planes(crtc);
-       intel_disable_primary_plane(dev_priv, plane, pipe);
+       intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 }
 
 /*
@@ -3733,8 +3849,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        intel_ddi_enable_transcoder_func(crtc);
 
        intel_update_watermarks(crtc);
-       intel_enable_pipe(dev_priv, pipe,
-                         intel_crtc->config.has_pch_encoder, false);
+       intel_enable_pipe(intel_crtc);
 
        if (intel_crtc->config.has_pch_encoder)
                lpt_pch_enable(crtc);
@@ -3748,16 +3863,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
         * to change the workaround. */
        haswell_mode_set_planes_workaround(intel_crtc);
        haswell_crtc_enable_planes(crtc);
-
-       /*
-        * There seems to be a race in PCH platform hw (at least on some
-        * outputs) where an enabled pipe still completes any pageflip right
-        * away (as if the pipe is off) instead of waiting for vblank. As soon
-        * as the first vblank happend, everything works as expected. Hence just
-        * wait for one vblank before returning to avoid strange things
-        * happening.
-        */
-       intel_wait_for_vblank(dev, intel_crtc->pipe);
 }
 
 static void ironlake_pfit_disable(struct intel_crtc *crtc)
@@ -3800,7 +3905,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 
        intel_crtc_update_cursor(crtc, false);
        intel_disable_planes(crtc);
-       intel_disable_primary_plane(dev_priv, plane, pipe);
+       intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 
        if (intel_crtc->config.has_pch_encoder)
                intel_set_pch_fifo_underrun_reporting(dev, pipe, false);
@@ -3972,6 +4077,117 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)
        I915_WRITE(BCLRPAT(crtc->pipe), 0);
 }
 
+#define for_each_power_domain(domain, mask)                            \
+       for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++)     \
+               if ((1 << (domain)) & (mask))
+
+enum intel_display_power_domain
+intel_display_port_power_domain(struct intel_encoder *intel_encoder)
+{
+       struct drm_device *dev = intel_encoder->base.dev;
+       struct intel_digital_port *intel_dig_port;
+
+       switch (intel_encoder->type) {
+       case INTEL_OUTPUT_UNKNOWN:
+               /* Only DDI platforms should ever use this output type */
+               WARN_ON_ONCE(!HAS_DDI(dev));
+       case INTEL_OUTPUT_DISPLAYPORT:
+       case INTEL_OUTPUT_HDMI:
+       case INTEL_OUTPUT_EDP:
+               intel_dig_port = enc_to_dig_port(&intel_encoder->base);
+               switch (intel_dig_port->port) {
+               case PORT_A:
+                       return POWER_DOMAIN_PORT_DDI_A_4_LANES;
+               case PORT_B:
+                       return POWER_DOMAIN_PORT_DDI_B_4_LANES;
+               case PORT_C:
+                       return POWER_DOMAIN_PORT_DDI_C_4_LANES;
+               case PORT_D:
+                       return POWER_DOMAIN_PORT_DDI_D_4_LANES;
+               default:
+                       WARN_ON_ONCE(1);
+                       return POWER_DOMAIN_PORT_OTHER;
+               }
+       case INTEL_OUTPUT_ANALOG:
+               return POWER_DOMAIN_PORT_CRT;
+       case INTEL_OUTPUT_DSI:
+               return POWER_DOMAIN_PORT_DSI;
+       default:
+               return POWER_DOMAIN_PORT_OTHER;
+       }
+}
+
+static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct intel_encoder *intel_encoder;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum pipe pipe = intel_crtc->pipe;
+       bool pfit_enabled = intel_crtc->config.pch_pfit.enabled;
+       unsigned long mask;
+       enum transcoder transcoder;
+
+       transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe);
+
+       mask = BIT(POWER_DOMAIN_PIPE(pipe));
+       mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
+       if (pfit_enabled)
+               mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe));
+
+       for_each_encoder_on_crtc(dev, crtc, intel_encoder)
+               mask |= BIT(intel_display_port_power_domain(intel_encoder));
+
+       return mask;
+}
+
+void intel_display_set_init_power(struct drm_i915_private *dev_priv,
+                                 bool enable)
+{
+       if (dev_priv->power_domains.init_power_on == enable)
+               return;
+
+       if (enable)
+               intel_display_power_get(dev_priv, POWER_DOMAIN_INIT);
+       else
+               intel_display_power_put(dev_priv, POWER_DOMAIN_INIT);
+
+       dev_priv->power_domains.init_power_on = enable;
+}
+
+static void modeset_update_crtc_power_domains(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long pipe_domains[I915_MAX_PIPES] = { 0, };
+       struct intel_crtc *crtc;
+
+       /*
+        * First get all needed power domains, then put all unneeded, to avoid
+        * any unnecessary toggling of the power wells.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+               enum intel_display_power_domain domain;
+
+               if (!crtc->base.enabled)
+                       continue;
+
+               pipe_domains[crtc->pipe] = get_crtc_power_domains(&crtc->base);
+
+               for_each_power_domain(domain, pipe_domains[crtc->pipe])
+                       intel_display_power_get(dev_priv, domain);
+       }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+               enum intel_display_power_domain domain;
+
+               for_each_power_domain(domain, crtc->enabled_power_domains)
+                       intel_display_power_put(dev_priv, domain);
+
+               crtc->enabled_power_domains = pipe_domains[crtc->pipe];
+       }
+
+       intel_display_set_init_power(dev_priv, false);
+}
+
 int valleyview_get_vco(struct drm_i915_private *dev_priv)
 {
        int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 };
@@ -4088,9 +4304,8 @@ static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
        /* Looks like the 200MHz CDclk freq doesn't work on some configs */
 }
 
-static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv,
-                                unsigned modeset_pipes,
-                                struct intel_crtc_config *pipe_config)
+/* compute the max pixel clock for new configuration */
+static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
        struct intel_crtc *intel_crtc;
@@ -4098,31 +4313,26 @@ static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv,
 
        list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
                            base.head) {
-               if (modeset_pipes & (1 << intel_crtc->pipe))
+               if (intel_crtc->new_enabled)
                        max_pixclk = max(max_pixclk,
-                                        pipe_config->adjusted_mode.crtc_clock);
-               else if (intel_crtc->base.enabled)
-                       max_pixclk = max(max_pixclk,
-                                        intel_crtc->config.adjusted_mode.crtc_clock);
+                                        intel_crtc->new_config->adjusted_mode.crtc_clock);
        }
 
        return max_pixclk;
 }
 
 static void valleyview_modeset_global_pipes(struct drm_device *dev,
-                                           unsigned *prepare_pipes,
-                                           unsigned modeset_pipes,
-                                           struct intel_crtc_config *pipe_config)
+                                           unsigned *prepare_pipes)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc;
-       int max_pixclk = intel_mode_max_pixclk(dev_priv, modeset_pipes,
-                                              pipe_config);
+       int max_pixclk = intel_mode_max_pixclk(dev_priv);
        int cur_cdclk = valleyview_cur_cdclk(dev_priv);
 
        if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk)
                return;
 
+       /* disable/enable all currently active pipes while we change cdclk */
        list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
                            base.head)
                if (intel_crtc->base.enabled)
@@ -4132,12 +4342,13 @@ static void valleyview_modeset_global_pipes(struct drm_device *dev,
 static void valleyview_modeset_global_resources(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int max_pixclk = intel_mode_max_pixclk(dev_priv, 0, NULL);
+       int max_pixclk = intel_mode_max_pixclk(dev_priv);
        int cur_cdclk = valleyview_cur_cdclk(dev_priv);
        int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
 
        if (req_cdclk != cur_cdclk)
                valleyview_set_cdclk(dev, req_cdclk);
+       modeset_update_crtc_power_domains(dev);
 }
 
 static void valleyview_crtc_enable(struct drm_crtc *crtc)
@@ -4175,8 +4386,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
        intel_crtc_load_lut(crtc);
 
        intel_update_watermarks(crtc);
-       intel_enable_pipe(dev_priv, pipe, false, is_dsi);
-       intel_enable_primary_plane(dev_priv, plane, pipe);
+       intel_enable_pipe(intel_crtc);
+       intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+       intel_enable_primary_hw_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
 
@@ -4213,8 +4425,9 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
        intel_crtc_load_lut(crtc);
 
        intel_update_watermarks(crtc);
-       intel_enable_pipe(dev_priv, pipe, false, false);
-       intel_enable_primary_plane(dev_priv, plane, pipe);
+       intel_enable_pipe(intel_crtc);
+       intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
+       intel_enable_primary_hw_plane(dev_priv, plane, pipe);
        intel_enable_planes(crtc);
        /* The fixup needs to happen before cursor is enabled */
        if (IS_G4X(dev))
@@ -4270,8 +4483,9 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
        intel_crtc_dpms_overlay(intel_crtc, false);
        intel_crtc_update_cursor(crtc, false);
        intel_disable_planes(crtc);
-       intel_disable_primary_plane(dev_priv, plane, pipe);
+       intel_disable_primary_hw_plane(dev_priv, plane, pipe);
 
+       intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
        intel_disable_pipe(dev_priv, pipe);
 
        i9xx_pfit_disable(intel_crtc);
@@ -4365,11 +4579,11 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
        assert_cursor_disabled(dev_priv, to_intel_crtc(crtc)->pipe);
        assert_pipe_disabled(dev->dev_private, to_intel_crtc(crtc)->pipe);
 
-       if (crtc->fb) {
+       if (crtc->primary->fb) {
                mutex_lock(&dev->struct_mutex);
-               intel_unpin_fb_obj(to_intel_framebuffer(crtc->fb)->obj);
+               intel_unpin_fb_obj(to_intel_framebuffer(crtc->primary->fb)->obj);
                mutex_unlock(&dev->struct_mutex);
-               crtc->fb = NULL;
+               crtc->primary->fb = NULL;
        }
 
        /* Update computed state. */
@@ -4583,7 +4797,7 @@ retry:
 static void hsw_compute_ips_config(struct intel_crtc *crtc,
                                   struct intel_crtc_config *pipe_config)
 {
-       pipe_config->ips_enabled = i915_enable_ips &&
+       pipe_config->ips_enabled = i915.enable_ips &&
                                   hsw_crtc_supports_ips(crtc) &&
                                   pipe_config->pipe_bpp <= 24;
 }
@@ -4784,8 +4998,8 @@ intel_link_compute_m_n(int bits_per_pixel, int nlanes,
 
 static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
 {
-       if (i915_panel_use_ssc >= 0)
-               return i915_panel_use_ssc != 0;
+       if (i915.panel_use_ssc >= 0)
+               return i915.panel_use_ssc != 0;
        return dev_priv->vbt.lvds_use_ssc
                && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
 }
@@ -4844,7 +5058,7 @@ static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
 
        crtc->lowfreq_avail = false;
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_LVDS) &&
-           reduced_clock && i915_powersave) {
+           reduced_clock && i915.powersave) {
                I915_WRITE(FP1(pipe), fp2);
                crtc->config.dpll_hw_state.fp1 = fp2;
                crtc->lowfreq_avail = true;
@@ -5161,21 +5375,26 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
        enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
        struct drm_display_mode *adjusted_mode =
                &intel_crtc->config.adjusted_mode;
-       uint32_t vsyncshift, crtc_vtotal, crtc_vblank_end;
+       uint32_t crtc_vtotal, crtc_vblank_end;
+       int vsyncshift = 0;
 
        /* We need to be careful not to changed the adjusted mode, for otherwise
         * the hw state checker will get angry at the mismatch. */
        crtc_vtotal = adjusted_mode->crtc_vtotal;
        crtc_vblank_end = adjusted_mode->crtc_vblank_end;
 
-       if (!IS_GEN2(dev) && adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
+       if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) {
                /* the chip adds 2 halflines automatically */
                crtc_vtotal -= 1;
                crtc_vblank_end -= 1;
-               vsyncshift = adjusted_mode->crtc_hsync_start
-                            - adjusted_mode->crtc_htotal / 2;
-       } else {
-               vsyncshift = 0;
+
+               if (intel_pipe_has_type(&intel_crtc->base, INTEL_OUTPUT_SDVO))
+                       vsyncshift = (adjusted_mode->crtc_htotal - 1) / 2;
+               else
+                       vsyncshift = adjusted_mode->crtc_hsync_start -
+                               adjusted_mode->crtc_htotal / 2;
+               if (vsyncshift < 0)
+                       vsyncshift += adjusted_mode->crtc_htotal;
        }
 
        if (INTEL_INFO(dev)->gen > 3)
@@ -5259,25 +5478,23 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc,
        pipe_config->requested_mode.hdisplay = pipe_config->pipe_src_w;
 }
 
-static void intel_crtc_mode_from_pipe_config(struct intel_crtc *intel_crtc,
-                                            struct intel_crtc_config *pipe_config)
+void intel_mode_from_pipe_config(struct drm_display_mode *mode,
+                                struct intel_crtc_config *pipe_config)
 {
-       struct drm_crtc *crtc = &intel_crtc->base;
+       mode->hdisplay = pipe_config->adjusted_mode.crtc_hdisplay;
+       mode->htotal = pipe_config->adjusted_mode.crtc_htotal;
+       mode->hsync_start = pipe_config->adjusted_mode.crtc_hsync_start;
+       mode->hsync_end = pipe_config->adjusted_mode.crtc_hsync_end;
 
-       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;
+       mode->vdisplay = pipe_config->adjusted_mode.crtc_vdisplay;
+       mode->vtotal = pipe_config->adjusted_mode.crtc_vtotal;
+       mode->vsync_start = pipe_config->adjusted_mode.crtc_vsync_start;
+       mode->vsync_end = pipe_config->adjusted_mode.crtc_vsync_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;
+       mode->flags = pipe_config->adjusted_mode.flags;
 
-       crtc->mode.flags = pipe_config->adjusted_mode.flags;
-
-       crtc->mode.clock = pipe_config->adjusted_mode.crtc_clock;
-       crtc->mode.flags |= pipe_config->adjusted_mode.flags;
+       mode->clock = pipe_config->adjusted_mode.crtc_clock;
+       mode->flags |= pipe_config->adjusted_mode.flags;
 }
 
 static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
@@ -5327,10 +5544,13 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
                }
        }
 
-       if (!IS_GEN2(dev) &&
-           intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
-               pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
-       else
+       if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
+               if (INTEL_INFO(dev)->gen < 4 ||
+                   intel_pipe_has_type(&intel_crtc->base, INTEL_OUTPUT_SDVO))
+                       pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
+               else
+                       pipeconf |= PIPECONF_INTERLACE_W_SYNC_SHIFT;
+       } else
                pipeconf |= PIPECONF_PROGRESSIVE;
 
        if (IS_VALLEYVIEW(dev) && intel_crtc->config.limited_color_range)
@@ -5512,6 +5732,67 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc,
        pipe_config->port_clock = clock.dot / 5;
 }
 
+static void i9xx_get_plane_config(struct intel_crtc *crtc,
+                                 struct intel_plane_config *plane_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val, base, offset;
+       int pipe = crtc->pipe, plane = crtc->plane;
+       int fourcc, pixel_format;
+       int aligned_height;
+
+       crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
+       if (!crtc->base.primary->fb) {
+               DRM_DEBUG_KMS("failed to alloc fb\n");
+               return;
+       }
+
+       val = I915_READ(DSPCNTR(plane));
+
+       if (INTEL_INFO(dev)->gen >= 4)
+               if (val & DISPPLANE_TILED)
+                       plane_config->tiled = true;
+
+       pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
+       fourcc = intel_format_to_fourcc(pixel_format);
+       crtc->base.primary->fb->pixel_format = fourcc;
+       crtc->base.primary->fb->bits_per_pixel =
+               drm_format_plane_cpp(fourcc, 0) * 8;
+
+       if (INTEL_INFO(dev)->gen >= 4) {
+               if (plane_config->tiled)
+                       offset = I915_READ(DSPTILEOFF(plane));
+               else
+                       offset = I915_READ(DSPLINOFF(plane));
+               base = I915_READ(DSPSURF(plane)) & 0xfffff000;
+       } else {
+               base = I915_READ(DSPADDR(plane));
+       }
+       plane_config->base = base;
+
+       val = I915_READ(PIPESRC(pipe));
+       crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
+       crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
+
+       val = I915_READ(DSPSTRIDE(pipe));
+       crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
+
+       aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
+                                           plane_config->tiled);
+
+       plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
+                                  aligned_height, PAGE_SIZE);
+
+       DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
+                     pipe, plane, crtc->base.primary->fb->width,
+                     crtc->base.primary->fb->height,
+                     crtc->base.primary->fb->bits_per_pixel, base,
+                     crtc->base.primary->fb->pitches[0],
+                     plane_config->size);
+
+}
+
 static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
                                 struct intel_crtc_config *pipe_config)
 {
@@ -5519,6 +5800,10 @@ static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t tmp;
 
+       if (!intel_display_power_enabled(dev_priv,
+                                        POWER_DOMAIN_PIPE(crtc->pipe)))
+               return false;
+
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
@@ -6180,7 +6465,7 @@ int ironlake_get_lanes_required(int target_clock, int link_bw, int bpp)
         * is 2.5%; use 5% for safety's sake.
         */
        u32 bps = target_clock * bpp * 21 / 20;
-       return bps / (link_bw * 8) + 1;
+       return DIV_ROUND_UP(bps, link_bw * 8);
 }
 
 static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor)
@@ -6348,7 +6633,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
-       if (is_lvds && has_reduced_clock && i915_powersave)
+       if (is_lvds && has_reduced_clock && i915.powersave)
                intel_crtc->lowfreq_avail = true;
        else
                intel_crtc->lowfreq_avail = false;
@@ -6455,8 +6740,68 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc,
        }
 }
 
-static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
-                                    struct intel_crtc_config *pipe_config)
+static void ironlake_get_plane_config(struct intel_crtc *crtc,
+                                     struct intel_plane_config *plane_config)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val, base, offset;
+       int pipe = crtc->pipe, plane = crtc->plane;
+       int fourcc, pixel_format;
+       int aligned_height;
+
+       crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
+       if (!crtc->base.primary->fb) {
+               DRM_DEBUG_KMS("failed to alloc fb\n");
+               return;
+       }
+
+       val = I915_READ(DSPCNTR(plane));
+
+       if (INTEL_INFO(dev)->gen >= 4)
+               if (val & DISPPLANE_TILED)
+                       plane_config->tiled = true;
+
+       pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
+       fourcc = intel_format_to_fourcc(pixel_format);
+       crtc->base.primary->fb->pixel_format = fourcc;
+       crtc->base.primary->fb->bits_per_pixel =
+               drm_format_plane_cpp(fourcc, 0) * 8;
+
+       base = I915_READ(DSPSURF(plane)) & 0xfffff000;
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+               offset = I915_READ(DSPOFFSET(plane));
+       } else {
+               if (plane_config->tiled)
+                       offset = I915_READ(DSPTILEOFF(plane));
+               else
+                       offset = I915_READ(DSPLINOFF(plane));
+       }
+       plane_config->base = base;
+
+       val = I915_READ(PIPESRC(pipe));
+       crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
+       crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
+
+       val = I915_READ(DSPSTRIDE(pipe));
+       crtc->base.primary->fb->pitches[0] = val & 0xffffff80;
+
+       aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
+                                           plane_config->tiled);
+
+       plane_config->size = ALIGN(crtc->base.primary->fb->pitches[0] *
+                                  aligned_height, PAGE_SIZE);
+
+       DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
+                     pipe, plane, crtc->base.primary->fb->width,
+                     crtc->base.primary->fb->height,
+                     crtc->base.primary->fb->bits_per_pixel, base,
+                     crtc->base.primary->fb->pitches[0],
+                     plane_config->size);
+}
+
+static bool ironlake_get_pipe_config(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;
@@ -6629,6 +6974,7 @@ static void hsw_disable_lcpll(struct drm_i915_private *dev_priv,
 static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
 {
        uint32_t val;
+       unsigned long irqflags;
 
        val = I915_READ(LCPLL_CTL);
 
@@ -6636,9 +6982,22 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
                    LCPLL_POWER_DOWN_ALLOW)) == LCPLL_PLL_LOCK)
                return;
 
-       /* Make sure we're not on PC8 state before disabling PC8, otherwise
-        * we'll hang the machine! */
-       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+       /*
+        * Make sure we're not on PC8 state before disabling PC8, otherwise
+        * we'll hang the machine. To prevent PC8 state, just enable force_wake.
+        *
+        * The other problem is that hsw_restore_lcpll() is called as part of
+        * the runtime PM resume sequence, so we can't just call
+        * gen6_gt_force_wake_get() because that function calls
+        * intel_runtime_pm_get(), and we can't change the runtime PM refcount
+        * while we are on the resume sequence. So to solve this problem we have
+        * to call special forcewake code that doesn't touch runtime PM and
+        * doesn't enable the forcewake delayed work.
+        */
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       if (dev_priv->uncore.forcewake_count++ == 0)
+               dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 
        if (val & LCPLL_POWER_DOWN_ALLOW) {
                val &= ~LCPLL_POWER_DOWN_ALLOW;
@@ -6672,26 +7031,45 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
                        DRM_ERROR("Switching back to LCPLL failed\n");
        }
 
-       gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+       /* See the big comment above. */
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       if (--dev_priv->uncore.forcewake_count == 0)
+               dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-void hsw_enable_pc8_work(struct work_struct *__work)
+/*
+ * Package states C8 and deeper are really deep PC states that can only be
+ * reached when all the devices on the system allow it, so even if the graphics
+ * device allows PC8+, it doesn't mean the system will actually get to these
+ * states. Our driver only allows PC8+ when going into runtime PM.
+ *
+ * The requirements for PC8+ are that all the outputs are disabled, the power
+ * well is disabled and most interrupts are disabled, and these are also
+ * requirements for runtime PM. When these conditions are met, we manually do
+ * the other conditions: disable the interrupts, clocks and switch LCPLL refclk
+ * to Fclk. If we're in PC8+ and we get an non-hotplug interrupt, we can hard
+ * hang the machine.
+ *
+ * When we really reach PC8 or deeper states (not just when we allow it) we lose
+ * the state of some registers, so when we come back from PC8+ we need to
+ * restore this state. We don't get into PC8+ if we're not in RC6, so we don't
+ * need to take care of the registers kept by RC6. Notice that this happens even
+ * if we don't put the device in PCI D3 state (which is what currently happens
+ * because of the runtime PM support).
+ *
+ * For more, read "Display Sequences for Package C8" on the hardware
+ * documentation.
+ */
+void hsw_enable_pc8(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv =
-               container_of(to_delayed_work(__work), struct drm_i915_private,
-                            pc8.enable_work);
        struct drm_device *dev = dev_priv->dev;
        uint32_t val;
 
        WARN_ON(!HAS_PC8(dev));
 
-       if (dev_priv->pc8.enabled)
-               return;
-
        DRM_DEBUG_KMS("Enabling package C8+\n");
 
-       dev_priv->pc8.enabled = true;
-
        if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
                val = I915_READ(SOUTH_DSPCLK_GATE_D);
                val &= ~PCH_LP_PARTITION_LEVEL_DISABLE;
@@ -6699,51 +7077,21 @@ void hsw_enable_pc8_work(struct work_struct *__work)
        }
 
        lpt_disable_clkout_dp(dev);
-       hsw_pc8_disable_interrupts(dev);
+       hsw_runtime_pm_disable_interrupts(dev);
        hsw_disable_lcpll(dev_priv, true, true);
-
-       intel_runtime_pm_put(dev_priv);
-}
-
-static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv)
-{
-       WARN_ON(!mutex_is_locked(&dev_priv->pc8.lock));
-       WARN(dev_priv->pc8.disable_count < 1,
-            "pc8.disable_count: %d\n", dev_priv->pc8.disable_count);
-
-       dev_priv->pc8.disable_count--;
-       if (dev_priv->pc8.disable_count != 0)
-               return;
-
-       schedule_delayed_work(&dev_priv->pc8.enable_work,
-                             msecs_to_jiffies(i915_pc8_timeout));
 }
 
-static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv)
+void hsw_disable_pc8(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
        uint32_t val;
 
-       WARN_ON(!mutex_is_locked(&dev_priv->pc8.lock));
-       WARN(dev_priv->pc8.disable_count < 0,
-            "pc8.disable_count: %d\n", dev_priv->pc8.disable_count);
-
-       dev_priv->pc8.disable_count++;
-       if (dev_priv->pc8.disable_count != 1)
-               return;
-
        WARN_ON(!HAS_PC8(dev));
 
-       cancel_delayed_work_sync(&dev_priv->pc8.enable_work);
-       if (!dev_priv->pc8.enabled)
-               return;
-
        DRM_DEBUG_KMS("Disabling package C8+\n");
 
-       intel_runtime_pm_get(dev_priv);
-
        hsw_restore_lcpll(dev_priv);
-       hsw_pc8_restore_interrupts(dev);
+       hsw_runtime_pm_restore_interrupts(dev);
        lpt_init_pch_refclk(dev);
 
        if (dev_priv->pch_id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
@@ -6757,185 +7105,11 @@ static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv)
        mutex_lock(&dev_priv->rps.hw_lock);
        gen6_update_ring_freq(dev);
        mutex_unlock(&dev_priv->rps.hw_lock);
-       dev_priv->pc8.enabled = false;
-}
-
-void hsw_enable_package_c8(struct drm_i915_private *dev_priv)
-{
-       if (!HAS_PC8(dev_priv->dev))
-               return;
-
-       mutex_lock(&dev_priv->pc8.lock);
-       __hsw_enable_package_c8(dev_priv);
-       mutex_unlock(&dev_priv->pc8.lock);
-}
-
-void hsw_disable_package_c8(struct drm_i915_private *dev_priv)
-{
-       if (!HAS_PC8(dev_priv->dev))
-               return;
-
-       mutex_lock(&dev_priv->pc8.lock);
-       __hsw_disable_package_c8(dev_priv);
-       mutex_unlock(&dev_priv->pc8.lock);
-}
-
-static bool hsw_can_enable_package_c8(struct drm_i915_private *dev_priv)
-{
-       struct drm_device *dev = dev_priv->dev;
-       struct intel_crtc *crtc;
-       uint32_t val;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head)
-               if (crtc->base.enabled)
-                       return false;
-
-       /* This case is still possible since we have the i915.disable_power_well
-        * parameter and also the KVMr or something else might be requesting the
-        * power well. */
-       val = I915_READ(HSW_PWR_WELL_DRIVER);
-       if (val != 0) {
-               DRM_DEBUG_KMS("Not enabling PC8: power well on\n");
-               return false;
-       }
-
-       return true;
-}
-
-/* Since we're called from modeset_global_resources there's no way to
- * symmetrically increase and decrease the refcount, so we use
- * dev_priv->pc8.requirements_met to track whether we already have the refcount
- * or not.
- */
-static void hsw_update_package_c8(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       bool allow;
-
-       if (!HAS_PC8(dev_priv->dev))
-               return;
-
-       if (!i915_enable_pc8)
-               return;
-
-       mutex_lock(&dev_priv->pc8.lock);
-
-       allow = hsw_can_enable_package_c8(dev_priv);
-
-       if (allow == dev_priv->pc8.requirements_met)
-               goto done;
-
-       dev_priv->pc8.requirements_met = allow;
-
-       if (allow)
-               __hsw_enable_package_c8(dev_priv);
-       else
-               __hsw_disable_package_c8(dev_priv);
-
-done:
-       mutex_unlock(&dev_priv->pc8.lock);
-}
-
-static void hsw_package_c8_gpu_idle(struct drm_i915_private *dev_priv)
-{
-       if (!HAS_PC8(dev_priv->dev))
-               return;
-
-       mutex_lock(&dev_priv->pc8.lock);
-       if (!dev_priv->pc8.gpu_idle) {
-               dev_priv->pc8.gpu_idle = true;
-               __hsw_enable_package_c8(dev_priv);
-       }
-       mutex_unlock(&dev_priv->pc8.lock);
-}
-
-static void hsw_package_c8_gpu_busy(struct drm_i915_private *dev_priv)
-{
-       if (!HAS_PC8(dev_priv->dev))
-               return;
-
-       mutex_lock(&dev_priv->pc8.lock);
-       if (dev_priv->pc8.gpu_idle) {
-               dev_priv->pc8.gpu_idle = false;
-               __hsw_disable_package_c8(dev_priv);
-       }
-       mutex_unlock(&dev_priv->pc8.lock);
-}
-
-#define for_each_power_domain(domain, mask)                            \
-       for ((domain) = 0; (domain) < POWER_DOMAIN_NUM; (domain)++)     \
-               if ((1 << (domain)) & (mask))
-
-static unsigned long get_pipe_power_domains(struct drm_device *dev,
-                                           enum pipe pipe, bool pfit_enabled)
-{
-       unsigned long mask;
-       enum transcoder transcoder;
-
-       transcoder = intel_pipe_to_cpu_transcoder(dev->dev_private, pipe);
-
-       mask = BIT(POWER_DOMAIN_PIPE(pipe));
-       mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
-       if (pfit_enabled)
-               mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe));
-
-       return mask;
-}
-
-void intel_display_set_init_power(struct drm_device *dev, bool enable)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       if (dev_priv->power_domains.init_power_on == enable)
-               return;
-
-       if (enable)
-               intel_display_power_get(dev, POWER_DOMAIN_INIT);
-       else
-               intel_display_power_put(dev, POWER_DOMAIN_INIT);
-
-       dev_priv->power_domains.init_power_on = enable;
-}
-
-static void modeset_update_power_wells(struct drm_device *dev)
-{
-       unsigned long pipe_domains[I915_MAX_PIPES] = { 0, };
-       struct intel_crtc *crtc;
-
-       /*
-        * First get all needed power domains, then put all unneeded, to avoid
-        * any unnecessary toggling of the power wells.
-        */
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
-               enum intel_display_power_domain domain;
-
-               if (!crtc->base.enabled)
-                       continue;
-
-               pipe_domains[crtc->pipe] = get_pipe_power_domains(dev,
-                                               crtc->pipe,
-                                               crtc->config.pch_pfit.enabled);
-
-               for_each_power_domain(domain, pipe_domains[crtc->pipe])
-                       intel_display_power_get(dev, domain);
-       }
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
-               enum intel_display_power_domain domain;
-
-               for_each_power_domain(domain, crtc->enabled_power_domains)
-                       intel_display_power_put(dev, domain);
-
-               crtc->enabled_power_domains = pipe_domains[crtc->pipe];
-       }
-
-       intel_display_set_init_power(dev, false);
 }
 
 static void haswell_modeset_global_resources(struct drm_device *dev)
 {
-       modeset_update_power_wells(dev);
-       hsw_update_package_c8(dev);
+       modeset_update_crtc_power_domains(dev);
 }
 
 static int haswell_crtc_mode_set(struct drm_crtc *crtc,
@@ -6985,6 +7159,10 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        enum intel_display_power_domain pfit_domain;
        uint32_t tmp;
 
+       if (!intel_display_power_enabled(dev_priv,
+                                        POWER_DOMAIN_PIPE(crtc->pipe)))
+               return false;
+
        pipe_config->cpu_transcoder = (enum transcoder) crtc->pipe;
        pipe_config->shared_dpll = DPLL_ID_PRIVATE;
 
@@ -7010,7 +7188,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
                        pipe_config->cpu_transcoder = TRANSCODER_EDP;
        }
 
-       if (!intel_display_power_enabled(dev,
+       if (!intel_display_power_enabled(dev_priv,
                        POWER_DOMAIN_TRANSCODER(pipe_config->cpu_transcoder)))
                return false;
 
@@ -7038,7 +7216,7 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        intel_get_pipe_timings(crtc, pipe_config);
 
        pfit_domain = POWER_DOMAIN_PIPE_PANEL_FITTER(crtc->pipe);
-       if (intel_display_power_enabled(dev, pfit_domain))
+       if (intel_display_power_enabled(dev_priv, pfit_domain))
                ironlake_get_pfit_config(crtc, pipe_config);
 
        if (IS_HASWELL(dev))
@@ -7435,10 +7613,26 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
        bool visible = base != 0;
 
        if (intel_crtc->cursor_visible != visible) {
+               int16_t width = intel_crtc->cursor_width;
                uint32_t cntl = I915_READ(CURCNTR(pipe));
                if (base) {
                        cntl &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT);
-                       cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+                       cntl |= MCURSOR_GAMMA_ENABLE;
+
+                       switch (width) {
+                       case 64:
+                               cntl |= CURSOR_MODE_64_ARGB_AX;
+                               break;
+                       case 128:
+                               cntl |= CURSOR_MODE_128_ARGB_AX;
+                               break;
+                       case 256:
+                               cntl |= CURSOR_MODE_256_ARGB_AX;
+                               break;
+                       default:
+                               WARN_ON(1);
+                               return;
+                       }
                        cntl |= pipe << 28; /* Connect to correct pipe */
                } else {
                        cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
@@ -7463,10 +7657,25 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
        bool visible = base != 0;
 
        if (intel_crtc->cursor_visible != visible) {
+               int16_t width = intel_crtc->cursor_width;
                uint32_t cntl = I915_READ(CURCNTR_IVB(pipe));
                if (base) {
                        cntl &= ~CURSOR_MODE;
-                       cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+                       cntl |= MCURSOR_GAMMA_ENABLE;
+                       switch (width) {
+                       case 64:
+                               cntl |= CURSOR_MODE_64_ARGB_AX;
+                               break;
+                       case 128:
+                               cntl |= CURSOR_MODE_128_ARGB_AX;
+                               break;
+                       case 256:
+                               cntl |= CURSOR_MODE_256_ARGB_AX;
+                               break;
+                       default:
+                               WARN_ON(1);
+                               return;
+                       }
                } else {
                        cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
                        cntl |= CURSOR_MODE_DISABLE;
@@ -7550,6 +7759,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_i915_gem_object *obj;
+       unsigned old_width;
        uint32_t addr;
        int ret;
 
@@ -7562,9 +7772,11 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                goto finish;
        }
 
-       /* Currently we only support 64x64 cursors */
-       if (width != 64 || height != 64) {
-               DRM_ERROR("we currently only support 64x64 cursors\n");
+       /* Check for which cursor types we support */
+       if (!((width == 64 && height == 64) ||
+                       (width == 128 && height == 128 && !IS_GEN2(dev)) ||
+                       (width == 256 && height == 256 && !IS_GEN2(dev)))) {
+               DRM_DEBUG("Cursor dimension not supported\n");
                return -EINVAL;
        }
 
@@ -7573,18 +7785,18 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                return -ENOENT;
 
        if (obj->base.size < width * height * 4) {
-               DRM_ERROR("buffer is to small\n");
+               DRM_DEBUG_KMS("buffer is to small\n");
                ret = -ENOMEM;
                goto fail;
        }
 
        /* we only need to pin inside GTT if cursor is non-phy */
        mutex_lock(&dev->struct_mutex);
-       if (!dev_priv->info->cursor_needs_physical) {
+       if (!INTEL_INFO(dev)->cursor_needs_physical) {
                unsigned alignment;
 
                if (obj->tiling_mode) {
-                       DRM_ERROR("cursor cannot be tiled\n");
+                       DRM_DEBUG_KMS("cursor cannot be tiled\n");
                        ret = -EINVAL;
                        goto fail_locked;
                }
@@ -7600,13 +7812,13 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 
                ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL);
                if (ret) {
-                       DRM_ERROR("failed to move cursor bo into the GTT\n");
+                       DRM_DEBUG_KMS("failed to move cursor bo into the GTT\n");
                        goto fail_locked;
                }
 
                ret = i915_gem_object_put_fence(obj);
                if (ret) {
-                       DRM_ERROR("failed to release fence for cursor");
+                       DRM_DEBUG_KMS("failed to release fence for cursor");
                        goto fail_unpin;
                }
 
@@ -7617,7 +7829,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                                                  (intel_crtc->pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1,
                                                  align);
                if (ret) {
-                       DRM_ERROR("failed to attach phys object\n");
+                       DRM_DEBUG_KMS("failed to attach phys object\n");
                        goto fail_locked;
                }
                addr = obj->phys_obj->handle->busaddr;
@@ -7628,7 +7840,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 
  finish:
        if (intel_crtc->cursor_bo) {
-               if (dev_priv->info->cursor_needs_physical) {
+               if (INTEL_INFO(dev)->cursor_needs_physical) {
                        if (intel_crtc->cursor_bo != obj)
                                i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
                } else
@@ -7638,13 +7850,18 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 
        mutex_unlock(&dev->struct_mutex);
 
+       old_width = intel_crtc->cursor_width;
+
        intel_crtc->cursor_addr = addr;
        intel_crtc->cursor_bo = obj;
        intel_crtc->cursor_width = width;
        intel_crtc->cursor_height = height;
 
-       if (intel_crtc->active)
+       if (intel_crtc->active) {
+               if (old_width != width)
+                       intel_update_watermarks(crtc);
                intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
+       }
 
        return 0;
 fail_unpin:
@@ -7690,10 +7907,10 @@ static struct drm_display_mode load_detect_mode = {
                 704, 832, 0, 480, 489, 491, 520, 0, DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
 };
 
-static struct drm_framebuffer *
-intel_framebuffer_create(struct drm_device *dev,
-                        struct drm_mode_fb_cmd2 *mode_cmd,
-                        struct drm_i915_gem_object *obj)
+struct drm_framebuffer *
+__intel_framebuffer_create(struct drm_device *dev,
+                          struct drm_mode_fb_cmd2 *mode_cmd,
+                          struct drm_i915_gem_object *obj)
 {
        struct intel_framebuffer *intel_fb;
        int ret;
@@ -7704,12 +7921,7 @@ intel_framebuffer_create(struct drm_device *dev,
                return ERR_PTR(-ENOMEM);
        }
 
-       ret = i915_mutex_lock_interruptible(dev);
-       if (ret)
-               goto err;
-
        ret = intel_framebuffer_init(dev, intel_fb, mode_cmd, obj);
-       mutex_unlock(&dev->struct_mutex);
        if (ret)
                goto err;
 
@@ -7721,6 +7933,23 @@ err:
        return ERR_PTR(ret);
 }
 
+static struct drm_framebuffer *
+intel_framebuffer_create(struct drm_device *dev,
+                        struct drm_mode_fb_cmd2 *mode_cmd,
+                        struct drm_i915_gem_object *obj)
+{
+       struct drm_framebuffer *fb;
+       int ret;
+
+       ret = i915_mutex_lock_interruptible(dev);
+       if (ret)
+               return ERR_PTR(ret);
+       fb = __intel_framebuffer_create(dev, mode_cmd, obj);
+       mutex_unlock(&dev->struct_mutex);
+
+       return fb;
+}
+
 static u32
 intel_framebuffer_pitch_for_width(int width, int bpp)
 {
@@ -7766,14 +7995,16 @@ mode_fits_in_fbdev(struct drm_device *dev,
        struct drm_i915_gem_object *obj;
        struct drm_framebuffer *fb;
 
-       if (dev_priv->fbdev == NULL)
+       if (!dev_priv->fbdev)
                return NULL;
 
-       obj = dev_priv->fbdev->ifb.obj;
-       if (obj == NULL)
+       if (!dev_priv->fbdev->fb)
                return NULL;
 
-       fb = &dev_priv->fbdev->ifb.base;
+       obj = dev_priv->fbdev->fb->obj;
+       BUG_ON(!obj);
+
+       fb = &dev_priv->fbdev->fb->base;
        if (fb->pitches[0] < intel_framebuffer_pitch_for_width(mode->hdisplay,
                                                               fb->bits_per_pixel))
                return NULL;
@@ -7855,6 +8086,8 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
        to_intel_connector(connector)->new_encoder = intel_encoder;
 
        intel_crtc = to_intel_crtc(crtc);
+       intel_crtc->new_enabled = true;
+       intel_crtc->new_config = &intel_crtc->config;
        old->dpms_mode = connector->dpms;
        old->load_detect_temp = true;
        old->release_fb = NULL;
@@ -7878,21 +8111,28 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
                DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
        if (IS_ERR(fb)) {
                DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
-               mutex_unlock(&crtc->mutex);
-               return false;
+               goto fail;
        }
 
        if (intel_set_mode(crtc, mode, 0, 0, fb)) {
                DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
                if (old->release_fb)
                        old->release_fb->funcs->destroy(old->release_fb);
-               mutex_unlock(&crtc->mutex);
-               return false;
+               goto fail;
        }
 
        /* let the connector get through one full cycle before testing */
        intel_wait_for_vblank(dev, intel_crtc->pipe);
        return true;
+
+ fail:
+       intel_crtc->new_enabled = crtc->enabled;
+       if (intel_crtc->new_enabled)
+               intel_crtc->new_config = &intel_crtc->config;
+       else
+               intel_crtc->new_config = NULL;
+       mutex_unlock(&crtc->mutex);
+       return false;
 }
 
 void intel_release_load_detect_pipe(struct drm_connector *connector,
@@ -7902,6 +8142,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
                intel_attached_encoder(connector);
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_crtc *crtc = encoder->crtc;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
                      connector->base.id, drm_get_connector_name(connector),
@@ -7910,6 +8151,8 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
        if (old->load_detect_temp) {
                to_intel_connector(connector)->new_encoder = NULL;
                intel_encoder->new_crtc = NULL;
+               intel_crtc->new_enabled = false;
+               intel_crtc->new_config = NULL;
                intel_set_mode(crtc, NULL, 0, 0, NULL);
 
                if (old->release_fb) {
@@ -8122,7 +8365,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
 static void intel_increase_pllclock(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        int dpll_reg = DPLL(pipe);
@@ -8153,7 +8396,7 @@ static void intel_increase_pllclock(struct drm_crtc *crtc)
 static void intel_decrease_pllclock(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
        if (HAS_PCH_SPLIT(dev))
@@ -8190,8 +8433,12 @@ void intel_mark_busy(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       hsw_package_c8_gpu_busy(dev_priv);
+       if (dev_priv->mm.busy)
+               return;
+
+       intel_runtime_pm_get(dev_priv);
        i915_update_gfx_val(dev_priv);
+       dev_priv->mm.busy = true;
 }
 
 void intel_mark_idle(struct drm_device *dev)
@@ -8199,20 +8446,26 @@ void intel_mark_idle(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
 
-       hsw_package_c8_gpu_idle(dev_priv);
-
-       if (!i915_powersave)
+       if (!dev_priv->mm.busy)
                return;
 
+       dev_priv->mm.busy = false;
+
+       if (!i915.powersave)
+               goto out;
+
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               if (!crtc->fb)
+               if (!crtc->primary->fb)
                        continue;
 
                intel_decrease_pllclock(crtc);
        }
 
-       if (dev_priv->info->gen >= 6)
+       if (INTEL_INFO(dev)->gen >= 6)
                gen6_rps_idle(dev->dev_private);
+
+out:
+       intel_runtime_pm_put(dev_priv);
 }
 
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
@@ -8221,14 +8474,14 @@ void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
        struct drm_device *dev = obj->base.dev;
        struct drm_crtc *crtc;
 
-       if (!i915_powersave)
+       if (!i915.powersave)
                return;
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               if (!crtc->fb)
+               if (!crtc->primary->fb)
                        continue;
 
-               if (to_intel_framebuffer(crtc->fb)->obj != obj)
+               if (to_intel_framebuffer(crtc->primary->fb)->obj != obj)
                        continue;
 
                intel_increase_pllclock(crtc);
@@ -8284,7 +8537,7 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 static void do_intel_finish_page_flip(struct drm_device *dev,
                                      struct drm_crtc *crtc)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_unpin_work *work;
        unsigned long flags;
@@ -8325,7 +8578,7 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 
 void intel_finish_page_flip(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
 
        do_intel_finish_page_flip(dev, crtc);
@@ -8333,7 +8586,7 @@ void intel_finish_page_flip(struct drm_device *dev, int pipe)
 
 void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->plane_to_crtc_mapping[plane];
 
        do_intel_finish_page_flip(dev, crtc);
@@ -8341,7 +8594,7 @@ void intel_finish_page_flip_plane(struct drm_device *dev, int plane)
 
 void intel_prepare_page_flip(struct drm_device *dev, int plane)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc =
                to_intel_crtc(dev_priv->plane_to_crtc_mapping[plane]);
        unsigned long flags;
@@ -8656,7 +8909,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_framebuffer *old_fb = crtc->fb;
+       struct drm_framebuffer *old_fb = crtc->primary->fb;
        struct drm_i915_gem_object *obj = to_intel_framebuffer(fb)->obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_unpin_work *work;
@@ -8664,7 +8917,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        int ret;
 
        /* Can't change pixel format via MI display flips. */
-       if (fb->pixel_format != crtc->fb->pixel_format)
+       if (fb->pixel_format != crtc->primary->fb->pixel_format)
                return -EINVAL;
 
        /*
@@ -8672,10 +8925,13 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
         * Note that pitch changes could also affect these register.
         */
        if (INTEL_INFO(dev)->gen > 3 &&
-           (fb->offsets[0] != crtc->fb->offsets[0] ||
-            fb->pitches[0] != crtc->fb->pitches[0]))
+           (fb->offsets[0] != crtc->primary->fb->offsets[0] ||
+            fb->pitches[0] != crtc->primary->fb->pitches[0]))
                return -EINVAL;
 
+       if (i915_terminally_wedged(&dev_priv->gpu_error))
+               goto out_hang;
+
        work = kzalloc(sizeof(*work), GFP_KERNEL);
        if (work == NULL)
                return -ENOMEM;
@@ -8713,7 +8969,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        drm_gem_object_reference(&work->old_fb_obj->base);
        drm_gem_object_reference(&obj->base);
 
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
 
        work->pending_flip_obj = obj;
 
@@ -8736,7 +8992,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
 
 cleanup_pending:
        atomic_dec(&intel_crtc->unpin_work_count);
-       crtc->fb = old_fb;
+       crtc->primary->fb = old_fb;
        drm_gem_object_unreference(&work->old_fb_obj->base);
        drm_gem_object_unreference(&obj->base);
        mutex_unlock(&dev->struct_mutex);
@@ -8750,6 +9006,13 @@ cleanup:
 free_work:
        kfree(work);
 
+       if (ret == -EIO) {
+out_hang:
+               intel_crtc_wait_for_pending_flips(crtc);
+               ret = intel_pipe_set_base(crtc, crtc->x, crtc->y, fb);
+               if (ret == 0 && event)
+                       drm_send_vblank_event(dev, intel_crtc->pipe, event);
+       }
        return ret;
 }
 
@@ -8766,6 +9029,7 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = {
  */
 static void intel_modeset_update_staged_output_state(struct drm_device *dev)
 {
+       struct intel_crtc *crtc;
        struct intel_encoder *encoder;
        struct intel_connector *connector;
 
@@ -8780,6 +9044,16 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
                encoder->new_crtc =
                        to_intel_crtc(encoder->base.crtc);
        }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               crtc->new_enabled = crtc->base.enabled;
+
+               if (crtc->new_enabled)
+                       crtc->new_config = &crtc->config;
+               else
+                       crtc->new_config = NULL;
+       }
 }
 
 /**
@@ -8789,6 +9063,7 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
  */
 static void intel_modeset_commit_output_state(struct drm_device *dev)
 {
+       struct intel_crtc *crtc;
        struct intel_encoder *encoder;
        struct intel_connector *connector;
 
@@ -8801,6 +9076,11 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
                            base.head) {
                encoder->base.crtc = &encoder->new_crtc->base;
        }
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               crtc->base.enabled = crtc->new_enabled;
+       }
 }
 
 static void
@@ -8941,23 +9221,47 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
        DRM_DEBUG_KMS("double wide: %i\n", pipe_config->double_wide);
 }
 
-static bool check_encoder_cloning(struct drm_crtc *crtc)
+static bool encoders_cloneable(const struct intel_encoder *a,
+                              const struct intel_encoder *b)
+{
+       /* masks could be asymmetric, so check both ways */
+       return a == b || (a->cloneable & (1 << b->type) &&
+                         b->cloneable & (1 << a->type));
+}
+
+static bool check_single_encoder_cloning(struct intel_crtc *crtc,
+                                        struct intel_encoder *encoder)
 {
-       int num_encoders = 0;
-       bool uncloneable_encoders = false;
+       struct drm_device *dev = crtc->base.dev;
+       struct intel_encoder *source_encoder;
+
+       list_for_each_entry(source_encoder,
+                           &dev->mode_config.encoder_list, base.head) {
+               if (source_encoder->new_crtc != crtc)
+                       continue;
+
+               if (!encoders_cloneable(encoder, source_encoder))
+                       return false;
+       }
+
+       return true;
+}
+
+static bool check_encoder_cloning(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
        struct intel_encoder *encoder;
 
-       list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list,
-                           base.head) {
-               if (&encoder->new_crtc->base != crtc)
+       list_for_each_entry(encoder,
+                           &dev->mode_config.encoder_list, base.head) {
+               if (encoder->new_crtc != crtc)
                        continue;
 
-               num_encoders++;
-               if (!encoder->cloneable)
-                       uncloneable_encoders = true;
+               if (!check_single_encoder_cloning(crtc, encoder))
+                       return false;
        }
 
-       return !(num_encoders > 1 && uncloneable_encoders);
+       return true;
 }
 
 static struct intel_crtc_config *
@@ -8971,7 +9275,7 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
        int plane_bpp, ret = -EINVAL;
        bool retry = true;
 
-       if (!check_encoder_cloning(crtc)) {
+       if (!check_encoder_cloning(to_intel_crtc(crtc))) {
                DRM_DEBUG_KMS("rejecting invalid cloning configuration\n");
                return ERR_PTR(-EINVAL);
        }
@@ -9127,29 +9431,22 @@ intel_modeset_affected_pipes(struct drm_crtc *crtc, unsigned *modeset_pipes,
                        *prepare_pipes |= 1 << encoder->new_crtc->pipe;
        }
 
-       /* Check for any pipes that will be fully disabled ... */
+       /* Check for pipes that will be enabled/disabled ... */
        list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
                            base.head) {
-               bool used = false;
-
-               /* Don't try to disable disabled crtcs. */
-               if (!intel_crtc->base.enabled)
+               if (intel_crtc->base.enabled == intel_crtc->new_enabled)
                        continue;
 
-               list_for_each_entry(encoder, &dev->mode_config.encoder_list,
-                                   base.head) {
-                       if (encoder->new_crtc == intel_crtc)
-                               used = true;
-               }
-
-               if (!used)
+               if (!intel_crtc->new_enabled)
                        *disable_pipes |= 1 << intel_crtc->pipe;
+               else
+                       *prepare_pipes |= 1 << intel_crtc->pipe;
        }
 
 
        /* set_mode is also used to update properties on life display pipes. */
        intel_crtc = to_intel_crtc(crtc);
-       if (crtc->enabled)
+       if (intel_crtc->new_enabled)
                *prepare_pipes |= 1 << intel_crtc->pipe;
 
        /*
@@ -9208,10 +9505,13 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
 
        intel_modeset_commit_output_state(dev);
 
-       /* Update computed state. */
+       /* Double check state. */
        list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
                            base.head) {
-               intel_crtc->base.enabled = intel_crtc_in_use(&intel_crtc->base);
+               WARN_ON(intel_crtc->base.enabled != intel_crtc_in_use(&intel_crtc->base));
+               WARN_ON(intel_crtc->new_config &&
+                       intel_crtc->new_config != &intel_crtc->config);
+               WARN_ON(intel_crtc->base.enabled != !!intel_crtc->new_config);
        }
 
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -9380,10 +9680,8 @@ intel_pipe_config_compare(struct drm_device *dev,
        if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5)
                PIPE_CONF_CHECK_I(pipe_bpp);
 
-       if (!HAS_DDI(dev)) {
-               PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.crtc_clock);
-               PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
-       }
+       PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.crtc_clock);
+       PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
 
 #undef PIPE_CONF_CHECK_X
 #undef PIPE_CONF_CHECK_I
@@ -9471,7 +9769,7 @@ check_encoder_state(struct drm_device *dev)
 static void
 check_crtc_state(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *crtc;
        struct intel_encoder *encoder;
        struct intel_crtc_config pipe_config;
@@ -9539,7 +9837,7 @@ check_crtc_state(struct drm_device *dev)
 static void
 check_shared_dpll_state(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *crtc;
        struct intel_dpll_hw_state dpll_hw_state;
        int i;
@@ -9612,7 +9910,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
                            int x, int y, struct drm_framebuffer *fb)
 {
        struct drm_device *dev = crtc->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_display_mode *saved_mode;
        struct intel_crtc_config *pipe_config = NULL;
        struct intel_crtc *intel_crtc;
@@ -9643,6 +9941,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
                }
                intel_dump_pipe_config(to_intel_crtc(crtc), pipe_config,
                                       "[modeset]");
+               to_intel_crtc(crtc)->new_config = pipe_config;
        }
 
        /*
@@ -9653,8 +9952,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
         * adjusted_mode bits in the crtc directly.
         */
        if (IS_VALLEYVIEW(dev)) {
-               valleyview_modeset_global_pipes(dev, &prepare_pipes,
-                                               modeset_pipes, pipe_config);
+               valleyview_modeset_global_pipes(dev, &prepare_pipes);
 
                /* may have added more to prepare_pipes than we should */
                prepare_pipes &= ~disable_pipes;
@@ -9676,6 +9974,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
                /* mode_set/enable/disable functions rely on a correct pipe
                 * config. */
                to_intel_crtc(crtc)->config = *pipe_config;
+               to_intel_crtc(crtc)->new_config = &to_intel_crtc(crtc)->config;
 
                /*
                 * Calculate and store various constants which
@@ -9734,7 +10033,7 @@ static int intel_set_mode(struct drm_crtc *crtc,
 
 void intel_crtc_restore_mode(struct drm_crtc *crtc)
 {
-       intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->fb);
+       intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y, crtc->primary->fb);
 }
 
 #undef for_each_intel_crtc_masked
@@ -9746,16 +10045,24 @@ static void intel_set_config_free(struct intel_set_config *config)
 
        kfree(config->save_connector_encoders);
        kfree(config->save_encoder_crtcs);
+       kfree(config->save_crtc_enabled);
        kfree(config);
 }
 
 static int intel_set_config_save_state(struct drm_device *dev,
                                       struct intel_set_config *config)
 {
+       struct drm_crtc *crtc;
        struct drm_encoder *encoder;
        struct drm_connector *connector;
        int count;
 
+       config->save_crtc_enabled =
+               kcalloc(dev->mode_config.num_crtc,
+                       sizeof(bool), GFP_KERNEL);
+       if (!config->save_crtc_enabled)
+               return -ENOMEM;
+
        config->save_encoder_crtcs =
                kcalloc(dev->mode_config.num_encoder,
                        sizeof(struct drm_crtc *), GFP_KERNEL);
@@ -9772,6 +10079,11 @@ static int intel_set_config_save_state(struct drm_device *dev,
         * Should anything bad happen only the expected state is
         * restored, not the drivers personal bookkeeping.
         */
+       count = 0;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               config->save_crtc_enabled[count++] = crtc->enabled;
+       }
+
        count = 0;
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
                config->save_encoder_crtcs[count++] = encoder->crtc;
@@ -9788,10 +10100,21 @@ static int intel_set_config_save_state(struct drm_device *dev,
 static void intel_set_config_restore_state(struct drm_device *dev,
                                           struct intel_set_config *config)
 {
+       struct intel_crtc *crtc;
        struct intel_encoder *encoder;
        struct intel_connector *connector;
        int count;
 
+       count = 0;
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+               crtc->new_enabled = config->save_crtc_enabled[count++];
+
+               if (crtc->new_enabled)
+                       crtc->new_config = &crtc->config;
+               else
+                       crtc->new_config = NULL;
+       }
+
        count = 0;
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
                encoder->new_crtc =
@@ -9834,13 +10157,13 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
         * and then just flip_or_move it */
        if (is_crtc_connector_off(set)) {
                config->mode_changed = true;
-       } else if (set->crtc->fb != set->fb) {
+       } else if (set->crtc->primary->fb != set->fb) {
                /* If we have no fb then treat it as a full mode set */
-               if (set->crtc->fb == NULL) {
+               if (set->crtc->primary->fb == NULL) {
                        struct intel_crtc *intel_crtc =
                                to_intel_crtc(set->crtc);
 
-                       if (intel_crtc->active && i915_fastboot) {
+                       if (intel_crtc->active && i915.fastboot) {
                                DRM_DEBUG_KMS("crtc has no fb, will flip\n");
                                config->fb_changed = true;
                        } else {
@@ -9850,7 +10173,7 @@ intel_set_config_compute_mode_changes(struct drm_mode_set *set,
                } else if (set->fb == NULL) {
                        config->mode_changed = true;
                } else if (set->fb->pixel_format !=
-                          set->crtc->fb->pixel_format) {
+                          set->crtc->primary->fb->pixel_format) {
                        config->mode_changed = true;
                } else {
                        config->fb_changed = true;
@@ -9876,9 +10199,9 @@ intel_modeset_stage_output_state(struct drm_device *dev,
                                 struct drm_mode_set *set,
                                 struct intel_set_config *config)
 {
-       struct drm_crtc *new_crtc;
        struct intel_connector *connector;
        struct intel_encoder *encoder;
+       struct intel_crtc *crtc;
        int ro;
 
        /* The upper layers ensure that we either disable a crtc or have a list
@@ -9921,6 +10244,8 @@ intel_modeset_stage_output_state(struct drm_device *dev,
        /* Update crtc of enabled connectors. */
        list_for_each_entry(connector, &dev->mode_config.connector_list,
                            base.head) {
+               struct drm_crtc *new_crtc;
+
                if (!connector->new_encoder)
                        continue;
 
@@ -9971,9 +10296,58 @@ intel_modeset_stage_output_state(struct drm_device *dev,
        }
        /* Now we've also updated encoder->new_crtc for all encoders. */
 
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               crtc->new_enabled = false;
+
+               list_for_each_entry(encoder,
+                                   &dev->mode_config.encoder_list,
+                                   base.head) {
+                       if (encoder->new_crtc == crtc) {
+                               crtc->new_enabled = true;
+                               break;
+                       }
+               }
+
+               if (crtc->new_enabled != crtc->base.enabled) {
+                       DRM_DEBUG_KMS("crtc %sabled, full mode switch\n",
+                                     crtc->new_enabled ? "en" : "dis");
+                       config->mode_changed = true;
+               }
+
+               if (crtc->new_enabled)
+                       crtc->new_config = &crtc->config;
+               else
+                       crtc->new_config = NULL;
+       }
+
        return 0;
 }
 
+static void disable_crtc_nofb(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct intel_encoder *encoder;
+       struct intel_connector *connector;
+
+       DRM_DEBUG_KMS("Trying to restore without FB -> disabling pipe %c\n",
+                     pipe_name(crtc->pipe));
+
+       list_for_each_entry(connector, &dev->mode_config.connector_list, base.head) {
+               if (connector->new_encoder &&
+                   connector->new_encoder->new_crtc == crtc)
+                       connector->new_encoder = NULL;
+       }
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               if (encoder->new_crtc == crtc)
+                       encoder->new_crtc = NULL;
+       }
+
+       crtc->new_enabled = false;
+       crtc->new_config = NULL;
+}
+
 static int intel_crtc_set_config(struct drm_mode_set *set)
 {
        struct drm_device *dev;
@@ -10012,7 +10386,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
        save_set.mode = &set->crtc->mode;
        save_set.x = set->crtc->x;
        save_set.y = set->crtc->y;
-       save_set.fb = set->crtc->fb;
+       save_set.fb = set->crtc->primary->fb;
 
        /* Compute whether we need a full modeset, only an fb base update or no
         * change at all. In the future we might also check whether only the
@@ -10040,7 +10414,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
                 * flipping, so increasing its cost here shouldn't be a big
                 * deal).
                 */
-               if (i915_fastboot && ret == 0)
+               if (i915.fastboot && ret == 0)
                        intel_modeset_check_state(set->crtc->dev);
        }
 
@@ -10050,6 +10424,15 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 fail:
                intel_set_config_restore_state(dev, config);
 
+               /*
+                * HACK: if the pipe was on, but we didn't have a framebuffer,
+                * force the pipe off to avoid oopsing in the modeset code
+                * due to fb==NULL. This should only happen during boot since
+                * we don't yet reconstruct the FB from the hardware state.
+                */
+               if (to_intel_crtc(save_set.crtc)->new_enabled && !save_set.fb)
+                       disable_crtc_nofb(to_intel_crtc(save_set.crtc));
+
                /* Try to restore the config */
                if (config->mode_changed &&
                    intel_set_mode(save_set.crtc, save_set.mode,
@@ -10174,7 +10557,7 @@ static void intel_shared_dpll_init(struct drm_device *dev)
 
 static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc;
        int i;
 
@@ -10184,6 +10567,16 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        drm_crtc_init(dev, &intel_crtc->base, &intel_crtc_funcs);
 
+       if (IS_GEN2(dev)) {
+               intel_crtc->max_cursor_width = GEN2_CURSOR_WIDTH;
+               intel_crtc->max_cursor_height = GEN2_CURSOR_HEIGHT;
+       } else {
+               intel_crtc->max_cursor_width = CURSOR_WIDTH;
+               intel_crtc->max_cursor_height = CURSOR_HEIGHT;
+       }
+       dev->mode_config.cursor_width = intel_crtc->max_cursor_width;
+       dev->mode_config.cursor_height = intel_crtc->max_cursor_height;
+
        drm_mode_crtc_set_gamma_size(&intel_crtc->base, 256);
        for (i = 0; i < 256; i++) {
                intel_crtc->lut_r[i] = i;
@@ -10255,12 +10648,7 @@ static int intel_encoder_clones(struct intel_encoder *encoder)
 
        list_for_each_entry(source_encoder,
                            &dev->mode_config.encoder_list, base.head) {
-
-               if (encoder == source_encoder)
-                       index_mask |= (1 << entry);
-
-               /* Intel hw has only one MUX where enocoders could be cloned. */
-               if (encoder->cloneable && source_encoder->cloneable)
+               if (encoders_cloneable(encoder, source_encoder))
                        index_mask |= (1 << entry);
 
                entry++;
@@ -10279,8 +10667,7 @@ static bool has_edp_a(struct drm_device *dev)
        if ((I915_READ(DP_A) & DP_DETECTED) == 0)
                return false;
 
-       if (IS_GEN5(dev) &&
-           (I915_READ(ILK_DISPLAY_CHICKEN_FUSES) & ILK_eDP_A_DISABLE))
+       if (IS_GEN5(dev) && (I915_READ(FUSE_STRAP) & ILK_eDP_A_DISABLE))
                return false;
 
        return true;
@@ -10433,18 +10820,13 @@ static void intel_setup_outputs(struct drm_device *dev)
        drm_helper_move_panel_connectors_to_head(dev);
 }
 
-void intel_framebuffer_fini(struct intel_framebuffer *fb)
-{
-       drm_framebuffer_cleanup(&fb->base);
-       WARN_ON(!fb->obj->framebuffer_references--);
-       drm_gem_object_unreference_unlocked(&fb->obj->base);
-}
-
 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
 
-       intel_framebuffer_fini(intel_fb);
+       drm_framebuffer_cleanup(fb);
+       WARN_ON(!intel_fb->obj->framebuffer_references--);
+       drm_gem_object_unreference_unlocked(&intel_fb->obj->base);
        kfree(intel_fb);
 }
 
@@ -10463,12 +10845,12 @@ static const struct drm_framebuffer_funcs intel_fb_funcs = {
        .create_handle = intel_user_framebuffer_create_handle,
 };
 
-int intel_framebuffer_init(struct drm_device *dev,
-                          struct intel_framebuffer *intel_fb,
-                          struct drm_mode_fb_cmd2 *mode_cmd,
-                          struct drm_i915_gem_object *obj)
+static int intel_framebuffer_init(struct drm_device *dev,
+                                 struct intel_framebuffer *intel_fb,
+                                 struct drm_mode_fb_cmd2 *mode_cmd,
+                                 struct drm_i915_gem_object *obj)
 {
-       int aligned_height, tile_height;
+       int aligned_height;
        int pitch_limit;
        int ret;
 
@@ -10562,9 +10944,8 @@ int intel_framebuffer_init(struct drm_device *dev,
        if (mode_cmd->offsets[0] != 0)
                return -EINVAL;
 
-       tile_height = IS_GEN2(dev) ? 16 : 8;
-       aligned_height = ALIGN(mode_cmd->height,
-                              obj->tiling_mode ? tile_height : 1);
+       aligned_height = intel_align_height(dev, mode_cmd->height,
+                                           obj->tiling_mode);
        /* FIXME drm helper for size checks (especially planar formats)? */
        if (obj->base.size < aligned_height * mode_cmd->pitches[0])
                return -EINVAL;
@@ -10624,32 +11005,40 @@ static void intel_init_display(struct drm_device *dev)
 
        if (HAS_DDI(dev)) {
                dev_priv->display.get_pipe_config = haswell_get_pipe_config;
+               dev_priv->display.get_plane_config = ironlake_get_plane_config;
                dev_priv->display.crtc_mode_set = haswell_crtc_mode_set;
                dev_priv->display.crtc_enable = haswell_crtc_enable;
                dev_priv->display.crtc_disable = haswell_crtc_disable;
                dev_priv->display.off = haswell_crtc_off;
-               dev_priv->display.update_plane = ironlake_update_plane;
+               dev_priv->display.update_primary_plane =
+                       ironlake_update_primary_plane;
        } else if (HAS_PCH_SPLIT(dev)) {
                dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
+               dev_priv->display.get_plane_config = ironlake_get_plane_config;
                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;
                dev_priv->display.off = ironlake_crtc_off;
-               dev_priv->display.update_plane = ironlake_update_plane;
+               dev_priv->display.update_primary_plane =
+                       ironlake_update_primary_plane;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_plane_config = i9xx_get_plane_config;
                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;
                dev_priv->display.off = i9xx_crtc_off;
-               dev_priv->display.update_plane = i9xx_update_plane;
+               dev_priv->display.update_primary_plane =
+                       i9xx_update_primary_plane;
        } else {
                dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
+               dev_priv->display.get_plane_config = i9xx_get_plane_config;
                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;
                dev_priv->display.off = i9xx_crtc_off;
-               dev_priv->display.update_plane = i9xx_update_plane;
+               dev_priv->display.update_primary_plane =
+                       i9xx_update_primary_plane;
        }
 
        /* Returns the core display clock speed */
@@ -10839,6 +11228,9 @@ static struct intel_quirk intel_quirks[] = {
 
        /* Acer Aspire 4736Z */
        { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
+
+       /* Acer Aspire 5336 */
+       { 0x2a42, 0x1025, 0x048a, quirk_invert_brightness },
 };
 
 static void intel_init_quirks(struct drm_device *dev)
@@ -10869,6 +11261,7 @@ static void i915_disable_vga(struct drm_device *dev)
        u8 sr1;
        u32 vga_reg = i915_vgacntrl_reg(dev);
 
+       /* WaEnableVGAAccessThroughIOPort:ctg,elk,ilk,snb,ivb,vlv,hsw */
        vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
        outb(SR01, VGA_SR_INDEX);
        sr1 = inb(VGA_SR_DATA);
@@ -10901,7 +11294,9 @@ void intel_modeset_suspend_hw(struct drm_device *dev)
 void intel_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int i, j, ret;
+       int sprite, ret;
+       enum pipe pipe;
+       struct intel_crtc *crtc;
 
        drm_mode_config_init(dev);
 
@@ -10938,13 +11333,13 @@ void intel_modeset_init(struct drm_device *dev)
                      INTEL_INFO(dev)->num_pipes,
                      INTEL_INFO(dev)->num_pipes > 1 ? "s" : "");
 
-       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);
+       for_each_pipe(pipe) {
+               intel_crtc_init(dev, pipe);
+               for_each_sprite(pipe, sprite) {
+                       ret = intel_plane_init(dev, pipe, sprite);
                        if (ret)
                                DRM_DEBUG_KMS("pipe %c sprite %c init failed: %d\n",
-                                             pipe_name(i), sprite_name(i, j), ret);
+                                             pipe_name(pipe), sprite_name(pipe, sprite), ret);
                }
        }
 
@@ -10960,6 +11355,33 @@ void intel_modeset_init(struct drm_device *dev)
 
        /* Just in case the BIOS is doing something questionable. */
        intel_disable_fbc(dev);
+
+       mutex_lock(&dev->mode_config.mutex);
+       intel_modeset_setup_hw_state(dev, false);
+       mutex_unlock(&dev->mode_config.mutex);
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               if (!crtc->active)
+                       continue;
+
+               /*
+                * Note that reserving the BIOS fb up front prevents us
+                * from stuffing other stolen allocations like the ring
+                * on top.  This prevents some ugliness at boot time, and
+                * can even allow for smooth boot transitions if the BIOS
+                * fb is large enough for the active pipe configuration.
+                */
+               if (dev_priv->display.get_plane_config) {
+                       dev_priv->display.get_plane_config(crtc,
+                                                          &crtc->plane_config);
+                       /*
+                        * If the fb is shared between multiple heads, we'll
+                        * just get the first one.
+                        */
+                       intel_find_plane_obj(crtc, &crtc->plane_config);
+               }
+       }
 }
 
 static void
@@ -11097,6 +11519,17 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
                        encoder->base.crtc = NULL;
                }
        }
+       if (crtc->active) {
+               /*
+                * We start out with underrun reporting disabled to avoid races.
+                * For correct bookkeeping mark this on active crtcs.
+                *
+                * No protection against concurrent access is required - at
+                * worst a fifo underrun happens which also sets this to false.
+                */
+               crtc->cpu_fifo_underrun_disabled = true;
+               crtc->pch_fifo_underrun_disabled = true;
+       }
 }
 
 static void intel_sanitize_encoder(struct intel_encoder *encoder)
@@ -11142,11 +11575,21 @@ static void intel_sanitize_encoder(struct intel_encoder *encoder)
         * the crtc fixup. */
 }
 
-void i915_redisable_vga(struct drm_device *dev)
+void i915_redisable_vga_power_on(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 vga_reg = i915_vgacntrl_reg(dev);
 
+       if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) {
+               DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
+               i915_disable_vga(dev);
+       }
+}
+
+void i915_redisable_vga(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
        /* This function can be called both from intel_modeset_setup_hw_state or
         * at a very early point in our resume sequence, where the power well
         * structures are not yet restored. Since this function is at a very
@@ -11154,14 +11597,10 @@ void i915_redisable_vga(struct drm_device *dev)
         * level, just check if the power well is enabled instead of trying to
         * follow the "don't touch the power well if we don't need it" policy
         * the rest of the driver uses. */
-       if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) &&
-           (I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_STATE_ENABLED) == 0)
+       if (!intel_display_power_enabled(dev_priv, POWER_DOMAIN_VGA))
                return;
 
-       if (!(I915_READ(vga_reg) & VGA_DISP_DISABLE)) {
-               DRM_DEBUG_KMS("Something enabled VGA plane, disabling it\n");
-               i915_disable_vga(dev);
-       }
+       i915_redisable_vga_power_on(dev);
 }
 
 static void intel_modeset_readout_hw_state(struct drm_device *dev)
@@ -11265,9 +11704,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
         */
        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);
-
+               if (crtc->active && i915.fastboot) {
+                       intel_mode_from_pipe_config(&crtc->base.mode, &crtc->config);
                        DRM_DEBUG_KMS("[CRTC:%d] found active mode: ",
                                      crtc->base.base.id);
                        drm_mode_debug_printmodeline(&crtc->base.mode);
@@ -11313,7 +11751,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                                dev_priv->pipe_to_crtc_mapping[pipe];
 
                        __intel_set_mode(crtc, &crtc->mode, crtc->x, crtc->y,
-                                        crtc->fb);
+                                        crtc->primary->fb);
                }
        } else {
                intel_modeset_update_staged_output_state(dev);
@@ -11324,14 +11762,44 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 
 void intel_modeset_gem_init(struct drm_device *dev)
 {
+       struct drm_crtc *c;
+       struct intel_framebuffer *fb;
+
+       mutex_lock(&dev->struct_mutex);
+       intel_init_gt_powersave(dev);
+       mutex_unlock(&dev->struct_mutex);
+
        intel_modeset_init_hw(dev);
 
        intel_setup_overlay(dev);
 
-       mutex_lock(&dev->mode_config.mutex);
-       drm_mode_config_reset(dev);
-       intel_modeset_setup_hw_state(dev, false);
-       mutex_unlock(&dev->mode_config.mutex);
+       /*
+        * Make sure any fbs we allocated at startup are properly
+        * pinned & fenced.  When we do the allocation it's too early
+        * for this.
+        */
+       mutex_lock(&dev->struct_mutex);
+       list_for_each_entry(c, &dev->mode_config.crtc_list, head) {
+               if (!c->primary->fb)
+                       continue;
+
+               fb = to_intel_framebuffer(c->primary->fb);
+               if (intel_pin_and_fence_fb_obj(dev, fb->obj, NULL)) {
+                       DRM_ERROR("failed to pin boot fb on pipe %d\n",
+                                 to_intel_crtc(c)->pipe);
+                       drm_framebuffer_unreference(c->primary->fb);
+                       c->primary->fb = NULL;
+               }
+       }
+       mutex_unlock(&dev->struct_mutex);
+}
+
+void intel_connector_unregister(struct intel_connector *intel_connector)
+{
+       struct drm_connector *connector = &intel_connector->base;
+
+       intel_panel_destroy_backlight(connector);
+       drm_sysfs_connector_remove(connector);
 }
 
 void intel_modeset_cleanup(struct drm_device *dev)
@@ -11359,7 +11827,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                /* Skip inactive CRTCs */
-               if (!crtc->fb)
+               if (!crtc->primary->fb)
                        continue;
 
                intel_increase_pllclock(crtc);
@@ -11378,13 +11846,19 @@ void intel_modeset_cleanup(struct drm_device *dev)
 
        /* destroy the backlight and sysfs files before encoders/connectors */
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               intel_panel_destroy_backlight(connector);
-               drm_sysfs_connector_remove(connector);
+               struct intel_connector *intel_connector;
+
+               intel_connector = to_intel_connector(connector);
+               intel_connector->unregister(intel_connector);
        }
 
        drm_mode_config_cleanup(dev);
 
        intel_cleanup_overlay(dev);
+
+       mutex_lock(&dev->struct_mutex);
+       intel_cleanup_gt_powersave(dev);
+       mutex_unlock(&dev->struct_mutex);
 }
 
 /*
@@ -11412,12 +11886,24 @@ int intel_modeset_vga_set_state(struct drm_device *dev, bool state)
        unsigned reg = INTEL_INFO(dev)->gen >= 6 ? SNB_GMCH_CTRL : INTEL_GMCH_CTRL;
        u16 gmch_ctrl;
 
-       pci_read_config_word(dev_priv->bridge_dev, reg, &gmch_ctrl);
+       if (pci_read_config_word(dev_priv->bridge_dev, reg, &gmch_ctrl)) {
+               DRM_ERROR("failed to read control word\n");
+               return -EIO;
+       }
+
+       if (!!(gmch_ctrl & INTEL_GMCH_VGA_DISABLE) == !state)
+               return 0;
+
        if (state)
                gmch_ctrl &= ~INTEL_GMCH_VGA_DISABLE;
        else
                gmch_ctrl |= INTEL_GMCH_VGA_DISABLE;
-       pci_write_config_word(dev_priv->bridge_dev, reg, gmch_ctrl);
+
+       if (pci_write_config_word(dev_priv->bridge_dev, reg, gmch_ctrl)) {
+               DRM_ERROR("failed to write control word\n");
+               return -EIO;
+       }
+
        return 0;
 }
 
@@ -11467,7 +11953,7 @@ struct intel_display_error_state {
 struct intel_display_error_state *
 intel_display_capture_error_state(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_display_error_state *error;
        int transcoders[] = {
                TRANSCODER_A,
@@ -11489,7 +11975,8 @@ intel_display_capture_error_state(struct drm_device *dev)
 
        for_each_pipe(i) {
                error->pipe[i].power_domain_on =
-                       intel_display_power_enabled_sw(dev, POWER_DOMAIN_PIPE(i));
+                       intel_display_power_enabled_sw(dev_priv,
+                                                      POWER_DOMAIN_PIPE(i));
                if (!error->pipe[i].power_domain_on)
                        continue;
 
@@ -11527,7 +12014,7 @@ intel_display_capture_error_state(struct drm_device *dev)
                enum transcoder cpu_transcoder = transcoders[i];
 
                error->transcoder[i].power_domain_on =
-                       intel_display_power_enabled_sw(dev,
+                       intel_display_power_enabled_sw(dev_priv,
                                POWER_DOMAIN_TRANSCODER(cpu_transcoder));
                if (!error->transcoder[i].power_domain_on)
                        continue;
index 2688f6d..a0dad1a 100644 (file)
@@ -91,18 +91,25 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
 }
 
 static void intel_dp_link_down(struct intel_dp *intel_dp);
+static bool _edp_panel_vdd_on(struct intel_dp *intel_dp);
+static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
 
 static int
 intel_dp_max_link_bw(struct intel_dp *intel_dp)
 {
        int max_link_bw = intel_dp->dpcd[DP_MAX_LINK_RATE];
+       struct drm_device *dev = intel_dp->attached_connector->base.dev;
 
        switch (max_link_bw) {
        case DP_LINK_BW_1_62:
        case DP_LINK_BW_2_7:
                break;
        case DP_LINK_BW_5_4: /* 1.2 capable displays may advertise higher bw */
-               max_link_bw = DP_LINK_BW_2_7;
+               if ((IS_HASWELL(dev) || INTEL_INFO(dev)->gen >= 8) &&
+                   intel_dp->dpcd[DP_DPCD_REV] >= 0x12)
+                       max_link_bw = DP_LINK_BW_5_4;
+               else
+                       max_link_bw = DP_LINK_BW_2_7;
                break;
        default:
                WARN(1, "invalid max DP link bw val %x, using 1.62Gbps\n",
@@ -294,7 +301,7 @@ static u32 _pp_stat_reg(struct intel_dp *intel_dp)
                return VLV_PIPE_PP_STATUS(vlv_power_sequencer_pipe(intel_dp));
 }
 
-static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp)
+static bool edp_have_panel_power(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -302,12 +309,13 @@ static bool ironlake_edp_have_panel_power(struct intel_dp *intel_dp)
        return (I915_READ(_pp_stat_reg(intel_dp)) & PP_ON) != 0;
 }
 
-static bool ironlake_edp_have_panel_vdd(struct intel_dp *intel_dp)
+static bool edp_have_panel_vdd(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       return (I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD) != 0;
+       return !dev_priv->pm.suspended &&
+              (I915_READ(_pp_ctrl_reg(intel_dp)) & EDP_FORCE_VDD) != 0;
 }
 
 static void
@@ -319,7 +327,7 @@ intel_dp_check_edp(struct intel_dp *intel_dp)
        if (!is_edp(intel_dp))
                return;
 
-       if (!ironlake_edp_have_panel_power(intel_dp) && !ironlake_edp_have_panel_vdd(intel_dp)) {
+       if (!edp_have_panel_power(intel_dp) && !edp_have_panel_vdd(intel_dp)) {
                WARN(1, "eDP powered off while attempting aux channel communication.\n");
                DRM_DEBUG_KMS("Status 0x%08x Control 0x%08x\n",
                              I915_READ(_pp_stat_reg(intel_dp)),
@@ -351,31 +359,46 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp, bool has_aux_irq)
        return status;
 }
 
-static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp,
-                                     int index)
+static uint32_t i9xx_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;
 
-       /* 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
-        *
-        * Note that PCH attached eDP panels should use a 125MHz input
-        * clock divider.
+       /*
+        * 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
         */
-       if (IS_VALLEYVIEW(dev)) {
-               return index ? 0 : 100;
-       } else if (intel_dig_port->port == PORT_A) {
-               if (index)
-                       return 0;
-               if (HAS_DDI(dev))
-                       return DIV_ROUND_CLOSEST(intel_ddi_get_cdclk_freq(dev_priv), 2000);
-               else if (IS_GEN6(dev) || IS_GEN7(dev))
+       return index ? 0 : intel_hrawclk(dev) / 2;
+}
+
+static uint32_t ilk_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;
+
+       if (index)
+               return 0;
+
+       if (intel_dig_port->port == PORT_A) {
+               if (IS_GEN6(dev) || IS_GEN7(dev))
                        return 200; /* SNB & IVB eDP input clock at 400Mhz */
                else
                        return 225; /* eDP input clock at 450Mhz */
+       } else {
+               return DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
+       }
+}
+
+static uint32_t hsw_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;
+
+       if (intel_dig_port->port == PORT_A) {
+               if (index)
+                       return 0;
+               return DIV_ROUND_CLOSEST(intel_ddi_get_cdclk_freq(dev_priv), 2000);
        } else if (dev_priv->pch_id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
                /* Workaround for non-ULT HSW */
                switch (index) {
@@ -383,13 +406,46 @@ static uint32_t get_aux_clock_divider(struct intel_dp *intel_dp,
                case 1: return 72;
                default: return 0;
                }
-       } else if (HAS_PCH_SPLIT(dev)) {
+       } else  {
                return index ? 0 : DIV_ROUND_UP(intel_pch_rawclk(dev), 2);
-       } else {
-               return index ? 0 :intel_hrawclk(dev) / 2;
        }
 }
 
+static uint32_t vlv_get_aux_clock_divider(struct intel_dp *intel_dp, int index)
+{
+       return index ? 0 : 100;
+}
+
+static uint32_t i9xx_get_aux_send_ctl(struct intel_dp *intel_dp,
+                                     bool has_aux_irq,
+                                     int send_bytes,
+                                     uint32_t aux_clock_divider)
+{
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       uint32_t precharge, timeout;
+
+       if (IS_GEN6(dev))
+               precharge = 3;
+       else
+               precharge = 5;
+
+       if (IS_BROADWELL(dev) && intel_dp->aux_ch_ctl_reg == DPA_AUX_CH_CTL)
+               timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
+       else
+               timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
+
+       return DP_AUX_CH_CTL_SEND_BUSY |
+              DP_AUX_CH_CTL_DONE |
+              (has_aux_irq ? DP_AUX_CH_CTL_INTERRUPT : 0) |
+              DP_AUX_CH_CTL_TIME_OUT_ERROR |
+              timeout |
+              DP_AUX_CH_CTL_RECEIVE_ERROR |
+              (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);
+}
+
 static int
 intel_dp_aux_ch(struct intel_dp *intel_dp,
                uint8_t *send, int send_bytes,
@@ -403,9 +459,11 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        uint32_t aux_clock_divider;
        int i, ret, recv_bytes;
        uint32_t status;
-       int try, precharge, clock = 0;
+       int try, clock = 0;
        bool has_aux_irq = HAS_AUX_IRQ(dev);
-       uint32_t timeout;
+       bool vdd;
+
+       vdd = _edp_panel_vdd_on(intel_dp);
 
        /* dp aux is extremely sensitive to irq latency, hence request the
         * lowest possible wakeup latency and so prevent the cpu from going into
@@ -415,16 +473,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
 
        intel_dp_check_edp(intel_dp);
 
-       if (IS_GEN6(dev))
-               precharge = 3;
-       else
-               precharge = 5;
-
-       if (IS_BROADWELL(dev) && ch_ctl == DPA_AUX_CH_CTL)
-               timeout = DP_AUX_CH_CTL_TIME_OUT_600us;
-       else
-               timeout = DP_AUX_CH_CTL_TIME_OUT_400us;
-
        intel_aux_display_runtime_get(dev_priv);
 
        /* Try to wait for any previous AUX channel activity */
@@ -448,7 +496,12 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                goto out;
        }
 
-       while ((aux_clock_divider = get_aux_clock_divider(intel_dp, clock++))) {
+       while ((aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, clock++))) {
+               u32 send_ctl = intel_dp->get_aux_send_ctl(intel_dp,
+                                                         has_aux_irq,
+                                                         send_bytes,
+                                                         aux_clock_divider);
+
                /* 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 */
@@ -457,16 +510,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
                                           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) |
-                                  timeout |
-                                  (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);
+                       I915_WRITE(ch_ctl, send_ctl);
 
                        status = intel_dp_aux_wait_done(intel_dp, has_aux_irq);
 
@@ -525,246 +569,140 @@ out:
        pm_qos_update_request(&dev_priv->pm_qos, PM_QOS_DEFAULT_VALUE);
        intel_aux_display_runtime_put(dev_priv);
 
+       if (vdd)
+               edp_panel_vdd_off(intel_dp, false);
+
        return ret;
 }
 
-/* Write data to the aux channel in native mode */
-static int
-intel_dp_aux_native_write(struct intel_dp *intel_dp,
-                         uint16_t address, uint8_t *send, int send_bytes)
+#define HEADER_SIZE    4
+static ssize_t
+intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
+       struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
+       uint8_t txbuf[20], rxbuf[20];
+       size_t txsize, rxsize;
        int ret;
-       uint8_t msg[20];
-       int msg_bytes;
-       uint8_t ack;
-       int retry;
 
-       if (WARN_ON(send_bytes > 16))
-               return -E2BIG;
+       txbuf[0] = msg->request << 4;
+       txbuf[1] = msg->address >> 8;
+       txbuf[2] = msg->address & 0xff;
+       txbuf[3] = msg->size - 1;
 
-       intel_dp_check_edp(intel_dp);
-       msg[0] = DP_AUX_NATIVE_WRITE << 4;
-       msg[1] = address >> 8;
-       msg[2] = address & 0xff;
-       msg[3] = send_bytes - 1;
-       memcpy(&msg[4], send, send_bytes);
-       msg_bytes = send_bytes + 4;
-       for (retry = 0; retry < 7; retry++) {
-               ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1);
-               if (ret < 0)
-                       return ret;
-               ack >>= 4;
-               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
-                       return send_bytes;
-               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
-                       usleep_range(400, 500);
-               else
-                       return -EIO;
-       }
+       switch (msg->request & ~DP_AUX_I2C_MOT) {
+       case DP_AUX_NATIVE_WRITE:
+       case DP_AUX_I2C_WRITE:
+               txsize = HEADER_SIZE + msg->size;
+               rxsize = 1;
 
-       DRM_ERROR("too many retries, giving up\n");
-       return -EIO;
-}
+               if (WARN_ON(txsize > 20))
+                       return -E2BIG;
 
-/* Write a single byte to the aux channel in native mode */
-static int
-intel_dp_aux_native_write_1(struct intel_dp *intel_dp,
-                           uint16_t address, uint8_t byte)
-{
-       return intel_dp_aux_native_write(intel_dp, address, &byte, 1);
-}
+               memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
 
-/* read bytes from a native aux channel */
-static int
-intel_dp_aux_native_read(struct intel_dp *intel_dp,
-                        uint16_t address, uint8_t *recv, int recv_bytes)
-{
-       uint8_t msg[4];
-       int msg_bytes;
-       uint8_t reply[20];
-       int reply_bytes;
-       uint8_t ack;
-       int ret;
-       int retry;
+               ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize);
+               if (ret > 0) {
+                       msg->reply = rxbuf[0] >> 4;
+
+                       /* Return payload size. */
+                       ret = msg->size;
+               }
+               break;
 
-       if (WARN_ON(recv_bytes > 19))
-               return -E2BIG;
+       case DP_AUX_NATIVE_READ:
+       case DP_AUX_I2C_READ:
+               txsize = HEADER_SIZE;
+               rxsize = msg->size + 1;
 
-       intel_dp_check_edp(intel_dp);
-       msg[0] = DP_AUX_NATIVE_READ << 4;
-       msg[1] = address >> 8;
-       msg[2] = address & 0xff;
-       msg[3] = recv_bytes - 1;
-
-       msg_bytes = 4;
-       reply_bytes = recv_bytes + 1;
-
-       for (retry = 0; retry < 7; retry++) {
-               ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes,
-                                     reply, reply_bytes);
-               if (ret == 0)
-                       return -EPROTO;
-               if (ret < 0)
-                       return ret;
-               ack = reply[0] >> 4;
-               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) {
-                       memcpy(recv, reply + 1, ret - 1);
-                       return ret - 1;
+               if (WARN_ON(rxsize > 20))
+                       return -E2BIG;
+
+               ret = intel_dp_aux_ch(intel_dp, txbuf, txsize, rxbuf, rxsize);
+               if (ret > 0) {
+                       msg->reply = rxbuf[0] >> 4;
+                       /*
+                        * Assume happy day, and copy the data. The caller is
+                        * expected to check msg->reply before touching it.
+                        *
+                        * Return payload size.
+                        */
+                       ret--;
+                       memcpy(msg->buffer, rxbuf + 1, ret);
                }
-               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
-                       usleep_range(400, 500);
-               else
-                       return -EIO;
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
        }
 
-       DRM_ERROR("too many retries, giving up\n");
-       return -EIO;
+       return ret;
 }
 
-static int
-intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
-                   uint8_t write_byte, uint8_t *read_byte)
-{
-       struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
-       struct intel_dp *intel_dp = container_of(adapter,
-                                               struct intel_dp,
-                                               adapter);
-       uint16_t address = algo_data->address;
-       uint8_t msg[5];
-       uint8_t reply[2];
-       unsigned retry;
-       int msg_bytes;
-       int reply_bytes;
+static void
+intel_dp_aux_init(struct intel_dp *intel_dp, struct intel_connector *connector)
+{
+       struct drm_device *dev = intel_dp_to_dev(intel_dp);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       enum port port = intel_dig_port->port;
+       const char *name = NULL;
        int ret;
 
-       ironlake_edp_panel_vdd_on(intel_dp);
-       intel_dp_check_edp(intel_dp);
-       /* Set up the command byte */
-       if (mode & MODE_I2C_READ)
-               msg[0] = DP_AUX_I2C_READ << 4;
-       else
-               msg[0] = DP_AUX_I2C_WRITE << 4;
-
-       if (!(mode & MODE_I2C_STOP))
-               msg[0] |= DP_AUX_I2C_MOT << 4;
-
-       msg[1] = address >> 8;
-       msg[2] = address;
-
-       switch (mode) {
-       case MODE_I2C_WRITE:
-               msg[3] = 0;
-               msg[4] = write_byte;
-               msg_bytes = 5;
-               reply_bytes = 1;
+       switch (port) {
+       case PORT_A:
+               intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL;
+               name = "DPDDC-A";
+               break;
+       case PORT_B:
+               intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL;
+               name = "DPDDC-B";
+               break;
+       case PORT_C:
+               intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL;
+               name = "DPDDC-C";
                break;
-       case MODE_I2C_READ:
-               msg[3] = 0;
-               msg_bytes = 4;
-               reply_bytes = 2;
+       case PORT_D:
+               intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL;
+               name = "DPDDC-D";
                break;
        default:
-               msg_bytes = 3;
-               reply_bytes = 1;
-               break;
+               BUG();
        }
 
-       /*
-        * DP1.2 sections 2.7.7.1.5.6.1 and 2.7.7.1.6.6.1: A DP Source device is
-        * required to retry at least seven times upon receiving AUX_DEFER
-        * before giving up the AUX transaction.
-        */
-       for (retry = 0; retry < 7; retry++) {
-               ret = intel_dp_aux_ch(intel_dp,
-                                     msg, msg_bytes,
-                                     reply, reply_bytes);
-               if (ret < 0) {
-                       DRM_DEBUG_KMS("aux_ch failed %d\n", ret);
-                       goto out;
-               }
+       if (!HAS_DDI(dev))
+               intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
 
-               switch ((reply[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK) {
-               case DP_AUX_NATIVE_REPLY_ACK:
-                       /* I2C-over-AUX Reply field is only valid
-                        * when paired with AUX ACK.
-                        */
-                       break;
-               case DP_AUX_NATIVE_REPLY_NACK:
-                       DRM_DEBUG_KMS("aux_ch native nack\n");
-                       ret = -EREMOTEIO;
-                       goto out;
-               case DP_AUX_NATIVE_REPLY_DEFER:
-                       /*
-                        * For now, just give more slack to branch devices. We
-                        * could check the DPCD for I2C bit rate capabilities,
-                        * and if available, adjust the interval. We could also
-                        * be more careful with DP-to-Legacy adapters where a
-                        * long legacy cable may force very low I2C bit rates.
-                        */
-                       if (intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
-                           DP_DWN_STRM_PORT_PRESENT)
-                               usleep_range(500, 600);
-                       else
-                               usleep_range(300, 400);
-                       continue;
-               default:
-                       DRM_ERROR("aux_ch invalid native reply 0x%02x\n",
-                                 reply[0]);
-                       ret = -EREMOTEIO;
-                       goto out;
-               }
+       intel_dp->aux.name = name;
+       intel_dp->aux.dev = dev->dev;
+       intel_dp->aux.transfer = intel_dp_aux_transfer;
 
-               switch ((reply[0] >> 4) & DP_AUX_I2C_REPLY_MASK) {
-               case DP_AUX_I2C_REPLY_ACK:
-                       if (mode == MODE_I2C_READ) {
-                               *read_byte = reply[1];
-                       }
-                       ret = reply_bytes - 1;
-                       goto out;
-               case DP_AUX_I2C_REPLY_NACK:
-                       DRM_DEBUG_KMS("aux_i2c nack\n");
-                       ret = -EREMOTEIO;
-                       goto out;
-               case DP_AUX_I2C_REPLY_DEFER:
-                       DRM_DEBUG_KMS("aux_i2c defer\n");
-                       udelay(100);
-                       break;
-               default:
-                       DRM_ERROR("aux_i2c invalid reply 0x%02x\n", reply[0]);
-                       ret = -EREMOTEIO;
-                       goto out;
-               }
-       }
+       DRM_DEBUG_KMS("registering %s bus for %s\n", name,
+                     connector->base.kdev->kobj.name);
 
-       DRM_ERROR("too many retries, giving up\n");
-       ret = -EREMOTEIO;
+       ret = drm_dp_aux_register_i2c_bus(&intel_dp->aux);
+       if (ret < 0) {
+               DRM_ERROR("drm_dp_aux_register_i2c_bus() for %s failed (%d)\n",
+                         name, ret);
+               return;
+       }
 
-out:
-       ironlake_edp_panel_vdd_off(intel_dp, false);
-       return ret;
+       ret = sysfs_create_link(&connector->base.kdev->kobj,
+                               &intel_dp->aux.ddc.dev.kobj,
+                               intel_dp->aux.ddc.dev.kobj.name);
+       if (ret < 0) {
+               DRM_ERROR("sysfs_create_link() for %s failed (%d)\n", name, ret);
+               drm_dp_aux_unregister_i2c_bus(&intel_dp->aux);
+       }
 }
 
-static int
-intel_dp_i2c_init(struct intel_dp *intel_dp,
-                 struct intel_connector *intel_connector, const char *name)
+static void
+intel_dp_connector_unregister(struct intel_connector *intel_connector)
 {
-       int     ret;
-
-       DRM_DEBUG_KMS("i2c_init %s\n", name);
-       intel_dp->algo.running = false;
-       intel_dp->algo.address = 0;
-       intel_dp->algo.aux_ch = intel_dp_i2c_aux_ch;
-
-       memset(&intel_dp->adapter, '\0', sizeof(intel_dp->adapter));
-       intel_dp->adapter.owner = THIS_MODULE;
-       intel_dp->adapter.class = I2C_CLASS_DDC;
-       strncpy(intel_dp->adapter.name, name, sizeof(intel_dp->adapter.name) - 1);
-       intel_dp->adapter.name[sizeof(intel_dp->adapter.name) - 1] = '\0';
-       intel_dp->adapter.algo_data = &intel_dp->algo;
-       intel_dp->adapter.dev.parent = intel_connector->base.kdev;
+       struct intel_dp *intel_dp = intel_attached_dp(&intel_connector->base);
 
-       ret = i2c_dp_aux_add_bus(&intel_dp->adapter);
-       return ret;
+       sysfs_remove_link(&intel_connector->base.kdev->kobj,
+                         intel_dp->aux.ddc.dev.kobj.name);
+       intel_connector_unregister(intel_connector);
 }
 
 static void
@@ -812,9 +750,10 @@ intel_dp_compute_config(struct intel_encoder *encoder,
        struct intel_connector *intel_connector = intel_dp->attached_connector;
        int lane_count, clock;
        int max_lane_count = drm_dp_max_lane_count(intel_dp->dpcd);
-       int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
+       /* Conveniently, the link BW constants become indices with a shift...*/
+       int max_clock = intel_dp_max_link_bw(intel_dp) >> 3;
        int bpp, mode_rate;
-       static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
+       static int bws[] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7, DP_LINK_BW_5_4 };
        int link_avail, link_clock;
 
        if (HAS_PCH_SPLIT(dev) && !HAS_DDI(dev) && port != PORT_A)
@@ -855,8 +794,8 @@ intel_dp_compute_config(struct intel_encoder *encoder,
                mode_rate = intel_dp_link_required(adjusted_mode->crtc_clock,
                                                   bpp);
 
-               for (clock = 0; clock <= max_clock; clock++) {
-                       for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
+               for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
+                       for (clock = 0; clock <= max_clock; clock++) {
                                link_clock = drm_dp_bw_code_to_link_rate(bws[clock]);
                                link_avail = intel_dp_max_data_rate(link_clock,
                                                                    lane_count);
@@ -1015,16 +954,16 @@ static void intel_dp_mode_set(struct intel_encoder *encoder)
                ironlake_set_pll_cpu_edp(intel_dp);
 }
 
-#define IDLE_ON_MASK           (PP_ON | 0        | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
-#define IDLE_ON_VALUE          (PP_ON | 0        | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_ON_IDLE)
+#define IDLE_ON_MASK           (PP_ON | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
+#define IDLE_ON_VALUE          (PP_ON | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_ON_IDLE)
 
-#define IDLE_OFF_MASK          (PP_ON | 0        | PP_SEQUENCE_MASK | 0                     | PP_SEQUENCE_STATE_MASK)
-#define IDLE_OFF_VALUE         (0     | 0        | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
+#define IDLE_OFF_MASK          (PP_ON | PP_SEQUENCE_MASK | 0                     | 0)
+#define IDLE_OFF_VALUE         (0     | PP_SEQUENCE_NONE | 0                     | 0)
 
-#define IDLE_CYCLE_MASK                (PP_ON | 0        | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
-#define IDLE_CYCLE_VALUE       (0     | 0        | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
+#define IDLE_CYCLE_MASK                (PP_ON | PP_SEQUENCE_MASK | PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK)
+#define IDLE_CYCLE_VALUE       (0     | PP_SEQUENCE_NONE | 0                     | PP_SEQUENCE_STATE_OFF_IDLE)
 
-static void ironlake_wait_panel_status(struct intel_dp *intel_dp,
+static void wait_panel_status(struct intel_dp *intel_dp,
                                       u32 mask,
                                       u32 value)
 {
@@ -1049,24 +988,41 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp,
        DRM_DEBUG_KMS("Wait complete\n");
 }
 
-static void ironlake_wait_panel_on(struct intel_dp *intel_dp)
+static void wait_panel_on(struct intel_dp *intel_dp)
 {
        DRM_DEBUG_KMS("Wait for panel power on\n");
-       ironlake_wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
+       wait_panel_status(intel_dp, IDLE_ON_MASK, IDLE_ON_VALUE);
 }
 
-static void ironlake_wait_panel_off(struct intel_dp *intel_dp)
+static void wait_panel_off(struct intel_dp *intel_dp)
 {
        DRM_DEBUG_KMS("Wait for panel power off time\n");
-       ironlake_wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
+       wait_panel_status(intel_dp, IDLE_OFF_MASK, IDLE_OFF_VALUE);
 }
 
-static void ironlake_wait_panel_power_cycle(struct intel_dp *intel_dp)
+static void wait_panel_power_cycle(struct intel_dp *intel_dp)
 {
        DRM_DEBUG_KMS("Wait for panel power cycle\n");
-       ironlake_wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE);
+
+       /* When we disable the VDD override bit last we have to do the manual
+        * wait. */
+       wait_remaining_ms_from_jiffies(intel_dp->last_power_cycle,
+                                      intel_dp->panel_power_cycle_delay);
+
+       wait_panel_status(intel_dp, IDLE_CYCLE_MASK, IDLE_CYCLE_VALUE);
+}
+
+static void wait_backlight_on(struct intel_dp *intel_dp)
+{
+       wait_remaining_ms_from_jiffies(intel_dp->last_power_on,
+                                      intel_dp->backlight_on_delay);
 }
 
+static void edp_wait_backlight_off(struct intel_dp *intel_dp)
+{
+       wait_remaining_ms_from_jiffies(intel_dp->last_backlight_off,
+                                      intel_dp->backlight_off_delay);
+}
 
 /* Read the current pp_control value, unlocking the register if it
  * is locked
@@ -1084,30 +1040,28 @@ static  u32 ironlake_get_pp_control(struct intel_dp *intel_dp)
        return control;
 }
 
-void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
+static bool _edp_panel_vdd_on(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 pp;
        u32 pp_stat_reg, pp_ctrl_reg;
+       bool need_to_disable = !intel_dp->want_panel_vdd;
 
        if (!is_edp(intel_dp))
-               return;
-
-       WARN(intel_dp->want_panel_vdd,
-            "eDP VDD already requested on\n");
+               return false;
 
        intel_dp->want_panel_vdd = true;
 
-       if (ironlake_edp_have_panel_vdd(intel_dp))
-               return;
+       if (edp_have_panel_vdd(intel_dp))
+               return need_to_disable;
 
        intel_runtime_pm_get(dev_priv);
 
        DRM_DEBUG_KMS("Turning eDP VDD on\n");
 
-       if (!ironlake_edp_have_panel_power(intel_dp))
-               ironlake_wait_panel_power_cycle(intel_dp);
+       if (!edp_have_panel_power(intel_dp))
+               wait_panel_power_cycle(intel_dp);
 
        pp = ironlake_get_pp_control(intel_dp);
        pp |= EDP_FORCE_VDD;
@@ -1122,13 +1076,24 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
        /*
         * If the panel wasn't on, delay before accessing aux channel
         */
-       if (!ironlake_edp_have_panel_power(intel_dp)) {
+       if (!edp_have_panel_power(intel_dp)) {
                DRM_DEBUG_KMS("eDP was not running\n");
                msleep(intel_dp->panel_power_up_delay);
        }
+
+       return need_to_disable;
+}
+
+void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
+{
+       if (is_edp(intel_dp)) {
+               bool vdd = _edp_panel_vdd_on(intel_dp);
+
+               WARN(!vdd, "eDP VDD already requested on\n");
+       }
 }
 
-static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
+static void edp_panel_vdd_off_sync(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1137,7 +1102,7 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
 
        WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
 
-       if (!intel_dp->want_panel_vdd && ironlake_edp_have_panel_vdd(intel_dp)) {
+       if (!intel_dp->want_panel_vdd && edp_have_panel_vdd(intel_dp)) {
                DRM_DEBUG_KMS("Turning eDP VDD off\n");
 
                pp = ironlake_get_pp_control(intel_dp);
@@ -1154,24 +1119,24 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *intel_dp)
                I915_READ(pp_stat_reg), I915_READ(pp_ctrl_reg));
 
                if ((pp & POWER_TARGET_ON) == 0)
-                       msleep(intel_dp->panel_power_cycle_delay);
+                       intel_dp->last_power_cycle = jiffies;
 
                intel_runtime_pm_put(dev_priv);
        }
 }
 
-static void ironlake_panel_vdd_work(struct work_struct *__work)
+static void edp_panel_vdd_work(struct work_struct *__work)
 {
        struct intel_dp *intel_dp = container_of(to_delayed_work(__work),
                                                 struct intel_dp, panel_vdd_work);
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
        mutex_lock(&dev->mode_config.mutex);
-       ironlake_panel_vdd_off_sync(intel_dp);
+       edp_panel_vdd_off_sync(intel_dp);
        mutex_unlock(&dev->mode_config.mutex);
 }
 
-void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
+static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
 {
        if (!is_edp(intel_dp))
                return;
@@ -1181,7 +1146,7 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
        intel_dp->want_panel_vdd = false;
 
        if (sync) {
-               ironlake_panel_vdd_off_sync(intel_dp);
+               edp_panel_vdd_off_sync(intel_dp);
        } else {
                /*
                 * Queue the timer to fire a long
@@ -1193,7 +1158,7 @@ void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
        }
 }
 
-void ironlake_edp_panel_on(struct intel_dp *intel_dp)
+void intel_edp_panel_on(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1205,12 +1170,12 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Turn eDP power on\n");
 
-       if (ironlake_edp_have_panel_power(intel_dp)) {
+       if (edp_have_panel_power(intel_dp)) {
                DRM_DEBUG_KMS("eDP power already on\n");
                return;
        }
 
-       ironlake_wait_panel_power_cycle(intel_dp);
+       wait_panel_power_cycle(intel_dp);
 
        pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
        pp = ironlake_get_pp_control(intel_dp);
@@ -1228,7 +1193,8 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
 
-       ironlake_wait_panel_on(intel_dp);
+       wait_panel_on(intel_dp);
+       intel_dp->last_power_on = jiffies;
 
        if (IS_GEN5(dev)) {
                pp |= PANEL_POWER_RESET; /* restore panel reset bit */
@@ -1237,7 +1203,7 @@ void ironlake_edp_panel_on(struct intel_dp *intel_dp)
        }
 }
 
-void ironlake_edp_panel_off(struct intel_dp *intel_dp)
+void intel_edp_panel_off(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1249,27 +1215,31 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Turn eDP power off\n");
 
+       edp_wait_backlight_off(intel_dp);
+
        WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
 
        pp = ironlake_get_pp_control(intel_dp);
        /* We need to switch off panel power _and_ force vdd, for otherwise some
         * panels get very unhappy and cease to work. */
-       pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+       pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_FORCE_VDD |
+               EDP_BLC_ENABLE);
 
        pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
 
+       intel_dp->want_panel_vdd = false;
+
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
 
-       intel_dp->want_panel_vdd = false;
-
-       ironlake_wait_panel_off(intel_dp);
+       intel_dp->last_power_cycle = jiffies;
+       wait_panel_off(intel_dp);
 
        /* We got a reference when we enabled the VDD. */
        intel_runtime_pm_put(dev_priv);
 }
 
-void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
+void intel_edp_backlight_on(struct intel_dp *intel_dp)
 {
        struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
        struct drm_device *dev = intel_dig_port->base.base.dev;
@@ -1287,7 +1257,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
         * link.  So delay a bit to make sure the image is solid before
         * allowing it to appear.
         */
-       msleep(intel_dp->backlight_on_delay);
+       wait_backlight_on(intel_dp);
        pp = ironlake_get_pp_control(intel_dp);
        pp |= EDP_BLC_ENABLE;
 
@@ -1299,7 +1269,7 @@ void ironlake_edp_backlight_on(struct intel_dp *intel_dp)
        intel_panel_enable_backlight(intel_dp->attached_connector);
 }
 
-void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
+void intel_edp_backlight_off(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1319,7 +1289,7 @@ void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
 
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
-       msleep(intel_dp->backlight_off_delay);
+       intel_dp->last_backlight_off = jiffies;
 }
 
 static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
@@ -1383,8 +1353,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
                return;
 
        if (mode != DRM_MODE_DPMS_ON) {
-               ret = intel_dp_aux_native_write_1(intel_dp, DP_SET_POWER,
-                                                 DP_SET_POWER_D3);
+               ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
+                                        DP_SET_POWER_D3);
                if (ret != 1)
                        DRM_DEBUG_DRIVER("failed to write sink power state\n");
        } else {
@@ -1393,9 +1363,8 @@ void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
                 * time to wake up.
                 */
                for (i = 0; i < 3; i++) {
-                       ret = intel_dp_aux_native_write_1(intel_dp,
-                                                         DP_SET_POWER,
-                                                         DP_SET_POWER_D0);
+                       ret = drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
+                                                DP_SET_POWER_D0);
                        if (ret == 1)
                                break;
                        msleep(1);
@@ -1410,7 +1379,14 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
        enum port port = dp_to_dig_port(intel_dp)->port;
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 tmp = I915_READ(intel_dp->output_reg);
+       enum intel_display_power_domain power_domain;
+       u32 tmp;
+
+       power_domain = intel_display_port_power_domain(encoder);
+       if (!intel_display_power_enabled(dev_priv, power_domain))
+               return false;
+
+       tmp = I915_READ(intel_dp->output_reg);
 
        if (!(tmp & DP_PORT_EN))
                return false;
@@ -1604,19 +1580,19 @@ 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);
+       uint32_t aux_clock_divider;
        int precharge = 0x3;
        int msg_size = 5;       /* Header(4) + Message(1) */
 
+       aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
+
        /* 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);
+               drm_dp_dpcd_writeb(&intel_dp->aux, 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);
+               drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
+                                  DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
 
        /* Setup AUX registers */
        I915_WRITE(EDP_PSR_AUX_DATA1(dev), EDP_PSR_DPCD_COMMAND);
@@ -1659,7 +1635,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
        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 drm_i915_gem_object *obj = to_intel_framebuffer(crtc->primary->fb)->obj;
        struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
 
        dev_priv->psr.source_ok = false;
@@ -1675,7 +1651,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
                return false;
        }
 
-       if (!i915_enable_psr) {
+       if (!i915.enable_psr) {
                DRM_DEBUG_KMS("PSR disable by flag\n");
                return false;
        }
@@ -1692,7 +1668,7 @@ static bool intel_edp_psr_match_conditions(struct intel_dp *intel_dp)
                return false;
        }
 
-       obj = to_intel_framebuffer(crtc->fb)->obj;
+       obj = to_intel_framebuffer(crtc->primary->fb)->obj;
        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");
@@ -1791,10 +1767,10 @@ static void intel_disable_dp(struct intel_encoder *encoder)
 
        /* Make sure the panel is off before trying to change the mode. But also
         * ensure that we have vdd while we switch off the panel. */
-       ironlake_edp_panel_vdd_on(intel_dp);
-       ironlake_edp_backlight_off(intel_dp);
+       intel_edp_panel_vdd_on(intel_dp);
+       intel_edp_backlight_off(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
-       ironlake_edp_panel_off(intel_dp);
+       intel_edp_panel_off(intel_dp);
 
        /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
        if (!(port == PORT_A || IS_VALLEYVIEW(dev)))
@@ -1824,11 +1800,11 @@ static void intel_enable_dp(struct intel_encoder *encoder)
        if (WARN_ON(dp_reg & DP_PORT_EN))
                return;
 
-       ironlake_edp_panel_vdd_on(intel_dp);
+       intel_edp_panel_vdd_on(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        intel_dp_start_link_train(intel_dp);
-       ironlake_edp_panel_on(intel_dp);
-       ironlake_edp_panel_vdd_off(intel_dp, true);
+       intel_edp_panel_on(intel_dp);
+       edp_panel_vdd_off(intel_dp, true);
        intel_dp_complete_link_train(intel_dp);
        intel_dp_stop_link_train(intel_dp);
 }
@@ -1838,14 +1814,14 @@ static void g4x_enable_dp(struct intel_encoder *encoder)
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
        intel_enable_dp(encoder);
-       ironlake_edp_backlight_on(intel_dp);
+       intel_edp_backlight_on(intel_dp);
 }
 
 static void vlv_enable_dp(struct intel_encoder *encoder)
 {
        struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
-       ironlake_edp_backlight_on(intel_dp);
+       intel_edp_backlight_on(intel_dp);
 }
 
 static void g4x_pre_enable_dp(struct intel_encoder *encoder)
@@ -1927,26 +1903,25 @@ static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder)
 /*
  * Native read with retry for link status and receiver capability reads for
  * cases where the sink may still be asleep.
+ *
+ * Sinks are *supposed* to come up within 1ms from an off state, but we're also
+ * supposed to retry 3 times per the spec.
  */
-static bool
-intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address,
-                              uint8_t *recv, int recv_bytes)
+static ssize_t
+intel_dp_dpcd_read_wake(struct drm_dp_aux *aux, unsigned int offset,
+                       void *buffer, size_t size)
 {
-       int ret, i;
+       ssize_t ret;
+       int i;
 
-       /*
-        * Sinks are *supposed* to come up within 1ms from an off state,
-        * but we're also supposed to retry 3 times per the spec.
-        */
        for (i = 0; i < 3; i++) {
-               ret = intel_dp_aux_native_read(intel_dp, address, recv,
-                                              recv_bytes);
-               if (ret == recv_bytes)
-                       return true;
+               ret = drm_dp_dpcd_read(aux, offset, buffer, size);
+               if (ret == size)
+                       return ret;
                msleep(1);
        }
 
-       return false;
+       return ret;
 }
 
 /*
@@ -1956,10 +1931,10 @@ intel_dp_aux_native_read_retry(struct intel_dp *intel_dp, uint16_t address,
 static bool
 intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
 {
-       return intel_dp_aux_native_read_retry(intel_dp,
-                                             DP_LANE0_1_STATUS,
-                                             link_status,
-                                             DP_LINK_STATUS_SIZE);
+       return intel_dp_dpcd_read_wake(&intel_dp->aux,
+                                      DP_LANE0_1_STATUS,
+                                      link_status,
+                                      DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
 }
 
 /*
@@ -2473,8 +2448,8 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
                len = intel_dp->lane_count + 1;
        }
 
-       ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_PATTERN_SET,
-                                       buf, len);
+       ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
+                               buf, len);
 
        return ret == len;
 }
@@ -2503,9 +2478,8 @@ intel_dp_update_link_train(struct intel_dp *intel_dp, uint32_t *DP,
        I915_WRITE(intel_dp->output_reg, *DP);
        POSTING_READ(intel_dp->output_reg);
 
-       ret = intel_dp_aux_native_write(intel_dp, DP_TRAINING_LANE0_SET,
-                                       intel_dp->train_set,
-                                       intel_dp->lane_count);
+       ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
+                               intel_dp->train_set, intel_dp->lane_count);
 
        return ret == intel_dp->lane_count;
 }
@@ -2561,11 +2535,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
        link_config[1] = intel_dp->lane_count;
        if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
                link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
-       intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET, link_config, 2);
+       drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
 
        link_config[0] = 0;
        link_config[1] = DP_SET_ANSI_8B10B;
-       intel_dp_aux_native_write(intel_dp, DP_DOWNSPREAD_CTRL, link_config, 2);
+       drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
 
        DP |= DP_PORT_EN;
 
@@ -2638,10 +2612,15 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
        bool channel_eq = false;
        int tries, cr_tries;
        uint32_t DP = intel_dp->DP;
+       uint32_t training_pattern = DP_TRAINING_PATTERN_2;
+
+       /* Training Pattern 3 for HBR2 ot 1.2 devices that support it*/
+       if (intel_dp->link_bw == DP_LINK_BW_5_4 || intel_dp->use_tps3)
+               training_pattern = DP_TRAINING_PATTERN_3;
 
        /* channel equalization */
        if (!intel_dp_set_link_train(intel_dp, &DP,
-                                    DP_TRAINING_PATTERN_2 |
+                                    training_pattern |
                                     DP_LINK_SCRAMBLING_DISABLE)) {
                DRM_ERROR("failed to start channel equalization\n");
                return;
@@ -2668,7 +2647,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
                if (!drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
                        intel_dp_start_link_train(intel_dp);
                        intel_dp_set_link_train(intel_dp, &DP,
-                                               DP_TRAINING_PATTERN_2 |
+                                               training_pattern |
                                                DP_LINK_SCRAMBLING_DISABLE);
                        cr_tries++;
                        continue;
@@ -2684,7 +2663,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
                        intel_dp_link_down(intel_dp);
                        intel_dp_start_link_train(intel_dp);
                        intel_dp_set_link_train(intel_dp, &DP,
-                                               DP_TRAINING_PATTERN_2 |
+                                               training_pattern |
                                                DP_LINK_SCRAMBLING_DISABLE);
                        tries = 0;
                        cr_tries++;
@@ -2803,8 +2782,8 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
 
        char dpcd_hex_dump[sizeof(intel_dp->dpcd) * 3];
 
-       if (intel_dp_aux_native_read_retry(intel_dp, 0x000, intel_dp->dpcd,
-                                          sizeof(intel_dp->dpcd)) == 0)
+       if (intel_dp_dpcd_read_wake(&intel_dp->aux, 0x000, intel_dp->dpcd,
+                                   sizeof(intel_dp->dpcd)) < 0)
                return false; /* aux transfer failed */
 
        hex_dump_to_buffer(intel_dp->dpcd, sizeof(intel_dp->dpcd),
@@ -2817,15 +2796,23 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        /* Check if the panel supports PSR */
        memset(intel_dp->psr_dpcd, 0, sizeof(intel_dp->psr_dpcd));
        if (is_edp(intel_dp)) {
-               intel_dp_aux_native_read_retry(intel_dp, DP_PSR_SUPPORT,
-                                              intel_dp->psr_dpcd,
-                                              sizeof(intel_dp->psr_dpcd));
+               intel_dp_dpcd_read_wake(&intel_dp->aux, DP_PSR_SUPPORT,
+                                       intel_dp->psr_dpcd,
+                                       sizeof(intel_dp->psr_dpcd));
                if (intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED) {
                        dev_priv->psr.sink_support = true;
                        DRM_DEBUG_KMS("Detected EDP PSR Panel.\n");
                }
        }
 
+       /* Training Pattern 3 support */
+       if (intel_dp->dpcd[DP_DPCD_REV] >= 0x12 &&
+           intel_dp->dpcd[DP_MAX_LANE_COUNT] & DP_TPS3_SUPPORTED) {
+               intel_dp->use_tps3 = true;
+               DRM_DEBUG_KMS("Displayport TPS3 supported");
+       } else
+               intel_dp->use_tps3 = false;
+
        if (!(intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] &
              DP_DWN_STRM_PORT_PRESENT))
                return true; /* native DP sink */
@@ -2833,9 +2820,9 @@ intel_dp_get_dpcd(struct intel_dp *intel_dp)
        if (intel_dp->dpcd[DP_DPCD_REV] == 0x10)
                return true; /* no per-port downstream info */
 
-       if (intel_dp_aux_native_read_retry(intel_dp, DP_DOWNSTREAM_PORT_0,
-                                          intel_dp->downstream_ports,
-                                          DP_MAX_DOWNSTREAM_PORTS) == 0)
+       if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_DOWNSTREAM_PORT_0,
+                                   intel_dp->downstream_ports,
+                                   DP_MAX_DOWNSTREAM_PORTS) < 0)
                return false; /* downstream port status fetch failed */
 
        return true;
@@ -2849,38 +2836,61 @@ intel_dp_probe_oui(struct intel_dp *intel_dp)
        if (!(intel_dp->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
                return;
 
-       ironlake_edp_panel_vdd_on(intel_dp);
+       intel_edp_panel_vdd_on(intel_dp);
 
-       if (intel_dp_aux_native_read_retry(intel_dp, DP_SINK_OUI, buf, 3))
+       if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_SINK_OUI, buf, 3) == 3)
                DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
                              buf[0], buf[1], buf[2]);
 
-       if (intel_dp_aux_native_read_retry(intel_dp, DP_BRANCH_OUI, buf, 3))
+       if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_BRANCH_OUI, buf, 3) == 3)
                DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
                              buf[0], buf[1], buf[2]);
 
-       ironlake_edp_panel_vdd_off(intel_dp, false);
+       edp_panel_vdd_off(intel_dp, false);
 }
 
-static bool
-intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector)
+int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc)
 {
-       int ret;
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct drm_device *dev = intel_dig_port->base.base.dev;
+       struct intel_crtc *intel_crtc =
+               to_intel_crtc(intel_dig_port->base.base.crtc);
+       u8 buf[1];
 
-       ret = intel_dp_aux_native_read_retry(intel_dp,
-                                            DP_DEVICE_SERVICE_IRQ_VECTOR,
-                                            sink_irq_vector, 1);
-       if (!ret)
-               return false;
+       if (drm_dp_dpcd_readb(&intel_dp->aux, DP_TEST_SINK_MISC, buf) < 0)
+               return -EAGAIN;
 
-       return true;
+       if (!(buf[0] & DP_TEST_CRC_SUPPORTED))
+               return -ENOTTY;
+
+       if (drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK,
+                              DP_TEST_SINK_START) < 0)
+               return -EAGAIN;
+
+       /* Wait 2 vblanks to be sure we will have the correct CRC value */
+       intel_wait_for_vblank(dev, intel_crtc->pipe);
+       intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+       if (drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_CRC_R_CR, crc, 6) < 0)
+               return -EAGAIN;
+
+       drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_SINK, 0);
+       return 0;
+}
+
+static bool
+intel_dp_get_sink_irq(struct intel_dp *intel_dp, u8 *sink_irq_vector)
+{
+       return intel_dp_dpcd_read_wake(&intel_dp->aux,
+                                      DP_DEVICE_SERVICE_IRQ_VECTOR,
+                                      sink_irq_vector, 1) == 1;
 }
 
 static void
 intel_dp_handle_test_request(struct intel_dp *intel_dp)
 {
        /* NAK by default */
-       intel_dp_aux_native_write_1(intel_dp, DP_TEST_RESPONSE, DP_TEST_NAK);
+       drm_dp_dpcd_writeb(&intel_dp->aux, DP_TEST_RESPONSE, DP_TEST_NAK);
 }
 
 /*
@@ -2919,9 +2929,9 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
            intel_dp_get_sink_irq(intel_dp, &sink_irq_vector)) {
                /* Clear interrupt source */
-               intel_dp_aux_native_write_1(intel_dp,
-                                           DP_DEVICE_SERVICE_IRQ_VECTOR,
-                                           sink_irq_vector);
+               drm_dp_dpcd_writeb(&intel_dp->aux,
+                                  DP_DEVICE_SERVICE_IRQ_VECTOR,
+                                  sink_irq_vector);
 
                if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST)
                        intel_dp_handle_test_request(intel_dp);
@@ -2956,15 +2966,17 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp)
        if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
            intel_dp->downstream_ports[0] & DP_DS_PORT_HPD) {
                uint8_t reg;
-               if (!intel_dp_aux_native_read_retry(intel_dp, DP_SINK_COUNT,
-                                                   &reg, 1))
+
+               if (intel_dp_dpcd_read_wake(&intel_dp->aux, DP_SINK_COUNT,
+                                           &reg, 1) < 0)
                        return connector_status_unknown;
+
                return DP_GET_SINK_COUNT(reg) ? connector_status_connected
                                              : connector_status_disconnected;
        }
 
        /* If no HPD, poke DDC gently */
-       if (drm_probe_ddc(&intel_dp->adapter))
+       if (drm_probe_ddc(&intel_dp->aux.ddc))
                return connector_status_connected;
 
        /* Well we tried, say unknown for unreliable port types */
@@ -3106,10 +3118,14 @@ intel_dp_detect(struct drm_connector *connector, bool force)
        struct drm_device *dev = connector->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum drm_connector_status status;
+       enum intel_display_power_domain power_domain;
        struct edid *edid = NULL;
 
        intel_runtime_pm_get(dev_priv);
 
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, drm_get_connector_name(connector));
 
@@ -3128,7 +3144,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
        if (intel_dp->force_audio != HDMI_AUDIO_AUTO) {
                intel_dp->has_audio = (intel_dp->force_audio == HDMI_AUDIO_ON);
        } else {
-               edid = intel_dp_get_edid(connector, &intel_dp->adapter);
+               edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
                if (edid) {
                        intel_dp->has_audio = drm_detect_monitor_audio(edid);
                        kfree(edid);
@@ -3140,21 +3156,32 @@ intel_dp_detect(struct drm_connector *connector, bool force)
        status = connector_status_connected;
 
 out:
+       intel_display_power_put(dev_priv, power_domain);
+
        intel_runtime_pm_put(dev_priv);
+
        return status;
 }
 
 static int intel_dp_get_modes(struct drm_connector *connector)
 {
        struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct intel_connector *intel_connector = to_intel_connector(connector);
        struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
        int ret;
 
        /* We should parse the EDID data and find out if it has an audio sink
         */
 
-       ret = intel_dp_get_edid_modes(connector, &intel_dp->adapter);
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
+       ret = intel_dp_get_edid_modes(connector, &intel_dp->aux.ddc);
+       intel_display_power_put(dev_priv, power_domain);
        if (ret)
                return ret;
 
@@ -3175,15 +3202,25 @@ static bool
 intel_dp_detect_audio(struct drm_connector *connector)
 {
        struct intel_dp *intel_dp = intel_attached_dp(connector);
+       struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+       struct intel_encoder *intel_encoder = &intel_dig_port->base;
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum intel_display_power_domain power_domain;
        struct edid *edid;
        bool has_audio = false;
 
-       edid = intel_dp_get_edid(connector, &intel_dp->adapter);
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
+       edid = intel_dp_get_edid(connector, &intel_dp->aux.ddc);
        if (edid) {
                has_audio = drm_detect_monitor_audio(edid);
                kfree(edid);
        }
 
+       intel_display_power_put(dev_priv, power_domain);
+
        return has_audio;
 }
 
@@ -3298,12 +3335,12 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
        struct intel_dp *intel_dp = &intel_dig_port->dp;
        struct drm_device *dev = intel_dp_to_dev(intel_dp);
 
-       i2c_del_adapter(&intel_dp->adapter);
+       drm_dp_aux_unregister_i2c_bus(&intel_dp->aux);
        drm_encoder_cleanup(encoder);
        if (is_edp(intel_dp)) {
                cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
                mutex_lock(&dev->mode_config.mutex);
-               ironlake_panel_vdd_off_sync(intel_dp);
+               edp_panel_vdd_off_sync(intel_dp);
                mutex_unlock(&dev->mode_config.mutex);
        }
        kfree(intel_dig_port);
@@ -3402,6 +3439,13 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
        }
 }
 
+static void intel_dp_init_panel_power_timestamps(struct intel_dp *intel_dp)
+{
+       intel_dp->last_power_cycle = jiffies;
+       intel_dp->last_power_on = jiffies;
+       intel_dp->last_backlight_off = jiffies;
+}
+
 static void
 intel_dp_init_panel_power_sequencer(struct drm_device *dev,
                                    struct intel_dp *intel_dp,
@@ -3524,10 +3568,17 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
                pp_div_reg = VLV_PIPE_PP_DIVISOR(pipe);
        }
 
-       /* And finally store the new values in the power sequencer. */
+       /*
+        * And finally store the new values in the power sequencer. The
+        * backlight delays are set to 1 because we do manual waits on them. For
+        * T8, even BSpec recommends doing it. For T9, if we don't do this,
+        * we'll end up waiting for the backlight off delay twice: once when we
+        * do the manual sleep, and once when we disable the panel and wait for
+        * the PP_STATUS bit to become zero.
+        */
        pp_on = (seq->t1_t3 << PANEL_POWER_UP_DELAY_SHIFT) |
-               (seq->t8 << PANEL_LIGHT_ON_DELAY_SHIFT);
-       pp_off = (seq->t9 << PANEL_LIGHT_OFF_DELAY_SHIFT) |
+               (1 << PANEL_LIGHT_ON_DELAY_SHIFT);
+       pp_off = (1 << PANEL_LIGHT_OFF_DELAY_SHIFT) |
                 (seq->t10 << PANEL_POWER_DOWN_DELAY_SHIFT);
        /* Compute the divisor for the pp clock, simply match the Bspec
         * formula. */
@@ -3562,14 +3613,14 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
 }
 
 static bool intel_edp_init_connector(struct intel_dp *intel_dp,
-                                    struct intel_connector *intel_connector)
+                                    struct intel_connector *intel_connector,
+                                    struct edp_power_seq *power_seq)
 {
        struct drm_connector *connector = &intel_connector->base;
        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;
        struct drm_display_mode *fixed_mode = NULL;
-       struct edp_power_seq power_seq = { 0 };
        bool has_dpcd;
        struct drm_display_mode *scan;
        struct edid *edid;
@@ -3577,12 +3628,10 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        if (!is_edp(intel_dp))
                return true;
 
-       intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
-
        /* Cache DPCD and EDID for edp. */
-       ironlake_edp_panel_vdd_on(intel_dp);
+       intel_edp_panel_vdd_on(intel_dp);
        has_dpcd = intel_dp_get_dpcd(intel_dp);
-       ironlake_edp_panel_vdd_off(intel_dp, false);
+       edp_panel_vdd_off(intel_dp, false);
 
        if (has_dpcd) {
                if (intel_dp->dpcd[DP_DPCD_REV] >= 0x11)
@@ -3596,10 +3645,10 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
        }
 
        /* We now know it's not a ghost, init power sequence regs. */
-       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp,
-                                                     &power_seq);
+       intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, power_seq);
 
-       edid = drm_get_edid(connector, &intel_dp->adapter);
+       mutex_lock(&dev->mode_config.mutex);
+       edid = drm_get_edid(connector, &intel_dp->aux.ddc);
        if (edid) {
                if (drm_add_edid_modes(connector, edid)) {
                        drm_mode_connector_update_edid_property(connector,
@@ -3629,8 +3678,9 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
                if (fixed_mode)
                        fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
        }
+       mutex_unlock(&dev->mode_config.mutex);
 
-       intel_panel_init(&intel_connector->panel, fixed_mode);
+       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
        intel_panel_setup_backlight(connector);
 
        return true;
@@ -3646,8 +3696,20 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        struct drm_device *dev = intel_encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        enum port port = intel_dig_port->port;
-       const char *name = NULL;
-       int type, error;
+       struct edp_power_seq power_seq = { 0 };
+       int type;
+
+       /* intel_dp vfuncs */
+       if (IS_VALLEYVIEW(dev))
+               intel_dp->get_aux_clock_divider = vlv_get_aux_clock_divider;
+       else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               intel_dp->get_aux_clock_divider = hsw_get_aux_clock_divider;
+       else if (HAS_PCH_SPLIT(dev))
+               intel_dp->get_aux_clock_divider = ilk_get_aux_clock_divider;
+       else
+               intel_dp->get_aux_clock_divider = i9xx_get_aux_clock_divider;
+
+       intel_dp->get_aux_send_ctl = i9xx_get_aux_send_ctl;
 
        /* Preserve the current hw state. */
        intel_dp->DP = I915_READ(intel_dp->output_reg);
@@ -3677,7 +3739,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
        connector->doublescan_allowed = 0;
 
        INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
-                         ironlake_panel_vdd_work);
+                         edp_panel_vdd_work);
 
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        drm_sysfs_connector_add(connector);
@@ -3686,61 +3748,41 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
                intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
        else
                intel_connector->get_hw_state = intel_connector_get_hw_state;
+       intel_connector->unregister = intel_dp_connector_unregister;
 
-       intel_dp->aux_ch_ctl_reg = intel_dp->output_reg + 0x10;
-       if (HAS_DDI(dev)) {
-               switch (intel_dig_port->port) {
-               case PORT_A:
-                       intel_dp->aux_ch_ctl_reg = DPA_AUX_CH_CTL;
-                       break;
-               case PORT_B:
-                       intel_dp->aux_ch_ctl_reg = PCH_DPB_AUX_CH_CTL;
-                       break;
-               case PORT_C:
-                       intel_dp->aux_ch_ctl_reg = PCH_DPC_AUX_CH_CTL;
-                       break;
-               case PORT_D:
-                       intel_dp->aux_ch_ctl_reg = PCH_DPD_AUX_CH_CTL;
-                       break;
-               default:
-                       BUG();
-               }
-       }
-
-       /* Set up the DDC bus. */
+       /* Set up the hotplug pin. */
        switch (port) {
        case PORT_A:
                intel_encoder->hpd_pin = HPD_PORT_A;
-               name = "DPDDC-A";
                break;
        case PORT_B:
                intel_encoder->hpd_pin = HPD_PORT_B;
-               name = "DPDDC-B";
                break;
        case PORT_C:
                intel_encoder->hpd_pin = HPD_PORT_C;
-               name = "DPDDC-C";
                break;
        case PORT_D:
                intel_encoder->hpd_pin = HPD_PORT_D;
-               name = "DPDDC-D";
                break;
        default:
                BUG();
        }
 
-       error = intel_dp_i2c_init(intel_dp, intel_connector, name);
-       WARN(error, "intel_dp_i2c_init failed with error %d for port %c\n",
-            error, port_name(port));
+       if (is_edp(intel_dp)) {
+               intel_dp_init_panel_power_timestamps(intel_dp);
+               intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq);
+       }
+
+       intel_dp_aux_init(intel_dp, intel_connector);
 
        intel_dp->psr_setup_done = false;
 
-       if (!intel_edp_init_connector(intel_dp, intel_connector)) {
-               i2c_del_adapter(&intel_dp->adapter);
+       if (!intel_edp_init_connector(intel_dp, intel_connector, &power_seq)) {
+               drm_dp_aux_unregister_i2c_bus(&intel_dp->aux);
                if (is_edp(intel_dp)) {
                        cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
                        mutex_lock(&dev->mode_config.mutex);
-                       ironlake_panel_vdd_off_sync(intel_dp);
+                       edp_panel_vdd_off_sync(intel_dp);
                        mutex_unlock(&dev->mode_config.mutex);
                }
                drm_sysfs_connector_remove(connector);
@@ -3806,7 +3848,7 @@ intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
 
        intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        intel_encoder->hot_plug = intel_dp_hot_plug;
 
        if (!intel_dp_init_connector(intel_dig_port, intel_connector)) {
index fbfaaba..0542de9 100644 (file)
 #define MAX_OUTPUTS 6
 /* maximum connectors per crtcs in the mode set */
 
+/* Maximum cursor sizes */
+#define GEN2_CURSOR_WIDTH 64
+#define GEN2_CURSOR_HEIGHT 64
+#define CURSOR_WIDTH 256
+#define CURSOR_HEIGHT 256
+
 #define INTEL_I2C_BUS_DVO 1
 #define INTEL_I2C_BUS_SDVO 2
 
@@ -110,9 +116,10 @@ struct intel_framebuffer {
 
 struct intel_fbdev {
        struct drm_fb_helper helper;
-       struct intel_framebuffer ifb;
+       struct intel_framebuffer *fb;
        struct list_head fbdev_list;
        struct drm_display_mode *our_mode;
+       int preferred_bpp;
 };
 
 struct intel_encoder {
@@ -124,11 +131,7 @@ struct intel_encoder {
        struct intel_crtc *new_crtc;
 
        int type;
-       /*
-        * Intel hw has only one MUX where encoders could be clone, hence a
-        * simple flag is enough to compute the possible_clones mask.
-        */
-       bool cloneable;
+       unsigned int cloneable;
        bool connectors_active;
        void (*hot_plug)(struct intel_encoder *);
        bool (*compute_config)(struct intel_encoder *,
@@ -187,6 +190,14 @@ struct intel_connector {
         * and active (i.e. dpms ON state). */
        bool (*get_hw_state)(struct intel_connector *);
 
+       /*
+        * Removes all interfaces through which the connector is accessible
+        * - like sysfs, debugfs entries -, so that no new operations can be
+        * started on the connector. Also makes sure all currently pending
+        * operations finish before returing.
+        */
+       void (*unregister)(struct intel_connector *);
+
        /* Panel info for eDP and LVDS */
        struct intel_panel panel;
 
@@ -210,6 +221,12 @@ typedef struct dpll {
        int     p;
 } intel_clock_t;
 
+struct intel_plane_config {
+       bool tiled;
+       int size;
+       u32 base;
+};
+
 struct intel_crtc_config {
        /**
         * quirks - bitfield with hw state readout quirks
@@ -356,9 +373,13 @@ struct intel_crtc {
        uint32_t cursor_addr;
        int16_t cursor_x, cursor_y;
        int16_t cursor_width, cursor_height;
+       int16_t max_cursor_width, max_cursor_height;
        bool cursor_visible;
 
+       struct intel_plane_config plane_config;
        struct intel_crtc_config config;
+       struct intel_crtc_config *new_config;
+       bool new_enabled;
 
        uint32_t ddi_pll_sel;
 
@@ -475,8 +496,7 @@ struct intel_dp {
        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;
+       struct drm_dp_aux aux;
        uint8_t train_set[4];
        int panel_power_up_delay;
        int panel_power_down_delay;
@@ -485,8 +505,22 @@ struct intel_dp {
        int backlight_off_delay;
        struct delayed_work panel_vdd_work;
        bool want_panel_vdd;
+       unsigned long last_power_cycle;
+       unsigned long last_power_on;
+       unsigned long last_backlight_off;
        bool psr_setup_done;
+       bool use_tps3;
        struct intel_connector *attached_connector;
+
+       uint32_t (*get_aux_clock_divider)(struct intel_dp *dp, int index);
+       /*
+        * This function returns the value we have to program the AUX_CTL
+        * register with to kick off an AUX transaction.
+        */
+       uint32_t (*get_aux_send_ctl)(struct intel_dp *dp,
+                                    bool has_aux_irq,
+                                    int send_bytes,
+                                    uint32_t aux_clock_divider);
 };
 
 struct intel_digital_port {
@@ -540,6 +574,7 @@ struct intel_unpin_work {
 struct intel_set_config {
        struct drm_encoder **save_connector_encoders;
        struct drm_crtc **save_encoder_crtcs;
+       bool *save_crtc_enabled;
 
        bool fb_changed;
        bool mode_changed;
@@ -584,6 +619,8 @@ hdmi_to_dig_port(struct intel_hdmi *intel_hdmi)
 /* i915_irq.c */
 bool intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
                                           enum pipe pipe, bool enable);
+bool __intel_set_cpu_fifo_underrun_reporting(struct drm_device *dev,
+                                            enum pipe pipe, bool enable);
 bool intel_set_pch_fifo_underrun_reporting(struct drm_device *dev,
                                           enum transcoder pch_transcoder,
                                           bool enable);
@@ -591,8 +628,8 @@ void ilk_enable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void ilk_disable_gt_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void snb_enable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
 void snb_disable_pm_irq(struct drm_i915_private *dev_priv, uint32_t mask);
-void hsw_pc8_disable_interrupts(struct drm_device *dev);
-void hsw_pc8_restore_interrupts(struct drm_device *dev);
+void hsw_runtime_pm_disable_interrupts(struct drm_device *dev);
+void hsw_runtime_pm_restore_interrupts(struct drm_device *dev);
 
 
 /* intel_crt.c */
@@ -664,11 +701,10 @@ int intel_pin_and_fence_fb_obj(struct drm_device *dev,
                               struct drm_i915_gem_object *obj,
                               struct intel_ring_buffer *pipelined);
 void intel_unpin_fb_obj(struct drm_i915_gem_object *obj);
-int intel_framebuffer_init(struct drm_device *dev,
-                          struct intel_framebuffer *ifb,
+struct drm_framebuffer *
+__intel_framebuffer_create(struct drm_device *dev,
                           struct drm_mode_fb_cmd2 *mode_cmd,
                           struct drm_i915_gem_object *obj);
-void intel_framebuffer_fini(struct intel_framebuffer *fb);
 void intel_prepare_page_flip(struct drm_device *dev, int plane);
 void intel_finish_page_flip(struct drm_device *dev, int pipe);
 void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
@@ -696,9 +732,8 @@ unsigned long intel_gen4_compute_page_offset(int *x, int *y,
                                             unsigned int bpp,
                                             unsigned int pitch);
 void intel_display_handle_reset(struct drm_device *dev);
-void hsw_enable_pc8_work(struct work_struct *__work);
-void hsw_enable_package_c8(struct drm_i915_private *dev_priv);
-void hsw_disable_package_c8(struct drm_i915_private *dev_priv);
+void hsw_enable_pc8(struct drm_i915_private *dev_priv);
+void hsw_disable_pc8(struct drm_i915_private *dev_priv);
 void intel_dp_get_m_n(struct intel_crtc *crtc,
                      struct intel_crtc_config *pipe_config);
 int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
@@ -708,8 +743,13 @@ ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
 bool intel_crtc_active(struct drm_crtc *crtc);
 void hsw_enable_ips(struct intel_crtc *crtc);
 void hsw_disable_ips(struct intel_crtc *crtc);
-void intel_display_set_init_power(struct drm_device *dev, bool enable);
+void intel_display_set_init_power(struct drm_i915_private *dev, bool enable);
+enum intel_display_power_domain
+intel_display_port_power_domain(struct intel_encoder *intel_encoder);
 int valleyview_get_vco(struct drm_i915_private *dev_priv);
+void intel_mode_from_pipe_config(struct drm_display_mode *mode,
+                                struct intel_crtc_config *pipe_config);
+int intel_format_to_fourcc(int format);
 
 /* intel_dp.c */
 void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
@@ -721,15 +761,15 @@ void intel_dp_stop_link_train(struct intel_dp *intel_dp);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
 void intel_dp_encoder_destroy(struct drm_encoder *encoder);
 void intel_dp_check_link_status(struct intel_dp *intel_dp);
+int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc);
 bool intel_dp_compute_config(struct intel_encoder *encoder,
                             struct intel_crtc_config *pipe_config);
 bool intel_dp_is_edp(struct drm_device *dev, enum port port);
-void ironlake_edp_backlight_on(struct intel_dp *intel_dp);
-void ironlake_edp_backlight_off(struct intel_dp *intel_dp);
-void ironlake_edp_panel_on(struct intel_dp *intel_dp);
-void ironlake_edp_panel_off(struct intel_dp *intel_dp);
-void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp);
-void ironlake_edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync);
+void intel_edp_backlight_on(struct intel_dp *intel_dp);
+void intel_edp_backlight_off(struct intel_dp *intel_dp);
+void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
+void intel_edp_panel_on(struct intel_dp *intel_dp);
+void intel_edp_panel_off(struct intel_dp *intel_dp);
 void intel_edp_psr_enable(struct intel_dp *intel_dp);
 void intel_edp_psr_disable(struct intel_dp *intel_dp);
 void intel_edp_psr_update(struct drm_device *dev);
@@ -808,7 +848,8 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
 
 /* intel_panel.c */
 int intel_panel_init(struct intel_panel *panel,
-                    struct drm_display_mode *fixed_mode);
+                    struct drm_display_mode *fixed_mode,
+                    struct drm_display_mode *downclock_mode);
 void intel_panel_fini(struct intel_panel *panel);
 void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
                            struct drm_display_mode *adjusted_mode);
@@ -845,18 +886,19 @@ bool intel_fbc_enabled(struct drm_device *dev);
 void intel_update_fbc(struct drm_device *dev);
 void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
 void intel_gpu_ips_teardown(void);
-int intel_power_domains_init(struct drm_device *dev);
-void intel_power_domains_remove(struct drm_device *dev);
-bool intel_display_power_enabled(struct drm_device *dev,
+int intel_power_domains_init(struct drm_i915_private *);
+void intel_power_domains_remove(struct drm_i915_private *);
+bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
                                 enum intel_display_power_domain domain);
-bool intel_display_power_enabled_sw(struct drm_device *dev,
+bool intel_display_power_enabled_sw(struct drm_i915_private *dev_priv,
                                    enum intel_display_power_domain domain);
-void intel_display_power_get(struct drm_device *dev,
+void intel_display_power_get(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain);
-void intel_display_power_put(struct drm_device *dev,
+void intel_display_power_put(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain);
-void intel_power_domains_init_hw(struct drm_device *dev);
-void intel_set_power_well(struct drm_device *dev, bool enable);
+void intel_power_domains_init_hw(struct drm_i915_private *dev_priv);
+void intel_init_gt_powersave(struct drm_device *dev);
+void intel_cleanup_gt_powersave(struct drm_device *dev);
 void intel_enable_gt_powersave(struct drm_device *dev);
 void intel_disable_gt_powersave(struct drm_device *dev);
 void ironlake_teardown_rc6(struct drm_device *dev);
index fabbf0d..3365664 100644 (file)
@@ -243,11 +243,16 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
                                   enum pipe *pipe)
 {
        struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       enum intel_display_power_domain power_domain;
        u32 port, func;
        enum pipe p;
 
        DRM_DEBUG_KMS("\n");
 
+       power_domain = intel_display_port_power_domain(encoder);
+       if (!intel_display_power_enabled(dev_priv, power_domain))
+               return false;
+
        /* XXX: this only works for one DSI output */
        for (p = PIPE_A; p <= PIPE_B; p++) {
                port = I915_READ(MIPI_PORT_CTRL(p));
@@ -488,8 +493,19 @@ static enum drm_connector_status
 intel_dsi_detect(struct drm_connector *connector, bool force)
 {
        struct intel_dsi *intel_dsi = intel_attached_dsi(connector);
+       struct intel_encoder *intel_encoder = &intel_dsi->base;
+       enum intel_display_power_domain power_domain;
+       enum drm_connector_status connector_status;
+       struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
+
        DRM_DEBUG_KMS("\n");
-       return intel_dsi->dev.dev_ops->detect(&intel_dsi->dev);
+       power_domain = intel_display_port_power_domain(intel_encoder);
+
+       intel_display_power_get(dev_priv, power_domain);
+       connector_status = intel_dsi->dev.dev_ops->detect(&intel_dsi->dev);
+       intel_display_power_put(dev_priv, power_domain);
+
+       return connector_status;
 }
 
 static int intel_dsi_get_modes(struct drm_connector *connector)
@@ -586,6 +602,7 @@ bool intel_dsi_init(struct drm_device *dev)
        intel_encoder->get_config = intel_dsi_get_config;
 
        intel_connector->get_hw_state = intel_connector_get_hw_state;
+       intel_connector->unregister = intel_connector_unregister;
 
        for (i = 0; i < ARRAY_SIZE(intel_dsi_devices); i++) {
                dsi = &intel_dsi_devices[i];
@@ -603,7 +620,7 @@ bool intel_dsi_init(struct drm_device *dev)
        intel_encoder->type = INTEL_OUTPUT_DSI;
        intel_encoder->crtc_mask = (1 << 0); /* XXX */
 
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
                           DRM_MODE_CONNECTOR_DSI);
 
@@ -624,7 +641,7 @@ bool intel_dsi_init(struct drm_device *dev)
        }
 
        fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
-       intel_panel_init(&intel_connector->panel, fixed_mode);
+       intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
 
        return true;
 
index eeff998..7fe3fee 100644 (file)
@@ -477,6 +477,7 @@ void intel_dvo_init(struct drm_device *dev)
        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;
+       intel_connector->unregister = intel_connector_unregister;
 
        /* Now, try to find a controller */
        for (i = 0; i < ARRAY_SIZE(intel_dvo_devices); i++) {
@@ -521,14 +522,15 @@ void intel_dvo_init(struct drm_device *dev)
                intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
                switch (dvo->type) {
                case INTEL_DVO_CHIP_TMDS:
-                       intel_encoder->cloneable = true;
+                       intel_encoder->cloneable = (1 << INTEL_OUTPUT_ANALOG) |
+                               (1 << INTEL_OUTPUT_DVO);
                        drm_connector_init(dev, connector,
                                           &intel_dvo_connector_funcs,
                                           DRM_MODE_CONNECTOR_DVII);
                        encoder_type = DRM_MODE_ENCODER_TMDS;
                        break;
                case INTEL_DVO_CHIP_LVDS:
-                       intel_encoder->cloneable = false;
+                       intel_encoder->cloneable = 0;
                        drm_connector_init(dev, connector,
                                           &intel_dvo_connector_funcs,
                                           DRM_MODE_CONNECTOR_LVDS);
index 39eac99..b4d44e6 100644 (file)
@@ -62,6 +62,7 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
 {
        struct intel_fbdev *ifbdev =
                container_of(helper, struct intel_fbdev, helper);
+       struct drm_framebuffer *fb;
        struct drm_device *dev = helper->dev;
        struct drm_mode_fb_cmd2 mode_cmd = {};
        struct drm_i915_gem_object *obj;
@@ -93,18 +94,22 @@ static int intelfb_alloc(struct drm_fb_helper *helper,
        /* Flush everything out, we'll be doing GTT only from now on */
        ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
        if (ret) {
-               DRM_ERROR("failed to pin fb: %d\n", ret);
+               DRM_ERROR("failed to pin obj: %d\n", ret);
                goto out_unref;
        }
 
-       ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
-       if (ret)
+       fb = __intel_framebuffer_create(dev, &mode_cmd, obj);
+       if (IS_ERR(fb)) {
+               ret = PTR_ERR(fb);
                goto out_unpin;
+       }
+
+       ifbdev->fb = to_intel_framebuffer(fb);
 
        return 0;
 
 out_unpin:
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
 out_unref:
        drm_gem_object_unreference(&obj->base);
 out:
@@ -116,23 +121,26 @@ static int intelfb_create(struct drm_fb_helper *helper,
 {
        struct intel_fbdev *ifbdev =
                container_of(helper, struct intel_fbdev, helper);
-       struct intel_framebuffer *intel_fb = &ifbdev->ifb;
+       struct intel_framebuffer *intel_fb = ifbdev->fb;
        struct drm_device *dev = helper->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct fb_info *info;
        struct drm_framebuffer *fb;
        struct drm_i915_gem_object *obj;
        int size, ret;
+       bool prealloc = false;
 
        mutex_lock(&dev->struct_mutex);
 
-       if (!intel_fb->obj) {
+       if (!intel_fb || WARN_ON(!intel_fb->obj)) {
                DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
                ret = intelfb_alloc(helper, sizes);
                if (ret)
                        goto out_unlock;
+               intel_fb = ifbdev->fb;
        } else {
                DRM_DEBUG_KMS("re-using BIOS fb\n");
+               prealloc = true;
                sizes->fb_width = intel_fb->base.width;
                sizes->fb_height = intel_fb->base.height;
        }
@@ -148,7 +156,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
 
        info->par = helper;
 
-       fb = &ifbdev->ifb.base;
+       fb = &ifbdev->fb->base;
 
        ifbdev->helper.fb = fb;
        ifbdev->helper.fbdev = info;
@@ -194,7 +202,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
         * If the object is stolen however, it will be full of whatever
         * garbage was left in there.
         */
-       if (ifbdev->ifb.obj->stolen)
+       if (ifbdev->fb->obj->stolen && !prealloc)
                memset_io(info->screen_base, 0, info->screen_size);
 
        /* Use default scratch pixmap (info->pixmap.flags = FB_PIXMAP_SYSTEM) */
@@ -208,7 +216,7 @@ static int intelfb_create(struct drm_fb_helper *helper,
        return 0;
 
 out_unpin:
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
        drm_gem_object_unreference(&obj->base);
 out_unlock:
        mutex_unlock(&dev->struct_mutex);
@@ -236,7 +244,193 @@ static void intel_crtc_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
        *blue = intel_crtc->lut_b[regno] << 8;
 }
 
+static struct drm_fb_helper_crtc *
+intel_fb_helper_crtc(struct drm_fb_helper *fb_helper, struct drm_crtc *crtc)
+{
+       int i;
+
+       for (i = 0; i < fb_helper->crtc_count; i++)
+               if (fb_helper->crtc_info[i].mode_set.crtc == crtc)
+                       return &fb_helper->crtc_info[i];
+
+       return NULL;
+}
+
+/*
+ * Try to read the BIOS display configuration and use it for the initial
+ * fb configuration.
+ *
+ * The BIOS or boot loader will generally create an initial display
+ * configuration for us that includes some set of active pipes and displays.
+ * This routine tries to figure out which pipes and connectors are active
+ * and stuffs them into the crtcs and modes array given to us by the
+ * drm_fb_helper code.
+ *
+ * The overall sequence is:
+ *   intel_fbdev_init - from driver load
+ *     intel_fbdev_init_bios - initialize the intel_fbdev using BIOS data
+ *     drm_fb_helper_init - build fb helper structs
+ *     drm_fb_helper_single_add_all_connectors - more fb helper structs
+ *   intel_fbdev_initial_config - apply the config
+ *     drm_fb_helper_initial_config - call ->probe then register_framebuffer()
+ *         drm_setup_crtcs - build crtc config for fbdev
+ *           intel_fb_initial_config - find active connectors etc
+ *         drm_fb_helper_single_fb_probe - set up fbdev
+ *           intelfb_create - re-use or alloc fb, build out fbdev structs
+ *
+ * Note that we don't make special consideration whether we could actually
+ * switch to the selected modes without a full modeset. E.g. when the display
+ * is in VGA mode we need to recalculate watermarks and set a new high-res
+ * framebuffer anyway.
+ */
+static bool intel_fb_initial_config(struct drm_fb_helper *fb_helper,
+                                   struct drm_fb_helper_crtc **crtcs,
+                                   struct drm_display_mode **modes,
+                                   bool *enabled, int width, int height)
+{
+       struct drm_device *dev = fb_helper->dev;
+       int i, j;
+       bool *save_enabled;
+       bool fallback = true;
+       int num_connectors_enabled = 0;
+       int num_connectors_detected = 0;
+
+       /*
+        * If the user specified any force options, just bail here
+        * and use that config.
+        */
+       for (i = 0; i < fb_helper->connector_count; i++) {
+               struct drm_fb_helper_connector *fb_conn;
+               struct drm_connector *connector;
+
+               fb_conn = fb_helper->connector_info[i];
+               connector = fb_conn->connector;
+
+               if (!enabled[i])
+                       continue;
+
+               if (connector->force != DRM_FORCE_UNSPECIFIED)
+                       return false;
+       }
+
+       save_enabled = kcalloc(dev->mode_config.num_connector, sizeof(bool),
+                              GFP_KERNEL);
+       if (!save_enabled)
+               return false;
+
+       memcpy(save_enabled, enabled, dev->mode_config.num_connector);
+
+       for (i = 0; i < fb_helper->connector_count; i++) {
+               struct drm_fb_helper_connector *fb_conn;
+               struct drm_connector *connector;
+               struct drm_encoder *encoder;
+               struct drm_fb_helper_crtc *new_crtc;
+
+               fb_conn = fb_helper->connector_info[i];
+               connector = fb_conn->connector;
+
+               if (connector->status == connector_status_connected)
+                       num_connectors_detected++;
+
+               if (!enabled[i]) {
+                       DRM_DEBUG_KMS("connector %d not enabled, skipping\n",
+                                     connector->base.id);
+                       continue;
+               }
+
+               encoder = connector->encoder;
+               if (!encoder || WARN_ON(!encoder->crtc)) {
+                       DRM_DEBUG_KMS("connector %d has no encoder or crtc, skipping\n",
+                                     connector->base.id);
+                       enabled[i] = false;
+                       continue;
+               }
+
+               num_connectors_enabled++;
+
+               new_crtc = intel_fb_helper_crtc(fb_helper, encoder->crtc);
+
+               /*
+                * Make sure we're not trying to drive multiple connectors
+                * with a single CRTC, since our cloning support may not
+                * match the BIOS.
+                */
+               for (j = 0; j < fb_helper->connector_count; j++) {
+                       if (crtcs[j] == new_crtc) {
+                               DRM_DEBUG_KMS("fallback: cloned configuration\n");
+                               fallback = true;
+                               goto out;
+                       }
+               }
+
+               DRM_DEBUG_KMS("looking for cmdline mode on connector %d\n",
+                             fb_conn->connector->base.id);
+
+               /* go for command line mode first */
+               modes[i] = drm_pick_cmdline_mode(fb_conn, width, height);
+
+               /* try for preferred next */
+               if (!modes[i]) {
+                       DRM_DEBUG_KMS("looking for preferred mode on connector %d\n",
+                                     fb_conn->connector->base.id);
+                       modes[i] = drm_has_preferred_mode(fb_conn, width,
+                                                         height);
+               }
+
+               /* last resort: use current mode */
+               if (!modes[i]) {
+                       /*
+                        * IMPORTANT: We want to use the adjusted mode (i.e.
+                        * after the panel fitter upscaling) as the initial
+                        * config, not the input mode, which is what crtc->mode
+                        * usually contains. But since our current fastboot
+                        * code puts a mode derived from the post-pfit timings
+                        * into crtc->mode this works out correctly. We don't
+                        * use hwmode anywhere right now, so use it for this
+                        * since the fb helper layer wants a pointer to
+                        * something we own.
+                        */
+                       intel_mode_from_pipe_config(&encoder->crtc->hwmode,
+                                                   &to_intel_crtc(encoder->crtc)->config);
+                       modes[i] = &encoder->crtc->hwmode;
+               }
+               crtcs[i] = new_crtc;
+
+               DRM_DEBUG_KMS("connector %s on crtc %d: %s\n",
+                             drm_get_connector_name(connector),
+                             encoder->crtc->base.id,
+                             modes[i]->name);
+
+               fallback = false;
+       }
+
+       /*
+        * If the BIOS didn't enable everything it could, fall back to have the
+        * same user experiencing of lighting up as much as possible like the
+        * fbdev helper library.
+        */
+       if (num_connectors_enabled != num_connectors_detected &&
+           num_connectors_enabled < INTEL_INFO(dev)->num_pipes) {
+               DRM_DEBUG_KMS("fallback: Not all outputs enabled\n");
+               DRM_DEBUG_KMS("Enabled: %i, detected: %i\n", num_connectors_enabled,
+                             num_connectors_detected);
+               fallback = true;
+       }
+
+out:
+       if (fallback) {
+               DRM_DEBUG_KMS("Not using firmware configuration\n");
+               memcpy(enabled, save_enabled, dev->mode_config.num_connector);
+               kfree(save_enabled);
+               return false;
+       }
+
+       kfree(save_enabled);
+       return true;
+}
+
 static struct drm_fb_helper_funcs intel_fb_helper_funcs = {
+       .initial_config = intel_fb_initial_config,
        .gamma_set = intel_crtc_fb_gamma_set,
        .gamma_get = intel_crtc_fb_gamma_get,
        .fb_probe = intelfb_create,
@@ -258,8 +452,139 @@ static void intel_fbdev_destroy(struct drm_device *dev,
 
        drm_fb_helper_fini(&ifbdev->helper);
 
-       drm_framebuffer_unregister_private(&ifbdev->ifb.base);
-       intel_framebuffer_fini(&ifbdev->ifb);
+       drm_framebuffer_unregister_private(&ifbdev->fb->base);
+       drm_framebuffer_remove(&ifbdev->fb->base);
+}
+
+/*
+ * Build an intel_fbdev struct using a BIOS allocated framebuffer, if possible.
+ * The core display code will have read out the current plane configuration,
+ * so we use that to figure out if there's an object for us to use as the
+ * fb, and if so, we re-use it for the fbdev configuration.
+ *
+ * Note we only support a single fb shared across pipes for boot (mostly for
+ * fbcon), so we just find the biggest and use that.
+ */
+static bool intel_fbdev_init_bios(struct drm_device *dev,
+                                struct intel_fbdev *ifbdev)
+{
+       struct intel_framebuffer *fb = NULL;
+       struct drm_crtc *crtc;
+       struct intel_crtc *intel_crtc;
+       struct intel_plane_config *plane_config = NULL;
+       unsigned int max_size = 0;
+
+       if (!i915.fastboot)
+               return false;
+
+       /* Find the largest fb */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               intel_crtc = to_intel_crtc(crtc);
+
+               if (!intel_crtc->active || !crtc->primary->fb) {
+                       DRM_DEBUG_KMS("pipe %c not active or no fb, skipping\n",
+                                     pipe_name(intel_crtc->pipe));
+                       continue;
+               }
+
+               if (intel_crtc->plane_config.size > max_size) {
+                       DRM_DEBUG_KMS("found possible fb from plane %c\n",
+                                     pipe_name(intel_crtc->pipe));
+                       plane_config = &intel_crtc->plane_config;
+                       fb = to_intel_framebuffer(crtc->primary->fb);
+                       max_size = plane_config->size;
+               }
+       }
+
+       if (!fb) {
+               DRM_DEBUG_KMS("no active fbs found, not using BIOS config\n");
+               goto out;
+       }
+
+       /* Now make sure all the pipes will fit into it */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               unsigned int cur_size;
+
+               intel_crtc = to_intel_crtc(crtc);
+
+               if (!intel_crtc->active) {
+                       DRM_DEBUG_KMS("pipe %c not active, skipping\n",
+                                     pipe_name(intel_crtc->pipe));
+                       continue;
+               }
+
+               DRM_DEBUG_KMS("checking plane %c for BIOS fb\n",
+                             pipe_name(intel_crtc->pipe));
+
+               /*
+                * See if the plane fb we found above will fit on this
+                * pipe.  Note we need to use the selected fb's pitch and bpp
+                * rather than the current pipe's, since they differ.
+                */
+               cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay;
+               cur_size = cur_size * fb->base.bits_per_pixel / 8;
+               if (fb->base.pitches[0] < cur_size) {
+                       DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n",
+                                     pipe_name(intel_crtc->pipe),
+                                     cur_size, fb->base.pitches[0]);
+                       plane_config = NULL;
+                       fb = NULL;
+                       break;
+               }
+
+               cur_size = intel_crtc->config.adjusted_mode.crtc_vdisplay;
+               cur_size = ALIGN(cur_size, plane_config->tiled ? (IS_GEN2(dev) ? 16 : 8) : 1);
+               cur_size *= fb->base.pitches[0];
+               DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
+                             pipe_name(intel_crtc->pipe),
+                             intel_crtc->config.adjusted_mode.crtc_hdisplay,
+                             intel_crtc->config.adjusted_mode.crtc_vdisplay,
+                             fb->base.bits_per_pixel,
+                             cur_size);
+
+               if (cur_size > max_size) {
+                       DRM_DEBUG_KMS("fb not big enough for plane %c (%d vs %d)\n",
+                                     pipe_name(intel_crtc->pipe),
+                                     cur_size, max_size);
+                       plane_config = NULL;
+                       fb = NULL;
+                       break;
+               }
+
+               DRM_DEBUG_KMS("fb big enough for plane %c (%d >= %d)\n",
+                             pipe_name(intel_crtc->pipe),
+                             max_size, cur_size);
+       }
+
+       if (!fb) {
+               DRM_DEBUG_KMS("BIOS fb not suitable for all pipes, not using\n");
+               goto out;
+       }
+
+       ifbdev->preferred_bpp = fb->base.bits_per_pixel;
+       ifbdev->fb = fb;
+
+       drm_framebuffer_reference(&ifbdev->fb->base);
+
+       /* Final pass to check if any active pipes don't have fbs */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               intel_crtc = to_intel_crtc(crtc);
+
+               if (!intel_crtc->active)
+                       continue;
+
+               WARN(!crtc->primary->fb,
+                    "re-used BIOS config but lost an fb on crtc %d\n",
+                    crtc->base.id);
+       }
+
+
+       DRM_DEBUG_KMS("using BIOS fb for initial console\n");
+       return true;
+
+out:
+
+       return false;
 }
 
 int intel_fbdev_init(struct drm_device *dev)
@@ -268,21 +593,25 @@ int intel_fbdev_init(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       ifbdev = kzalloc(sizeof(*ifbdev), GFP_KERNEL);
-       if (!ifbdev)
+       if (WARN_ON(INTEL_INFO(dev)->num_pipes == 0))
+               return -ENODEV;
+
+       ifbdev = kzalloc(sizeof(struct intel_fbdev), GFP_KERNEL);
+       if (ifbdev == NULL)
                return -ENOMEM;
 
-       dev_priv->fbdev = ifbdev;
        ifbdev->helper.funcs = &intel_fb_helper_funcs;
+       if (!intel_fbdev_init_bios(dev, ifbdev))
+               ifbdev->preferred_bpp = 32;
 
        ret = drm_fb_helper_init(dev, &ifbdev->helper,
-                                INTEL_INFO(dev)->num_pipes,
-                                4);
+                                INTEL_INFO(dev)->num_pipes, 4);
        if (ret) {
                kfree(ifbdev);
                return ret;
        }
 
+       dev_priv->fbdev = ifbdev;
        drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
 
        return 0;
@@ -291,9 +620,10 @@ int intel_fbdev_init(struct drm_device *dev)
 void intel_fbdev_initial_config(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_fbdev *ifbdev = dev_priv->fbdev;
 
        /* Due to peculiar init order wrt to hpd handling this is separate. */
-       drm_fb_helper_initial_config(&dev_priv->fbdev->helper, 32);
+       drm_fb_helper_initial_config(&ifbdev->helper, ifbdev->preferred_bpp);
 }
 
 void intel_fbdev_fini(struct drm_device *dev)
@@ -322,7 +652,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
         * been restored from swap. If the object is stolen however, it will be
         * full of whatever garbage was left in there.
         */
-       if (state == FBINFO_STATE_RUNNING && ifbdev->ifb.obj->stolen)
+       if (state == FBINFO_STATE_RUNNING && ifbdev->fb->obj->stolen)
                memset_io(info->screen_base, 0, info->screen_size);
 
        fb_set_suspend(info, state);
@@ -331,7 +661,8 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
 void intel_fbdev_output_poll_changed(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
+       if (dev_priv->fbdev)
+               drm_fb_helper_hotplug_event(&dev_priv->fbdev->helper);
 }
 
 void intel_fbdev_restore_mode(struct drm_device *dev)
@@ -339,7 +670,7 @@ void intel_fbdev_restore_mode(struct drm_device *dev)
        int ret;
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (INTEL_INFO(dev)->num_pipes == 0)
+       if (!dev_priv->fbdev)
                return;
 
        drm_modeset_lock_all(dev);
index ee3181e..b0413e1 100644 (file)
@@ -113,7 +113,8 @@ static u32 hsw_infoframe_enable(enum hdmi_infoframe_type type)
 }
 
 static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type,
-                                 enum transcoder cpu_transcoder)
+                                 enum transcoder cpu_transcoder,
+                                 struct drm_i915_private *dev_priv)
 {
        switch (type) {
        case HDMI_INFOFRAME_TYPE_AVI:
@@ -296,7 +297,8 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
        u32 val = I915_READ(ctl_reg);
 
        data_reg = hsw_infoframe_data_reg(type,
-                                         intel_crtc->config.cpu_transcoder);
+                                         intel_crtc->config.cpu_transcoder,
+                                         dev_priv);
        if (data_reg == 0)
                return;
 
@@ -423,7 +425,7 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
        struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
        u32 reg = VIDEO_DIP_CTL;
        u32 val = I915_READ(reg);
-       u32 port;
+       u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
 
        assert_hdmi_port_disabled(intel_hdmi);
 
@@ -447,18 +449,6 @@ static void g4x_set_infoframes(struct drm_encoder *encoder,
                return;
        }
 
-       switch (intel_dig_port->port) {
-       case PORT_B:
-               port = VIDEO_DIP_PORT_B;
-               break;
-       case PORT_C:
-               port = VIDEO_DIP_PORT_C;
-               break;
-       default:
-               BUG();
-               return;
-       }
-
        if (port != (val & VIDEO_DIP_PORT_MASK)) {
                if (val & VIDEO_DIP_ENABLE) {
                        val &= ~VIDEO_DIP_ENABLE;
@@ -489,7 +479,7 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
        struct intel_hdmi *intel_hdmi = &intel_dig_port->hdmi;
        u32 reg = TVIDEO_DIP_CTL(intel_crtc->pipe);
        u32 val = I915_READ(reg);
-       u32 port;
+       u32 port = VIDEO_DIP_PORT(intel_dig_port->port);
 
        assert_hdmi_port_disabled(intel_hdmi);
 
@@ -505,21 +495,6 @@ static void ibx_set_infoframes(struct drm_encoder *encoder,
                return;
        }
 
-       switch (intel_dig_port->port) {
-       case PORT_B:
-               port = VIDEO_DIP_PORT_B;
-               break;
-       case PORT_C:
-               port = VIDEO_DIP_PORT_C;
-               break;
-       case PORT_D:
-               port = VIDEO_DIP_PORT_D;
-               break;
-       default:
-               BUG();
-               return;
-       }
-
        if (port != (val & VIDEO_DIP_PORT_MASK)) {
                if (val & VIDEO_DIP_ENABLE) {
                        val &= ~VIDEO_DIP_ENABLE;
@@ -692,8 +667,13 @@ static bool intel_hdmi_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_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
+       enum intel_display_power_domain power_domain;
        u32 tmp;
 
+       power_domain = intel_display_port_power_domain(encoder);
+       if (!intel_display_power_enabled(dev_priv, power_domain))
+               return false;
+
        tmp = I915_READ(intel_hdmi->hdmi_reg);
 
        if (!(tmp & SDVO_ENABLE))
@@ -868,6 +848,30 @@ intel_hdmi_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
+static bool hdmi_12bpc_possible(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct intel_encoder *encoder;
+       int count = 0, count_hdmi = 0;
+
+       if (!HAS_PCH_SPLIT(dev))
+               return false;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, base.head) {
+               if (encoder->new_crtc != crtc)
+                       continue;
+
+               count_hdmi += encoder->type == INTEL_OUTPUT_HDMI;
+               count++;
+       }
+
+       /*
+        * HDMI 12bpc affects the clocks, so it's only possible
+        * when not cloning with other encoder types.
+        */
+       return count_hdmi > 0 && count_hdmi == count;
+}
+
 bool intel_hdmi_compute_config(struct intel_encoder *encoder,
                               struct intel_crtc_config *pipe_config)
 {
@@ -900,7 +904,8 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         * within limits.
         */
        if (pipe_config->pipe_bpp > 8*3 && intel_hdmi->has_hdmi_sink &&
-           clock_12bpc <= portclock_limit && HAS_PCH_SPLIT(dev)) {
+           clock_12bpc <= portclock_limit &&
+           hdmi_12bpc_possible(encoder->new_crtc)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
 
@@ -934,11 +939,15 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
        struct intel_encoder *intel_encoder = &intel_dig_port->base;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct edid *edid;
+       enum intel_display_power_domain power_domain;
        enum drm_connector_status status = connector_status_disconnected;
 
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, drm_get_connector_name(connector));
 
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
        intel_hdmi->has_hdmi_sink = false;
        intel_hdmi->has_audio = false;
        intel_hdmi->rgb_quant_range_selectable = false;
@@ -966,31 +975,48 @@ intel_hdmi_detect(struct drm_connector *connector, bool force)
                intel_encoder->type = INTEL_OUTPUT_HDMI;
        }
 
+       intel_display_power_put(dev_priv, power_domain);
+
        return status;
 }
 
 static int intel_hdmi_get_modes(struct drm_connector *connector)
 {
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct intel_encoder *intel_encoder = intel_attached_encoder(connector);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       enum intel_display_power_domain power_domain;
+       int ret;
 
        /* We should parse the EDID data and find out if it's an HDMI sink so
         * we can send audio to it.
         */
 
-       return intel_ddc_get_modes(connector,
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
+       ret = intel_ddc_get_modes(connector,
                                   intel_gmbus_get_adapter(dev_priv,
                                                           intel_hdmi->ddc_bus));
+
+       intel_display_power_put(dev_priv, power_domain);
+
+       return ret;
 }
 
 static bool
 intel_hdmi_detect_audio(struct drm_connector *connector)
 {
-       struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
+       struct intel_encoder *intel_encoder = intel_attached_encoder(connector);
+       struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&intel_encoder->base);
        struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       enum intel_display_power_domain power_domain;
        struct edid *edid;
        bool has_audio = false;
 
+       power_domain = intel_display_port_power_domain(intel_encoder);
+       intel_display_power_get(dev_priv, power_domain);
+
        edid = drm_get_edid(connector,
                            intel_gmbus_get_adapter(dev_priv,
                                                    intel_hdmi->ddc_bus));
@@ -1000,6 +1026,8 @@ intel_hdmi_detect_audio(struct drm_connector *connector)
                kfree(edid);
        }
 
+       intel_display_power_put(dev_priv, power_domain);
+
        return has_audio;
 }
 
@@ -1261,6 +1289,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
                intel_connector->get_hw_state = intel_ddi_connector_get_hw_state;
        else
                intel_connector->get_hw_state = intel_connector_get_hw_state;
+       intel_connector->unregister = intel_connector_unregister;
 
        intel_hdmi_add_properties(intel_hdmi, connector);
 
@@ -1314,7 +1343,14 @@ void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port)
 
        intel_encoder->type = INTEL_OUTPUT_HDMI;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 1 << INTEL_OUTPUT_ANALOG;
+       /*
+        * BSpec is unclear about HDMI+HDMI cloning on g4x, but it seems
+        * to work on real hardware. And since g4x can send infoframes to
+        * only one port anyway, nothing is lost by allowing it.
+        */
+       if (IS_G4X(dev))
+               intel_encoder->cloneable |= 1 << INTEL_OUTPUT_HDMI;
 
        intel_dig_port->port = port;
        intel_dig_port->hdmi.hdmi_reg = hdmi_reg;
index 8bcb93a..f1ecf91 100644 (file)
@@ -848,8 +848,8 @@ static bool compute_is_dual_link_lvds(struct intel_lvds_encoder *lvds_encoder)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        /* use the module option value if specified */
-       if (i915_lvds_channel_mode > 0)
-               return i915_lvds_channel_mode == 2;
+       if (i915.lvds_channel_mode > 0)
+               return i915.lvds_channel_mode == 2;
 
        if (dmi_check_system(intel_dual_link_lvds))
                return true;
@@ -899,6 +899,7 @@ void intel_lvds_init(struct drm_device *dev)
        struct drm_encoder *encoder;
        struct drm_display_mode *scan; /* *modes, *bios_mode; */
        struct drm_display_mode *fixed_mode = NULL;
+       struct drm_display_mode *downclock_mode = NULL;
        struct edid *edid;
        struct drm_crtc *crtc;
        u32 lvds;
@@ -957,11 +958,12 @@ void intel_lvds_init(struct drm_device *dev)
        intel_encoder->get_hw_state = intel_lvds_get_hw_state;
        intel_encoder->get_config = intel_lvds_get_config;
        intel_connector->get_hw_state = intel_connector_get_hw_state;
+       intel_connector->unregister = intel_connector_unregister;
 
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_LVDS;
 
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        if (HAS_PCH_SPLIT(dev))
                intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
        else if (IS_GEN4(dev))
@@ -1000,6 +1002,7 @@ void intel_lvds_init(struct drm_device *dev)
         * Attempt to get the fixed panel mode from DDC.  Assume that the
         * preferred mode is the right one.
         */
+       mutex_lock(&dev->mode_config.mutex);
        edid = drm_get_edid(connector, intel_gmbus_get_adapter(dev_priv, pin));
        if (edid) {
                if (drm_add_edid_modes(connector, edid)) {
@@ -1032,15 +1035,14 @@ void intel_lvds_init(struct drm_device *dev)
 
                        fixed_mode = drm_mode_duplicate(dev, scan);
                        if (fixed_mode) {
-                               intel_connector->panel.downclock_mode =
+                               downclock_mode =
                                        intel_find_panel_downclock(dev,
                                        fixed_mode, connector);
-                               if (intel_connector->panel.downclock_mode !=
-                                       NULL && i915_lvds_downclock) {
+                               if (downclock_mode != NULL &&
+                                       i915.lvds_downclock) {
                                        /* We found the downclock for LVDS. */
                                        dev_priv->lvds_downclock_avail = true;
                                        dev_priv->lvds_downclock =
-                                               intel_connector->panel.
                                                downclock_mode->clock;
                                        DRM_DEBUG_KMS("LVDS downclock is found"
                                        " in EDID. Normal clock %dKhz, "
@@ -1094,6 +1096,8 @@ void intel_lvds_init(struct drm_device *dev)
                goto failed;
 
 out:
+       mutex_unlock(&dev->mode_config.mutex);
+
        lvds_encoder->is_dual_link = compute_is_dual_link_lvds(lvds_encoder);
        DRM_DEBUG_KMS("detected %s-link lvds configuration\n",
                      lvds_encoder->is_dual_link ? "dual" : "single");
@@ -1116,17 +1120,17 @@ out:
        }
        drm_sysfs_connector_add(connector);
 
-       intel_panel_init(&intel_connector->panel, fixed_mode);
+       intel_panel_init(&intel_connector->panel, fixed_mode, downclock_mode);
        intel_panel_setup_backlight(connector);
 
        return;
 
 failed:
+       mutex_unlock(&dev->mode_config.mutex);
+
        DRM_DEBUG_KMS("No LVDS modes found, disabling.\n");
        drm_connector_cleanup(connector);
        drm_encoder_cleanup(encoder);
-       if (fixed_mode)
-               drm_mode_destroy(dev, fixed_mode);
        kfree(lvds_encoder);
        kfree(lvds_connector);
        return;
index a759ecd..d8adc91 100644 (file)
@@ -189,7 +189,7 @@ struct intel_overlay {
 static struct overlay_registers __iomem *
 intel_overlay_map_regs(struct intel_overlay *overlay)
 {
-       drm_i915_private_t *dev_priv = overlay->dev->dev_private;
+       struct drm_i915_private *dev_priv = overlay->dev->dev_private;
        struct overlay_registers __iomem *regs;
 
        if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
@@ -212,7 +212,7 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
                                         void (*tail)(struct intel_overlay *))
 {
        struct drm_device *dev = overlay->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
        int ret;
 
@@ -262,7 +262,7 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
                                  bool load_polyphase_filter)
 {
        struct drm_device *dev = overlay->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
        u32 flip_addr = overlay->flip_addr;
        u32 tmp;
@@ -293,7 +293,7 @@ static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
 {
        struct drm_i915_gem_object *obj = overlay->old_vid_bo;
 
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
        drm_gem_object_unreference(&obj->base);
 
        overlay->old_vid_bo = NULL;
@@ -306,7 +306,7 @@ static void intel_overlay_off_tail(struct intel_overlay *overlay)
        /* never have the overlay hw on without showing a frame */
        BUG_ON(!overlay->vid_bo);
 
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
        drm_gem_object_unreference(&obj->base);
        overlay->vid_bo = NULL;
 
@@ -362,7 +362,7 @@ static int intel_overlay_off(struct intel_overlay *overlay)
 static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
 {
        struct drm_device *dev = overlay->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
        int ret;
 
@@ -388,7 +388,7 @@ static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
 static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
 {
        struct drm_device *dev = overlay->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
        int ret;
 
@@ -606,14 +606,14 @@ static void update_colorkey(struct intel_overlay *overlay,
 {
        u32 key = overlay->color_key;
 
-       switch (overlay->crtc->base.fb->bits_per_pixel) {
+       switch (overlay->crtc->base.primary->fb->bits_per_pixel) {
        case 8:
                iowrite32(0, &regs->DCLRKV);
                iowrite32(CLK_RGB8I_MASK | DST_KEY_ENABLE, &regs->DCLRKM);
                break;
 
        case 16:
-               if (overlay->crtc->base.fb->depth == 15) {
+               if (overlay->crtc->base.primary->fb->depth == 15) {
                        iowrite32(RGB15_TO_COLORKEY(key), &regs->DCLRKV);
                        iowrite32(CLK_RGB15_MASK | DST_KEY_ENABLE,
                                  &regs->DCLRKM);
@@ -782,7 +782,7 @@ static int intel_overlay_do_put_image(struct intel_overlay *overlay,
        return 0;
 
 out_unpin:
-       i915_gem_object_unpin(new_bo);
+       i915_gem_object_ggtt_unpin(new_bo);
        return ret;
 }
 
@@ -834,7 +834,7 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
 static void update_pfit_vscale_ratio(struct intel_overlay *overlay)
 {
        struct drm_device *dev = overlay->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 pfit_control = I915_READ(PFIT_CONTROL);
        u32 ratio;
 
@@ -1026,7 +1026,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
                            struct drm_file *file_priv)
 {
        struct drm_intel_overlay_put_image *put_image_rec = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_overlay *overlay;
        struct drm_mode_object *drmmode_obj;
        struct intel_crtc *crtc;
@@ -1076,7 +1076,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
        mutex_lock(&dev->struct_mutex);
 
        if (new_bo->tiling_mode) {
-               DRM_ERROR("buffer used for overlay image can not be tiled\n");
+               DRM_DEBUG_KMS("buffer used for overlay image can not be tiled\n");
                ret = -EINVAL;
                goto out_unlock;
        }
@@ -1226,7 +1226,7 @@ int intel_overlay_attrs(struct drm_device *dev, void *data,
                        struct drm_file *file_priv)
 {
        struct drm_intel_overlay_attrs *attrs = data;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_overlay *overlay;
        struct overlay_registers __iomem *regs;
        int ret;
@@ -1311,7 +1311,7 @@ out_unlock:
 
 void intel_setup_overlay(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_overlay *overlay;
        struct drm_i915_gem_object *reg_bo;
        struct overlay_registers __iomem *regs;
@@ -1349,7 +1349,7 @@ void intel_setup_overlay(struct drm_device *dev)
                }
                overlay->flip_addr = reg_bo->phys_obj->handle->busaddr;
        } else {
-               ret = i915_gem_obj_ggtt_pin(reg_bo, PAGE_SIZE, true, false);
+               ret = i915_gem_obj_ggtt_pin(reg_bo, PAGE_SIZE, PIN_MAPPABLE);
                if (ret) {
                        DRM_ERROR("failed to pin overlay register bo\n");
                        goto out_free_bo;
@@ -1386,7 +1386,7 @@ void intel_setup_overlay(struct drm_device *dev)
 
 out_unpin_bo:
        if (!OVERLAY_NEEDS_PHYSICAL(dev))
-               i915_gem_object_unpin(reg_bo);
+               i915_gem_object_ggtt_unpin(reg_bo);
 out_free_bo:
        drm_gem_object_unreference(&reg_bo->base);
 out_free:
@@ -1397,7 +1397,7 @@ out_free:
 
 void intel_cleanup_overlay(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (!dev_priv->overlay)
                return;
@@ -1421,7 +1421,7 @@ struct intel_overlay_error_state {
 static struct overlay_registers __iomem *
 intel_overlay_map_regs_atomic(struct intel_overlay *overlay)
 {
-       drm_i915_private_t *dev_priv = overlay->dev->dev_private;
+       struct drm_i915_private *dev_priv = overlay->dev->dev_private;
        struct overlay_registers __iomem *regs;
 
        if (OVERLAY_NEEDS_PHYSICAL(overlay->dev))
@@ -1447,7 +1447,7 @@ static void intel_overlay_unmap_regs_atomic(struct intel_overlay *overlay,
 struct intel_overlay_error_state *
 intel_overlay_capture_error_state(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_overlay *overlay = dev_priv->overlay;
        struct intel_overlay_error_state *error;
        struct overlay_registers __iomem *regs;
index 079ea38..cb05840 100644 (file)
@@ -33,8 +33,6 @@
 #include <linux/moduleparam.h>
 #include "intel_drv.h"
 
-#define PCI_LBPC 0xf4 /* legacy/combination backlight modes */
-
 void
 intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
                       struct drm_display_mode *adjusted_mode)
@@ -325,13 +323,6 @@ out:
        pipe_config->gmch_pfit.lvds_border_bits = border;
 }
 
-static int i915_panel_invert_brightness;
-MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
-       "(-1 force normal, 0 machine defaults, 1 force inversion), please "
-       "report PCI device ID, subsystem vendor and subsystem device ID "
-       "to dri-devel@lists.freedesktop.org, if your machine needs it. "
-       "It will then be included in an upcoming module version.");
-module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
 static u32 intel_panel_compute_brightness(struct intel_connector *connector,
                                          u32 val)
 {
@@ -341,10 +332,10 @@ static u32 intel_panel_compute_brightness(struct intel_connector *connector,
 
        WARN_ON(panel->backlight.max == 0);
 
-       if (i915_panel_invert_brightness < 0)
+       if (i915.invert_brightness < 0)
                return val;
 
-       if (i915_panel_invert_brightness > 0 ||
+       if (i915.invert_brightness > 0 ||
            dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
                return panel->backlight.max - val;
        }
@@ -810,13 +801,13 @@ intel_panel_detect(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        /* Assume that the BIOS does not lie through the OpRegion... */
-       if (!i915_panel_ignore_lid && dev_priv->opregion.lid_state) {
+       if (!i915.panel_ignore_lid && dev_priv->opregion.lid_state) {
                return ioread32(dev_priv->opregion.lid_state) & 0x1 ?
                        connector_status_connected :
                        connector_status_disconnected;
        }
 
-       switch (i915_panel_ignore_lid) {
+       switch (i915.panel_ignore_lid) {
        case -2:
                return connector_status_connected;
        case -1:
@@ -1199,9 +1190,11 @@ void intel_panel_init_backlight_funcs(struct drm_device *dev)
 }
 
 int intel_panel_init(struct intel_panel *panel,
-                    struct drm_display_mode *fixed_mode)
+                    struct drm_display_mode *fixed_mode,
+                    struct drm_display_mode *downclock_mode)
 {
        panel->fixed_mode = fixed_mode;
+       panel->downclock_mode = downclock_mode;
 
        return 0;
 }
index e1fc35a..5874716 100644 (file)
@@ -92,12 +92,12 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_framebuffer *fb = crtc->primary->fb;
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        struct drm_i915_gem_object *obj = intel_fb->obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int cfb_pitch;
-       int plane, i;
+       int i;
        u32 fbc_ctl;
 
        cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
@@ -109,7 +109,6 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
                cfb_pitch = (cfb_pitch / 32) - 1;
        else
                cfb_pitch = (cfb_pitch / 64) - 1;
-       plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
 
        /* Clear old tags */
        for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
@@ -120,7 +119,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
 
                /* Set it up... */
                fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
-               fbc_ctl2 |= plane;
+               fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane);
                I915_WRITE(FBC_CONTROL2, fbc_ctl2);
                I915_WRITE(FBC_FENCE_OFF, crtc->y);
        }
@@ -135,7 +134,7 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc)
        fbc_ctl |= obj->fence_reg;
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
-       DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c",
+       DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
                      cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
 }
 
@@ -150,21 +149,23 @@ static void g4x_enable_fbc(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_framebuffer *fb = crtc->primary->fb;
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        struct drm_i915_gem_object *obj = intel_fb->obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
        u32 dpfc_ctl;
 
-       dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
+       dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN;
+       if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
+               dpfc_ctl |= DPFC_CTL_LIMIT_2X;
+       else
+               dpfc_ctl |= DPFC_CTL_LIMIT_1X;
        dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
-       I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
 
        I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
 
        /* enable it... */
-       I915_WRITE(DPFC_CONTROL, I915_READ(DPFC_CONTROL) | DPFC_CTL_EN);
+       I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
        DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 }
@@ -220,22 +221,20 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_framebuffer *fb = crtc->primary->fb;
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        struct drm_i915_gem_object *obj = intel_fb->obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
        u32 dpfc_ctl;
 
-       dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
-       dpfc_ctl &= DPFC_RESERVED;
-       dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
-       /* Set persistent mode for front-buffer rendering, ala X. */
-       dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE;
+       dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane);
+       if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
+               dpfc_ctl |= DPFC_CTL_LIMIT_2X;
+       else
+               dpfc_ctl |= DPFC_CTL_LIMIT_1X;
        dpfc_ctl |= DPFC_CTL_FENCE_EN;
        if (IS_GEN5(dev))
                dpfc_ctl |= obj->fence_reg;
-       I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
 
        I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
        I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
@@ -278,24 +277,31 @@ static void gen7_enable_fbc(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_framebuffer *fb = crtc->primary->fb;
        struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
        struct drm_i915_gem_object *obj = intel_fb->obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       u32 dpfc_ctl;
 
-       I915_WRITE(IVB_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj));
+       dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane);
+       if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
+               dpfc_ctl |= DPFC_CTL_LIMIT_2X;
+       else
+               dpfc_ctl |= DPFC_CTL_LIMIT_1X;
+       dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
 
-       I915_WRITE(ILK_DPFC_CONTROL, DPFC_CTL_EN | DPFC_CTL_LIMIT_1X |
-                  IVB_DPFC_CTL_FENCE_EN |
-                  intel_crtc->plane << IVB_DPFC_CTL_PLANE_SHIFT);
+       I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
 
        if (IS_IVYBRIDGE(dev)) {
                /* WaFbcAsynchFlipDisableFbcQueue:ivb */
-               I915_WRITE(ILK_DISPLAY_CHICKEN1, ILK_FBCQ_DIS);
+               I915_WRITE(ILK_DISPLAY_CHICKEN1,
+                          I915_READ(ILK_DISPLAY_CHICKEN1) |
+                          ILK_FBCQ_DIS);
        } else {
-               /* WaFbcAsynchFlipDisableFbcQueue:hsw */
-               I915_WRITE(HSW_PIPE_SLICE_CHICKEN_1(intel_crtc->pipe),
-                          HSW_BYPASS_FBC_QUEUE);
+               /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
+               I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe),
+                          I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) |
+                          HSW_FBCQ_DIS);
        }
 
        I915_WRITE(SNB_DPFC_CTL_SA,
@@ -330,11 +336,11 @@ static void intel_fbc_work_fn(struct work_struct *__work)
                /* Double check that we haven't switched fb without cancelling
                 * the prior work.
                 */
-               if (work->crtc->fb == work->fb) {
+               if (work->crtc->primary->fb == work->fb) {
                        dev_priv->display.enable_fbc(work->crtc);
 
                        dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
-                       dev_priv->fbc.fb_id = work->crtc->fb->base.id;
+                       dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
                        dev_priv->fbc.y = work->crtc->y;
                }
 
@@ -387,7 +393,7 @@ static void intel_enable_fbc(struct drm_crtc *crtc)
        }
 
        work->crtc = crtc;
-       work->fb = crtc->fb;
+       work->fb = crtc->primary->fb;
        INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
 
        dev_priv->fbc.fbc_work = work;
@@ -466,7 +472,7 @@ void intel_update_fbc(struct drm_device *dev)
                return;
        }
 
-       if (!i915_powersave) {
+       if (!i915.powersave) {
                if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
                        DRM_DEBUG_KMS("fbc disabled per module param\n");
                return;
@@ -493,25 +499,25 @@ void intel_update_fbc(struct drm_device *dev)
                }
        }
 
-       if (!crtc || crtc->fb == NULL) {
+       if (!crtc || crtc->primary->fb == NULL) {
                if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
                        DRM_DEBUG_KMS("no output, disabling\n");
                goto out_disable;
        }
 
        intel_crtc = to_intel_crtc(crtc);
-       fb = crtc->fb;
+       fb = crtc->primary->fb;
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
        adjusted_mode = &intel_crtc->config.adjusted_mode;
 
-       if (i915_enable_fbc < 0 &&
+       if (i915.enable_fbc < 0 &&
            INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev)) {
                if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
                        DRM_DEBUG_KMS("disabled per chip default\n");
                goto out_disable;
        }
-       if (!i915_enable_fbc) {
+       if (!i915.enable_fbc) {
                if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
                        DRM_DEBUG_KMS("fbc disabled per module param\n");
                goto out_disable;
@@ -537,7 +543,7 @@ void intel_update_fbc(struct drm_device *dev)
                        DRM_DEBUG_KMS("mode too large for compression, disabling\n");
                goto out_disable;
        }
-       if ((INTEL_INFO(dev)->gen < 4 || IS_HASWELL(dev)) &&
+       if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) &&
            intel_crtc->plane != PLANE_A) {
                if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
                        DRM_DEBUG_KMS("plane not A, disabling compression\n");
@@ -617,7 +623,7 @@ out_disable:
 
 static void i915_pineview_get_mem_freq(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 tmp;
 
        tmp = I915_READ(CLKCFG);
@@ -656,7 +662,7 @@ static void i915_pineview_get_mem_freq(struct drm_device *dev)
 
 static void i915_ironlake_get_mem_freq(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        u16 ddrpll, csipll;
 
        ddrpll = I915_READ16(DDRMPLL1);
@@ -1035,7 +1041,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
        crtc = single_enabled_crtc(dev);
        if (crtc) {
                const struct drm_display_mode *adjusted_mode;
-               int pixel_size = crtc->fb->bits_per_pixel / 8;
+               int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
                int clock;
 
                adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
@@ -1115,7 +1121,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
        clock = adjusted_mode->crtc_clock;
        htotal = adjusted_mode->crtc_htotal;
        hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
-       pixel_size = crtc->fb->bits_per_pixel / 8;
+       pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 
        /* Use the small buffer method to calculate plane watermark */
        entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
@@ -1128,9 +1134,9 @@ static bool g4x_compute_wm0(struct drm_device *dev,
                *plane_wm = display->max_wm;
 
        /* Use the large buffer method to calculate cursor watermark */
-       line_time_us = ((htotal * 1000) / clock);
+       line_time_us = max(htotal * 1000 / clock, 1);
        line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
-       entries = line_count * 64 * pixel_size;
+       entries = line_count * to_intel_crtc(crtc)->cursor_width * pixel_size;
        tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
        if (tlb_miss > 0)
                entries += tlb_miss;
@@ -1202,9 +1208,9 @@ static bool g4x_compute_srwm(struct drm_device *dev,
        clock = adjusted_mode->crtc_clock;
        htotal = adjusted_mode->crtc_htotal;
        hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
-       pixel_size = crtc->fb->bits_per_pixel / 8;
+       pixel_size = crtc->primary->fb->bits_per_pixel / 8;
 
-       line_time_us = (htotal * 1000) / clock;
+       line_time_us = max(htotal * 1000 / clock, 1);
        line_count = (latency_ns / line_time_us + 1000) / 1000;
        line_size = hdisplay * pixel_size;
 
@@ -1216,7 +1222,7 @@ static bool g4x_compute_srwm(struct drm_device *dev,
        *display_wm = entries + display->guard_size;
 
        /* calculate the self-refresh watermark for display cursor */
-       entries = line_count * pixel_size * 64;
+       entries = line_count * pixel_size * to_intel_crtc(crtc)->cursor_width;
        entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
        *cursor_wm = entries + cursor->guard_size;
 
@@ -1241,7 +1247,7 @@ static bool vlv_compute_drain_latency(struct drm_device *dev,
                return false;
 
        clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
-       pixel_size = crtc->fb->bits_per_pixel / 8;      /* BPP */
+       pixel_size = crtc->primary->fb->bits_per_pixel / 8;     /* BPP */
 
        entries = (clock / 1000) * pixel_size;
        *plane_prec_mult = (entries > 256) ?
@@ -1433,11 +1439,11 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
                int clock = adjusted_mode->crtc_clock;
                int htotal = adjusted_mode->crtc_htotal;
                int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
-               int pixel_size = crtc->fb->bits_per_pixel / 8;
+               int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
                unsigned long line_time_us;
                int entries;
 
-               line_time_us = ((htotal * 1000) / clock);
+               line_time_us = max(htotal * 1000 / clock, 1);
 
                /* Use ns/us then divide to preserve precision */
                entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
@@ -1451,7 +1457,7 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
                              entries, srwm);
 
                entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                       pixel_size * 64;
+                       pixel_size * to_intel_crtc(crtc)->cursor_width;
                entries = DIV_ROUND_UP(entries,
                                          i965_cursor_wm_info.cacheline_size);
                cursor_sr = i965_cursor_wm_info.fifo_size -
@@ -1506,7 +1512,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
        crtc = intel_get_crtc_for_plane(dev, 0);
        if (intel_crtc_active(crtc)) {
                const struct drm_display_mode *adjusted_mode;
-               int cpp = crtc->fb->bits_per_pixel / 8;
+               int cpp = crtc->primary->fb->bits_per_pixel / 8;
                if (IS_GEN2(dev))
                        cpp = 4;
 
@@ -1522,7 +1528,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
        crtc = intel_get_crtc_for_plane(dev, 1);
        if (intel_crtc_active(crtc)) {
                const struct drm_display_mode *adjusted_mode;
-               int cpp = crtc->fb->bits_per_pixel / 8;
+               int cpp = crtc->primary->fb->bits_per_pixel / 8;
                if (IS_GEN2(dev))
                        cpp = 4;
 
@@ -1559,11 +1565,11 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
                int clock = adjusted_mode->crtc_clock;
                int htotal = adjusted_mode->crtc_htotal;
                int hdisplay = to_intel_crtc(enabled)->config.pipe_src_w;
-               int pixel_size = enabled->fb->bits_per_pixel / 8;
+               int pixel_size = enabled->primary->fb->bits_per_pixel / 8;
                unsigned long line_time_us;
                int entries;
 
-               line_time_us = (htotal * 1000) / clock;
+               line_time_us = max(htotal * 1000 / clock, 1);
 
                /* Use ns/us then divide to preserve precision */
                entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
@@ -1886,7 +1892,7 @@ static unsigned int ilk_cursor_wm_max(const struct drm_device *dev,
 }
 
 /* Calculate the maximum FBC watermark */
-static unsigned int ilk_fbc_wm_max(struct drm_device *dev)
+static unsigned int ilk_fbc_wm_max(const struct drm_device *dev)
 {
        /* max that registers can hold */
        if (INTEL_INFO(dev)->gen >= 8)
@@ -1895,7 +1901,7 @@ static unsigned int ilk_fbc_wm_max(struct drm_device *dev)
                return 15;
 }
 
-static void ilk_compute_wm_maximums(struct drm_device *dev,
+static void ilk_compute_wm_maximums(const struct drm_device *dev,
                                    int level,
                                    const struct intel_wm_config *config,
                                    enum intel_ddb_partitioning ddb_partitioning,
@@ -1948,7 +1954,7 @@ static bool ilk_validate_wm_level(int level,
        return ret;
 }
 
-static void ilk_compute_wm_level(struct drm_i915_private *dev_priv,
+static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
                                 int level,
                                 const struct ilk_pipe_wm_parameters *p,
                                 struct intel_wm_level *result)
@@ -2079,7 +2085,7 @@ static void intel_print_wm_latency(struct drm_device *dev,
        }
 }
 
-static void intel_setup_wm_latency(struct drm_device *dev)
+static void ilk_setup_wm_latency(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -2111,10 +2117,10 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
        if (p->active) {
                p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
                p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
-               p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
+               p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
                p->cur.bytes_per_pixel = 4;
                p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
-               p->cur.horiz_pixels = 64;
+               p->cur.horiz_pixels = intel_crtc->cursor_width;
                /* TODO: for now, assume primary and cursor planes are always enabled. */
                p->pri.enabled = true;
                p->cur.enabled = true;
@@ -2123,7 +2129,7 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
                config->num_pipes_active += intel_crtc_active(crtc);
 
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+       drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
                struct intel_plane *intel_plane = to_intel_plane(plane);
 
                if (intel_plane->pipe == pipe)
@@ -2140,7 +2146,7 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
                                  struct intel_pipe_wm *pipe_wm)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       const struct drm_i915_private *dev_priv = dev->dev_private;
        int level, max_level = ilk_wm_max_level(dev);
        /* LP0 watermark maximums depend on this pipe alone */
        struct intel_wm_config config = {
@@ -2738,7 +2744,7 @@ intel_alloc_context_page(struct drm_device *dev)
                return NULL;
        }
 
-       ret = i915_gem_obj_ggtt_pin(ctx, 4096, true, false);
+       ret = i915_gem_obj_ggtt_pin(ctx, 4096, 0);
        if (ret) {
                DRM_ERROR("failed to pin power context: %d\n", ret);
                goto err_unref;
@@ -2753,7 +2759,7 @@ intel_alloc_context_page(struct drm_device *dev)
        return ctx;
 
 err_unpin:
-       i915_gem_object_unpin(ctx);
+       i915_gem_object_ggtt_unpin(ctx);
 err_unref:
        drm_gem_object_unreference(&ctx->base);
        return NULL;
@@ -2901,9 +2907,9 @@ static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val)
         * the hw runs at the minimal clock before selecting the desired
         * frequency, if the down threshold expires in that window we will not
         * receive a down interrupt. */
-       limits = dev_priv->rps.max_delay << 24;
-       if (val <= dev_priv->rps.min_delay)
-               limits |= dev_priv->rps.min_delay << 16;
+       limits = dev_priv->rps.max_freq_softlimit << 24;
+       if (val <= dev_priv->rps.min_freq_softlimit)
+               limits |= dev_priv->rps.min_freq_softlimit << 16;
 
        return limits;
 }
@@ -2915,26 +2921,26 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
        new_power = dev_priv->rps.power;
        switch (dev_priv->rps.power) {
        case LOW_POWER:
-               if (val > dev_priv->rps.rpe_delay + 1 && val > dev_priv->rps.cur_delay)
+               if (val > dev_priv->rps.efficient_freq + 1 && val > dev_priv->rps.cur_freq)
                        new_power = BETWEEN;
                break;
 
        case BETWEEN:
-               if (val <= dev_priv->rps.rpe_delay && val < dev_priv->rps.cur_delay)
+               if (val <= dev_priv->rps.efficient_freq && val < dev_priv->rps.cur_freq)
                        new_power = LOW_POWER;
-               else if (val >= dev_priv->rps.rp0_delay && val > dev_priv->rps.cur_delay)
+               else if (val >= dev_priv->rps.rp0_freq && val > dev_priv->rps.cur_freq)
                        new_power = HIGH_POWER;
                break;
 
        case HIGH_POWER:
-               if (val < (dev_priv->rps.rp1_delay + dev_priv->rps.rp0_delay) >> 1 && val < dev_priv->rps.cur_delay)
+               if (val < (dev_priv->rps.rp1_freq + dev_priv->rps.rp0_freq) >> 1 && val < dev_priv->rps.cur_freq)
                        new_power = BETWEEN;
                break;
        }
        /* Max/min bins are special */
-       if (val == dev_priv->rps.min_delay)
+       if (val == dev_priv->rps.min_freq_softlimit)
                new_power = LOW_POWER;
-       if (val == dev_priv->rps.max_delay)
+       if (val == dev_priv->rps.max_freq_softlimit)
                new_power = HIGH_POWER;
        if (new_power == dev_priv->rps.power)
                return;
@@ -3000,41 +3006,113 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
        dev_priv->rps.last_adj = 0;
 }
 
+static u32 gen6_rps_pm_mask(struct drm_i915_private *dev_priv, u8 val)
+{
+       u32 mask = 0;
+
+       if (val > dev_priv->rps.min_freq_softlimit)
+               mask |= GEN6_PM_RP_DOWN_THRESHOLD | GEN6_PM_RP_DOWN_TIMEOUT;
+       if (val < dev_priv->rps.max_freq_softlimit)
+               mask |= GEN6_PM_RP_UP_THRESHOLD;
+
+       /* IVB and SNB hard hangs on looping batchbuffer
+        * if GEN6_PM_UP_EI_EXPIRED is masked.
+        */
+       if (INTEL_INFO(dev_priv->dev)->gen <= 7 && !IS_HASWELL(dev_priv->dev))
+               mask |= GEN6_PM_RP_UP_EI_EXPIRED;
+
+       return ~mask;
+}
+
+/* gen6_set_rps is called to update the frequency request, but should also be
+ * called when the range (min_delay and max_delay) is modified so that we can
+ * update the GEN6_RP_INTERRUPT_LIMITS register accordingly. */
 void gen6_set_rps(struct drm_device *dev, u8 val)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-       WARN_ON(val > dev_priv->rps.max_delay);
-       WARN_ON(val < dev_priv->rps.min_delay);
-
-       if (val == dev_priv->rps.cur_delay)
-               return;
+       WARN_ON(val > dev_priv->rps.max_freq_softlimit);
+       WARN_ON(val < dev_priv->rps.min_freq_softlimit);
 
-       gen6_set_rps_thresholds(dev_priv, val);
+       /* min/max delay may still have been modified so be sure to
+        * write the limits value.
+        */
+       if (val != dev_priv->rps.cur_freq) {
+               gen6_set_rps_thresholds(dev_priv, val);
 
-       if (IS_HASWELL(dev))
-               I915_WRITE(GEN6_RPNSWREQ,
-                          HSW_FREQUENCY(val));
-       else
-               I915_WRITE(GEN6_RPNSWREQ,
-                          GEN6_FREQUENCY(val) |
-                          GEN6_OFFSET(0) |
-                          GEN6_AGGRESSIVE_TURBO);
+               if (IS_HASWELL(dev))
+                       I915_WRITE(GEN6_RPNSWREQ,
+                                  HSW_FREQUENCY(val));
+               else
+                       I915_WRITE(GEN6_RPNSWREQ,
+                                  GEN6_FREQUENCY(val) |
+                                  GEN6_OFFSET(0) |
+                                  GEN6_AGGRESSIVE_TURBO);
+       }
 
        /* Make sure we continue to get interrupts
         * until we hit the minimum or maximum frequencies.
         */
-       I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
-                  gen6_rps_limits(dev_priv, val));
+       I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, gen6_rps_limits(dev_priv, val));
+       I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
 
        POSTING_READ(GEN6_RPNSWREQ);
 
-       dev_priv->rps.cur_delay = val;
-
+       dev_priv->rps.cur_freq = val;
        trace_intel_gpu_freq_change(val * 50);
 }
 
+/* vlv_set_rps_idle: Set the frequency to Rpn if Gfx clocks are down
+ *
+ * * If Gfx is Idle, then
+ * 1. Mask Turbo interrupts
+ * 2. Bring up Gfx clock
+ * 3. Change the freq to Rpn and wait till P-Unit updates freq
+ * 4. Clear the Force GFX CLK ON bit so that Gfx can down
+ * 5. Unmask Turbo interrupts
+*/
+static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
+{
+       /*
+        * When we are idle.  Drop to min voltage state.
+        */
+
+       if (dev_priv->rps.cur_freq <= dev_priv->rps.min_freq_softlimit)
+               return;
+
+       /* Mask turbo interrupt so that they will not come in between */
+       I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
+
+       /* Bring up the Gfx clock */
+       I915_WRITE(VLV_GTLC_SURVIVABILITY_REG,
+               I915_READ(VLV_GTLC_SURVIVABILITY_REG) |
+                               VLV_GFX_CLK_FORCE_ON_BIT);
+
+       if (wait_for(((VLV_GFX_CLK_STATUS_BIT &
+               I915_READ(VLV_GTLC_SURVIVABILITY_REG)) != 0), 5)) {
+                       DRM_ERROR("GFX_CLK_ON request timed out\n");
+               return;
+       }
+
+       dev_priv->rps.cur_freq = dev_priv->rps.min_freq_softlimit;
+
+       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ,
+                                       dev_priv->rps.min_freq_softlimit);
+
+       if (wait_for(((vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS))
+                               & GENFREQSTATUS) == 0, 5))
+               DRM_ERROR("timed out waiting for Punit\n");
+
+       /* Release the Gfx clock */
+       I915_WRITE(VLV_GTLC_SURVIVABILITY_REG,
+               I915_READ(VLV_GTLC_SURVIVABILITY_REG) &
+                               ~VLV_GFX_CLK_FORCE_ON_BIT);
+
+       I915_WRITE(GEN6_PMINTRMSK,
+                  gen6_rps_pm_mask(dev_priv, dev_priv->rps.cur_freq));
+}
+
 void gen6_rps_idle(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
@@ -3042,9 +3120,9 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
        mutex_lock(&dev_priv->rps.hw_lock);
        if (dev_priv->rps.enabled) {
                if (IS_VALLEYVIEW(dev))
-                       valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_delay);
+                       vlv_set_rps_idle(dev_priv);
                else
-                       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay);
+                       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
                dev_priv->rps.last_adj = 0;
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -3057,9 +3135,9 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv)
        mutex_lock(&dev_priv->rps.hw_lock);
        if (dev_priv->rps.enabled) {
                if (IS_VALLEYVIEW(dev))
-                       valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_delay);
+                       valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
                else
-                       gen6_set_rps(dev_priv->dev, dev_priv->rps.max_delay);
+                       gen6_set_rps(dev_priv->dev, dev_priv->rps.max_freq_softlimit);
                dev_priv->rps.last_adj = 0;
        }
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -3070,21 +3148,20 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-       WARN_ON(val > dev_priv->rps.max_delay);
-       WARN_ON(val < dev_priv->rps.min_delay);
+       WARN_ON(val > dev_priv->rps.max_freq_softlimit);
+       WARN_ON(val < dev_priv->rps.min_freq_softlimit);
 
        DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay),
-                        dev_priv->rps.cur_delay,
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
+                        dev_priv->rps.cur_freq,
                         vlv_gpu_freq(dev_priv, val), val);
 
-       if (val == dev_priv->rps.cur_delay)
-               return;
-
-       vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
+       if (val != dev_priv->rps.cur_freq)
+               vlv_punit_write(dev_priv, PUNIT_REG_GPU_FREQ_REQ, val);
 
-       dev_priv->rps.cur_delay = val;
+       I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
 
+       dev_priv->rps.cur_freq = val;
        trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
 }
 
@@ -3093,7 +3170,8 @@ static void gen6_disable_rps_interrupts(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
-       I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) & ~GEN6_PM_RPS_EVENTS);
+       I915_WRITE(GEN6_PMIER, I915_READ(GEN6_PMIER) &
+                               ~dev_priv->pm_rps_events);
        /* 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
@@ -3103,7 +3181,7 @@ static void gen6_disable_rps_interrupts(struct drm_device *dev)
        dev_priv->rps.pm_iir = 0;
        spin_unlock_irq(&dev_priv->irq_lock);
 
-       I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
+       I915_WRITE(GEN6_PMIIR, dev_priv->pm_rps_events);
 }
 
 static void gen6_disable_rps(struct drm_device *dev)
@@ -3123,25 +3201,14 @@ static void valleyview_disable_rps(struct drm_device *dev)
        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);
-               dev_priv->vlv_pctx = NULL;
-       }
 }
 
 static void intel_print_rc6_info(struct drm_device *dev, u32 mode)
 {
-       if (IS_GEN6(dev))
-               DRM_DEBUG_DRIVER("Sandybridge: deep RC6 disabled\n");
-
-       if (IS_HASWELL(dev))
-               DRM_DEBUG_DRIVER("Haswell: only RC6 available\n");
-
        DRM_INFO("Enabling RC6 states: RC6 %s, RC6p %s, RC6pp %s\n",
-                       (mode & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off",
-                       (mode & GEN6_RC_CTL_RC6p_ENABLE) ? "on" : "off",
-                       (mode & GEN6_RC_CTL_RC6pp_ENABLE) ? "on" : "off");
+                (mode & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off",
+                (mode & GEN6_RC_CTL_RC6p_ENABLE) ? "on" : "off",
+                (mode & GEN6_RC_CTL_RC6pp_ENABLE) ? "on" : "off");
 }
 
 int intel_enable_rc6(const struct drm_device *dev)
@@ -3151,44 +3218,28 @@ int intel_enable_rc6(const struct drm_device *dev)
                return 0;
 
        /* Respect the kernel parameter if it is set */
-       if (i915_enable_rc6 >= 0)
-               return i915_enable_rc6;
+       if (i915.enable_rc6 >= 0)
+               return i915.enable_rc6;
 
        /* Disable RC6 on Ironlake */
        if (INTEL_INFO(dev)->gen == 5)
                return 0;
 
-       if (IS_HASWELL(dev))
-               return INTEL_RC6_ENABLE;
-
-       /* snb/ivb have more than one rc6 state. */
-       if (INTEL_INFO(dev)->gen == 6)
-               return INTEL_RC6_ENABLE;
+       if (IS_IVYBRIDGE(dev))
+               return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
 
-       return (INTEL_RC6_ENABLE | INTEL_RC6p_ENABLE);
+       return INTEL_RC6_ENABLE;
 }
 
 static void gen6_enable_rps_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 enabled_intrs;
 
        spin_lock_irq(&dev_priv->irq_lock);
        WARN_ON(dev_priv->rps.pm_iir);
-       snb_enable_pm_irq(dev_priv, GEN6_PM_RPS_EVENTS);
-       I915_WRITE(GEN6_PMIIR, GEN6_PM_RPS_EVENTS);
+       snb_enable_pm_irq(dev_priv, dev_priv->pm_rps_events);
+       I915_WRITE(GEN6_PMIIR, dev_priv->pm_rps_events);
        spin_unlock_irq(&dev_priv->irq_lock);
-
-       /* only unmask PM interrupts we need. Mask all others. */
-       enabled_intrs = GEN6_PM_RPS_EVENTS;
-
-       /* IVB and SNB hard hangs on looping batchbuffer
-        * if GEN6_PM_UP_EI_EXPIRED is masked.
-        */
-       if (INTEL_INFO(dev)->gen <= 7 && !IS_HASWELL(dev))
-               enabled_intrs |= GEN6_PM_RP_UP_EI_EXPIRED;
-
-       I915_WRITE(GEN6_PMINTRMSK, ~enabled_intrs);
 }
 
 static void gen8_enable_rps(struct drm_device *dev)
@@ -3222,10 +3273,10 @@ static void gen8_enable_rps(struct drm_device *dev)
        /* 3: Enable RC6 */
        if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
                rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
-       DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off");
+       intel_print_rc6_info(dev, rc6_mask);
        I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
-                       GEN6_RC_CTL_EI_MODE(1) |
-                       rc6_mask);
+                                   GEN6_RC_CTL_EI_MODE(1) |
+                                   rc6_mask);
 
        /* 4 Program defaults and thresholds for RPS*/
        I915_WRITE(GEN6_RPNSWREQ, HSW_FREQUENCY(10)); /* Request 500 MHz */
@@ -3235,8 +3286,8 @@ static void gen8_enable_rps(struct drm_device *dev)
 
        /* Docs recommend 900MHz, and 300 MHz respectively */
        I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
-                  dev_priv->rps.max_delay << 24 |
-                  dev_priv->rps.min_delay << 16);
+                  dev_priv->rps.max_freq_softlimit << 24 |
+                  dev_priv->rps.min_freq_softlimit << 16);
 
        I915_WRITE(GEN6_RP_UP_THRESHOLD, 7600000 / 128); /* 76ms busyness per EI, 90% */
        I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 31300000 / 128); /* 313ms busyness per EI, 70%*/
@@ -3269,7 +3320,7 @@ static void gen6_enable_rps(struct drm_device *dev)
        struct intel_ring_buffer *ring;
        u32 rp_state_cap;
        u32 gt_perf_status;
-       u32 rc6vids, pcu_mbox, rc6_mask = 0;
+       u32 rc6vids, pcu_mbox = 0, rc6_mask = 0;
        u32 gtfifodbg;
        int rc6_mode;
        int i, ret;
@@ -3295,13 +3346,23 @@ static void gen6_enable_rps(struct drm_device *dev)
        rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
        gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
 
-       /* In units of 50MHz */
-       dev_priv->rps.hw_max = dev_priv->rps.max_delay = rp_state_cap & 0xff;
-       dev_priv->rps.min_delay = (rp_state_cap >> 16) & 0xff;
-       dev_priv->rps.rp1_delay = (rp_state_cap >>  8) & 0xff;
-       dev_priv->rps.rp0_delay = (rp_state_cap >>  0) & 0xff;
-       dev_priv->rps.rpe_delay = dev_priv->rps.rp1_delay;
-       dev_priv->rps.cur_delay = 0;
+       /* All of these values are in units of 50MHz */
+       dev_priv->rps.cur_freq          = 0;
+       /* static values from HW: RP0 < RPe < RP1 < RPn (min_freq) */
+       dev_priv->rps.rp1_freq          = (rp_state_cap >>  8) & 0xff;
+       dev_priv->rps.rp0_freq          = (rp_state_cap >>  0) & 0xff;
+       dev_priv->rps.min_freq          = (rp_state_cap >> 16) & 0xff;
+       /* XXX: only BYT has a special efficient freq */
+       dev_priv->rps.efficient_freq    = dev_priv->rps.rp1_freq;
+       /* hw_max = RP0 until we check for overclocking */
+       dev_priv->rps.max_freq          = dev_priv->rps.rp0_freq;
+
+       /* Preserve min/max settings in case of re-init */
+       if (dev_priv->rps.max_freq_softlimit == 0)
+               dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
+
+       if (dev_priv->rps.min_freq_softlimit == 0)
+               dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
 
        /* disable the counters and set deterministic thresholds */
        I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -3350,21 +3411,19 @@ static void gen6_enable_rps(struct drm_device *dev)
        I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
 
        ret = sandybridge_pcode_write(dev_priv, GEN6_PCODE_WRITE_MIN_FREQ_TABLE, 0);
-       if (!ret) {
-               pcu_mbox = 0;
-               ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox);
-               if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */
-                       DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n",
-                                        (dev_priv->rps.max_delay & 0xff) * 50,
-                                        (pcu_mbox & 0xff) * 50);
-                       dev_priv->rps.hw_max = pcu_mbox & 0xff;
-               }
-       } else {
+       if (ret)
                DRM_DEBUG_DRIVER("Failed to set the min frequency\n");
+
+       ret = sandybridge_pcode_read(dev_priv, GEN6_READ_OC_PARAMS, &pcu_mbox);
+       if (!ret && (pcu_mbox & (1<<31))) { /* OC supported */
+               DRM_DEBUG_DRIVER("Overclocking supported. Max: %dMHz, Overclock max: %dMHz\n",
+                                (dev_priv->rps.max_freq_softlimit & 0xff) * 50,
+                                (pcu_mbox & 0xff) * 50);
+               dev_priv->rps.max_freq = pcu_mbox & 0xff;
        }
 
        dev_priv->rps.power = HIGH_POWER; /* force a reset */
-       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay);
+       gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
 
        gen6_enable_rps_interrupts(dev);
 
@@ -3420,9 +3479,9 @@ void gen6_update_ring_freq(struct drm_device *dev)
         * to use for memory access.  We do this by specifying the IA frequency
         * the PCU should use as a reference to determine the ring frequency.
         */
-       for (gpu_freq = dev_priv->rps.max_delay; gpu_freq >= dev_priv->rps.min_delay;
+       for (gpu_freq = dev_priv->rps.max_freq_softlimit; gpu_freq >= dev_priv->rps.min_freq_softlimit;
             gpu_freq--) {
-               int diff = dev_priv->rps.max_delay - gpu_freq;
+               int diff = dev_priv->rps.max_freq_softlimit - gpu_freq;
                unsigned int ia_freq = 0, ring_freq = 0;
 
                if (INTEL_INFO(dev)->gen >= 8) {
@@ -3485,6 +3544,15 @@ int valleyview_rps_min_freq(struct drm_i915_private *dev_priv)
        return vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM) & 0xff;
 }
 
+/* Check that the pctx buffer wasn't move under us. */
+static void valleyview_check_pctx(struct drm_i915_private *dev_priv)
+{
+       unsigned long pctx_addr = I915_READ(VLV_PCBR) & ~4095;
+
+       WARN_ON(pctx_addr != dev_priv->mm.stolen_base +
+                            dev_priv->vlv_pctx->stolen->start);
+}
+
 static void valleyview_setup_pctx(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3529,6 +3597,17 @@ out:
        dev_priv->vlv_pctx = pctx;
 }
 
+static void valleyview_cleanup_pctx(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (WARN_ON(!dev_priv->vlv_pctx))
+               return;
+
+       drm_gem_object_unreference(&dev_priv->vlv_pctx->base);
+       dev_priv->vlv_pctx = NULL;
+}
+
 static void valleyview_enable_rps(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3538,6 +3617,8 @@ static void valleyview_enable_rps(struct drm_device *dev)
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
 
+       valleyview_check_pctx(dev_priv);
+
        if ((gtfifodbg = I915_READ(GTFIFODBG))) {
                DRM_DEBUG_DRIVER("GT fifo had a previous error %x\n",
                                 gtfifodbg);
@@ -3588,32 +3669,39 @@ static void valleyview_enable_rps(struct drm_device *dev)
        DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no");
        DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
 
-       dev_priv->rps.cur_delay = (val >> 8) & 0xff;
+       dev_priv->rps.cur_freq = (val >> 8) & 0xff;
        DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay),
-                        dev_priv->rps.cur_delay);
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
+                        dev_priv->rps.cur_freq);
 
-       dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv);
-       dev_priv->rps.hw_max = dev_priv->rps.max_delay;
+       dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv);
+       dev_priv->rps.rp0_freq  = dev_priv->rps.max_freq;
        DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay),
-                        dev_priv->rps.max_delay);
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq),
+                        dev_priv->rps.max_freq);
 
-       dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv);
+       dev_priv->rps.efficient_freq = valleyview_rps_rpe_freq(dev_priv);
        DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay),
-                        dev_priv->rps.rpe_delay);
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+                        dev_priv->rps.efficient_freq);
 
-       dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv);
+       dev_priv->rps.min_freq = valleyview_rps_min_freq(dev_priv);
        DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay),
-                        dev_priv->rps.min_delay);
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
+                        dev_priv->rps.min_freq);
+
+       /* Preserve min/max settings in case of re-init */
+       if (dev_priv->rps.max_freq_softlimit == 0)
+               dev_priv->rps.max_freq_softlimit = dev_priv->rps.max_freq;
+
+       if (dev_priv->rps.min_freq_softlimit == 0)
+               dev_priv->rps.min_freq_softlimit = dev_priv->rps.min_freq;
 
        DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay),
-                        dev_priv->rps.rpe_delay);
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+                        dev_priv->rps.efficient_freq);
 
-       valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
+       valleyview_set_rps(dev_priv->dev, dev_priv->rps.efficient_freq);
 
        gen6_enable_rps_interrupts(dev);
 
@@ -3625,13 +3713,13 @@ void ironlake_teardown_rc6(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        if (dev_priv->ips.renderctx) {
-               i915_gem_object_unpin(dev_priv->ips.renderctx);
+               i915_gem_object_ggtt_unpin(dev_priv->ips.renderctx);
                drm_gem_object_unreference(&dev_priv->ips.renderctx->base);
                dev_priv->ips.renderctx = NULL;
        }
 
        if (dev_priv->ips.pwrctx) {
-               i915_gem_object_unpin(dev_priv->ips.pwrctx);
+               i915_gem_object_ggtt_unpin(dev_priv->ips.pwrctx);
                drm_gem_object_unreference(&dev_priv->ips.pwrctx->base);
                dev_priv->ips.pwrctx = NULL;
        }
@@ -3823,9 +3911,10 @@ static unsigned long __i915_chipset_val(struct drm_i915_private *dev_priv)
 
 unsigned long i915_chipset_val(struct drm_i915_private *dev_priv)
 {
+       struct drm_device *dev = dev_priv->dev;
        unsigned long val;
 
-       if (dev_priv->info->gen != 5)
+       if (INTEL_INFO(dev)->gen != 5)
                return 0;
 
        spin_lock_irq(&mchdev_lock);
@@ -3854,6 +3943,7 @@ unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
 
 static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
 {
+       struct drm_device *dev = dev_priv->dev;
        static const struct v_table {
                u16 vd; /* in .1 mil */
                u16 vm; /* in .1 mil */
@@ -3987,7 +4077,7 @@ static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
                { 16000, 14875, },
                { 16125, 15000, },
        };
-       if (dev_priv->info->is_mobile)
+       if (INTEL_INFO(dev)->is_mobile)
                return v_table[pxvid].vm;
        else
                return v_table[pxvid].vd;
@@ -4030,7 +4120,9 @@ static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
 
 void i915_update_gfx_val(struct drm_i915_private *dev_priv)
 {
-       if (dev_priv->info->gen != 5)
+       struct drm_device *dev = dev_priv->dev;
+
+       if (INTEL_INFO(dev)->gen != 5)
                return;
 
        spin_lock_irq(&mchdev_lock);
@@ -4047,7 +4139,7 @@ static unsigned long __i915_gfx_val(struct drm_i915_private *dev_priv)
 
        assert_spin_locked(&mchdev_lock);
 
-       pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->rps.cur_delay * 4));
+       pxvid = I915_READ(PXVFREQ_BASE + (dev_priv->rps.cur_freq * 4));
        pxvid = (pxvid >> 24) & 0x7f;
        ext_v = pvid_to_extvid(dev_priv, pxvid);
 
@@ -4079,9 +4171,10 @@ static unsigned long __i915_gfx_val(struct drm_i915_private *dev_priv)
 
 unsigned long i915_gfx_val(struct drm_i915_private *dev_priv)
 {
+       struct drm_device *dev = dev_priv->dev;
        unsigned long val;
 
-       if (dev_priv->info->gen != 5)
+       if (INTEL_INFO(dev)->gen != 5)
                return 0;
 
        spin_lock_irq(&mchdev_lock);
@@ -4270,6 +4363,7 @@ void intel_gpu_ips_teardown(void)
        i915_mch_dev = NULL;
        spin_unlock_irq(&mchdev_lock);
 }
+
 static void intel_init_emon(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4341,6 +4435,18 @@ static void intel_init_emon(struct drm_device *dev)
        dev_priv->ips.corr = (lcfuse & LCFUSE_HIV_MASK);
 }
 
+void intel_init_gt_powersave(struct drm_device *dev)
+{
+       if (IS_VALLEYVIEW(dev))
+               valleyview_setup_pctx(dev);
+}
+
+void intel_cleanup_gt_powersave(struct drm_device *dev)
+{
+       if (IS_VALLEYVIEW(dev))
+               valleyview_cleanup_pctx(dev);
+}
+
 void intel_disable_gt_powersave(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -4395,8 +4501,6 @@ void intel_enable_gt_powersave(struct drm_device *dev)
                ironlake_enable_rc6(dev);
                intel_init_emon(dev);
        } else if (IS_GEN6(dev) || IS_GEN7(dev)) {
-               if (IS_VALLEYVIEW(dev))
-                       valleyview_setup_pctx(dev);
                /*
                 * PCU communication is slow and this doesn't need to be
                 * done at any specific time, so do this out of our fast path
@@ -4587,6 +4691,17 @@ static void gen6_init_clock_gating(struct drm_device *dev)
                I915_WRITE(GEN6_GT_MODE,
                           _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE));
 
+       /*
+        * BSpec recoomends 8x4 when MSAA is used,
+        * however in practice 16x4 seems fastest.
+        *
+        * Note that PS/WM thread counts depend on the WIZ hashing
+        * disable bit, which we don't touch here, but it's good
+        * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
+        */
+       I915_WRITE(GEN6_GT_MODE,
+                  GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4);
+
        ilk_init_lp_watermarks(dev);
 
        I915_WRITE(CACHE_MODE_0,
@@ -4607,17 +4722,24 @@ static void gen6_init_clock_gating(struct drm_device *dev)
         * According to the spec, bit 11 (RCCUNIT) must also be set,
         * but we didn't debug actual testcases to find it out.
         *
-        * Also apply WaDisableVDSUnitClockGating:snb and
-        * WaDisableRCPBUnitClockGating:snb.
+        * WaDisableRCCUnitClockGating:snb
+        * WaDisableRCPBUnitClockGating:snb
         */
        I915_WRITE(GEN6_UCGCTL2,
-                  GEN7_VDSUNIT_CLOCK_GATE_DISABLE |
                   GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
                   GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
 
-       /* Bspec says we need to always set all mask bits. */
-       I915_WRITE(_3D_CHICKEN3, (0xFFFF << 16) |
-                  _3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL);
+       /* WaStripsFansDisableFastClipPerformanceFix:snb */
+       I915_WRITE(_3D_CHICKEN3,
+                  _MASKED_BIT_ENABLE(_3D_CHICKEN3_SF_DISABLE_FASTCLIP_CULL));
+
+       /*
+        * Bspec says:
+        * "This bit must be set if 3DSTATE_CLIP clip mode is set to normal and
+        * 3DSTATE_SF number of SF output attributes is more than 16."
+        */
+       I915_WRITE(_3D_CHICKEN3,
+                  _MASKED_BIT_ENABLE(_3D_CHICKEN3_SF_DISABLE_PIPELINED_ATTR_FETCH));
 
        /*
         * According to the spec the following bits should be
@@ -4643,11 +4765,6 @@ static void gen6_init_clock_gating(struct drm_device *dev)
 
        g4x_disable_trickle_feed(dev);
 
-       /* The default value should be 0x200 according to docs, but the two
-        * platforms I checked have a 0 for this. (Maybe BIOS overrides?) */
-       I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_DISABLE(0xffff));
-       I915_WRITE(GEN6_GT_MODE, _MASKED_BIT_ENABLE(GEN6_GT_MODE_HI));
-
        cpt_init_clock_gating(dev);
 
        gen6_check_mch_setup(dev);
@@ -4657,14 +4774,17 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
 {
        uint32_t reg = I915_READ(GEN7_FF_THREAD_MODE);
 
+       /*
+        * WaVSThreadDispatchOverride:ivb,vlv
+        *
+        * This actually overrides the dispatch
+        * mode for all thread types.
+        */
        reg &= ~GEN7_FF_SCHED_MASK;
        reg |= GEN7_FF_TS_SCHED_HW;
        reg |= GEN7_FF_VS_SCHED_HW;
        reg |= GEN7_FF_DS_SCHED_HW;
 
-       if (IS_HASWELL(dev_priv->dev))
-               reg &= ~GEN7_FF_VS_REF_CNT_FFME;
-
        I915_WRITE(GEN7_FF_THREAD_MODE, reg);
 }
 
@@ -4702,7 +4822,7 @@ static void lpt_suspend_hw(struct drm_device *dev)
 static void gen8_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       enum pipe i;
+       enum pipe pipe;
 
        I915_WRITE(WM3_LP_ILK, 0);
        I915_WRITE(WM2_LP_ILK, 0);
@@ -4711,8 +4831,19 @@ static void gen8_init_clock_gating(struct drm_device *dev)
        /* FIXME(BDW): Check all the w/a, some might only apply to
         * pre-production hw. */
 
-       WARN(!i915_preliminary_hw_support,
-            "GEN8_CENTROID_PIXEL_OPT_DIS not be needed for production\n");
+       /* WaDisablePartialInstShootdown:bdw */
+       I915_WRITE(GEN8_ROW_CHICKEN,
+                  _MASKED_BIT_ENABLE(PARTIAL_INSTRUCTION_SHOOTDOWN_DISABLE));
+
+       /* WaDisableThreadStallDopClockGating:bdw */
+       /* FIXME: Unclear whether we really need this on production bdw. */
+       I915_WRITE(GEN8_ROW_CHICKEN,
+                  _MASKED_BIT_ENABLE(STALL_DOP_GATING_DISABLE));
+
+       /*
+        * This GEN8_CENTROID_PIXEL_OPT_DIS W/A is only needed for
+        * pre-production hardware
+        */
        I915_WRITE(HALF_SLICE_CHICKEN3,
                   _MASKED_BIT_ENABLE(GEN8_CENTROID_PIXEL_OPT_DIS));
        I915_WRITE(HALF_SLICE_CHICKEN3,
@@ -4736,10 +4867,10 @@ static void gen8_init_clock_gating(struct drm_device *dev)
                   I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD);
 
        /* WaPsrDPRSUnmaskVBlankInSRD:bdw */
-       for_each_pipe(i) {
-               I915_WRITE(CHICKEN_PIPESL_1(i),
-                          I915_READ(CHICKEN_PIPESL_1(i) |
-                                    DPRS_MASK_VBLANK_SRD));
+       for_each_pipe(pipe) {
+               I915_WRITE(CHICKEN_PIPESL_1(pipe),
+                          I915_READ(CHICKEN_PIPESL_1(pipe)) |
+                          BDW_DPRS_MASK_VBLANK_SRD);
        }
 
        /* Use Force Non-Coherent whenever executing a 3D context. This is a
@@ -4755,6 +4886,28 @@ static void gen8_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN7_FF_THREAD_MODE,
                   I915_READ(GEN7_FF_THREAD_MODE) &
                   ~(GEN8_FF_DS_REF_CNT_FFME | GEN7_FF_VS_REF_CNT_FFME));
+
+       /*
+        * BSpec recommends 8x4 when MSAA is used,
+        * however in practice 16x4 seems fastest.
+        *
+        * Note that PS/WM thread counts depend on the WIZ hashing
+        * disable bit, which we don't touch here, but it's good
+        * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
+        */
+       I915_WRITE(GEN7_GT_MODE,
+                  GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4);
+
+       I915_WRITE(GEN6_RC_SLEEP_PSMI_CONTROL,
+                  _MASKED_BIT_ENABLE(GEN8_RC_SEMA_IDLE_MSG_DISABLE));
+
+       /* WaDisableSDEUnitClockGating:bdw */
+       I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
+                  GEN8_SDEUNIT_CLOCK_GATE_DISABLE);
+
+       /* Wa4x4STCOptimizationDisable:bdw */
+       I915_WRITE(CACHE_MODE_1,
+                  _MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
 }
 
 static void haswell_init_clock_gating(struct drm_device *dev)
@@ -4763,21 +4916,6 @@ static void haswell_init_clock_gating(struct drm_device *dev)
 
        ilk_init_lp_watermarks(dev);
 
-       /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
-        * This implements the WaDisableRCZUnitClockGating:hsw workaround.
-        */
-       I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
-
-       /* Apply the WaDisableRHWOOptimizationForRenderHang:hsw workaround. */
-       I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
-                  GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
-
-       /* WaApplyL3ControlAndL3ChickenMode:hsw */
-       I915_WRITE(GEN7_L3CNTLREG1,
-                       GEN7_WA_FOR_GEN7_L3_CONTROL);
-       I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER,
-                       GEN7_WA_L3_CHICKEN_MODE);
-
        /* L3 caching of data atomics doesn't work -- disable it. */
        I915_WRITE(HSW_SCRATCH1, HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE);
        I915_WRITE(HSW_ROW_CHICKEN3,
@@ -4789,12 +4927,28 @@ static void haswell_init_clock_gating(struct drm_device *dev)
                        GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
 
        /* WaVSRefCountFullforceMissDisable:hsw */
-       gen7_setup_fixed_func_scheduler(dev_priv);
+       I915_WRITE(GEN7_FF_THREAD_MODE,
+                  I915_READ(GEN7_FF_THREAD_MODE) & ~GEN7_FF_VS_REF_CNT_FFME);
+
+       /* enable HiZ Raw Stall Optimization */
+       I915_WRITE(CACHE_MODE_0_GEN7,
+                  _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE));
 
        /* WaDisable4x2SubspanOptimization:hsw */
        I915_WRITE(CACHE_MODE_1,
                   _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
 
+       /*
+        * BSpec recommends 8x4 when MSAA is used,
+        * however in practice 16x4 seems fastest.
+        *
+        * Note that PS/WM thread counts depend on the WIZ hashing
+        * disable bit, which we don't touch here, but it's good
+        * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
+        */
+       I915_WRITE(GEN7_GT_MODE,
+                  GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4);
+
        /* WaSwitchSolVfFArbitrationPriority:hsw */
        I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
 
@@ -4827,9 +4981,6 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
        if (IS_IVB_GT1(dev))
                I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
                           _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
-       else
-               I915_WRITE(GEN7_HALF_SLICE_CHICKEN1_GT2,
-                          _MASKED_BIT_ENABLE(GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
 
        /* Apply the WaDisableRHWOOptimizationForRenderHang:ivb workaround. */
        I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
@@ -4843,31 +4994,24 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
        if (IS_IVB_GT1(dev))
                I915_WRITE(GEN7_ROW_CHICKEN2,
                           _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
-       else
+       else {
+               /* must write both registers */
+               I915_WRITE(GEN7_ROW_CHICKEN2,
+                          _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
                I915_WRITE(GEN7_ROW_CHICKEN2_GT2,
                           _MASKED_BIT_ENABLE(DOP_CLOCK_GATING_DISABLE));
-
+       }
 
        /* WaForceL3Serialization:ivb */
        I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) &
                   ~L3SQ_URB_READ_CAM_MATCH_DISABLE);
 
-       /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
-        * gating disable must be set.  Failure to set it results in
-        * flickering pixels due to Z write ordering failures after
-        * some amount of runtime in the Mesa "fire" demo, and Unigine
-        * Sanctuary and Tropics, and apparently anything else with
-        * alpha test or pixel discard.
-        *
-        * According to the spec, bit 11 (RCCUNIT) must also be set,
-        * but we didn't debug actual testcases to find it out.
-        *
+       /*
         * According to the spec, bit 13 (RCZUNIT) must be set on IVB.
         * This implements the WaDisableRCZUnitClockGating:ivb workaround.
         */
        I915_WRITE(GEN6_UCGCTL2,
-                  GEN6_RCZUNIT_CLOCK_GATE_DISABLE |
-                  GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
+                  GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
 
        /* This is required by WaCatErrorRejectionIssue:ivb */
        I915_WRITE(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG,
@@ -4876,13 +5020,29 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
 
        g4x_disable_trickle_feed(dev);
 
-       /* WaVSRefCountFullforceMissDisable:ivb */
        gen7_setup_fixed_func_scheduler(dev_priv);
 
+       if (0) { /* causes HiZ corruption on ivb:gt1 */
+               /* enable HiZ Raw Stall Optimization */
+               I915_WRITE(CACHE_MODE_0_GEN7,
+                          _MASKED_BIT_DISABLE(HIZ_RAW_STALL_OPT_DISABLE));
+       }
+
        /* WaDisable4x2SubspanOptimization:ivb */
        I915_WRITE(CACHE_MODE_1,
                   _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
 
+       /*
+        * BSpec recommends 8x4 when MSAA is used,
+        * however in practice 16x4 seems fastest.
+        *
+        * Note that PS/WM thread counts depend on the WIZ hashing
+        * disable bit, which we don't touch here, but it's good
+        * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
+        */
+       I915_WRITE(GEN7_GT_MODE,
+                  GEN6_WIZ_HASHING_MASK | GEN6_WIZ_HASHING_16x4);
+
        snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
        snpcr &= ~GEN6_MBC_SNPCR_MASK;
        snpcr |= GEN6_MBC_SNPCR_MED;
@@ -4904,13 +5064,11 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
        mutex_unlock(&dev_priv->rps.hw_lock);
        switch ((val >> 6) & 3) {
        case 0:
-               dev_priv->mem_freq = 800;
-               break;
        case 1:
-               dev_priv->mem_freq = 1066;
+               dev_priv->mem_freq = 800;
                break;
        case 2:
-               dev_priv->mem_freq = 1333;
+               dev_priv->mem_freq = 1066;
                break;
        case 3:
                dev_priv->mem_freq = 1333;
@@ -4929,19 +5087,12 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
                   CHICKEN3_DGMG_REQ_OUT_FIX_DISABLE |
                   CHICKEN3_DGMG_DONE_FIX_DISABLE);
 
+       /* WaPsdDispatchEnable:vlv */
        /* WaDisablePSDDualDispatchEnable:vlv */
        I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
                   _MASKED_BIT_ENABLE(GEN7_MAX_PS_THREAD_DEP |
                                      GEN7_PSD_SINGLE_PORT_DISPATCH_ENABLE));
 
-       /* Apply the WaDisableRHWOOptimizationForRenderHang:vlv workaround. */
-       I915_WRITE(GEN7_COMMON_SLICE_CHICKEN1,
-                  GEN7_CSC1_RHWO_OPT_DISABLE_IN_RCC);
-
-       /* WaApplyL3ControlAndL3ChickenMode:vlv */
-       I915_WRITE(GEN7_L3CNTLREG1, I915_READ(GEN7_L3CNTLREG1) | GEN7_L3AGDIS);
-       I915_WRITE(GEN7_L3_CHICKEN_MODE_REGISTER, GEN7_WA_L3_CHICKEN_MODE);
-
        /* WaForceL3Serialization:vlv */
        I915_WRITE(GEN7_L3SQCREG4, I915_READ(GEN7_L3SQCREG4) &
                   ~L3SQ_URB_READ_CAM_MATCH_DISABLE);
@@ -4955,51 +5106,39 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
                   I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
                   GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
 
-       /* According to the BSpec vol1g, bit 12 (RCPBUNIT) clock
-        * gating disable must be set.  Failure to set it results in
-        * flickering pixels due to Z write ordering failures after
-        * some amount of runtime in the Mesa "fire" demo, and Unigine
-        * Sanctuary and Tropics, and apparently anything else with
-        * alpha test or pixel discard.
-        *
-        * According to the spec, bit 11 (RCCUNIT) must also be set,
-        * but we didn't debug actual testcases to find it out.
-        *
+       gen7_setup_fixed_func_scheduler(dev_priv);
+
+       /*
         * According to the spec, bit 13 (RCZUNIT) must be set on IVB.
         * This implements the WaDisableRCZUnitClockGating:vlv workaround.
-        *
-        * Also apply WaDisableVDSUnitClockGating:vlv and
-        * WaDisableRCPBUnitClockGating:vlv.
         */
        I915_WRITE(GEN6_UCGCTL2,
-                  GEN7_VDSUNIT_CLOCK_GATE_DISABLE |
-                  GEN7_TDLUNIT_CLOCK_GATE_DISABLE |
-                  GEN6_RCZUNIT_CLOCK_GATE_DISABLE |
-                  GEN6_RCPBUNIT_CLOCK_GATE_DISABLE |
-                  GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
+                  GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
 
+       /* WaDisableL3Bank2xClockGate:vlv */
        I915_WRITE(GEN7_UCGCTL4, GEN7_L3BANK2X_CLOCK_GATE_DISABLE);
 
        I915_WRITE(MI_ARB_VLV, MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE);
 
+       /*
+        * BSpec says this must be set, even though
+        * WaDisable4x2SubspanOptimization isn't listed for VLV.
+        */
        I915_WRITE(CACHE_MODE_1,
                   _MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
 
+       /*
+        * WaIncreaseL3CreditsForVLVB0:vlv
+        * This is the hardware default actually.
+        */
+       I915_WRITE(GEN7_L3SQCREG1, VLV_B0_WA_L3SQCREG1_VALUE);
+
        /*
         * WaDisableVLVClockGating_VBIIssue:vlv
         * Disable clock gating on th GCFG unit to prevent a delay
         * in the reporting of vblank events.
         */
-       I915_WRITE(VLV_GUNIT_CLOCK_GATE, 0xffffffff);
-
-       /* Conservative clock gating settings for now */
-       I915_WRITE(0x9400, 0xffffffff);
-       I915_WRITE(0x9404, 0xffffffff);
-       I915_WRITE(0x9408, 0xffffffff);
-       I915_WRITE(0x940c, 0xffffffff);
-       I915_WRITE(0x9410, 0xffffffff);
-       I915_WRITE(0x9414, 0xffffffff);
-       I915_WRITE(0x9418, 0xffffffff);
+       I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS);
 }
 
 static void g4x_init_clock_gating(struct drm_device *dev)
@@ -5114,19 +5253,16 @@ void intel_suspend_hw(struct drm_device *dev)
  * enable it, so check if it's enabled and also check if we've requested it to
  * be enabled.
  */
-static bool hsw_power_well_enabled(struct drm_device *dev,
+static bool hsw_power_well_enabled(struct drm_i915_private *dev_priv,
                                   struct i915_power_well *power_well)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        return I915_READ(HSW_PWR_WELL_DRIVER) ==
                     (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
 }
 
-bool intel_display_power_enabled_sw(struct drm_device *dev,
+bool intel_display_power_enabled_sw(struct drm_i915_private *dev_priv,
                                    enum intel_display_power_domain domain)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains;
 
        power_domains = &dev_priv->power_domains;
@@ -5134,15 +5270,17 @@ bool intel_display_power_enabled_sw(struct drm_device *dev,
        return power_domains->domain_use_count[domain];
 }
 
-bool intel_display_power_enabled(struct drm_device *dev,
+bool intel_display_power_enabled(struct drm_i915_private *dev_priv,
                                 enum intel_display_power_domain domain)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains;
        struct i915_power_well *power_well;
        bool is_enabled;
        int i;
 
+       if (dev_priv->pm.suspended)
+               return false;
+
        power_domains = &dev_priv->power_domains;
 
        is_enabled = true;
@@ -5152,7 +5290,7 @@ bool intel_display_power_enabled(struct drm_device *dev,
                if (power_well->always_on)
                        continue;
 
-               if (!power_well->is_enabled(dev, power_well)) {
+               if (!power_well->ops->is_enabled(dev_priv, power_well)) {
                        is_enabled = false;
                        break;
                }
@@ -5162,6 +5300,12 @@ bool intel_display_power_enabled(struct drm_device *dev,
        return is_enabled;
 }
 
+/*
+ * Starting with Haswell, we have a "Power Down Well" that can be turned off
+ * when not needed anymore. We have 4 registers that can request the power well
+ * to be enabled, and it will only be disabled if none of the registers is
+ * requesting it to be enabled.
+ */
 static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
@@ -5198,10 +5342,17 @@ static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
        }
 }
 
+static void reset_vblank_counter(struct drm_device *dev, enum pipe pipe)
+{
+       assert_spin_locked(&dev->vbl_lock);
+
+       dev->vblank[pipe].last = 0;
+}
+
 static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv)
 {
        struct drm_device *dev = dev_priv->dev;
-       enum pipe p;
+       enum pipe pipe;
        unsigned long irqflags;
 
        /*
@@ -5212,21 +5363,18 @@ static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv)
         * FIXME: Should we do this in general in drm_vblank_post_modeset?
         */
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
-       for_each_pipe(p)
-               if (p != PIPE_A)
-                       dev->vblank[p].last = 0;
+       for_each_pipe(pipe)
+               if (pipe != PIPE_A)
+                       reset_vblank_counter(dev, pipe);
        spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
 
-static void hsw_set_power_well(struct drm_device *dev,
+static void hsw_set_power_well(struct drm_i915_private *dev_priv,
                               struct i915_power_well *power_well, bool enable)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        bool is_enabled, enable_requested;
        uint32_t tmp;
 
-       WARN_ON(dev_priv->pc8.enabled);
-
        tmp = I915_READ(HSW_PWR_WELL_DRIVER);
        is_enabled = tmp & HSW_PWR_WELL_STATE_ENABLED;
        enable_requested = tmp & HSW_PWR_WELL_ENABLE_REQUEST;
@@ -5255,55 +5403,229 @@ static void hsw_set_power_well(struct drm_device *dev,
        }
 }
 
-static void __intel_power_well_get(struct drm_device *dev,
+static void hsw_power_well_sync_hw(struct drm_i915_private *dev_priv,
                                   struct i915_power_well *power_well)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       hsw_set_power_well(dev_priv, power_well, power_well->count > 0);
 
-       if (!power_well->count++ && power_well->set) {
-               hsw_disable_package_c8(dev_priv);
-               power_well->set(dev, power_well, true);
-       }
+       /*
+        * We're taking over the BIOS, so clear any requests made by it since
+        * the driver is in charge now.
+        */
+       if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST)
+               I915_WRITE(HSW_PWR_WELL_BIOS, 0);
+}
+
+static void hsw_power_well_enable(struct drm_i915_private *dev_priv,
+                                 struct i915_power_well *power_well)
+{
+       hsw_set_power_well(dev_priv, power_well, true);
 }
 
-static void __intel_power_well_put(struct drm_device *dev,
+static void hsw_power_well_disable(struct drm_i915_private *dev_priv,
                                   struct i915_power_well *power_well)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       hsw_set_power_well(dev_priv, power_well, false);
+}
+
+static void i9xx_always_on_power_well_noop(struct drm_i915_private *dev_priv,
+                                          struct i915_power_well *power_well)
+{
+}
+
+static bool i9xx_always_on_power_well_enabled(struct drm_i915_private *dev_priv,
+                                            struct i915_power_well *power_well)
+{
+       return true;
+}
+
+static void vlv_set_power_well(struct drm_i915_private *dev_priv,
+                              struct i915_power_well *power_well, bool enable)
+{
+       enum punit_power_well power_well_id = power_well->data;
+       u32 mask;
+       u32 state;
+       u32 ctrl;
+
+       mask = PUNIT_PWRGT_MASK(power_well_id);
+       state = enable ? PUNIT_PWRGT_PWR_ON(power_well_id) :
+                        PUNIT_PWRGT_PWR_GATE(power_well_id);
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+
+#define COND \
+       ((vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask) == state)
+
+       if (COND)
+               goto out;
+
+       ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL);
+       ctrl &= ~mask;
+       ctrl |= state;
+       vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, ctrl);
+
+       if (wait_for(COND, 100))
+               DRM_ERROR("timout setting power well state %08x (%08x)\n",
+                         state,
+                         vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL));
+
+#undef COND
+
+out:
+       mutex_unlock(&dev_priv->rps.hw_lock);
+}
+
+static void vlv_power_well_sync_hw(struct drm_i915_private *dev_priv,
+                                  struct i915_power_well *power_well)
+{
+       vlv_set_power_well(dev_priv, power_well, power_well->count > 0);
+}
+
+static void vlv_power_well_enable(struct drm_i915_private *dev_priv,
+                                 struct i915_power_well *power_well)
+{
+       vlv_set_power_well(dev_priv, power_well, true);
+}
+
+static void vlv_power_well_disable(struct drm_i915_private *dev_priv,
+                                  struct i915_power_well *power_well)
+{
+       vlv_set_power_well(dev_priv, power_well, false);
+}
+
+static bool vlv_power_well_enabled(struct drm_i915_private *dev_priv,
+                                  struct i915_power_well *power_well)
+{
+       int power_well_id = power_well->data;
+       bool enabled = false;
+       u32 mask;
+       u32 state;
+       u32 ctrl;
+
+       mask = PUNIT_PWRGT_MASK(power_well_id);
+       ctrl = PUNIT_PWRGT_PWR_ON(power_well_id);
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+
+       state = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS) & mask;
+       /*
+        * We only ever set the power-on and power-gate states, anything
+        * else is unexpected.
+        */
+       WARN_ON(state != PUNIT_PWRGT_PWR_ON(power_well_id) &&
+               state != PUNIT_PWRGT_PWR_GATE(power_well_id));
+       if (state == ctrl)
+               enabled = true;
+
+       /*
+        * A transient state at this point would mean some unexpected party
+        * is poking at the power controls too.
+        */
+       ctrl = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_CTRL) & mask;
+       WARN_ON(ctrl != state);
+
+       mutex_unlock(&dev_priv->rps.hw_lock);
+
+       return enabled;
+}
 
-       WARN_ON(!power_well->count);
+static void vlv_display_power_well_enable(struct drm_i915_private *dev_priv,
+                                         struct i915_power_well *power_well)
+{
+       WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
+
+       vlv_set_power_well(dev_priv, power_well, true);
+
+       spin_lock_irq(&dev_priv->irq_lock);
+       valleyview_enable_display_irqs(dev_priv);
+       spin_unlock_irq(&dev_priv->irq_lock);
+
+       /*
+        * During driver initialization we need to defer enabling hotplug
+        * processing until fbdev is set up.
+        */
+       if (dev_priv->enable_hotplug_processing)
+               intel_hpd_init(dev_priv->dev);
+
+       i915_redisable_vga_power_on(dev_priv->dev);
+}
+
+static void vlv_display_power_well_disable(struct drm_i915_private *dev_priv,
+                                          struct i915_power_well *power_well)
+{
+       struct drm_device *dev = dev_priv->dev;
+       enum pipe pipe;
+
+       WARN_ON_ONCE(power_well->data != PUNIT_POWER_WELL_DISP2D);
+
+       spin_lock_irq(&dev_priv->irq_lock);
+       for_each_pipe(pipe)
+               __intel_set_cpu_fifo_underrun_reporting(dev, pipe, false);
+
+       valleyview_disable_display_irqs(dev_priv);
+       spin_unlock_irq(&dev_priv->irq_lock);
+
+       spin_lock_irq(&dev->vbl_lock);
+       for_each_pipe(pipe)
+               reset_vblank_counter(dev, pipe);
+       spin_unlock_irq(&dev->vbl_lock);
+
+       vlv_set_power_well(dev_priv, power_well, false);
+}
 
-       if (!--power_well->count && power_well->set &&
-           i915_disable_power_well) {
-               power_well->set(dev, power_well, false);
-               hsw_enable_package_c8(dev_priv);
+static void check_power_well_state(struct drm_i915_private *dev_priv,
+                                  struct i915_power_well *power_well)
+{
+       bool enabled = power_well->ops->is_enabled(dev_priv, power_well);
+
+       if (power_well->always_on || !i915.disable_power_well) {
+               if (!enabled)
+                       goto mismatch;
+
+               return;
        }
+
+       if (enabled != (power_well->count > 0))
+               goto mismatch;
+
+       return;
+
+mismatch:
+       WARN(1, "state mismatch for '%s' (always_on %d hw state %d use-count %d disable_power_well %d\n",
+                 power_well->name, power_well->always_on, enabled,
+                 power_well->count, i915.disable_power_well);
 }
 
-void intel_display_power_get(struct drm_device *dev,
+void intel_display_power_get(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains;
        struct i915_power_well *power_well;
        int i;
 
+       intel_runtime_pm_get(dev_priv);
+
        power_domains = &dev_priv->power_domains;
 
        mutex_lock(&power_domains->lock);
 
-       for_each_power_well(i, power_well, BIT(domain), power_domains)
-               __intel_power_well_get(dev, power_well);
+       for_each_power_well(i, power_well, BIT(domain), power_domains) {
+               if (!power_well->count++) {
+                       DRM_DEBUG_KMS("enabling %s\n", power_well->name);
+                       power_well->ops->enable(dev_priv, power_well);
+               }
+
+               check_power_well_state(dev_priv, power_well);
+       }
 
        power_domains->domain_use_count[domain]++;
 
        mutex_unlock(&power_domains->lock);
 }
 
-void intel_display_power_put(struct drm_device *dev,
+void intel_display_power_put(struct drm_i915_private *dev_priv,
                             enum intel_display_power_domain domain)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains;
        struct i915_power_well *power_well;
        int i;
@@ -5315,10 +5637,20 @@ void intel_display_power_put(struct drm_device *dev,
        WARN_ON(!power_domains->domain_use_count[domain]);
        power_domains->domain_use_count[domain]--;
 
-       for_each_power_well_rev(i, power_well, BIT(domain), power_domains)
-               __intel_power_well_put(dev, power_well);
+       for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
+               WARN_ON(!power_well->count);
+
+               if (!--power_well->count && i915.disable_power_well) {
+                       DRM_DEBUG_KMS("disabling %s\n", power_well->name);
+                       power_well->ops->disable(dev_priv, power_well);
+               }
+
+               check_power_well_state(dev_priv, power_well);
+       }
 
        mutex_unlock(&power_domains->lock);
+
+       intel_runtime_pm_put(dev_priv);
 }
 
 static struct i915_power_domains *hsw_pwr;
@@ -5333,7 +5665,7 @@ void i915_request_power_well(void)
 
        dev_priv = container_of(hsw_pwr, struct drm_i915_private,
                                power_domains);
-       intel_display_power_get(dev_priv->dev, POWER_DOMAIN_AUDIO);
+       intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
 }
 EXPORT_SYMBOL_GPL(i915_request_power_well);
 
@@ -5347,29 +5679,99 @@ void i915_release_power_well(void)
 
        dev_priv = container_of(hsw_pwr, struct drm_i915_private,
                                power_domains);
-       intel_display_power_put(dev_priv->dev, POWER_DOMAIN_AUDIO);
+       intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
 }
 EXPORT_SYMBOL_GPL(i915_release_power_well);
 
+#define POWER_DOMAIN_MASK (BIT(POWER_DOMAIN_NUM) - 1)
+
+#define HSW_ALWAYS_ON_POWER_DOMAINS (                  \
+       BIT(POWER_DOMAIN_PIPE_A) |                      \
+       BIT(POWER_DOMAIN_TRANSCODER_EDP) |              \
+       BIT(POWER_DOMAIN_PORT_DDI_A_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_A_4_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) |          \
+       BIT(POWER_DOMAIN_PORT_CRT) |                    \
+       BIT(POWER_DOMAIN_INIT))
+#define HSW_DISPLAY_POWER_DOMAINS (                            \
+       (POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) |    \
+       BIT(POWER_DOMAIN_INIT))
+
+#define BDW_ALWAYS_ON_POWER_DOMAINS (                  \
+       HSW_ALWAYS_ON_POWER_DOMAINS |                   \
+       BIT(POWER_DOMAIN_PIPE_A_PANEL_FITTER))
+#define BDW_DISPLAY_POWER_DOMAINS (                            \
+       (POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS) |    \
+       BIT(POWER_DOMAIN_INIT))
+
+#define VLV_ALWAYS_ON_POWER_DOMAINS    BIT(POWER_DOMAIN_INIT)
+#define VLV_DISPLAY_POWER_DOMAINS      POWER_DOMAIN_MASK
+
+#define VLV_DPIO_CMN_BC_POWER_DOMAINS (                \
+       BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_CRT) |            \
+       BIT(POWER_DOMAIN_INIT))
+
+#define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS ( \
+       BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |  \
+       BIT(POWER_DOMAIN_INIT))
+
+#define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS ( \
+       BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) |  \
+       BIT(POWER_DOMAIN_INIT))
+
+#define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS ( \
+       BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) |  \
+       BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |  \
+       BIT(POWER_DOMAIN_INIT))
+
+#define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS ( \
+       BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) |  \
+       BIT(POWER_DOMAIN_INIT))
+
+static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
+       .sync_hw = i9xx_always_on_power_well_noop,
+       .enable = i9xx_always_on_power_well_noop,
+       .disable = i9xx_always_on_power_well_noop,
+       .is_enabled = i9xx_always_on_power_well_enabled,
+};
+
 static struct i915_power_well i9xx_always_on_power_well[] = {
        {
                .name = "always-on",
                .always_on = 1,
                .domains = POWER_DOMAIN_MASK,
+               .ops = &i9xx_always_on_power_well_ops,
        },
 };
 
+static const struct i915_power_well_ops hsw_power_well_ops = {
+       .sync_hw = hsw_power_well_sync_hw,
+       .enable = hsw_power_well_enable,
+       .disable = hsw_power_well_disable,
+       .is_enabled = hsw_power_well_enabled,
+};
+
 static struct i915_power_well hsw_power_wells[] = {
        {
                .name = "always-on",
                .always_on = 1,
                .domains = HSW_ALWAYS_ON_POWER_DOMAINS,
+               .ops = &i9xx_always_on_power_well_ops,
        },
        {
                .name = "display",
-               .domains = POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS,
-               .is_enabled = hsw_power_well_enabled,
-               .set = hsw_set_power_well,
+               .domains = HSW_DISPLAY_POWER_DOMAINS,
+               .ops = &hsw_power_well_ops,
        },
 };
 
@@ -5378,12 +5780,83 @@ static struct i915_power_well bdw_power_wells[] = {
                .name = "always-on",
                .always_on = 1,
                .domains = BDW_ALWAYS_ON_POWER_DOMAINS,
+               .ops = &i9xx_always_on_power_well_ops,
        },
        {
                .name = "display",
-               .domains = POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS,
-               .is_enabled = hsw_power_well_enabled,
-               .set = hsw_set_power_well,
+               .domains = BDW_DISPLAY_POWER_DOMAINS,
+               .ops = &hsw_power_well_ops,
+       },
+};
+
+static const struct i915_power_well_ops vlv_display_power_well_ops = {
+       .sync_hw = vlv_power_well_sync_hw,
+       .enable = vlv_display_power_well_enable,
+       .disable = vlv_display_power_well_disable,
+       .is_enabled = vlv_power_well_enabled,
+};
+
+static const struct i915_power_well_ops vlv_dpio_power_well_ops = {
+       .sync_hw = vlv_power_well_sync_hw,
+       .enable = vlv_power_well_enable,
+       .disable = vlv_power_well_disable,
+       .is_enabled = vlv_power_well_enabled,
+};
+
+static struct i915_power_well vlv_power_wells[] = {
+       {
+               .name = "always-on",
+               .always_on = 1,
+               .domains = VLV_ALWAYS_ON_POWER_DOMAINS,
+               .ops = &i9xx_always_on_power_well_ops,
+       },
+       {
+               .name = "display",
+               .domains = VLV_DISPLAY_POWER_DOMAINS,
+               .data = PUNIT_POWER_WELL_DISP2D,
+               .ops = &vlv_display_power_well_ops,
+       },
+       {
+               .name = "dpio-common",
+               .domains = VLV_DPIO_CMN_BC_POWER_DOMAINS,
+               .data = PUNIT_POWER_WELL_DPIO_CMN_BC,
+               .ops = &vlv_dpio_power_well_ops,
+       },
+       {
+               .name = "dpio-tx-b-01",
+               .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_01,
+       },
+       {
+               .name = "dpio-tx-b-23",
+               .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_B_LANES_23,
+       },
+       {
+               .name = "dpio-tx-c-01",
+               .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_01,
+       },
+       {
+               .name = "dpio-tx-c-23",
+               .domains = VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS |
+                          VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS,
+               .ops = &vlv_dpio_power_well_ops,
+               .data = PUNIT_POWER_WELL_DPIO_TX_C_LANES_23,
        },
 };
 
@@ -5392,9 +5865,8 @@ static struct i915_power_well bdw_power_wells[] = {
        (power_domains)->power_well_count = ARRAY_SIZE(__power_wells);  \
 })
 
-int intel_power_domains_init(struct drm_device *dev)
+int intel_power_domains_init(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
 
        mutex_init(&power_domains->lock);
@@ -5403,12 +5875,14 @@ int intel_power_domains_init(struct drm_device *dev)
         * The enabling order will be from lower to higher indexed wells,
         * the disabling order is reversed.
         */
-       if (IS_HASWELL(dev)) {
+       if (IS_HASWELL(dev_priv->dev)) {
                set_power_wells(power_domains, hsw_power_wells);
                hsw_pwr = power_domains;
-       } else if (IS_BROADWELL(dev)) {
+       } else if (IS_BROADWELL(dev_priv->dev)) {
                set_power_wells(power_domains, bdw_power_wells);
                hsw_pwr = power_domains;
+       } else if (IS_VALLEYVIEW(dev_priv->dev)) {
+               set_power_wells(power_domains, vlv_power_wells);
        } else {
                set_power_wells(power_domains, i9xx_always_on_power_well);
        }
@@ -5416,58 +5890,38 @@ int intel_power_domains_init(struct drm_device *dev)
        return 0;
 }
 
-void intel_power_domains_remove(struct drm_device *dev)
+void intel_power_domains_remove(struct drm_i915_private *dev_priv)
 {
        hsw_pwr = NULL;
 }
 
-static void intel_power_domains_resume(struct drm_device *dev)
+static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *power_well;
        int i;
 
        mutex_lock(&power_domains->lock);
-       for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
-               if (power_well->set)
-                       power_well->set(dev, power_well, power_well->count > 0);
-       }
+       for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains)
+               power_well->ops->sync_hw(dev_priv, power_well);
        mutex_unlock(&power_domains->lock);
 }
 
-/*
- * Starting with Haswell, we have a "Power Down Well" that can be turned off
- * when not needed anymore. We have 4 registers that can request the power well
- * to be enabled, and it will only be disabled if none of the registers is
- * requesting it to be enabled.
- */
-void intel_power_domains_init_hw(struct drm_device *dev)
+void intel_power_domains_init_hw(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        /* For now, we need the power well to be always enabled. */
-       intel_display_set_init_power(dev, true);
-       intel_power_domains_resume(dev);
-
-       if (!(IS_HASWELL(dev) || IS_BROADWELL(dev)))
-               return;
-
-       /* We're taking over the BIOS, so clear any requests made by it since
-        * the driver is in charge now. */
-       if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST)
-               I915_WRITE(HSW_PWR_WELL_BIOS, 0);
+       intel_display_set_init_power(dev_priv, true);
+       intel_power_domains_resume(dev_priv);
 }
 
-/* Disables PC8 so we can use the GMBUS and DP AUX interrupts. */
 void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv)
 {
-       hsw_disable_package_c8(dev_priv);
+       intel_runtime_pm_get(dev_priv);
 }
 
 void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
 {
-       hsw_enable_package_c8(dev_priv);
+       intel_runtime_pm_put(dev_priv);
 }
 
 void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
@@ -5499,8 +5953,6 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
        struct drm_device *dev = dev_priv->dev;
        struct device *device = &dev->pdev->dev;
 
-       dev_priv->pm.suspended = false;
-
        if (!HAS_RUNTIME_PM(dev))
                return;
 
@@ -5509,6 +5961,8 @@ void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
        pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
        pm_runtime_mark_last_busy(device);
        pm_runtime_use_autosuspend(device);
+
+       pm_runtime_put_autosuspend(device);
 }
 
 void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
@@ -5560,7 +6014,7 @@ void intel_init_pm(struct drm_device *dev)
 
        /* For FIFO watermark updates */
        if (HAS_PCH_SPLIT(dev)) {
-               intel_setup_wm_latency(dev);
+               ilk_setup_wm_latency(dev);
 
                if ((IS_GEN5(dev) && dev_priv->wm.pri_latency[1] &&
                     dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
@@ -5731,13 +6185,9 @@ void intel_pm_setup(struct drm_device *dev)
 
        mutex_init(&dev_priv->rps.hw_lock);
 
-       mutex_init(&dev_priv->pc8.lock);
-       dev_priv->pc8.requirements_met = false;
-       dev_priv->pc8.gpu_idle = false;
-       dev_priv->pc8.irqs_disabled = false;
-       dev_priv->pc8.enabled = false;
-       dev_priv->pc8.disable_count = 2; /* requirements_met + gpu_idle */
-       INIT_DELAYED_WORK(&dev_priv->pc8.enable_work, hsw_enable_pc8_work);
        INIT_DELAYED_WORK(&dev_priv->rps.delayed_resume_work,
                          intel_gen6_powersave_work);
+
+       dev_priv->pm.suspended = false;
+       dev_priv->pm.irqs_disabled = false;
 }
index 31b36c5..6bc68bd 100644 (file)
@@ -406,17 +406,24 @@ gen8_render_ring_flush(struct intel_ring_buffer *ring,
 static void ring_write_tail(struct intel_ring_buffer *ring,
                            u32 value)
 {
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
        I915_WRITE_TAIL(ring, value);
 }
 
-u32 intel_ring_get_active_head(struct intel_ring_buffer *ring)
+u64 intel_ring_get_active_head(struct intel_ring_buffer *ring)
 {
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
-       u32 acthd_reg = INTEL_INFO(ring->dev)->gen >= 4 ?
-                       RING_ACTHD(ring->mmio_base) : ACTHD;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       u64 acthd;
+
+       if (INTEL_INFO(ring->dev)->gen >= 8)
+               acthd = I915_READ64_2x32(RING_ACTHD(ring->mmio_base),
+                                        RING_ACTHD_UDW(ring->mmio_base));
+       else if (INTEL_INFO(ring->dev)->gen >= 4)
+               acthd = I915_READ(RING_ACTHD(ring->mmio_base));
+       else
+               acthd = I915_READ(ACTHD);
 
-       return I915_READ(acthd_reg);
+       return acthd;
 }
 
 static void ring_setup_phys_status_page(struct intel_ring_buffer *ring)
@@ -433,22 +440,24 @@ static void ring_setup_phys_status_page(struct intel_ring_buffer *ring)
 static int init_ring_common(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_object *obj = ring->obj;
        int ret = 0;
        u32 head;
 
        gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
-       if (I915_NEED_GFX_HWS(dev))
-               intel_ring_setup_status_page(ring);
-       else
-               ring_setup_phys_status_page(ring);
-
        /* Stop the ring if it's running. */
        I915_WRITE_CTL(ring, 0);
        I915_WRITE_HEAD(ring, 0);
        ring->write_tail(ring, 0);
+       if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000))
+               DRM_ERROR("%s :timed out trying to stop ring\n", ring->name);
+
+       if (I915_NEED_GFX_HWS(dev))
+               intel_ring_setup_status_page(ring);
+       else
+               ring_setup_phys_status_page(ring);
 
        head = I915_READ_HEAD(ring) & HEAD_ADDR;
 
@@ -531,9 +540,11 @@ init_pipe_control(struct intel_ring_buffer *ring)
                goto err;
        }
 
-       i915_gem_object_set_cache_level(ring->scratch.obj, I915_CACHE_LLC);
+       ret = i915_gem_object_set_cache_level(ring->scratch.obj, I915_CACHE_LLC);
+       if (ret)
+               goto err_unref;
 
-       ret = i915_gem_obj_ggtt_pin(ring->scratch.obj, 4096, true, false);
+       ret = i915_gem_obj_ggtt_pin(ring->scratch.obj, 4096, 0);
        if (ret)
                goto err_unref;
 
@@ -549,7 +560,7 @@ init_pipe_control(struct intel_ring_buffer *ring)
        return 0;
 
 err_unpin:
-       i915_gem_object_unpin(ring->scratch.obj);
+       i915_gem_object_ggtt_unpin(ring->scratch.obj);
 err_unref:
        drm_gem_object_unreference(&ring->scratch.obj->base);
 err:
@@ -562,14 +573,15 @@ static int init_render_ring(struct intel_ring_buffer *ring)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret = init_ring_common(ring);
 
-       if (INTEL_INFO(dev)->gen > 3)
+       /* WaTimedSingleVertexDispatch:cl,bw,ctg,elk,ilk,snb */
+       if (INTEL_INFO(dev)->gen >= 4 && INTEL_INFO(dev)->gen < 7)
                I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(VS_TIMER_DISPATCH));
 
        /* We need to disable the AsyncFlip performance optimisations in order
         * to use MI_WAIT_FOR_EVENT within the CS. It should already be
         * programmed to '1' on all products.
         *
-        * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv
+        * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv,bdw
         */
        if (INTEL_INFO(dev)->gen >= 6)
                I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
@@ -625,7 +637,7 @@ static void render_ring_cleanup(struct intel_ring_buffer *ring)
 
        if (INTEL_INFO(dev)->gen >= 5) {
                kunmap(sg_page(ring->scratch.obj->pages->sgl));
-               i915_gem_object_unpin(ring->scratch.obj);
+               i915_gem_object_ggtt_unpin(ring->scratch.obj);
        }
 
        drm_gem_object_unreference(&ring->scratch.obj->base);
@@ -809,8 +821,11 @@ gen6_ring_get_seqno(struct intel_ring_buffer *ring, bool lazy_coherency)
        /* Workaround to force correct ordering between irq and seqno writes on
         * ivb (and maybe also on snb) by reading from a CS register (like
         * ACTHD) before reading the status page. */
-       if (!lazy_coherency)
-               intel_ring_get_active_head(ring);
+       if (!lazy_coherency) {
+               struct drm_i915_private *dev_priv = ring->dev->dev_private;
+               POSTING_READ(RING_ACTHD(ring->mmio_base));
+       }
+
        return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
 }
 
@@ -842,7 +857,7 @@ static bool
 gen5_ring_get_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
 
        if (!dev->irq_enabled)
@@ -860,7 +875,7 @@ static void
 gen5_ring_put_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
@@ -873,7 +888,7 @@ static bool
 i9xx_ring_get_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
 
        if (!dev->irq_enabled)
@@ -894,7 +909,7 @@ static void
 i9xx_ring_put_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
@@ -910,7 +925,7 @@ static bool
 i8xx_ring_get_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
 
        if (!dev->irq_enabled)
@@ -931,7 +946,7 @@ static void
 i8xx_ring_put_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
@@ -946,7 +961,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring)
 void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
        u32 mmio = 0;
 
        /* The ring status page addresses are no longer next to the rest of
@@ -977,9 +992,19 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
        I915_WRITE(mmio, (u32)ring->status_page.gfx_addr);
        POSTING_READ(mmio);
 
-       /* Flush the TLB for this page */
-       if (INTEL_INFO(dev)->gen >= 6) {
+       /*
+        * Flush the TLB for this page
+        *
+        * FIXME: These two bits have disappeared on gen8, so a question
+        * arises: do we still need this and if so how should we go about
+        * invalidating the TLB?
+        */
+       if (INTEL_INFO(dev)->gen >= 6 && INTEL_INFO(dev)->gen < 8) {
                u32 reg = RING_INSTPM(ring->mmio_base);
+
+               /* ring should be idle before issuing a sync flush*/
+               WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
+
                I915_WRITE(reg,
                           _MASKED_BIT_ENABLE(INSTPM_TLB_INVALIDATE |
                                              INSTPM_SYNC_FLUSH));
@@ -1029,7 +1054,7 @@ static bool
 gen6_ring_get_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
 
        if (!dev->irq_enabled)
@@ -1054,7 +1079,7 @@ static void
 gen6_ring_put_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long flags;
 
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
@@ -1253,7 +1278,7 @@ static void cleanup_status_page(struct intel_ring_buffer *ring)
                return;
 
        kunmap(sg_page(obj->pages->sgl));
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
        drm_gem_object_unreference(&obj->base);
        ring->status_page.obj = NULL;
 }
@@ -1271,12 +1296,13 @@ static int init_status_page(struct intel_ring_buffer *ring)
                goto err;
        }
 
-       i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
+       ret = i915_gem_object_set_cache_level(obj, I915_CACHE_LLC);
+       if (ret)
+               goto err_unref;
 
-       ret = i915_gem_obj_ggtt_pin(obj, 4096, true, false);
-       if (ret != 0) {
+       ret = i915_gem_obj_ggtt_pin(obj, 4096, 0);
+       if (ret)
                goto err_unref;
-       }
 
        ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(obj);
        ring->status_page.page_addr = kmap(sg_page(obj->pages->sgl));
@@ -1293,7 +1319,7 @@ static int init_status_page(struct intel_ring_buffer *ring)
        return 0;
 
 err_unpin:
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
 err_unref:
        drm_gem_object_unreference(&obj->base);
 err:
@@ -1356,7 +1382,7 @@ static int intel_init_ring_buffer(struct drm_device *dev,
 
        ring->obj = obj;
 
-       ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, true, false);
+       ret = i915_gem_obj_ggtt_pin(obj, PAGE_SIZE, PIN_MAPPABLE);
        if (ret)
                goto err_unref;
 
@@ -1385,12 +1411,14 @@ static int intel_init_ring_buffer(struct drm_device *dev,
        if (IS_I830(ring->dev) || IS_845G(ring->dev))
                ring->effective_size -= 128;
 
+       i915_cmd_parser_init_ring(ring);
+
        return 0;
 
 err_unmap:
        iounmap(ring->virtual_start);
 err_unpin:
-       i915_gem_object_unpin(obj);
+       i915_gem_object_ggtt_unpin(obj);
 err_unref:
        drm_gem_object_unreference(&obj->base);
        ring->obj = NULL;
@@ -1418,7 +1446,7 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
 
        iounmap(ring->virtual_start);
 
-       i915_gem_object_unpin(ring->obj);
+       i915_gem_object_ggtt_unpin(ring->obj);
        drm_gem_object_unreference(&ring->obj->base);
        ring->obj = NULL;
        ring->preallocated_lazy_request = NULL;
@@ -1430,28 +1458,16 @@ void intel_cleanup_ring_buffer(struct intel_ring_buffer *ring)
        cleanup_status_page(ring);
 }
 
-static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno)
-{
-       int ret;
-
-       ret = i915_wait_seqno(ring, seqno);
-       if (!ret)
-               i915_gem_retire_requests_ring(ring);
-
-       return ret;
-}
-
 static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n)
 {
        struct drm_i915_gem_request *request;
-       u32 seqno = 0;
+       u32 seqno = 0, tail;
        int ret;
 
-       i915_gem_retire_requests_ring(ring);
-
        if (ring->last_retired_head != -1) {
                ring->head = ring->last_retired_head;
                ring->last_retired_head = -1;
+
                ring->space = ring_space(ring);
                if (ring->space >= n)
                        return 0;
@@ -1468,6 +1484,7 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n)
                        space += ring->size;
                if (space >= n) {
                        seqno = request->seqno;
+                       tail = request->tail;
                        break;
                }
 
@@ -1482,15 +1499,11 @@ static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n)
        if (seqno == 0)
                return -ENOSPC;
 
-       ret = intel_ring_wait_seqno(ring, seqno);
+       ret = i915_wait_seqno(ring, seqno);
        if (ret)
                return ret;
 
-       if (WARN_ON(ring->last_retired_head == -1))
-               return -ENOSPC;
-
-       ring->head = ring->last_retired_head;
-       ring->last_retired_head = -1;
+       ring->head = tail;
        ring->space = ring_space(ring);
        if (WARN_ON(ring->space < n))
                return -ENOSPC;
@@ -1528,7 +1541,8 @@ static int ring_wait_for_space(struct intel_ring_buffer *ring, int n)
                        return 0;
                }
 
-               if (dev->primary->master) {
+               if (!drm_core_check_feature(dev, DRIVER_MODESET) &&
+                   dev->primary->master) {
                        struct drm_i915_master_private *master_priv = dev->primary->master->driver_priv;
                        if (master_priv->sarea_priv)
                                master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
@@ -1632,7 +1646,7 @@ static int __intel_ring_prepare(struct intel_ring_buffer *ring,
 int intel_ring_begin(struct intel_ring_buffer *ring,
                     int num_dwords)
 {
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
        int ret;
 
        ret = i915_gem_check_wedge(&dev_priv->gpu_error,
@@ -1694,7 +1708,7 @@ void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno)
 static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
                                     u32 value)
 {
-       drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
 
        /* Every tail move must follow the sequence below */
 
@@ -1869,7 +1883,7 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring,
 
 int intel_init_render_ring_buffer(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
 
        ring->name = "render ring";
@@ -1954,7 +1968,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
                        return -ENOMEM;
                }
 
-               ret = i915_gem_obj_ggtt_pin(obj, 0, true, false);
+               ret = i915_gem_obj_ggtt_pin(obj, 0, 0);
                if (ret != 0) {
                        drm_gem_object_unreference(&obj->base);
                        DRM_ERROR("Failed to ping batch bo\n");
@@ -1970,7 +1984,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
 
 int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[RCS];
        int ret;
 
@@ -2038,7 +2052,7 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
 
 int intel_init_bsd_ring_buffer(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[VCS];
 
        ring->name = "bsd ring";
@@ -2101,7 +2115,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
 
 int intel_init_blt_ring_buffer(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[BCS];
 
        ring->name = "blitter ring";
@@ -2141,7 +2155,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
 
 int intel_init_vebox_ring_buffer(struct drm_device *dev)
 {
-       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *ring = &dev_priv->ring[VECS];
 
        ring->name = "video enhancement ring";
index 0b243ce..270a6a9 100644 (file)
@@ -33,6 +33,8 @@ struct  intel_hw_status_page {
 #define I915_READ_IMR(ring) I915_READ(RING_IMR((ring)->mmio_base))
 #define I915_WRITE_IMR(ring, val) I915_WRITE(RING_IMR((ring)->mmio_base), val)
 
+#define I915_READ_MODE(ring) I915_READ(RING_MI_MODE((ring)->mmio_base))
+
 enum intel_ring_hangcheck_action {
        HANGCHECK_IDLE = 0,
        HANGCHECK_WAIT,
@@ -41,12 +43,14 @@ enum intel_ring_hangcheck_action {
        HANGCHECK_HUNG,
 };
 
+#define HANGCHECK_SCORE_RING_HUNG 31
+
 struct intel_ring_hangcheck {
-       bool deadlock;
+       u64 acthd;
        u32 seqno;
-       u32 acthd;
        int score;
        enum intel_ring_hangcheck_action action;
+       bool deadlock;
 };
 
 struct  intel_ring_buffer {
@@ -162,6 +166,38 @@ struct  intel_ring_buffer {
                u32 gtt_offset;
                volatile u32 *cpu_page;
        } scratch;
+
+       /*
+        * Tables of commands the command parser needs to know about
+        * for this ring.
+        */
+       const struct drm_i915_cmd_table *cmd_tables;
+       int cmd_table_count;
+
+       /*
+        * Table of registers allowed in commands that read/write registers.
+        */
+       const u32 *reg_table;
+       int reg_count;
+
+       /*
+        * Table of registers allowed in commands that read/write registers, but
+        * only from the DRM master.
+        */
+       const u32 *master_reg_table;
+       int master_reg_count;
+
+       /*
+        * Returns the bitmask for the length field of the specified command.
+        * Return 0 for an unrecognized/invalid command.
+        *
+        * If the command parser finds an entry for a command in the ring's
+        * cmd_tables, it gets the command's length based on the table entry.
+        * If not, it calls this function to determine the per-ring length field
+        * encoding for the command (i.e. certain opcode ranges use certain bits
+        * to encode the command length in the header).
+        */
+       u32 (*get_cmd_length_mask)(u32 cmd_header);
 };
 
 static inline bool
@@ -256,7 +292,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev);
 int intel_init_blt_ring_buffer(struct drm_device *dev);
 int intel_init_vebox_ring_buffer(struct drm_device *dev);
 
-u32 intel_ring_get_active_head(struct intel_ring_buffer *ring);
+u64 intel_ring_get_active_head(struct intel_ring_buffer *ring);
 void intel_ring_setup_status_page(struct intel_ring_buffer *ring);
 
 static inline u32 intel_ring_get_tail(struct intel_ring_buffer *ring)
index 95bdfb3..d27155a 100644 (file)
@@ -1461,7 +1461,7 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
        u32 temp;
        bool input1, input2;
        int i;
-       u8 status;
+       bool success;
 
        temp = I915_READ(intel_sdvo->sdvo_reg);
        if ((temp & SDVO_ENABLE) == 0) {
@@ -1475,12 +1475,12 @@ static void intel_enable_sdvo(struct intel_encoder *encoder)
        for (i = 0; i < 2; i++)
                intel_wait_for_vblank(dev, intel_crtc->pipe);
 
-       status = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
+       success = intel_sdvo_get_trained_inputs(intel_sdvo, &input1, &input2);
        /* Warn if the device reported failure to sync.
         * A lot of SDVO devices fail to notify of sync, but it's
         * a given it the status is a success, we succeeded.
         */
-       if (status == SDVO_CMD_STATUS_SUCCESS && !input1) {
+       if (success && !input1) {
                DRM_DEBUG_KMS("First %s output reported failure to "
                                "sync\n", SDVO_NAME(intel_sdvo));
        }
@@ -2382,24 +2382,62 @@ intel_sdvo_get_slave_addr(struct drm_device *dev, struct intel_sdvo *sdvo)
 }
 
 static void
+intel_sdvo_connector_unregister(struct intel_connector *intel_connector)
+{
+       struct drm_connector *drm_connector;
+       struct intel_sdvo *sdvo_encoder;
+
+       drm_connector = &intel_connector->base;
+       sdvo_encoder = intel_attached_sdvo(&intel_connector->base);
+
+       sysfs_remove_link(&drm_connector->kdev->kobj,
+                         sdvo_encoder->ddc.dev.kobj.name);
+       intel_connector_unregister(intel_connector);
+}
+
+static int
 intel_sdvo_connector_init(struct intel_sdvo_connector *connector,
                          struct intel_sdvo *encoder)
 {
-       drm_connector_init(encoder->base.base.dev,
-                          &connector->base.base,
+       struct drm_connector *drm_connector;
+       int ret;
+
+       drm_connector = &connector->base.base;
+       ret = drm_connector_init(encoder->base.base.dev,
+                          drm_connector,
                           &intel_sdvo_connector_funcs,
                           connector->base.base.connector_type);
+       if (ret < 0)
+               return ret;
 
-       drm_connector_helper_add(&connector->base.base,
+       drm_connector_helper_add(drm_connector,
                                 &intel_sdvo_connector_helper_funcs);
 
        connector->base.base.interlace_allowed = 1;
        connector->base.base.doublescan_allowed = 0;
        connector->base.base.display_info.subpixel_order = SubPixelHorizontalRGB;
        connector->base.get_hw_state = intel_sdvo_connector_get_hw_state;
+       connector->base.unregister = intel_sdvo_connector_unregister;
 
        intel_connector_attach_encoder(&connector->base, &encoder->base);
-       drm_sysfs_connector_add(&connector->base.base);
+       ret = drm_sysfs_connector_add(drm_connector);
+       if (ret < 0)
+               goto err1;
+
+       ret = sysfs_create_link(&encoder->ddc.dev.kobj,
+                               &drm_connector->kdev->kobj,
+                               encoder->ddc.dev.kobj.name);
+       if (ret < 0)
+               goto err2;
+
+       return 0;
+
+err2:
+       drm_sysfs_connector_remove(drm_connector);
+err1:
+       drm_connector_cleanup(drm_connector);
+
+       return ret;
 }
 
 static void
@@ -2459,7 +2497,11 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
                intel_sdvo->is_hdmi = true;
        }
 
-       intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
+               kfree(intel_sdvo_connector);
+               return false;
+       }
+
        if (intel_sdvo->is_hdmi)
                intel_sdvo_add_hdmi_properties(intel_sdvo, intel_sdvo_connector);
 
@@ -2490,7 +2532,10 @@ intel_sdvo_tv_init(struct intel_sdvo *intel_sdvo, int type)
 
        intel_sdvo->is_tv = true;
 
-       intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
+               kfree(intel_sdvo_connector);
+               return false;
+       }
 
        if (!intel_sdvo_tv_create_property(intel_sdvo, intel_sdvo_connector, type))
                goto err;
@@ -2534,8 +2579,11 @@ intel_sdvo_analog_init(struct intel_sdvo *intel_sdvo, int device)
                intel_sdvo_connector->output_flag = SDVO_OUTPUT_RGB1;
        }
 
-       intel_sdvo_connector_init(intel_sdvo_connector,
-                                 intel_sdvo);
+       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
+               kfree(intel_sdvo_connector);
+               return false;
+       }
+
        return true;
 }
 
@@ -2566,7 +2614,11 @@ intel_sdvo_lvds_init(struct intel_sdvo *intel_sdvo, int device)
                intel_sdvo_connector->output_flag = SDVO_OUTPUT_LVDS1;
        }
 
-       intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo);
+       if (intel_sdvo_connector_init(intel_sdvo_connector, intel_sdvo) < 0) {
+               kfree(intel_sdvo_connector);
+               return false;
+       }
+
        if (!intel_sdvo_create_enhance_property(intel_sdvo, intel_sdvo_connector))
                goto err;
 
@@ -2980,7 +3032,7 @@ bool intel_sdvo_init(struct drm_device *dev, uint32_t sdvo_reg, bool is_sdvob)
         * simplistic anyway to express such constraints, so just give up on
         * cloning for SDVO encoders.
         */
-       intel_sdvo->base.cloneable = false;
+       intel_sdvo->base.cloneable = 0;
 
        intel_sdvo_select_ddc_bus(dev_priv, intel_sdvo, sdvo_reg);
 
index 716a3c9..336ae6c 100644 (file)
@@ -124,9 +124,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
        crtc_w--;
        crtc_h--;
 
-       I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
-       I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
-
        linear_offset = y * fb->pitches[0] + x * pixel_size;
        sprsurf_offset = intel_gen4_compute_page_offset(&x, &y,
                                                        obj->tiling_mode,
@@ -134,6 +131,9 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
                                                        fb->pitches[0]);
        linear_offset -= sprsurf_offset;
 
+       I915_WRITE(SPSTRIDE(pipe, plane), fb->pitches[0]);
+       I915_WRITE(SPPOS(pipe, plane), (crtc_y << 16) | crtc_x);
+
        if (obj->tiling_mode != I915_TILING_NONE)
                I915_WRITE(SPTILEOFF(pipe, plane), (y << 16) | x);
        else
@@ -293,15 +293,15 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        if (crtc_w != src_w || crtc_h != src_h)
                sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
 
-       I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
-       I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
-
        linear_offset = y * fb->pitches[0] + x * pixel_size;
        sprsurf_offset =
                intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
                                               pixel_size, fb->pitches[0]);
        linear_offset -= sprsurf_offset;
 
+       I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
+       I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
+
        /* HSW consolidates SPRTILEOFF and SPRLINOFF into a single SPROFFSET
         * register */
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
@@ -472,15 +472,15 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        if (crtc_w != src_w || crtc_h != src_h)
                dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
 
-       I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
-       I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
-
        linear_offset = y * fb->pitches[0] + x * pixel_size;
        dvssurf_offset =
                intel_gen4_compute_page_offset(&x, &y, obj->tiling_mode,
                                               pixel_size, fb->pitches[0]);
        linear_offset -= dvssurf_offset;
 
+       I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
+       I915_WRITE(DVSPOS(pipe), (crtc_y << 16) | crtc_x);
+
        if (obj->tiling_mode != I915_TILING_NONE)
                I915_WRITE(DVSTILEOFF(pipe), (y << 16) | x);
        else
index 22cf0f4..bafe92e 100644 (file)
@@ -1189,8 +1189,8 @@ intel_tv_detect_type(struct intel_tv *intel_tv,
        if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
                i915_disable_pipestat(dev_priv, 0,
-                                     PIPE_HOTPLUG_INTERRUPT_ENABLE |
-                                     PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+                                     PIPE_HOTPLUG_INTERRUPT_STATUS |
+                                     PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
        }
 
@@ -1266,8 +1266,8 @@ intel_tv_detect_type(struct intel_tv *intel_tv,
        if (connector->polled & DRM_CONNECTOR_POLL_HPD) {
                spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
                i915_enable_pipestat(dev_priv, 0,
-                                    PIPE_HOTPLUG_INTERRUPT_ENABLE |
-                                    PIPE_HOTPLUG_TV_INTERRUPT_ENABLE);
+                                    PIPE_HOTPLUG_INTERRUPT_STATUS |
+                                    PIPE_HOTPLUG_TV_INTERRUPT_STATUS);
                spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
        }
 
@@ -1536,9 +1536,14 @@ static int tv_is_present_in_vbt(struct drm_device *dev)
                /*
                 * If the device type is not TV, continue.
                 */
-               if (p_child->old.device_type != DEVICE_TYPE_INT_TV &&
-                       p_child->old.device_type != DEVICE_TYPE_TV)
+               switch (p_child->old.device_type) {
+               case DEVICE_TYPE_INT_TV:
+               case DEVICE_TYPE_TV:
+               case DEVICE_TYPE_TV_SVIDEO_COMPOSITE:
+                       break;
+               default:
                        continue;
+               }
                /* Only when the addin_offset is non-zero, it is regarded
                 * as present.
                 */
@@ -1634,13 +1639,13 @@ intel_tv_init(struct drm_device *dev)
        intel_encoder->disable = intel_disable_tv;
        intel_encoder->get_hw_state = intel_tv_get_hw_state;
        intel_connector->get_hw_state = intel_connector_get_hw_state;
+       intel_connector->unregister = intel_connector_unregister;
 
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        intel_encoder->type = INTEL_OUTPUT_TVOUT;
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
-       intel_encoder->cloneable = false;
+       intel_encoder->cloneable = 0;
        intel_encoder->base.possible_crtcs = ((1 << 0) | (1 << 1));
-       intel_encoder->base.possible_clones = (1 << INTEL_OUTPUT_TVOUT);
        intel_tv->type = DRM_MODE_CONNECTOR_Unknown;
 
        /* BIOS margin values */
index 87df68f..f729dc7 100644 (file)
 
 #define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32(dev_priv__, reg__)
 
+static void
+assert_device_not_suspended(struct drm_i915_private *dev_priv)
+{
+       WARN(HAS_RUNTIME_PM(dev_priv->dev) && dev_priv->pm.suspended,
+            "Device suspended\n");
+}
 
 static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv)
 {
@@ -83,14 +89,14 @@ static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv,
        __gen6_gt_wait_for_thread_c0(dev_priv);
 }
 
-static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv)
+static void __gen7_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,
+static void __gen7_gt_force_wake_mt_get(struct drm_i915_private *dev_priv,
                                                        int fw_engine)
 {
        u32 forcewake_ack;
@@ -136,14 +142,16 @@ static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv,
        gen6_gt_check_fifodbg(dev_priv);
 }
 
-static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv,
+static void __gen7_gt_force_wake_mt_put(struct drm_i915_private *dev_priv,
                                                        int fw_engine)
 {
        __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);
+
+       if (IS_GEN7(dev_priv->dev))
+               gen6_gt_check_fifodbg(dev_priv);
 }
 
 static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
@@ -251,16 +259,16 @@ void vlv_force_wake_get(struct drm_i915_private *dev_priv,
        unsigned long irqflags;
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-       if (FORCEWAKE_RENDER & fw_engine) {
-               if (dev_priv->uncore.fw_rendercount++ == 0)
-                       dev_priv->uncore.funcs.force_wake_get(dev_priv,
-                                                       FORCEWAKE_RENDER);
-       }
-       if (FORCEWAKE_MEDIA & fw_engine) {
-               if (dev_priv->uncore.fw_mediacount++ == 0)
-                       dev_priv->uncore.funcs.force_wake_get(dev_priv,
-                                                       FORCEWAKE_MEDIA);
-       }
+
+       if (fw_engine & FORCEWAKE_RENDER &&
+           dev_priv->uncore.fw_rendercount++ != 0)
+               fw_engine &= ~FORCEWAKE_RENDER;
+       if (fw_engine & FORCEWAKE_MEDIA &&
+           dev_priv->uncore.fw_mediacount++ != 0)
+               fw_engine &= ~FORCEWAKE_MEDIA;
+
+       if (fw_engine)
+               dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_engine);
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
@@ -272,46 +280,89 @@ void vlv_force_wake_put(struct drm_i915_private *dev_priv,
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
 
-       if (FORCEWAKE_RENDER & fw_engine) {
-               WARN_ON(dev_priv->uncore.fw_rendercount == 0);
-               if (--dev_priv->uncore.fw_rendercount == 0)
-                       dev_priv->uncore.funcs.force_wake_put(dev_priv,
-                                                       FORCEWAKE_RENDER);
+       if (fw_engine & FORCEWAKE_RENDER) {
+               WARN_ON(!dev_priv->uncore.fw_rendercount);
+               if (--dev_priv->uncore.fw_rendercount != 0)
+                       fw_engine &= ~FORCEWAKE_RENDER;
        }
 
-       if (FORCEWAKE_MEDIA & fw_engine) {
-               WARN_ON(dev_priv->uncore.fw_mediacount == 0);
-               if (--dev_priv->uncore.fw_mediacount == 0)
-                       dev_priv->uncore.funcs.force_wake_put(dev_priv,
-                                                       FORCEWAKE_MEDIA);
+       if (fw_engine & FORCEWAKE_MEDIA) {
+               WARN_ON(!dev_priv->uncore.fw_mediacount);
+               if (--dev_priv->uncore.fw_mediacount != 0)
+                       fw_engine &= ~FORCEWAKE_MEDIA;
        }
 
+       if (fw_engine)
+               dev_priv->uncore.funcs.force_wake_put(dev_priv, fw_engine);
+
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
-static void gen6_force_wake_work(struct work_struct *work)
+static void gen6_force_wake_timer(unsigned long arg)
 {
-       struct drm_i915_private *dev_priv =
-               container_of(work, typeof(*dev_priv), uncore.force_wake_work.work);
+       struct drm_i915_private *dev_priv = (void *)arg;
        unsigned long irqflags;
 
+       assert_device_not_suspended(dev_priv);
+
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       WARN_ON(!dev_priv->uncore.forcewake_count);
+
        if (--dev_priv->uncore.forcewake_count == 0)
                dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+
+       intel_runtime_pm_put(dev_priv);
 }
 
-static void intel_uncore_forcewake_reset(struct drm_device *dev)
+static void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long irqflags;
 
-       if (IS_VALLEYVIEW(dev)) {
+       del_timer_sync(&dev_priv->uncore.force_wake_timer);
+
+       /* Hold uncore.lock across reset to prevent any register access
+        * with forcewake not set correctly
+        */
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+       if (IS_VALLEYVIEW(dev))
                vlv_force_wake_reset(dev_priv);
-       } else if (INTEL_INFO(dev)->gen >= 6) {
+       else if (IS_GEN6(dev) || IS_GEN7(dev))
                __gen6_gt_force_wake_reset(dev_priv);
-               if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
-                       __gen6_gt_force_wake_mt_reset(dev_priv);
+
+       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_GEN8(dev))
+               __gen7_gt_force_wake_mt_reset(dev_priv);
+
+       if (restore) { /* If reset with a user forcewake, try to restore */
+               unsigned fw = 0;
+
+               if (IS_VALLEYVIEW(dev)) {
+                       if (dev_priv->uncore.fw_rendercount)
+                               fw |= FORCEWAKE_RENDER;
+
+                       if (dev_priv->uncore.fw_mediacount)
+                               fw |= FORCEWAKE_MEDIA;
+               } else {
+                       if (dev_priv->uncore.forcewake_count)
+                               fw = FORCEWAKE_ALL;
+               }
+
+               if (fw)
+                       dev_priv->uncore.funcs.force_wake_get(dev_priv, fw);
+
+               if (IS_GEN6(dev) || IS_GEN7(dev))
+                       dev_priv->uncore.fifo_count =
+                               __raw_i915_read32(dev_priv, GTFIFOCTL) &
+                               GT_FIFO_FREE_ENTRIES_MASK;
+       } else {
+               dev_priv->uncore.forcewake_count = 0;
+               dev_priv->uncore.fw_rendercount = 0;
+               dev_priv->uncore.fw_mediacount = 0;
        }
+
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
 void intel_uncore_early_sanitize(struct drm_device *dev)
@@ -337,7 +388,7 @@ void intel_uncore_early_sanitize(struct drm_device *dev)
                __raw_i915_write32(dev_priv, GTFIFODBG,
                                   __raw_i915_read32(dev_priv, GTFIFODBG));
 
-       intel_uncore_forcewake_reset(dev);
+       intel_uncore_forcewake_reset(dev, false);
 }
 
 void intel_uncore_sanitize(struct drm_device *dev)
@@ -354,7 +405,9 @@ void intel_uncore_sanitize(struct drm_device *dev)
                mutex_lock(&dev_priv->rps.hw_lock);
                reg_val = vlv_punit_read(dev_priv, PUNIT_REG_PWRGT_STATUS);
 
-               if (reg_val & (RENDER_PWRGT | MEDIA_PWRGT | DISP2D_PWRGT))
+               if (reg_val & (PUNIT_PWRGT_PWR_GATE(PUNIT_POWER_WELL_RENDER) |
+                              PUNIT_PWRGT_PWR_GATE(PUNIT_POWER_WELL_MEDIA) |
+                              PUNIT_PWRGT_PWR_GATE(PUNIT_POWER_WELL_DISP2D)))
                        vlv_punit_write(dev_priv, PUNIT_REG_PWRGT_CTRL, 0x0);
 
                mutex_unlock(&dev_priv->rps.hw_lock);
@@ -393,25 +446,40 @@ void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
 void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
 {
        unsigned long irqflags;
+       bool delayed = false;
 
        if (!dev_priv->uncore.funcs.force_wake_put)
                return;
 
        /* Redirect to VLV specific routine */
-       if (IS_VALLEYVIEW(dev_priv->dev))
-               return vlv_force_wake_put(dev_priv, fw_engine);
+       if (IS_VALLEYVIEW(dev_priv->dev)) {
+               vlv_force_wake_put(dev_priv, fw_engine);
+               goto out;
+       }
 
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       WARN_ON(!dev_priv->uncore.forcewake_count);
+
        if (--dev_priv->uncore.forcewake_count == 0) {
                dev_priv->uncore.forcewake_count++;
-               mod_delayed_work(dev_priv->wq,
-                                &dev_priv->uncore.force_wake_work,
-                                1);
+               delayed = true;
+               mod_timer_pinned(&dev_priv->uncore.force_wake_timer,
+                                jiffies + 1);
        }
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 
-       intel_runtime_pm_put(dev_priv);
+out:
+       if (!delayed)
+               intel_runtime_pm_put(dev_priv);
+}
+
+void assert_force_wake_inactive(struct drm_i915_private *dev_priv)
+{
+       if (!dev_priv->uncore.funcs.force_wake_get)
+               return;
+
+       WARN_ON(dev_priv->uncore.forcewake_count > 0);
 }
 
 /* We give fast paths for the really cool registers */
@@ -446,16 +514,10 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
        }
 }
 
-static void
-assert_device_not_suspended(struct drm_i915_private *dev_priv)
-{
-       WARN(HAS_RUNTIME_PM(dev_priv->dev) && dev_priv->pm.suspended,
-            "Device suspended\n");
-}
-
 #define REG_READ_HEADER(x) \
        unsigned long irqflags; \
        u##x val = 0; \
+       assert_device_not_suspended(dev_priv); \
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
 
 #define REG_READ_FOOTER \
@@ -484,14 +546,13 @@ gen5_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
 static u##x \
 gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
        REG_READ_HEADER(x); \
-       if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
-               if (dev_priv->uncore.forcewake_count == 0) \
-                       dev_priv->uncore.funcs.force_wake_get(dev_priv, \
-                                                       FORCEWAKE_ALL); \
+       if (dev_priv->uncore.forcewake_count == 0 && \
+           NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
+               dev_priv->uncore.funcs.force_wake_get(dev_priv, \
+                                                     FORCEWAKE_ALL); \
                val = __raw_i915_read##x(dev_priv, reg); \
-               if (dev_priv->uncore.forcewake_count == 0) \
-                       dev_priv->uncore.funcs.force_wake_put(dev_priv, \
-                                                       FORCEWAKE_ALL); \
+               dev_priv->uncore.funcs.force_wake_put(dev_priv, \
+                                                     FORCEWAKE_ALL); \
        } else { \
                val = __raw_i915_read##x(dev_priv, reg); \
        } \
@@ -502,27 +563,19 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
 static u##x \
 vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
        unsigned fwengine = 0; \
-       unsigned *fwcount; \
        REG_READ_HEADER(x); \
-       if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) {   \
-               fwengine = FORCEWAKE_RENDER;            \
-               fwcount = &dev_priv->uncore.fw_rendercount;    \
-       }                                               \
-       else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) {       \
-               fwengine = FORCEWAKE_MEDIA;             \
-               fwcount = &dev_priv->uncore.fw_mediacount;     \
+       if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) { \
+               if (dev_priv->uncore.fw_rendercount == 0) \
+                       fwengine = FORCEWAKE_RENDER; \
+       } else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) { \
+               if (dev_priv->uncore.fw_mediacount == 0) \
+                       fwengine = FORCEWAKE_MEDIA; \
        }  \
-       if (fwengine != 0) {            \
-               if ((*fwcount)++ == 0) \
-                       (dev_priv)->uncore.funcs.force_wake_get(dev_priv, \
-                                                               fwengine); \
-               val = __raw_i915_read##x(dev_priv, reg); \
-               if (--(*fwcount) == 0) \
-                       (dev_priv)->uncore.funcs.force_wake_put(dev_priv, \
-                                                       fwengine); \
-       } else { \
-               val = __raw_i915_read##x(dev_priv, reg); \
-       } \
+       if (fwengine) \
+               dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \
+       val = __raw_i915_read##x(dev_priv, reg); \
+       if (fwengine) \
+               dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \
        REG_READ_FOOTER; \
 }
 
@@ -554,6 +607,7 @@ __gen4_read(64)
 #define REG_WRITE_HEADER \
        unsigned long irqflags; \
        trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
+       assert_device_not_suspended(dev_priv); \
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
 
 #define REG_WRITE_FOOTER \
@@ -584,7 +638,6 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
                __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
        } \
-       assert_device_not_suspended(dev_priv); \
        __raw_i915_write##x(dev_priv, reg, val); \
        if (unlikely(__fifo_ret)) { \
                gen6_gt_check_fifodbg(dev_priv); \
@@ -600,7 +653,6 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace)
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
                __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
        } \
-       assert_device_not_suspended(dev_priv); \
        hsw_unclaimed_reg_clear(dev_priv, reg); \
        __raw_i915_write##x(dev_priv, reg, val); \
        if (unlikely(__fifo_ret)) { \
@@ -634,16 +686,17 @@ static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg)
 #define __gen8_write(x) \
 static void \
 gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
-       bool __needs_put = reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg); \
        REG_WRITE_HEADER; \
-       if (__needs_put) { \
-               dev_priv->uncore.funcs.force_wake_get(dev_priv, \
-                                                       FORCEWAKE_ALL); \
-       } \
-       __raw_i915_write##x(dev_priv, reg, val); \
-       if (__needs_put) { \
-               dev_priv->uncore.funcs.force_wake_put(dev_priv, \
-                                                       FORCEWAKE_ALL); \
+       if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) { \
+               if (dev_priv->uncore.forcewake_count == 0) \
+                       dev_priv->uncore.funcs.force_wake_get(dev_priv, \
+                                                             FORCEWAKE_ALL); \
+               __raw_i915_write##x(dev_priv, reg, val); \
+               if (dev_priv->uncore.forcewake_count == 0) \
+                       dev_priv->uncore.funcs.force_wake_put(dev_priv, \
+                                                             FORCEWAKE_ALL); \
+       } else { \
+               __raw_i915_write##x(dev_priv, reg, val); \
        } \
        REG_WRITE_FOOTER; \
 }
@@ -681,15 +734,17 @@ void intel_uncore_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       INIT_DELAYED_WORK(&dev_priv->uncore.force_wake_work,
-                         gen6_force_wake_work);
+       setup_timer(&dev_priv->uncore.force_wake_timer,
+                   gen6_force_wake_timer, (unsigned long)dev_priv);
+
+       intel_uncore_early_sanitize(dev);
 
        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) || IS_GEN8(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;
+               dev_priv->uncore.funcs.force_wake_get = __gen7_gt_force_wake_mt_get;
+               dev_priv->uncore.funcs.force_wake_put = __gen7_gt_force_wake_mt_put;
        } else if (IS_IVYBRIDGE(dev)) {
                u32 ecobus;
 
@@ -703,16 +758,16 @@ void intel_uncore_init(struct drm_device *dev)
                 * forcewake being disabled.
                 */
                mutex_lock(&dev->struct_mutex);
-               __gen6_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL);
+               __gen7_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL);
                ecobus = __raw_i915_read32(dev_priv, ECOBUS);
-               __gen6_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL);
+               __gen7_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL);
                mutex_unlock(&dev->struct_mutex);
 
                if (ecobus & FORCEWAKE_MT_ENABLE) {
                        dev_priv->uncore.funcs.force_wake_get =
-                               __gen6_gt_force_wake_mt_get;
+                               __gen7_gt_force_wake_mt_get;
                        dev_priv->uncore.funcs.force_wake_put =
-                               __gen6_gt_force_wake_mt_put;
+                               __gen7_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");
@@ -792,12 +847,9 @@ void intel_uncore_init(struct drm_device *dev)
 
 void intel_uncore_fini(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       flush_delayed_work(&dev_priv->uncore.force_wake_work);
-
        /* Paranoia: make sure we have disabled everything before we exit. */
        intel_uncore_sanitize(dev);
+       intel_uncore_forcewake_reset(dev, false);
 }
 
 static const struct register_whitelist {
@@ -814,7 +866,7 @@ int i915_reg_read_ioctl(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_reg_read *reg = data;
        struct register_whitelist const *entry = whitelist;
-       int i;
+       int i, ret = 0;
 
        for (i = 0; i < ARRAY_SIZE(whitelist); i++, entry++) {
                if (entry->offset == reg->offset &&
@@ -825,6 +877,8 @@ int i915_reg_read_ioctl(struct drm_device *dev,
        if (i == ARRAY_SIZE(whitelist))
                return -EINVAL;
 
+       intel_runtime_pm_get(dev_priv);
+
        switch (entry->size) {
        case 8:
                reg->val = I915_READ64(reg->offset);
@@ -840,10 +894,13 @@ int i915_reg_read_ioctl(struct drm_device *dev,
                break;
        default:
                WARN_ON(1);
-               return -EINVAL;
+               ret = -EINVAL;
+               goto out;
        }
 
-       return 0;
+out:
+       intel_runtime_pm_put(dev_priv);
+       return ret;
 }
 
 int i915_get_reset_stats_ioctl(struct drm_device *dev,
@@ -852,6 +909,7 @@ int i915_get_reset_stats_ioctl(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_reset_stats *args = data;
        struct i915_ctx_hang_stats *hs;
+       struct i915_hw_context *ctx;
        int ret;
 
        if (args->flags || args->pad)
@@ -864,11 +922,12 @@ int i915_get_reset_stats_ioctl(struct drm_device *dev,
        if (ret)
                return ret;
 
-       hs = i915_gem_context_get_hang_stats(dev, file, args->ctx_id);
-       if (IS_ERR(hs)) {
+       ctx = i915_gem_context_get(file->driver_priv, args->ctx_id);
+       if (IS_ERR(ctx)) {
                mutex_unlock(&dev->struct_mutex);
-               return PTR_ERR(hs);
+               return PTR_ERR(ctx);
        }
+       hs = &ctx->hang_stats;
 
        if (capable(CAP_SYS_ADMIN))
                args->reset_count = i915_reset_count(&dev_priv->gpu_error);
@@ -944,12 +1003,6 @@ 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 */
 
@@ -962,18 +1015,8 @@ static int gen6_do_reset(struct drm_device *dev)
        /* 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);
 
-       intel_uncore_forcewake_reset(dev);
+       intel_uncore_forcewake_reset(dev, true);
 
-       /* 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, FORCEWAKE_ALL);
-       else
-               dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
-
-       /* Restore fifo count */
-       dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK;
-
-       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
        return ret;
 }
 
index 9683747..a034ed4 100644 (file)
@@ -29,7 +29,7 @@ static void mga_crtc_load_lut(struct drm_crtc *crtc)
        struct mga_crtc *mga_crtc = to_mga_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct mga_device *mdev = dev->dev_private;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_framebuffer *fb = crtc->primary->fb;
        int i;
 
        if (!crtc->enabled)
@@ -742,7 +742,7 @@ static int mga_crtc_do_set_base(struct drm_crtc *crtc,
                mgag200_bo_unreserve(bo);
        }
 
-       mga_fb = to_mga_framebuffer(crtc->fb);
+       mga_fb = to_mga_framebuffer(crtc->primary->fb);
        obj = mga_fb->obj;
        bo = gem_to_mga_bo(obj);
 
@@ -805,7 +805,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
                /* 0x48: */        0,    0,    0,    0,    0,    0,    0,    0
        };
 
-       bppshift = mdev->bpp_shifts[(crtc->fb->bits_per_pixel >> 3) - 1];
+       bppshift = mdev->bpp_shifts[(crtc->primary->fb->bits_per_pixel >> 3) - 1];
 
        switch (mdev->type) {
        case G200_SE_A:
@@ -843,12 +843,12 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
                break;
        }
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
                dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_8bits;
                break;
        case 16:
-               if (crtc->fb->depth == 15)
+               if (crtc->primary->fb->depth == 15)
                        dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_15bits;
                else
                        dacvalue[MGA1064_MUL_CTL] = MGA1064_MUL_CTL_16bits;
@@ -896,8 +896,8 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
        WREG_SEQ(3, 0);
        WREG_SEQ(4, 0xe);
 
-       pitch = crtc->fb->pitches[0] / (crtc->fb->bits_per_pixel / 8);
-       if (crtc->fb->bits_per_pixel == 24)
+       pitch = crtc->primary->fb->pitches[0] / (crtc->primary->fb->bits_per_pixel / 8);
+       if (crtc->primary->fb->bits_per_pixel == 24)
                pitch = (pitch * 3) >> (4 - bppshift);
        else
                pitch = pitch >> (4 - bppshift);
@@ -974,7 +974,7 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
                ((vdisplay & 0xc00) >> 7) |
                ((vsyncstart & 0xc00) >> 5) |
                ((vdisplay & 0x400) >> 3);
-       if (crtc->fb->bits_per_pixel == 24)
+       if (crtc->primary->fb->bits_per_pixel == 24)
                ext_vga[3] = (((1 << bppshift) * 3) - 1) | 0x80;
        else
                ext_vga[3] = ((1 << bppshift) - 1) | 0x80;
@@ -1034,9 +1034,9 @@ static int mga_crtc_mode_set(struct drm_crtc *crtc,
                        u32 bpp;
                        u32 mb;
 
-                       if (crtc->fb->bits_per_pixel > 16)
+                       if (crtc->primary->fb->bits_per_pixel > 16)
                                bpp = 32;
-                       else if (crtc->fb->bits_per_pixel > 8)
+                       else if (crtc->primary->fb->bits_per_pixel > 8)
                                bpp = 16;
                        else
                                bpp = 8;
@@ -1277,8 +1277,8 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
        int ret;
        DRM_DEBUG_KMS("\n");
        mga_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-       if (crtc->fb) {
-               struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->fb);
+       if (crtc->primary->fb) {
+               struct mga_framebuffer *mga_fb = to_mga_framebuffer(crtc->primary->fb);
                struct drm_gem_object *obj = mga_fb->obj;
                struct mgag200_bo *bo = gem_to_mga_bo(obj);
                ret = mgag200_bo_reserve(bo, false);
@@ -1287,7 +1287,7 @@ static void mga_crtc_disable(struct drm_crtc *crtc)
                mgag200_bo_push_sysram(bo);
                mgag200_bo_unreserve(bo);
        }
-       crtc->fb = NULL;
+       crtc->primary->fb = NULL;
 }
 
 /* These provide the minimum set of functions required to handle a CRTC */
index adb5166..5a00e90 100644 (file)
@@ -259,7 +259,9 @@ int mgag200_mm_init(struct mga_device *mdev)
 
        ret = ttm_bo_device_init(&mdev->ttm.bdev,
                                 mdev->ttm.bo_global_ref.ref.object,
-                                &mgag200_bo_driver, DRM_FILE_PAGE_OFFSET,
+                                &mgag200_bo_driver,
+                                dev->anon_inode->i_mapping,
+                                DRM_FILE_PAGE_OFFSET,
                                 true);
        if (ret) {
                DRM_ERROR("Error initialising bo driver; %d\n", ret);
@@ -324,7 +326,6 @@ int mgag200_bo_create(struct drm_device *dev, int size, int align,
        }
 
        mgabo->bo.bdev = &mdev->ttm.bdev;
-       mgabo->bo.bdev->dev_mapping = dev->dev_mapping;
 
        mgag200_ttm_placement(mgabo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
 
index 4f977a5..5e1e6b0 100644 (file)
@@ -7,6 +7,7 @@ msm-y := \
        adreno/adreno_gpu.o \
        adreno/a3xx_gpu.o \
        hdmi/hdmi.o \
+       hdmi/hdmi_audio.o \
        hdmi/hdmi_bridge.o \
        hdmi/hdmi_connector.o \
        hdmi/hdmi_i2c.o \
index 461df93..f20fbde 100644 (file)
         A3XX_INT0_CP_AHB_ERROR_HALT |     \
         A3XX_INT0_UCHE_OOB_ACCESS)
 
-static struct platform_device *a3xx_pdev;
+
+static bool hang_debug = false;
+MODULE_PARM_DESC(hang_debug, "Dump registers when hang is detected (can be slow!)");
+module_param_named(hang_debug, hang_debug, bool, 0600);
+static void a3xx_dump(struct msm_gpu *gpu);
 
 static void a3xx_me_init(struct msm_gpu *gpu)
 {
@@ -291,6 +295,9 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
 
 static void a3xx_recover(struct msm_gpu *gpu)
 {
+       /* dump registers before resetting gpu, if enabled: */
+       if (hang_debug)
+               a3xx_dump(gpu);
        gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1);
        gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD);
        gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0);
@@ -311,27 +318,18 @@ static void a3xx_destroy(struct msm_gpu *gpu)
                ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl);
 #endif
 
-       put_device(&a3xx_gpu->pdev->dev);
        kfree(a3xx_gpu);
 }
 
 static void a3xx_idle(struct msm_gpu *gpu)
 {
-       unsigned long t;
-
        /* wait for ringbuffer to drain: */
        adreno_idle(gpu);
 
-       t = jiffies + ADRENO_IDLE_TIMEOUT;
-
        /* then wait for GPU to finish: */
-       do {
-               uint32_t rbbm_status = gpu_read(gpu, REG_A3XX_RBBM_STATUS);
-               if (!(rbbm_status & A3XX_RBBM_STATUS_GPU_BUSY))
-                       return;
-       } while(time_before(jiffies, t));
-
-       DRM_ERROR("timeout waiting for %s to idle!\n", gpu->name);
+       if (spin_until(!(gpu_read(gpu, REG_A3XX_RBBM_STATUS) &
+                       A3XX_RBBM_STATUS_GPU_BUSY)))
+               DRM_ERROR("%s: timeout waiting for GPU to idle!\n", gpu->name);
 
        /* TODO maybe we need to reset GPU here to recover from hang? */
 }
@@ -352,7 +350,6 @@ static irqreturn_t a3xx_irq(struct msm_gpu *gpu)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_DEBUG_FS
 static const unsigned int a3xx_registers[] = {
        0x0000, 0x0002, 0x0010, 0x0012, 0x0018, 0x0018, 0x0020, 0x0027,
        0x0029, 0x002b, 0x002e, 0x0033, 0x0040, 0x0042, 0x0050, 0x005c,
@@ -392,11 +389,18 @@ static const unsigned int a3xx_registers[] = {
        0x303c, 0x303c, 0x305e, 0x305f,
 };
 
+#ifdef CONFIG_DEBUG_FS
 static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
 {
+       struct drm_device *dev = gpu->dev;
        int i;
 
        adreno_show(gpu, m);
+
+       mutex_lock(&dev->struct_mutex);
+
+       gpu->funcs->pm_resume(gpu);
+
        seq_printf(m, "status:   %08x\n",
                        gpu_read(gpu, REG_A3XX_RBBM_STATUS));
 
@@ -412,9 +416,36 @@ static void a3xx_show(struct msm_gpu *gpu, struct seq_file *m)
                        seq_printf(m, "IO:R %08x %08x\n", addr<<2, val);
                }
        }
+
+       gpu->funcs->pm_suspend(gpu);
+
+       mutex_unlock(&dev->struct_mutex);
 }
 #endif
 
+/* would be nice to not have to duplicate the _show() stuff with printk(): */
+static void a3xx_dump(struct msm_gpu *gpu)
+{
+       int i;
+
+       adreno_dump(gpu);
+       printk("status:   %08x\n",
+                       gpu_read(gpu, REG_A3XX_RBBM_STATUS));
+
+       /* dump these out in a form that can be parsed by demsm: */
+       printk("IO:region %s 00000000 00020000\n", gpu->name);
+       for (i = 0; i < ARRAY_SIZE(a3xx_registers); i += 2) {
+               uint32_t start = a3xx_registers[i];
+               uint32_t end   = a3xx_registers[i+1];
+               uint32_t addr;
+
+               for (addr = start; addr <= end; addr++) {
+                       uint32_t val = gpu_read(gpu, addr);
+                       printk("IO:R %08x %08x\n", addr<<2, val);
+               }
+       }
+}
+
 static const struct adreno_gpu_funcs funcs = {
        .base = {
                .get_param = adreno_get_param,
@@ -439,7 +470,8 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
        struct a3xx_gpu *a3xx_gpu = NULL;
        struct adreno_gpu *adreno_gpu;
        struct msm_gpu *gpu;
-       struct platform_device *pdev = a3xx_pdev;
+       struct msm_drm_private *priv = dev->dev_private;
+       struct platform_device *pdev = priv->gpu_pdev;
        struct adreno_platform_config *config;
        int ret;
 
@@ -460,7 +492,6 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
        adreno_gpu = &a3xx_gpu->base;
        gpu = &adreno_gpu->base;
 
-       get_device(&pdev->dev);
        a3xx_gpu->pdev = pdev;
 
        gpu->fast_rate = config->fast_rate;
@@ -522,17 +553,24 @@ fail:
 #  include <mach/kgsl.h>
 #endif
 
-static int a3xx_probe(struct platform_device *pdev)
+static void set_gpu_pdev(struct drm_device *dev,
+               struct platform_device *pdev)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       priv->gpu_pdev = pdev;
+}
+
+static int a3xx_bind(struct device *dev, struct device *master, void *data)
 {
        static struct adreno_platform_config config = {};
 #ifdef CONFIG_OF
-       struct device_node *child, *node = pdev->dev.of_node;
+       struct device_node *child, *node = dev->of_node;
        u32 val;
        int ret;
 
        ret = of_property_read_u32(node, "qcom,chipid", &val);
        if (ret) {
-               dev_err(&pdev->dev, "could not find chipid: %d\n", ret);
+               dev_err(dev, "could not find chipid: %d\n", ret);
                return ret;
        }
 
@@ -548,7 +586,7 @@ static int a3xx_probe(struct platform_device *pdev)
                        for_each_child_of_node(child, pwrlvl) {
                                ret = of_property_read_u32(pwrlvl, "qcom,gpu-freq", &val);
                                if (ret) {
-                                       dev_err(&pdev->dev, "could not find gpu-freq: %d\n", ret);
+                                       dev_err(dev, "could not find gpu-freq: %d\n", ret);
                                        return ret;
                                }
                                config.fast_rate = max(config.fast_rate, val);
@@ -558,12 +596,12 @@ static int a3xx_probe(struct platform_device *pdev)
        }
 
        if (!config.fast_rate) {
-               dev_err(&pdev->dev, "could not find clk rates\n");
+               dev_err(dev, "could not find clk rates\n");
                return -ENXIO;
        }
 
 #else
-       struct kgsl_device_platform_data *pdata = pdev->dev.platform_data;
+       struct kgsl_device_platform_data *pdata = dev->platform_data;
        uint32_t version = socinfo_get_version();
        if (cpu_is_apq8064ab()) {
                config.fast_rate = 450000000;
@@ -609,14 +647,30 @@ static int a3xx_probe(struct platform_device *pdev)
        config.bus_scale_table = pdata->bus_scale_table;
 #  endif
 #endif
-       pdev->dev.platform_data = &config;
-       a3xx_pdev = pdev;
+       dev->platform_data = &config;
+       set_gpu_pdev(dev_get_drvdata(master), to_platform_device(dev));
        return 0;
 }
 
+static void a3xx_unbind(struct device *dev, struct device *master,
+               void *data)
+{
+       set_gpu_pdev(dev_get_drvdata(master), NULL);
+}
+
+static const struct component_ops a3xx_ops = {
+               .bind   = a3xx_bind,
+               .unbind = a3xx_unbind,
+};
+
+static int a3xx_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &a3xx_ops);
+}
+
 static int a3xx_remove(struct platform_device *pdev)
 {
-       a3xx_pdev = NULL;
+       component_del(&pdev->dev, &a3xx_ops);
        return 0;
 }
 
@@ -624,7 +678,6 @@ static const struct of_device_id dt_match[] = {
        { .compatible = "qcom,kgsl-3d0" },
        {}
 };
-MODULE_DEVICE_TABLE(of, dt_match);
 
 static struct platform_driver a3xx_driver = {
        .probe = a3xx_probe,
index d321099..28ca8cd 100644 (file)
@@ -73,6 +73,12 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value)
        case MSM_PARAM_GMEM_SIZE:
                *value = adreno_gpu->gmem;
                return 0;
+       case MSM_PARAM_CHIP_ID:
+               *value = adreno_gpu->rev.patchid |
+                               (adreno_gpu->rev.minor << 8) |
+                               (adreno_gpu->rev.major << 16) |
+                               (adreno_gpu->rev.core << 24);
+               return 0;
        default:
                DBG("%s: invalid param: %u", gpu->name, param);
                return -EINVAL;
@@ -225,19 +231,11 @@ void adreno_flush(struct msm_gpu *gpu)
 void adreno_idle(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
-       uint32_t rptr, wptr = get_wptr(gpu->rb);
-       unsigned long t;
-
-       t = jiffies + ADRENO_IDLE_TIMEOUT;
-
-       /* then wait for CP to drain ringbuffer: */
-       do {
-               rptr = adreno_gpu->memptrs->rptr;
-               if (rptr == wptr)
-                       return;
-       } while(time_before(jiffies, t));
+       uint32_t wptr = get_wptr(gpu->rb);
 
-       DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
+       /* wait for CP to drain ringbuffer: */
+       if (spin_until(adreno_gpu->memptrs->rptr == wptr))
+               DRM_ERROR("%s: timeout waiting to drain ringbuffer!\n", gpu->name);
 
        /* TODO maybe we need to reset GPU here to recover from hang? */
 }
@@ -260,22 +258,37 @@ void adreno_show(struct msm_gpu *gpu, struct seq_file *m)
 }
 #endif
 
-void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
+/* would be nice to not have to duplicate the _show() stuff with printk(): */
+void adreno_dump(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
-       uint32_t freedwords;
-       unsigned long t = jiffies + ADRENO_IDLE_TIMEOUT;
-       do {
-               uint32_t size = gpu->rb->size / 4;
-               uint32_t wptr = get_wptr(gpu->rb);
-               uint32_t rptr = adreno_gpu->memptrs->rptr;
-               freedwords = (rptr + (size - 1) - wptr) % size;
-
-               if (time_after(jiffies, t)) {
-                       DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
-                       break;
-               }
-       } while(freedwords < ndwords);
+
+       printk("revision: %d (%d.%d.%d.%d)\n",
+                       adreno_gpu->info->revn, adreno_gpu->rev.core,
+                       adreno_gpu->rev.major, adreno_gpu->rev.minor,
+                       adreno_gpu->rev.patchid);
+
+       printk("fence:    %d/%d\n", adreno_gpu->memptrs->fence,
+                       gpu->submitted_fence);
+       printk("rptr:     %d\n", adreno_gpu->memptrs->rptr);
+       printk("wptr:     %d\n", adreno_gpu->memptrs->wptr);
+       printk("rb wptr:  %d\n", get_wptr(gpu->rb));
+
+}
+
+static uint32_t ring_freewords(struct msm_gpu *gpu)
+{
+       struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       uint32_t size = gpu->rb->size / 4;
+       uint32_t wptr = get_wptr(gpu->rb);
+       uint32_t rptr = adreno_gpu->memptrs->rptr;
+       return (rptr + (size - 1) - wptr) % size;
+}
+
+void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords)
+{
+       if (spin_until(ring_freewords(gpu) >= ndwords))
+               DRM_ERROR("%s: timeout waiting for ringbuffer space\n", gpu->name);
 }
 
 static const char *iommu_ports[] = {
index ca11ea4..63c36ce 100644 (file)
@@ -76,7 +76,20 @@ struct adreno_platform_config {
 #endif
 };
 
-#define ADRENO_IDLE_TIMEOUT (20 * 1000)
+#define ADRENO_IDLE_TIMEOUT msecs_to_jiffies(1000)
+
+#define spin_until(X) ({                                   \
+       int __ret = -ETIMEDOUT;                            \
+       unsigned long __t = jiffies + ADRENO_IDLE_TIMEOUT; \
+       do {                                               \
+               if (X) {                                   \
+                       __ret = 0;                         \
+                       break;                             \
+               }                                          \
+       } while (time_before(jiffies, __t));               \
+       __ret;                                             \
+})
+
 
 static inline bool adreno_is_a3xx(struct adreno_gpu *gpu)
 {
@@ -114,6 +127,7 @@ void adreno_idle(struct msm_gpu *gpu);
 #ifdef CONFIG_DEBUG_FS
 void adreno_show(struct msm_gpu *gpu, struct seq_file *m);
 #endif
+void adreno_dump(struct msm_gpu *gpu);
 void adreno_wait_ring(struct msm_gpu *gpu, uint32_t ndwords);
 
 int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
index 6f1588a..ae750f6 100644 (file)
@@ -17,8 +17,6 @@
 
 #include "hdmi.h"
 
-static struct platform_device *hdmi_pdev;
-
 void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
 {
        uint32_t ctrl = 0;
@@ -67,7 +65,7 @@ void hdmi_destroy(struct kref *kref)
        if (hdmi->i2c)
                hdmi_i2c_destroy(hdmi->i2c);
 
-       put_device(&hdmi->pdev->dev);
+       platform_set_drvdata(hdmi->pdev, NULL);
 }
 
 /* initialize connector */
@@ -75,7 +73,7 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 {
        struct hdmi *hdmi = NULL;
        struct msm_drm_private *priv = dev->dev_private;
-       struct platform_device *pdev = hdmi_pdev;
+       struct platform_device *pdev = priv->hdmi_pdev;
        struct hdmi_platform_config *config;
        int i, ret;
 
@@ -95,13 +93,13 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 
        kref_init(&hdmi->refcount);
 
-       get_device(&pdev->dev);
-
        hdmi->dev = dev;
        hdmi->pdev = pdev;
        hdmi->config = config;
        hdmi->encoder = encoder;
 
+       hdmi_audio_infoframe_init(&hdmi->audio.infoframe);
+
        /* not sure about which phy maps to which msm.. probably I miss some */
        if (config->phy_init)
                hdmi->phy = config->phy_init(hdmi);
@@ -228,6 +226,8 @@ struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
        priv->bridges[priv->num_bridges++]       = hdmi->bridge;
        priv->connectors[priv->num_connectors++] = hdmi->connector;
 
+       platform_set_drvdata(pdev, hdmi);
+
        return hdmi;
 
 fail:
@@ -249,17 +249,24 @@ fail:
 
 #include <linux/of_gpio.h>
 
-static int hdmi_dev_probe(struct platform_device *pdev)
+static void set_hdmi_pdev(struct drm_device *dev,
+               struct platform_device *pdev)
+{
+       struct msm_drm_private *priv = dev->dev_private;
+       priv->hdmi_pdev = pdev;
+}
+
+static int hdmi_bind(struct device *dev, struct device *master, void *data)
 {
        static struct hdmi_platform_config config = {};
 #ifdef CONFIG_OF
-       struct device_node *of_node = pdev->dev.of_node;
+       struct device_node *of_node = dev->of_node;
 
        int get_gpio(const char *name)
        {
                int gpio = of_get_named_gpio(of_node, name, 0);
                if (gpio < 0) {
-                       dev_err(&pdev->dev, "failed to get gpio: %s (%d)\n",
+                       dev_err(dev, "failed to get gpio: %s (%d)\n",
                                        name, gpio);
                        gpio = -1;
                }
@@ -305,7 +312,7 @@ static int hdmi_dev_probe(struct platform_device *pdev)
                config.ddc_data_gpio = 71;
                config.hpd_gpio      = 72;
                config.mux_en_gpio   = -1;
-               config.mux_sel_gpio  = 13 + NR_GPIO_IRQS;
+               config.mux_sel_gpio  = -1;
        } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
                static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
                config.phy_init      = hdmi_phy_8960_init;
@@ -336,14 +343,30 @@ static int hdmi_dev_probe(struct platform_device *pdev)
                config.mux_sel_gpio  = -1;
        }
 #endif
-       pdev->dev.platform_data = &config;
-       hdmi_pdev = pdev;
+       dev->platform_data = &config;
+       set_hdmi_pdev(dev_get_drvdata(master), to_platform_device(dev));
        return 0;
 }
 
+static void hdmi_unbind(struct device *dev, struct device *master,
+               void *data)
+{
+       set_hdmi_pdev(dev_get_drvdata(master), NULL);
+}
+
+static const struct component_ops hdmi_ops = {
+               .bind   = hdmi_bind,
+               .unbind = hdmi_unbind,
+};
+
+static int hdmi_dev_probe(struct platform_device *pdev)
+{
+       return component_add(&pdev->dev, &hdmi_ops);
+}
+
 static int hdmi_dev_remove(struct platform_device *pdev)
 {
-       hdmi_pdev = NULL;
+       component_del(&pdev->dev, &hdmi_ops);
        return 0;
 }
 
@@ -351,7 +374,6 @@ static const struct of_device_id dt_match[] = {
        { .compatible = "qcom,hdmi-tx" },
        {}
 };
-MODULE_DEVICE_TABLE(of, dt_match);
 
 static struct platform_driver hdmi_driver = {
        .probe = hdmi_dev_probe,
index 41b29ad..9fafee6 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
+#include <linux/hdmi.h>
 
 #include "msm_drv.h"
 #include "hdmi.xml.h"
 struct hdmi_phy;
 struct hdmi_platform_config;
 
+struct hdmi_audio {
+       bool enabled;
+       struct hdmi_audio_infoframe infoframe;
+       int rate;
+};
+
 struct hdmi {
        struct kref refcount;
 
@@ -38,6 +45,13 @@ struct hdmi {
 
        const struct hdmi_platform_config *config;
 
+       /* audio state: */
+       struct hdmi_audio audio;
+
+       /* video state: */
+       bool power_on;
+       unsigned long int pixclock;
+
        void __iomem *mmio;
 
        struct regulator *hpd_regs[2];
@@ -131,6 +145,17 @@ struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi);
 struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi);
 struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi);
 
+/*
+ * audio:
+ */
+
+int hdmi_audio_update(struct hdmi *hdmi);
+int hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
+       uint32_t num_of_channels, uint32_t channel_allocation,
+       uint32_t level_shift, bool down_mix);
+void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
+
+
 /*
  * hdmi bridge:
  */
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_audio.c b/drivers/gpu/drm/msm/hdmi/hdmi_audio.c
new file mode 100644 (file)
index 0000000..872485f
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2013 Red Hat
+ * Author: Rob Clark <robdclark@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/hdmi.h>
+#include "hdmi.h"
+
+
+/* Supported HDMI Audio channels */
+#define MSM_HDMI_AUDIO_CHANNEL_2               0
+#define MSM_HDMI_AUDIO_CHANNEL_4               1
+#define MSM_HDMI_AUDIO_CHANNEL_6               2
+#define MSM_HDMI_AUDIO_CHANNEL_8               3
+
+/* maps MSM_HDMI_AUDIO_CHANNEL_n consts used by audio driver to # of channels: */
+static int nchannels[] = { 2, 4, 6, 8 };
+
+/* Supported HDMI Audio sample rates */
+#define MSM_HDMI_SAMPLE_RATE_32KHZ             0
+#define MSM_HDMI_SAMPLE_RATE_44_1KHZ           1
+#define MSM_HDMI_SAMPLE_RATE_48KHZ             2
+#define MSM_HDMI_SAMPLE_RATE_88_2KHZ           3
+#define MSM_HDMI_SAMPLE_RATE_96KHZ             4
+#define MSM_HDMI_SAMPLE_RATE_176_4KHZ          5
+#define MSM_HDMI_SAMPLE_RATE_192KHZ            6
+#define MSM_HDMI_SAMPLE_RATE_MAX               7
+
+
+struct hdmi_msm_audio_acr {
+       uint32_t n;     /* N parameter for clock regeneration */
+       uint32_t cts;   /* CTS parameter for clock regeneration */
+};
+
+struct hdmi_msm_audio_arcs {
+       unsigned long int pixclock;
+       struct hdmi_msm_audio_acr lut[MSM_HDMI_SAMPLE_RATE_MAX];
+};
+
+#define HDMI_MSM_AUDIO_ARCS(pclk, ...) { (1000 * (pclk)), __VA_ARGS__ }
+
+/* Audio constants lookup table for hdmi_msm_audio_acr_setup */
+/* Valid Pixel-Clock rates: 25.2MHz, 27MHz, 27.03MHz, 74.25MHz, 148.5MHz */
+static const struct hdmi_msm_audio_arcs acr_lut[] = {
+       /*  25.200MHz  */
+       HDMI_MSM_AUDIO_ARCS(25200, {
+               {4096, 25200}, {6272, 28000}, {6144, 25200}, {12544, 28000},
+               {12288, 25200}, {25088, 28000}, {24576, 25200} }),
+       /*  27.000MHz  */
+       HDMI_MSM_AUDIO_ARCS(27000, {
+               {4096, 27000}, {6272, 30000}, {6144, 27000}, {12544, 30000},
+               {12288, 27000}, {25088, 30000}, {24576, 27000} }),
+       /*  27.027MHz */
+       HDMI_MSM_AUDIO_ARCS(27030, {
+               {4096, 27027}, {6272, 30030}, {6144, 27027}, {12544, 30030},
+               {12288, 27027}, {25088, 30030}, {24576, 27027} }),
+       /*  74.250MHz */
+       HDMI_MSM_AUDIO_ARCS(74250, {
+               {4096, 74250}, {6272, 82500}, {6144, 74250}, {12544, 82500},
+               {12288, 74250}, {25088, 82500}, {24576, 74250} }),
+       /* 148.500MHz */
+       HDMI_MSM_AUDIO_ARCS(148500, {
+               {4096, 148500}, {6272, 165000}, {6144, 148500}, {12544, 165000},
+               {12288, 148500}, {25088, 165000}, {24576, 148500} }),
+};
+
+static const struct hdmi_msm_audio_arcs *get_arcs(unsigned long int pixclock)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(acr_lut); i++) {
+               const struct hdmi_msm_audio_arcs *arcs = &acr_lut[i];
+               if (arcs->pixclock == pixclock)
+                       return arcs;
+       }
+
+       return NULL;
+}
+
+int hdmi_audio_update(struct hdmi *hdmi)
+{
+       struct hdmi_audio *audio = &hdmi->audio;
+       struct hdmi_audio_infoframe *info = &audio->infoframe;
+       const struct hdmi_msm_audio_arcs *arcs = NULL;
+       bool enabled = audio->enabled;
+       uint32_t acr_pkt_ctrl, vbi_pkt_ctrl, aud_pkt_ctrl;
+       uint32_t infofrm_ctrl, audio_config;
+
+       DBG("audio: enabled=%d, channels=%d, channel_allocation=0x%x, "
+               "level_shift_value=%d, downmix_inhibit=%d, rate=%d",
+               audio->enabled, info->channels,  info->channel_allocation,
+               info->level_shift_value, info->downmix_inhibit, audio->rate);
+       DBG("video: power_on=%d, pixclock=%lu", hdmi->power_on, hdmi->pixclock);
+
+       if (enabled && !(hdmi->power_on && hdmi->pixclock)) {
+               DBG("disabling audio: no video");
+               enabled = false;
+       }
+
+       if (enabled) {
+               arcs = get_arcs(hdmi->pixclock);
+               if (!arcs) {
+                       DBG("disabling audio: unsupported pixclock: %lu",
+                                       hdmi->pixclock);
+                       enabled = false;
+               }
+       }
+
+       /* Read first before writing */
+       acr_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_ACR_PKT_CTRL);
+       vbi_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_VBI_PKT_CTRL);
+       aud_pkt_ctrl = hdmi_read(hdmi, REG_HDMI_AUDIO_PKT_CTRL1);
+       infofrm_ctrl = hdmi_read(hdmi, REG_HDMI_INFOFRAME_CTRL0);
+       audio_config = hdmi_read(hdmi, REG_HDMI_AUDIO_CFG);
+
+       /* Clear N/CTS selection bits */
+       acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SELECT__MASK;
+
+       if (enabled) {
+               uint32_t n, cts, multiplier;
+               enum hdmi_acr_cts select;
+               uint8_t buf[14];
+
+               n   = arcs->lut[audio->rate].n;
+               cts = arcs->lut[audio->rate].cts;
+
+               if ((MSM_HDMI_SAMPLE_RATE_192KHZ == audio->rate) ||
+                               (MSM_HDMI_SAMPLE_RATE_176_4KHZ == audio->rate)) {
+                       multiplier = 4;
+                       n >>= 2; /* divide N by 4 and use multiplier */
+               } else if ((MSM_HDMI_SAMPLE_RATE_96KHZ == audio->rate) ||
+                               (MSM_HDMI_SAMPLE_RATE_88_2KHZ == audio->rate)) {
+                       multiplier = 2;
+                       n >>= 1; /* divide N by 2 and use multiplier */
+               } else {
+                       multiplier = 1;
+               }
+
+               DBG("n=%u, cts=%u, multiplier=%u", n, cts, multiplier);
+
+               acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SOURCE;
+               acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_AUDIO_PRIORITY;
+               acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_N_MULTIPLIER(multiplier);
+
+               if ((MSM_HDMI_SAMPLE_RATE_48KHZ == audio->rate) ||
+                               (MSM_HDMI_SAMPLE_RATE_96KHZ == audio->rate) ||
+                               (MSM_HDMI_SAMPLE_RATE_192KHZ == audio->rate))
+                       select = ACR_48;
+               else if ((MSM_HDMI_SAMPLE_RATE_44_1KHZ == audio->rate) ||
+                               (MSM_HDMI_SAMPLE_RATE_88_2KHZ == audio->rate) ||
+                               (MSM_HDMI_SAMPLE_RATE_176_4KHZ == audio->rate))
+                       select = ACR_44;
+               else /* default to 32k */
+                       select = ACR_32;
+
+               acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SELECT(select);
+
+               hdmi_write(hdmi, REG_HDMI_ACR_0(select - 1),
+                               HDMI_ACR_0_CTS(cts));
+               hdmi_write(hdmi, REG_HDMI_ACR_1(select - 1),
+                               HDMI_ACR_1_N(n));
+
+               hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL2,
+                               COND(info->channels != 2, HDMI_AUDIO_PKT_CTRL2_LAYOUT) |
+                               HDMI_AUDIO_PKT_CTRL2_OVERRIDE);
+
+               acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_CONT;
+               acr_pkt_ctrl |= HDMI_ACR_PKT_CTRL_SEND;
+
+               /* configure infoframe: */
+               hdmi_audio_infoframe_pack(info, buf, sizeof(buf));
+               hdmi_write(hdmi, REG_HDMI_AUDIO_INFO0,
+                               (buf[3] <<  0) || (buf[4] <<  8) ||
+                               (buf[5] << 16) || (buf[6] << 24));
+               hdmi_write(hdmi, REG_HDMI_AUDIO_INFO1,
+                               (buf[7] <<  0) || (buf[8] << 8));
+
+               hdmi_write(hdmi, REG_HDMI_GC, 0);
+
+               vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_ENABLE;
+               vbi_pkt_ctrl |= HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
+
+               aud_pkt_ctrl |= HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
+
+               infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
+               infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
+               infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
+               infofrm_ctrl |= HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
+
+               audio_config &= ~HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK;
+               audio_config |= HDMI_AUDIO_CFG_FIFO_WATERMARK(4);
+               audio_config |= HDMI_AUDIO_CFG_ENGINE_ENABLE;
+       } else {
+               hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
+               acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_CONT;
+               acr_pkt_ctrl &= ~HDMI_ACR_PKT_CTRL_SEND;
+               vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_ENABLE;
+               vbi_pkt_ctrl &= ~HDMI_VBI_PKT_CTRL_GC_EVERY_FRAME;
+               aud_pkt_ctrl &= ~HDMI_AUDIO_PKT_CTRL1_AUDIO_SAMPLE_SEND;
+               infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SEND;
+               infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_CONT;
+               infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_SOURCE;
+               infofrm_ctrl &= ~HDMI_INFOFRAME_CTRL0_AUDIO_INFO_UPDATE;
+               audio_config &= ~HDMI_AUDIO_CFG_ENGINE_ENABLE;
+       }
+
+       hdmi_write(hdmi, REG_HDMI_ACR_PKT_CTRL, acr_pkt_ctrl);
+       hdmi_write(hdmi, REG_HDMI_VBI_PKT_CTRL, vbi_pkt_ctrl);
+       hdmi_write(hdmi, REG_HDMI_AUDIO_PKT_CTRL1, aud_pkt_ctrl);
+       hdmi_write(hdmi, REG_HDMI_INFOFRAME_CTRL0, infofrm_ctrl);
+
+       hdmi_write(hdmi, REG_HDMI_AUD_INT,
+                       COND(enabled, HDMI_AUD_INT_AUD_FIFO_URUN_INT) |
+                       COND(enabled, HDMI_AUD_INT_AUD_SAM_DROP_INT));
+
+       hdmi_write(hdmi, REG_HDMI_AUDIO_CFG, audio_config);
+
+
+       DBG("audio %sabled", enabled ? "en" : "dis");
+
+       return 0;
+}
+
+int hdmi_audio_info_setup(struct hdmi *hdmi, bool enabled,
+       uint32_t num_of_channels, uint32_t channel_allocation,
+       uint32_t level_shift, bool down_mix)
+{
+       struct hdmi_audio *audio;
+
+       if (!hdmi)
+               return -ENXIO;
+
+       audio = &hdmi->audio;
+
+       if (num_of_channels >= ARRAY_SIZE(nchannels))
+               return -EINVAL;
+
+       audio->enabled = enabled;
+       audio->infoframe.channels = nchannels[num_of_channels];
+       audio->infoframe.channel_allocation = channel_allocation;
+       audio->infoframe.level_shift_value = level_shift;
+       audio->infoframe.downmix_inhibit = down_mix;
+
+       return hdmi_audio_update(hdmi);
+}
+
+void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate)
+{
+       struct hdmi_audio *audio;
+
+       if (!hdmi)
+               return;
+
+       audio = &hdmi->audio;
+
+       if ((rate < 0) || (rate >= MSM_HDMI_SAMPLE_RATE_MAX))
+               return;
+
+       audio->rate = rate;
+       hdmi_audio_update(hdmi);
+}
index 7d10e55..f6cf745 100644 (file)
 
 struct hdmi_bridge {
        struct drm_bridge base;
-
        struct hdmi *hdmi;
-       bool power_on;
-
-       unsigned long int pixclock;
 };
 #define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
 
@@ -52,8 +48,8 @@ static void power_on(struct drm_bridge *bridge)
        }
 
        if (config->pwr_clk_cnt > 0) {
-               DBG("pixclock: %lu", hdmi_bridge->pixclock);
-               ret = clk_set_rate(hdmi->pwr_clks[0], hdmi_bridge->pixclock);
+               DBG("pixclock: %lu", hdmi->pixclock);
+               ret = clk_set_rate(hdmi->pwr_clks[0], hdmi->pixclock);
                if (ret) {
                        dev_err(dev->dev, "failed to set pixel clk: %s (%d)\n",
                                        config->pwr_clk_names[0], ret);
@@ -102,12 +98,13 @@ static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
 
        DBG("power up");
 
-       if (!hdmi_bridge->power_on) {
+       if (!hdmi->power_on) {
                power_on(bridge);
-               hdmi_bridge->power_on = true;
+               hdmi->power_on = true;
+               hdmi_audio_update(hdmi);
        }
 
-       phy->funcs->powerup(phy, hdmi_bridge->pixclock);
+       phy->funcs->powerup(phy, hdmi->pixclock);
        hdmi_set_mode(hdmi, true);
 }
 
@@ -129,9 +126,10 @@ static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
        hdmi_set_mode(hdmi, false);
        phy->funcs->powerdown(phy);
 
-       if (hdmi_bridge->power_on) {
+       if (hdmi->power_on) {
                power_off(bridge);
-               hdmi_bridge->power_on = false;
+               hdmi->power_on = false;
+               hdmi_audio_update(hdmi);
        }
 }
 
@@ -146,7 +144,7 @@ static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
 
        mode = adjusted_mode;
 
-       hdmi_bridge->pixclock = mode->clock * 1000;
+       hdmi->pixclock = mode->clock * 1000;
 
        hdmi->hdmi_mode = drm_match_cea_mode(mode) > 1;
 
@@ -194,9 +192,7 @@ static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
        DBG("frame_ctrl=%08x", frame_ctrl);
        hdmi_write(hdmi, REG_HDMI_FRAME_CTRL, frame_ctrl);
 
-       // TODO until we have audio, this might be safest:
-       if (hdmi->hdmi_mode)
-               hdmi_write(hdmi, REG_HDMI_GC, HDMI_GC_MUTE);
+       hdmi_audio_update(hdmi);
 }
 
 static const struct drm_bridge_funcs hdmi_bridge_funcs = {
index 84c5b13..3e6c0f3 100644 (file)
@@ -120,7 +120,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
 
        /* grab reference to incoming scanout fb: */
        drm_framebuffer_reference(new_fb);
-       mdp4_crtc->base.fb = new_fb;
+       mdp4_crtc->base.primary->fb = new_fb;
        mdp4_crtc->fb = new_fb;
 
        if (old_fb)
@@ -182,7 +182,7 @@ static void pageflip_cb(struct msm_fence_cb *cb)
        struct mdp4_crtc *mdp4_crtc =
                container_of(cb, struct mdp4_crtc, pageflip_cb);
        struct drm_crtc *crtc = &mdp4_crtc->base;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_framebuffer *fb = crtc->primary->fb;
 
        if (!fb)
                return;
@@ -348,14 +348,14 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
                        mode->type, mode->flags);
 
        /* grab extra ref for update_scanout() */
-       drm_framebuffer_reference(crtc->fb);
+       drm_framebuffer_reference(crtc->primary->fb);
 
-       ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->fb,
+       ret = mdp4_plane_mode_set(mdp4_crtc->plane, crtc, crtc->primary->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16);
        if (ret) {
-               drm_framebuffer_unreference(crtc->fb);
+               drm_framebuffer_unreference(crtc->primary->fb);
                dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
                                mdp4_crtc->name, ret);
                return ret;
@@ -368,7 +368,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
        /* take data from pipe: */
        mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_BASE(dma), 0);
        mdp4_write(mdp4_kms, REG_MDP4_DMA_SRC_STRIDE(dma),
-                       crtc->fb->pitches[0]);
+                       crtc->primary->fb->pitches[0]);
        mdp4_write(mdp4_kms, REG_MDP4_DMA_DST_SIZE(dma),
                        MDP4_DMA_DST_SIZE_WIDTH(0) |
                        MDP4_DMA_DST_SIZE_HEIGHT(0));
@@ -378,7 +378,7 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
                        MDP4_OVLP_SIZE_WIDTH(mode->hdisplay) |
                        MDP4_OVLP_SIZE_HEIGHT(mode->vdisplay));
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_STRIDE(ovlp),
-                       crtc->fb->pitches[0]);
+                       crtc->primary->fb->pitches[0]);
 
        mdp4_write(mdp4_kms, REG_MDP4_OVLP_CFG(ovlp), 1);
 
@@ -388,8 +388,8 @@ static int mdp4_crtc_mode_set(struct drm_crtc *crtc,
                mdp4_write(mdp4_kms, REG_MDP4_DMA_E_QUANT(2), 0x00ff0000);
        }
 
-       update_fb(crtc, crtc->fb);
-       update_scanout(crtc, crtc->fb);
+       update_fb(crtc, crtc->primary->fb);
+       update_scanout(crtc, crtc->primary->fb);
 
        return 0;
 }
@@ -420,19 +420,19 @@ static int mdp4_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        int ret;
 
        /* grab extra ref for update_scanout() */
-       drm_framebuffer_reference(crtc->fb);
+       drm_framebuffer_reference(crtc->primary->fb);
 
-       ret = mdp4_plane_mode_set(plane, crtc, crtc->fb,
+       ret = mdp4_plane_mode_set(plane, crtc, crtc->primary->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16);
        if (ret) {
-               drm_framebuffer_unreference(crtc->fb);
+               drm_framebuffer_unreference(crtc->primary->fb);
                return ret;
        }
 
-       update_fb(crtc, crtc->fb);
-       update_scanout(crtc, crtc->fb);
+       update_fb(crtc, crtc->primary->fb);
+       update_scanout(crtc, crtc->primary->fb);
 
        return 0;
 }
@@ -740,6 +740,9 @@ void mdp4_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
 
 void mdp4_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
 {
+       /* don't actually detatch our primary plane: */
+       if (to_mdp4_crtc(crtc)->plane == plane)
+               return;
        set_attach(crtc, mdp4_plane_pipe(plane), NULL);
 }
 
@@ -791,7 +794,7 @@ struct drm_crtc *mdp4_crtc_init(struct drm_device *dev,
 
        INIT_FENCE_CB(&mdp4_crtc->pageflip_cb, pageflip_cb);
 
-       drm_crtc_init(dev, crtc, &mdp4_crtc_funcs);
+       drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp4_crtc_funcs);
        drm_crtc_helper_add(crtc, &mdp4_crtc_helper_funcs);
 
        mdp4_plane_install_properties(mdp4_crtc->plane, &crtc->base);
index 1e893dd..66f33db 100644 (file)
@@ -222,6 +222,7 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
        struct drm_plane *plane = NULL;
        struct mdp4_plane *mdp4_plane;
        int ret;
+       enum drm_plane_type type;
 
        mdp4_plane = kzalloc(sizeof(*mdp4_plane), GFP_KERNEL);
        if (!mdp4_plane) {
@@ -237,9 +238,10 @@ struct drm_plane *mdp4_plane_init(struct drm_device *dev,
        mdp4_plane->nformats = mdp4_get_formats(pipe_id, mdp4_plane->formats,
                        ARRAY_SIZE(mdp4_plane->formats));
 
-       drm_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
-                       mdp4_plane->formats, mdp4_plane->nformats,
-                       private_plane);
+       type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+       drm_universal_plane_init(dev, plane, 0xff, &mdp4_plane_funcs,
+                                mdp4_plane->formats, mdp4_plane->nformats,
+                                type);
 
        mdp4_plane_install_properties(plane, &plane->base);
 
index f279402..6ea10bd 100644 (file)
@@ -102,7 +102,7 @@ static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
 
        /* grab reference to incoming scanout fb: */
        drm_framebuffer_reference(new_fb);
-       mdp5_crtc->base.fb = new_fb;
+       mdp5_crtc->base.primary->fb = new_fb;
        mdp5_crtc->fb = new_fb;
 
        if (old_fb)
@@ -289,14 +289,14 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
                        mode->type, mode->flags);
 
        /* grab extra ref for update_scanout() */
-       drm_framebuffer_reference(crtc->fb);
+       drm_framebuffer_reference(crtc->primary->fb);
 
-       ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->fb,
+       ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->primary->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16);
        if (ret) {
-               drm_framebuffer_unreference(crtc->fb);
+               drm_framebuffer_unreference(crtc->primary->fb);
                dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
                                mdp5_crtc->name, ret);
                return ret;
@@ -306,8 +306,8 @@ static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
                        MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
                        MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
 
-       update_fb(crtc, crtc->fb);
-       update_scanout(crtc, crtc->fb);
+       update_fb(crtc, crtc->primary->fb);
+       update_scanout(crtc, crtc->primary->fb);
 
        return 0;
 }
@@ -338,19 +338,19 @@ static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        int ret;
 
        /* grab extra ref for update_scanout() */
-       drm_framebuffer_reference(crtc->fb);
+       drm_framebuffer_reference(crtc->primary->fb);
 
-       ret = mdp5_plane_mode_set(plane, crtc, crtc->fb,
+       ret = mdp5_plane_mode_set(plane, crtc, crtc->primary->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16);
        if (ret) {
-               drm_framebuffer_unreference(crtc->fb);
+               drm_framebuffer_unreference(crtc->primary->fb);
                return ret;
        }
 
-       update_fb(crtc, crtc->fb);
-       update_scanout(crtc, crtc->fb);
+       update_fb(crtc, crtc->primary->fb);
+       update_scanout(crtc, crtc->primary->fb);
 
        return 0;
 }
@@ -524,6 +524,9 @@ void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
 
 void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
 {
+       /* don't actually detatch our primary plane: */
+       if (to_mdp5_crtc(crtc)->plane == plane)
+               return;
        set_attach(crtc, mdp5_plane_pipe(plane), NULL);
 }
 
@@ -559,7 +562,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
 
        INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb);
 
-       drm_crtc_init(dev, crtc, &mdp5_crtc_funcs);
+       drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs);
        drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
 
        mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base);
index 0ac8bb5..47f7bbb 100644 (file)
@@ -358,6 +358,7 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
        struct drm_plane *plane = NULL;
        struct mdp5_plane *mdp5_plane;
        int ret;
+       enum drm_plane_type type;
 
        mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
        if (!mdp5_plane) {
@@ -373,9 +374,10 @@ struct drm_plane *mdp5_plane_init(struct drm_device *dev,
        mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats,
                        ARRAY_SIZE(mdp5_plane->formats));
 
-       drm_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
-                       mdp5_plane->formats, mdp5_plane->nformats,
-                       private_plane);
+       type = private_plane ? DRM_PLANE_TYPE_PRIMARY : DRM_PLANE_TYPE_OVERLAY;
+       drm_universal_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
+                                mdp5_plane->formats, mdp5_plane->nformats,
+                                type);
 
        mdp5_plane_install_properties(plane, &plane->base);
 
index 3be48f7..03455b6 100644 (file)
@@ -101,7 +101,8 @@ void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask)
                .count = 1,
        };
        mdp_irq_register(mdp_kms, &wait.irq);
-       wait_event(wait_event, (wait.count <= 0));
+       wait_event_timeout(wait_event, (wait.count <= 0),
+                       msecs_to_jiffies(100));
        mdp_irq_unregister(mdp_kms, &wait.irq);
 }
 
index e6adafc..f9de156 100644 (file)
@@ -56,6 +56,10 @@ static char *vram;
 MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU");
 module_param(vram, charp, 0);
 
+/*
+ * Util/helpers:
+ */
+
 void __iomem *msm_ioremap(struct platform_device *pdev, const char *name,
                const char *dbgname)
 {
@@ -143,6 +147,8 @@ static int msm_unload(struct drm_device *dev)
                                priv->vram.paddr, &attrs);
        }
 
+       component_unbind_all(dev->dev, dev);
+
        dev->dev_private = NULL;
 
        kfree(priv);
@@ -175,6 +181,7 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
        struct msm_kms *kms;
        int ret;
 
+
        priv = kzalloc(sizeof(*priv), GFP_KERNEL);
        if (!priv) {
                dev_err(dev->dev, "failed to allocate private data\n");
@@ -226,6 +233,13 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
                                (uint32_t)(priv->vram.paddr + size));
        }
 
+       platform_set_drvdata(pdev, dev);
+
+       /* Bind all our sub-components: */
+       ret = component_bind_all(dev->dev, dev);
+       if (ret)
+               return ret;
+
        switch (get_mdp_ver(pdev)) {
        case 4:
                kms = mdp4_kms_init(dev);
@@ -281,8 +295,6 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
                goto fail;
        }
 
-       platform_set_drvdata(pdev, dev);
-
 #ifdef CONFIG_DRM_MSM_FBDEV
        priv->fbdev = msm_fbdev_init(dev);
 #endif
@@ -311,7 +323,6 @@ static void load_gpu(struct drm_device *dev)
                gpu = NULL;
                /* not fatal */
        }
-       mutex_unlock(&dev->struct_mutex);
 
        if (gpu) {
                int ret;
@@ -321,10 +332,16 @@ static void load_gpu(struct drm_device *dev)
                        dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
                        gpu->funcs->destroy(gpu);
                        gpu = NULL;
+               } else {
+                       /* give inactive pm a chance to kick in: */
+                       msm_gpu_retire(gpu);
                }
+
        }
 
        priv->gpu = gpu;
+
+       mutex_unlock(&dev->struct_mutex);
 }
 
 static int msm_open(struct drm_device *dev, struct drm_file *file)
@@ -647,6 +664,12 @@ static int msm_ioctl_gem_new(struct drm_device *dev, void *data,
                struct drm_file *file)
 {
        struct drm_msm_gem_new *args = data;
+
+       if (args->flags & ~MSM_BO_FLAGS) {
+               DRM_ERROR("invalid flags: %08x\n", args->flags);
+               return -EINVAL;
+       }
+
        return msm_gem_new_handle(dev, file, args->size,
                        args->flags, &args->handle);
 }
@@ -660,6 +683,11 @@ static int msm_ioctl_gem_cpu_prep(struct drm_device *dev, void *data,
        struct drm_gem_object *obj;
        int ret;
 
+       if (args->op & ~MSM_PREP_FLAGS) {
+               DRM_ERROR("invalid op: %08x\n", args->op);
+               return -EINVAL;
+       }
+
        obj = drm_gem_object_lookup(dev, file, args->handle);
        if (!obj)
                return -ENOENT;
@@ -714,7 +742,14 @@ static int msm_ioctl_wait_fence(struct drm_device *dev, void *data,
                struct drm_file *file)
 {
        struct drm_msm_wait_fence *args = data;
-       return msm_wait_fence_interruptable(dev, args->fence, &TS(args->timeout));
+
+       if (args->pad) {
+               DRM_ERROR("invalid pad: %08x\n", args->pad);
+               return -EINVAL;
+       }
+
+       return msm_wait_fence_interruptable(dev, args->fence,
+                       &TS(args->timeout));
 }
 
 static const struct drm_ioctl_desc msm_ioctls[] = {
@@ -818,6 +853,98 @@ static const struct dev_pm_ops msm_pm_ops = {
        SET_SYSTEM_SLEEP_PM_OPS(msm_pm_suspend, msm_pm_resume)
 };
 
+/*
+ * Componentized driver support:
+ */
+
+#ifdef CONFIG_OF
+/* NOTE: the CONFIG_OF case duplicates the same code as exynos or imx
+ * (or probably any other).. so probably some room for some helpers
+ */
+static int compare_of(struct device *dev, void *data)
+{
+       return dev->of_node == data;
+}
+
+static int msm_drm_add_components(struct device *master, struct master *m)
+{
+       struct device_node *np = master->of_node;
+       unsigned i;
+       int ret;
+
+       for (i = 0; ; i++) {
+               struct device_node *node;
+
+               node = of_parse_phandle(np, "connectors", i);
+               if (!node)
+                       break;
+
+               ret = component_master_add_child(m, compare_of, node);
+               of_node_put(node);
+
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+#else
+static int compare_dev(struct device *dev, void *data)
+{
+       return dev == data;
+}
+
+static int msm_drm_add_components(struct device *master, struct master *m)
+{
+       /* For non-DT case, it kinda sucks.  We don't actually have a way
+        * to know whether or not we are waiting for certain devices (or if
+        * they are simply not present).  But for non-DT we only need to
+        * care about apq8064/apq8060/etc (all mdp4/a3xx):
+        */
+       static const char *devnames[] = {
+                       "hdmi_msm.0", "kgsl-3d0.0",
+       };
+       int i;
+
+       DBG("Adding components..");
+
+       for (i = 0; i < ARRAY_SIZE(devnames); i++) {
+               struct device *dev;
+               int ret;
+
+               dev = bus_find_device_by_name(&platform_bus_type,
+                               NULL, devnames[i]);
+               if (!dev) {
+                       dev_info(master, "still waiting for %s\n", devnames[i]);
+                       return -EPROBE_DEFER;
+               }
+
+               ret = component_master_add_child(m, compare_dev, dev);
+               if (ret) {
+                       DBG("could not add child: %d", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+#endif
+
+static int msm_drm_bind(struct device *dev)
+{
+       return drm_platform_init(&msm_driver, to_platform_device(dev));
+}
+
+static void msm_drm_unbind(struct device *dev)
+{
+       drm_put_dev(platform_get_drvdata(to_platform_device(dev)));
+}
+
+static const struct component_master_ops msm_drm_ops = {
+               .add_components = msm_drm_add_components,
+               .bind = msm_drm_bind,
+               .unbind = msm_drm_unbind,
+};
+
 /*
  * Platform driver:
  */
@@ -825,12 +952,12 @@ static const struct dev_pm_ops msm_pm_ops = {
 static int msm_pdev_probe(struct platform_device *pdev)
 {
        pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
-       return drm_platform_init(&msm_driver, pdev);
+       return component_master_add(&pdev->dev, &msm_drm_ops);
 }
 
 static int msm_pdev_remove(struct platform_device *pdev)
 {
-       drm_put_dev(platform_get_drvdata(pdev));
+       component_master_del(&pdev->dev, &msm_drm_ops);
 
        return 0;
 }
index 3d63269..9d10ee0 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/clk.h>
 #include <linux/cpufreq.h>
 #include <linux/module.h>
+#include <linux/component.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
@@ -69,6 +70,9 @@ struct msm_drm_private {
 
        struct msm_kms *kms;
 
+       /* subordinate devices, if present: */
+       struct platform_device *hdmi_pdev, *gpu_pdev;
+
        /* when we have more than one 'msm_gpu' these need to be an array: */
        struct msm_gpu *gpu;
        struct msm_file_private *lastctx;
index 5423e91..1f1f4cf 100644 (file)
@@ -23,7 +23,6 @@
  * Cmdstream submission:
  */
 
-#define BO_INVALID_FLAGS ~(MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE)
 /* make sure these don't conflict w/ MSM_SUBMIT_BO_x */
 #define BO_VALID    0x8000
 #define BO_LOCKED   0x4000
@@ -77,7 +76,7 @@ static int submit_lookup_objects(struct msm_gem_submit *submit,
                        goto out_unlock;
                }
 
-               if (submit_bo.flags & BO_INVALID_FLAGS) {
+               if (submit_bo.flags & ~MSM_SUBMIT_BO_FLAGS) {
                        DRM_ERROR("invalid flags: %x\n", submit_bo.flags);
                        ret = -EINVAL;
                        goto out_unlock;
@@ -369,6 +368,18 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
                        goto out;
                }
 
+               /* validate input from userspace: */
+               switch (submit_cmd.type) {
+               case MSM_SUBMIT_CMD_BUF:
+               case MSM_SUBMIT_CMD_IB_TARGET_BUF:
+               case MSM_SUBMIT_CMD_CTX_RESTORE_BUF:
+                       break;
+               default:
+                       DRM_ERROR("invalid type: %08x\n", submit_cmd.type);
+                       ret = -EINVAL;
+                       goto out;
+               }
+
                ret = submit_bo(submit, submit_cmd.submit_idx,
                                &msm_obj, &iova, NULL);
                if (ret)
index 0cfe3f4..3e667ca 100644 (file)
@@ -154,9 +154,18 @@ static int disable_axi(struct msm_gpu *gpu)
 
 int msm_gpu_pm_resume(struct msm_gpu *gpu)
 {
+       struct drm_device *dev = gpu->dev;
        int ret;
 
-       DBG("%s", gpu->name);
+       DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt);
+
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+       if (gpu->active_cnt++ > 0)
+               return 0;
+
+       if (WARN_ON(gpu->active_cnt <= 0))
+               return -EINVAL;
 
        ret = enable_pwrrail(gpu);
        if (ret)
@@ -175,9 +184,18 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)
 
 int msm_gpu_pm_suspend(struct msm_gpu *gpu)
 {
+       struct drm_device *dev = gpu->dev;
        int ret;
 
-       DBG("%s", gpu->name);
+       DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt);
+
+       WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
+       if (--gpu->active_cnt > 0)
+               return 0;
+
+       if (WARN_ON(gpu->active_cnt < 0))
+               return -EINVAL;
 
        ret = disable_axi(gpu);
        if (ret)
@@ -194,6 +212,55 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
        return 0;
 }
 
+/*
+ * Inactivity detection (for suspend):
+ */
+
+static void inactive_worker(struct work_struct *work)
+{
+       struct msm_gpu *gpu = container_of(work, struct msm_gpu, inactive_work);
+       struct drm_device *dev = gpu->dev;
+
+       if (gpu->inactive)
+               return;
+
+       DBG("%s: inactive!\n", gpu->name);
+       mutex_lock(&dev->struct_mutex);
+       if (!(msm_gpu_active(gpu) || gpu->inactive)) {
+               disable_axi(gpu);
+               disable_clk(gpu);
+               gpu->inactive = true;
+       }
+       mutex_unlock(&dev->struct_mutex);
+}
+
+static void inactive_handler(unsigned long data)
+{
+       struct msm_gpu *gpu = (struct msm_gpu *)data;
+       struct msm_drm_private *priv = gpu->dev->dev_private;
+
+       queue_work(priv->wq, &gpu->inactive_work);
+}
+
+/* cancel inactive timer and make sure we are awake: */
+static void inactive_cancel(struct msm_gpu *gpu)
+{
+       DBG("%s", gpu->name);
+       del_timer(&gpu->inactive_timer);
+       if (gpu->inactive) {
+               enable_clk(gpu);
+               enable_axi(gpu);
+               gpu->inactive = false;
+       }
+}
+
+static void inactive_start(struct msm_gpu *gpu)
+{
+       DBG("%s", gpu->name);
+       mod_timer(&gpu->inactive_timer,
+                       round_jiffies_up(jiffies + DRM_MSM_INACTIVE_JIFFIES));
+}
+
 /*
  * Hangcheck detection for locked gpu:
  */
@@ -206,7 +273,10 @@ static void recover_worker(struct work_struct *work)
        dev_err(dev->dev, "%s: hangcheck recover!\n", gpu->name);
 
        mutex_lock(&dev->struct_mutex);
-       gpu->funcs->recover(gpu);
+       if (msm_gpu_active(gpu)) {
+               inactive_cancel(gpu);
+               gpu->funcs->recover(gpu);
+       }
        mutex_unlock(&dev->struct_mutex);
 
        msm_gpu_retire(gpu);
@@ -281,6 +351,9 @@ static void retire_worker(struct work_struct *work)
        }
 
        mutex_unlock(&dev->struct_mutex);
+
+       if (!msm_gpu_active(gpu))
+               inactive_start(gpu);
 }
 
 /* call from irq handler to schedule work to retire bo's */
@@ -302,6 +375,8 @@ int msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
 
        gpu->submitted_fence = submit->fence;
 
+       inactive_cancel(gpu);
+
        ret = gpu->funcs->submit(gpu, submit, ctx);
        priv->lastctx = ctx;
 
@@ -357,11 +432,15 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        gpu->dev = drm;
        gpu->funcs = funcs;
        gpu->name = name;
+       gpu->inactive = true;
 
        INIT_LIST_HEAD(&gpu->active_list);
        INIT_WORK(&gpu->retire_work, retire_worker);
+       INIT_WORK(&gpu->inactive_work, inactive_worker);
        INIT_WORK(&gpu->recover_work, recover_worker);
 
+       setup_timer(&gpu->inactive_timer, inactive_handler,
+                       (unsigned long)gpu);
        setup_timer(&gpu->hangcheck_timer, hangcheck_handler,
                        (unsigned long)gpu);
 
index 458db8c..fad2700 100644 (file)
@@ -72,6 +72,10 @@ struct msm_gpu {
 
        uint32_t submitted_fence;
 
+       /* is gpu powered/active? */
+       int active_cnt;
+       bool inactive;
+
        /* worker for handling active-list retiring: */
        struct work_struct retire_work;
 
@@ -91,7 +95,12 @@ struct msm_gpu {
        uint32_t bsc;
 #endif
 
-       /* Hang Detction: */
+       /* Hang and Inactivity Detection:
+        */
+#define DRM_MSM_INACTIVE_PERIOD   66 /* in ms (roughly four frames) */
+#define DRM_MSM_INACTIVE_JIFFIES  msecs_to_jiffies(DRM_MSM_INACTIVE_PERIOD)
+       struct timer_list inactive_timer;
+       struct work_struct inactive_work;
 #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */
 #define DRM_MSM_HANGCHECK_JIFFIES msecs_to_jiffies(DRM_MSM_HANGCHECK_PERIOD)
        struct timer_list hangcheck_timer;
@@ -99,6 +108,11 @@ struct msm_gpu {
        struct work_struct recover_work;
 };
 
+static inline bool msm_gpu_active(struct msm_gpu *gpu)
+{
+       return gpu->submitted_fence > gpu->funcs->last_fence(gpu);
+}
+
 static inline void gpu_write(struct msm_gpu *gpu, u32 reg, u32 data)
 {
        msm_writel(data, gpu->mmio + (reg << 2));
index d310c19..b7d2162 100644 (file)
@@ -48,6 +48,7 @@ nouveau-y += core/subdev/bios/therm.o
 nouveau-y += core/subdev/bios/vmap.o
 nouveau-y += core/subdev/bios/volt.o
 nouveau-y += core/subdev/bios/xpio.o
+nouveau-y += core/subdev/bios/P0260.o
 nouveau-y += core/subdev/bus/hwsq.o
 nouveau-y += core/subdev/bus/nv04.o
 nouveau-y += core/subdev/bus/nv31.o
@@ -77,6 +78,7 @@ nouveau-y += core/subdev/devinit/nv98.o
 nouveau-y += core/subdev/devinit/nva3.o
 nouveau-y += core/subdev/devinit/nvaf.o
 nouveau-y += core/subdev/devinit/nvc0.o
+nouveau-y += core/subdev/devinit/gm107.o
 nouveau-y += core/subdev/fb/base.o
 nouveau-y += core/subdev/fb/nv04.o
 nouveau-y += core/subdev/fb/nv10.o
@@ -100,6 +102,7 @@ nouveau-y += core/subdev/fb/nvaa.o
 nouveau-y += core/subdev/fb/nvaf.o
 nouveau-y += core/subdev/fb/nvc0.o
 nouveau-y += core/subdev/fb/nve0.o
+nouveau-y += core/subdev/fb/gm107.o
 nouveau-y += core/subdev/fb/ramnv04.o
 nouveau-y += core/subdev/fb/ramnv10.o
 nouveau-y += core/subdev/fb/ramnv1a.o
@@ -114,6 +117,7 @@ nouveau-y += core/subdev/fb/ramnva3.o
 nouveau-y += core/subdev/fb/ramnvaa.o
 nouveau-y += core/subdev/fb/ramnvc0.o
 nouveau-y += core/subdev/fb/ramnve0.o
+nouveau-y += core/subdev/fb/ramgm107.o
 nouveau-y += core/subdev/fb/sddr3.o
 nouveau-y += core/subdev/fb/gddr5.o
 nouveau-y += core/subdev/gpio/base.o
@@ -136,7 +140,8 @@ nouveau-y += core/subdev/instmem/base.o
 nouveau-y += core/subdev/instmem/nv04.o
 nouveau-y += core/subdev/instmem/nv40.o
 nouveau-y += core/subdev/instmem/nv50.o
-nouveau-y += core/subdev/ltcg/nvc0.o
+nouveau-y += core/subdev/ltcg/gf100.o
+nouveau-y += core/subdev/ltcg/gm107.o
 nouveau-y += core/subdev/mc/base.o
 nouveau-y += core/subdev/mc/nv04.o
 nouveau-y += core/subdev/mc/nv40.o
@@ -170,6 +175,7 @@ nouveau-y += core/subdev/therm/nva3.o
 nouveau-y += core/subdev/therm/nvd0.o
 nouveau-y += core/subdev/timer/base.o
 nouveau-y += core/subdev/timer/nv04.o
+nouveau-y += core/subdev/timer/gk20a.o
 nouveau-y += core/subdev/vm/base.o
 nouveau-y += core/subdev/vm/nv04.o
 nouveau-y += core/subdev/vm/nv41.o
@@ -206,6 +212,7 @@ nouveau-y += core/engine/device/nv40.o
 nouveau-y += core/engine/device/nv50.o
 nouveau-y += core/engine/device/nvc0.o
 nouveau-y += core/engine/device/nve0.o
+nouveau-y += core/engine/device/gm100.o
 nouveau-y += core/engine/disp/base.o
 nouveau-y += core/engine/disp/nv04.o
 nouveau-y += core/engine/disp/nv50.o
@@ -216,6 +223,7 @@ nouveau-y += core/engine/disp/nva3.o
 nouveau-y += core/engine/disp/nvd0.o
 nouveau-y += core/engine/disp/nve0.o
 nouveau-y += core/engine/disp/nvf0.o
+nouveau-y += core/engine/disp/gm107.o
 nouveau-y += core/engine/disp/dacnv50.o
 nouveau-y += core/engine/disp/dport.o
 nouveau-y += core/engine/disp/hdanva3.o
@@ -242,13 +250,14 @@ nouveau-y += core/engine/graph/ctxnv40.o
 nouveau-y += core/engine/graph/ctxnv50.o
 nouveau-y += core/engine/graph/ctxnvc0.o
 nouveau-y += core/engine/graph/ctxnvc1.o
-nouveau-y += core/engine/graph/ctxnvc3.o
+nouveau-y += core/engine/graph/ctxnvc4.o
 nouveau-y += core/engine/graph/ctxnvc8.o
 nouveau-y += core/engine/graph/ctxnvd7.o
 nouveau-y += core/engine/graph/ctxnvd9.o
 nouveau-y += core/engine/graph/ctxnve4.o
 nouveau-y += core/engine/graph/ctxnvf0.o
 nouveau-y += core/engine/graph/ctxnv108.o
+nouveau-y += core/engine/graph/ctxgm107.o
 nouveau-y += core/engine/graph/nv04.o
 nouveau-y += core/engine/graph/nv10.o
 nouveau-y += core/engine/graph/nv20.o
@@ -261,13 +270,14 @@ nouveau-y += core/engine/graph/nv40.o
 nouveau-y += core/engine/graph/nv50.o
 nouveau-y += core/engine/graph/nvc0.o
 nouveau-y += core/engine/graph/nvc1.o
-nouveau-y += core/engine/graph/nvc3.o
+nouveau-y += core/engine/graph/nvc4.o
 nouveau-y += core/engine/graph/nvc8.o
 nouveau-y += core/engine/graph/nvd7.o
 nouveau-y += core/engine/graph/nvd9.o
 nouveau-y += core/engine/graph/nve4.o
 nouveau-y += core/engine/graph/nvf0.o
 nouveau-y += core/engine/graph/nv108.o
+nouveau-y += core/engine/graph/gm107.o
 nouveau-y += core/engine/mpeg/nv31.o
 nouveau-y += core/engine/mpeg/nv40.o
 nouveau-y += core/engine/mpeg/nv44.o
index 1ce95a8..0594a59 100644 (file)
@@ -167,7 +167,7 @@ int
 nouveau_namedb_create_(struct nouveau_object *parent,
                       struct nouveau_object *engine,
                       struct nouveau_oclass *oclass, u32 pclass,
-                      struct nouveau_oclass *sclass, u32 engcls,
+                      struct nouveau_oclass *sclass, u64 engcls,
                       int length, void **pobject)
 {
        struct nouveau_namedb *namedb;
index 313380c..dee5d12 100644 (file)
@@ -49,7 +49,7 @@ nouveau_parent_sclass(struct nouveau_object *parent, u16 handle,
 
        mask = nv_parent(parent)->engine;
        while (mask) {
-               int i = ffsll(mask) - 1;
+               int i = __ffs64(mask);
 
                if (nv_iclass(parent, NV_CLIENT_CLASS))
                        engine = nv_engine(nv_client(parent)->device);
index dd01c6c..18c8c72 100644 (file)
@@ -131,8 +131,8 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       mmio_base = pci_resource_start(device->pdev, 0);
-       mmio_size = pci_resource_len(device->pdev, 0);
+       mmio_base = nv_device_resource_start(device, 0);
+       mmio_size = nv_device_resource_len(device, 0);
 
        /* translate api disable mask into internal mapping */
        disable = args->debug0;
@@ -185,6 +185,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                        case 0x0e0:
                        case 0x0f0:
                        case 0x100: device->card_type = NV_E0; break;
+                       case 0x110: device->card_type = GM100; break;
                        default:
                                break;
                        }
@@ -208,6 +209,7 @@ nouveau_devobj_ctor(struct nouveau_object *parent,
                case NV_C0:
                case NV_D0: ret = nvc0_identify(device); break;
                case NV_E0: ret = nve0_identify(device); break;
+               case GM100: ret = gm100_identify(device); break;
                default:
                        ret = -EINVAL;
                        break;
@@ -446,6 +448,72 @@ nouveau_device_dtor(struct nouveau_object *object)
        nouveau_engine_destroy(&device->base);
 }
 
+resource_size_t
+nv_device_resource_start(struct nouveau_device *device, unsigned int bar)
+{
+       if (nv_device_is_pci(device)) {
+               return pci_resource_start(device->pdev, bar);
+       } else {
+               struct resource *res;
+               res = platform_get_resource(device->platformdev,
+                                           IORESOURCE_MEM, bar);
+               if (!res)
+                       return 0;
+               return res->start;
+       }
+}
+
+resource_size_t
+nv_device_resource_len(struct nouveau_device *device, unsigned int bar)
+{
+       if (nv_device_is_pci(device)) {
+               return pci_resource_len(device->pdev, bar);
+       } else {
+               struct resource *res;
+               res = platform_get_resource(device->platformdev,
+                                           IORESOURCE_MEM, bar);
+               if (!res)
+                       return 0;
+               return resource_size(res);
+       }
+}
+
+dma_addr_t
+nv_device_map_page(struct nouveau_device *device, struct page *page)
+{
+       dma_addr_t ret;
+
+       if (nv_device_is_pci(device)) {
+               ret = pci_map_page(device->pdev, page, 0, PAGE_SIZE,
+                                  PCI_DMA_BIDIRECTIONAL);
+               if (pci_dma_mapping_error(device->pdev, ret))
+                       ret = 0;
+       } else {
+               ret = page_to_phys(page);
+       }
+
+       return ret;
+}
+
+void
+nv_device_unmap_page(struct nouveau_device *device, dma_addr_t addr)
+{
+       if (nv_device_is_pci(device))
+               pci_unmap_page(device->pdev, addr, PAGE_SIZE,
+                              PCI_DMA_BIDIRECTIONAL);
+}
+
+int
+nv_device_get_irq(struct nouveau_device *device, bool stall)
+{
+       if (nv_device_is_pci(device)) {
+               return device->pdev->irq;
+       } else {
+               return platform_get_irq_byname(device->platformdev,
+                                              stall ? "stall" : "nonstall");
+       }
+}
+
 static struct nouveau_oclass
 nouveau_device_oclass = {
        .handle = NV_ENGINE(DEVICE, 0x00),
@@ -457,8 +525,8 @@ nouveau_device_oclass = {
 };
 
 int
-nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname,
-                      const char *cfg, const char *dbg,
+nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name,
+                      const char *sname, const char *cfg, const char *dbg,
                       int length, void **pobject)
 {
        struct nouveau_device *device;
@@ -476,7 +544,14 @@ nouveau_device_create_(struct pci_dev *pdev, u64 name, const char *sname,
        if (ret)
                goto done;
 
-       device->pdev = pdev;
+       switch (type) {
+       case NOUVEAU_BUS_PCI:
+               device->pdev = dev;
+               break;
+       case NOUVEAU_BUS_PLATFORM:
+               device->platformdev = dev;
+               break;
+       }
        device->handle = name;
        device->cfgopt = cfg;
        device->dbgopt = dbg;
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c
new file mode 100644 (file)
index 0000000..d258c21
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/clock.h>
+#include <subdev/therm.h>
+#include <subdev/mxm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/ltcg.h>
+#include <subdev/ibus.h>
+#include <subdev/instmem.h>
+#include <subdev/vm.h>
+#include <subdev/bar.h>
+#include <subdev/pwr.h>
+#include <subdev/volt.h>
+
+#include <engine/device.h>
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/software.h>
+#include <engine/graph.h>
+#include <engine/disp.h>
+#include <engine/copy.h>
+#include <engine/bsp.h>
+#include <engine/vp.h>
+#include <engine/ppp.h>
+#include <engine/perfmon.h>
+
+int
+gm100_identify(struct nouveau_device *device)
+{
+       switch (device->chipset) {
+       case 0x117:
+               device->cname = "GM107";
+               device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
+               device->oclass[NVDEV_SUBDEV_GPIO   ] = &nve0_gpio_oclass;
+               device->oclass[NVDEV_SUBDEV_I2C    ] = &nvd0_i2c_oclass;
+               device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
+#if 0
+               device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
+#endif
+               device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  gm107_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
+               device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
+               device->oclass[NVDEV_SUBDEV_TIMER  ] = &gk20a_timer_oclass;
+               device->oclass[NVDEV_SUBDEV_FB     ] =  gm107_fb_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gm107_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
+               device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
+#if 0
+               device->oclass[NVDEV_SUBDEV_PWR    ] = &nv108_pwr_oclass;
+               device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv108_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  gm107_graph_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  gm107_disp_oclass;
+               device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
+#endif
+               device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
+#if 0
+               device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
+               device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
+               device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
+#endif
+               break;
+       default:
+               nv_fatal(device, "unknown Maxwell chipset\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
index 32113b0..0a51ff4 100644 (file)
@@ -60,7 +60,7 @@ nv04_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv04_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv04_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x05:
                device->cname = "NV05";
@@ -78,7 +78,7 @@ nv04_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv04_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv04_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        default:
                nv_fatal(device, "unknown RIVA chipset\n");
index 744f15d..e008de8 100644 (file)
@@ -60,7 +60,7 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x15:
                device->cname = "NV15";
@@ -79,7 +79,7 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x16:
                device->cname = "NV16";
@@ -98,7 +98,7 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x1a:
                device->cname = "nForce";
@@ -117,7 +117,7 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x11:
                device->cname = "NV11";
@@ -136,7 +136,7 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x17:
                device->cname = "NV17";
@@ -155,7 +155,7 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x1f:
                device->cname = "nForce2";
@@ -174,7 +174,7 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x18:
                device->cname = "NV18";
@@ -193,7 +193,7 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        default:
                nv_fatal(device, "unknown Celsius chipset\n");
index 27ba61f..7b629a3 100644 (file)
@@ -63,7 +63,7 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv20_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x25:
                device->cname = "NV25";
@@ -82,7 +82,7 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv25_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x28:
                device->cname = "NV28";
@@ -101,7 +101,7 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv25_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x2a:
                device->cname = "NV2A";
@@ -120,7 +120,7 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv2a_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        default:
                nv_fatal(device, "unknown Kelvin chipset\n");
index fd47ace..7dfddd5 100644 (file)
@@ -63,7 +63,7 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv30_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x35:
                device->cname = "NV35";
@@ -82,7 +82,7 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv35_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x31:
                device->cname = "NV31";
@@ -102,7 +102,7 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv30_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x36:
                device->cname = "NV36";
@@ -122,7 +122,7 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv35_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        case 0x34:
                device->cname = "NV34";
@@ -142,7 +142,7 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv34_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv31_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                break;
        default:
                nv_fatal(device, "unknown Rankine chipset\n");
index 08b8859..7c1ce6c 100644 (file)
@@ -70,7 +70,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x41:
@@ -93,7 +93,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x42:
@@ -116,7 +116,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x43:
@@ -139,7 +139,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv40_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x45:
@@ -162,7 +162,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x47:
@@ -185,7 +185,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x49:
@@ -208,7 +208,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x4b:
@@ -231,7 +231,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x44:
@@ -254,7 +254,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x46:
@@ -277,7 +277,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x4a:
@@ -300,7 +300,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x4c:
@@ -323,7 +323,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x4e:
@@ -346,7 +346,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x63:
@@ -369,7 +369,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x67:
@@ -392,7 +392,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        case 0x68:
@@ -415,7 +415,7 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv10_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv40_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv44_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv04_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv04_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv40_perfmon_oclass;
                break;
        default:
index 81d5c26..66499fa 100644 (file)
@@ -79,7 +79,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_SW     ] =  nv50_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv50_graph_oclass;
                device->oclass[NVDEV_ENGINE_MPEG   ] = &nv50_mpeg_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv50_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv50_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv50_perfmon_oclass;
                break;
        case 0x84:
@@ -107,7 +107,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv84_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv84_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x86:
@@ -135,7 +135,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv84_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv84_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x92:
@@ -163,7 +163,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv84_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv84_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x94:
@@ -191,7 +191,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x96:
@@ -219,7 +219,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0x98:
@@ -247,7 +247,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0xa0:
@@ -275,7 +275,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_VP     ] = &nv84_vp_oclass;
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv84_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv84_bsp_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva0_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0xaa:
@@ -303,7 +303,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0xac:
@@ -331,7 +331,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_CRYPT  ] = &nv98_crypt_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nv94_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nv94_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nv84_perfmon_oclass;
                break;
        case 0xa3:
@@ -361,7 +361,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
                break;
        case 0xa5:
@@ -390,7 +390,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
                break;
        case 0xa8:
@@ -419,7 +419,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
                break;
        case 0xaf:
@@ -448,7 +448,7 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nv98_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nv98_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nva3_copy_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] =  nva3_perfmon_oclass;
                break;
        default:
index b7d66b5..2075b30 100644 (file)
@@ -70,7 +70,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -86,7 +86,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xc4:
@@ -102,7 +102,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -112,13 +112,13 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-               device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  nvc4_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xc3:
@@ -134,7 +134,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -144,12 +144,12 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-               device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  nvc4_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xce:
@@ -165,7 +165,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -175,13 +175,13 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-               device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  nvc4_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xcf:
@@ -197,7 +197,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -207,13 +207,13 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvc0_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nvc0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-               device->oclass[NVDEV_ENGINE_GR     ] =  nvc3_graph_oclass;
+               device->oclass[NVDEV_ENGINE_GR     ] =  nvc4_graph_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nvc0_vp_oclass;
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xc1:
@@ -229,7 +229,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -244,7 +244,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xc8:
@@ -260,7 +260,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -276,7 +276,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nvc0_copy1_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nva3_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nva3_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xd9:
@@ -292,7 +292,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -307,7 +307,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nvd0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nvd0_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        case 0xd7:
@@ -323,7 +323,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -336,7 +336,7 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_BSP    ] = &nvc0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nvc0_copy0_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nvd0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nvd0_disp_oclass;
                device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
                break;
        default:
index 987edbc..9784cbf 100644 (file)
@@ -70,7 +70,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -81,7 +81,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nve0_disp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
@@ -103,7 +103,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -114,7 +114,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nve0_disp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
@@ -136,7 +136,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -147,7 +147,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nve4_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nve0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nve0_disp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
@@ -169,7 +169,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -180,7 +180,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nvf0_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nvf0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nvf0_disp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
@@ -204,7 +204,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
+               device->oclass[NVDEV_SUBDEV_LTCG   ] =  gf100_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
                device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
@@ -215,7 +215,7 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv108_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] =  nv108_graph_oclass;
-               device->oclass[NVDEV_ENGINE_DISP   ] = &nvf0_disp_oclass;
+               device->oclass[NVDEV_ENGINE_DISP   ] =  nvf0_disp_oclass;
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
index 1bd4c63..3ca2d25 100644 (file)
@@ -273,7 +273,7 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
                .outp = outp,
                .head = head,
        }, *dp = &_dp;
-       const u32 bw_list[] = { 270000, 162000, 0 };
+       const u32 bw_list[] = { 540000, 270000, 162000, 0 };
        const u32 *link_bw = bw_list;
        u8  hdr, cnt, len;
        u32 data;
@@ -312,6 +312,14 @@ nouveau_dp_train(struct nouveau_disp *disp, const struct nouveau_dp_func *func,
                ERR("failed to read DPCD\n");
        }
 
+       /* bring capabilities within encoder limits */
+       if ((dp->dpcd[2] & 0x1f) > dp->outp->dpconf.link_nr) {
+               dp->dpcd[2] &= ~0x1f;
+               dp->dpcd[2] |= dp->outp->dpconf.link_nr;
+       }
+       if (dp->dpcd[1] > dp->outp->dpconf.link_bw)
+               dp->dpcd[1] = dp->outp->dpconf.link_bw;
+
        /* adjust required bandwidth for 8B/10B coding overhead */
        datarate = (datarate / 8) * 10;
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
new file mode 100644 (file)
index 0000000..cf6f596
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <engine/software.h>
+#include <engine/disp.h>
+
+#include <core/class.h>
+
+#include "nv50.h"
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nouveau_oclass
+gm107_disp_sclass[] = {
+       { GM107_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs },
+       { GM107_DISP_SYNC_CLASS, &nvd0_disp_sync_ofuncs },
+       { GM107_DISP_OVLY_CLASS, &nvd0_disp_ovly_ofuncs },
+       { GM107_DISP_OIMM_CLASS, &nvd0_disp_oimm_ofuncs },
+       { GM107_DISP_CURS_CLASS, &nvd0_disp_curs_ofuncs },
+       {}
+};
+
+static struct nouveau_oclass
+gm107_disp_base_oclass[] = {
+       { GM107_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
+       {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct nv50_disp_priv *priv;
+       int heads = nv_rd32(parent, 0x022448);
+       int ret;
+
+       ret = nouveau_disp_create(parent, engine, oclass, heads,
+                                 "PDISP", "display", &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       nv_engine(priv)->sclass = gm107_disp_base_oclass;
+       nv_engine(priv)->cclass = &nv50_disp_cclass;
+       nv_subdev(priv)->intr = nvd0_disp_intr;
+       INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
+       priv->sclass = gm107_disp_sclass;
+       priv->head.nr = heads;
+       priv->dac.nr = 3;
+       priv->sor.nr = 4;
+       priv->dac.power = nv50_dac_power;
+       priv->dac.sense = nv50_dac_sense;
+       priv->sor.power = nv50_sor_power;
+       priv->sor.hda_eld = nvd0_hda_eld;
+       priv->sor.hdmi = nvd0_hdmi_ctrl;
+       priv->sor.dp = &nvd0_sor_dp_func;
+       return 0;
+}
+
+struct nouveau_oclass *
+gm107_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x07),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gm107_disp_ctor,
+               .dtor = _nouveau_disp_dtor,
+               .init = _nouveau_disp_init,
+               .fini = _nouveau_disp_fini,
+       },
+       .mthd.core = &nve0_disp_mast_mthd_chan,
+       .mthd.base = &nvd0_disp_sync_mthd_chan,
+       .mthd.ovly = &nve0_disp_ovly_mthd_chan,
+       .mthd.prev = -0x020000,
+}.base.base;
index 7cf8b13..6c89af7 100644 (file)
@@ -22,7 +22,7 @@
  * Authors: Ben Skeggs
  */
 
-#include <engine/disp.h>
+#include "priv.h"
 
 #include <core/event.h>
 #include <core/class.h>
@@ -138,13 +138,13 @@ nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nv04_disp_oclass = {
-       .handle = NV_ENGINE(DISP, 0x04),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv04_disp_oclass = &(struct nouveau_disp_impl) {
+       .base.handle = NV_ENGINE(DISP, 0x04),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv04_disp_ctor,
                .dtor = _nouveau_disp_dtor,
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
-};
+}.base;
index 9ad722e..9a0cab9 100644 (file)
@@ -26,8 +26,7 @@
 #include <core/parent.h>
 #include <core/handle.h>
 #include <core/class.h>
-
-#include <engine/disp.h>
+#include <core/enum.h>
 
 #include <subdev/bios.h>
 #include <subdev/bios/dcb.h>
@@ -227,6 +226,177 @@ nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
  * EVO master channel object
  ******************************************************************************/
 
+static void
+nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c,
+                   const struct nv50_disp_mthd_list *list, int inst)
+{
+       struct nouveau_object *disp = nv_object(priv);
+       int i;
+
+       for (i = 0; list->data[i].mthd; i++) {
+               if (list->data[i].addr) {
+                       u32 next = nv_rd32(priv, list->data[i].addr + base + 0);
+                       u32 prev = nv_rd32(priv, list->data[i].addr + base + c);
+                       u32 mthd = list->data[i].mthd + (list->mthd * inst);
+                       const char *name = list->data[i].name;
+                       char mods[16];
+
+                       if (prev != next)
+                               snprintf(mods, sizeof(mods), "-> 0x%08x", next);
+                       else
+                               snprintf(mods, sizeof(mods), "%13c", ' ');
+
+                       nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n",
+                                  mthd, prev, mods, name ? " // " : "",
+                                  name ? name : "");
+               }
+       }
+}
+
+void
+nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
+                   const struct nv50_disp_mthd_chan *chan)
+{
+       struct nouveau_object *disp = nv_object(priv);
+       const struct nv50_disp_impl *impl = (void *)disp->oclass;
+       const struct nv50_disp_mthd_list *list;
+       int i, j;
+
+       if (debug > nv_subdev(priv)->debug)
+               return;
+
+       for (i = 0; (list = chan->data[i].mthd) != NULL; i++) {
+               u32 base = head * chan->addr;
+               for (j = 0; j < chan->data[i].nr; j++, base += list->addr) {
+                       const char *cname = chan->name;
+                       const char *sname = "";
+                       char cname_[16], sname_[16];
+
+                       if (chan->addr) {
+                               snprintf(cname_, sizeof(cname_), "%s %d",
+                                        chan->name, head);
+                               cname = cname_;
+                       }
+
+                       if (chan->data[i].nr > 1) {
+                               snprintf(sname_, sizeof(sname_), " - %s %d",
+                                        chan->data[i].name, j);
+                               sname = sname_;
+                       }
+
+                       nv_printk_(disp, debug, "%s%s:\n", cname, sname);
+                       nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev,
+                                           list, j);
+               }
+       }
+}
+
+const struct nv50_disp_mthd_list
+nv50_disp_mast_mthd_base = {
+       .mthd = 0x0000,
+       .addr = 0x000000,
+       .data = {
+               { 0x0080, 0x000000 },
+               { 0x0084, 0x610bb8 },
+               { 0x0088, 0x610b9c },
+               { 0x008c, 0x000000 },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_list
+nv50_disp_mast_mthd_dac = {
+       .mthd = 0x0080,
+       .addr = 0x000008,
+       .data = {
+               { 0x0400, 0x610b58 },
+               { 0x0404, 0x610bdc },
+               { 0x0420, 0x610828 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_list
+nv50_disp_mast_mthd_sor = {
+       .mthd = 0x0040,
+       .addr = 0x000008,
+       .data = {
+               { 0x0600, 0x610b70 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_list
+nv50_disp_mast_mthd_pior = {
+       .mthd = 0x0040,
+       .addr = 0x000008,
+       .data = {
+               { 0x0700, 0x610b80 },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_list
+nv50_disp_mast_mthd_head = {
+       .mthd = 0x0400,
+       .addr = 0x000540,
+       .data = {
+               { 0x0800, 0x610ad8 },
+               { 0x0804, 0x610ad0 },
+               { 0x0808, 0x610a48 },
+               { 0x080c, 0x610a78 },
+               { 0x0810, 0x610ac0 },
+               { 0x0814, 0x610af8 },
+               { 0x0818, 0x610b00 },
+               { 0x081c, 0x610ae8 },
+               { 0x0820, 0x610af0 },
+               { 0x0824, 0x610b08 },
+               { 0x0828, 0x610b10 },
+               { 0x082c, 0x610a68 },
+               { 0x0830, 0x610a60 },
+               { 0x0834, 0x000000 },
+               { 0x0838, 0x610a40 },
+               { 0x0840, 0x610a24 },
+               { 0x0844, 0x610a2c },
+               { 0x0848, 0x610aa8 },
+               { 0x084c, 0x610ab0 },
+               { 0x0860, 0x610a84 },
+               { 0x0864, 0x610a90 },
+               { 0x0868, 0x610b18 },
+               { 0x086c, 0x610b20 },
+               { 0x0870, 0x610ac8 },
+               { 0x0874, 0x610a38 },
+               { 0x0880, 0x610a58 },
+               { 0x0884, 0x610a9c },
+               { 0x08a0, 0x610a70 },
+               { 0x08a4, 0x610a50 },
+               { 0x08a8, 0x610ae0 },
+               { 0x08c0, 0x610b28 },
+               { 0x08c4, 0x610b30 },
+               { 0x08c8, 0x610b40 },
+               { 0x08d4, 0x610b38 },
+               { 0x08d8, 0x610b48 },
+               { 0x08dc, 0x610b50 },
+               { 0x0900, 0x610a18 },
+               { 0x0904, 0x610ab8 },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_chan
+nv50_disp_mast_mthd_chan = {
+       .name = "Core",
+       .addr = 0x000000,
+       .data = {
+               { "Global", 1, &nv50_disp_mast_mthd_base },
+               {    "DAC", 3, &nv50_disp_mast_mthd_dac  },
+               {    "SOR", 2, &nv50_disp_mast_mthd_sor  },
+               {   "PIOR", 3, &nv50_disp_mast_mthd_pior },
+               {   "HEAD", 2, &nv50_disp_mast_mthd_head },
+               {}
+       }
+};
+
 static int
 nv50_disp_mast_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
@@ -323,6 +493,56 @@ nv50_disp_mast_ofuncs = {
  * EVO sync channel objects
  ******************************************************************************/
 
+static const struct nv50_disp_mthd_list
+nv50_disp_sync_mthd_base = {
+       .mthd = 0x0000,
+       .addr = 0x000000,
+       .data = {
+               { 0x0080, 0x000000 },
+               { 0x0084, 0x0008c4 },
+               { 0x0088, 0x0008d0 },
+               { 0x008c, 0x0008dc },
+               { 0x0090, 0x0008e4 },
+               { 0x0094, 0x610884 },
+               { 0x00a0, 0x6108a0 },
+               { 0x00a4, 0x610878 },
+               { 0x00c0, 0x61086c },
+               { 0x00e0, 0x610858 },
+               { 0x00e4, 0x610860 },
+               { 0x00e8, 0x6108ac },
+               { 0x00ec, 0x6108b4 },
+               { 0x0100, 0x610894 },
+               { 0x0110, 0x6108bc },
+               { 0x0114, 0x61088c },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_list
+nv50_disp_sync_mthd_image = {
+       .mthd = 0x0400,
+       .addr = 0x000000,
+       .data = {
+               { 0x0800, 0x6108f0 },
+               { 0x0804, 0x6108fc },
+               { 0x0808, 0x61090c },
+               { 0x080c, 0x610914 },
+               { 0x0810, 0x610904 },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_chan
+nv50_disp_sync_mthd_chan = {
+       .name = "Base",
+       .addr = 0x000540,
+       .data = {
+               { "Global", 1, &nv50_disp_sync_mthd_base },
+               {  "Image", 2, &nv50_disp_sync_mthd_image },
+               {}
+       }
+};
+
 static int
 nv50_disp_sync_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
@@ -362,6 +582,44 @@ nv50_disp_sync_ofuncs = {
  * EVO overlay channel objects
  ******************************************************************************/
 
+const struct nv50_disp_mthd_list
+nv50_disp_ovly_mthd_base = {
+       .mthd = 0x0000,
+       .addr = 0x000000,
+       .data = {
+               { 0x0080, 0x000000 },
+               { 0x0084, 0x0009a0 },
+               { 0x0088, 0x0009c0 },
+               { 0x008c, 0x0009c8 },
+               { 0x0090, 0x6109b4 },
+               { 0x0094, 0x610970 },
+               { 0x00a0, 0x610998 },
+               { 0x00a4, 0x610964 },
+               { 0x00c0, 0x610958 },
+               { 0x00e0, 0x6109a8 },
+               { 0x00e4, 0x6109d0 },
+               { 0x00e8, 0x6109d8 },
+               { 0x0100, 0x61094c },
+               { 0x0104, 0x610984 },
+               { 0x0108, 0x61098c },
+               { 0x0800, 0x6109f8 },
+               { 0x0808, 0x610a08 },
+               { 0x080c, 0x610a10 },
+               { 0x0810, 0x610a00 },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_chan
+nv50_disp_ovly_mthd_chan = {
+       .name = "Overlay",
+       .addr = 0x000540,
+       .data = {
+               { "Global", 1, &nv50_disp_ovly_mthd_base },
+               {}
+       }
+};
+
 static int
 nv50_disp_ovly_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
@@ -782,25 +1040,78 @@ nv50_disp_cclass = {
  * Display engine implementation
  ******************************************************************************/
 
-static void
-nv50_disp_intr_error(struct nv50_disp_priv *priv)
-{
-       u32 channels = (nv_rd32(priv, 0x610020) & 0x001f0000) >> 16;
-       u32 addr, data;
-       int chid;
-
-       for (chid = 0; chid < 5; chid++) {
-               if (!(channels & (1 << chid)))
-                       continue;
+static const struct nouveau_enum
+nv50_disp_intr_error_type[] = {
+       { 3, "ILLEGAL_MTHD" },
+       { 4, "INVALID_VALUE" },
+       { 5, "INVALID_STATE" },
+       { 7, "INVALID_HANDLE" },
+       {}
+};
 
-               nv_wr32(priv, 0x610020, 0x00010000 << chid);
-               addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
-               data = nv_rd32(priv, 0x610084 + (chid * 0x08));
-               nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
+static const struct nouveau_enum
+nv50_disp_intr_error_code[] = {
+       { 0x00, "" },
+       {}
+};
 
-               nv_error(priv, "chid %d mthd 0x%04x data 0x%08x 0x%08x\n",
-                        chid, addr & 0xffc, data, addr);
+static void
+nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
+{
+       struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+       u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
+       u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
+       u32 code = (addr & 0x00ff0000) >> 16;
+       u32 type = (addr & 0x00007000) >> 12;
+       u32 mthd = (addr & 0x00000ffc);
+       const struct nouveau_enum *ec, *et;
+       char ecunk[6], etunk[6];
+
+       et = nouveau_enum_find(nv50_disp_intr_error_type, type);
+       if (!et)
+               snprintf(etunk, sizeof(etunk), "UNK%02X", type);
+
+       ec = nouveau_enum_find(nv50_disp_intr_error_code, code);
+       if (!ec)
+               snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
+
+       nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
+                et ? et->name : etunk, ec ? ec->name : ecunk,
+                chid, mthd, data);
+
+       if (chid == 0) {
+               switch (mthd) {
+               case 0x0080:
+                       nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
+                                           impl->mthd.core);
+                       break;
+               default:
+                       break;
+               }
+       } else
+       if (chid <= 2) {
+               switch (mthd) {
+               case 0x0080:
+                       nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
+                                           impl->mthd.base);
+                       break;
+               default:
+                       break;
+               }
+       } else
+       if (chid <= 4) {
+               switch (mthd) {
+               case 0x0080:
+                       nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3,
+                                           impl->mthd.ovly);
+                       break;
+               default:
+                       break;
+               }
        }
+
+       nv_wr32(priv, 0x610020, 0x00010000 << chid);
+       nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
 }
 
 static u16
@@ -1241,12 +1552,14 @@ nv50_disp_intr_supervisor(struct work_struct *work)
 {
        struct nv50_disp_priv *priv =
                container_of(work, struct nv50_disp_priv, supervisor);
+       struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
        u32 super = nv_rd32(priv, 0x610030);
        int head;
 
        nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
 
        if (priv->super & 0x00000010) {
+               nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
                for (head = 0; head < priv->head.nr; head++) {
                        if (!(super & (0x00000020 << head)))
                                continue;
@@ -1290,9 +1603,10 @@ nv50_disp_intr(struct nouveau_subdev *subdev)
        u32 intr0 = nv_rd32(priv, 0x610020);
        u32 intr1 = nv_rd32(priv, 0x610024);
 
-       if (intr0 & 0x001f0000) {
-               nv50_disp_intr_error(priv);
-               intr0 &= ~0x001f0000;
+       while (intr0 & 0x001f0000) {
+               u32 chid = __ffs(intr0 & 0x001f0000) - 16;
+               nv50_disp_intr_error(priv, chid);
+               intr0 &= ~(0x00010000 << chid);
        }
 
        if (intr1 & 0x00000004) {
@@ -1346,13 +1660,17 @@ nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nv50_disp_oclass = {
-       .handle = NV_ENGINE(DISP, 0x50),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv50_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x50),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv50_disp_ctor,
                .dtor = _nouveau_disp_dtor,
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
-};
+       .mthd.core = &nv50_disp_mast_mthd_chan,
+       .mthd.base = &nv50_disp_sync_mthd_chan,
+       .mthd.ovly = &nv50_disp_ovly_mthd_chan,
+       .mthd.prev = 0x000004,
+}.base.base;
index d31d426..48d59db 100644 (file)
@@ -8,9 +8,19 @@
 #include <core/event.h>
 
 #include <engine/dmaobj.h>
-#include <engine/disp.h>
 
 #include "dport.h"
+#include "priv.h"
+
+struct nv50_disp_impl {
+       struct nouveau_disp_impl base;
+       struct {
+               const struct nv50_disp_mthd_chan *core;
+               const struct nv50_disp_mthd_chan *base;
+               const struct nv50_disp_mthd_chan *ovly;
+               int prev;
+       } mthd;
+};
 
 struct nv50_disp_priv {
        struct nouveau_disp base;
@@ -124,21 +134,60 @@ struct nv50_disp_pioc {
        struct nv50_disp_chan base;
 };
 
+struct nv50_disp_mthd_list {
+       u32 mthd;
+       u32 addr;
+       struct {
+               u32 mthd;
+               u32 addr;
+               const char *name;
+       } data[];
+};
+
+struct nv50_disp_mthd_chan {
+       const char *name;
+       u32 addr;
+       struct {
+               const char *name;
+               int nr;
+               const struct nv50_disp_mthd_list *mthd;
+       } data[];
+};
+
 extern struct nouveau_ofuncs nv50_disp_mast_ofuncs;
+extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_base;
+extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_sor;
+extern const struct nv50_disp_mthd_list nv50_disp_mast_mthd_pior;
 extern struct nouveau_ofuncs nv50_disp_sync_ofuncs;
+extern const struct nv50_disp_mthd_list nv50_disp_sync_mthd_image;
 extern struct nouveau_ofuncs nv50_disp_ovly_ofuncs;
+extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base;
 extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs;
 extern struct nouveau_ofuncs nv50_disp_curs_ofuncs;
 extern struct nouveau_ofuncs nv50_disp_base_ofuncs;
 extern struct nouveau_oclass nv50_disp_cclass;
+void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
+                        const struct nv50_disp_mthd_chan *);
 void nv50_disp_intr_supervisor(struct work_struct *);
 void nv50_disp_intr(struct nouveau_subdev *);
 
+extern const struct nv50_disp_mthd_chan nv84_disp_mast_mthd_chan;
+extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_dac;
+extern const struct nv50_disp_mthd_list nv84_disp_mast_mthd_head;
+extern const struct nv50_disp_mthd_chan nv84_disp_sync_mthd_chan;
+extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan;
 extern struct nouveau_omthds nv84_disp_base_omthds[];
 
+extern const struct nv50_disp_mthd_chan nv94_disp_mast_mthd_chan;
+
 extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs;
+extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_base;
+extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_dac;
+extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_sor;
+extern const struct nv50_disp_mthd_list nvd0_disp_mast_mthd_pior;
 extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs;
+extern const struct nv50_disp_mthd_chan nvd0_disp_sync_mthd_chan;
 extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs;
 extern struct nouveau_omthds nvd0_disp_base_omthds[];
@@ -147,4 +196,7 @@ extern struct nouveau_oclass nvd0_disp_cclass;
 void nvd0_disp_intr_supervisor(struct work_struct *);
 void nvd0_disp_intr(struct nouveau_subdev *);
 
+extern const struct nv50_disp_mthd_chan nve0_disp_mast_mthd_chan;
+extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;
+
 #endif
index ef9ce30..98c5b19 100644 (file)
 
 #include "nv50.h"
 
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+nv84_disp_mast_mthd_dac = {
+       .mthd = 0x0080,
+       .addr = 0x000008,
+       .data = {
+               { 0x0400, 0x610b58 },
+               { 0x0404, 0x610bdc },
+               { 0x0420, 0x610bc4 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_list
+nv84_disp_mast_mthd_head = {
+       .mthd = 0x0400,
+       .addr = 0x000540,
+       .data = {
+               { 0x0800, 0x610ad8 },
+               { 0x0804, 0x610ad0 },
+               { 0x0808, 0x610a48 },
+               { 0x080c, 0x610a78 },
+               { 0x0810, 0x610ac0 },
+               { 0x0814, 0x610af8 },
+               { 0x0818, 0x610b00 },
+               { 0x081c, 0x610ae8 },
+               { 0x0820, 0x610af0 },
+               { 0x0824, 0x610b08 },
+               { 0x0828, 0x610b10 },
+               { 0x082c, 0x610a68 },
+               { 0x0830, 0x610a60 },
+               { 0x0834, 0x000000 },
+               { 0x0838, 0x610a40 },
+               { 0x0840, 0x610a24 },
+               { 0x0844, 0x610a2c },
+               { 0x0848, 0x610aa8 },
+               { 0x084c, 0x610ab0 },
+               { 0x085c, 0x610c5c },
+               { 0x0860, 0x610a84 },
+               { 0x0864, 0x610a90 },
+               { 0x0868, 0x610b18 },
+               { 0x086c, 0x610b20 },
+               { 0x0870, 0x610ac8 },
+               { 0x0874, 0x610a38 },
+               { 0x0878, 0x610c50 },
+               { 0x0880, 0x610a58 },
+               { 0x0884, 0x610a9c },
+               { 0x089c, 0x610c68 },
+               { 0x08a0, 0x610a70 },
+               { 0x08a4, 0x610a50 },
+               { 0x08a8, 0x610ae0 },
+               { 0x08c0, 0x610b28 },
+               { 0x08c4, 0x610b30 },
+               { 0x08c8, 0x610b40 },
+               { 0x08d4, 0x610b38 },
+               { 0x08d8, 0x610b48 },
+               { 0x08dc, 0x610b50 },
+               { 0x0900, 0x610a18 },
+               { 0x0904, 0x610ab8 },
+               { 0x0910, 0x610c70 },
+               { 0x0914, 0x610c78 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_chan
+nv84_disp_mast_mthd_chan = {
+       .name = "Core",
+       .addr = 0x000000,
+       .data = {
+               { "Global", 1, &nv50_disp_mast_mthd_base },
+               {    "DAC", 3, &nv84_disp_mast_mthd_dac  },
+               {    "SOR", 2, &nv50_disp_mast_mthd_sor  },
+               {   "PIOR", 3, &nv50_disp_mast_mthd_pior },
+               {   "HEAD", 2, &nv84_disp_mast_mthd_head },
+               {}
+       }
+};
+
+/*******************************************************************************
+ * EVO sync channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+nv84_disp_sync_mthd_base = {
+       .mthd = 0x0000,
+       .addr = 0x000000,
+       .data = {
+               { 0x0080, 0x000000 },
+               { 0x0084, 0x0008c4 },
+               { 0x0088, 0x0008d0 },
+               { 0x008c, 0x0008dc },
+               { 0x0090, 0x0008e4 },
+               { 0x0094, 0x610884 },
+               { 0x00a0, 0x6108a0 },
+               { 0x00a4, 0x610878 },
+               { 0x00c0, 0x61086c },
+               { 0x00c4, 0x610800 },
+               { 0x00c8, 0x61080c },
+               { 0x00cc, 0x610818 },
+               { 0x00e0, 0x610858 },
+               { 0x00e4, 0x610860 },
+               { 0x00e8, 0x6108ac },
+               { 0x00ec, 0x6108b4 },
+               { 0x00fc, 0x610824 },
+               { 0x0100, 0x610894 },
+               { 0x0104, 0x61082c },
+               { 0x0110, 0x6108bc },
+               { 0x0114, 0x61088c },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_chan
+nv84_disp_sync_mthd_chan = {
+       .name = "Base",
+       .addr = 0x000540,
+       .data = {
+               { "Global", 1, &nv84_disp_sync_mthd_base },
+               {  "Image", 2, &nv50_disp_sync_mthd_image },
+               {}
+       }
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+nv84_disp_ovly_mthd_base = {
+       .mthd = 0x0000,
+       .addr = 0x000000,
+       .data = {
+               { 0x0080, 0x000000 },
+               { 0x0084, 0x6109a0 },
+               { 0x0088, 0x6109c0 },
+               { 0x008c, 0x6109c8 },
+               { 0x0090, 0x6109b4 },
+               { 0x0094, 0x610970 },
+               { 0x00a0, 0x610998 },
+               { 0x00a4, 0x610964 },
+               { 0x00c0, 0x610958 },
+               { 0x00e0, 0x6109a8 },
+               { 0x00e4, 0x6109d0 },
+               { 0x00e8, 0x6109d8 },
+               { 0x0100, 0x61094c },
+               { 0x0104, 0x610984 },
+               { 0x0108, 0x61098c },
+               { 0x0800, 0x6109f8 },
+               { 0x0808, 0x610a08 },
+               { 0x080c, 0x610a10 },
+               { 0x0810, 0x610a00 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_chan
+nv84_disp_ovly_mthd_chan = {
+       .name = "Overlay",
+       .addr = 0x000540,
+       .data = {
+               { "Global", 1, &nv84_disp_ovly_mthd_base },
+               {}
+       }
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
 static struct nouveau_oclass
 nv84_disp_sclass[] = {
        { NV84_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
@@ -59,6 +232,10 @@ nv84_disp_base_oclass[] = {
        {}
 };
 
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
 static int
 nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -91,13 +268,17 @@ nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nv84_disp_oclass = {
-       .handle = NV_ENGINE(DISP, 0x82),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv84_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x82),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv84_disp_ctor,
                .dtor = _nouveau_disp_dtor,
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
-};
+       .mthd.core = &nv84_disp_mast_mthd_chan,
+       .mthd.base = &nv84_disp_sync_mthd_chan,
+       .mthd.ovly = &nv84_disp_ovly_mthd_chan,
+       .mthd.prev = 0x000004,
+}.base.base;
index a518543..6844061 100644 (file)
 
 #include "nv50.h"
 
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+nv94_disp_mast_mthd_sor = {
+       .mthd = 0x0040,
+       .addr = 0x000008,
+       .data = {
+               { 0x0600, 0x610794 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_chan
+nv94_disp_mast_mthd_chan = {
+       .name = "Core",
+       .addr = 0x000000,
+       .data = {
+               { "Global", 1, &nv50_disp_mast_mthd_base },
+               {    "DAC", 3, &nv84_disp_mast_mthd_dac  },
+               {    "SOR", 4, &nv94_disp_mast_mthd_sor  },
+               {   "PIOR", 3, &nv50_disp_mast_mthd_pior },
+               {   "HEAD", 2, &nv84_disp_mast_mthd_head },
+               {}
+       }
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
 static struct nouveau_oclass
 nv94_disp_sclass[] = {
        { NV94_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
@@ -59,6 +91,10 @@ nv94_disp_base_oclass[] = {
        {}
 };
 
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
 static int
 nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -92,13 +128,17 @@ nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nv94_disp_oclass = {
-       .handle = NV_ENGINE(DISP, 0x88),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv94_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x88),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv94_disp_ctor,
                .dtor = _nouveau_disp_dtor,
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
-};
+       .mthd.core = &nv94_disp_mast_mthd_chan,
+       .mthd.base = &nv84_disp_sync_mthd_chan,
+       .mthd.ovly = &nv84_disp_ovly_mthd_chan,
+       .mthd.prev = 0x000004,
+}.base.base;
index 6cf8eef..88c9624 100644 (file)
 
 #include "nv50.h"
 
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+nva0_disp_ovly_mthd_base = {
+       .mthd = 0x0000,
+       .addr = 0x000000,
+       .data = {
+               { 0x0080, 0x000000 },
+               { 0x0084, 0x6109a0 },
+               { 0x0088, 0x6109c0 },
+               { 0x008c, 0x6109c8 },
+               { 0x0090, 0x6109b4 },
+               { 0x0094, 0x610970 },
+               { 0x00a0, 0x610998 },
+               { 0x00a4, 0x610964 },
+               { 0x00b0, 0x610c98 },
+               { 0x00b4, 0x610ca4 },
+               { 0x00b8, 0x610cac },
+               { 0x00c0, 0x610958 },
+               { 0x00e0, 0x6109a8 },
+               { 0x00e4, 0x6109d0 },
+               { 0x00e8, 0x6109d8 },
+               { 0x0100, 0x61094c },
+               { 0x0104, 0x610984 },
+               { 0x0108, 0x61098c },
+               { 0x0800, 0x6109f8 },
+               { 0x0808, 0x610a08 },
+               { 0x080c, 0x610a10 },
+               { 0x0810, 0x610a00 },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_chan
+nva0_disp_ovly_mthd_chan = {
+       .name = "Overlay",
+       .addr = 0x000540,
+       .data = {
+               { "Global", 1, &nva0_disp_ovly_mthd_base },
+               {}
+       }
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
 static struct nouveau_oclass
 nva0_disp_sclass[] = {
        { NVA0_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
@@ -45,6 +94,10 @@ nva0_disp_base_oclass[] = {
        {}
 };
 
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
 static int
 nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -77,13 +130,17 @@ nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nva0_disp_oclass = {
-       .handle = NV_ENGINE(DISP, 0x83),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nva0_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x83),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nva0_disp_ctor,
                .dtor = _nouveau_disp_dtor,
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
-};
+       .mthd.core = &nv84_disp_mast_mthd_chan,
+       .mthd.base = &nv84_disp_sync_mthd_chan,
+       .mthd.ovly = &nva0_disp_ovly_mthd_chan,
+       .mthd.prev = 0x000004,
+}.base.base;
index 6ad6dce..46cb2ce 100644 (file)
 
 #include "nv50.h"
 
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
 static struct nouveau_oclass
 nva3_disp_sclass[] = {
        { NVA3_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs },
@@ -60,6 +64,10 @@ nva3_disp_base_oclass[] = {
        {}
 };
 
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
 static int
 nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -94,13 +102,17 @@ nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nva3_disp_oclass = {
-       .handle = NV_ENGINE(DISP, 0x85),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nva3_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x85),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nva3_disp_ctor,
                .dtor = _nouveau_disp_dtor,
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
-};
+       .mthd.core = &nv94_disp_mast_mthd_chan,
+       .mthd.base = &nv84_disp_sync_mthd_chan,
+       .mthd.ovly = &nv84_disp_ovly_mthd_chan,
+       .mthd.prev = 0x000004,
+}.base.base;
index 1c5e4e8..7762665 100644 (file)
@@ -124,6 +124,146 @@ nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
  * EVO master channel object
  ******************************************************************************/
 
+const struct nv50_disp_mthd_list
+nvd0_disp_mast_mthd_base = {
+       .mthd = 0x0000,
+       .addr = 0x000000,
+       .data = {
+               { 0x0080, 0x660080 },
+               { 0x0084, 0x660084 },
+               { 0x0088, 0x660088 },
+               { 0x008c, 0x000000 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_list
+nvd0_disp_mast_mthd_dac = {
+       .mthd = 0x0020,
+       .addr = 0x000020,
+       .data = {
+               { 0x0180, 0x660180 },
+               { 0x0184, 0x660184 },
+               { 0x0188, 0x660188 },
+               { 0x0190, 0x660190 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_list
+nvd0_disp_mast_mthd_sor = {
+       .mthd = 0x0020,
+       .addr = 0x000020,
+       .data = {
+               { 0x0200, 0x660200 },
+               { 0x0204, 0x660204 },
+               { 0x0208, 0x660208 },
+               { 0x0210, 0x660210 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_list
+nvd0_disp_mast_mthd_pior = {
+       .mthd = 0x0020,
+       .addr = 0x000020,
+       .data = {
+               { 0x0300, 0x660300 },
+               { 0x0304, 0x660304 },
+               { 0x0308, 0x660308 },
+               { 0x0310, 0x660310 },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_list
+nvd0_disp_mast_mthd_head = {
+       .mthd = 0x0300,
+       .addr = 0x000300,
+       .data = {
+               { 0x0400, 0x660400 },
+               { 0x0404, 0x660404 },
+               { 0x0408, 0x660408 },
+               { 0x040c, 0x66040c },
+               { 0x0410, 0x660410 },
+               { 0x0414, 0x660414 },
+               { 0x0418, 0x660418 },
+               { 0x041c, 0x66041c },
+               { 0x0420, 0x660420 },
+               { 0x0424, 0x660424 },
+               { 0x0428, 0x660428 },
+               { 0x042c, 0x66042c },
+               { 0x0430, 0x660430 },
+               { 0x0434, 0x660434 },
+               { 0x0438, 0x660438 },
+               { 0x0440, 0x660440 },
+               { 0x0444, 0x660444 },
+               { 0x0448, 0x660448 },
+               { 0x044c, 0x66044c },
+               { 0x0450, 0x660450 },
+               { 0x0454, 0x660454 },
+               { 0x0458, 0x660458 },
+               { 0x045c, 0x66045c },
+               { 0x0460, 0x660460 },
+               { 0x0468, 0x660468 },
+               { 0x046c, 0x66046c },
+               { 0x0470, 0x660470 },
+               { 0x0474, 0x660474 },
+               { 0x0480, 0x660480 },
+               { 0x0484, 0x660484 },
+               { 0x048c, 0x66048c },
+               { 0x0490, 0x660490 },
+               { 0x0494, 0x660494 },
+               { 0x0498, 0x660498 },
+               { 0x04b0, 0x6604b0 },
+               { 0x04b8, 0x6604b8 },
+               { 0x04bc, 0x6604bc },
+               { 0x04c0, 0x6604c0 },
+               { 0x04c4, 0x6604c4 },
+               { 0x04c8, 0x6604c8 },
+               { 0x04d0, 0x6604d0 },
+               { 0x04d4, 0x6604d4 },
+               { 0x04e0, 0x6604e0 },
+               { 0x04e4, 0x6604e4 },
+               { 0x04e8, 0x6604e8 },
+               { 0x04ec, 0x6604ec },
+               { 0x04f0, 0x6604f0 },
+               { 0x04f4, 0x6604f4 },
+               { 0x04f8, 0x6604f8 },
+               { 0x04fc, 0x6604fc },
+               { 0x0500, 0x660500 },
+               { 0x0504, 0x660504 },
+               { 0x0508, 0x660508 },
+               { 0x050c, 0x66050c },
+               { 0x0510, 0x660510 },
+               { 0x0514, 0x660514 },
+               { 0x0518, 0x660518 },
+               { 0x051c, 0x66051c },
+               { 0x052c, 0x66052c },
+               { 0x0530, 0x660530 },
+               { 0x054c, 0x66054c },
+               { 0x0550, 0x660550 },
+               { 0x0554, 0x660554 },
+               { 0x0558, 0x660558 },
+               { 0x055c, 0x66055c },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_chan
+nvd0_disp_mast_mthd_chan = {
+       .name = "Core",
+       .addr = 0x000000,
+       .data = {
+               { "Global", 1, &nvd0_disp_mast_mthd_base },
+               {    "DAC", 3, &nvd0_disp_mast_mthd_dac  },
+               {    "SOR", 8, &nvd0_disp_mast_mthd_sor  },
+               {   "PIOR", 4, &nvd0_disp_mast_mthd_pior },
+               {   "HEAD", 4, &nvd0_disp_mast_mthd_head },
+               {}
+       }
+};
+
 static int
 nvd0_disp_mast_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
@@ -216,6 +356,81 @@ nvd0_disp_mast_ofuncs = {
  * EVO sync channel objects
  ******************************************************************************/
 
+static const struct nv50_disp_mthd_list
+nvd0_disp_sync_mthd_base = {
+       .mthd = 0x0000,
+       .addr = 0x000000,
+       .data = {
+               { 0x0080, 0x661080 },
+               { 0x0084, 0x661084 },
+               { 0x0088, 0x661088 },
+               { 0x008c, 0x66108c },
+               { 0x0090, 0x661090 },
+               { 0x0094, 0x661094 },
+               { 0x00a0, 0x6610a0 },
+               { 0x00a4, 0x6610a4 },
+               { 0x00c0, 0x6610c0 },
+               { 0x00c4, 0x6610c4 },
+               { 0x00c8, 0x6610c8 },
+               { 0x00cc, 0x6610cc },
+               { 0x00e0, 0x6610e0 },
+               { 0x00e4, 0x6610e4 },
+               { 0x00e8, 0x6610e8 },
+               { 0x00ec, 0x6610ec },
+               { 0x00fc, 0x6610fc },
+               { 0x0100, 0x661100 },
+               { 0x0104, 0x661104 },
+               { 0x0108, 0x661108 },
+               { 0x010c, 0x66110c },
+               { 0x0110, 0x661110 },
+               { 0x0114, 0x661114 },
+               { 0x0118, 0x661118 },
+               { 0x011c, 0x66111c },
+               { 0x0130, 0x661130 },
+               { 0x0134, 0x661134 },
+               { 0x0138, 0x661138 },
+               { 0x013c, 0x66113c },
+               { 0x0140, 0x661140 },
+               { 0x0144, 0x661144 },
+               { 0x0148, 0x661148 },
+               { 0x014c, 0x66114c },
+               { 0x0150, 0x661150 },
+               { 0x0154, 0x661154 },
+               { 0x0158, 0x661158 },
+               { 0x015c, 0x66115c },
+               { 0x0160, 0x661160 },
+               { 0x0164, 0x661164 },
+               { 0x0168, 0x661168 },
+               { 0x016c, 0x66116c },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_list
+nvd0_disp_sync_mthd_image = {
+       .mthd = 0x0400,
+       .addr = 0x000400,
+       .data = {
+               { 0x0400, 0x661400 },
+               { 0x0404, 0x661404 },
+               { 0x0408, 0x661408 },
+               { 0x040c, 0x66140c },
+               { 0x0410, 0x661410 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_chan
+nvd0_disp_sync_mthd_chan = {
+       .name = "Base",
+       .addr = 0x001000,
+       .data = {
+               { "Global", 1, &nvd0_disp_sync_mthd_base },
+               {  "Image", 2, &nvd0_disp_sync_mthd_image },
+               {}
+       }
+};
+
 static int
 nvd0_disp_sync_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
@@ -256,6 +471,68 @@ nvd0_disp_sync_ofuncs = {
  * EVO overlay channel objects
  ******************************************************************************/
 
+static const struct nv50_disp_mthd_list
+nvd0_disp_ovly_mthd_base = {
+       .mthd = 0x0000,
+       .data = {
+               { 0x0080, 0x665080 },
+               { 0x0084, 0x665084 },
+               { 0x0088, 0x665088 },
+               { 0x008c, 0x66508c },
+               { 0x0090, 0x665090 },
+               { 0x0094, 0x665094 },
+               { 0x00a0, 0x6650a0 },
+               { 0x00a4, 0x6650a4 },
+               { 0x00b0, 0x6650b0 },
+               { 0x00b4, 0x6650b4 },
+               { 0x00b8, 0x6650b8 },
+               { 0x00c0, 0x6650c0 },
+               { 0x00e0, 0x6650e0 },
+               { 0x00e4, 0x6650e4 },
+               { 0x00e8, 0x6650e8 },
+               { 0x0100, 0x665100 },
+               { 0x0104, 0x665104 },
+               { 0x0108, 0x665108 },
+               { 0x010c, 0x66510c },
+               { 0x0110, 0x665110 },
+               { 0x0118, 0x665118 },
+               { 0x011c, 0x66511c },
+               { 0x0120, 0x665120 },
+               { 0x0124, 0x665124 },
+               { 0x0130, 0x665130 },
+               { 0x0134, 0x665134 },
+               { 0x0138, 0x665138 },
+               { 0x013c, 0x66513c },
+               { 0x0140, 0x665140 },
+               { 0x0144, 0x665144 },
+               { 0x0148, 0x665148 },
+               { 0x014c, 0x66514c },
+               { 0x0150, 0x665150 },
+               { 0x0154, 0x665154 },
+               { 0x0158, 0x665158 },
+               { 0x015c, 0x66515c },
+               { 0x0160, 0x665160 },
+               { 0x0164, 0x665164 },
+               { 0x0168, 0x665168 },
+               { 0x016c, 0x66516c },
+               { 0x0400, 0x665400 },
+               { 0x0408, 0x665408 },
+               { 0x040c, 0x66540c },
+               { 0x0410, 0x665410 },
+               {}
+       }
+};
+
+static const struct nv50_disp_mthd_chan
+nvd0_disp_ovly_mthd_chan = {
+       .name = "Overlay",
+       .addr = 0x001000,
+       .data = {
+               { "Global", 1, &nvd0_disp_ovly_mthd_base },
+               {}
+       }
+};
+
 static int
 nvd0_disp_ovly_ctor(struct nouveau_object *parent,
                    struct nouveau_object *engine,
@@ -897,19 +1174,22 @@ nvd0_disp_intr_supervisor(struct work_struct *work)
 {
        struct nv50_disp_priv *priv =
                container_of(work, struct nv50_disp_priv, supervisor);
+       struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
        u32 mask[4];
        int head;
 
-       nv_debug(priv, "supervisor %08x\n", priv->super);
+       nv_debug(priv, "supervisor %d\n", ffs(priv->super));
        for (head = 0; head < priv->head.nr; head++) {
                mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800));
                nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]);
        }
 
        if (priv->super & 0x00000001) {
+               nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
                for (head = 0; head < priv->head.nr; head++) {
                        if (!(mask[head] & 0x00001000))
                                continue;
+                       nv_debug(priv, "supervisor 1.0 - head %d\n", head);
                        nvd0_disp_intr_unk1_0(priv, head);
                }
        } else
@@ -917,16 +1197,19 @@ nvd0_disp_intr_supervisor(struct work_struct *work)
                for (head = 0; head < priv->head.nr; head++) {
                        if (!(mask[head] & 0x00001000))
                                continue;
+                       nv_debug(priv, "supervisor 2.0 - head %d\n", head);
                        nvd0_disp_intr_unk2_0(priv, head);
                }
                for (head = 0; head < priv->head.nr; head++) {
                        if (!(mask[head] & 0x00010000))
                                continue;
+                       nv_debug(priv, "supervisor 2.1 - head %d\n", head);
                        nvd0_disp_intr_unk2_1(priv, head);
                }
                for (head = 0; head < priv->head.nr; head++) {
                        if (!(mask[head] & 0x00001000))
                                continue;
+                       nv_debug(priv, "supervisor 2.2 - head %d\n", head);
                        nvd0_disp_intr_unk2_2(priv, head);
                }
        } else
@@ -934,6 +1217,7 @@ nvd0_disp_intr_supervisor(struct work_struct *work)
                for (head = 0; head < priv->head.nr; head++) {
                        if (!(mask[head] & 0x00001000))
                                continue;
+                       nv_debug(priv, "supervisor 3.0 - head %d\n", head);
                        nvd0_disp_intr_unk4_0(priv, head);
                }
        }
@@ -943,6 +1227,53 @@ nvd0_disp_intr_supervisor(struct work_struct *work)
        nv_wr32(priv, 0x6101d0, 0x80000000);
 }
 
+static void
+nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid)
+{
+       const struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+       u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12));
+       u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12));
+       u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12));
+
+       nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
+                      "0x%08x 0x%08x\n",
+                chid, (mthd & 0x0000ffc), data, mthd, unkn);
+
+       if (chid == 0) {
+               switch (mthd) {
+               case 0x0080:
+                       nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
+                                           impl->mthd.core);
+                       break;
+               default:
+                       break;
+               }
+       } else
+       if (chid <= 4) {
+               switch (mthd) {
+               case 0x0080:
+                       nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
+                                           impl->mthd.base);
+                       break;
+               default:
+                       break;
+               }
+       } else
+       if (chid <= 8) {
+               switch (mthd) {
+               case 0x0080:
+                       nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5,
+                                           impl->mthd.ovly);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       nv_wr32(priv, 0x61009c, (1 << chid));
+       nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
+}
+
 void
 nvd0_disp_intr(struct nouveau_subdev *subdev)
 {
@@ -959,18 +1290,8 @@ nvd0_disp_intr(struct nouveau_subdev *subdev)
        if (intr & 0x00000002) {
                u32 stat = nv_rd32(priv, 0x61009c);
                int chid = ffs(stat) - 1;
-               if (chid >= 0) {
-                       u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12));
-                       u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12));
-                       u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12));
-
-                       nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
-                                      "0x%08x 0x%08x\n",
-                                chid, (mthd & 0x0000ffc), data, mthd, unkn);
-                       nv_wr32(priv, 0x61009c, (1 << chid));
-                       nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
-               }
-
+               if (chid >= 0)
+                       nvd0_disp_intr_error(priv, chid);
                intr &= ~0x00000002;
        }
 
@@ -1035,13 +1356,17 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nvd0_disp_oclass = {
-       .handle = NV_ENGINE(DISP, 0x90),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nvd0_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x90),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nvd0_disp_ctor,
                .dtor = _nouveau_disp_dtor,
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
-};
+       .mthd.core = &nvd0_disp_mast_mthd_chan,
+       .mthd.base = &nvd0_disp_sync_mthd_chan,
+       .mthd.ovly = &nvd0_disp_ovly_mthd_chan,
+       .mthd.prev = -0x020000,
+}.base.base;
index ab63f32..44e0b8f 100644 (file)
 
 #include "nv50.h"
 
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+nve0_disp_mast_mthd_head = {
+       .mthd = 0x0300,
+       .addr = 0x000300,
+       .data = {
+               { 0x0400, 0x660400 },
+               { 0x0404, 0x660404 },
+               { 0x0408, 0x660408 },
+               { 0x040c, 0x66040c },
+               { 0x0410, 0x660410 },
+               { 0x0414, 0x660414 },
+               { 0x0418, 0x660418 },
+               { 0x041c, 0x66041c },
+               { 0x0420, 0x660420 },
+               { 0x0424, 0x660424 },
+               { 0x0428, 0x660428 },
+               { 0x042c, 0x66042c },
+               { 0x0430, 0x660430 },
+               { 0x0434, 0x660434 },
+               { 0x0438, 0x660438 },
+               { 0x0440, 0x660440 },
+               { 0x0444, 0x660444 },
+               { 0x0448, 0x660448 },
+               { 0x044c, 0x66044c },
+               { 0x0450, 0x660450 },
+               { 0x0454, 0x660454 },
+               { 0x0458, 0x660458 },
+               { 0x045c, 0x66045c },
+               { 0x0460, 0x660460 },
+               { 0x0468, 0x660468 },
+               { 0x046c, 0x66046c },
+               { 0x0470, 0x660470 },
+               { 0x0474, 0x660474 },
+               { 0x047c, 0x66047c },
+               { 0x0480, 0x660480 },
+               { 0x0484, 0x660484 },
+               { 0x0488, 0x660488 },
+               { 0x048c, 0x66048c },
+               { 0x0490, 0x660490 },
+               { 0x0494, 0x660494 },
+               { 0x0498, 0x660498 },
+               { 0x04a0, 0x6604a0 },
+               { 0x04b0, 0x6604b0 },
+               { 0x04b8, 0x6604b8 },
+               { 0x04bc, 0x6604bc },
+               { 0x04c0, 0x6604c0 },
+               { 0x04c4, 0x6604c4 },
+               { 0x04c8, 0x6604c8 },
+               { 0x04d0, 0x6604d0 },
+               { 0x04d4, 0x6604d4 },
+               { 0x04e0, 0x6604e0 },
+               { 0x04e4, 0x6604e4 },
+               { 0x04e8, 0x6604e8 },
+               { 0x04ec, 0x6604ec },
+               { 0x04f0, 0x6604f0 },
+               { 0x04f4, 0x6604f4 },
+               { 0x04f8, 0x6604f8 },
+               { 0x04fc, 0x6604fc },
+               { 0x0500, 0x660500 },
+               { 0x0504, 0x660504 },
+               { 0x0508, 0x660508 },
+               { 0x050c, 0x66050c },
+               { 0x0510, 0x660510 },
+               { 0x0514, 0x660514 },
+               { 0x0518, 0x660518 },
+               { 0x051c, 0x66051c },
+               { 0x0520, 0x660520 },
+               { 0x0524, 0x660524 },
+               { 0x052c, 0x66052c },
+               { 0x0530, 0x660530 },
+               { 0x054c, 0x66054c },
+               { 0x0550, 0x660550 },
+               { 0x0554, 0x660554 },
+               { 0x0558, 0x660558 },
+               { 0x055c, 0x66055c },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_chan
+nve0_disp_mast_mthd_chan = {
+       .name = "Core",
+       .addr = 0x000000,
+       .data = {
+               { "Global", 1, &nvd0_disp_mast_mthd_base },
+               {    "DAC", 3, &nvd0_disp_mast_mthd_dac  },
+               {    "SOR", 8, &nvd0_disp_mast_mthd_sor  },
+               {   "PIOR", 4, &nvd0_disp_mast_mthd_pior },
+               {   "HEAD", 4, &nve0_disp_mast_mthd_head },
+               {}
+       }
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+nve0_disp_ovly_mthd_base = {
+       .mthd = 0x0000,
+       .data = {
+               { 0x0080, 0x665080 },
+               { 0x0084, 0x665084 },
+               { 0x0088, 0x665088 },
+               { 0x008c, 0x66508c },
+               { 0x0090, 0x665090 },
+               { 0x0094, 0x665094 },
+               { 0x00a0, 0x6650a0 },
+               { 0x00a4, 0x6650a4 },
+               { 0x00b0, 0x6650b0 },
+               { 0x00b4, 0x6650b4 },
+               { 0x00b8, 0x6650b8 },
+               { 0x00c0, 0x6650c0 },
+               { 0x00c4, 0x6650c4 },
+               { 0x00e0, 0x6650e0 },
+               { 0x00e4, 0x6650e4 },
+               { 0x00e8, 0x6650e8 },
+               { 0x0100, 0x665100 },
+               { 0x0104, 0x665104 },
+               { 0x0108, 0x665108 },
+               { 0x010c, 0x66510c },
+               { 0x0110, 0x665110 },
+               { 0x0118, 0x665118 },
+               { 0x011c, 0x66511c },
+               { 0x0120, 0x665120 },
+               { 0x0124, 0x665124 },
+               { 0x0130, 0x665130 },
+               { 0x0134, 0x665134 },
+               { 0x0138, 0x665138 },
+               { 0x013c, 0x66513c },
+               { 0x0140, 0x665140 },
+               { 0x0144, 0x665144 },
+               { 0x0148, 0x665148 },
+               { 0x014c, 0x66514c },
+               { 0x0150, 0x665150 },
+               { 0x0154, 0x665154 },
+               { 0x0158, 0x665158 },
+               { 0x015c, 0x66515c },
+               { 0x0160, 0x665160 },
+               { 0x0164, 0x665164 },
+               { 0x0168, 0x665168 },
+               { 0x016c, 0x66516c },
+               { 0x0400, 0x665400 },
+               { 0x0404, 0x665404 },
+               { 0x0408, 0x665408 },
+               { 0x040c, 0x66540c },
+               { 0x0410, 0x665410 },
+               {}
+       }
+};
+
+const struct nv50_disp_mthd_chan
+nve0_disp_ovly_mthd_chan = {
+       .name = "Overlay",
+       .addr = 0x001000,
+       .data = {
+               { "Global", 1, &nve0_disp_ovly_mthd_base },
+               {}
+       }
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
 static struct nouveau_oclass
 nve0_disp_sclass[] = {
        { NVE0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs },
@@ -45,6 +214,10 @@ nve0_disp_base_oclass[] = {
        {}
 };
 
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
 static int
 nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -77,13 +250,17 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nve0_disp_oclass = {
-       .handle = NV_ENGINE(DISP, 0x91),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nve0_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x91),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nve0_disp_ctor,
                .dtor = _nouveau_disp_dtor,
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
-};
+       .mthd.core = &nve0_disp_mast_mthd_chan,
+       .mthd.base = &nvd0_disp_sync_mthd_chan,
+       .mthd.ovly = &nve0_disp_ovly_mthd_chan,
+       .mthd.prev = -0x020000,
+}.base.base;
index 05fee10..482585d 100644 (file)
 
 #include "nv50.h"
 
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
 static struct nouveau_oclass
 nvf0_disp_sclass[] = {
        { NVF0_DISP_MAST_CLASS, &nvd0_disp_mast_ofuncs },
@@ -45,6 +49,10 @@ nvf0_disp_base_oclass[] = {
        {}
 };
 
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
 static int
 nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
               struct nouveau_oclass *oclass, void *data, u32 size,
@@ -77,13 +85,17 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nouveau_oclass
-nvf0_disp_oclass = {
-       .handle = NV_ENGINE(DISP, 0x92),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nvf0_disp_oclass = &(struct nv50_disp_impl) {
+       .base.base.handle = NV_ENGINE(DISP, 0x92),
+       .base.base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nvf0_disp_ctor,
                .dtor = _nouveau_disp_dtor,
                .init = _nouveau_disp_init,
                .fini = _nouveau_disp_fini,
        },
-};
+       .mthd.core = &nve0_disp_mast_mthd_chan,
+       .mthd.base = &nvd0_disp_sync_mthd_chan,
+       .mthd.ovly = &nve0_disp_ovly_mthd_chan,
+       .mthd.prev = -0x020000,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
new file mode 100644 (file)
index 0000000..cc3c7a4
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __NVKM_DISP_PRIV_H__
+#define __NVKM_DISP_PRIV_H__
+
+#include <engine/disp.h>
+
+struct nouveau_disp_impl {
+       struct nouveau_oclass base;
+};
+
+#endif
index 944e73a..1cfb3bb 100644 (file)
@@ -53,6 +53,9 @@ nvd0_dmaobj_bind(struct nouveau_dmaeng *dmaeng,
                case NVF0_DISP_MAST_CLASS:
                case NVF0_DISP_SYNC_CLASS:
                case NVF0_DISP_OVLY_CLASS:
+               case GM107_DISP_MAST_CLASS:
+               case GM107_DISP_SYNC_CLASS:
+               case GM107_DISP_OVLY_CLASS:
                        break;
                default:
                        return -EINVAL;
index 5e077e4..2914646 100644 (file)
@@ -119,7 +119,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
                snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x",
                         device->chipset, falcon->addr >> 12);
 
-               ret = request_firmware(&fw, name, &device->pdev->dev);
+               ret = request_firmware(&fw, name, nv_device_base(device));
                if (ret == 0) {
                        falcon->code.data = vmemdup(fw->data, fw->size);
                        falcon->code.size = fw->size;
@@ -138,7 +138,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
                snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd",
                         device->chipset, falcon->addr >> 12);
 
-               ret = request_firmware(&fw, name, &device->pdev->dev);
+               ret = request_firmware(&fw, name, nv_device_base(device));
                if (ret) {
                        nv_error(falcon, "unable to load firmware data\n");
                        return ret;
@@ -153,7 +153,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
                snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc",
                         device->chipset, falcon->addr >> 12);
 
-               ret = request_firmware(&fw, name, &device->pdev->dev);
+               ret = request_firmware(&fw, name, nv_device_base(device));
                if (ret) {
                        nv_error(falcon, "unable to load firmware code\n");
                        return ret;
index d3ec436..6f9041c 100644 (file)
@@ -86,7 +86,7 @@ nouveau_fifo_channel_create_(struct nouveau_object *parent,
        }
 
        /* map fifo control registers */
-       chan->user = ioremap(pci_resource_start(device->pdev, bar) + addr +
+       chan->user = ioremap(nv_device_resource_start(device, bar) + addr +
                             (chan->chid * size), size);
        if (!chan->user)
                return -EFAULT;
index b22a33f..fa1e719 100644 (file)
 
 struct nvc0_fifo_priv {
        struct nouveau_fifo base;
-       struct nouveau_gpuobj *playlist[2];
-       int cur_playlist;
+
+       struct work_struct fault;
+       u64 mask;
+
+       struct {
+               struct nouveau_gpuobj *mem[2];
+               int active;
+               wait_queue_head_t wait;
+       } runlist;
+
        struct {
                struct nouveau_gpuobj *mem;
                struct nouveau_vma bar;
@@ -58,6 +66,11 @@ struct nvc0_fifo_base {
 
 struct nvc0_fifo_chan {
        struct nouveau_fifo_chan base;
+       enum {
+               STOPPED,
+               RUNNING,
+               KILLED
+       } state;
 };
 
 /*******************************************************************************
@@ -65,29 +78,33 @@ struct nvc0_fifo_chan {
  ******************************************************************************/
 
 static void
-nvc0_fifo_playlist_update(struct nvc0_fifo_priv *priv)
+nvc0_fifo_runlist_update(struct nvc0_fifo_priv *priv)
 {
        struct nouveau_bar *bar = nouveau_bar(priv);
        struct nouveau_gpuobj *cur;
        int i, p;
 
        mutex_lock(&nv_subdev(priv)->mutex);
-       cur = priv->playlist[priv->cur_playlist];
-       priv->cur_playlist = !priv->cur_playlist;
+       cur = priv->runlist.mem[priv->runlist.active];
+       priv->runlist.active = !priv->runlist.active;
 
        for (i = 0, p = 0; i < 128; i++) {
-               if (!(nv_rd32(priv, 0x003004 + (i * 8)) & 1))
-                       continue;
-               nv_wo32(cur, p + 0, i);
-               nv_wo32(cur, p + 4, 0x00000004);
-               p += 8;
+               struct nvc0_fifo_chan *chan = (void *)priv->base.channel[i];
+               if (chan && chan->state == RUNNING) {
+                       nv_wo32(cur, p + 0, i);
+                       nv_wo32(cur, p + 4, 0x00000004);
+                       p += 8;
+               }
        }
        bar->flush(bar);
 
        nv_wr32(priv, 0x002270, cur->addr >> 12);
        nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
-       if (!nv_wait(priv, 0x00227c, 0x00100000, 0x00000000))
-               nv_error(priv, "playlist update failed\n");
+
+       if (wait_event_timeout(priv->runlist.wait,
+                              !(nv_rd32(priv, 0x00227c) & 0x00100000),
+                              msecs_to_jiffies(2000)) == 0)
+               nv_error(priv, "runlist update timeout\n");
        mutex_unlock(&nv_subdev(priv)->mutex);
 }
 
@@ -239,30 +256,32 @@ nvc0_fifo_chan_init(struct nouveau_object *object)
                return ret;
 
        nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
-       nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
-       nvc0_fifo_playlist_update(priv);
+
+       if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
+               nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
+               nvc0_fifo_runlist_update(priv);
+       }
+
        return 0;
 }
 
+static void nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv);
+
 static int
 nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
 {
        struct nvc0_fifo_priv *priv = (void *)object->engine;
        struct nvc0_fifo_chan *chan = (void *)object;
        u32 chid = chan->base.chid;
-       u32 mask, engine;
 
-       nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
-       nvc0_fifo_playlist_update(priv);
-       mask = nv_rd32(priv, 0x0025a4);
-       for (engine = 0; mask && engine < 16; engine++) {
-               if (!(mask & (1 << engine)))
-                       continue;
-               nv_mask(priv, 0x0025a8 + (engine * 4), 0x00000000, 0x00000000);
-               mask &= ~(1 << engine);
+       if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
+               nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
+               nvc0_fifo_runlist_update(priv);
        }
-       nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
 
+       nvc0_fifo_intr_engine(priv);
+
+       nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
        return nouveau_fifo_channel_fini(&chan->base, suspend);
 }
 
@@ -345,11 +364,177 @@ nvc0_fifo_cclass = {
  * PFIFO engine
  ******************************************************************************/
 
-static const struct nouveau_enum nvc0_fifo_fault_unit[] = {
+static inline int
+nvc0_fifo_engidx(struct nvc0_fifo_priv *priv, u32 engn)
+{
+       switch (engn) {
+       case NVDEV_ENGINE_GR   : engn = 0; break;
+       case NVDEV_ENGINE_BSP  : engn = 1; break;
+       case NVDEV_ENGINE_PPP  : engn = 2; break;
+       case NVDEV_ENGINE_VP   : engn = 3; break;
+       case NVDEV_ENGINE_COPY0: engn = 4; break;
+       case NVDEV_ENGINE_COPY1: engn = 5; break;
+       default:
+               return -1;
+       }
+
+       return engn;
+}
+
+static inline struct nouveau_engine *
+nvc0_fifo_engine(struct nvc0_fifo_priv *priv, u32 engn)
+{
+       switch (engn) {
+       case 0: engn = NVDEV_ENGINE_GR; break;
+       case 1: engn = NVDEV_ENGINE_BSP; break;
+       case 2: engn = NVDEV_ENGINE_PPP; break;
+       case 3: engn = NVDEV_ENGINE_VP; break;
+       case 4: engn = NVDEV_ENGINE_COPY0; break;
+       case 5: engn = NVDEV_ENGINE_COPY1; break;
+       default:
+               return NULL;
+       }
+
+       return nouveau_engine(priv, engn);
+}
+
+static void
+nvc0_fifo_recover_work(struct work_struct *work)
+{
+       struct nvc0_fifo_priv *priv = container_of(work, typeof(*priv), fault);
+       struct nouveau_object *engine;
+       unsigned long flags;
+       u32 engn, engm = 0;
+       u64 mask, todo;
+
+       spin_lock_irqsave(&priv->base.lock, flags);
+       mask = priv->mask;
+       priv->mask = 0ULL;
+       spin_unlock_irqrestore(&priv->base.lock, flags);
+
+       for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
+               engm |= 1 << nvc0_fifo_engidx(priv, engn);
+       nv_mask(priv, 0x002630, engm, engm);
+
+       for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
+               if ((engine = (void *)nouveau_engine(priv, engn))) {
+                       nv_ofuncs(engine)->fini(engine, false);
+                       WARN_ON(nv_ofuncs(engine)->init(engine));
+               }
+       }
+
+       nvc0_fifo_runlist_update(priv);
+       nv_wr32(priv, 0x00262c, engm);
+       nv_mask(priv, 0x002630, engm, 0x00000000);
+}
+
+static void
+nvc0_fifo_recover(struct nvc0_fifo_priv *priv, struct nouveau_engine *engine,
+                 struct nvc0_fifo_chan *chan)
+{
+       struct nouveau_object *engobj = nv_object(engine);
+       u32 chid = chan->base.chid;
+       unsigned long flags;
+
+       nv_error(priv, "%s engine fault on channel %d, recovering...\n",
+                      nv_subdev(engine)->name, chid);
+
+       nv_mask(priv, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000);
+       chan->state = KILLED;
+
+       spin_lock_irqsave(&priv->base.lock, flags);
+       priv->mask |= 1ULL << nv_engidx(engobj);
+       spin_unlock_irqrestore(&priv->base.lock, flags);
+       schedule_work(&priv->fault);
+}
+
+static int
+nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
+{
+       struct nvc0_fifo_chan *chan = NULL;
+       struct nouveau_handle *bind;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&priv->base.lock, flags);
+       if (likely(chid >= priv->base.min && chid <= priv->base.max))
+               chan = (void *)priv->base.channel[chid];
+       if (unlikely(!chan))
+               goto out;
+
+       bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
+       if (likely(bind)) {
+               if (!mthd || !nv_call(bind->object, mthd, data))
+                       ret = 0;
+               nouveau_namedb_put(bind);
+       }
+
+out:
+       spin_unlock_irqrestore(&priv->base.lock, flags);
+       return ret;
+}
+
+static const struct nouveau_enum
+nvc0_fifo_sched_reason[] = {
+       { 0x0a, "CTXSW_TIMEOUT" },
+       {}
+};
+
+static void
+nvc0_fifo_intr_sched_ctxsw(struct nvc0_fifo_priv *priv)
+{
+       struct nouveau_engine *engine;
+       struct nvc0_fifo_chan *chan;
+       u32 engn;
+
+       for (engn = 0; engn < 6; engn++) {
+               u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
+               u32 busy = (stat & 0x80000000);
+               u32 save = (stat & 0x00100000); /* maybe? */
+               u32 unk0 = (stat & 0x00040000);
+               u32 unk1 = (stat & 0x00001000);
+               u32 chid = (stat & 0x0000007f);
+               (void)save;
+
+               if (busy && unk0 && unk1) {
+                       if (!(chan = (void *)priv->base.channel[chid]))
+                               continue;
+                       if (!(engine = nvc0_fifo_engine(priv, engn)))
+                               continue;
+                       nvc0_fifo_recover(priv, engine, chan);
+               }
+       }
+}
+
+static void
+nvc0_fifo_intr_sched(struct nvc0_fifo_priv *priv)
+{
+       u32 intr = nv_rd32(priv, 0x00254c);
+       u32 code = intr & 0x000000ff;
+       const struct nouveau_enum *en;
+       char enunk[6] = "";
+
+       en = nouveau_enum_find(nvc0_fifo_sched_reason, code);
+       if (!en)
+               snprintf(enunk, sizeof(enunk), "UNK%02x", code);
+
+       nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
+
+       switch (code) {
+       case 0x0a:
+               nvc0_fifo_intr_sched_ctxsw(priv);
+               break;
+       default:
+               break;
+       }
+}
+
+static const struct nouveau_enum
+nvc0_fifo_fault_engine[] = {
        { 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR },
-       { 0x03, "PEEPHOLE" },
-       { 0x04, "BAR1" },
-       { 0x05, "BAR3" },
+       { 0x03, "PEEPHOLE", NULL, NVDEV_ENGINE_IFB },
+       { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
+       { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
        { 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO },
        { 0x10, "PBSP", NULL, NVDEV_ENGINE_BSP },
        { 0x11, "PPPP", NULL, NVDEV_ENGINE_PPP },
@@ -361,7 +546,8 @@ static const struct nouveau_enum nvc0_fifo_fault_unit[] = {
        {}
 };
 
-static const struct nouveau_enum nvc0_fifo_fault_reason[] = {
+static const struct nouveau_enum
+nvc0_fifo_fault_reason[] = {
        { 0x00, "PT_NOT_PRESENT" },
        { 0x01, "PT_TOO_SHORT" },
        { 0x02, "PAGE_NOT_PRESENT" },
@@ -374,7 +560,8 @@ static const struct nouveau_enum nvc0_fifo_fault_reason[] = {
        {}
 };
 
-static const struct nouveau_enum nvc0_fifo_fault_hubclient[] = {
+static const struct nouveau_enum
+nvc0_fifo_fault_hubclient[] = {
        { 0x01, "PCOPY0" },
        { 0x02, "PCOPY1" },
        { 0x04, "DISPATCH" },
@@ -392,7 +579,8 @@ static const struct nouveau_enum nvc0_fifo_fault_hubclient[] = {
        {}
 };
 
-static const struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
+static const struct nouveau_enum
+nvc0_fifo_fault_gpcclient[] = {
        { 0x01, "TEX" },
        { 0x0c, "ESETUP" },
        { 0x0e, "CTXCTL" },
@@ -400,92 +588,92 @@ static const struct nouveau_enum nvc0_fifo_fault_gpcclient[] = {
        {}
 };
 
-static const struct nouveau_bitfield nvc0_fifo_subfifo_intr[] = {
-/*     { 0x00008000, "" }      seen with null ib push */
-       { 0x00200000, "ILLEGAL_MTHD" },
-       { 0x00800000, "EMPTY_SUBC" },
-       {}
-};
-
 static void
-nvc0_fifo_isr_vm_fault(struct nvc0_fifo_priv *priv, int unit)
+nvc0_fifo_intr_fault(struct nvc0_fifo_priv *priv, int unit)
 {
        u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
        u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
        u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
        u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
+       u32 gpc    = (stat & 0x1f000000) >> 24;
        u32 client = (stat & 0x00001f00) >> 8;
-       const struct nouveau_enum *en;
-       struct nouveau_engine *engine;
-       struct nouveau_object *engctx = NULL;
-
-       switch (unit) {
-       case 3: /* PEEPHOLE */
-               nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
-               break;
-       case 4: /* BAR1 */
-               nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
-               break;
-       case 5: /* BAR3 */
-               nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
-               break;
-       default:
-               break;
+       u32 write  = (stat & 0x00000080);
+       u32 hub    = (stat & 0x00000040);
+       u32 reason = (stat & 0x0000000f);
+       struct nouveau_object *engctx = NULL, *object;
+       struct nouveau_engine *engine = NULL;
+       const struct nouveau_enum *er, *eu, *ec;
+       char erunk[6] = "";
+       char euunk[6] = "";
+       char ecunk[6] = "";
+       char gpcid[3] = "";
+
+       er = nouveau_enum_find(nvc0_fifo_fault_reason, reason);
+       if (!er)
+               snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
+
+       eu = nouveau_enum_find(nvc0_fifo_fault_engine, unit);
+       if (eu) {
+               switch (eu->data2) {
+               case NVDEV_SUBDEV_BAR:
+                       nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
+                       break;
+               case NVDEV_SUBDEV_INSTMEM:
+                       nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
+                       break;
+               case NVDEV_ENGINE_IFB:
+                       nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
+                       break;
+               default:
+                       engine = nouveau_engine(priv, eu->data2);
+                       if (engine)
+                               engctx = nouveau_engctx_get(engine, inst);
+                       break;
+               }
+       } else {
+               snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
        }
 
-       nv_error(priv, "%s fault at 0x%010llx [", (stat & 0x00000080) ?
-                "write" : "read", (u64)vahi << 32 | valo);
-       nouveau_enum_print(nvc0_fifo_fault_reason, stat & 0x0000000f);
-       pr_cont("] from ");
-       en = nouveau_enum_print(nvc0_fifo_fault_unit, unit);
-       if (stat & 0x00000040) {
-               pr_cont("/");
-               nouveau_enum_print(nvc0_fifo_fault_hubclient, client);
+       if (hub) {
+               ec = nouveau_enum_find(nvc0_fifo_fault_hubclient, client);
        } else {
-               pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24);
-               nouveau_enum_print(nvc0_fifo_fault_gpcclient, client);
+               ec = nouveau_enum_find(nvc0_fifo_fault_gpcclient, client);
+               snprintf(gpcid, sizeof(gpcid), "%d", gpc);
        }
 
-       if (en && en->data2) {
-               engine = nouveau_engine(priv, en->data2);
-               if (engine)
-                       engctx = nouveau_engctx_get(engine, inst);
-
+       if (!ec)
+               snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
+
+       nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
+                      "channel 0x%010llx [%s]\n", write ? "write" : "read",
+                (u64)vahi << 32 | valo, er ? er->name : erunk,
+                eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
+                ec ? ec->name : ecunk, (u64)inst << 12,
+                nouveau_client_name(engctx));
+
+       object = engctx;
+       while (object) {
+               switch (nv_mclass(object)) {
+               case NVC0_CHANNEL_IND_CLASS:
+                       nvc0_fifo_recover(priv, engine, (void *)object);
+                       break;
+               }
+               object = object->parent;
        }
-       pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12,
-                       nouveau_client_name(engctx));
 
        nouveau_engctx_put(engctx);
 }
 
-static int
-nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
-{
-       struct nvc0_fifo_chan *chan = NULL;
-       struct nouveau_handle *bind;
-       unsigned long flags;
-       int ret = -EINVAL;
-
-       spin_lock_irqsave(&priv->base.lock, flags);
-       if (likely(chid >= priv->base.min && chid <= priv->base.max))
-               chan = (void *)priv->base.channel[chid];
-       if (unlikely(!chan))
-               goto out;
-
-       bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
-       if (likely(bind)) {
-               if (!mthd || !nv_call(bind->object, mthd, data))
-                       ret = 0;
-               nouveau_namedb_put(bind);
-       }
-
-out:
-       spin_unlock_irqrestore(&priv->base.lock, flags);
-       return ret;
-}
+static const struct nouveau_bitfield
+nvc0_fifo_pbdma_intr[] = {
+/*     { 0x00008000, "" }      seen with null ib push */
+       { 0x00200000, "ILLEGAL_MTHD" },
+       { 0x00800000, "EMPTY_SUBC" },
+       {}
+};
 
 static void
-nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit)
+nvc0_fifo_intr_pbdma(struct nvc0_fifo_priv *priv, int unit)
 {
        u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
        u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
@@ -501,11 +689,11 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit)
        }
 
        if (show) {
-               nv_error(priv, "SUBFIFO%d:", unit);
-               nouveau_bitfield_print(nvc0_fifo_subfifo_intr, show);
+               nv_error(priv, "PBDMA%d:", unit);
+               nouveau_bitfield_print(nvc0_fifo_pbdma_intr, show);
                pr_cont("\n");
                nv_error(priv,
-                        "SUBFIFO%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
+                        "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
                         unit, chid,
                         nouveau_client_name_for_fifo_chid(&priv->base, chid),
                         subc, mthd, data);
@@ -515,6 +703,56 @@ nvc0_fifo_isr_subfifo_intr(struct nvc0_fifo_priv *priv, int unit)
        nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
 }
 
+static void
+nvc0_fifo_intr_runlist(struct nvc0_fifo_priv *priv)
+{
+       u32 intr = nv_rd32(priv, 0x002a00);
+
+       if (intr & 0x10000000) {
+               wake_up(&priv->runlist.wait);
+               nv_wr32(priv, 0x002a00, 0x10000000);
+               intr &= ~0x10000000;
+       }
+
+       if (intr) {
+               nv_error(priv, "RUNLIST 0x%08x\n", intr);
+               nv_wr32(priv, 0x002a00, intr);
+       }
+}
+
+static void
+nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
+{
+       u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04));
+       u32 inte = nv_rd32(priv, 0x002628);
+       u32 unkn;
+
+       for (unkn = 0; unkn < 8; unkn++) {
+               u32 ints = (intr >> (unkn * 0x04)) & inte;
+               if (ints & 0x1) {
+                       nouveau_event_trigger(priv->base.uevent, 0);
+                       ints &= ~1;
+               }
+               if (ints) {
+                       nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints);
+                       nv_mask(priv, 0x002628, ints, 0);
+               }
+       }
+
+       nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
+}
+
+static void
+nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv)
+{
+       u32 mask = nv_rd32(priv, 0x0025a4);
+       while (mask) {
+               u32 unit = __ffs(mask);
+               nvc0_fifo_intr_engine_unit(priv, unit);
+               mask &= ~(1 << unit);
+       }
+}
+
 static void
 nvc0_fifo_intr(struct nouveau_subdev *subdev)
 {
@@ -530,8 +768,7 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
        }
 
        if (stat & 0x00000100) {
-               u32 intr = nv_rd32(priv, 0x00254c);
-               nv_warn(priv, "INTR 0x00000100: 0x%08x\n", intr);
+               nvc0_fifo_intr_sched(priv);
                nv_wr32(priv, 0x002100, 0x00000100);
                stat &= ~0x00000100;
        }
@@ -551,52 +788,41 @@ nvc0_fifo_intr(struct nouveau_subdev *subdev)
        }
 
        if (stat & 0x10000000) {
-               u32 units = nv_rd32(priv, 0x00259c);
-               u32 u = units;
-
-               while (u) {
-                       int i = ffs(u) - 1;
-                       nvc0_fifo_isr_vm_fault(priv, i);
-                       u &= ~(1 << i);
+               u32 mask = nv_rd32(priv, 0x00259c);
+               while (mask) {
+                       u32 unit = __ffs(mask);
+                       nvc0_fifo_intr_fault(priv, unit);
+                       nv_wr32(priv, 0x00259c, (1 << unit));
+                       mask &= ~(1 << unit);
                }
-
-               nv_wr32(priv, 0x00259c, units);
                stat &= ~0x10000000;
        }
 
        if (stat & 0x20000000) {
-               u32 units = nv_rd32(priv, 0x0025a0);
-               u32 u = units;
-
-               while (u) {
-                       int i = ffs(u) - 1;
-                       nvc0_fifo_isr_subfifo_intr(priv, i);
-                       u &= ~(1 << i);
+               u32 mask = nv_rd32(priv, 0x0025a0);
+               while (mask) {
+                       u32 unit = __ffs(mask);
+                       nvc0_fifo_intr_pbdma(priv, unit);
+                       nv_wr32(priv, 0x0025a0, (1 << unit));
+                       mask &= ~(1 << unit);
                }
-
-               nv_wr32(priv, 0x0025a0, units);
                stat &= ~0x20000000;
        }
 
        if (stat & 0x40000000) {
-               u32 intr0 = nv_rd32(priv, 0x0025a4);
-               u32 intr1 = nv_mask(priv, 0x002a00, 0x00000000, 0x00000);
-               nv_debug(priv, "INTR 0x40000000: 0x%08x 0x%08x\n",
-                              intr0, intr1);
+               nvc0_fifo_intr_runlist(priv);
                stat &= ~0x40000000;
        }
 
        if (stat & 0x80000000) {
-               u32 intr = nv_mask(priv, 0x0025a8, 0x00000000, 0x00000000);
-               nouveau_event_trigger(priv->base.uevent, 0);
-               nv_debug(priv, "INTR 0x80000000: 0x%08x\n", intr);
+               nvc0_fifo_intr_engine(priv);
                stat &= ~0x80000000;
        }
 
        if (stat) {
-               nv_fatal(priv, "unhandled status 0x%08x\n", stat);
+               nv_error(priv, "INTR 0x%08x\n", stat);
+               nv_mask(priv, 0x002140, stat, 0x00000000);
                nv_wr32(priv, 0x002100, stat);
-               nv_wr32(priv, 0x002140, 0);
        }
 }
 
@@ -627,16 +853,20 @@ nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       INIT_WORK(&priv->fault, nvc0_fifo_recover_work);
+
        ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
-                               &priv->playlist[0]);
+                               &priv->runlist.mem[0]);
        if (ret)
                return ret;
 
        ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
-                               &priv->playlist[1]);
+                               &priv->runlist.mem[1]);
        if (ret)
                return ret;
 
+       init_waitqueue_head(&priv->runlist.wait);
+
        ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0,
                                &priv->user.mem);
        if (ret)
@@ -665,8 +895,8 @@ nvc0_fifo_dtor(struct nouveau_object *object)
 
        nouveau_gpuobj_unmap(&priv->user.bar);
        nouveau_gpuobj_ref(NULL, &priv->user.mem);
-       nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
-       nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
+       nouveau_gpuobj_ref(NULL, &priv->runlist.mem[0]);
+       nouveau_gpuobj_ref(NULL, &priv->runlist.mem[1]);
 
        nouveau_fifo_destroy(&priv->base);
 }
@@ -685,9 +915,9 @@ nvc0_fifo_init(struct nouveau_object *object)
        nv_wr32(priv, 0x002204, 0xffffffff);
 
        priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
-       nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr);
+       nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
 
-       /* assign engines to subfifos */
+       /* assign engines to PBDMAs */
        if (priv->spoon_nr >= 3) {
                nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
                nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
@@ -697,7 +927,7 @@ nvc0_fifo_init(struct nouveau_object *object)
                nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
        }
 
-       /* PSUBFIFO[n] */
+       /* PBDMA[n] */
        for (i = 0; i < priv->spoon_nr; i++) {
                nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
                nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
@@ -707,10 +937,9 @@ nvc0_fifo_init(struct nouveau_object *object)
        nv_mask(priv, 0x002200, 0x00000001, 0x00000001);
        nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
 
-       nv_wr32(priv, 0x002a00, 0xffffffff); /* clears PFIFO.INTR bit 30 */
        nv_wr32(priv, 0x002100, 0xffffffff);
-       nv_wr32(priv, 0x002140, 0x3fffffff);
-       nv_wr32(priv, 0x002628, 0x00000001); /* makes mthd 0x20 work */
+       nv_wr32(priv, 0x002140, 0x7fffffff);
+       nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
        return 0;
 }
 
index 54c1b5b..a9a1a9c 100644 (file)
@@ -60,10 +60,15 @@ static const struct {
 struct nve0_fifo_engn {
        struct nouveau_gpuobj *runlist[2];
        int cur_runlist;
+       wait_queue_head_t wait;
 };
 
 struct nve0_fifo_priv {
        struct nouveau_fifo base;
+
+       struct work_struct fault;
+       u64 mask;
+
        struct nve0_fifo_engn engine[FIFO_ENGINE_NR];
        struct {
                struct nouveau_gpuobj *mem;
@@ -81,6 +86,11 @@ struct nve0_fifo_base {
 struct nve0_fifo_chan {
        struct nouveau_fifo_chan base;
        u32 engine;
+       enum {
+               STOPPED,
+               RUNNING,
+               KILLED
+       } state;
 };
 
 /*******************************************************************************
@@ -93,7 +103,6 @@ nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine)
        struct nouveau_bar *bar = nouveau_bar(priv);
        struct nve0_fifo_engn *engn = &priv->engine[engine];
        struct nouveau_gpuobj *cur;
-       u32 match = (engine << 16) | 0x00000001;
        int i, p;
 
        mutex_lock(&nv_subdev(priv)->mutex);
@@ -101,18 +110,21 @@ nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine)
        engn->cur_runlist = !engn->cur_runlist;
 
        for (i = 0, p = 0; i < priv->base.max; i++) {
-               u32 ctrl = nv_rd32(priv, 0x800004 + (i * 8)) & 0x001f0001;
-               if (ctrl != match)
-                       continue;
-               nv_wo32(cur, p + 0, i);
-               nv_wo32(cur, p + 4, 0x00000000);
-               p += 8;
+               struct nve0_fifo_chan *chan = (void *)priv->base.channel[i];
+               if (chan && chan->state == RUNNING && chan->engine == engine) {
+                       nv_wo32(cur, p + 0, i);
+                       nv_wo32(cur, p + 4, 0x00000000);
+                       p += 8;
+               }
        }
        bar->flush(bar);
 
        nv_wr32(priv, 0x002270, cur->addr >> 12);
        nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
-       if (!nv_wait(priv, 0x002284 + (engine * 8), 0x00100000, 0x00000000))
+
+       if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 +
+                              (engine * 0x08)) & 0x00100000),
+                               msecs_to_jiffies(2000)) == 0)
                nv_error(priv, "runlist %d update timeout\n", engine);
        mutex_unlock(&nv_subdev(priv)->mutex);
 }
@@ -129,9 +141,11 @@ nve0_fifo_context_attach(struct nouveau_object *parent,
 
        switch (nv_engidx(object->engine)) {
        case NVDEV_ENGINE_SW   :
+               return 0;
        case NVDEV_ENGINE_COPY0:
        case NVDEV_ENGINE_COPY1:
        case NVDEV_ENGINE_COPY2:
+               nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
                return 0;
        case NVDEV_ENGINE_GR   : addr = 0x0210; break;
        case NVDEV_ENGINE_BSP  : addr = 0x0270; break;
@@ -279,9 +293,13 @@ nve0_fifo_chan_init(struct nouveau_object *object)
 
        nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
        nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
-       nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
-       nve0_fifo_runlist_update(priv, chan->engine);
-       nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
+
+       if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
+               nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
+               nve0_fifo_runlist_update(priv, chan->engine);
+               nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
+       }
+
        return 0;
 }
 
@@ -292,10 +310,12 @@ nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
        struct nve0_fifo_chan *chan = (void *)object;
        u32 chid = chan->base.chid;
 
-       nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
-       nve0_fifo_runlist_update(priv, chan->engine);
-       nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
+       if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
+               nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
+               nve0_fifo_runlist_update(priv, chan->engine);
+       }
 
+       nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
        return nouveau_fifo_channel_fini(&chan->base, suspend);
 }
 
@@ -377,14 +397,211 @@ nve0_fifo_cclass = {
  * PFIFO engine
  ******************************************************************************/
 
-static const struct nouveau_enum nve0_fifo_sched_reason[] = {
+static inline int
+nve0_fifo_engidx(struct nve0_fifo_priv *priv, u32 engn)
+{
+       switch (engn) {
+       case NVDEV_ENGINE_GR   :
+       case NVDEV_ENGINE_COPY2: engn = 0; break;
+       case NVDEV_ENGINE_BSP  : engn = 1; break;
+       case NVDEV_ENGINE_PPP  : engn = 2; break;
+       case NVDEV_ENGINE_VP   : engn = 3; break;
+       case NVDEV_ENGINE_COPY0: engn = 4; break;
+       case NVDEV_ENGINE_COPY1: engn = 5; break;
+       case NVDEV_ENGINE_VENC : engn = 6; break;
+       default:
+               return -1;
+       }
+
+       return engn;
+}
+
+static inline struct nouveau_engine *
+nve0_fifo_engine(struct nve0_fifo_priv *priv, u32 engn)
+{
+       if (engn >= ARRAY_SIZE(fifo_engine))
+               return NULL;
+       return nouveau_engine(priv, fifo_engine[engn].subdev);
+}
+
+static void
+nve0_fifo_recover_work(struct work_struct *work)
+{
+       struct nve0_fifo_priv *priv = container_of(work, typeof(*priv), fault);
+       struct nouveau_object *engine;
+       unsigned long flags;
+       u32 engn, engm = 0;
+       u64 mask, todo;
+
+       spin_lock_irqsave(&priv->base.lock, flags);
+       mask = priv->mask;
+       priv->mask = 0ULL;
+       spin_unlock_irqrestore(&priv->base.lock, flags);
+
+       for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
+               engm |= 1 << nve0_fifo_engidx(priv, engn);
+       nv_mask(priv, 0x002630, engm, engm);
+
+       for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
+               if ((engine = (void *)nouveau_engine(priv, engn))) {
+                       nv_ofuncs(engine)->fini(engine, false);
+                       WARN_ON(nv_ofuncs(engine)->init(engine));
+               }
+               nve0_fifo_runlist_update(priv, nve0_fifo_engidx(priv, engn));
+       }
+
+       nv_wr32(priv, 0x00262c, engm);
+       nv_mask(priv, 0x002630, engm, 0x00000000);
+}
+
+static void
+nve0_fifo_recover(struct nve0_fifo_priv *priv, struct nouveau_engine *engine,
+                 struct nve0_fifo_chan *chan)
+{
+       struct nouveau_object *engobj = nv_object(engine);
+       u32 chid = chan->base.chid;
+       unsigned long flags;
+
+       nv_error(priv, "%s engine fault on channel %d, recovering...\n",
+                      nv_subdev(engine)->name, chid);
+
+       nv_mask(priv, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800);
+       chan->state = KILLED;
+
+       spin_lock_irqsave(&priv->base.lock, flags);
+       priv->mask |= 1ULL << nv_engidx(engobj);
+       spin_unlock_irqrestore(&priv->base.lock, flags);
+       schedule_work(&priv->fault);
+}
+
+static int
+nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
+{
+       struct nve0_fifo_chan *chan = NULL;
+       struct nouveau_handle *bind;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       spin_lock_irqsave(&priv->base.lock, flags);
+       if (likely(chid >= priv->base.min && chid <= priv->base.max))
+               chan = (void *)priv->base.channel[chid];
+       if (unlikely(!chan))
+               goto out;
+
+       bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
+       if (likely(bind)) {
+               if (!mthd || !nv_call(bind->object, mthd, data))
+                       ret = 0;
+               nouveau_namedb_put(bind);
+       }
+
+out:
+       spin_unlock_irqrestore(&priv->base.lock, flags);
+       return ret;
+}
+
+static const struct nouveau_enum
+nve0_fifo_bind_reason[] = {
+       { 0x01, "BIND_NOT_UNBOUND" },
+       { 0x02, "SNOOP_WITHOUT_BAR1" },
+       { 0x03, "UNBIND_WHILE_RUNNING" },
+       { 0x05, "INVALID_RUNLIST" },
+       { 0x06, "INVALID_CTX_TGT" },
+       { 0x0b, "UNBIND_WHILE_PARKED" },
+       {}
+};
+
+static void
+nve0_fifo_intr_bind(struct nve0_fifo_priv *priv)
+{
+       u32 intr = nv_rd32(priv, 0x00252c);
+       u32 code = intr & 0x000000ff;
+       const struct nouveau_enum *en;
+       char enunk[6] = "";
+
+       en = nouveau_enum_find(nve0_fifo_bind_reason, code);
+       if (!en)
+               snprintf(enunk, sizeof(enunk), "UNK%02x", code);
+
+       nv_error(priv, "BIND_ERROR [ %s ]\n", en ? en->name : enunk);
+}
+
+static const struct nouveau_enum
+nve0_fifo_sched_reason[] = {
        { 0x0a, "CTXSW_TIMEOUT" },
        {}
 };
 
-static const struct nouveau_enum nve0_fifo_fault_engine[] = {
+static void
+nve0_fifo_intr_sched_ctxsw(struct nve0_fifo_priv *priv)
+{
+       struct nouveau_engine *engine;
+       struct nve0_fifo_chan *chan;
+       u32 engn;
+
+       for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) {
+               u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
+               u32 busy = (stat & 0x80000000);
+               u32 next = (stat & 0x07ff0000) >> 16;
+               u32 chsw = (stat & 0x00008000);
+               u32 save = (stat & 0x00004000);
+               u32 load = (stat & 0x00002000);
+               u32 prev = (stat & 0x000007ff);
+               u32 chid = load ? next : prev;
+               (void)save;
+
+               if (busy && chsw) {
+                       if (!(chan = (void *)priv->base.channel[chid]))
+                               continue;
+                       if (!(engine = nve0_fifo_engine(priv, engn)))
+                               continue;
+                       nve0_fifo_recover(priv, engine, chan);
+               }
+       }
+}
+
+static void
+nve0_fifo_intr_sched(struct nve0_fifo_priv *priv)
+{
+       u32 intr = nv_rd32(priv, 0x00254c);
+       u32 code = intr & 0x000000ff;
+       const struct nouveau_enum *en;
+       char enunk[6] = "";
+
+       en = nouveau_enum_find(nve0_fifo_sched_reason, code);
+       if (!en)
+               snprintf(enunk, sizeof(enunk), "UNK%02x", code);
+
+       nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
+
+       switch (code) {
+       case 0x0a:
+               nve0_fifo_intr_sched_ctxsw(priv);
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+nve0_fifo_intr_chsw(struct nve0_fifo_priv *priv)
+{
+       u32 stat = nv_rd32(priv, 0x00256c);
+       nv_error(priv, "CHSW_ERROR 0x%08x\n", stat);
+       nv_wr32(priv, 0x00256c, stat);
+}
+
+static void
+nve0_fifo_intr_dropped_fault(struct nve0_fifo_priv *priv)
+{
+       u32 stat = nv_rd32(priv, 0x00259c);
+       nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat);
+}
+
+static const struct nouveau_enum
+nve0_fifo_fault_engine[] = {
        { 0x00, "GR", NULL, NVDEV_ENGINE_GR },
-       { 0x03, "IFB" },
+       { 0x03, "IFB", NULL, NVDEV_ENGINE_IFB },
        { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
        { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
        { 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO },
@@ -402,7 +619,8 @@ static const struct nouveau_enum nve0_fifo_fault_engine[] = {
        {}
 };
 
-static const struct nouveau_enum nve0_fifo_fault_reason[] = {
+static const struct nouveau_enum
+nve0_fifo_fault_reason[] = {
        { 0x00, "PDE" },
        { 0x01, "PDE_SIZE" },
        { 0x02, "PTE" },
@@ -422,7 +640,8 @@ static const struct nouveau_enum nve0_fifo_fault_reason[] = {
        {}
 };
 
-static const struct nouveau_enum nve0_fifo_fault_hubclient[] = {
+static const struct nouveau_enum
+nve0_fifo_fault_hubclient[] = {
        { 0x00, "VIP" },
        { 0x01, "CE0" },
        { 0x02, "CE1" },
@@ -458,7 +677,8 @@ static const struct nouveau_enum nve0_fifo_fault_hubclient[] = {
        {}
 };
 
-static const struct nouveau_enum nve0_fifo_fault_gpcclient[] = {
+static const struct nouveau_enum
+nve0_fifo_fault_gpcclient[] = {
        { 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" },
        { 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" },
        { 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" },
@@ -483,6 +703,82 @@ static const struct nouveau_enum nve0_fifo_fault_gpcclient[] = {
        {}
 };
 
+static void
+nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit)
+{
+       u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
+       u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
+       u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
+       u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
+       u32 gpc    = (stat & 0x1f000000) >> 24;
+       u32 client = (stat & 0x00001f00) >> 8;
+       u32 write  = (stat & 0x00000080);
+       u32 hub    = (stat & 0x00000040);
+       u32 reason = (stat & 0x0000000f);
+       struct nouveau_object *engctx = NULL, *object;
+       struct nouveau_engine *engine = NULL;
+       const struct nouveau_enum *er, *eu, *ec;
+       char erunk[6] = "";
+       char euunk[6] = "";
+       char ecunk[6] = "";
+       char gpcid[3] = "";
+
+       er = nouveau_enum_find(nve0_fifo_fault_reason, reason);
+       if (!er)
+               snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
+
+       eu = nouveau_enum_find(nve0_fifo_fault_engine, unit);
+       if (eu) {
+               switch (eu->data2) {
+               case NVDEV_SUBDEV_BAR:
+                       nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
+                       break;
+               case NVDEV_SUBDEV_INSTMEM:
+                       nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
+                       break;
+               case NVDEV_ENGINE_IFB:
+                       nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
+                       break;
+               default:
+                       engine = nouveau_engine(priv, eu->data2);
+                       if (engine)
+                               engctx = nouveau_engctx_get(engine, inst);
+                       break;
+               }
+       } else {
+               snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
+       }
+
+       if (hub) {
+               ec = nouveau_enum_find(nve0_fifo_fault_hubclient, client);
+       } else {
+               ec = nouveau_enum_find(nve0_fifo_fault_gpcclient, client);
+               snprintf(gpcid, sizeof(gpcid), "%d", gpc);
+       }
+
+       if (!ec)
+               snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
+
+       nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
+                      "channel 0x%010llx [%s]\n", write ? "write" : "read",
+                (u64)vahi << 32 | valo, er ? er->name : erunk,
+                eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
+                ec ? ec->name : ecunk, (u64)inst << 12,
+                nouveau_client_name(engctx));
+
+       object = engctx;
+       while (object) {
+               switch (nv_mclass(object)) {
+               case NVE0_CHANNEL_IND_CLASS:
+                       nve0_fifo_recover(priv, engine, (void *)object);
+                       break;
+               }
+               object = object->parent;
+       }
+
+       nouveau_engctx_put(engctx);
+}
+
 static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = {
        { 0x00000001, "MEMREQ" },
        { 0x00000002, "MEMACK_TIMEOUT" },
@@ -517,104 +813,6 @@ static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = {
        {}
 };
 
-static void
-nve0_fifo_intr_sched(struct nve0_fifo_priv *priv)
-{
-       u32 intr = nv_rd32(priv, 0x00254c);
-       u32 code = intr & 0x000000ff;
-       nv_error(priv, "SCHED_ERROR [");
-       nouveau_enum_print(nve0_fifo_sched_reason, code);
-       pr_cont("]\n");
-}
-
-static void
-nve0_fifo_intr_chsw(struct nve0_fifo_priv *priv)
-{
-       u32 stat = nv_rd32(priv, 0x00256c);
-       nv_error(priv, "CHSW_ERROR 0x%08x\n", stat);
-       nv_wr32(priv, 0x00256c, stat);
-}
-
-static void
-nve0_fifo_intr_dropped_fault(struct nve0_fifo_priv *priv)
-{
-       u32 stat = nv_rd32(priv, 0x00259c);
-       nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat);
-}
-
-static void
-nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit)
-{
-       u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10));
-       u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10));
-       u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10));
-       u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10));
-       u32 client = (stat & 0x00001f00) >> 8;
-       struct nouveau_engine *engine = NULL;
-       struct nouveau_object *engctx = NULL;
-       const struct nouveau_enum *en;
-       const char *name = "unknown";
-
-       nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ?
-                      "write" : "read", (u64)vahi << 32 | valo);
-       nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f);
-       pr_cont("] from ");
-       en = nouveau_enum_print(nve0_fifo_fault_engine, unit);
-       if (stat & 0x00000040) {
-               pr_cont("/");
-               nouveau_enum_print(nve0_fifo_fault_hubclient, client);
-       } else {
-               pr_cont("/GPC%d/", (stat & 0x1f000000) >> 24);
-               nouveau_enum_print(nve0_fifo_fault_gpcclient, client);
-       }
-
-       if (en && en->data2) {
-               if (en->data2 == NVDEV_SUBDEV_BAR) {
-                       nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
-                       name = "BAR1";
-               } else
-               if (en->data2 == NVDEV_SUBDEV_INSTMEM) {
-                       nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
-                       name = "BAR3";
-               } else {
-                       engine = nouveau_engine(priv, en->data2);
-                       if (engine) {
-                               engctx = nouveau_engctx_get(engine, inst);
-                               name   = nouveau_client_name(engctx);
-                       }
-               }
-       }
-       pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12, name);
-
-       nouveau_engctx_put(engctx);
-}
-
-static int
-nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
-{
-       struct nve0_fifo_chan *chan = NULL;
-       struct nouveau_handle *bind;
-       unsigned long flags;
-       int ret = -EINVAL;
-
-       spin_lock_irqsave(&priv->base.lock, flags);
-       if (likely(chid >= priv->base.min && chid <= priv->base.max))
-               chan = (void *)priv->base.channel[chid];
-       if (unlikely(!chan))
-               goto out;
-
-       bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
-       if (likely(bind)) {
-               if (!mthd || !nv_call(bind->object, mthd, data))
-                       ret = 0;
-               nouveau_namedb_put(bind);
-       }
-
-out:
-       spin_unlock_irqrestore(&priv->base.lock, flags);
-       return ret;
-}
-
 static void
 nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit)
 {
@@ -646,6 +844,24 @@ nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit)
        nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
 }
 
+static void
+nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
+{
+       u32 mask = nv_rd32(priv, 0x002a00);
+       while (mask) {
+               u32 engn = __ffs(mask);
+               wake_up(&priv->engine[engn].wait);
+               nv_wr32(priv, 0x002a00, 1 << engn);
+               mask &= ~(1 << engn);
+       }
+}
+
+static void
+nve0_fifo_intr_engine(struct nve0_fifo_priv *priv)
+{
+       nouveau_event_trigger(priv->base.uevent, 0);
+}
+
 static void
 nve0_fifo_intr(struct nouveau_subdev *subdev)
 {
@@ -654,8 +870,7 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
        u32 stat = nv_rd32(priv, 0x002100) & mask;
 
        if (stat & 0x00000001) {
-               u32 stat = nv_rd32(priv, 0x00252c);
-               nv_error(priv, "BIND_ERROR 0x%08x\n", stat);
+               nve0_fifo_intr_bind(priv);
                nv_wr32(priv, 0x002100, 0x00000001);
                stat &= ~0x00000001;
        }
@@ -697,55 +912,42 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
        }
 
        if (stat & 0x10000000) {
-               u32 units = nv_rd32(priv, 0x00259c);
-               u32 u = units;
-
-               while (u) {
-                       int i = ffs(u) - 1;
-                       nve0_fifo_intr_fault(priv, i);
-                       u &= ~(1 << i);
+               u32 mask = nv_rd32(priv, 0x00259c);
+               while (mask) {
+                       u32 unit = __ffs(mask);
+                       nve0_fifo_intr_fault(priv, unit);
+                       nv_wr32(priv, 0x00259c, (1 << unit));
+                       mask &= ~(1 << unit);
                }
-
-               nv_wr32(priv, 0x00259c, units);
                stat &= ~0x10000000;
        }
 
        if (stat & 0x20000000) {
                u32 mask = nv_rd32(priv, 0x0025a0);
-               u32 temp = mask;
-
-               while (temp) {
-                       u32 unit = ffs(temp) - 1;
+               while (mask) {
+                       u32 unit = __ffs(mask);
                        nve0_fifo_intr_pbdma(priv, unit);
-                       temp &= ~(1 << unit);
+                       nv_wr32(priv, 0x0025a0, (1 << unit));
+                       mask &= ~(1 << unit);
                }
-
-               nv_wr32(priv, 0x0025a0, mask);
                stat &= ~0x20000000;
        }
 
        if (stat & 0x40000000) {
-               u32 mask = nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
-
-               while (mask) {
-                       u32 engn = ffs(mask) - 1;
-                       /* runlist event, not currently used */
-                       mask &= ~(1 << engn);
-               }
-
+               nve0_fifo_intr_runlist(priv);
                stat &= ~0x40000000;
        }
 
        if (stat & 0x80000000) {
-               nouveau_event_trigger(priv->base.uevent, 0);
+               nve0_fifo_intr_engine(priv);
                nv_wr32(priv, 0x002100, 0x80000000);
                stat &= ~0x80000000;
        }
 
        if (stat) {
-               nv_fatal(priv, "unhandled status 0x%08x\n", stat);
+               nv_error(priv, "INTR 0x%08x\n", stat);
+               nv_mask(priv, 0x002140, stat, 0x00000000);
                nv_wr32(priv, 0x002100, stat);
-               nv_wr32(priv, 0x002140, 0);
        }
 }
 
@@ -802,9 +1004,8 @@ nve0_fifo_init(struct nouveau_object *object)
 
        nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
 
-       nv_wr32(priv, 0x002a00, 0xffffffff);
        nv_wr32(priv, 0x002100, 0xffffffff);
-       nv_wr32(priv, 0x002140, 0x3fffffff);
+       nv_wr32(priv, 0x002140, 0x7fffffff);
        return 0;
 }
 
@@ -840,6 +1041,8 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
+       INIT_WORK(&priv->fault, nve0_fifo_recover_work);
+
        for (i = 0; i < FIFO_ENGINE_NR; i++) {
                ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
                                         0, &priv->engine[i].runlist[0]);
@@ -850,10 +1053,12 @@ nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                                         0, &priv->engine[i].runlist[1]);
                if (ret)
                        return ret;
+
+               init_waitqueue_head(&priv->engine[i].wait);
        }
 
-       ret = nouveau_gpuobj_new(nv_object(priv), NULL, 4096 * 0x200, 0x1000,
-                                NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+       ret = nouveau_gpuobj_new(nv_object(priv), NULL, impl->channels * 0x200,
+                               0x1000, NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
        if (ret)
                return ret;
 
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c
new file mode 100644 (file)
index 0000000..1dc37b1
--- /dev/null
@@ -0,0 +1,989 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "ctxnvc0.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct nvc0_graph_init
+gm107_grctx_init_icmd_0[] = {
+       { 0x001000,   1, 0x01, 0x00000004 },
+       { 0x000039,   3, 0x01, 0x00000000 },
+       { 0x0000a9,   1, 0x01, 0x0000ffff },
+       { 0x000038,   1, 0x01, 0x0fac6881 },
+       { 0x00003d,   1, 0x01, 0x00000001 },
+       { 0x0000e8,   8, 0x01, 0x00000400 },
+       { 0x000078,   8, 0x01, 0x00000300 },
+       { 0x000050,   1, 0x01, 0x00000011 },
+       { 0x000058,   8, 0x01, 0x00000008 },
+       { 0x000208,   8, 0x01, 0x00000001 },
+       { 0x000081,   1, 0x01, 0x00000001 },
+       { 0x000085,   1, 0x01, 0x00000004 },
+       { 0x000088,   1, 0x01, 0x00000400 },
+       { 0x000090,   1, 0x01, 0x00000300 },
+       { 0x000098,   1, 0x01, 0x00001001 },
+       { 0x0000e3,   1, 0x01, 0x00000001 },
+       { 0x0000da,   1, 0x01, 0x00000001 },
+       { 0x0000f8,   1, 0x01, 0x00000003 },
+       { 0x0000fa,   1, 0x01, 0x00000001 },
+       { 0x0000b1,   2, 0x01, 0x00000001 },
+       { 0x00009f,   4, 0x01, 0x0000ffff },
+       { 0x0000a8,   1, 0x01, 0x0000ffff },
+       { 0x0000ad,   1, 0x01, 0x0000013e },
+       { 0x0000e1,   1, 0x01, 0x00000010 },
+       { 0x000290,  16, 0x01, 0x00000000 },
+       { 0x0003b0,  16, 0x01, 0x00000000 },
+       { 0x0002a0,  16, 0x01, 0x00000000 },
+       { 0x000420,  16, 0x01, 0x00000000 },
+       { 0x0002b0,  16, 0x01, 0x00000000 },
+       { 0x000430,  16, 0x01, 0x00000000 },
+       { 0x0002c0,  16, 0x01, 0x00000000 },
+       { 0x0004d0,  16, 0x01, 0x00000000 },
+       { 0x000720,  16, 0x01, 0x00000000 },
+       { 0x0008c0,  16, 0x01, 0x00000000 },
+       { 0x000890,  16, 0x01, 0x00000000 },
+       { 0x0008e0,  16, 0x01, 0x00000000 },
+       { 0x0008a0,  16, 0x01, 0x00000000 },
+       { 0x0008f0,  16, 0x01, 0x00000000 },
+       { 0x00094c,   1, 0x01, 0x000000ff },
+       { 0x00094d,   1, 0x01, 0xffffffff },
+       { 0x00094e,   1, 0x01, 0x00000002 },
+       { 0x0002f2,   2, 0x01, 0x00000001 },
+       { 0x0002f5,   1, 0x01, 0x00000001 },
+       { 0x0002f7,   1, 0x01, 0x00000001 },
+       { 0x000303,   1, 0x01, 0x00000001 },
+       { 0x0002e6,   1, 0x01, 0x00000001 },
+       { 0x000466,   1, 0x01, 0x00000052 },
+       { 0x000301,   1, 0x01, 0x3f800000 },
+       { 0x000304,   1, 0x01, 0x30201000 },
+       { 0x000305,   1, 0x01, 0x70605040 },
+       { 0x000306,   1, 0x01, 0xb8a89888 },
+       { 0x000307,   1, 0x01, 0xf8e8d8c8 },
+       { 0x00030a,   1, 0x01, 0x00ffff00 },
+       { 0x0000de,   1, 0x01, 0x00000001 },
+       { 0x00030b,   1, 0x01, 0x0000001a },
+       { 0x00030c,   1, 0x01, 0x00000001 },
+       { 0x000318,   1, 0x01, 0x00000001 },
+       { 0x000340,   1, 0x01, 0x00000000 },
+       { 0x00037d,   1, 0x01, 0x00000006 },
+       { 0x0003a0,   1, 0x01, 0x00000002 },
+       { 0x0003aa,   1, 0x01, 0x00000001 },
+       { 0x0003a9,   1, 0x01, 0x00000001 },
+       { 0x000380,   1, 0x01, 0x00000001 },
+       { 0x000383,   1, 0x01, 0x00000011 },
+       { 0x000360,   1, 0x01, 0x00000040 },
+       { 0x000366,   2, 0x01, 0x00000000 },
+       { 0x000368,   1, 0x01, 0x00000fff },
+       { 0x000370,   2, 0x01, 0x00000000 },
+       { 0x000372,   1, 0x01, 0x000fffff },
+       { 0x00037a,   1, 0x01, 0x00000012 },
+       { 0x000619,   1, 0x01, 0x00000003 },
+       { 0x000811,   1, 0x01, 0x00000003 },
+       { 0x000812,   1, 0x01, 0x00000004 },
+       { 0x000813,   1, 0x01, 0x00000006 },
+       { 0x000814,   1, 0x01, 0x00000008 },
+       { 0x000815,   1, 0x01, 0x0000000b },
+       { 0x000800,   6, 0x01, 0x00000001 },
+       { 0x000632,   1, 0x01, 0x00000001 },
+       { 0x000633,   1, 0x01, 0x00000002 },
+       { 0x000634,   1, 0x01, 0x00000003 },
+       { 0x000635,   1, 0x01, 0x00000004 },
+       { 0x000654,   1, 0x01, 0x3f800000 },
+       { 0x000657,   1, 0x01, 0x3f800000 },
+       { 0x000655,   2, 0x01, 0x3f800000 },
+       { 0x0006cd,   1, 0x01, 0x3f800000 },
+       { 0x0007f5,   1, 0x01, 0x3f800000 },
+       { 0x0007dc,   1, 0x01, 0x39291909 },
+       { 0x0007dd,   1, 0x01, 0x79695949 },
+       { 0x0007de,   1, 0x01, 0xb9a99989 },
+       { 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+       { 0x0007e8,   1, 0x01, 0x00003210 },
+       { 0x0007e9,   1, 0x01, 0x00007654 },
+       { 0x0007ea,   1, 0x01, 0x00000098 },
+       { 0x0007ec,   1, 0x01, 0x39291909 },
+       { 0x0007ed,   1, 0x01, 0x79695949 },
+       { 0x0007ee,   1, 0x01, 0xb9a99989 },
+       { 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+       { 0x0007f0,   1, 0x01, 0x00003210 },
+       { 0x0007f1,   1, 0x01, 0x00007654 },
+       { 0x0007f2,   1, 0x01, 0x00000098 },
+       { 0x0005a5,   1, 0x01, 0x00000001 },
+       { 0x0005d0,   1, 0x01, 0x20181008 },
+       { 0x0005d1,   1, 0x01, 0x40383028 },
+       { 0x0005d2,   1, 0x01, 0x60585048 },
+       { 0x0005d3,   1, 0x01, 0x80787068 },
+       { 0x000980, 128, 0x01, 0x00000000 },
+       { 0x000468,   1, 0x01, 0x00000004 },
+       { 0x00046c,   1, 0x01, 0x00000001 },
+       { 0x000470,  96, 0x01, 0x00000000 },
+       { 0x000510,  16, 0x01, 0x3f800000 },
+       { 0x000520,   1, 0x01, 0x000002b6 },
+       { 0x000529,   1, 0x01, 0x00000001 },
+       { 0x000530,  16, 0x01, 0xffff0000 },
+       { 0x000550,  32, 0x01, 0xffff0000 },
+       { 0x000585,   1, 0x01, 0x0000003f },
+       { 0x000576,   1, 0x01, 0x00000003 },
+       { 0x00057b,   1, 0x01, 0x00000059 },
+       { 0x000586,   1, 0x01, 0x00000040 },
+       { 0x000582,   2, 0x01, 0x00000080 },
+       { 0x000595,   1, 0x01, 0x00400040 },
+       { 0x000596,   1, 0x01, 0x00000492 },
+       { 0x000597,   1, 0x01, 0x08080203 },
+       { 0x0005ad,   1, 0x01, 0x00000008 },
+       { 0x000598,   1, 0x01, 0x00020001 },
+       { 0x0005c2,   1, 0x01, 0x00000001 },
+       { 0x000638,   2, 0x01, 0x00000001 },
+       { 0x00063a,   1, 0x01, 0x00000002 },
+       { 0x00063b,   2, 0x01, 0x00000001 },
+       { 0x00063d,   1, 0x01, 0x00000002 },
+       { 0x00063e,   1, 0x01, 0x00000001 },
+       { 0x0008b8,   8, 0x01, 0x00000001 },
+       { 0x000900,   8, 0x01, 0x00000001 },
+       { 0x000908,   8, 0x01, 0x00000002 },
+       { 0x000910,  16, 0x01, 0x00000001 },
+       { 0x000920,   8, 0x01, 0x00000002 },
+       { 0x000928,   8, 0x01, 0x00000001 },
+       { 0x000662,   1, 0x01, 0x00000001 },
+       { 0x000648,   9, 0x01, 0x00000001 },
+       { 0x000658,   1, 0x01, 0x0000000f },
+       { 0x0007ff,   1, 0x01, 0x0000000a },
+       { 0x00066a,   1, 0x01, 0x40000000 },
+       { 0x00066b,   1, 0x01, 0x10000000 },
+       { 0x00066c,   2, 0x01, 0xffff0000 },
+       { 0x0007af,   2, 0x01, 0x00000008 },
+       { 0x0007f6,   1, 0x01, 0x00000001 },
+       { 0x0006b2,   1, 0x01, 0x00000055 },
+       { 0x0007ad,   1, 0x01, 0x00000003 },
+       { 0x000971,   1, 0x01, 0x00000008 },
+       { 0x000972,   1, 0x01, 0x00000040 },
+       { 0x000973,   1, 0x01, 0x0000012c },
+       { 0x00097c,   1, 0x01, 0x00000040 },
+       { 0x000975,   1, 0x01, 0x00000020 },
+       { 0x000976,   1, 0x01, 0x00000001 },
+       { 0x000977,   1, 0x01, 0x00000020 },
+       { 0x000978,   1, 0x01, 0x00000001 },
+       { 0x000957,   1, 0x01, 0x00000003 },
+       { 0x00095e,   1, 0x01, 0x20164010 },
+       { 0x00095f,   1, 0x01, 0x00000020 },
+       { 0x000a0d,   1, 0x01, 0x00000006 },
+       { 0x00097d,   1, 0x01, 0x0000000c },
+       { 0x000683,   1, 0x01, 0x00000006 },
+       { 0x000687,   1, 0x01, 0x003fffff },
+       { 0x0006a0,   1, 0x01, 0x00000005 },
+       { 0x000840,   1, 0x01, 0x00400008 },
+       { 0x000841,   1, 0x01, 0x08000080 },
+       { 0x000842,   1, 0x01, 0x00400008 },
+       { 0x000843,   1, 0x01, 0x08000080 },
+       { 0x000818,   8, 0x01, 0x00000000 },
+       { 0x000848,  16, 0x01, 0x00000000 },
+       { 0x000738,   1, 0x01, 0x00000000 },
+       { 0x0006aa,   1, 0x01, 0x00000001 },
+       { 0x0006ab,   1, 0x01, 0x00000002 },
+       { 0x0006ac,   1, 0x01, 0x00000080 },
+       { 0x0006ad,   2, 0x01, 0x00000100 },
+       { 0x0006b1,   1, 0x01, 0x00000011 },
+       { 0x0006bb,   1, 0x01, 0x000000cf },
+       { 0x0006ce,   1, 0x01, 0x2a712488 },
+       { 0x000739,   1, 0x01, 0x4085c000 },
+       { 0x00073a,   1, 0x01, 0x00000080 },
+       { 0x000786,   1, 0x01, 0x80000100 },
+       { 0x00073c,   1, 0x01, 0x00010100 },
+       { 0x00073d,   1, 0x01, 0x02800000 },
+       { 0x000787,   1, 0x01, 0x000000cf },
+       { 0x00078c,   1, 0x01, 0x00000008 },
+       { 0x000792,   1, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
+       { 0x000797,   1, 0x01, 0x000000cf },
+       { 0x000836,   1, 0x01, 0x00000001 },
+       { 0x00079a,   1, 0x01, 0x00000002 },
+       { 0x000833,   1, 0x01, 0x04444480 },
+       { 0x0007a1,   1, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
+       { 0x000831,   1, 0x01, 0x00000004 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x000a04,   1, 0x01, 0x000000ff },
+       { 0x000a0b,   1, 0x01, 0x00000040 },
+       { 0x00097f,   1, 0x01, 0x00000100 },
+       { 0x000a02,   1, 0x01, 0x00000001 },
+       { 0x000809,   1, 0x01, 0x00000007 },
+       { 0x00c221,   1, 0x01, 0x00000040 },
+       { 0x00c1b0,   8, 0x01, 0x0000000f },
+       { 0x00c1b8,   1, 0x01, 0x0fac6881 },
+       { 0x00c1b9,   1, 0x01, 0x00fac688 },
+       { 0x00c401,   1, 0x01, 0x00000001 },
+       { 0x00c402,   1, 0x01, 0x00010001 },
+       { 0x00c403,   2, 0x01, 0x00000001 },
+       { 0x00c40e,   1, 0x01, 0x00000020 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000002 },
+       { 0x0006aa,   1, 0x01, 0x00000001 },
+       { 0x0006ad,   2, 0x01, 0x00000100 },
+       { 0x0006b1,   1, 0x01, 0x00000011 },
+       { 0x00078c,   1, 0x01, 0x00000008 },
+       { 0x000792,   1, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
+       { 0x000797,   1, 0x01, 0x000000cf },
+       { 0x00079a,   1, 0x01, 0x00000002 },
+       { 0x0007a1,   1, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
+       { 0x000831,   1, 0x01, 0x00000004 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000008 },
+       { 0x000039,   3, 0x01, 0x00000000 },
+       { 0x000380,   1, 0x01, 0x00000001 },
+       { 0x000366,   2, 0x01, 0x00000000 },
+       { 0x000368,   1, 0x01, 0x00000fff },
+       { 0x000370,   2, 0x01, 0x00000000 },
+       { 0x000372,   1, 0x01, 0x000fffff },
+       { 0x000813,   1, 0x01, 0x00000006 },
+       { 0x000814,   1, 0x01, 0x00000008 },
+       { 0x000818,   8, 0x01, 0x00000000 },
+       { 0x000848,  16, 0x01, 0x00000000 },
+       { 0x000738,   1, 0x01, 0x00000000 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x000a04,   1, 0x01, 0x000000ff },
+       { 0x000a0b,   1, 0x01, 0x00000040 },
+       { 0x00097f,   1, 0x01, 0x00000100 },
+       { 0x000a02,   1, 0x01, 0x00000001 },
+       { 0x000809,   1, 0x01, 0x00000007 },
+       { 0x00c221,   1, 0x01, 0x00000040 },
+       { 0x00c401,   1, 0x01, 0x00000001 },
+       { 0x00c402,   1, 0x01, 0x00010001 },
+       { 0x00c403,   2, 0x01, 0x00000001 },
+       { 0x00c40e,   1, 0x01, 0x00000020 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000001 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+gm107_grctx_pack_icmd[] = {
+       { gm107_grctx_init_icmd_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_b097_0[] = {
+       { 0x000800,   8, 0x40, 0x00000000 },
+       { 0x000804,   8, 0x40, 0x00000000 },
+       { 0x000808,   8, 0x40, 0x00000400 },
+       { 0x00080c,   8, 0x40, 0x00000300 },
+       { 0x000810,   1, 0x04, 0x000000cf },
+       { 0x000850,   7, 0x40, 0x00000000 },
+       { 0x000814,   8, 0x40, 0x00000040 },
+       { 0x000818,   8, 0x40, 0x00000001 },
+       { 0x00081c,   8, 0x40, 0x00000000 },
+       { 0x000820,   8, 0x40, 0x00000000 },
+       { 0x001c00,  16, 0x10, 0x00000000 },
+       { 0x001c04,  16, 0x10, 0x00000000 },
+       { 0x001c08,  16, 0x10, 0x00000000 },
+       { 0x001c0c,  16, 0x10, 0x00000000 },
+       { 0x001d00,  16, 0x10, 0x00000000 },
+       { 0x001d04,  16, 0x10, 0x00000000 },
+       { 0x001d08,  16, 0x10, 0x00000000 },
+       { 0x001d0c,  16, 0x10, 0x00000000 },
+       { 0x001f00,  16, 0x08, 0x00000000 },
+       { 0x001f04,  16, 0x08, 0x00000000 },
+       { 0x001f80,  16, 0x08, 0x00000000 },
+       { 0x001f84,  16, 0x08, 0x00000000 },
+       { 0x002000,   1, 0x04, 0x00000000 },
+       { 0x002040,   1, 0x04, 0x00000011 },
+       { 0x002080,   1, 0x04, 0x00000020 },
+       { 0x0020c0,   1, 0x04, 0x00000030 },
+       { 0x002100,   1, 0x04, 0x00000040 },
+       { 0x002140,   1, 0x04, 0x00000051 },
+       { 0x00200c,   6, 0x40, 0x00000001 },
+       { 0x002010,   1, 0x04, 0x00000000 },
+       { 0x002050,   1, 0x04, 0x00000000 },
+       { 0x002090,   1, 0x04, 0x00000001 },
+       { 0x0020d0,   1, 0x04, 0x00000002 },
+       { 0x002110,   1, 0x04, 0x00000003 },
+       { 0x002150,   1, 0x04, 0x00000004 },
+       { 0x000380,   4, 0x20, 0x00000000 },
+       { 0x000384,   4, 0x20, 0x00000000 },
+       { 0x000388,   4, 0x20, 0x00000000 },
+       { 0x00038c,   4, 0x20, 0x00000000 },
+       { 0x000700,   4, 0x10, 0x00000000 },
+       { 0x000704,   4, 0x10, 0x00000000 },
+       { 0x000708,   4, 0x10, 0x00000000 },
+       { 0x002800, 128, 0x04, 0x00000000 },
+       { 0x000a00,  16, 0x20, 0x00000000 },
+       { 0x000a04,  16, 0x20, 0x00000000 },
+       { 0x000a08,  16, 0x20, 0x00000000 },
+       { 0x000a0c,  16, 0x20, 0x00000000 },
+       { 0x000a10,  16, 0x20, 0x00000000 },
+       { 0x000a14,  16, 0x20, 0x00000000 },
+       { 0x000c00,  16, 0x10, 0x00000000 },
+       { 0x000c04,  16, 0x10, 0x00000000 },
+       { 0x000c08,  16, 0x10, 0x00000000 },
+       { 0x000c0c,  16, 0x10, 0x3f800000 },
+       { 0x000d00,   8, 0x08, 0xffff0000 },
+       { 0x000d04,   8, 0x08, 0xffff0000 },
+       { 0x000e00,  16, 0x10, 0x00000000 },
+       { 0x000e04,  16, 0x10, 0xffff0000 },
+       { 0x000e08,  16, 0x10, 0xffff0000 },
+       { 0x000d40,   4, 0x08, 0x00000000 },
+       { 0x000d44,   4, 0x08, 0x00000000 },
+       { 0x001e00,   8, 0x20, 0x00000001 },
+       { 0x001e04,   8, 0x20, 0x00000001 },
+       { 0x001e08,   8, 0x20, 0x00000002 },
+       { 0x001e0c,   8, 0x20, 0x00000001 },
+       { 0x001e10,   8, 0x20, 0x00000001 },
+       { 0x001e14,   8, 0x20, 0x00000002 },
+       { 0x001e18,   8, 0x20, 0x00000001 },
+       { 0x001480,   8, 0x10, 0x00000000 },
+       { 0x001484,   8, 0x10, 0x00000000 },
+       { 0x001488,   8, 0x10, 0x00000000 },
+       { 0x003400, 128, 0x04, 0x00000000 },
+       { 0x00030c,   1, 0x04, 0x00000001 },
+       { 0x001944,   1, 0x04, 0x00000000 },
+       { 0x001514,   1, 0x04, 0x00000000 },
+       { 0x000d68,   1, 0x04, 0x0000ffff },
+       { 0x00121c,   1, 0x04, 0x0fac6881 },
+       { 0x000fac,   1, 0x04, 0x00000001 },
+       { 0x001538,   1, 0x04, 0x00000001 },
+       { 0x000fe0,   2, 0x04, 0x00000000 },
+       { 0x000fe8,   1, 0x04, 0x00000014 },
+       { 0x000fec,   1, 0x04, 0x00000040 },
+       { 0x000ff0,   1, 0x04, 0x00000000 },
+       { 0x00179c,   1, 0x04, 0x00000000 },
+       { 0x001228,   1, 0x04, 0x00000400 },
+       { 0x00122c,   1, 0x04, 0x00000300 },
+       { 0x001230,   1, 0x04, 0x00010001 },
+       { 0x0007f8,   1, 0x04, 0x00000000 },
+       { 0x0015b4,   1, 0x04, 0x00000001 },
+       { 0x0015cc,   1, 0x04, 0x00000000 },
+       { 0x001534,   1, 0x04, 0x00000000 },
+       { 0x000754,   1, 0x04, 0x00000001 },
+       { 0x000fb0,   1, 0x04, 0x00000000 },
+       { 0x0015d0,   1, 0x04, 0x00000000 },
+       { 0x00153c,   1, 0x04, 0x00000000 },
+       { 0x0016b4,   1, 0x04, 0x00000003 },
+       { 0x000fbc,   4, 0x04, 0x0000ffff },
+       { 0x000df8,   2, 0x04, 0x00000000 },
+       { 0x001948,   1, 0x04, 0x00000000 },
+       { 0x001970,   1, 0x04, 0x00000001 },
+       { 0x00161c,   1, 0x04, 0x000009f0 },
+       { 0x000dcc,   1, 0x04, 0x00000010 },
+       { 0x0015e4,   1, 0x04, 0x00000000 },
+       { 0x001160,  32, 0x04, 0x25e00040 },
+       { 0x001880,  32, 0x04, 0x00000000 },
+       { 0x000f84,   2, 0x04, 0x00000000 },
+       { 0x0017c8,   2, 0x04, 0x00000000 },
+       { 0x0017d0,   1, 0x04, 0x000000ff },
+       { 0x0017d4,   1, 0x04, 0xffffffff },
+       { 0x0017d8,   1, 0x04, 0x00000002 },
+       { 0x0017dc,   1, 0x04, 0x00000000 },
+       { 0x0015f4,   2, 0x04, 0x00000000 },
+       { 0x001434,   2, 0x04, 0x00000000 },
+       { 0x000d74,   1, 0x04, 0x00000000 },
+       { 0x0013a4,   1, 0x04, 0x00000000 },
+       { 0x001318,   1, 0x04, 0x00000001 },
+       { 0x001080,   2, 0x04, 0x00000000 },
+       { 0x001088,   2, 0x04, 0x00000001 },
+       { 0x001090,   1, 0x04, 0x00000000 },
+       { 0x001094,   1, 0x04, 0x00000001 },
+       { 0x001098,   1, 0x04, 0x00000000 },
+       { 0x00109c,   1, 0x04, 0x00000001 },
+       { 0x0010a0,   2, 0x04, 0x00000000 },
+       { 0x001644,   1, 0x04, 0x00000000 },
+       { 0x000748,   1, 0x04, 0x00000000 },
+       { 0x000de8,   1, 0x04, 0x00000000 },
+       { 0x001648,   1, 0x04, 0x00000000 },
+       { 0x0012a4,   1, 0x04, 0x00000000 },
+       { 0x001120,   4, 0x04, 0x00000000 },
+       { 0x001118,   1, 0x04, 0x00000000 },
+       { 0x00164c,   1, 0x04, 0x00000000 },
+       { 0x001658,   1, 0x04, 0x00000000 },
+       { 0x001910,   1, 0x04, 0x00000290 },
+       { 0x001518,   1, 0x04, 0x00000000 },
+       { 0x00165c,   1, 0x04, 0x00000001 },
+       { 0x001520,   1, 0x04, 0x00000000 },
+       { 0x001604,   1, 0x04, 0x00000000 },
+       { 0x001570,   1, 0x04, 0x00000000 },
+       { 0x0013b0,   2, 0x04, 0x3f800000 },
+       { 0x00020c,   1, 0x04, 0x00000000 },
+       { 0x001670,   1, 0x04, 0x30201000 },
+       { 0x001674,   1, 0x04, 0x70605040 },
+       { 0x001678,   1, 0x04, 0xb8a89888 },
+       { 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+       { 0x00166c,   1, 0x04, 0x00000000 },
+       { 0x001680,   1, 0x04, 0x00ffff00 },
+       { 0x0012d0,   1, 0x04, 0x00000003 },
+       { 0x0012d4,   1, 0x04, 0x00000002 },
+       { 0x001684,   2, 0x04, 0x00000000 },
+       { 0x000dac,   2, 0x04, 0x00001b02 },
+       { 0x000db4,   1, 0x04, 0x00000000 },
+       { 0x00168c,   1, 0x04, 0x00000000 },
+       { 0x0015bc,   1, 0x04, 0x00000000 },
+       { 0x00156c,   1, 0x04, 0x00000000 },
+       { 0x00187c,   1, 0x04, 0x00000000 },
+       { 0x001110,   1, 0x04, 0x00000001 },
+       { 0x000dc0,   3, 0x04, 0x00000000 },
+       { 0x000f40,   5, 0x04, 0x00000000 },
+       { 0x001234,   1, 0x04, 0x00000000 },
+       { 0x001690,   1, 0x04, 0x00000000 },
+       { 0x000790,   5, 0x04, 0x00000000 },
+       { 0x00077c,   1, 0x04, 0x00000000 },
+       { 0x001000,   1, 0x04, 0x00000010 },
+       { 0x0010fc,   1, 0x04, 0x00000000 },
+       { 0x001290,   1, 0x04, 0x00000000 },
+       { 0x000218,   1, 0x04, 0x00000010 },
+       { 0x0012d8,   1, 0x04, 0x00000000 },
+       { 0x0012dc,   1, 0x04, 0x00000010 },
+       { 0x000d94,   1, 0x04, 0x00000001 },
+       { 0x00155c,   2, 0x04, 0x00000000 },
+       { 0x001564,   1, 0x04, 0x00000fff },
+       { 0x001574,   2, 0x04, 0x00000000 },
+       { 0x00157c,   1, 0x04, 0x000fffff },
+       { 0x001354,   1, 0x04, 0x00000000 },
+       { 0x001610,   1, 0x04, 0x00000012 },
+       { 0x001608,   2, 0x04, 0x00000000 },
+       { 0x00260c,   1, 0x04, 0x00000000 },
+       { 0x0007ac,   1, 0x04, 0x00000000 },
+       { 0x00162c,   1, 0x04, 0x00000003 },
+       { 0x000210,   1, 0x04, 0x00000000 },
+       { 0x000320,   1, 0x04, 0x00000000 },
+       { 0x000324,   6, 0x04, 0x3f800000 },
+       { 0x000750,   1, 0x04, 0x00000000 },
+       { 0x000760,   1, 0x04, 0x39291909 },
+       { 0x000764,   1, 0x04, 0x79695949 },
+       { 0x000768,   1, 0x04, 0xb9a99989 },
+       { 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+       { 0x000770,   1, 0x04, 0x30201000 },
+       { 0x000774,   1, 0x04, 0x70605040 },
+       { 0x000778,   1, 0x04, 0x00009080 },
+       { 0x000780,   1, 0x04, 0x39291909 },
+       { 0x000784,   1, 0x04, 0x79695949 },
+       { 0x000788,   1, 0x04, 0xb9a99989 },
+       { 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+       { 0x0007d0,   1, 0x04, 0x30201000 },
+       { 0x0007d4,   1, 0x04, 0x70605040 },
+       { 0x0007d8,   1, 0x04, 0x00009080 },
+       { 0x00037c,   1, 0x04, 0x00000001 },
+       { 0x000740,   2, 0x04, 0x00000000 },
+       { 0x002600,   1, 0x04, 0x00000000 },
+       { 0x001918,   1, 0x04, 0x00000000 },
+       { 0x00191c,   1, 0x04, 0x00000900 },
+       { 0x001920,   1, 0x04, 0x00000405 },
+       { 0x001308,   1, 0x04, 0x00000001 },
+       { 0x001924,   1, 0x04, 0x00000000 },
+       { 0x0013ac,   1, 0x04, 0x00000000 },
+       { 0x00192c,   1, 0x04, 0x00000001 },
+       { 0x00193c,   1, 0x04, 0x00002c1c },
+       { 0x000d7c,   1, 0x04, 0x00000000 },
+       { 0x000f8c,   1, 0x04, 0x00000000 },
+       { 0x0002c0,   1, 0x04, 0x00000001 },
+       { 0x001510,   1, 0x04, 0x00000000 },
+       { 0x001940,   1, 0x04, 0x00000000 },
+       { 0x000ff4,   2, 0x04, 0x00000000 },
+       { 0x00194c,   2, 0x04, 0x00000000 },
+       { 0x001968,   1, 0x04, 0x00000000 },
+       { 0x001590,   1, 0x04, 0x0000003f },
+       { 0x0007e8,   4, 0x04, 0x00000000 },
+       { 0x00196c,   1, 0x04, 0x00000011 },
+       { 0x0002e4,   1, 0x04, 0x0000b001 },
+       { 0x00036c,   2, 0x04, 0x00000000 },
+       { 0x00197c,   1, 0x04, 0x00000000 },
+       { 0x000fcc,   2, 0x04, 0x00000000 },
+       { 0x0002d8,   1, 0x04, 0x00000040 },
+       { 0x001980,   1, 0x04, 0x00000080 },
+       { 0x001504,   1, 0x04, 0x00000080 },
+       { 0x001984,   1, 0x04, 0x00000000 },
+       { 0x000f60,   1, 0x04, 0x00000000 },
+       { 0x000f64,   1, 0x04, 0x00400040 },
+       { 0x000f68,   1, 0x04, 0x00002212 },
+       { 0x000f6c,   1, 0x04, 0x08080203 },
+       { 0x001108,   1, 0x04, 0x00000008 },
+       { 0x000f70,   1, 0x04, 0x00080001 },
+       { 0x000ffc,   1, 0x04, 0x00000000 },
+       { 0x000300,   1, 0x04, 0x00000001 },
+       { 0x0013a8,   1, 0x04, 0x00000000 },
+       { 0x0012ec,   1, 0x04, 0x00000000 },
+       { 0x001310,   1, 0x04, 0x00000000 },
+       { 0x001314,   1, 0x04, 0x00000001 },
+       { 0x001380,   1, 0x04, 0x00000000 },
+       { 0x001384,   4, 0x04, 0x00000001 },
+       { 0x001394,   1, 0x04, 0x00000000 },
+       { 0x00139c,   1, 0x04, 0x00000000 },
+       { 0x001398,   1, 0x04, 0x00000000 },
+       { 0x001594,   1, 0x04, 0x00000000 },
+       { 0x001598,   4, 0x04, 0x00000001 },
+       { 0x000f54,   3, 0x04, 0x00000000 },
+       { 0x0019bc,   1, 0x04, 0x00000000 },
+       { 0x000f9c,   2, 0x04, 0x00000000 },
+       { 0x0012cc,   1, 0x04, 0x00000000 },
+       { 0x0012e8,   1, 0x04, 0x00000000 },
+       { 0x00130c,   1, 0x04, 0x00000001 },
+       { 0x001360,   8, 0x04, 0x00000000 },
+       { 0x00133c,   2, 0x04, 0x00000001 },
+       { 0x001344,   1, 0x04, 0x00000002 },
+       { 0x001348,   2, 0x04, 0x00000001 },
+       { 0x001350,   1, 0x04, 0x00000002 },
+       { 0x001358,   1, 0x04, 0x00000001 },
+       { 0x0012e4,   1, 0x04, 0x00000000 },
+       { 0x00131c,   4, 0x04, 0x00000000 },
+       { 0x0019c0,   1, 0x04, 0x00000000 },
+       { 0x001140,   1, 0x04, 0x00000000 },
+       { 0x000dd0,   1, 0x04, 0x00000000 },
+       { 0x000dd4,   1, 0x04, 0x00000001 },
+       { 0x0002f4,   1, 0x04, 0x00000000 },
+       { 0x0019c4,   1, 0x04, 0x00000000 },
+       { 0x0019c8,   1, 0x04, 0x00001500 },
+       { 0x00135c,   1, 0x04, 0x00000000 },
+       { 0x000f90,   1, 0x04, 0x00000000 },
+       { 0x0019e0,   8, 0x04, 0x00000001 },
+       { 0x0019cc,   1, 0x04, 0x00000001 },
+       { 0x0015b8,   1, 0x04, 0x00000000 },
+       { 0x001a00,   1, 0x04, 0x00001111 },
+       { 0x001a04,   7, 0x04, 0x00000000 },
+       { 0x000d6c,   2, 0x04, 0xffff0000 },
+       { 0x0010f8,   1, 0x04, 0x00001010 },
+       { 0x000d80,   5, 0x04, 0x00000000 },
+       { 0x000da0,   1, 0x04, 0x00000000 },
+       { 0x0007a4,   2, 0x04, 0x00000000 },
+       { 0x001508,   1, 0x04, 0x80000000 },
+       { 0x00150c,   1, 0x04, 0x40000000 },
+       { 0x001668,   1, 0x04, 0x00000000 },
+       { 0x000318,   2, 0x04, 0x00000008 },
+       { 0x000d9c,   1, 0x04, 0x00000001 },
+       { 0x000f14,   1, 0x04, 0x00000000 },
+       { 0x000374,   1, 0x04, 0x00000000 },
+       { 0x000378,   1, 0x04, 0x0000000c },
+       { 0x0007dc,   1, 0x04, 0x00000000 },
+       { 0x00074c,   1, 0x04, 0x00000055 },
+       { 0x001420,   1, 0x04, 0x00000003 },
+       { 0x001008,   1, 0x04, 0x00000008 },
+       { 0x00100c,   1, 0x04, 0x00000040 },
+       { 0x001010,   1, 0x04, 0x0000012c },
+       { 0x000d60,   1, 0x04, 0x00000040 },
+       { 0x001018,   1, 0x04, 0x00000020 },
+       { 0x00101c,   1, 0x04, 0x00000001 },
+       { 0x001020,   1, 0x04, 0x00000020 },
+       { 0x001024,   1, 0x04, 0x00000001 },
+       { 0x001444,   3, 0x04, 0x00000000 },
+       { 0x000360,   1, 0x04, 0x20164010 },
+       { 0x000364,   1, 0x04, 0x00000020 },
+       { 0x000368,   1, 0x04, 0x00000000 },
+       { 0x000da8,   1, 0x04, 0x00000030 },
+       { 0x000de4,   1, 0x04, 0x00000000 },
+       { 0x000204,   1, 0x04, 0x00000006 },
+       { 0x0002d0,   1, 0x04, 0x003fffff },
+       { 0x001220,   1, 0x04, 0x00000005 },
+       { 0x000fdc,   1, 0x04, 0x00000000 },
+       { 0x000f98,   1, 0x04, 0x00400008 },
+       { 0x001284,   1, 0x04, 0x08000080 },
+       { 0x001450,   1, 0x04, 0x00400008 },
+       { 0x001454,   1, 0x04, 0x08000080 },
+       { 0x000214,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+gm107_grctx_pack_mthd[] = {
+       { gm107_grctx_init_b097_0, 0xb097 },
+       { nvc0_grctx_init_902d_0, 0x902d },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_fe_0[] = {
+       { 0x404004,   8, 0x04, 0x00000000 },
+       { 0x404024,   1, 0x04, 0x0000e000 },
+       { 0x404028,   8, 0x04, 0x00000000 },
+       { 0x4040a8,   8, 0x04, 0x00000000 },
+       { 0x4040c8,   1, 0x04, 0xf800008f },
+       { 0x4040d0,   6, 0x04, 0x00000000 },
+       { 0x4040f8,   1, 0x04, 0x00000000 },
+       { 0x404100,  10, 0x04, 0x00000000 },
+       { 0x404130,   2, 0x04, 0x00000000 },
+       { 0x404150,   1, 0x04, 0x0000002e },
+       { 0x404154,   1, 0x04, 0x00000400 },
+       { 0x404158,   1, 0x04, 0x00000200 },
+       { 0x404164,   1, 0x04, 0x00000045 },
+       { 0x40417c,   2, 0x04, 0x00000000 },
+       { 0x404194,   1, 0x04, 0x01000700 },
+       { 0x4041a0,   4, 0x04, 0x00000000 },
+       { 0x404200,   4, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_ds_0[] = {
+       { 0x405800,   1, 0x04, 0x0f8001bf },
+       { 0x405830,   1, 0x04, 0x0aa01000 },
+       { 0x405834,   1, 0x04, 0x08000000 },
+       { 0x405838,   1, 0x04, 0x00000000 },
+       { 0x405854,   1, 0x04, 0x00000000 },
+       { 0x405870,   4, 0x04, 0x00000001 },
+       { 0x405a00,   2, 0x04, 0x00000000 },
+       { 0x405a18,   1, 0x04, 0x00000000 },
+       { 0x405a1c,   1, 0x04, 0x000000ff },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_pd_0[] = {
+       { 0x406020,   1, 0x04, 0x07410001 },
+       { 0x406028,   4, 0x04, 0x00000001 },
+       { 0x4064a8,   1, 0x04, 0x00000000 },
+       { 0x4064ac,   1, 0x04, 0x00003fff },
+       { 0x4064b0,   3, 0x04, 0x00000000 },
+       { 0x4064c0,   1, 0x04, 0x80400280 },
+       { 0x4064c4,   1, 0x04, 0x0400ffff },
+       { 0x4064c8,   1, 0x04, 0x018001ff },
+       { 0x4064cc,   9, 0x04, 0x00000000 },
+       { 0x4064fc,   1, 0x04, 0x0000022a },
+       { 0x406500,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_be_0[] = {
+       { 0x408800,   1, 0x04, 0x32802a3c },
+       { 0x408804,   1, 0x04, 0x00000040 },
+       { 0x408808,   1, 0x04, 0x1003e005 },
+       { 0x408840,   1, 0x04, 0x0000000b },
+       { 0x408900,   1, 0x04, 0xb080b801 },
+       { 0x408904,   1, 0x04, 0x63038001 },
+       { 0x408908,   1, 0x04, 0x02c8102f },
+       { 0x408980,   1, 0x04, 0x0000011d },
+       {}
+};
+
+static const struct nvc0_graph_pack
+gm107_grctx_pack_hub[] = {
+       { nvc0_grctx_init_main_0 },
+       { gm107_grctx_init_fe_0 },
+       { nvf0_grctx_init_pri_0 },
+       { nve4_grctx_init_memfmt_0 },
+       { gm107_grctx_init_ds_0 },
+       { nvf0_grctx_init_cwd_0 },
+       { gm107_grctx_init_pd_0 },
+       { nv108_grctx_init_rstr2d_0 },
+       { nve4_grctx_init_scc_0 },
+       { gm107_grctx_init_be_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_gpc_unk_0[] = {
+       { 0x418380,   1, 0x04, 0x00000056 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_gpc_unk_1[] = {
+       { 0x418600,   1, 0x04, 0x0000007f },
+       { 0x418684,   1, 0x04, 0x0000001f },
+       { 0x418700,   1, 0x04, 0x00000002 },
+       { 0x418704,   1, 0x04, 0x00000080 },
+       { 0x418708,   1, 0x04, 0x40000000 },
+       { 0x41870c,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_setup_0[] = {
+       { 0x418800,   1, 0x04, 0x7006863a },
+       { 0x418810,   1, 0x04, 0x00000000 },
+       { 0x418828,   1, 0x04, 0x00000044 },
+       { 0x418830,   1, 0x04, 0x10000001 },
+       { 0x4188d8,   1, 0x04, 0x00000008 },
+       { 0x4188e0,   1, 0x04, 0x01000000 },
+       { 0x4188e8,   5, 0x04, 0x00000000 },
+       { 0x4188fc,   1, 0x04, 0x20100058 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_gpc_unk_2[] = {
+       { 0x418d24,   1, 0x04, 0x00000000 },
+       { 0x418e00,   1, 0x04, 0x90000000 },
+       { 0x418e24,   1, 0x04, 0x00000000 },
+       { 0x418e28,   1, 0x04, 0x00000030 },
+       { 0x418e30,   1, 0x04, 0x00000000 },
+       { 0x418e34,   1, 0x04, 0x00010000 },
+       { 0x418e38,   1, 0x04, 0x00000000 },
+       { 0x418e40,  22, 0x04, 0x00000000 },
+       { 0x418ea0,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+gm107_grctx_pack_gpc[] = {
+       { gm107_grctx_init_gpc_unk_0 },
+       { nv108_grctx_init_prop_0 },
+       { gm107_grctx_init_gpc_unk_1 },
+       { gm107_grctx_init_setup_0 },
+       { nvc0_grctx_init_zcull_0 },
+       { nv108_grctx_init_crstr_0 },
+       { nve4_grctx_init_gpm_0 },
+       { gm107_grctx_init_gpc_unk_2 },
+       { nvc0_grctx_init_gcc_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_tex_0[] = {
+       { 0x419a00,   1, 0x04, 0x000300f0 },
+       { 0x419a04,   1, 0x04, 0x00000005 },
+       { 0x419a08,   1, 0x04, 0x00000421 },
+       { 0x419a0c,   1, 0x04, 0x00120000 },
+       { 0x419a10,   1, 0x04, 0x00000000 },
+       { 0x419a14,   1, 0x04, 0x00002200 },
+       { 0x419a1c,   1, 0x04, 0x0000c000 },
+       { 0x419a20,   1, 0x04, 0x20008a00 },
+       { 0x419a30,   1, 0x04, 0x00000001 },
+       { 0x419a3c,   1, 0x04, 0x00000002 },
+       { 0x419ac4,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_mpc_0[] = {
+       { 0x419c00,   1, 0x04, 0x0000001a },
+       { 0x419c04,   1, 0x04, 0x80000006 },
+       { 0x419c08,   1, 0x04, 0x00000002 },
+       { 0x419c20,   1, 0x04, 0x00000000 },
+       { 0x419c24,   1, 0x04, 0x00084210 },
+       { 0x419c28,   1, 0x04, 0x3efbefbe },
+       { 0x419c2c,   1, 0x04, 0x00000000 },
+       { 0x419c34,   1, 0x04, 0x01ff1ff3 },
+       { 0x419c3c,   1, 0x04, 0x00001919 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_l1c_0[] = {
+       { 0x419c84,   1, 0x04, 0x00000020 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_sm_0[] = {
+       { 0x419e04,   3, 0x04, 0x00000000 },
+       { 0x419e10,   1, 0x04, 0x00001c02 },
+       { 0x419e44,   1, 0x04, 0x00d3eff2 },
+       { 0x419e48,   1, 0x04, 0x00000000 },
+       { 0x419e4c,   1, 0x04, 0x0000007f },
+       { 0x419e50,   1, 0x04, 0x00000000 },
+       { 0x419e60,   4, 0x04, 0x00000000 },
+       { 0x419e74,  10, 0x04, 0x00000000 },
+       { 0x419eac,   1, 0x04, 0x0001cf8b },
+       { 0x419eb0,   1, 0x04, 0x00030300 },
+       { 0x419eb8,   1, 0x04, 0x00000000 },
+       { 0x419ef0,  24, 0x04, 0x00000000 },
+       { 0x419f68,   2, 0x04, 0x00000000 },
+       { 0x419f70,   1, 0x04, 0x00000020 },
+       { 0x419f78,   1, 0x04, 0x000003eb },
+       { 0x419f7c,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+gm107_grctx_pack_tpc[] = {
+       { nvd7_grctx_init_pe_0 },
+       { gm107_grctx_init_tex_0 },
+       { gm107_grctx_init_mpc_0 },
+       { gm107_grctx_init_l1c_0 },
+       { gm107_grctx_init_sm_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_cbm_0[] = {
+       { 0x41bec0,   1, 0x04, 0x00000000 },
+       { 0x41bec4,   1, 0x04, 0x01050000 },
+       { 0x41bee4,   1, 0x04, 0x00000000 },
+       { 0x41bef0,   1, 0x04, 0x000003ff },
+       { 0x41bef4,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_grctx_init_wwdx_0[] = {
+       { 0x41bf00,   1, 0x04, 0x0a418820 },
+       { 0x41bf04,   1, 0x04, 0x062080e6 },
+       { 0x41bf08,   1, 0x04, 0x020398a4 },
+       { 0x41bf0c,   1, 0x04, 0x0e629062 },
+       { 0x41bf10,   1, 0x04, 0x0a418820 },
+       { 0x41bf14,   1, 0x04, 0x000000e6 },
+       { 0x41bfd0,   1, 0x04, 0x00900103 },
+       { 0x41bfe0,   1, 0x04, 0x80000000 },
+       { 0x41bfe4,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+gm107_grctx_pack_ppc[] = {
+       { nve4_grctx_init_pes_0 },
+       { gm107_grctx_init_cbm_0 },
+       { gm107_grctx_init_wwdx_0 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+static void
+gm107_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+       mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+       mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+       mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+
+       mmio_list(0x40800c, 0x00000000,  8, 1);
+       mmio_list(0x408010, 0x80000000,  0, 0);
+       mmio_list(0x419004, 0x00000000,  8, 1);
+       mmio_list(0x419008, 0x00000000,  0, 0);
+       mmio_list(0x4064cc, 0x80000000,  0, 0);
+       mmio_list(0x418e30, 0x80000000,  0, 0);
+
+       mmio_list(0x408004, 0x00000000,  8, 0);
+       mmio_list(0x408008, 0x80000030,  0, 0);
+       mmio_list(0x418e24, 0x00000000,  8, 0);
+       mmio_list(0x418e28, 0x80000030,  0, 0);
+
+       mmio_list(0x418810, 0x80000000, 12, 2);
+       mmio_list(0x419848, 0x10000000, 12, 2);
+       mmio_list(0x419c2c, 0x10000000, 12, 2);
+
+       mmio_list(0x405830, 0x0aa01000,  0, 0);
+       mmio_list(0x4064c4, 0x0400ffff,  0, 0);
+
+       /*XXX*/
+       mmio_list(0x5030c0, 0x00001540,  0, 0);
+       mmio_list(0x5030f4, 0x00000000,  0, 0);
+       mmio_list(0x5030e4, 0x00002000,  0, 0);
+       mmio_list(0x5030f8, 0x00003fc0,  0, 0);
+       mmio_list(0x418ea0, 0x07151540,  0, 0);
+
+       mmio_list(0x5032c0, 0x00001540,  0, 0);
+       mmio_list(0x5032f4, 0x00001fe0,  0, 0);
+       mmio_list(0x5032e4, 0x00002000,  0, 0);
+       mmio_list(0x5032f8, 0x00006fc0,  0, 0);
+       mmio_list(0x418ea4, 0x07151540,  0, 0);
+}
+
+static void
+gm107_grctx_generate_tpcid(struct nvc0_graph_priv *priv)
+{
+       int gpc, tpc, id;
+
+       for (tpc = 0, id = 0; tpc < 4; tpc++) {
+               for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+                       if (tpc < priv->tpc_nr[gpc]) {
+                               nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
+                               nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
+                               nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
+                               id++;
+                       }
+
+                       nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+                       nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
+               }
+       }
+}
+
+static void
+gm107_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+       struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+       int i;
+
+       nvc0_graph_mmio(priv, oclass->hub);
+       nvc0_graph_mmio(priv, oclass->gpc);
+       nvc0_graph_mmio(priv, oclass->zcull);
+       nvc0_graph_mmio(priv, oclass->tpc);
+       nvc0_graph_mmio(priv, oclass->ppc);
+
+       nv_wr32(priv, 0x404154, 0x00000000);
+
+       oclass->mods(priv, info);
+       oclass->unkn(priv);
+
+       gm107_grctx_generate_tpcid(priv);
+       nvc0_grctx_generate_r406028(priv);
+       nve4_grctx_generate_r418bb8(priv);
+       nvc0_grctx_generate_r406800(priv);
+
+       nv_wr32(priv, 0x4064d0, 0x00000001);
+       for (i = 1; i < 8; i++)
+               nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+       nv_wr32(priv, 0x406500, 0x00000001);
+
+       nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
+
+       if (priv->gpc_nr == 1) {
+               nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
+               nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
+       } else {
+               nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
+               nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
+       }
+
+       nvc0_graph_icmd(priv, oclass->icmd);
+       nv_wr32(priv, 0x404154, 0x00000400);
+       nvc0_graph_mthd(priv, oclass->mthd);
+
+       nv_mask(priv, 0x419e00, 0x00808080, 0x00808080);
+       nv_mask(priv, 0x419ccc, 0x80000000, 0x80000000);
+       nv_mask(priv, 0x419f80, 0x80000000, 0x80000000);
+       nv_mask(priv, 0x419f88, 0x80000000, 0x80000000);
+}
+
+struct nouveau_oclass *
+gm107_grctx_oclass = &(struct nvc0_grctx_oclass) {
+       .base.handle = NV_ENGCTX(GR, 0x08),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_graph_context_ctor,
+               .dtor = nvc0_graph_context_dtor,
+               .init = _nouveau_graph_context_init,
+               .fini = _nouveau_graph_context_fini,
+               .rd32 = _nouveau_graph_context_rd32,
+               .wr32 = _nouveau_graph_context_wr32,
+       },
+       .main  = gm107_grctx_generate_main,
+       .mods  = gm107_grctx_generate_mods,
+       .unkn  = nve4_grctx_generate_unkn,
+       .hub   = gm107_grctx_pack_hub,
+       .gpc   = gm107_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = gm107_grctx_pack_tpc,
+       .ppc   = gm107_grctx_pack_ppc,
+       .icmd  = gm107_grctx_pack_icmd,
+       .mthd  = gm107_grctx_pack_mthd,
+}.base;
index a86bd33..48351b4 100644 (file)
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "nvc0.h"
+#include "ctxnvc0.h"
 
-static struct nvc0_graph_init
-nv108_grctx_init_icmd[] = {
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct nvc0_graph_init
+nv108_grctx_init_icmd_0[] = {
        { 0x001000,   1, 0x01, 0x00000004 },
        { 0x000039,   3, 0x01, 0x00000000 },
        { 0x0000a9,   1, 0x01, 0x0000ffff },
@@ -274,839 +278,14 @@ nv108_grctx_init_icmd[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nv108_grctx_init_a197[] = {
-       { 0x000800,   1, 0x04, 0x00000000 },
-       { 0x000840,   1, 0x04, 0x00000000 },
-       { 0x000880,   1, 0x04, 0x00000000 },
-       { 0x0008c0,   1, 0x04, 0x00000000 },
-       { 0x000900,   1, 0x04, 0x00000000 },
-       { 0x000940,   1, 0x04, 0x00000000 },
-       { 0x000980,   1, 0x04, 0x00000000 },
-       { 0x0009c0,   1, 0x04, 0x00000000 },
-       { 0x000804,   1, 0x04, 0x00000000 },
-       { 0x000844,   1, 0x04, 0x00000000 },
-       { 0x000884,   1, 0x04, 0x00000000 },
-       { 0x0008c4,   1, 0x04, 0x00000000 },
-       { 0x000904,   1, 0x04, 0x00000000 },
-       { 0x000944,   1, 0x04, 0x00000000 },
-       { 0x000984,   1, 0x04, 0x00000000 },
-       { 0x0009c4,   1, 0x04, 0x00000000 },
-       { 0x000808,   1, 0x04, 0x00000400 },
-       { 0x000848,   1, 0x04, 0x00000400 },
-       { 0x000888,   1, 0x04, 0x00000400 },
-       { 0x0008c8,   1, 0x04, 0x00000400 },
-       { 0x000908,   1, 0x04, 0x00000400 },
-       { 0x000948,   1, 0x04, 0x00000400 },
-       { 0x000988,   1, 0x04, 0x00000400 },
-       { 0x0009c8,   1, 0x04, 0x00000400 },
-       { 0x00080c,   1, 0x04, 0x00000300 },
-       { 0x00084c,   1, 0x04, 0x00000300 },
-       { 0x00088c,   1, 0x04, 0x00000300 },
-       { 0x0008cc,   1, 0x04, 0x00000300 },
-       { 0x00090c,   1, 0x04, 0x00000300 },
-       { 0x00094c,   1, 0x04, 0x00000300 },
-       { 0x00098c,   1, 0x04, 0x00000300 },
-       { 0x0009cc,   1, 0x04, 0x00000300 },
-       { 0x000810,   1, 0x04, 0x000000cf },
-       { 0x000850,   1, 0x04, 0x00000000 },
-       { 0x000890,   1, 0x04, 0x00000000 },
-       { 0x0008d0,   1, 0x04, 0x00000000 },
-       { 0x000910,   1, 0x04, 0x00000000 },
-       { 0x000950,   1, 0x04, 0x00000000 },
-       { 0x000990,   1, 0x04, 0x00000000 },
-       { 0x0009d0,   1, 0x04, 0x00000000 },
-       { 0x000814,   1, 0x04, 0x00000040 },
-       { 0x000854,   1, 0x04, 0x00000040 },
-       { 0x000894,   1, 0x04, 0x00000040 },
-       { 0x0008d4,   1, 0x04, 0x00000040 },
-       { 0x000914,   1, 0x04, 0x00000040 },
-       { 0x000954,   1, 0x04, 0x00000040 },
-       { 0x000994,   1, 0x04, 0x00000040 },
-       { 0x0009d4,   1, 0x04, 0x00000040 },
-       { 0x000818,   1, 0x04, 0x00000001 },
-       { 0x000858,   1, 0x04, 0x00000001 },
-       { 0x000898,   1, 0x04, 0x00000001 },
-       { 0x0008d8,   1, 0x04, 0x00000001 },
-       { 0x000918,   1, 0x04, 0x00000001 },
-       { 0x000958,   1, 0x04, 0x00000001 },
-       { 0x000998,   1, 0x04, 0x00000001 },
-       { 0x0009d8,   1, 0x04, 0x00000001 },
-       { 0x00081c,   1, 0x04, 0x00000000 },
-       { 0x00085c,   1, 0x04, 0x00000000 },
-       { 0x00089c,   1, 0x04, 0x00000000 },
-       { 0x0008dc,   1, 0x04, 0x00000000 },
-       { 0x00091c,   1, 0x04, 0x00000000 },
-       { 0x00095c,   1, 0x04, 0x00000000 },
-       { 0x00099c,   1, 0x04, 0x00000000 },
-       { 0x0009dc,   1, 0x04, 0x00000000 },
-       { 0x000820,   1, 0x04, 0x00000000 },
-       { 0x000860,   1, 0x04, 0x00000000 },
-       { 0x0008a0,   1, 0x04, 0x00000000 },
-       { 0x0008e0,   1, 0x04, 0x00000000 },
-       { 0x000920,   1, 0x04, 0x00000000 },
-       { 0x000960,   1, 0x04, 0x00000000 },
-       { 0x0009a0,   1, 0x04, 0x00000000 },
-       { 0x0009e0,   1, 0x04, 0x00000000 },
-       { 0x001c00,   1, 0x04, 0x00000000 },
-       { 0x001c10,   1, 0x04, 0x00000000 },
-       { 0x001c20,   1, 0x04, 0x00000000 },
-       { 0x001c30,   1, 0x04, 0x00000000 },
-       { 0x001c40,   1, 0x04, 0x00000000 },
-       { 0x001c50,   1, 0x04, 0x00000000 },
-       { 0x001c60,   1, 0x04, 0x00000000 },
-       { 0x001c70,   1, 0x04, 0x00000000 },
-       { 0x001c80,   1, 0x04, 0x00000000 },
-       { 0x001c90,   1, 0x04, 0x00000000 },
-       { 0x001ca0,   1, 0x04, 0x00000000 },
-       { 0x001cb0,   1, 0x04, 0x00000000 },
-       { 0x001cc0,   1, 0x04, 0x00000000 },
-       { 0x001cd0,   1, 0x04, 0x00000000 },
-       { 0x001ce0,   1, 0x04, 0x00000000 },
-       { 0x001cf0,   1, 0x04, 0x00000000 },
-       { 0x001c04,   1, 0x04, 0x00000000 },
-       { 0x001c14,   1, 0x04, 0x00000000 },
-       { 0x001c24,   1, 0x04, 0x00000000 },
-       { 0x001c34,   1, 0x04, 0x00000000 },
-       { 0x001c44,   1, 0x04, 0x00000000 },
-       { 0x001c54,   1, 0x04, 0x00000000 },
-       { 0x001c64,   1, 0x04, 0x00000000 },
-       { 0x001c74,   1, 0x04, 0x00000000 },
-       { 0x001c84,   1, 0x04, 0x00000000 },
-       { 0x001c94,   1, 0x04, 0x00000000 },
-       { 0x001ca4,   1, 0x04, 0x00000000 },
-       { 0x001cb4,   1, 0x04, 0x00000000 },
-       { 0x001cc4,   1, 0x04, 0x00000000 },
-       { 0x001cd4,   1, 0x04, 0x00000000 },
-       { 0x001ce4,   1, 0x04, 0x00000000 },
-       { 0x001cf4,   1, 0x04, 0x00000000 },
-       { 0x001c08,   1, 0x04, 0x00000000 },
-       { 0x001c18,   1, 0x04, 0x00000000 },
-       { 0x001c28,   1, 0x04, 0x00000000 },
-       { 0x001c38,   1, 0x04, 0x00000000 },
-       { 0x001c48,   1, 0x04, 0x00000000 },
-       { 0x001c58,   1, 0x04, 0x00000000 },
-       { 0x001c68,   1, 0x04, 0x00000000 },
-       { 0x001c78,   1, 0x04, 0x00000000 },
-       { 0x001c88,   1, 0x04, 0x00000000 },
-       { 0x001c98,   1, 0x04, 0x00000000 },
-       { 0x001ca8,   1, 0x04, 0x00000000 },
-       { 0x001cb8,   1, 0x04, 0x00000000 },
-       { 0x001cc8,   1, 0x04, 0x00000000 },
-       { 0x001cd8,   1, 0x04, 0x00000000 },
-       { 0x001ce8,   1, 0x04, 0x00000000 },
-       { 0x001cf8,   1, 0x04, 0x00000000 },
-       { 0x001c0c,   1, 0x04, 0x00000000 },
-       { 0x001c1c,   1, 0x04, 0x00000000 },
-       { 0x001c2c,   1, 0x04, 0x00000000 },
-       { 0x001c3c,   1, 0x04, 0x00000000 },
-       { 0x001c4c,   1, 0x04, 0x00000000 },
-       { 0x001c5c,   1, 0x04, 0x00000000 },
-       { 0x001c6c,   1, 0x04, 0x00000000 },
-       { 0x001c7c,   1, 0x04, 0x00000000 },
-       { 0x001c8c,   1, 0x04, 0x00000000 },
-       { 0x001c9c,   1, 0x04, 0x00000000 },
-       { 0x001cac,   1, 0x04, 0x00000000 },
-       { 0x001cbc,   1, 0x04, 0x00000000 },
-       { 0x001ccc,   1, 0x04, 0x00000000 },
-       { 0x001cdc,   1, 0x04, 0x00000000 },
-       { 0x001cec,   1, 0x04, 0x00000000 },
-       { 0x001cfc,   2, 0x04, 0x00000000 },
-       { 0x001d10,   1, 0x04, 0x00000000 },
-       { 0x001d20,   1, 0x04, 0x00000000 },
-       { 0x001d30,   1, 0x04, 0x00000000 },
-       { 0x001d40,   1, 0x04, 0x00000000 },
-       { 0x001d50,   1, 0x04, 0x00000000 },
-       { 0x001d60,   1, 0x04, 0x00000000 },
-       { 0x001d70,   1, 0x04, 0x00000000 },
-       { 0x001d80,   1, 0x04, 0x00000000 },
-       { 0x001d90,   1, 0x04, 0x00000000 },
-       { 0x001da0,   1, 0x04, 0x00000000 },
-       { 0x001db0,   1, 0x04, 0x00000000 },
-       { 0x001dc0,   1, 0x04, 0x00000000 },
-       { 0x001dd0,   1, 0x04, 0x00000000 },
-       { 0x001de0,   1, 0x04, 0x00000000 },
-       { 0x001df0,   1, 0x04, 0x00000000 },
-       { 0x001d04,   1, 0x04, 0x00000000 },
-       { 0x001d14,   1, 0x04, 0x00000000 },
-       { 0x001d24,   1, 0x04, 0x00000000 },
-       { 0x001d34,   1, 0x04, 0x00000000 },
-       { 0x001d44,   1, 0x04, 0x00000000 },
-       { 0x001d54,   1, 0x04, 0x00000000 },
-       { 0x001d64,   1, 0x04, 0x00000000 },
-       { 0x001d74,   1, 0x04, 0x00000000 },
-       { 0x001d84,   1, 0x04, 0x00000000 },
-       { 0x001d94,   1, 0x04, 0x00000000 },
-       { 0x001da4,   1, 0x04, 0x00000000 },
-       { 0x001db4,   1, 0x04, 0x00000000 },
-       { 0x001dc4,   1, 0x04, 0x00000000 },
-       { 0x001dd4,   1, 0x04, 0x00000000 },
-       { 0x001de4,   1, 0x04, 0x00000000 },
-       { 0x001df4,   1, 0x04, 0x00000000 },
-       { 0x001d08,   1, 0x04, 0x00000000 },
-       { 0x001d18,   1, 0x04, 0x00000000 },
-       { 0x001d28,   1, 0x04, 0x00000000 },
-       { 0x001d38,   1, 0x04, 0x00000000 },
-       { 0x001d48,   1, 0x04, 0x00000000 },
-       { 0x001d58,   1, 0x04, 0x00000000 },
-       { 0x001d68,   1, 0x04, 0x00000000 },
-       { 0x001d78,   1, 0x04, 0x00000000 },
-       { 0x001d88,   1, 0x04, 0x00000000 },
-       { 0x001d98,   1, 0x04, 0x00000000 },
-       { 0x001da8,   1, 0x04, 0x00000000 },
-       { 0x001db8,   1, 0x04, 0x00000000 },
-       { 0x001dc8,   1, 0x04, 0x00000000 },
-       { 0x001dd8,   1, 0x04, 0x00000000 },
-       { 0x001de8,   1, 0x04, 0x00000000 },
-       { 0x001df8,   1, 0x04, 0x00000000 },
-       { 0x001d0c,   1, 0x04, 0x00000000 },
-       { 0x001d1c,   1, 0x04, 0x00000000 },
-       { 0x001d2c,   1, 0x04, 0x00000000 },
-       { 0x001d3c,   1, 0x04, 0x00000000 },
-       { 0x001d4c,   1, 0x04, 0x00000000 },
-       { 0x001d5c,   1, 0x04, 0x00000000 },
-       { 0x001d6c,   1, 0x04, 0x00000000 },
-       { 0x001d7c,   1, 0x04, 0x00000000 },
-       { 0x001d8c,   1, 0x04, 0x00000000 },
-       { 0x001d9c,   1, 0x04, 0x00000000 },
-       { 0x001dac,   1, 0x04, 0x00000000 },
-       { 0x001dbc,   1, 0x04, 0x00000000 },
-       { 0x001dcc,   1, 0x04, 0x00000000 },
-       { 0x001ddc,   1, 0x04, 0x00000000 },
-       { 0x001dec,   1, 0x04, 0x00000000 },
-       { 0x001dfc,   1, 0x04, 0x00000000 },
-       { 0x001f00,   1, 0x04, 0x00000000 },
-       { 0x001f08,   1, 0x04, 0x00000000 },
-       { 0x001f10,   1, 0x04, 0x00000000 },
-       { 0x001f18,   1, 0x04, 0x00000000 },
-       { 0x001f20,   1, 0x04, 0x00000000 },
-       { 0x001f28,   1, 0x04, 0x00000000 },
-       { 0x001f30,   1, 0x04, 0x00000000 },
-       { 0x001f38,   1, 0x04, 0x00000000 },
-       { 0x001f40,   1, 0x04, 0x00000000 },
-       { 0x001f48,   1, 0x04, 0x00000000 },
-       { 0x001f50,   1, 0x04, 0x00000000 },
-       { 0x001f58,   1, 0x04, 0x00000000 },
-       { 0x001f60,   1, 0x04, 0x00000000 },
-       { 0x001f68,   1, 0x04, 0x00000000 },
-       { 0x001f70,   1, 0x04, 0x00000000 },
-       { 0x001f78,   1, 0x04, 0x00000000 },
-       { 0x001f04,   1, 0x04, 0x00000000 },
-       { 0x001f0c,   1, 0x04, 0x00000000 },
-       { 0x001f14,   1, 0x04, 0x00000000 },
-       { 0x001f1c,   1, 0x04, 0x00000000 },
-       { 0x001f24,   1, 0x04, 0x00000000 },
-       { 0x001f2c,   1, 0x04, 0x00000000 },
-       { 0x001f34,   1, 0x04, 0x00000000 },
-       { 0x001f3c,   1, 0x04, 0x00000000 },
-       { 0x001f44,   1, 0x04, 0x00000000 },
-       { 0x001f4c,   1, 0x04, 0x00000000 },
-       { 0x001f54,   1, 0x04, 0x00000000 },
-       { 0x001f5c,   1, 0x04, 0x00000000 },
-       { 0x001f64,   1, 0x04, 0x00000000 },
-       { 0x001f6c,   1, 0x04, 0x00000000 },
-       { 0x001f74,   1, 0x04, 0x00000000 },
-       { 0x001f7c,   2, 0x04, 0x00000000 },
-       { 0x001f88,   1, 0x04, 0x00000000 },
-       { 0x001f90,   1, 0x04, 0x00000000 },
-       { 0x001f98,   1, 0x04, 0x00000000 },
-       { 0x001fa0,   1, 0x04, 0x00000000 },
-       { 0x001fa8,   1, 0x04, 0x00000000 },
-       { 0x001fb0,   1, 0x04, 0x00000000 },
-       { 0x001fb8,   1, 0x04, 0x00000000 },
-       { 0x001fc0,   1, 0x04, 0x00000000 },
-       { 0x001fc8,   1, 0x04, 0x00000000 },
-       { 0x001fd0,   1, 0x04, 0x00000000 },
-       { 0x001fd8,   1, 0x04, 0x00000000 },
-       { 0x001fe0,   1, 0x04, 0x00000000 },
-       { 0x001fe8,   1, 0x04, 0x00000000 },
-       { 0x001ff0,   1, 0x04, 0x00000000 },
-       { 0x001ff8,   1, 0x04, 0x00000000 },
-       { 0x001f84,   1, 0x04, 0x00000000 },
-       { 0x001f8c,   1, 0x04, 0x00000000 },
-       { 0x001f94,   1, 0x04, 0x00000000 },
-       { 0x001f9c,   1, 0x04, 0x00000000 },
-       { 0x001fa4,   1, 0x04, 0x00000000 },
-       { 0x001fac,   1, 0x04, 0x00000000 },
-       { 0x001fb4,   1, 0x04, 0x00000000 },
-       { 0x001fbc,   1, 0x04, 0x00000000 },
-       { 0x001fc4,   1, 0x04, 0x00000000 },
-       { 0x001fcc,   1, 0x04, 0x00000000 },
-       { 0x001fd4,   1, 0x04, 0x00000000 },
-       { 0x001fdc,   1, 0x04, 0x00000000 },
-       { 0x001fe4,   1, 0x04, 0x00000000 },
-       { 0x001fec,   1, 0x04, 0x00000000 },
-       { 0x001ff4,   1, 0x04, 0x00000000 },
-       { 0x001ffc,   2, 0x04, 0x00000000 },
-       { 0x002040,   1, 0x04, 0x00000011 },
-       { 0x002080,   1, 0x04, 0x00000020 },
-       { 0x0020c0,   1, 0x04, 0x00000030 },
-       { 0x002100,   1, 0x04, 0x00000040 },
-       { 0x002140,   1, 0x04, 0x00000051 },
-       { 0x00200c,   1, 0x04, 0x00000001 },
-       { 0x00204c,   1, 0x04, 0x00000001 },
-       { 0x00208c,   1, 0x04, 0x00000001 },
-       { 0x0020cc,   1, 0x04, 0x00000001 },
-       { 0x00210c,   1, 0x04, 0x00000001 },
-       { 0x00214c,   1, 0x04, 0x00000001 },
-       { 0x002010,   1, 0x04, 0x00000000 },
-       { 0x002050,   1, 0x04, 0x00000000 },
-       { 0x002090,   1, 0x04, 0x00000001 },
-       { 0x0020d0,   1, 0x04, 0x00000002 },
-       { 0x002110,   1, 0x04, 0x00000003 },
-       { 0x002150,   1, 0x04, 0x00000004 },
-       { 0x000380,   1, 0x04, 0x00000000 },
-       { 0x0003a0,   1, 0x04, 0x00000000 },
-       { 0x0003c0,   1, 0x04, 0x00000000 },
-       { 0x0003e0,   1, 0x04, 0x00000000 },
-       { 0x000384,   1, 0x04, 0x00000000 },
-       { 0x0003a4,   1, 0x04, 0x00000000 },
-       { 0x0003c4,   1, 0x04, 0x00000000 },
-       { 0x0003e4,   1, 0x04, 0x00000000 },
-       { 0x000388,   1, 0x04, 0x00000000 },
-       { 0x0003a8,   1, 0x04, 0x00000000 },
-       { 0x0003c8,   1, 0x04, 0x00000000 },
-       { 0x0003e8,   1, 0x04, 0x00000000 },
-       { 0x00038c,   1, 0x04, 0x00000000 },
-       { 0x0003ac,   1, 0x04, 0x00000000 },
-       { 0x0003cc,   1, 0x04, 0x00000000 },
-       { 0x0003ec,   1, 0x04, 0x00000000 },
-       { 0x000700,   1, 0x04, 0x00000000 },
-       { 0x000710,   1, 0x04, 0x00000000 },
-       { 0x000720,   1, 0x04, 0x00000000 },
-       { 0x000730,   1, 0x04, 0x00000000 },
-       { 0x000704,   1, 0x04, 0x00000000 },
-       { 0x000714,   1, 0x04, 0x00000000 },
-       { 0x000724,   1, 0x04, 0x00000000 },
-       { 0x000734,   1, 0x04, 0x00000000 },
-       { 0x000708,   1, 0x04, 0x00000000 },
-       { 0x000718,   1, 0x04, 0x00000000 },
-       { 0x000728,   1, 0x04, 0x00000000 },
-       { 0x000738,   1, 0x04, 0x00000000 },
-       { 0x002800, 128, 0x04, 0x00000000 },
-       { 0x000a00,   1, 0x04, 0x00000000 },
-       { 0x000a20,   1, 0x04, 0x00000000 },
-       { 0x000a40,   1, 0x04, 0x00000000 },
-       { 0x000a60,   1, 0x04, 0x00000000 },
-       { 0x000a80,   1, 0x04, 0x00000000 },
-       { 0x000aa0,   1, 0x04, 0x00000000 },
-       { 0x000ac0,   1, 0x04, 0x00000000 },
-       { 0x000ae0,   1, 0x04, 0x00000000 },
-       { 0x000b00,   1, 0x04, 0x00000000 },
-       { 0x000b20,   1, 0x04, 0x00000000 },
-       { 0x000b40,   1, 0x04, 0x00000000 },
-       { 0x000b60,   1, 0x04, 0x00000000 },
-       { 0x000b80,   1, 0x04, 0x00000000 },
-       { 0x000ba0,   1, 0x04, 0x00000000 },
-       { 0x000bc0,   1, 0x04, 0x00000000 },
-       { 0x000be0,   1, 0x04, 0x00000000 },
-       { 0x000a04,   1, 0x04, 0x00000000 },
-       { 0x000a24,   1, 0x04, 0x00000000 },
-       { 0x000a44,   1, 0x04, 0x00000000 },
-       { 0x000a64,   1, 0x04, 0x00000000 },
-       { 0x000a84,   1, 0x04, 0x00000000 },
-       { 0x000aa4,   1, 0x04, 0x00000000 },
-       { 0x000ac4,   1, 0x04, 0x00000000 },
-       { 0x000ae4,   1, 0x04, 0x00000000 },
-       { 0x000b04,   1, 0x04, 0x00000000 },
-       { 0x000b24,   1, 0x04, 0x00000000 },
-       { 0x000b44,   1, 0x04, 0x00000000 },
-       { 0x000b64,   1, 0x04, 0x00000000 },
-       { 0x000b84,   1, 0x04, 0x00000000 },
-       { 0x000ba4,   1, 0x04, 0x00000000 },
-       { 0x000bc4,   1, 0x04, 0x00000000 },
-       { 0x000be4,   1, 0x04, 0x00000000 },
-       { 0x000a08,   1, 0x04, 0x00000000 },
-       { 0x000a28,   1, 0x04, 0x00000000 },
-       { 0x000a48,   1, 0x04, 0x00000000 },
-       { 0x000a68,   1, 0x04, 0x00000000 },
-       { 0x000a88,   1, 0x04, 0x00000000 },
-       { 0x000aa8,   1, 0x04, 0x00000000 },
-       { 0x000ac8,   1, 0x04, 0x00000000 },
-       { 0x000ae8,   1, 0x04, 0x00000000 },
-       { 0x000b08,   1, 0x04, 0x00000000 },
-       { 0x000b28,   1, 0x04, 0x00000000 },
-       { 0x000b48,   1, 0x04, 0x00000000 },
-       { 0x000b68,   1, 0x04, 0x00000000 },
-       { 0x000b88,   1, 0x04, 0x00000000 },
-       { 0x000ba8,   1, 0x04, 0x00000000 },
-       { 0x000bc8,   1, 0x04, 0x00000000 },
-       { 0x000be8,   1, 0x04, 0x00000000 },
-       { 0x000a0c,   1, 0x04, 0x00000000 },
-       { 0x000a2c,   1, 0x04, 0x00000000 },
-       { 0x000a4c,   1, 0x04, 0x00000000 },
-       { 0x000a6c,   1, 0x04, 0x00000000 },
-       { 0x000a8c,   1, 0x04, 0x00000000 },
-       { 0x000aac,   1, 0x04, 0x00000000 },
-       { 0x000acc,   1, 0x04, 0x00000000 },
-       { 0x000aec,   1, 0x04, 0x00000000 },
-       { 0x000b0c,   1, 0x04, 0x00000000 },
-       { 0x000b2c,   1, 0x04, 0x00000000 },
-       { 0x000b4c,   1, 0x04, 0x00000000 },
-       { 0x000b6c,   1, 0x04, 0x00000000 },
-       { 0x000b8c,   1, 0x04, 0x00000000 },
-       { 0x000bac,   1, 0x04, 0x00000000 },
-       { 0x000bcc,   1, 0x04, 0x00000000 },
-       { 0x000bec,   1, 0x04, 0x00000000 },
-       { 0x000a10,   1, 0x04, 0x00000000 },
-       { 0x000a30,   1, 0x04, 0x00000000 },
-       { 0x000a50,   1, 0x04, 0x00000000 },
-       { 0x000a70,   1, 0x04, 0x00000000 },
-       { 0x000a90,   1, 0x04, 0x00000000 },
-       { 0x000ab0,   1, 0x04, 0x00000000 },
-       { 0x000ad0,   1, 0x04, 0x00000000 },
-       { 0x000af0,   1, 0x04, 0x00000000 },
-       { 0x000b10,   1, 0x04, 0x00000000 },
-       { 0x000b30,   1, 0x04, 0x00000000 },
-       { 0x000b50,   1, 0x04, 0x00000000 },
-       { 0x000b70,   1, 0x04, 0x00000000 },
-       { 0x000b90,   1, 0x04, 0x00000000 },
-       { 0x000bb0,   1, 0x04, 0x00000000 },
-       { 0x000bd0,   1, 0x04, 0x00000000 },
-       { 0x000bf0,   1, 0x04, 0x00000000 },
-       { 0x000a14,   1, 0x04, 0x00000000 },
-       { 0x000a34,   1, 0x04, 0x00000000 },
-       { 0x000a54,   1, 0x04, 0x00000000 },
-       { 0x000a74,   1, 0x04, 0x00000000 },
-       { 0x000a94,   1, 0x04, 0x00000000 },
-       { 0x000ab4,   1, 0x04, 0x00000000 },
-       { 0x000ad4,   1, 0x04, 0x00000000 },
-       { 0x000af4,   1, 0x04, 0x00000000 },
-       { 0x000b14,   1, 0x04, 0x00000000 },
-       { 0x000b34,   1, 0x04, 0x00000000 },
-       { 0x000b54,   1, 0x04, 0x00000000 },
-       { 0x000b74,   1, 0x04, 0x00000000 },
-       { 0x000b94,   1, 0x04, 0x00000000 },
-       { 0x000bb4,   1, 0x04, 0x00000000 },
-       { 0x000bd4,   1, 0x04, 0x00000000 },
-       { 0x000bf4,   1, 0x04, 0x00000000 },
-       { 0x000c00,   1, 0x04, 0x00000000 },
-       { 0x000c10,   1, 0x04, 0x00000000 },
-       { 0x000c20,   1, 0x04, 0x00000000 },
-       { 0x000c30,   1, 0x04, 0x00000000 },
-       { 0x000c40,   1, 0x04, 0x00000000 },
-       { 0x000c50,   1, 0x04, 0x00000000 },
-       { 0x000c60,   1, 0x04, 0x00000000 },
-       { 0x000c70,   1, 0x04, 0x00000000 },
-       { 0x000c80,   1, 0x04, 0x00000000 },
-       { 0x000c90,   1, 0x04, 0x00000000 },
-       { 0x000ca0,   1, 0x04, 0x00000000 },
-       { 0x000cb0,   1, 0x04, 0x00000000 },
-       { 0x000cc0,   1, 0x04, 0x00000000 },
-       { 0x000cd0,   1, 0x04, 0x00000000 },
-       { 0x000ce0,   1, 0x04, 0x00000000 },
-       { 0x000cf0,   1, 0x04, 0x00000000 },
-       { 0x000c04,   1, 0x04, 0x00000000 },
-       { 0x000c14,   1, 0x04, 0x00000000 },
-       { 0x000c24,   1, 0x04, 0x00000000 },
-       { 0x000c34,   1, 0x04, 0x00000000 },
-       { 0x000c44,   1, 0x04, 0x00000000 },
-       { 0x000c54,   1, 0x04, 0x00000000 },
-       { 0x000c64,   1, 0x04, 0x00000000 },
-       { 0x000c74,   1, 0x04, 0x00000000 },
-       { 0x000c84,   1, 0x04, 0x00000000 },
-       { 0x000c94,   1, 0x04, 0x00000000 },
-       { 0x000ca4,   1, 0x04, 0x00000000 },
-       { 0x000cb4,   1, 0x04, 0x00000000 },
-       { 0x000cc4,   1, 0x04, 0x00000000 },
-       { 0x000cd4,   1, 0x04, 0x00000000 },
-       { 0x000ce4,   1, 0x04, 0x00000000 },
-       { 0x000cf4,   1, 0x04, 0x00000000 },
-       { 0x000c08,   1, 0x04, 0x00000000 },
-       { 0x000c18,   1, 0x04, 0x00000000 },
-       { 0x000c28,   1, 0x04, 0x00000000 },
-       { 0x000c38,   1, 0x04, 0x00000000 },
-       { 0x000c48,   1, 0x04, 0x00000000 },
-       { 0x000c58,   1, 0x04, 0x00000000 },
-       { 0x000c68,   1, 0x04, 0x00000000 },
-       { 0x000c78,   1, 0x04, 0x00000000 },
-       { 0x000c88,   1, 0x04, 0x00000000 },
-       { 0x000c98,   1, 0x04, 0x00000000 },
-       { 0x000ca8,   1, 0x04, 0x00000000 },
-       { 0x000cb8,   1, 0x04, 0x00000000 },
-       { 0x000cc8,   1, 0x04, 0x00000000 },
-       { 0x000cd8,   1, 0x04, 0x00000000 },
-       { 0x000ce8,   1, 0x04, 0x00000000 },
-       { 0x000cf8,   1, 0x04, 0x00000000 },
-       { 0x000c0c,   1, 0x04, 0x3f800000 },
-       { 0x000c1c,   1, 0x04, 0x3f800000 },
-       { 0x000c2c,   1, 0x04, 0x3f800000 },
-       { 0x000c3c,   1, 0x04, 0x3f800000 },
-       { 0x000c4c,   1, 0x04, 0x3f800000 },
-       { 0x000c5c,   1, 0x04, 0x3f800000 },
-       { 0x000c6c,   1, 0x04, 0x3f800000 },
-       { 0x000c7c,   1, 0x04, 0x3f800000 },
-       { 0x000c8c,   1, 0x04, 0x3f800000 },
-       { 0x000c9c,   1, 0x04, 0x3f800000 },
-       { 0x000cac,   1, 0x04, 0x3f800000 },
-       { 0x000cbc,   1, 0x04, 0x3f800000 },
-       { 0x000ccc,   1, 0x04, 0x3f800000 },
-       { 0x000cdc,   1, 0x04, 0x3f800000 },
-       { 0x000cec,   1, 0x04, 0x3f800000 },
-       { 0x000cfc,   1, 0x04, 0x3f800000 },
-       { 0x000d00,   1, 0x04, 0xffff0000 },
-       { 0x000d08,   1, 0x04, 0xffff0000 },
-       { 0x000d10,   1, 0x04, 0xffff0000 },
-       { 0x000d18,   1, 0x04, 0xffff0000 },
-       { 0x000d20,   1, 0x04, 0xffff0000 },
-       { 0x000d28,   1, 0x04, 0xffff0000 },
-       { 0x000d30,   1, 0x04, 0xffff0000 },
-       { 0x000d38,   1, 0x04, 0xffff0000 },
-       { 0x000d04,   1, 0x04, 0xffff0000 },
-       { 0x000d0c,   1, 0x04, 0xffff0000 },
-       { 0x000d14,   1, 0x04, 0xffff0000 },
-       { 0x000d1c,   1, 0x04, 0xffff0000 },
-       { 0x000d24,   1, 0x04, 0xffff0000 },
-       { 0x000d2c,   1, 0x04, 0xffff0000 },
-       { 0x000d34,   1, 0x04, 0xffff0000 },
-       { 0x000d3c,   1, 0x04, 0xffff0000 },
-       { 0x000e00,   1, 0x04, 0x00000000 },
-       { 0x000e10,   1, 0x04, 0x00000000 },
-       { 0x000e20,   1, 0x04, 0x00000000 },
-       { 0x000e30,   1, 0x04, 0x00000000 },
-       { 0x000e40,   1, 0x04, 0x00000000 },
-       { 0x000e50,   1, 0x04, 0x00000000 },
-       { 0x000e60,   1, 0x04, 0x00000000 },
-       { 0x000e70,   1, 0x04, 0x00000000 },
-       { 0x000e80,   1, 0x04, 0x00000000 },
-       { 0x000e90,   1, 0x04, 0x00000000 },
-       { 0x000ea0,   1, 0x04, 0x00000000 },
-       { 0x000eb0,   1, 0x04, 0x00000000 },
-       { 0x000ec0,   1, 0x04, 0x00000000 },
-       { 0x000ed0,   1, 0x04, 0x00000000 },
-       { 0x000ee0,   1, 0x04, 0x00000000 },
-       { 0x000ef0,   1, 0x04, 0x00000000 },
-       { 0x000e04,   1, 0x04, 0xffff0000 },
-       { 0x000e14,   1, 0x04, 0xffff0000 },
-       { 0x000e24,   1, 0x04, 0xffff0000 },
-       { 0x000e34,   1, 0x04, 0xffff0000 },
-       { 0x000e44,   1, 0x04, 0xffff0000 },
-       { 0x000e54,   1, 0x04, 0xffff0000 },
-       { 0x000e64,   1, 0x04, 0xffff0000 },
-       { 0x000e74,   1, 0x04, 0xffff0000 },
-       { 0x000e84,   1, 0x04, 0xffff0000 },
-       { 0x000e94,   1, 0x04, 0xffff0000 },
-       { 0x000ea4,   1, 0x04, 0xffff0000 },
-       { 0x000eb4,   1, 0x04, 0xffff0000 },
-       { 0x000ec4,   1, 0x04, 0xffff0000 },
-       { 0x000ed4,   1, 0x04, 0xffff0000 },
-       { 0x000ee4,   1, 0x04, 0xffff0000 },
-       { 0x000ef4,   1, 0x04, 0xffff0000 },
-       { 0x000e08,   1, 0x04, 0xffff0000 },
-       { 0x000e18,   1, 0x04, 0xffff0000 },
-       { 0x000e28,   1, 0x04, 0xffff0000 },
-       { 0x000e38,   1, 0x04, 0xffff0000 },
-       { 0x000e48,   1, 0x04, 0xffff0000 },
-       { 0x000e58,   1, 0x04, 0xffff0000 },
-       { 0x000e68,   1, 0x04, 0xffff0000 },
-       { 0x000e78,   1, 0x04, 0xffff0000 },
-       { 0x000e88,   1, 0x04, 0xffff0000 },
-       { 0x000e98,   1, 0x04, 0xffff0000 },
-       { 0x000ea8,   1, 0x04, 0xffff0000 },
-       { 0x000eb8,   1, 0x04, 0xffff0000 },
-       { 0x000ec8,   1, 0x04, 0xffff0000 },
-       { 0x000ed8,   1, 0x04, 0xffff0000 },
-       { 0x000ee8,   1, 0x04, 0xffff0000 },
-       { 0x000ef8,   1, 0x04, 0xffff0000 },
-       { 0x000d40,   1, 0x04, 0x00000000 },
-       { 0x000d48,   1, 0x04, 0x00000000 },
-       { 0x000d50,   1, 0x04, 0x00000000 },
-       { 0x000d58,   1, 0x04, 0x00000000 },
-       { 0x000d44,   1, 0x04, 0x00000000 },
-       { 0x000d4c,   1, 0x04, 0x00000000 },
-       { 0x000d54,   1, 0x04, 0x00000000 },
-       { 0x000d5c,   1, 0x04, 0x00000000 },
-       { 0x001e00,   1, 0x04, 0x00000001 },
-       { 0x001e20,   1, 0x04, 0x00000001 },
-       { 0x001e40,   1, 0x04, 0x00000001 },
-       { 0x001e60,   1, 0x04, 0x00000001 },
-       { 0x001e80,   1, 0x04, 0x00000001 },
-       { 0x001ea0,   1, 0x04, 0x00000001 },
-       { 0x001ec0,   1, 0x04, 0x00000001 },
-       { 0x001ee0,   1, 0x04, 0x00000001 },
-       { 0x001e04,   1, 0x04, 0x00000001 },
-       { 0x001e24,   1, 0x04, 0x00000001 },
-       { 0x001e44,   1, 0x04, 0x00000001 },
-       { 0x001e64,   1, 0x04, 0x00000001 },
-       { 0x001e84,   1, 0x04, 0x00000001 },
-       { 0x001ea4,   1, 0x04, 0x00000001 },
-       { 0x001ec4,   1, 0x04, 0x00000001 },
-       { 0x001ee4,   1, 0x04, 0x00000001 },
-       { 0x001e08,   1, 0x04, 0x00000002 },
-       { 0x001e28,   1, 0x04, 0x00000002 },
-       { 0x001e48,   1, 0x04, 0x00000002 },
-       { 0x001e68,   1, 0x04, 0x00000002 },
-       { 0x001e88,   1, 0x04, 0x00000002 },
-       { 0x001ea8,   1, 0x04, 0x00000002 },
-       { 0x001ec8,   1, 0x04, 0x00000002 },
-       { 0x001ee8,   1, 0x04, 0x00000002 },
-       { 0x001e0c,   1, 0x04, 0x00000001 },
-       { 0x001e2c,   1, 0x04, 0x00000001 },
-       { 0x001e4c,   1, 0x04, 0x00000001 },
-       { 0x001e6c,   1, 0x04, 0x00000001 },
-       { 0x001e8c,   1, 0x04, 0x00000001 },
-       { 0x001eac,   1, 0x04, 0x00000001 },
-       { 0x001ecc,   1, 0x04, 0x00000001 },
-       { 0x001eec,   1, 0x04, 0x00000001 },
-       { 0x001e10,   1, 0x04, 0x00000001 },
-       { 0x001e30,   1, 0x04, 0x00000001 },
-       { 0x001e50,   1, 0x04, 0x00000001 },
-       { 0x001e70,   1, 0x04, 0x00000001 },
-       { 0x001e90,   1, 0x04, 0x00000001 },
-       { 0x001eb0,   1, 0x04, 0x00000001 },
-       { 0x001ed0,   1, 0x04, 0x00000001 },
-       { 0x001ef0,   1, 0x04, 0x00000001 },
-       { 0x001e14,   1, 0x04, 0x00000002 },
-       { 0x001e34,   1, 0x04, 0x00000002 },
-       { 0x001e54,   1, 0x04, 0x00000002 },
-       { 0x001e74,   1, 0x04, 0x00000002 },
-       { 0x001e94,   1, 0x04, 0x00000002 },
-       { 0x001eb4,   1, 0x04, 0x00000002 },
-       { 0x001ed4,   1, 0x04, 0x00000002 },
-       { 0x001ef4,   1, 0x04, 0x00000002 },
-       { 0x001e18,   1, 0x04, 0x00000001 },
-       { 0x001e38,   1, 0x04, 0x00000001 },
-       { 0x001e58,   1, 0x04, 0x00000001 },
-       { 0x001e78,   1, 0x04, 0x00000001 },
-       { 0x001e98,   1, 0x04, 0x00000001 },
-       { 0x001eb8,   1, 0x04, 0x00000001 },
-       { 0x001ed8,   1, 0x04, 0x00000001 },
-       { 0x001ef8,   1, 0x04, 0x00000001 },
-       { 0x003400, 128, 0x04, 0x00000000 },
-       { 0x00030c,   1, 0x04, 0x00000001 },
-       { 0x001944,   1, 0x04, 0x00000000 },
-       { 0x001514,   1, 0x04, 0x00000000 },
-       { 0x000d68,   1, 0x04, 0x0000ffff },
-       { 0x00121c,   1, 0x04, 0x0fac6881 },
-       { 0x000fac,   1, 0x04, 0x00000001 },
-       { 0x001538,   1, 0x04, 0x00000001 },
-       { 0x000fe0,   2, 0x04, 0x00000000 },
-       { 0x000fe8,   1, 0x04, 0x00000014 },
-       { 0x000fec,   1, 0x04, 0x00000040 },
-       { 0x000ff0,   1, 0x04, 0x00000000 },
-       { 0x00179c,   1, 0x04, 0x00000000 },
-       { 0x001228,   1, 0x04, 0x00000400 },
-       { 0x00122c,   1, 0x04, 0x00000300 },
-       { 0x001230,   1, 0x04, 0x00010001 },
-       { 0x0007f8,   1, 0x04, 0x00000000 },
-       { 0x0015b4,   1, 0x04, 0x00000001 },
-       { 0x0015cc,   1, 0x04, 0x00000000 },
-       { 0x001534,   1, 0x04, 0x00000000 },
-       { 0x000fb0,   1, 0x04, 0x00000000 },
-       { 0x0015d0,   1, 0x04, 0x00000000 },
-       { 0x00153c,   1, 0x04, 0x00000000 },
-       { 0x0016b4,   1, 0x04, 0x00000003 },
-       { 0x000fbc,   4, 0x04, 0x0000ffff },
-       { 0x000df8,   2, 0x04, 0x00000000 },
-       { 0x001948,   1, 0x04, 0x00000000 },
-       { 0x001970,   1, 0x04, 0x00000001 },
-       { 0x00161c,   1, 0x04, 0x000009f0 },
-       { 0x000dcc,   1, 0x04, 0x00000010 },
-       { 0x00163c,   1, 0x04, 0x00000000 },
-       { 0x0015e4,   1, 0x04, 0x00000000 },
-       { 0x001160,  32, 0x04, 0x25e00040 },
-       { 0x001880,  32, 0x04, 0x00000000 },
-       { 0x000f84,   2, 0x04, 0x00000000 },
-       { 0x0017c8,   2, 0x04, 0x00000000 },
-       { 0x0017d0,   1, 0x04, 0x000000ff },
-       { 0x0017d4,   1, 0x04, 0xffffffff },
-       { 0x0017d8,   1, 0x04, 0x00000002 },
-       { 0x0017dc,   1, 0x04, 0x00000000 },
-       { 0x0015f4,   2, 0x04, 0x00000000 },
-       { 0x001434,   2, 0x04, 0x00000000 },
-       { 0x000d74,   1, 0x04, 0x00000000 },
-       { 0x000dec,   1, 0x04, 0x00000001 },
-       { 0x0013a4,   1, 0x04, 0x00000000 },
-       { 0x001318,   1, 0x04, 0x00000001 },
-       { 0x001644,   1, 0x04, 0x00000000 },
-       { 0x000748,   1, 0x04, 0x00000000 },
-       { 0x000de8,   1, 0x04, 0x00000000 },
-       { 0x001648,   1, 0x04, 0x00000000 },
-       { 0x0012a4,   1, 0x04, 0x00000000 },
-       { 0x001120,   4, 0x04, 0x00000000 },
-       { 0x001118,   1, 0x04, 0x00000000 },
-       { 0x00164c,   1, 0x04, 0x00000000 },
-       { 0x001658,   1, 0x04, 0x00000000 },
-       { 0x001910,   1, 0x04, 0x00000290 },
-       { 0x001518,   1, 0x04, 0x00000000 },
-       { 0x00165c,   1, 0x04, 0x00000001 },
-       { 0x001520,   1, 0x04, 0x00000000 },
-       { 0x001604,   1, 0x04, 0x00000000 },
-       { 0x001570,   1, 0x04, 0x00000000 },
-       { 0x0013b0,   2, 0x04, 0x3f800000 },
-       { 0x00020c,   1, 0x04, 0x00000000 },
-       { 0x001670,   1, 0x04, 0x30201000 },
-       { 0x001674,   1, 0x04, 0x70605040 },
-       { 0x001678,   1, 0x04, 0xb8a89888 },
-       { 0x00167c,   1, 0x04, 0xf8e8d8c8 },
-       { 0x00166c,   1, 0x04, 0x00000000 },
-       { 0x001680,   1, 0x04, 0x00ffff00 },
-       { 0x0012d0,   1, 0x04, 0x00000003 },
-       { 0x0012d4,   1, 0x04, 0x00000002 },
-       { 0x001684,   2, 0x04, 0x00000000 },
-       { 0x000dac,   2, 0x04, 0x00001b02 },
-       { 0x000db4,   1, 0x04, 0x00000000 },
-       { 0x00168c,   1, 0x04, 0x00000000 },
-       { 0x0015bc,   1, 0x04, 0x00000000 },
-       { 0x00156c,   1, 0x04, 0x00000000 },
-       { 0x00187c,   1, 0x04, 0x00000000 },
-       { 0x001110,   1, 0x04, 0x00000001 },
-       { 0x000dc0,   3, 0x04, 0x00000000 },
-       { 0x001234,   1, 0x04, 0x00000000 },
-       { 0x001690,   1, 0x04, 0x00000000 },
-       { 0x0012ac,   1, 0x04, 0x00000001 },
-       { 0x0002c4,   1, 0x04, 0x00000000 },
-       { 0x000790,   5, 0x04, 0x00000000 },
-       { 0x00077c,   1, 0x04, 0x00000000 },
-       { 0x001000,   1, 0x04, 0x00000010 },
-       { 0x0010fc,   1, 0x04, 0x00000000 },
-       { 0x001290,   1, 0x04, 0x00000000 },
-       { 0x000218,   1, 0x04, 0x00000010 },
-       { 0x0012d8,   1, 0x04, 0x00000000 },
-       { 0x0012dc,   1, 0x04, 0x00000010 },
-       { 0x000d94,   1, 0x04, 0x00000001 },
-       { 0x00155c,   2, 0x04, 0x00000000 },
-       { 0x001564,   1, 0x04, 0x00000fff },
-       { 0x001574,   2, 0x04, 0x00000000 },
-       { 0x00157c,   1, 0x04, 0x000fffff },
-       { 0x001354,   1, 0x04, 0x00000000 },
-       { 0x001610,   1, 0x04, 0x00000012 },
-       { 0x001608,   2, 0x04, 0x00000000 },
-       { 0x00260c,   1, 0x04, 0x00000000 },
-       { 0x0007ac,   1, 0x04, 0x00000000 },
-       { 0x00162c,   1, 0x04, 0x00000003 },
-       { 0x000210,   1, 0x04, 0x00000000 },
-       { 0x000320,   1, 0x04, 0x00000000 },
-       { 0x000324,   6, 0x04, 0x3f800000 },
-       { 0x000750,   1, 0x04, 0x00000000 },
-       { 0x000760,   1, 0x04, 0x39291909 },
-       { 0x000764,   1, 0x04, 0x79695949 },
-       { 0x000768,   1, 0x04, 0xb9a99989 },
-       { 0x00076c,   1, 0x04, 0xf9e9d9c9 },
-       { 0x000770,   1, 0x04, 0x30201000 },
-       { 0x000774,   1, 0x04, 0x70605040 },
-       { 0x000778,   1, 0x04, 0x00009080 },
-       { 0x000780,   1, 0x04, 0x39291909 },
-       { 0x000784,   1, 0x04, 0x79695949 },
-       { 0x000788,   1, 0x04, 0xb9a99989 },
-       { 0x00078c,   1, 0x04, 0xf9e9d9c9 },
-       { 0x0007d0,   1, 0x04, 0x30201000 },
-       { 0x0007d4,   1, 0x04, 0x70605040 },
-       { 0x0007d8,   1, 0x04, 0x00009080 },
-       { 0x00037c,   1, 0x04, 0x00000001 },
-       { 0x000740,   2, 0x04, 0x00000000 },
-       { 0x002600,   1, 0x04, 0x00000000 },
-       { 0x001918,   1, 0x04, 0x00000000 },
-       { 0x00191c,   1, 0x04, 0x00000900 },
-       { 0x001920,   1, 0x04, 0x00000405 },
-       { 0x001308,   1, 0x04, 0x00000001 },
-       { 0x001924,   1, 0x04, 0x00000000 },
-       { 0x0013ac,   1, 0x04, 0x00000000 },
-       { 0x00192c,   1, 0x04, 0x00000001 },
-       { 0x00193c,   1, 0x04, 0x00002c1c },
-       { 0x000d7c,   1, 0x04, 0x00000000 },
-       { 0x000f8c,   1, 0x04, 0x00000000 },
-       { 0x0002c0,   1, 0x04, 0x00000001 },
-       { 0x001510,   1, 0x04, 0x00000000 },
-       { 0x001940,   1, 0x04, 0x00000000 },
-       { 0x000ff4,   2, 0x04, 0x00000000 },
-       { 0x00194c,   2, 0x04, 0x00000000 },
-       { 0x001968,   1, 0x04, 0x00000000 },
-       { 0x001590,   1, 0x04, 0x0000003f },
-       { 0x0007e8,   4, 0x04, 0x00000000 },
-       { 0x00196c,   1, 0x04, 0x00000011 },
-       { 0x0002e4,   1, 0x04, 0x0000b001 },
-       { 0x00036c,   2, 0x04, 0x00000000 },
-       { 0x00197c,   1, 0x04, 0x00000000 },
-       { 0x000fcc,   2, 0x04, 0x00000000 },
-       { 0x0002d8,   1, 0x04, 0x00000040 },
-       { 0x001980,   1, 0x04, 0x00000080 },
-       { 0x001504,   1, 0x04, 0x00000080 },
-       { 0x001984,   1, 0x04, 0x00000000 },
-       { 0x000300,   1, 0x04, 0x00000001 },
-       { 0x0013a8,   1, 0x04, 0x00000000 },
-       { 0x0012ec,   1, 0x04, 0x00000000 },
-       { 0x001310,   1, 0x04, 0x00000000 },
-       { 0x001314,   1, 0x04, 0x00000001 },
-       { 0x001380,   1, 0x04, 0x00000000 },
-       { 0x001384,   4, 0x04, 0x00000001 },
-       { 0x001394,   1, 0x04, 0x00000000 },
-       { 0x00139c,   1, 0x04, 0x00000000 },
-       { 0x001398,   1, 0x04, 0x00000000 },
-       { 0x001594,   1, 0x04, 0x00000000 },
-       { 0x001598,   4, 0x04, 0x00000001 },
-       { 0x000f54,   3, 0x04, 0x00000000 },
-       { 0x0019bc,   1, 0x04, 0x00000000 },
-       { 0x000f9c,   2, 0x04, 0x00000000 },
-       { 0x0012cc,   1, 0x04, 0x00000000 },
-       { 0x0012e8,   1, 0x04, 0x00000000 },
-       { 0x00130c,   1, 0x04, 0x00000001 },
-       { 0x001360,   8, 0x04, 0x00000000 },
-       { 0x00133c,   2, 0x04, 0x00000001 },
-       { 0x001344,   1, 0x04, 0x00000002 },
-       { 0x001348,   2, 0x04, 0x00000001 },
-       { 0x001350,   1, 0x04, 0x00000002 },
-       { 0x001358,   1, 0x04, 0x00000001 },
-       { 0x0012e4,   1, 0x04, 0x00000000 },
-       { 0x00131c,   4, 0x04, 0x00000000 },
-       { 0x0019c0,   1, 0x04, 0x00000000 },
-       { 0x001140,   1, 0x04, 0x00000000 },
-       { 0x0019c4,   1, 0x04, 0x00000000 },
-       { 0x0019c8,   1, 0x04, 0x00001500 },
-       { 0x00135c,   1, 0x04, 0x00000000 },
-       { 0x000f90,   1, 0x04, 0x00000000 },
-       { 0x0019e0,   8, 0x04, 0x00000001 },
-       { 0x0019cc,   1, 0x04, 0x00000001 },
-       { 0x0015b8,   1, 0x04, 0x00000000 },
-       { 0x001a00,   1, 0x04, 0x00001111 },
-       { 0x001a04,   7, 0x04, 0x00000000 },
-       { 0x000d6c,   2, 0x04, 0xffff0000 },
-       { 0x0010f8,   1, 0x04, 0x00001010 },
-       { 0x000d80,   5, 0x04, 0x00000000 },
-       { 0x000da0,   1, 0x04, 0x00000000 },
-       { 0x0007a4,   2, 0x04, 0x00000000 },
-       { 0x001508,   1, 0x04, 0x80000000 },
-       { 0x00150c,   1, 0x04, 0x40000000 },
-       { 0x001668,   1, 0x04, 0x00000000 },
-       { 0x000318,   2, 0x04, 0x00000008 },
-       { 0x000d9c,   1, 0x04, 0x00000001 },
-       { 0x000ddc,   1, 0x04, 0x00000002 },
-       { 0x000374,   1, 0x04, 0x00000000 },
-       { 0x000378,   1, 0x04, 0x00000020 },
-       { 0x0007dc,   1, 0x04, 0x00000000 },
-       { 0x00074c,   1, 0x04, 0x00000055 },
-       { 0x001420,   1, 0x04, 0x00000003 },
-       { 0x0017bc,   2, 0x04, 0x00000000 },
-       { 0x0017c4,   1, 0x04, 0x00000001 },
-       { 0x001008,   1, 0x04, 0x00000008 },
-       { 0x00100c,   1, 0x04, 0x00000040 },
-       { 0x001010,   1, 0x04, 0x0000012c },
-       { 0x000d60,   1, 0x04, 0x00000040 },
-       { 0x00075c,   1, 0x04, 0x00000003 },
-       { 0x001018,   1, 0x04, 0x00000020 },
-       { 0x00101c,   1, 0x04, 0x00000001 },
-       { 0x001020,   1, 0x04, 0x00000020 },
-       { 0x001024,   1, 0x04, 0x00000001 },
-       { 0x001444,   3, 0x04, 0x00000000 },
-       { 0x000360,   1, 0x04, 0x20164010 },
-       { 0x000364,   1, 0x04, 0x00000020 },
-       { 0x000368,   1, 0x04, 0x00000000 },
-       { 0x000de4,   1, 0x04, 0x00000000 },
-       { 0x000204,   1, 0x04, 0x00000006 },
-       { 0x000208,   1, 0x04, 0x00000000 },
-       { 0x0002cc,   2, 0x04, 0x003fffff },
-       { 0x001220,   1, 0x04, 0x00000005 },
-       { 0x000fdc,   1, 0x04, 0x00000000 },
-       { 0x000f98,   1, 0x04, 0x00400008 },
-       { 0x001284,   1, 0x04, 0x08000080 },
-       { 0x001450,   1, 0x04, 0x00400008 },
-       { 0x001454,   1, 0x04, 0x08000080 },
-       { 0x000214,   1, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nv108_grctx_pack_icmd[] = {
+       { nv108_grctx_init_icmd_0 },
        {}
 };
 
-static struct nvc0_graph_init
-nv108_grctx_init_unk40xx[] = {
+static const struct nvc0_graph_init
+nv108_grctx_init_fe_0[] = {
        { 0x404004,   8, 0x04, 0x00000000 },
        { 0x404024,   1, 0x04, 0x0000e000 },
        { 0x404028,   8, 0x04, 0x00000000 },
@@ -1132,8 +311,8 @@ nv108_grctx_init_unk40xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nv108_grctx_init_unk58xx[] = {
+static const struct nvc0_graph_init
+nv108_grctx_init_ds_0[] = {
        { 0x405800,   1, 0x04, 0x0f8000bf },
        { 0x405830,   1, 0x04, 0x02180648 },
        { 0x405834,   1, 0x04, 0x08000000 },
@@ -1146,8 +325,10 @@ nv108_grctx_init_unk58xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nv108_grctx_init_unk64xx[] = {
+static const struct nvc0_graph_init
+nv108_grctx_init_pd_0[] = {
+       { 0x406020,   1, 0x04, 0x034103c1 },
+       { 0x406028,   4, 0x04, 0x00000001 },
        { 0x4064a8,   1, 0x04, 0x00000000 },
        { 0x4064ac,   1, 0x04, 0x00003fff },
        { 0x4064b0,   3, 0x04, 0x00000000 },
@@ -1159,8 +340,8 @@ nv108_grctx_init_unk64xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nv108_grctx_init_unk78xx[] = {
+const struct nvc0_graph_init
+nv108_grctx_init_rstr2d_0[] = {
        { 0x407804,   1, 0x04, 0x00000063 },
        { 0x40780c,   1, 0x04, 0x0a418820 },
        { 0x407810,   1, 0x04, 0x062080e6 },
@@ -1172,8 +353,8 @@ nv108_grctx_init_unk78xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nv108_grctx_init_unk88xx[] = {
+static const struct nvc0_graph_init
+nv108_grctx_init_be_0[] = {
        { 0x408800,   1, 0x04, 0x32802a3c },
        { 0x408804,   1, 0x04, 0x00000040 },
        { 0x408808,   1, 0x04, 0x1003e005 },
@@ -1185,9 +366,23 @@ nv108_grctx_init_unk88xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nv108_grctx_init_gpc_0[] = {
-       { 0x418380,   1, 0x04, 0x00000016 },
+static const struct nvc0_graph_pack
+nv108_grctx_pack_hub[] = {
+       { nvc0_grctx_init_main_0 },
+       { nv108_grctx_init_fe_0 },
+       { nvf0_grctx_init_pri_0 },
+       { nve4_grctx_init_memfmt_0 },
+       { nv108_grctx_init_ds_0 },
+       { nvf0_grctx_init_cwd_0 },
+       { nv108_grctx_init_pd_0 },
+       { nv108_grctx_init_rstr2d_0 },
+       { nve4_grctx_init_scc_0 },
+       { nv108_grctx_init_be_0 },
+       {}
+};
+
+const struct nvc0_graph_init
+nv108_grctx_init_prop_0[] = {
        { 0x418400,   1, 0x04, 0x38005e00 },
        { 0x418404,   1, 0x04, 0x71e0ffff },
        { 0x41840c,   1, 0x04, 0x00001008 },
@@ -1196,11 +391,21 @@ nv108_grctx_init_gpc_0[] = {
        { 0x418450,   6, 0x04, 0x00000000 },
        { 0x418468,   1, 0x04, 0x00000001 },
        { 0x41846c,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nv108_grctx_init_gpc_unk_1[] = {
        { 0x418600,   1, 0x04, 0x0000007f },
        { 0x418684,   1, 0x04, 0x0000001f },
        { 0x418700,   1, 0x04, 0x00000002 },
        { 0x418704,   2, 0x04, 0x00000080 },
        { 0x41870c,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nv108_grctx_init_setup_0[] = {
        { 0x418800,   1, 0x04, 0x7006863a },
        { 0x418808,   1, 0x04, 0x00000000 },
        { 0x41880c,   1, 0x04, 0x00000030 },
@@ -1211,10 +416,11 @@ nv108_grctx_init_gpc_0[] = {
        { 0x4188e0,   1, 0x04, 0x01000000 },
        { 0x4188e8,   5, 0x04, 0x00000000 },
        { 0x4188fc,   1, 0x04, 0x20100058 },
-       { 0x41891c,   1, 0x04, 0x00ff00ff },
-       { 0x418924,   1, 0x04, 0x00000000 },
-       { 0x418928,   1, 0x04, 0x00ffff00 },
-       { 0x41892c,   1, 0x04, 0x0000ff00 },
+       {}
+};
+
+const struct nvc0_graph_init
+nv108_grctx_init_crstr_0[] = {
        { 0x418b00,   1, 0x04, 0x0000001e },
        { 0x418b08,   1, 0x04, 0x0a418820 },
        { 0x418b0c,   1, 0x04, 0x062080e6 },
@@ -1223,24 +429,36 @@ nv108_grctx_init_gpc_0[] = {
        { 0x418b18,   1, 0x04, 0x0a418820 },
        { 0x418b1c,   1, 0x04, 0x000000e6 },
        { 0x418bb8,   1, 0x04, 0x00000103 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nv108_grctx_init_gpm_0[] = {
        { 0x418c08,   1, 0x04, 0x00000001 },
        { 0x418c10,   8, 0x04, 0x00000000 },
        { 0x418c40,   1, 0x04, 0xffffffff },
        { 0x418c6c,   1, 0x04, 0x00000001 },
        { 0x418c80,   1, 0x04, 0x2020000c },
        { 0x418c8c,   1, 0x04, 0x00000001 },
-       { 0x418d24,   1, 0x04, 0x00000000 },
-       { 0x419000,   1, 0x04, 0x00000780 },
-       { 0x419004,   2, 0x04, 0x00000000 },
-       { 0x419014,   1, 0x04, 0x00000004 },
        {}
 };
 
-static struct nvc0_graph_init
-nv108_grctx_init_tpc[] = {
-       { 0x419848,   1, 0x04, 0x00000000 },
-       { 0x419864,   1, 0x04, 0x00000129 },
-       { 0x419888,   1, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nv108_grctx_pack_gpc[] = {
+       { nvc0_grctx_init_gpc_unk_0 },
+       { nv108_grctx_init_prop_0 },
+       { nv108_grctx_init_gpc_unk_1 },
+       { nv108_grctx_init_setup_0 },
+       { nvc0_grctx_init_zcull_0 },
+       { nv108_grctx_init_crstr_0 },
+       { nv108_grctx_init_gpm_0 },
+       { nvf0_grctx_init_gpc_unk_2 },
+       { nvc0_grctx_init_gcc_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nv108_grctx_init_tex_0[] = {
        { 0x419a00,   1, 0x04, 0x000100f0 },
        { 0x419a04,   1, 0x04, 0x00000001 },
        { 0x419a08,   1, 0x04, 0x00000421 },
@@ -1251,14 +469,11 @@ nv108_grctx_init_tpc[] = {
        { 0x419a20,   1, 0x04, 0x00000800 },
        { 0x419a30,   1, 0x04, 0x00000001 },
        { 0x419ac4,   1, 0x04, 0x0037f440 },
-       { 0x419c00,   1, 0x04, 0x0000001a },
-       { 0x419c04,   1, 0x04, 0x80000006 },
-       { 0x419c08,   1, 0x04, 0x00000002 },
-       { 0x419c20,   1, 0x04, 0x00000000 },
-       { 0x419c24,   1, 0x04, 0x00084210 },
-       { 0x419c28,   1, 0x04, 0x3efbefbe },
-       { 0x419ce8,   1, 0x04, 0x00000000 },
-       { 0x419cf4,   1, 0x04, 0x00000203 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nv108_grctx_init_sm_0[] = {
        { 0x419e04,   1, 0x04, 0x00000000 },
        { 0x419e08,   1, 0x04, 0x0000001d },
        { 0x419e0c,   1, 0x04, 0x00000000 },
@@ -1272,7 +487,7 @@ nv108_grctx_init_tpc[] = {
        { 0x419e68,   1, 0x04, 0x00000002 },
        { 0x419e6c,  12, 0x04, 0x00000000 },
        { 0x419eac,   1, 0x04, 0x00001f8f },
-       { 0x419eb0,   1, 0x04, 0x0db00da0 },
+       { 0x419eb0,   1, 0x04, 0x0db00d2f },
        { 0x419eb8,   1, 0x04, 0x00000000 },
        { 0x419ec8,   1, 0x04, 0x0001304f },
        { 0x419f30,   4, 0x04, 0x00000000 },
@@ -1285,25 +500,37 @@ nv108_grctx_init_tpc[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nv108_grctx_init_unk[] = {
-       { 0x41be24,   1, 0x04, 0x00000006 },
+static const struct nvc0_graph_pack
+nv108_grctx_pack_tpc[] = {
+       { nvd7_grctx_init_pe_0 },
+       { nv108_grctx_init_tex_0 },
+       { nvf0_grctx_init_mpc_0 },
+       { nvf0_grctx_init_l1c_0 },
+       { nv108_grctx_init_sm_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nv108_grctx_init_cbm_0[] = {
        { 0x41bec0,   1, 0x04, 0x10000000 },
        { 0x41bec4,   1, 0x04, 0x00037f7f },
        { 0x41bee4,   1, 0x04, 0x00000000 },
        { 0x41bef0,   1, 0x04, 0x000003ff },
-       { 0x41bf00,   1, 0x04, 0x0a418820 },
-       { 0x41bf04,   1, 0x04, 0x062080e6 },
-       { 0x41bf08,   1, 0x04, 0x020398a4 },
-       { 0x41bf0c,   1, 0x04, 0x0e629062 },
-       { 0x41bf10,   1, 0x04, 0x0a418820 },
-       { 0x41bf14,   1, 0x04, 0x000000e6 },
-       { 0x41bfd0,   1, 0x04, 0x00900103 },
-       { 0x41bfe0,   1, 0x04, 0x00400001 },
-       { 0x41bfe4,   1, 0x04, 0x00000000 },
        {}
 };
 
+static const struct nvc0_graph_pack
+nv108_grctx_pack_ppc[] = {
+       { nve4_grctx_init_pes_0 },
+       { nv108_grctx_init_cbm_0 },
+       { nvd7_grctx_init_wwdx_0 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
 static void
 nv108_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
@@ -1346,47 +573,6 @@ nv108_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
        mmio_list(0x17e920, 0x00090d08, 0, 0);
 }
 
-static struct nvc0_graph_init *
-nv108_grctx_init_hub[] = {
-       nvc0_grctx_init_base,
-       nv108_grctx_init_unk40xx,
-       nvf0_grctx_init_unk44xx,
-       nve4_grctx_init_unk46xx,
-       nve4_grctx_init_unk47xx,
-       nv108_grctx_init_unk58xx,
-       nvf0_grctx_init_unk5bxx,
-       nvf0_grctx_init_unk60xx,
-       nv108_grctx_init_unk64xx,
-       nv108_grctx_init_unk78xx,
-       nve4_grctx_init_unk80xx,
-       nv108_grctx_init_unk88xx,
-       NULL
-};
-
-struct nvc0_graph_init *
-nv108_grctx_init_gpc[] = {
-       nv108_grctx_init_gpc_0,
-       nvc0_grctx_init_gpc_1,
-       nv108_grctx_init_tpc,
-       nv108_grctx_init_unk,
-       NULL
-};
-
-struct nvc0_graph_init
-nv108_grctx_init_mthd_magic[] = {
-       { 0x3410, 1, 0x04, 0x8e0e2006 },
-       { 0x3414, 1, 0x04, 0x00000038 },
-       {}
-};
-
-static struct nvc0_graph_mthd
-nv108_grctx_init_mthd[] = {
-       { 0xa197, nv108_grctx_init_a197, },
-       { 0x902d, nvc0_grctx_init_902d, },
-       { 0x902d, nv108_grctx_init_mthd_magic, },
-       {}
-};
-
 struct nouveau_oclass *
 nv108_grctx_oclass = &(struct nvc0_grctx_oclass) {
        .base.handle = NV_ENGCTX(GR, 0x08),
@@ -1398,11 +584,14 @@ nv108_grctx_oclass = &(struct nvc0_grctx_oclass) {
                .rd32 = _nouveau_graph_context_rd32,
                .wr32 = _nouveau_graph_context_wr32,
        },
-       .main = nve4_grctx_generate_main,
-       .mods = nv108_grctx_generate_mods,
-       .unkn = nve4_grctx_generate_unkn,
-       .hub  = nv108_grctx_init_hub,
-       .gpc  = nv108_grctx_init_gpc,
-       .icmd = nv108_grctx_init_icmd,
-       .mthd = nv108_grctx_init_mthd,
+       .main  = nve4_grctx_generate_main,
+       .mods  = nv108_grctx_generate_mods,
+       .unkn  = nve4_grctx_generate_unkn,
+       .hub   = nv108_grctx_pack_hub,
+       .gpc   = nv108_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = nv108_grctx_pack_tpc,
+       .ppc   = nv108_grctx_pack_ppc,
+       .icmd  = nv108_grctx_pack_icmd,
+       .mthd  = nvf0_grctx_pack_mthd,
 }.base;
index fe67415..833a965 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include "nvc0.h"
+#include "ctxnvc0.h"
 
-struct nvc0_graph_init
-nvc0_grctx_init_icmd[] = {
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct nvc0_graph_init
+nvc0_grctx_init_icmd_0[] = {
        { 0x001000,   1, 0x01, 0x00000004 },
        { 0x0000a9,   1, 0x01, 0x0000ffff },
        { 0x000038,   1, 0x01, 0x0fac6881 },
@@ -140,8 +144,7 @@ nvc0_grctx_init_icmd[] = {
        { 0x000586,   1, 0x01, 0x00000040 },
        { 0x000582,   2, 0x01, 0x00000080 },
        { 0x0005c2,   1, 0x01, 0x00000001 },
-       { 0x000638,   1, 0x01, 0x00000001 },
-       { 0x000639,   1, 0x01, 0x00000001 },
+       { 0x000638,   2, 0x01, 0x00000001 },
        { 0x00063a,   1, 0x01, 0x00000002 },
        { 0x00063b,   2, 0x01, 0x00000001 },
        { 0x00063d,   1, 0x01, 0x00000002 },
@@ -201,15 +204,13 @@ nvc0_grctx_init_icmd[] = {
        { 0x000787,   1, 0x01, 0x000000cf },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x000836,   1, 0x01, 0x00000001 },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x00080c,   1, 0x01, 0x00000002 },
        { 0x00080d,   2, 0x01, 0x00000100 },
@@ -235,14 +236,12 @@ nvc0_grctx_init_icmd[] = {
        { 0x0006b1,   1, 0x01, 0x00000011 },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x01e100,   1, 0x01, 0x00000001 },
        { 0x001000,   1, 0x01, 0x00000014 },
@@ -267,8 +266,14 @@ nvc0_grctx_init_icmd[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_9097[] = {
+const struct nvc0_graph_pack
+nvc0_grctx_pack_icmd[] = {
+       { nvc0_grctx_init_icmd_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc0_grctx_init_9097_0[] = {
        { 0x000800,   8, 0x40, 0x00000000 },
        { 0x000804,   8, 0x40, 0x00000000 },
        { 0x000808,   8, 0x40, 0x00000400 },
@@ -516,8 +521,7 @@ nvc0_grctx_init_9097[] = {
        { 0x001350,   1, 0x04, 0x00000002 },
        { 0x001358,   1, 0x04, 0x00000001 },
        { 0x0012e4,   1, 0x04, 0x00000000 },
-       { 0x00131c,   1, 0x04, 0x00000000 },
-       { 0x001320,   3, 0x04, 0x00000000 },
+       { 0x00131c,   4, 0x04, 0x00000000 },
        { 0x0019c0,   1, 0x04, 0x00000000 },
        { 0x001140,   1, 0x04, 0x00000000 },
        { 0x0019c4,   1, 0x04, 0x00000000 },
@@ -571,8 +575,8 @@ nvc0_grctx_init_9097[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_902d[] = {
+const struct nvc0_graph_init
+nvc0_grctx_init_902d_0[] = {
        { 0x000200,   1, 0x04, 0x000000cf },
        { 0x000204,   1, 0x04, 0x00000001 },
        { 0x000208,   1, 0x04, 0x00000020 },
@@ -590,8 +594,8 @@ nvc0_grctx_init_902d[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_9039[] = {
+const struct nvc0_graph_init
+nvc0_grctx_init_9039_0[] = {
        { 0x00030c,   3, 0x04, 0x00000000 },
        { 0x000320,   1, 0x04, 0x00000000 },
        { 0x000238,   2, 0x04, 0x00000000 },
@@ -599,8 +603,8 @@ nvc0_grctx_init_9039[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_90c0[] = {
+const struct nvc0_graph_init
+nvc0_grctx_init_90c0_0[] = {
        { 0x00270c,   8, 0x20, 0x00000000 },
        { 0x00030c,   1, 0x04, 0x00000001 },
        { 0x001944,   1, 0x04, 0x00000000 },
@@ -617,38 +621,44 @@ nvc0_grctx_init_90c0[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_base[] = {
+const struct nvc0_graph_pack
+nvc0_grctx_pack_mthd[] = {
+       { nvc0_grctx_init_9097_0, 0x9097 },
+       { nvc0_grctx_init_902d_0, 0x902d },
+       { nvc0_grctx_init_9039_0, 0x9039 },
+       { nvc0_grctx_init_90c0_0, 0x90c0 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_main_0[] = {
        { 0x400204,   2, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_unk40xx[] = {
-       { 0x404004,  10, 0x04, 0x00000000 },
+const struct nvc0_graph_init
+nvc0_grctx_init_fe_0[] = {
+       { 0x404004,  11, 0x04, 0x00000000 },
        { 0x404044,   1, 0x04, 0x00000000 },
-       { 0x404094,   1, 0x04, 0x00000000 },
-       { 0x404098,  12, 0x04, 0x00000000 },
+       { 0x404094,  13, 0x04, 0x00000000 },
        { 0x4040c8,   1, 0x04, 0xf0000087 },
        { 0x4040d0,   6, 0x04, 0x00000000 },
        { 0x4040e8,   1, 0x04, 0x00001000 },
        { 0x4040f8,   1, 0x04, 0x00000000 },
-       { 0x404130,   1, 0x04, 0x00000000 },
-       { 0x404134,   1, 0x04, 0x00000000 },
+       { 0x404130,   2, 0x04, 0x00000000 },
        { 0x404138,   1, 0x04, 0x20000040 },
        { 0x404150,   1, 0x04, 0x0000002e },
        { 0x404154,   1, 0x04, 0x00000400 },
        { 0x404158,   1, 0x04, 0x00000200 },
        { 0x404164,   1, 0x04, 0x00000055 },
        { 0x404168,   1, 0x04, 0x00000000 },
-       { 0x404174,   1, 0x04, 0x00000000 },
-       { 0x404178,   2, 0x04, 0x00000000 },
+       { 0x404174,   3, 0x04, 0x00000000 },
        { 0x404200,   8, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_unk44xx[] = {
+const struct nvc0_graph_init
+nvc0_grctx_init_pri_0[] = {
        { 0x404404,  14, 0x04, 0x00000000 },
        { 0x404460,   2, 0x04, 0x00000000 },
        { 0x404468,   1, 0x04, 0x00ffffff },
@@ -658,8 +668,8 @@ nvc0_grctx_init_unk44xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_unk46xx[] = {
+const struct nvc0_graph_init
+nvc0_grctx_init_memfmt_0[] = {
        { 0x404604,   1, 0x04, 0x00000015 },
        { 0x404608,   1, 0x04, 0x00000000 },
        { 0x40460c,   1, 0x04, 0x00002e00 },
@@ -674,19 +684,14 @@ nvc0_grctx_init_unk46xx[] = {
        { 0x4046a0,   1, 0x04, 0x007f0080 },
        { 0x4046a4,  18, 0x04, 0x00000000 },
        { 0x4046f0,   2, 0x04, 0x00000000 },
-       {}
-};
-
-struct nvc0_graph_init
-nvc0_grctx_init_unk47xx[] = {
        { 0x404700,  13, 0x04, 0x00000000 },
        { 0x404734,   1, 0x04, 0x00000100 },
        { 0x404738,   8, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_unk58xx[] = {
+static const struct nvc0_graph_init
+nvc0_grctx_init_ds_0[] = {
        { 0x405800,   1, 0x04, 0x078000bf },
        { 0x405830,   1, 0x04, 0x02180000 },
        { 0x405834,   2, 0x04, 0x00000000 },
@@ -697,23 +702,18 @@ nvc0_grctx_init_unk58xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_unk60xx[] = {
+static const struct nvc0_graph_init
+nvc0_grctx_init_pd_0[] = {
        { 0x406020,   1, 0x04, 0x000103c1 },
        { 0x406028,   4, 0x04, 0x00000001 },
-       {}
-};
-
-struct nvc0_graph_init
-nvc0_grctx_init_unk64xx[] = {
        { 0x4064a8,   1, 0x04, 0x00000000 },
        { 0x4064ac,   1, 0x04, 0x00003fff },
        { 0x4064b4,   2, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_unk78xx[] = {
+const struct nvc0_graph_init
+nvc0_grctx_init_rstr2d_0[] = {
        { 0x407804,   1, 0x04, 0x00000023 },
        { 0x40780c,   1, 0x04, 0x0a418820 },
        { 0x407810,   1, 0x04, 0x062080e6 },
@@ -725,8 +725,8 @@ nvc0_grctx_init_unk78xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_unk80xx[] = {
+const struct nvc0_graph_init
+nvc0_grctx_init_scc_0[] = {
        { 0x408000,   2, 0x04, 0x00000000 },
        { 0x408008,   1, 0x04, 0x00000018 },
        { 0x40800c,   2, 0x04, 0x00000000 },
@@ -736,8 +736,8 @@ nvc0_grctx_init_unk80xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_rop[] = {
+static const struct nvc0_graph_init
+nvc0_grctx_init_be_0[] = {
        { 0x408800,   1, 0x04, 0x02802a3c },
        { 0x408804,   1, 0x04, 0x00000040 },
        { 0x408808,   1, 0x04, 0x0003e00d },
@@ -748,9 +748,28 @@ nvc0_grctx_init_rop[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_gpc_0[] = {
+const struct nvc0_graph_pack
+nvc0_grctx_pack_hub[] = {
+       { nvc0_grctx_init_main_0 },
+       { nvc0_grctx_init_fe_0 },
+       { nvc0_grctx_init_pri_0 },
+       { nvc0_grctx_init_memfmt_0 },
+       { nvc0_grctx_init_ds_0 },
+       { nvc0_grctx_init_pd_0 },
+       { nvc0_grctx_init_rstr2d_0 },
+       { nvc0_grctx_init_scc_0 },
+       { nvc0_grctx_init_be_0 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_gpc_unk_0[] = {
        { 0x418380,   1, 0x04, 0x00000016 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_prop_0[] = {
        { 0x418400,   1, 0x04, 0x38004e00 },
        { 0x418404,   1, 0x04, 0x71e0ffff },
        { 0x418408,   1, 0x04, 0x00000000 },
@@ -760,6 +779,11 @@ nvc0_grctx_init_gpc_0[] = {
        { 0x418450,   6, 0x04, 0x00000000 },
        { 0x418468,   1, 0x04, 0x00000001 },
        { 0x41846c,   2, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_gpc_unk_1[] = {
        { 0x418600,   1, 0x04, 0x0000001f },
        { 0x418684,   1, 0x04, 0x0000000f },
        { 0x418700,   1, 0x04, 0x00000002 },
@@ -767,6 +791,11 @@ nvc0_grctx_init_gpc_0[] = {
        { 0x418708,   1, 0x04, 0x00000000 },
        { 0x41870c,   1, 0x04, 0x07c80000 },
        { 0x418710,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc0_grctx_init_setup_0[] = {
        { 0x418800,   1, 0x04, 0x0006860a },
        { 0x418808,   3, 0x04, 0x00000000 },
        { 0x418828,   1, 0x04, 0x00008442 },
@@ -775,10 +804,20 @@ nvc0_grctx_init_gpc_0[] = {
        { 0x4188e0,   1, 0x04, 0x01000000 },
        { 0x4188e8,   5, 0x04, 0x00000000 },
        { 0x4188fc,   1, 0x04, 0x00100000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_zcull_0[] = {
        { 0x41891c,   1, 0x04, 0x00ff00ff },
        { 0x418924,   1, 0x04, 0x00000000 },
        { 0x418928,   1, 0x04, 0x00ffff00 },
        { 0x41892c,   1, 0x04, 0x0000ff00 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_crstr_0[] = {
        { 0x418b00,   1, 0x04, 0x00000000 },
        { 0x418b08,   1, 0x04, 0x0a418820 },
        { 0x418b0c,   1, 0x04, 0x062080e6 },
@@ -787,18 +826,41 @@ nvc0_grctx_init_gpc_0[] = {
        { 0x418b18,   1, 0x04, 0x0a418820 },
        { 0x418b1c,   1, 0x04, 0x000000e6 },
        { 0x418bb8,   1, 0x04, 0x00000103 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_gpm_0[] = {
        { 0x418c08,   1, 0x04, 0x00000001 },
        { 0x418c10,   8, 0x04, 0x00000000 },
        { 0x418c80,   1, 0x04, 0x20200004 },
        { 0x418c8c,   1, 0x04, 0x00000001 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_gcc_0[] = {
        { 0x419000,   1, 0x04, 0x00000780 },
        { 0x419004,   2, 0x04, 0x00000000 },
        { 0x419014,   1, 0x04, 0x00000004 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_gpc_1[] = {
+const struct nvc0_graph_pack
+nvc0_grctx_pack_gpc[] = {
+       { nvc0_grctx_init_gpc_unk_0 },
+       { nvc0_grctx_init_prop_0 },
+       { nvc0_grctx_init_gpc_unk_1 },
+       { nvc0_grctx_init_setup_0 },
+       { nvc0_grctx_init_zcull_0 },
+       { nvc0_grctx_init_crstr_0 },
+       { nvc0_grctx_init_gpm_0 },
+       { nvc0_grctx_init_gcc_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc0_grctx_init_zcullr_0[] = {
        { 0x418a00,   3, 0x04, 0x00000000 },
        { 0x418a0c,   1, 0x04, 0x00010000 },
        { 0x418a10,   3, 0x04, 0x00000000 },
@@ -826,19 +888,35 @@ nvc0_grctx_init_gpc_1[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_grctx_init_tpc[] = {
+const struct nvc0_graph_pack
+nvc0_grctx_pack_zcull[] = {
+       { nvc0_grctx_init_zcullr_0 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_pe_0[] = {
        { 0x419818,   1, 0x04, 0x00000000 },
        { 0x41983c,   1, 0x04, 0x00038bc7 },
        { 0x419848,   1, 0x04, 0x00000000 },
        { 0x419864,   1, 0x04, 0x0000012a },
        { 0x419888,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc0_grctx_init_tex_0[] = {
        { 0x419a00,   1, 0x04, 0x000001f0 },
        { 0x419a04,   1, 0x04, 0x00000001 },
        { 0x419a08,   1, 0x04, 0x00000023 },
        { 0x419a0c,   1, 0x04, 0x00020000 },
        { 0x419a10,   1, 0x04, 0x00000000 },
        { 0x419a14,   1, 0x04, 0x00000200 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_wwdx_0[] = {
        { 0x419b00,   1, 0x04, 0x0a418820 },
        { 0x419b04,   1, 0x04, 0x062080e6 },
        { 0x419b08,   1, 0x04, 0x020398a4 },
@@ -848,15 +926,35 @@ nvc0_grctx_init_tpc[] = {
        { 0x419bd0,   1, 0x04, 0x00900103 },
        { 0x419be0,   1, 0x04, 0x00000001 },
        { 0x419be4,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_mpc_0[] = {
        { 0x419c00,   1, 0x04, 0x00000002 },
        { 0x419c04,   1, 0x04, 0x00000006 },
        { 0x419c08,   1, 0x04, 0x00000002 },
        { 0x419c20,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc0_grctx_init_l1c_0[] = {
        { 0x419cb0,   1, 0x04, 0x00060048 },
        { 0x419ce8,   1, 0x04, 0x00000000 },
        { 0x419cf4,   1, 0x04, 0x00000183 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_grctx_init_tpccs_0[] = {
        { 0x419d20,   1, 0x04, 0x02180000 },
        { 0x419d24,   1, 0x04, 0x00001fff },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc0_grctx_init_sm_0[] = {
        { 0x419e04,   3, 0x04, 0x00000000 },
        { 0x419e10,   1, 0x04, 0x00000002 },
        { 0x419e44,   1, 0x04, 0x001beff2 },
@@ -868,6 +966,22 @@ nvc0_grctx_init_tpc[] = {
        {}
 };
 
+const struct nvc0_graph_pack
+nvc0_grctx_pack_tpc[] = {
+       { nvc0_grctx_init_pe_0 },
+       { nvc0_grctx_init_tex_0 },
+       { nvc0_grctx_init_wwdx_0 },
+       { nvc0_grctx_init_mpc_0 },
+       { nvc0_grctx_init_l1c_0 },
+       { nvc0_grctx_init_tpccs_0 },
+       { nvc0_grctx_init_sm_0 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
 void
 nvc0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
@@ -1055,14 +1169,14 @@ void
 nvc0_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
        struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
-       int i;
 
        nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
 
-       for (i = 0; oclass->hub[i]; i++)
-               nvc0_graph_mmio(priv, oclass->hub[i]);
-       for (i = 0; oclass->gpc[i]; i++)
-               nvc0_graph_mmio(priv, oclass->gpc[i]);
+       nvc0_graph_mmio(priv, oclass->hub);
+       nvc0_graph_mmio(priv, oclass->gpc);
+       nvc0_graph_mmio(priv, oclass->zcull);
+       nvc0_graph_mmio(priv, oclass->tpc);
+       nvc0_graph_mmio(priv, oclass->ppc);
 
        nv_wr32(priv, 0x404154, 0x00000000);
 
@@ -1182,46 +1296,6 @@ done:
        return ret;
 }
 
-struct nvc0_graph_init *
-nvc0_grctx_init_hub[] = {
-       nvc0_grctx_init_base,
-       nvc0_grctx_init_unk40xx,
-       nvc0_grctx_init_unk44xx,
-       nvc0_grctx_init_unk46xx,
-       nvc0_grctx_init_unk47xx,
-       nvc0_grctx_init_unk58xx,
-       nvc0_grctx_init_unk60xx,
-       nvc0_grctx_init_unk64xx,
-       nvc0_grctx_init_unk78xx,
-       nvc0_grctx_init_unk80xx,
-       nvc0_grctx_init_rop,
-       NULL
-};
-
-static struct nvc0_graph_init *
-nvc0_grctx_init_gpc[] = {
-       nvc0_grctx_init_gpc_0,
-       nvc0_grctx_init_gpc_1,
-       nvc0_grctx_init_tpc,
-       NULL
-};
-
-struct nvc0_graph_init
-nvc0_grctx_init_mthd_magic[] = {
-       { 0x3410, 1, 0x04, 0x00000000 },
-       {}
-};
-
-struct nvc0_graph_mthd
-nvc0_grctx_init_mthd[] = {
-       { 0x9097, nvc0_grctx_init_9097, },
-       { 0x902d, nvc0_grctx_init_902d, },
-       { 0x9039, nvc0_grctx_init_9039, },
-       { 0x90c0, nvc0_grctx_init_90c0, },
-       { 0x902d, nvc0_grctx_init_mthd_magic, },
-       {}
-};
-
 struct nouveau_oclass *
 nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) {
        .base.handle = NV_ENGCTX(GR, 0xc0),
@@ -1233,11 +1307,13 @@ nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) {
                .rd32 = _nouveau_graph_context_rd32,
                .wr32 = _nouveau_graph_context_wr32,
        },
-       .main = nvc0_grctx_generate_main,
-       .mods = nvc0_grctx_generate_mods,
-       .unkn = nvc0_grctx_generate_unkn,
-       .hub  = nvc0_grctx_init_hub,
-       .gpc  = nvc0_grctx_init_gpc,
-       .icmd = nvc0_grctx_init_icmd,
-       .mthd = nvc0_grctx_init_mthd,
+       .main  = nvc0_grctx_generate_main,
+       .mods  = nvc0_grctx_generate_mods,
+       .unkn  = nvc0_grctx_generate_unkn,
+       .hub   = nvc0_grctx_pack_hub,
+       .gpc   = nvc0_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = nvc0_grctx_pack_tpc,
+       .icmd  = nvc0_grctx_pack_icmd,
+       .mthd  = nvc0_grctx_pack_mthd,
 }.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h
new file mode 100644 (file)
index 0000000..9c815d1
--- /dev/null
@@ -0,0 +1,170 @@
+#ifndef __NVKM_GRCTX_NVC0_H__
+#define __NVKM_GRCTX_NVC0_H__
+
+#include "nvc0.h"
+
+struct nvc0_grctx {
+       struct nvc0_graph_priv *priv;
+       struct nvc0_graph_data *data;
+       struct nvc0_graph_mmio *mmio;
+       int buffer_nr;
+       u64 buffer[4];
+       u64 addr;
+};
+
+struct nvc0_grctx_oclass {
+       struct nouveau_oclass base;
+       /* main context generation function */
+       void  (*main)(struct nvc0_graph_priv *, struct nvc0_grctx *);
+       /* context-specific modify-on-first-load list generation function */
+       void  (*mods)(struct nvc0_graph_priv *, struct nvc0_grctx *);
+       void  (*unkn)(struct nvc0_graph_priv *);
+       /* mmio context data */
+       const struct nvc0_graph_pack *hub;
+       const struct nvc0_graph_pack *gpc;
+       const struct nvc0_graph_pack *zcull;
+       const struct nvc0_graph_pack *tpc;
+       const struct nvc0_graph_pack *ppc;
+       /* indirect context data, generated with icmds/mthds */
+       const struct nvc0_graph_pack *icmd;
+       const struct nvc0_graph_pack *mthd;
+};
+
+#define mmio_data(s,a,p) do {                                                  \
+       info->buffer[info->buffer_nr] = round_up(info->addr, (a));             \
+       info->addr = info->buffer[info->buffer_nr++] + (s);                    \
+       info->data->size = (s);                                                \
+       info->data->align = (a);                                               \
+       info->data->access = (p);                                              \
+       info->data++;                                                          \
+} while(0)
+
+#define mmio_list(r,d,s,b) do {                                                \
+       info->mmio->addr = (r);                                                \
+       info->mmio->data = (d);                                                \
+       info->mmio->shift = (s);                                               \
+       info->mmio->buffer = (b);                                              \
+       info->mmio++;                                                          \
+       nv_wr32(priv, (r), (d) | ((s) ? (info->buffer[(b)] >> (s)) : 0));      \
+} while(0)
+
+extern struct nouveau_oclass *nvc0_grctx_oclass;
+int  nvc0_grctx_generate(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nvc0_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nvc0_grctx_generate_unkn(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *);
+void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *);
+
+extern struct nouveau_oclass *nvc1_grctx_oclass;
+void nvc1_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *);
+
+extern struct nouveau_oclass *nvc4_grctx_oclass;
+extern struct nouveau_oclass *nvc8_grctx_oclass;
+extern struct nouveau_oclass *nvd7_grctx_oclass;
+extern struct nouveau_oclass *nvd9_grctx_oclass;
+
+extern struct nouveau_oclass *nve4_grctx_oclass;
+void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
+void nve4_grctx_generate_unkn(struct nvc0_graph_priv *);
+void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *);
+
+extern struct nouveau_oclass *nvf0_grctx_oclass;
+extern struct nouveau_oclass *nv108_grctx_oclass;
+extern struct nouveau_oclass *gm107_grctx_oclass;
+
+/* context init value lists */
+
+extern const struct nvc0_graph_pack nvc0_grctx_pack_icmd[];
+
+extern const struct nvc0_graph_pack nvc0_grctx_pack_mthd[];
+extern const struct nvc0_graph_init nvc0_grctx_init_902d_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_9039_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_90c0_0[];
+
+extern const struct nvc0_graph_pack nvc0_grctx_pack_hub[];
+extern const struct nvc0_graph_init nvc0_grctx_init_main_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_fe_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_pri_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_memfmt_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_rstr2d_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_scc_0[];
+
+extern const struct nvc0_graph_pack nvc0_grctx_pack_gpc[];
+extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_prop_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_1[];
+extern const struct nvc0_graph_init nvc0_grctx_init_zcull_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_crstr_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_gpm_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_gcc_0[];
+
+extern const struct nvc0_graph_pack nvc0_grctx_pack_zcull[];
+
+extern const struct nvc0_graph_pack nvc0_grctx_pack_tpc[];
+extern const struct nvc0_graph_init nvc0_grctx_init_pe_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_wwdx_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_mpc_0[];
+extern const struct nvc0_graph_init nvc0_grctx_init_tpccs_0[];
+
+extern const struct nvc0_graph_init nvc4_grctx_init_tex_0[];
+extern const struct nvc0_graph_init nvc4_grctx_init_l1c_0[];
+extern const struct nvc0_graph_init nvc4_grctx_init_sm_0[];
+
+extern const struct nvc0_graph_init nvc1_grctx_init_9097_0[];
+
+extern const struct nvc0_graph_init nvc1_grctx_init_gpm_0[];
+
+extern const struct nvc0_graph_init nvc1_grctx_init_pe_0[];
+extern const struct nvc0_graph_init nvc1_grctx_init_wwdx_0[];
+extern const struct nvc0_graph_init nvc1_grctx_init_tpccs_0[];
+
+extern const struct nvc0_graph_init nvc8_grctx_init_9197_0[];
+extern const struct nvc0_graph_init nvc8_grctx_init_9297_0[];
+
+extern const struct nvc0_graph_pack nvd9_grctx_pack_icmd[];
+
+extern const struct nvc0_graph_pack nvd9_grctx_pack_mthd[];
+
+extern const struct nvc0_graph_init nvd9_grctx_init_fe_0[];
+extern const struct nvc0_graph_init nvd9_grctx_init_be_0[];
+
+extern const struct nvc0_graph_init nvd9_grctx_init_prop_0[];
+extern const struct nvc0_graph_init nvd9_grctx_init_gpc_unk_1[];
+extern const struct nvc0_graph_init nvd9_grctx_init_crstr_0[];
+
+extern const struct nvc0_graph_init nvd9_grctx_init_sm_0[];
+
+extern const struct nvc0_graph_init nvd7_grctx_init_pe_0[];
+
+extern const struct nvc0_graph_init nvd7_grctx_init_wwdx_0[];
+
+extern const struct nvc0_graph_init nve4_grctx_init_memfmt_0[];
+extern const struct nvc0_graph_init nve4_grctx_init_ds_0[];
+extern const struct nvc0_graph_init nve4_grctx_init_scc_0[];
+
+extern const struct nvc0_graph_init nve4_grctx_init_gpm_0[];
+
+extern const struct nvc0_graph_init nve4_grctx_init_pes_0[];
+
+extern const struct nvc0_graph_pack nvf0_grctx_pack_mthd[];
+
+extern const struct nvc0_graph_init nvf0_grctx_init_pri_0[];
+extern const struct nvc0_graph_init nvf0_grctx_init_cwd_0[];
+
+extern const struct nvc0_graph_init nvf0_grctx_init_gpc_unk_2[];
+
+extern const struct nvc0_graph_init nvf0_grctx_init_mpc_0[];
+extern const struct nvc0_graph_init nvf0_grctx_init_l1c_0[];
+
+extern const struct nvc0_graph_init nv108_grctx_init_rstr2d_0[];
+
+extern const struct nvc0_graph_init nv108_grctx_init_prop_0[];
+extern const struct nvc0_graph_init nv108_grctx_init_crstr_0[];
+
+
+#endif
index 71b4283..24a92c5 100644 (file)
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "nvc0.h"
+#include "ctxnvc0.h"
 
-static struct nvc0_graph_init
-nvc1_grctx_init_icmd[] = {
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct nvc0_graph_init
+nvc1_grctx_init_icmd_0[] = {
        { 0x001000,   1, 0x01, 0x00000004 },
        { 0x0000a9,   1, 0x01, 0x0000ffff },
        { 0x000038,   1, 0x01, 0x0fac6881 },
@@ -141,8 +145,7 @@ nvc1_grctx_init_icmd[] = {
        { 0x000586,   1, 0x01, 0x00000040 },
        { 0x000582,   2, 0x01, 0x00000080 },
        { 0x0005c2,   1, 0x01, 0x00000001 },
-       { 0x000638,   1, 0x01, 0x00000001 },
-       { 0x000639,   1, 0x01, 0x00000001 },
+       { 0x000638,   2, 0x01, 0x00000001 },
        { 0x00063a,   1, 0x01, 0x00000002 },
        { 0x00063b,   2, 0x01, 0x00000001 },
        { 0x00063d,   1, 0x01, 0x00000002 },
@@ -202,15 +205,13 @@ nvc1_grctx_init_icmd[] = {
        { 0x000787,   1, 0x01, 0x000000cf },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x000836,   1, 0x01, 0x00000001 },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x00080c,   1, 0x01, 0x00000002 },
        { 0x00080d,   2, 0x01, 0x00000100 },
@@ -236,14 +237,12 @@ nvc1_grctx_init_icmd[] = {
        { 0x0006b1,   1, 0x01, 0x00000011 },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x01e100,   1, 0x01, 0x00000001 },
        { 0x001000,   1, 0x01, 0x00000014 },
@@ -268,8 +267,14 @@ nvc1_grctx_init_icmd[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc1_grctx_init_9097[] = {
+static const struct nvc0_graph_pack
+nvc1_grctx_pack_icmd[] = {
+       { nvc1_grctx_init_icmd_0 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc1_grctx_init_9097_0[] = {
        { 0x000800,   8, 0x40, 0x00000000 },
        { 0x000804,   8, 0x40, 0x00000000 },
        { 0x000808,   8, 0x40, 0x00000400 },
@@ -516,8 +521,7 @@ nvc1_grctx_init_9097[] = {
        { 0x001350,   1, 0x04, 0x00000002 },
        { 0x001358,   1, 0x04, 0x00000001 },
        { 0x0012e4,   1, 0x04, 0x00000000 },
-       { 0x00131c,   1, 0x04, 0x00000000 },
-       { 0x001320,   3, 0x04, 0x00000000 },
+       { 0x00131c,   4, 0x04, 0x00000000 },
        { 0x0019c0,   1, 0x04, 0x00000000 },
        { 0x001140,   1, 0x04, 0x00000000 },
        { 0x0019c4,   1, 0x04, 0x00000000 },
@@ -571,15 +575,25 @@ nvc1_grctx_init_9097[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvc1_grctx_init_9197[] = {
+static const struct nvc0_graph_init
+nvc1_grctx_init_9197_0[] = {
        { 0x003400, 128, 0x04, 0x00000000 },
        { 0x0002e4,   1, 0x04, 0x0000b001 },
        {}
 };
 
-static struct nvc0_graph_init
-nvc1_grctx_init_unk58xx[] = {
+static const struct nvc0_graph_pack
+nvc1_grctx_pack_mthd[] = {
+       { nvc1_grctx_init_9097_0, 0x9097 },
+       { nvc1_grctx_init_9197_0, 0x9197 },
+       { nvc0_grctx_init_902d_0, 0x902d },
+       { nvc0_grctx_init_9039_0, 0x9039 },
+       { nvc0_grctx_init_90c0_0, 0x90c0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc1_grctx_init_ds_0[] = {
        { 0x405800,   1, 0x04, 0x0f8000bf },
        { 0x405830,   1, 0x04, 0x02180218 },
        { 0x405834,   2, 0x04, 0x00000000 },
@@ -590,8 +604,20 @@ nvc1_grctx_init_unk58xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvc1_grctx_init_rop[] = {
+static const struct nvc0_graph_init
+nvc1_grctx_init_pd_0[] = {
+       { 0x406020,   1, 0x04, 0x000103c1 },
+       { 0x406028,   4, 0x04, 0x00000001 },
+       { 0x4064a8,   1, 0x04, 0x00000000 },
+       { 0x4064ac,   1, 0x04, 0x00003fff },
+       { 0x4064b4,   2, 0x04, 0x00000000 },
+       { 0x4064c0,   1, 0x04, 0x80140078 },
+       { 0x4064c4,   1, 0x04, 0x0086ffff },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc1_grctx_init_be_0[] = {
        { 0x408800,   1, 0x04, 0x02802a3c },
        { 0x408804,   1, 0x04, 0x00000040 },
        { 0x408808,   1, 0x04, 0x1003e005 },
@@ -602,25 +628,22 @@ nvc1_grctx_init_rop[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvc1_grctx_init_gpc_0[] = {
-       { 0x418380,   1, 0x04, 0x00000016 },
-       { 0x418400,   1, 0x04, 0x38004e00 },
-       { 0x418404,   1, 0x04, 0x71e0ffff },
-       { 0x418408,   1, 0x04, 0x00000000 },
-       { 0x41840c,   1, 0x04, 0x00001008 },
-       { 0x418410,   1, 0x04, 0x0fff0fff },
-       { 0x418414,   1, 0x04, 0x00200fff },
-       { 0x418450,   6, 0x04, 0x00000000 },
-       { 0x418468,   1, 0x04, 0x00000001 },
-       { 0x41846c,   2, 0x04, 0x00000000 },
-       { 0x418600,   1, 0x04, 0x0000001f },
-       { 0x418684,   1, 0x04, 0x0000000f },
-       { 0x418700,   1, 0x04, 0x00000002 },
-       { 0x418704,   1, 0x04, 0x00000080 },
-       { 0x418708,   1, 0x04, 0x00000000 },
-       { 0x41870c,   1, 0x04, 0x07c80000 },
-       { 0x418710,   1, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nvc1_grctx_pack_hub[] = {
+       { nvc0_grctx_init_main_0 },
+       { nvc0_grctx_init_fe_0 },
+       { nvc0_grctx_init_pri_0 },
+       { nvc0_grctx_init_memfmt_0 },
+       { nvc1_grctx_init_ds_0 },
+       { nvc1_grctx_init_pd_0 },
+       { nvc0_grctx_init_rstr2d_0 },
+       { nvc0_grctx_init_scc_0 },
+       { nvc1_grctx_init_be_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc1_grctx_init_setup_0[] = {
        { 0x418800,   1, 0x04, 0x0006860a },
        { 0x418808,   3, 0x04, 0x00000000 },
        { 0x418828,   1, 0x04, 0x00008442 },
@@ -629,69 +652,44 @@ nvc1_grctx_init_gpc_0[] = {
        { 0x4188e0,   1, 0x04, 0x01000000 },
        { 0x4188e8,   5, 0x04, 0x00000000 },
        { 0x4188fc,   1, 0x04, 0x00100018 },
-       { 0x41891c,   1, 0x04, 0x00ff00ff },
-       { 0x418924,   1, 0x04, 0x00000000 },
-       { 0x418928,   1, 0x04, 0x00ffff00 },
-       { 0x41892c,   1, 0x04, 0x0000ff00 },
-       { 0x418a00,   3, 0x04, 0x00000000 },
-       { 0x418a0c,   1, 0x04, 0x00010000 },
-       { 0x418a10,   3, 0x04, 0x00000000 },
-       { 0x418a20,   3, 0x04, 0x00000000 },
-       { 0x418a2c,   1, 0x04, 0x00010000 },
-       { 0x418a30,   3, 0x04, 0x00000000 },
-       { 0x418a40,   3, 0x04, 0x00000000 },
-       { 0x418a4c,   1, 0x04, 0x00010000 },
-       { 0x418a50,   3, 0x04, 0x00000000 },
-       { 0x418a60,   3, 0x04, 0x00000000 },
-       { 0x418a6c,   1, 0x04, 0x00010000 },
-       { 0x418a70,   3, 0x04, 0x00000000 },
-       { 0x418a80,   3, 0x04, 0x00000000 },
-       { 0x418a8c,   1, 0x04, 0x00010000 },
-       { 0x418a90,   3, 0x04, 0x00000000 },
-       { 0x418aa0,   3, 0x04, 0x00000000 },
-       { 0x418aac,   1, 0x04, 0x00010000 },
-       { 0x418ab0,   3, 0x04, 0x00000000 },
-       { 0x418ac0,   3, 0x04, 0x00000000 },
-       { 0x418acc,   1, 0x04, 0x00010000 },
-       { 0x418ad0,   3, 0x04, 0x00000000 },
-       { 0x418ae0,   3, 0x04, 0x00000000 },
-       { 0x418aec,   1, 0x04, 0x00010000 },
-       { 0x418af0,   3, 0x04, 0x00000000 },
-       { 0x418b00,   1, 0x04, 0x00000000 },
-       { 0x418b08,   1, 0x04, 0x0a418820 },
-       { 0x418b0c,   1, 0x04, 0x062080e6 },
-       { 0x418b10,   1, 0x04, 0x020398a4 },
-       { 0x418b14,   1, 0x04, 0x0e629062 },
-       { 0x418b18,   1, 0x04, 0x0a418820 },
-       { 0x418b1c,   1, 0x04, 0x000000e6 },
-       { 0x418bb8,   1, 0x04, 0x00000103 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc1_grctx_init_gpm_0[] = {
        { 0x418c08,   1, 0x04, 0x00000001 },
        { 0x418c10,   8, 0x04, 0x00000000 },
        { 0x418c6c,   1, 0x04, 0x00000001 },
        { 0x418c80,   1, 0x04, 0x20200004 },
        { 0x418c8c,   1, 0x04, 0x00000001 },
-       { 0x419000,   1, 0x04, 0x00000780 },
-       { 0x419004,   2, 0x04, 0x00000000 },
-       { 0x419014,   1, 0x04, 0x00000004 },
        {}
 };
 
-static struct nvc0_graph_init
-nvc1_grctx_init_tpc[] = {
+static const struct nvc0_graph_pack
+nvc1_grctx_pack_gpc[] = {
+       { nvc0_grctx_init_gpc_unk_0 },
+       { nvc0_grctx_init_prop_0 },
+       { nvc0_grctx_init_gpc_unk_1 },
+       { nvc1_grctx_init_setup_0 },
+       { nvc0_grctx_init_zcull_0 },
+       { nvc0_grctx_init_crstr_0 },
+       { nvc1_grctx_init_gpm_0 },
+       { nvc0_grctx_init_gcc_0 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc1_grctx_init_pe_0[] = {
        { 0x419818,   1, 0x04, 0x00000000 },
        { 0x41983c,   1, 0x04, 0x00038bc7 },
        { 0x419848,   1, 0x04, 0x00000000 },
        { 0x419864,   1, 0x04, 0x00000129 },
        { 0x419888,   1, 0x04, 0x00000000 },
-       { 0x419a00,   1, 0x04, 0x000001f0 },
-       { 0x419a04,   1, 0x04, 0x00000001 },
-       { 0x419a08,   1, 0x04, 0x00000023 },
-       { 0x419a0c,   1, 0x04, 0x00020000 },
-       { 0x419a10,   1, 0x04, 0x00000000 },
-       { 0x419a14,   1, 0x04, 0x00000200 },
-       { 0x419a1c,   1, 0x04, 0x00000000 },
-       { 0x419a20,   1, 0x04, 0x00000800 },
-       { 0x419ac4,   1, 0x04, 0x0007f440 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc1_grctx_init_wwdx_0[] = {
        { 0x419b00,   1, 0x04, 0x0a418820 },
        { 0x419b04,   1, 0x04, 0x062080e6 },
        { 0x419b08,   1, 0x04, 0x020398a4 },
@@ -701,28 +699,33 @@ nvc1_grctx_init_tpc[] = {
        { 0x419bd0,   1, 0x04, 0x00900103 },
        { 0x419be0,   1, 0x04, 0x00400001 },
        { 0x419be4,   1, 0x04, 0x00000000 },
-       { 0x419c00,   1, 0x04, 0x00000002 },
-       { 0x419c04,   1, 0x04, 0x00000006 },
-       { 0x419c08,   1, 0x04, 0x00000002 },
-       { 0x419c20,   1, 0x04, 0x00000000 },
-       { 0x419cb0,   1, 0x04, 0x00020048 },
-       { 0x419ce8,   1, 0x04, 0x00000000 },
-       { 0x419cf4,   1, 0x04, 0x00000183 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc1_grctx_init_tpccs_0[] = {
        { 0x419d20,   1, 0x04, 0x12180000 },
        { 0x419d24,   1, 0x04, 0x00001fff },
        { 0x419d44,   1, 0x04, 0x02180218 },
-       { 0x419e04,   3, 0x04, 0x00000000 },
-       { 0x419e10,   1, 0x04, 0x00000002 },
-       { 0x419e44,   1, 0x04, 0x001beff2 },
-       { 0x419e48,   1, 0x04, 0x00000000 },
-       { 0x419e4c,   1, 0x04, 0x0000000f },
-       { 0x419e50,  17, 0x04, 0x00000000 },
-       { 0x419e98,   1, 0x04, 0x00000000 },
-       { 0x419ee0,   1, 0x04, 0x00011110 },
-       { 0x419f30,  11, 0x04, 0x00000000 },
        {}
 };
 
+static const struct nvc0_graph_pack
+nvc1_grctx_pack_tpc[] = {
+       { nvc1_grctx_init_pe_0 },
+       { nvc4_grctx_init_tex_0 },
+       { nvc1_grctx_init_wwdx_0 },
+       { nvc0_grctx_init_mpc_0 },
+       { nvc4_grctx_init_l1c_0 },
+       { nvc1_grctx_init_tpccs_0 },
+       { nvc4_grctx_init_sm_0 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
 void
 nvc1_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
@@ -771,41 +774,6 @@ nvc1_grctx_generate_unkn(struct nvc0_graph_priv *priv)
        nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
 }
 
-static struct nvc0_graph_init *
-nvc1_grctx_init_hub[] = {
-       nvc0_grctx_init_base,
-       nvc0_grctx_init_unk40xx,
-       nvc0_grctx_init_unk44xx,
-       nvc0_grctx_init_unk46xx,
-       nvc0_grctx_init_unk47xx,
-       nvc1_grctx_init_unk58xx,
-       nvc0_grctx_init_unk60xx,
-       nvc0_grctx_init_unk64xx,
-       nvc0_grctx_init_unk78xx,
-       nvc0_grctx_init_unk80xx,
-       nvc1_grctx_init_rop,
-       NULL
-};
-
-struct nvc0_graph_init *
-nvc1_grctx_init_gpc[] = {
-       nvc1_grctx_init_gpc_0,
-       nvc0_grctx_init_gpc_1,
-       nvc1_grctx_init_tpc,
-       NULL
-};
-
-static struct nvc0_graph_mthd
-nvc1_grctx_init_mthd[] = {
-       { 0x9097, nvc1_grctx_init_9097, },
-       { 0x9197, nvc1_grctx_init_9197, },
-       { 0x902d, nvc0_grctx_init_902d, },
-       { 0x9039, nvc0_grctx_init_9039, },
-       { 0x90c0, nvc0_grctx_init_90c0, },
-       { 0x902d, nvc0_grctx_init_mthd_magic, },
-       {}
-};
-
 struct nouveau_oclass *
 nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) {
        .base.handle = NV_ENGCTX(GR, 0xc1),
@@ -817,11 +785,13 @@ nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) {
                .rd32 = _nouveau_graph_context_rd32,
                .wr32 = _nouveau_graph_context_wr32,
        },
-       .main = nvc0_grctx_generate_main,
-       .mods = nvc1_grctx_generate_mods,
-       .unkn = nvc1_grctx_generate_unkn,
-       .hub  = nvc1_grctx_init_hub,
-       .gpc  = nvc1_grctx_init_gpc,
-       .icmd = nvc1_grctx_init_icmd,
-       .mthd = nvc1_grctx_init_mthd,
+       .main  = nvc0_grctx_generate_main,
+       .mods  = nvc1_grctx_generate_mods,
+       .unkn  = nvc1_grctx_generate_unkn,
+       .hub   = nvc1_grctx_pack_hub,
+       .gpc   = nvc1_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = nvc1_grctx_pack_tpc,
+       .icmd  = nvc1_grctx_pack_icmd,
+       .mthd  = nvc1_grctx_pack_mthd,
 }.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc3.c
deleted file mode 100644 (file)
index 8f237b3..0000000
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-
-static struct nvc0_graph_init
-nvc3_grctx_init_tpc[] = {
-       { 0x419818,   1, 0x04, 0x00000000 },
-       { 0x41983c,   1, 0x04, 0x00038bc7 },
-       { 0x419848,   1, 0x04, 0x00000000 },
-       { 0x419864,   1, 0x04, 0x0000012a },
-       { 0x419888,   1, 0x04, 0x00000000 },
-       { 0x419a00,   1, 0x04, 0x000001f0 },
-       { 0x419a04,   1, 0x04, 0x00000001 },
-       { 0x419a08,   1, 0x04, 0x00000023 },
-       { 0x419a0c,   1, 0x04, 0x00020000 },
-       { 0x419a10,   1, 0x04, 0x00000000 },
-       { 0x419a14,   1, 0x04, 0x00000200 },
-       { 0x419a1c,   1, 0x04, 0x00000000 },
-       { 0x419a20,   1, 0x04, 0x00000800 },
-       { 0x419ac4,   1, 0x04, 0x0007f440 },
-       { 0x419b00,   1, 0x04, 0x0a418820 },
-       { 0x419b04,   1, 0x04, 0x062080e6 },
-       { 0x419b08,   1, 0x04, 0x020398a4 },
-       { 0x419b0c,   1, 0x04, 0x0e629062 },
-       { 0x419b10,   1, 0x04, 0x0a418820 },
-       { 0x419b14,   1, 0x04, 0x000000e6 },
-       { 0x419bd0,   1, 0x04, 0x00900103 },
-       { 0x419be0,   1, 0x04, 0x00000001 },
-       { 0x419be4,   1, 0x04, 0x00000000 },
-       { 0x419c00,   1, 0x04, 0x00000002 },
-       { 0x419c04,   1, 0x04, 0x00000006 },
-       { 0x419c08,   1, 0x04, 0x00000002 },
-       { 0x419c20,   1, 0x04, 0x00000000 },
-       { 0x419cb0,   1, 0x04, 0x00020048 },
-       { 0x419ce8,   1, 0x04, 0x00000000 },
-       { 0x419cf4,   1, 0x04, 0x00000183 },
-       { 0x419d20,   1, 0x04, 0x02180000 },
-       { 0x419d24,   1, 0x04, 0x00001fff },
-       { 0x419e04,   3, 0x04, 0x00000000 },
-       { 0x419e10,   1, 0x04, 0x00000002 },
-       { 0x419e44,   1, 0x04, 0x001beff2 },
-       { 0x419e48,   1, 0x04, 0x00000000 },
-       { 0x419e4c,   1, 0x04, 0x0000000f },
-       { 0x419e50,  17, 0x04, 0x00000000 },
-       { 0x419e98,   1, 0x04, 0x00000000 },
-       { 0x419ee0,   1, 0x04, 0x00011110 },
-       { 0x419f30,  11, 0x04, 0x00000000 },
-       {}
-};
-
-struct nvc0_graph_init *
-nvc3_grctx_init_gpc[] = {
-       nvc0_grctx_init_gpc_0,
-       nvc0_grctx_init_gpc_1,
-       nvc3_grctx_init_tpc,
-       NULL
-};
-
-struct nouveau_oclass *
-nvc3_grctx_oclass = &(struct nvc0_grctx_oclass) {
-       .base.handle = NV_ENGCTX(GR, 0xc3),
-       .base.ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nvc0_graph_context_ctor,
-               .dtor = nvc0_graph_context_dtor,
-               .init = _nouveau_graph_context_init,
-               .fini = _nouveau_graph_context_fini,
-               .rd32 = _nouveau_graph_context_rd32,
-               .wr32 = _nouveau_graph_context_wr32,
-       },
-       .main = nvc0_grctx_generate_main,
-       .mods = nvc0_grctx_generate_mods,
-       .unkn = nvc0_grctx_generate_unkn,
-       .hub  = nvc0_grctx_init_hub,
-       .gpc  = nvc3_grctx_init_gpc,
-       .icmd = nvc0_grctx_init_icmd,
-       .mthd = nvc0_grctx_init_mthd,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c
new file mode 100644 (file)
index 0000000..e11ed55
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "ctxnvc0.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+const struct nvc0_graph_init
+nvc4_grctx_init_tex_0[] = {
+       { 0x419a00,   1, 0x04, 0x000001f0 },
+       { 0x419a04,   1, 0x04, 0x00000001 },
+       { 0x419a08,   1, 0x04, 0x00000023 },
+       { 0x419a0c,   1, 0x04, 0x00020000 },
+       { 0x419a10,   1, 0x04, 0x00000000 },
+       { 0x419a14,   1, 0x04, 0x00000200 },
+       { 0x419a1c,   1, 0x04, 0x00000000 },
+       { 0x419a20,   1, 0x04, 0x00000800 },
+       { 0x419ac4,   1, 0x04, 0x0007f440 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc4_grctx_init_l1c_0[] = {
+       { 0x419cb0,   1, 0x04, 0x00020048 },
+       { 0x419ce8,   1, 0x04, 0x00000000 },
+       { 0x419cf4,   1, 0x04, 0x00000183 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc4_grctx_init_sm_0[] = {
+       { 0x419e04,   3, 0x04, 0x00000000 },
+       { 0x419e10,   1, 0x04, 0x00000002 },
+       { 0x419e44,   1, 0x04, 0x001beff2 },
+       { 0x419e48,   1, 0x04, 0x00000000 },
+       { 0x419e4c,   1, 0x04, 0x0000000f },
+       { 0x419e50,  17, 0x04, 0x00000000 },
+       { 0x419e98,   1, 0x04, 0x00000000 },
+       { 0x419ee0,   1, 0x04, 0x00011110 },
+       { 0x419f30,  11, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+nvc4_grctx_pack_tpc[] = {
+       { nvc0_grctx_init_pe_0 },
+       { nvc4_grctx_init_tex_0 },
+       { nvc0_grctx_init_wwdx_0 },
+       { nvc0_grctx_init_mpc_0 },
+       { nvc4_grctx_init_l1c_0 },
+       { nvc0_grctx_init_tpccs_0 },
+       { nvc4_grctx_init_sm_0 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nouveau_oclass *
+nvc4_grctx_oclass = &(struct nvc0_grctx_oclass) {
+       .base.handle = NV_ENGCTX(GR, 0xc3),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_graph_context_ctor,
+               .dtor = nvc0_graph_context_dtor,
+               .init = _nouveau_graph_context_init,
+               .fini = _nouveau_graph_context_fini,
+               .rd32 = _nouveau_graph_context_rd32,
+               .wr32 = _nouveau_graph_context_wr32,
+       },
+       .main  = nvc0_grctx_generate_main,
+       .mods  = nvc0_grctx_generate_mods,
+       .unkn  = nvc0_grctx_generate_unkn,
+       .hub   = nvc0_grctx_pack_hub,
+       .gpc   = nvc0_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = nvc4_grctx_pack_tpc,
+       .icmd  = nvc0_grctx_pack_icmd,
+       .mthd  = nvc0_grctx_pack_mthd,
+}.base;
index d0d4ce3..feebd58 100644 (file)
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "nvc0.h"
+#include "ctxnvc0.h"
 
-static struct nvc0_graph_init
-nvc8_grctx_init_icmd[] = {
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct nvc0_graph_init
+nvc8_grctx_init_icmd_0[] = {
        { 0x001000,   1, 0x01, 0x00000004 },
        { 0x0000a9,   1, 0x01, 0x0000ffff },
        { 0x000038,   1, 0x01, 0x0fac6881 },
@@ -141,8 +145,7 @@ nvc8_grctx_init_icmd[] = {
        { 0x000586,   1, 0x01, 0x00000040 },
        { 0x000582,   2, 0x01, 0x00000080 },
        { 0x0005c2,   1, 0x01, 0x00000001 },
-       { 0x000638,   1, 0x01, 0x00000001 },
-       { 0x000639,   1, 0x01, 0x00000001 },
+       { 0x000638,   2, 0x01, 0x00000001 },
        { 0x00063a,   1, 0x01, 0x00000002 },
        { 0x00063b,   2, 0x01, 0x00000001 },
        { 0x00063d,   1, 0x01, 0x00000002 },
@@ -203,15 +206,13 @@ nvc8_grctx_init_icmd[] = {
        { 0x000787,   1, 0x01, 0x000000cf },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x000836,   1, 0x01, 0x00000001 },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x00080c,   1, 0x01, 0x00000002 },
        { 0x00080d,   2, 0x01, 0x00000100 },
@@ -237,14 +238,12 @@ nvc8_grctx_init_icmd[] = {
        { 0x0006b1,   1, 0x01, 0x00000011 },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x01e100,   1, 0x01, 0x00000001 },
        { 0x001000,   1, 0x01, 0x00000014 },
@@ -269,58 +268,20 @@ nvc8_grctx_init_icmd[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvc8_grctx_init_tpc[] = {
-       { 0x419818,   1, 0x04, 0x00000000 },
-       { 0x41983c,   1, 0x04, 0x00038bc7 },
-       { 0x419848,   1, 0x04, 0x00000000 },
-       { 0x419864,   1, 0x04, 0x0000012a },
-       { 0x419888,   1, 0x04, 0x00000000 },
-       { 0x419a00,   1, 0x04, 0x000001f0 },
-       { 0x419a04,   1, 0x04, 0x00000001 },
-       { 0x419a08,   1, 0x04, 0x00000023 },
-       { 0x419a0c,   1, 0x04, 0x00020000 },
-       { 0x419a10,   1, 0x04, 0x00000000 },
-       { 0x419a14,   1, 0x04, 0x00000200 },
-       { 0x419a1c,   1, 0x04, 0x00000000 },
-       { 0x419a20,   1, 0x04, 0x00000800 },
-       { 0x419b00,   1, 0x04, 0x0a418820 },
-       { 0x419b04,   1, 0x04, 0x062080e6 },
-       { 0x419b08,   1, 0x04, 0x020398a4 },
-       { 0x419b0c,   1, 0x04, 0x0e629062 },
-       { 0x419b10,   1, 0x04, 0x0a418820 },
-       { 0x419b14,   1, 0x04, 0x000000e6 },
-       { 0x419bd0,   1, 0x04, 0x00900103 },
-       { 0x419be0,   1, 0x04, 0x00000001 },
-       { 0x419be4,   1, 0x04, 0x00000000 },
-       { 0x419c00,   1, 0x04, 0x00000002 },
-       { 0x419c04,   1, 0x04, 0x00000006 },
-       { 0x419c08,   1, 0x04, 0x00000002 },
-       { 0x419c20,   1, 0x04, 0x00000000 },
-       { 0x419cb0,   1, 0x04, 0x00060048 },
-       { 0x419ce8,   1, 0x04, 0x00000000 },
-       { 0x419cf4,   1, 0x04, 0x00000183 },
-       { 0x419d20,   1, 0x04, 0x02180000 },
-       { 0x419d24,   1, 0x04, 0x00001fff },
-       { 0x419e04,   3, 0x04, 0x00000000 },
-       { 0x419e10,   1, 0x04, 0x00000002 },
-       { 0x419e44,   1, 0x04, 0x001beff2 },
-       { 0x419e48,   1, 0x04, 0x00000000 },
-       { 0x419e4c,   1, 0x04, 0x0000000f },
-       { 0x419e50,  17, 0x04, 0x00000000 },
-       { 0x419e98,   1, 0x04, 0x00000000 },
-       { 0x419f50,   2, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nvc8_grctx_pack_icmd[] = {
+       { nvc8_grctx_init_icmd_0 },
        {}
 };
 
-struct nvc0_graph_init
-nvc8_grctx_init_9197[] = {
+const struct nvc0_graph_init
+nvc8_grctx_init_9197_0[] = {
        { 0x0002e4,   1, 0x04, 0x0000b001 },
        {}
 };
 
-struct nvc0_graph_init
-nvc8_grctx_init_9297[] = {
+const struct nvc0_graph_init
+nvc8_grctx_init_9297_0[] = {
        { 0x003400, 128, 0x04, 0x00000000 },
        { 0x00036c,   2, 0x04, 0x00000000 },
        { 0x0007a4,   2, 0x04, 0x00000000 },
@@ -329,26 +290,47 @@ nvc8_grctx_init_9297[] = {
        {}
 };
 
-static struct nvc0_graph_mthd
-nvc8_grctx_init_mthd[] = {
-       { 0x9097, nvc1_grctx_init_9097, },
-       { 0x9197, nvc8_grctx_init_9197, },
-       { 0x9297, nvc8_grctx_init_9297, },
-       { 0x902d, nvc0_grctx_init_902d, },
-       { 0x9039, nvc0_grctx_init_9039, },
-       { 0x90c0, nvc0_grctx_init_90c0, },
-       { 0x902d, nvc0_grctx_init_mthd_magic, },
+static const struct nvc0_graph_pack
+nvc8_grctx_pack_mthd[] = {
+       { nvc1_grctx_init_9097_0, 0x9097 },
+       { nvc8_grctx_init_9197_0, 0x9197 },
+       { nvc8_grctx_init_9297_0, 0x9297 },
+       { nvc0_grctx_init_902d_0, 0x902d },
+       { nvc0_grctx_init_9039_0, 0x9039 },
+       { nvc0_grctx_init_90c0_0, 0x90c0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc8_grctx_init_setup_0[] = {
+       { 0x418800,   1, 0x04, 0x0006860a },
+       { 0x418808,   3, 0x04, 0x00000000 },
+       { 0x418828,   1, 0x04, 0x00008442 },
+       { 0x418830,   1, 0x04, 0x00000001 },
+       { 0x4188d8,   1, 0x04, 0x00000008 },
+       { 0x4188e0,   1, 0x04, 0x01000000 },
+       { 0x4188e8,   5, 0x04, 0x00000000 },
+       { 0x4188fc,   1, 0x04, 0x20100000 },
        {}
 };
 
-static struct nvc0_graph_init *
-nvc8_grctx_init_gpc[] = {
-       nvc0_grctx_init_gpc_0,
-       nvc0_grctx_init_gpc_1,
-       nvc8_grctx_init_tpc,
-       NULL
+static const struct nvc0_graph_pack
+nvc8_grctx_pack_gpc[] = {
+       { nvc0_grctx_init_gpc_unk_0 },
+       { nvc0_grctx_init_prop_0 },
+       { nvc0_grctx_init_gpc_unk_1 },
+       { nvc8_grctx_init_setup_0 },
+       { nvc0_grctx_init_zcull_0 },
+       { nvc0_grctx_init_crstr_0 },
+       { nvc0_grctx_init_gpm_0 },
+       { nvc0_grctx_init_gcc_0 },
+       {}
 };
 
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
 struct nouveau_oclass *
 nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) {
        .base.handle = NV_ENGCTX(GR, 0xc8),
@@ -360,11 +342,13 @@ nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) {
                .rd32 = _nouveau_graph_context_rd32,
                .wr32 = _nouveau_graph_context_wr32,
        },
-       .main = nvc0_grctx_generate_main,
-       .mods = nvc0_grctx_generate_mods,
-       .unkn = nvc0_grctx_generate_unkn,
-       .hub  = nvc0_grctx_init_hub,
-       .gpc  = nvc8_grctx_init_gpc,
-       .icmd = nvc8_grctx_init_icmd,
-       .mthd = nvc8_grctx_init_mthd,
+       .main  = nvc0_grctx_generate_main,
+       .mods  = nvc0_grctx_generate_mods,
+       .unkn  = nvc0_grctx_generate_unkn,
+       .hub   = nvc0_grctx_pack_hub,
+       .gpc   = nvc8_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = nvc0_grctx_pack_tpc,
+       .icmd  = nvc8_grctx_pack_icmd,
+       .mthd  = nvc8_grctx_pack_mthd,
 }.base;
index c4740d5..1dbc8d7 100644 (file)
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "nvc0.h"
+#include "ctxnvc0.h"
 
-struct nvc0_graph_init
-nvd7_grctx_init_unk40xx[] = {
-       { 0x404004,  10, 0x04, 0x00000000 },
-       { 0x404044,   1, 0x04, 0x00000000 },
-       { 0x404094,   1, 0x04, 0x00000000 },
-       { 0x404098,  12, 0x04, 0x00000000 },
-       { 0x4040c8,   1, 0x04, 0xf0000087 },
-       { 0x4040d0,   6, 0x04, 0x00000000 },
-       { 0x4040e8,   1, 0x04, 0x00001000 },
-       { 0x4040f8,   1, 0x04, 0x00000000 },
-       { 0x404130,   1, 0x04, 0x00000000 },
-       { 0x404134,   1, 0x04, 0x00000000 },
-       { 0x404138,   1, 0x04, 0x20000040 },
-       { 0x404150,   1, 0x04, 0x0000002e },
-       { 0x404154,   1, 0x04, 0x00000400 },
-       { 0x404158,   1, 0x04, 0x00000200 },
-       { 0x404164,   1, 0x04, 0x00000055 },
-       { 0x404168,   1, 0x04, 0x00000000 },
-       { 0x404178,   2, 0x04, 0x00000000 },
-       { 0x404200,   8, 0x04, 0x00000000 },
-       {}
-};
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
 
-static struct nvc0_graph_init
-nvd7_grctx_init_unk58xx[] = {
+static const struct nvc0_graph_init
+nvd7_grctx_init_ds_0[] = {
        { 0x405800,   1, 0x04, 0x0f8000bf },
        { 0x405830,   1, 0x04, 0x02180324 },
        { 0x405834,   1, 0x04, 0x08000000 },
@@ -60,8 +41,10 @@ nvd7_grctx_init_unk58xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvd7_grctx_init_unk64xx[] = {
+static const struct nvc0_graph_init
+nvd7_grctx_init_pd_0[] = {
+       { 0x406020,   1, 0x04, 0x000103c1 },
+       { 0x406028,   4, 0x04, 0x00000001 },
        { 0x4064a8,   1, 0x04, 0x00000000 },
        { 0x4064ac,   1, 0x04, 0x00003fff },
        { 0x4064b4,   3, 0x04, 0x00000000 },
@@ -71,22 +54,22 @@ nvd7_grctx_init_unk64xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvd7_grctx_init_gpc_0[] = {
-       { 0x418380,   1, 0x04, 0x00000016 },
-       { 0x418400,   1, 0x04, 0x38004e00 },
-       { 0x418404,   1, 0x04, 0x71e0ffff },
-       { 0x41840c,   1, 0x04, 0x00001008 },
-       { 0x418410,   1, 0x04, 0x0fff0fff },
-       { 0x418414,   1, 0x04, 0x02200fff },
-       { 0x418450,   6, 0x04, 0x00000000 },
-       { 0x418468,   1, 0x04, 0x00000001 },
-       { 0x41846c,   2, 0x04, 0x00000000 },
-       { 0x418600,   1, 0x04, 0x0000001f },
-       { 0x418684,   1, 0x04, 0x0000000f },
-       { 0x418700,   1, 0x04, 0x00000002 },
-       { 0x418704,   1, 0x04, 0x00000080 },
-       { 0x418708,   3, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nvd7_grctx_pack_hub[] = {
+       { nvc0_grctx_init_main_0 },
+       { nvd9_grctx_init_fe_0 },
+       { nvc0_grctx_init_pri_0 },
+       { nvc0_grctx_init_memfmt_0 },
+       { nvd7_grctx_init_ds_0 },
+       { nvd7_grctx_init_pd_0 },
+       { nvc0_grctx_init_rstr2d_0 },
+       { nvc0_grctx_init_scc_0 },
+       { nvd9_grctx_init_be_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd7_grctx_init_setup_0[] = {
        { 0x418800,   1, 0x04, 0x7006860a },
        { 0x418808,   3, 0x04, 0x00000000 },
        { 0x418828,   1, 0x04, 0x00008442 },
@@ -95,34 +78,32 @@ nvd7_grctx_init_gpc_0[] = {
        { 0x4188e0,   1, 0x04, 0x01000000 },
        { 0x4188e8,   5, 0x04, 0x00000000 },
        { 0x4188fc,   1, 0x04, 0x20100018 },
-       { 0x41891c,   1, 0x04, 0x00ff00ff },
-       { 0x418924,   1, 0x04, 0x00000000 },
-       { 0x418928,   1, 0x04, 0x00ffff00 },
-       { 0x41892c,   1, 0x04, 0x0000ff00 },
-       { 0x418b00,   1, 0x04, 0x00000006 },
-       { 0x418b08,   1, 0x04, 0x0a418820 },
-       { 0x418b0c,   1, 0x04, 0x062080e6 },
-       { 0x418b10,   1, 0x04, 0x020398a4 },
-       { 0x418b14,   1, 0x04, 0x0e629062 },
-       { 0x418b18,   1, 0x04, 0x0a418820 },
-       { 0x418b1c,   1, 0x04, 0x000000e6 },
-       { 0x418bb8,   1, 0x04, 0x00000103 },
-       { 0x418c08,   1, 0x04, 0x00000001 },
-       { 0x418c10,   8, 0x04, 0x00000000 },
-       { 0x418c6c,   1, 0x04, 0x00000001 },
-       { 0x418c80,   1, 0x04, 0x20200004 },
-       { 0x418c8c,   1, 0x04, 0x00000001 },
-       { 0x419000,   1, 0x04, 0x00000780 },
-       { 0x419004,   2, 0x04, 0x00000000 },
-       { 0x419014,   1, 0x04, 0x00000004 },
        {}
 };
 
-static struct nvc0_graph_init
-nvd7_grctx_init_tpc[] = {
+static const struct nvc0_graph_pack
+nvd7_grctx_pack_gpc[] = {
+       { nvc0_grctx_init_gpc_unk_0 },
+       { nvd9_grctx_init_prop_0 },
+       { nvd9_grctx_init_gpc_unk_1 },
+       { nvd7_grctx_init_setup_0 },
+       { nvc0_grctx_init_zcull_0 },
+       { nvd9_grctx_init_crstr_0 },
+       { nvc1_grctx_init_gpm_0 },
+       { nvc0_grctx_init_gcc_0 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd7_grctx_init_pe_0[] = {
        { 0x419848,   1, 0x04, 0x00000000 },
        { 0x419864,   1, 0x04, 0x00000129 },
        { 0x419888,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd7_grctx_init_tex_0[] = {
        { 0x419a00,   1, 0x04, 0x000001f0 },
        { 0x419a04,   1, 0x04, 0x00000001 },
        { 0x419a08,   1, 0x04, 0x00000023 },
@@ -132,33 +113,46 @@ nvd7_grctx_init_tpc[] = {
        { 0x419a1c,   1, 0x04, 0x00008000 },
        { 0x419a20,   1, 0x04, 0x00000800 },
        { 0x419ac4,   1, 0x04, 0x0017f440 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd7_grctx_init_mpc_0[] = {
        { 0x419c00,   1, 0x04, 0x0000000a },
        { 0x419c04,   1, 0x04, 0x00000006 },
        { 0x419c08,   1, 0x04, 0x00000002 },
        { 0x419c20,   1, 0x04, 0x00000000 },
        { 0x419c24,   1, 0x04, 0x00084210 },
        { 0x419c28,   1, 0x04, 0x3efbefbe },
-       { 0x419cb0,   1, 0x04, 0x00020048 },
-       { 0x419ce8,   1, 0x04, 0x00000000 },
-       { 0x419cf4,   1, 0x04, 0x00000183 },
-       { 0x419e04,   3, 0x04, 0x00000000 },
-       { 0x419e10,   1, 0x04, 0x00000002 },
-       { 0x419e44,   1, 0x04, 0x001beff2 },
-       { 0x419e48,   1, 0x04, 0x00000000 },
-       { 0x419e4c,   1, 0x04, 0x0000000f },
-       { 0x419e50,  17, 0x04, 0x00000000 },
-       { 0x419e98,   1, 0x04, 0x00000000 },
-       { 0x419ee0,   1, 0x04, 0x00010110 },
-       { 0x419f30,  11, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nvd7_grctx_init_unk[] = {
+static const struct nvc0_graph_pack
+nvd7_grctx_pack_tpc[] = {
+       { nvd7_grctx_init_pe_0 },
+       { nvd7_grctx_init_tex_0 },
+       { nvd7_grctx_init_mpc_0 },
+       { nvc4_grctx_init_l1c_0 },
+       { nvd9_grctx_init_sm_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd7_grctx_init_pes_0[] = {
        { 0x41be24,   1, 0x04, 0x00000002 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd7_grctx_init_cbm_0[] = {
        { 0x41bec0,   1, 0x04, 0x12180000 },
        { 0x41bec4,   1, 0x04, 0x00003fff },
        { 0x41bee4,   1, 0x04, 0x03240218 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd7_grctx_init_wwdx_0[] = {
        { 0x41bf00,   1, 0x04, 0x0a418820 },
        { 0x41bf04,   1, 0x04, 0x062080e6 },
        { 0x41bf08,   1, 0x04, 0x020398a4 },
@@ -171,6 +165,18 @@ nvd7_grctx_init_unk[] = {
        {}
 };
 
+static const struct nvc0_graph_pack
+nvd7_grctx_pack_ppc[] = {
+       { nvd7_grctx_init_pes_0 },
+       { nvd7_grctx_init_cbm_0 },
+       { nvd7_grctx_init_wwdx_0 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
 static void
 nvd7_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
@@ -219,10 +225,11 @@ nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 
        nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
 
-       for (i = 0; oclass->hub[i]; i++)
-               nvc0_graph_mmio(priv, oclass->hub[i]);
-       for (i = 0; oclass->gpc[i]; i++)
-               nvc0_graph_mmio(priv, oclass->gpc[i]);
+       nvc0_graph_mmio(priv, oclass->hub);
+       nvc0_graph_mmio(priv, oclass->gpc);
+       nvc0_graph_mmio(priv, oclass->zcull);
+       nvc0_graph_mmio(priv, oclass->tpc);
+       nvc0_graph_mmio(priv, oclass->ppc);
 
        nv_wr32(priv, 0x404154, 0x00000000);
 
@@ -244,32 +251,6 @@ nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
        nv_mask(priv, 0x000260, 0x00000001, 0x00000001);
 }
 
-
-static struct nvc0_graph_init *
-nvd7_grctx_init_hub[] = {
-       nvc0_grctx_init_base,
-       nvd7_grctx_init_unk40xx,
-       nvc0_grctx_init_unk44xx,
-       nvc0_grctx_init_unk46xx,
-       nvc0_grctx_init_unk47xx,
-       nvd7_grctx_init_unk58xx,
-       nvc0_grctx_init_unk60xx,
-       nvd7_grctx_init_unk64xx,
-       nvc0_grctx_init_unk78xx,
-       nvc0_grctx_init_unk80xx,
-       nvd9_grctx_init_rop,
-       NULL
-};
-
-struct nvc0_graph_init *
-nvd7_grctx_init_gpc[] = {
-       nvd7_grctx_init_gpc_0,
-       nvc0_grctx_init_gpc_1,
-       nvd7_grctx_init_tpc,
-       nvd7_grctx_init_unk,
-       NULL
-};
-
 struct nouveau_oclass *
 nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) {
        .base.handle = NV_ENGCTX(GR, 0xd7),
@@ -281,11 +262,14 @@ nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) {
                .rd32 = _nouveau_graph_context_rd32,
                .wr32 = _nouveau_graph_context_wr32,
        },
-       .main = nvd7_grctx_generate_main,
-       .mods = nvd7_grctx_generate_mods,
-       .unkn = nve4_grctx_generate_unkn,
-       .hub  = nvd7_grctx_init_hub,
-       .gpc  = nvd7_grctx_init_gpc,
-       .icmd = nvd9_grctx_init_icmd,
-       .mthd = nvd9_grctx_init_mthd,
+       .main  = nvd7_grctx_generate_main,
+       .mods  = nvd7_grctx_generate_mods,
+       .unkn  = nve4_grctx_generate_unkn,
+       .hub   = nvd7_grctx_pack_hub,
+       .gpc   = nvd7_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = nvd7_grctx_pack_tpc,
+       .ppc   = nvd7_grctx_pack_ppc,
+       .icmd  = nvd9_grctx_pack_icmd,
+       .mthd  = nvd9_grctx_pack_mthd,
 }.base;
index a1102cb..c665fb7 100644 (file)
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "nvc0.h"
+#include "ctxnvc0.h"
 
-struct nvc0_graph_init
-nvd9_grctx_init_90c0[] = {
-       { 0x002700,   4, 0x40, 0x00000000 },
-       { 0x002720,   4, 0x40, 0x00000000 },
-       { 0x002704,   4, 0x40, 0x00000000 },
-       { 0x002724,   4, 0x40, 0x00000000 },
-       { 0x002708,   4, 0x40, 0x00000000 },
-       { 0x002728,   4, 0x40, 0x00000000 },
-       { 0x00270c,   8, 0x20, 0x00000000 },
-       { 0x002710,   4, 0x40, 0x00014000 },
-       { 0x002730,   4, 0x40, 0x00014000 },
-       { 0x002714,   4, 0x40, 0x00000040 },
-       { 0x002734,   4, 0x40, 0x00000040 },
-       { 0x00030c,   1, 0x04, 0x00000001 },
-       { 0x001944,   1, 0x04, 0x00000000 },
-       { 0x000758,   1, 0x04, 0x00000100 },
-       { 0x0002c4,   1, 0x04, 0x00000000 },
-       { 0x000790,   5, 0x04, 0x00000000 },
-       { 0x00077c,   1, 0x04, 0x00000000 },
-       { 0x000204,   3, 0x04, 0x00000000 },
-       { 0x000214,   1, 0x04, 0x00000000 },
-       { 0x00024c,   1, 0x04, 0x00000000 },
-       { 0x000d94,   1, 0x04, 0x00000001 },
-       { 0x001608,   2, 0x04, 0x00000000 },
-       { 0x001664,   1, 0x04, 0x00000000 },
-       {}
-};
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
 
-struct nvc0_graph_init
-nvd9_grctx_init_icmd[] = {
+static const struct nvc0_graph_init
+nvd9_grctx_init_icmd_0[] = {
        { 0x001000,   1, 0x01, 0x00000004 },
        { 0x0000a9,   1, 0x01, 0x0000ffff },
        { 0x000038,   1, 0x01, 0x0fac6881 },
@@ -171,8 +147,7 @@ nvd9_grctx_init_icmd[] = {
        { 0x000586,   1, 0x01, 0x00000040 },
        { 0x000582,   2, 0x01, 0x00000080 },
        { 0x0005c2,   1, 0x01, 0x00000001 },
-       { 0x000638,   1, 0x01, 0x00000001 },
-       { 0x000639,   1, 0x01, 0x00000001 },
+       { 0x000638,   2, 0x01, 0x00000001 },
        { 0x00063a,   1, 0x01, 0x00000002 },
        { 0x00063b,   2, 0x01, 0x00000001 },
        { 0x00063d,   1, 0x01, 0x00000002 },
@@ -233,15 +208,13 @@ nvd9_grctx_init_icmd[] = {
        { 0x000787,   1, 0x01, 0x000000cf },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x000836,   1, 0x01, 0x00000001 },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x00080c,   1, 0x01, 0x00000002 },
        { 0x00080d,   2, 0x01, 0x00000100 },
@@ -267,14 +240,12 @@ nvd9_grctx_init_icmd[] = {
        { 0x0006b1,   1, 0x01, 0x00000011 },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x01e100,   1, 0x01, 0x00000001 },
        { 0x001000,   1, 0x01, 0x00000014 },
@@ -299,18 +270,56 @@ nvd9_grctx_init_icmd[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvd9_grctx_init_unk40xx[] = {
-       { 0x404004,  11, 0x04, 0x00000000 },
+const struct nvc0_graph_pack
+nvd9_grctx_pack_icmd[] = {
+       { nvd9_grctx_init_icmd_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd9_grctx_init_90c0_0[] = {
+       { 0x002700,   8, 0x20, 0x00000000 },
+       { 0x002704,   8, 0x20, 0x00000000 },
+       { 0x002708,   8, 0x20, 0x00000000 },
+       { 0x00270c,   8, 0x20, 0x00000000 },
+       { 0x002710,   8, 0x20, 0x00014000 },
+       { 0x002714,   8, 0x20, 0x00000040 },
+       { 0x00030c,   1, 0x04, 0x00000001 },
+       { 0x001944,   1, 0x04, 0x00000000 },
+       { 0x000758,   1, 0x04, 0x00000100 },
+       { 0x0002c4,   1, 0x04, 0x00000000 },
+       { 0x000790,   5, 0x04, 0x00000000 },
+       { 0x00077c,   1, 0x04, 0x00000000 },
+       { 0x000204,   3, 0x04, 0x00000000 },
+       { 0x000214,   1, 0x04, 0x00000000 },
+       { 0x00024c,   1, 0x04, 0x00000000 },
+       { 0x000d94,   1, 0x04, 0x00000001 },
+       { 0x001608,   2, 0x04, 0x00000000 },
+       { 0x001664,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_pack
+nvd9_grctx_pack_mthd[] = {
+       { nvc1_grctx_init_9097_0, 0x9097 },
+       { nvc8_grctx_init_9197_0, 0x9197 },
+       { nvc8_grctx_init_9297_0, 0x9297 },
+       { nvc0_grctx_init_902d_0, 0x902d },
+       { nvc0_grctx_init_9039_0, 0x9039 },
+       { nvd9_grctx_init_90c0_0, 0x90c0 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd9_grctx_init_fe_0[] = {
+       { 0x404004,  10, 0x04, 0x00000000 },
        { 0x404044,   1, 0x04, 0x00000000 },
-       { 0x404094,   1, 0x04, 0x00000000 },
-       { 0x404098,  12, 0x04, 0x00000000 },
+       { 0x404094,  13, 0x04, 0x00000000 },
        { 0x4040c8,   1, 0x04, 0xf0000087 },
        { 0x4040d0,   6, 0x04, 0x00000000 },
        { 0x4040e8,   1, 0x04, 0x00001000 },
        { 0x4040f8,   1, 0x04, 0x00000000 },
-       { 0x404130,   1, 0x04, 0x00000000 },
-       { 0x404134,   1, 0x04, 0x00000000 },
+       { 0x404130,   2, 0x04, 0x00000000 },
        { 0x404138,   1, 0x04, 0x20000040 },
        { 0x404150,   1, 0x04, 0x0000002e },
        { 0x404154,   1, 0x04, 0x00000400 },
@@ -322,8 +331,8 @@ nvd9_grctx_init_unk40xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvd9_grctx_init_unk58xx[] = {
+static const struct nvc0_graph_init
+nvd9_grctx_init_ds_0[] = {
        { 0x405800,   1, 0x04, 0x0f8000bf },
        { 0x405830,   1, 0x04, 0x02180218 },
        { 0x405834,   1, 0x04, 0x08000000 },
@@ -335,8 +344,10 @@ nvd9_grctx_init_unk58xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvd9_grctx_init_unk64xx[] = {
+static const struct nvc0_graph_init
+nvd9_grctx_init_pd_0[] = {
+       { 0x406020,   1, 0x04, 0x000103c1 },
+       { 0x406028,   4, 0x04, 0x00000001 },
        { 0x4064a8,   1, 0x04, 0x00000000 },
        { 0x4064ac,   1, 0x04, 0x00003fff },
        { 0x4064b4,   3, 0x04, 0x00000000 },
@@ -345,21 +356,34 @@ nvd9_grctx_init_unk64xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvd9_grctx_init_rop[] = {
+const struct nvc0_graph_init
+nvd9_grctx_init_be_0[] = {
        { 0x408800,   1, 0x04, 0x02802a3c },
        { 0x408804,   1, 0x04, 0x00000040 },
        { 0x408808,   1, 0x04, 0x1043e005 },
        { 0x408900,   1, 0x04, 0x3080b801 },
-       { 0x408904,   1, 0x04, 0x1043e005 },
+       { 0x408904,   1, 0x04, 0x62000001 },
        { 0x408908,   1, 0x04, 0x00c8102f },
        { 0x408980,   1, 0x04, 0x0000011d },
        {}
 };
 
-static struct nvc0_graph_init
-nvd9_grctx_init_gpc_0[] = {
-       { 0x418380,   1, 0x04, 0x00000016 },
+static const struct nvc0_graph_pack
+nvd9_grctx_pack_hub[] = {
+       { nvc0_grctx_init_main_0 },
+       { nvd9_grctx_init_fe_0 },
+       { nvc0_grctx_init_pri_0 },
+       { nvc0_grctx_init_memfmt_0 },
+       { nvd9_grctx_init_ds_0 },
+       { nvd9_grctx_init_pd_0 },
+       { nvc0_grctx_init_rstr2d_0 },
+       { nvc0_grctx_init_scc_0 },
+       { nvd9_grctx_init_be_0 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd9_grctx_init_prop_0[] = {
        { 0x418400,   1, 0x04, 0x38004e00 },
        { 0x418404,   1, 0x04, 0x71e0ffff },
        { 0x41840c,   1, 0x04, 0x00001008 },
@@ -368,11 +392,21 @@ nvd9_grctx_init_gpc_0[] = {
        { 0x418450,   6, 0x04, 0x00000000 },
        { 0x418468,   1, 0x04, 0x00000001 },
        { 0x41846c,   2, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd9_grctx_init_gpc_unk_1[] = {
        { 0x418600,   1, 0x04, 0x0000001f },
        { 0x418684,   1, 0x04, 0x0000000f },
        { 0x418700,   1, 0x04, 0x00000002 },
        { 0x418704,   1, 0x04, 0x00000080 },
        { 0x418708,   3, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd9_grctx_init_setup_0[] = {
        { 0x418800,   1, 0x04, 0x7006860a },
        { 0x418808,   3, 0x04, 0x00000000 },
        { 0x418828,   1, 0x04, 0x00008442 },
@@ -381,10 +415,11 @@ nvd9_grctx_init_gpc_0[] = {
        { 0x4188e0,   1, 0x04, 0x01000000 },
        { 0x4188e8,   5, 0x04, 0x00000000 },
        { 0x4188fc,   1, 0x04, 0x20100008 },
-       { 0x41891c,   1, 0x04, 0x00ff00ff },
-       { 0x418924,   1, 0x04, 0x00000000 },
-       { 0x418928,   1, 0x04, 0x00ffff00 },
-       { 0x41892c,   1, 0x04, 0x0000ff00 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd9_grctx_init_crstr_0[] = {
        { 0x418b00,   1, 0x04, 0x00000006 },
        { 0x418b08,   1, 0x04, 0x0a418820 },
        { 0x418b0c,   1, 0x04, 0x062080e6 },
@@ -393,24 +428,24 @@ nvd9_grctx_init_gpc_0[] = {
        { 0x418b18,   1, 0x04, 0x0a418820 },
        { 0x418b1c,   1, 0x04, 0x000000e6 },
        { 0x418bb8,   1, 0x04, 0x00000103 },
-       { 0x418c08,   1, 0x04, 0x00000001 },
-       { 0x418c10,   8, 0x04, 0x00000000 },
-       { 0x418c6c,   1, 0x04, 0x00000001 },
-       { 0x418c80,   1, 0x04, 0x20200004 },
-       { 0x418c8c,   1, 0x04, 0x00000001 },
-       { 0x419000,   1, 0x04, 0x00000780 },
-       { 0x419004,   2, 0x04, 0x00000000 },
-       { 0x419014,   1, 0x04, 0x00000004 },
        {}
 };
 
-static struct nvc0_graph_init
-nvd9_grctx_init_tpc[] = {
-       { 0x419818,   1, 0x04, 0x00000000 },
-       { 0x41983c,   1, 0x04, 0x00038bc7 },
-       { 0x419848,   1, 0x04, 0x00000000 },
-       { 0x419864,   1, 0x04, 0x00000129 },
-       { 0x419888,   1, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nvd9_grctx_pack_gpc[] = {
+       { nvc0_grctx_init_gpc_unk_0 },
+       { nvd9_grctx_init_prop_0 },
+       { nvd9_grctx_init_gpc_unk_1 },
+       { nvd9_grctx_init_setup_0 },
+       { nvc0_grctx_init_zcull_0 },
+       { nvd9_grctx_init_crstr_0 },
+       { nvc1_grctx_init_gpm_0 },
+       { nvc0_grctx_init_gcc_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd9_grctx_init_tex_0[] = {
        { 0x419a00,   1, 0x04, 0x000001f0 },
        { 0x419a04,   1, 0x04, 0x00000001 },
        { 0x419a08,   1, 0x04, 0x00000023 },
@@ -420,27 +455,22 @@ nvd9_grctx_init_tpc[] = {
        { 0x419a1c,   1, 0x04, 0x00000000 },
        { 0x419a20,   1, 0x04, 0x00000800 },
        { 0x419ac4,   1, 0x04, 0x0017f440 },
-       { 0x419b00,   1, 0x04, 0x0a418820 },
-       { 0x419b04,   1, 0x04, 0x062080e6 },
-       { 0x419b08,   1, 0x04, 0x020398a4 },
-       { 0x419b0c,   1, 0x04, 0x0e629062 },
-       { 0x419b10,   1, 0x04, 0x0a418820 },
-       { 0x419b14,   1, 0x04, 0x000000e6 },
-       { 0x419bd0,   1, 0x04, 0x00900103 },
-       { 0x419be0,   1, 0x04, 0x00400001 },
-       { 0x419be4,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd9_grctx_init_mpc_0[] = {
        { 0x419c00,   1, 0x04, 0x0000000a },
        { 0x419c04,   1, 0x04, 0x00000006 },
        { 0x419c08,   1, 0x04, 0x00000002 },
        { 0x419c20,   1, 0x04, 0x00000000 },
        { 0x419c24,   1, 0x04, 0x00084210 },
        { 0x419c28,   1, 0x04, 0x3cf3cf3c },
-       { 0x419cb0,   1, 0x04, 0x00020048 },
-       { 0x419ce8,   1, 0x04, 0x00000000 },
-       { 0x419cf4,   1, 0x04, 0x00000183 },
-       { 0x419d20,   1, 0x04, 0x12180000 },
-       { 0x419d24,   1, 0x04, 0x00001fff },
-       { 0x419d44,   1, 0x04, 0x02180218 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd9_grctx_init_sm_0[] = {
        { 0x419e04,   3, 0x04, 0x00000000 },
        { 0x419e10,   1, 0x04, 0x00000002 },
        { 0x419e44,   1, 0x04, 0x001beff2 },
@@ -453,47 +483,21 @@ nvd9_grctx_init_tpc[] = {
        {}
 };
 
-static struct nvc0_graph_init *
-nvd9_grctx_init_hub[] = {
-       nvc0_grctx_init_base,
-       nvd9_grctx_init_unk40xx,
-       nvc0_grctx_init_unk44xx,
-       nvc0_grctx_init_unk46xx,
-       nvc0_grctx_init_unk47xx,
-       nvd9_grctx_init_unk58xx,
-       nvc0_grctx_init_unk60xx,
-       nvd9_grctx_init_unk64xx,
-       nvc0_grctx_init_unk78xx,
-       nvc0_grctx_init_unk80xx,
-       nvd9_grctx_init_rop,
-       NULL
-};
-
-struct nvc0_graph_init *
-nvd9_grctx_init_gpc[] = {
-       nvd9_grctx_init_gpc_0,
-       nvc0_grctx_init_gpc_1,
-       nvd9_grctx_init_tpc,
-       NULL
-};
-
-struct nvc0_graph_init
-nvd9_grctx_init_mthd_magic[] = {
-       { 0x3410, 1, 0x04, 0x80002006 },
+static const struct nvc0_graph_pack
+nvd9_grctx_pack_tpc[] = {
+       { nvc1_grctx_init_pe_0 },
+       { nvd9_grctx_init_tex_0 },
+       { nvc1_grctx_init_wwdx_0 },
+       { nvd9_grctx_init_mpc_0 },
+       { nvc4_grctx_init_l1c_0 },
+       { nvc1_grctx_init_tpccs_0 },
+       { nvd9_grctx_init_sm_0 },
        {}
 };
 
-struct nvc0_graph_mthd
-nvd9_grctx_init_mthd[] = {
-       { 0x9097, nvc1_grctx_init_9097, },
-       { 0x9197, nvc8_grctx_init_9197, },
-       { 0x9297, nvc8_grctx_init_9297, },
-       { 0x902d, nvc0_grctx_init_902d, },
-       { 0x9039, nvc0_grctx_init_9039, },
-       { 0x90c0, nvd9_grctx_init_90c0, },
-       { 0x902d, nvd9_grctx_init_mthd_magic, },
-       {}
-};
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
 
 struct nouveau_oclass *
 nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) {
@@ -506,11 +510,13 @@ nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) {
                .rd32 = _nouveau_graph_context_rd32,
                .wr32 = _nouveau_graph_context_wr32,
        },
-       .main = nvc0_grctx_generate_main,
-       .mods = nvc1_grctx_generate_mods,
-       .unkn = nvc1_grctx_generate_unkn,
-       .hub  = nvd9_grctx_init_hub,
-       .gpc  = nvd9_grctx_init_gpc,
-       .icmd = nvd9_grctx_init_icmd,
-       .mthd = nvd9_grctx_init_mthd,
+       .main  = nvc0_grctx_generate_main,
+       .mods  = nvc1_grctx_generate_mods,
+       .unkn  = nvc1_grctx_generate_unkn,
+       .hub   = nvd9_grctx_pack_hub,
+       .gpc   = nvd9_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = nvd9_grctx_pack_tpc,
+       .icmd  = nvd9_grctx_pack_icmd,
+       .mthd  = nvd9_grctx_pack_mthd,
 }.base;
index e2de73e..49a14b1 100644 (file)
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "nvc0.h"
+#include "ctxnvc0.h"
 
-struct nvc0_graph_init
-nve4_grctx_init_icmd[] = {
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct nvc0_graph_init
+nve4_grctx_init_icmd_0[] = {
        { 0x001000,   1, 0x01, 0x00000004 },
        { 0x000039,   3, 0x01, 0x00000000 },
        { 0x0000a9,   1, 0x01, 0x0000ffff },
@@ -138,8 +142,7 @@ nve4_grctx_init_icmd[] = {
        { 0x000586,   1, 0x01, 0x00000040 },
        { 0x000582,   2, 0x01, 0x00000080 },
        { 0x0005c2,   1, 0x01, 0x00000001 },
-       { 0x000638,   1, 0x01, 0x00000001 },
-       { 0x000639,   1, 0x01, 0x00000001 },
+       { 0x000638,   2, 0x01, 0x00000001 },
        { 0x00063a,   1, 0x01, 0x00000002 },
        { 0x00063b,   2, 0x01, 0x00000001 },
        { 0x00063d,   1, 0x01, 0x00000002 },
@@ -197,15 +200,13 @@ nve4_grctx_init_icmd[] = {
        { 0x000787,   1, 0x01, 0x000000cf },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x000836,   1, 0x01, 0x00000001 },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x000b07,   1, 0x01, 0x00000002 },
        { 0x000b08,   2, 0x01, 0x00000100 },
@@ -231,14 +232,12 @@ nve4_grctx_init_icmd[] = {
        { 0x0006b1,   1, 0x01, 0x00000011 },
        { 0x00078c,   1, 0x01, 0x00000008 },
        { 0x000792,   1, 0x01, 0x00000001 },
-       { 0x000794,   1, 0x01, 0x00000001 },
-       { 0x000795,   2, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
        { 0x000797,   1, 0x01, 0x000000cf },
        { 0x00079a,   1, 0x01, 0x00000002 },
        { 0x000833,   1, 0x01, 0x04444480 },
        { 0x0007a1,   1, 0x01, 0x00000001 },
-       { 0x0007a3,   1, 0x01, 0x00000001 },
-       { 0x0007a4,   2, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
        { 0x000831,   1, 0x01, 0x00000004 },
        { 0x01e100,   1, 0x01, 0x00000001 },
        { 0x001000,   1, 0x01, 0x00000008 },
@@ -273,8 +272,14 @@ nve4_grctx_init_icmd[] = {
        {}
 };
 
-struct nvc0_graph_init
-nve4_grctx_init_a097[] = {
+static const struct nvc0_graph_pack
+nve4_grctx_pack_icmd[] = {
+       { nve4_grctx_init_icmd_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_grctx_init_a097_0[] = {
        { 0x000800,   8, 0x40, 0x00000000 },
        { 0x000804,   8, 0x40, 0x00000000 },
        { 0x000808,   8, 0x40, 0x00000400 },
@@ -517,8 +522,7 @@ nve4_grctx_init_a097[] = {
        { 0x001350,   1, 0x04, 0x00000002 },
        { 0x001358,   1, 0x04, 0x00000001 },
        { 0x0012e4,   1, 0x04, 0x00000000 },
-       { 0x00131c,   1, 0x04, 0x00000000 },
-       { 0x001320,   3, 0x04, 0x00000000 },
+       { 0x00131c,   4, 0x04, 0x00000000 },
        { 0x0019c0,   1, 0x04, 0x00000000 },
        { 0x001140,   1, 0x04, 0x00000000 },
        { 0x0019c4,   1, 0x04, 0x00000000 },
@@ -574,19 +578,24 @@ nve4_grctx_init_a097[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nve4_grctx_init_unk40xx[] = {
+static const struct nvc0_graph_pack
+nve4_grctx_pack_mthd[] = {
+       { nve4_grctx_init_a097_0, 0xa097 },
+       { nvc0_grctx_init_902d_0, 0x902d },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_grctx_init_fe_0[] = {
        { 0x404010,   5, 0x04, 0x00000000 },
        { 0x404024,   1, 0x04, 0x0000e000 },
        { 0x404028,   1, 0x04, 0x00000000 },
-       { 0x4040a8,   1, 0x04, 0x00000000 },
-       { 0x4040ac,   7, 0x04, 0x00000000 },
+       { 0x4040a8,   8, 0x04, 0x00000000 },
        { 0x4040c8,   1, 0x04, 0xf800008f },
        { 0x4040d0,   6, 0x04, 0x00000000 },
        { 0x4040e8,   1, 0x04, 0x00001000 },
        { 0x4040f8,   1, 0x04, 0x00000000 },
-       { 0x404130,   1, 0x04, 0x00000000 },
-       { 0x404134,   1, 0x04, 0x00000000 },
+       { 0x404130,   2, 0x04, 0x00000000 },
        { 0x404138,   1, 0x04, 0x20000040 },
        { 0x404150,   1, 0x04, 0x0000002e },
        { 0x404154,   1, 0x04, 0x00000400 },
@@ -597,8 +606,8 @@ nve4_grctx_init_unk40xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nve4_grctx_init_unk46xx[] = {
+const struct nvc0_graph_init
+nve4_grctx_init_memfmt_0[] = {
        { 0x404604,   1, 0x04, 0x00000014 },
        { 0x404608,   1, 0x04, 0x00000000 },
        { 0x40460c,   1, 0x04, 0x00003fff },
@@ -614,11 +623,6 @@ nve4_grctx_init_unk46xx[] = {
        { 0x4046a0,   1, 0x04, 0x007f0080 },
        { 0x4046a4,   8, 0x04, 0x00000000 },
        { 0x4046c8,   3, 0x04, 0x00000000 },
-       {}
-};
-
-struct nvc0_graph_init
-nve4_grctx_init_unk47xx[] = {
        { 0x404700,   3, 0x04, 0x00000000 },
        { 0x404718,   7, 0x04, 0x00000000 },
        { 0x404734,   1, 0x04, 0x00000100 },
@@ -628,8 +632,8 @@ nve4_grctx_init_unk47xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nve4_grctx_init_unk58xx[] = {
+const struct nvc0_graph_init
+nve4_grctx_init_ds_0[] = {
        { 0x405800,   1, 0x04, 0x0f8000bf },
        { 0x405830,   1, 0x04, 0x02180648 },
        { 0x405834,   1, 0x04, 0x08000000 },
@@ -641,22 +645,17 @@ nve4_grctx_init_unk58xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nve4_grctx_init_unk5bxx[] = {
+static const struct nvc0_graph_init
+nve4_grctx_init_cwd_0[] = {
        { 0x405b00,   1, 0x04, 0x00000000 },
        { 0x405b10,   1, 0x04, 0x00001000 },
        {}
 };
 
-static struct nvc0_graph_init
-nve4_grctx_init_unk60xx[] = {
+static const struct nvc0_graph_init
+nve4_grctx_init_pd_0[] = {
        { 0x406020,   1, 0x04, 0x004103c1 },
        { 0x406028,   4, 0x04, 0x00000001 },
-       {}
-};
-
-static struct nvc0_graph_init
-nve4_grctx_init_unk64xx[] = {
        { 0x4064a8,   1, 0x04, 0x00000000 },
        { 0x4064ac,   1, 0x04, 0x00003fff },
        { 0x4064b4,   2, 0x04, 0x00000000 },
@@ -668,14 +667,14 @@ nve4_grctx_init_unk64xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nve4_grctx_init_unk70xx[] = {
+static const struct nvc0_graph_init
+nve4_grctx_init_sked_0[] = {
        { 0x407040,   1, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nve4_grctx_init_unk80xx[] = {
+const struct nvc0_graph_init
+nve4_grctx_init_scc_0[] = {
        { 0x408000,   2, 0x04, 0x00000000 },
        { 0x408008,   1, 0x04, 0x00000030 },
        { 0x40800c,   2, 0x04, 0x00000000 },
@@ -685,8 +684,8 @@ nve4_grctx_init_unk80xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nve4_grctx_init_rop[] = {
+static const struct nvc0_graph_init
+nve4_grctx_init_be_0[] = {
        { 0x408800,   1, 0x04, 0x02802a3c },
        { 0x408804,   1, 0x04, 0x00000040 },
        { 0x408808,   1, 0x04, 0x1043e005 },
@@ -698,22 +697,24 @@ nve4_grctx_init_rop[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nve4_grctx_init_gpc_0[] = {
-       { 0x418380,   1, 0x04, 0x00000016 },
-       { 0x418400,   1, 0x04, 0x38004e00 },
-       { 0x418404,   1, 0x04, 0x71e0ffff },
-       { 0x41840c,   1, 0x04, 0x00001008 },
-       { 0x418410,   1, 0x04, 0x0fff0fff },
-       { 0x418414,   1, 0x04, 0x02200fff },
-       { 0x418450,   6, 0x04, 0x00000000 },
-       { 0x418468,   1, 0x04, 0x00000001 },
-       { 0x41846c,   2, 0x04, 0x00000000 },
-       { 0x418600,   1, 0x04, 0x0000001f },
-       { 0x418684,   1, 0x04, 0x0000000f },
-       { 0x418700,   1, 0x04, 0x00000002 },
-       { 0x418704,   1, 0x04, 0x00000080 },
-       { 0x418708,   3, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nve4_grctx_pack_hub[] = {
+       { nvc0_grctx_init_main_0 },
+       { nve4_grctx_init_fe_0 },
+       { nvc0_grctx_init_pri_0 },
+       { nve4_grctx_init_memfmt_0 },
+       { nve4_grctx_init_ds_0 },
+       { nve4_grctx_init_cwd_0 },
+       { nve4_grctx_init_pd_0 },
+       { nve4_grctx_init_sked_0 },
+       { nvc0_grctx_init_rstr2d_0 },
+       { nve4_grctx_init_scc_0 },
+       { nve4_grctx_init_be_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_grctx_init_setup_0[] = {
        { 0x418800,   1, 0x04, 0x7006860a },
        { 0x418808,   3, 0x04, 0x00000000 },
        { 0x418828,   1, 0x04, 0x00000044 },
@@ -722,35 +723,35 @@ nve4_grctx_init_gpc_0[] = {
        { 0x4188e0,   1, 0x04, 0x01000000 },
        { 0x4188e8,   5, 0x04, 0x00000000 },
        { 0x4188fc,   1, 0x04, 0x20100018 },
-       { 0x41891c,   1, 0x04, 0x00ff00ff },
-       { 0x418924,   1, 0x04, 0x00000000 },
-       { 0x418928,   1, 0x04, 0x00ffff00 },
-       { 0x41892c,   1, 0x04, 0x0000ff00 },
-       { 0x418b00,   1, 0x04, 0x00000006 },
-       { 0x418b08,   1, 0x04, 0x0a418820 },
-       { 0x418b0c,   1, 0x04, 0x062080e6 },
-       { 0x418b10,   1, 0x04, 0x020398a4 },
-       { 0x418b14,   1, 0x04, 0x0e629062 },
-       { 0x418b18,   1, 0x04, 0x0a418820 },
-       { 0x418b1c,   1, 0x04, 0x000000e6 },
-       { 0x418bb8,   1, 0x04, 0x00000103 },
+       {}
+};
+
+const struct nvc0_graph_init
+nve4_grctx_init_gpm_0[] = {
        { 0x418c08,   1, 0x04, 0x00000001 },
        { 0x418c10,   8, 0x04, 0x00000000 },
        { 0x418c40,   1, 0x04, 0xffffffff },
        { 0x418c6c,   1, 0x04, 0x00000001 },
        { 0x418c80,   1, 0x04, 0x20200004 },
        { 0x418c8c,   1, 0x04, 0x00000001 },
-       { 0x419000,   1, 0x04, 0x00000780 },
-       { 0x419004,   2, 0x04, 0x00000000 },
-       { 0x419014,   1, 0x04, 0x00000004 },
        {}
 };
 
-static struct nvc0_graph_init
-nve4_grctx_init_tpc[] = {
-       { 0x419848,   1, 0x04, 0x00000000 },
-       { 0x419864,   1, 0x04, 0x00000129 },
-       { 0x419888,   1, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nve4_grctx_pack_gpc[] = {
+       { nvc0_grctx_init_gpc_unk_0 },
+       { nvd9_grctx_init_prop_0 },
+       { nvd9_grctx_init_gpc_unk_1 },
+       { nve4_grctx_init_setup_0 },
+       { nvc0_grctx_init_zcull_0 },
+       { nvd9_grctx_init_crstr_0 },
+       { nve4_grctx_init_gpm_0 },
+       { nvc0_grctx_init_gcc_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_grctx_init_tex_0[] = {
        { 0x419a00,   1, 0x04, 0x000000f0 },
        { 0x419a04,   1, 0x04, 0x00000001 },
        { 0x419a08,   1, 0x04, 0x00000021 },
@@ -761,14 +762,29 @@ nve4_grctx_init_tpc[] = {
        { 0x419a20,   1, 0x04, 0x00000800 },
        { 0x419a30,   1, 0x04, 0x00000001 },
        { 0x419ac4,   1, 0x04, 0x0037f440 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_grctx_init_mpc_0[] = {
        { 0x419c00,   1, 0x04, 0x0000000a },
        { 0x419c04,   1, 0x04, 0x80000006 },
        { 0x419c08,   1, 0x04, 0x00000002 },
        { 0x419c20,   1, 0x04, 0x00000000 },
        { 0x419c24,   1, 0x04, 0x00084210 },
        { 0x419c28,   1, 0x04, 0x3efbefbe },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_grctx_init_l1c_0[] = {
        { 0x419ce8,   1, 0x04, 0x00000000 },
        { 0x419cf4,   1, 0x04, 0x00003203 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_grctx_init_sm_0[] = {
        { 0x419e04,   3, 0x04, 0x00000000 },
        { 0x419e10,   1, 0x04, 0x00000402 },
        { 0x419e44,   1, 0x04, 0x0013eff2 },
@@ -782,28 +798,46 @@ nve4_grctx_init_tpc[] = {
        { 0x419f58,   1, 0x04, 0x00000000 },
        { 0x419f70,   1, 0x04, 0x00000000 },
        { 0x419f78,   1, 0x04, 0x0000000b },
-       { 0x419f7c,   1, 0x04, 0x0000027a },
+       { 0x419f7c,   1, 0x04, 0x0000027c },
+       {}
+};
+
+static const struct nvc0_graph_pack
+nve4_grctx_pack_tpc[] = {
+       { nvd7_grctx_init_pe_0 },
+       { nve4_grctx_init_tex_0 },
+       { nve4_grctx_init_mpc_0 },
+       { nve4_grctx_init_l1c_0 },
+       { nve4_grctx_init_sm_0 },
        {}
 };
 
-static struct nvc0_graph_init
-nve4_grctx_init_unk[] = {
+const struct nvc0_graph_init
+nve4_grctx_init_pes_0[] = {
        { 0x41be24,   1, 0x04, 0x00000006 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_grctx_init_cbm_0[] = {
        { 0x41bec0,   1, 0x04, 0x12180000 },
        { 0x41bec4,   1, 0x04, 0x00037f7f },
        { 0x41bee4,   1, 0x04, 0x06480430 },
-       { 0x41bf00,   1, 0x04, 0x0a418820 },
-       { 0x41bf04,   1, 0x04, 0x062080e6 },
-       { 0x41bf08,   1, 0x04, 0x020398a4 },
-       { 0x41bf0c,   1, 0x04, 0x0e629062 },
-       { 0x41bf10,   1, 0x04, 0x0a418820 },
-       { 0x41bf14,   1, 0x04, 0x000000e6 },
-       { 0x41bfd0,   1, 0x04, 0x00900103 },
-       { 0x41bfe0,   1, 0x04, 0x00400001 },
-       { 0x41bfe4,   1, 0x04, 0x00000000 },
        {}
 };
 
+static const struct nvc0_graph_pack
+nve4_grctx_pack_ppc[] = {
+       { nve4_grctx_init_pes_0 },
+       { nve4_grctx_init_cbm_0 },
+       { nvd7_grctx_init_wwdx_0 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
 static void
 nve4_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
@@ -925,10 +959,11 @@ nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 
        nv_mask(priv, 0x000260, 0x00000001, 0x00000000);
 
-       for (i = 0; oclass->hub[i]; i++)
-               nvc0_graph_mmio(priv, oclass->hub[i]);
-       for (i = 0; oclass->gpc[i]; i++)
-               nvc0_graph_mmio(priv, oclass->gpc[i]);
+       nvc0_graph_mmio(priv, oclass->hub);
+       nvc0_graph_mmio(priv, oclass->gpc);
+       nvc0_graph_mmio(priv, oclass->zcull);
+       nvc0_graph_mmio(priv, oclass->tpc);
+       nvc0_graph_mmio(priv, oclass->ppc);
 
        nv_wr32(priv, 0x404154, 0x00000000);
 
@@ -962,41 +997,6 @@ nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
        nv_mask(priv, 0x41be10, 0x00800000, 0x00800000);
 }
 
-static struct nvc0_graph_init *
-nve4_grctx_init_hub[] = {
-       nvc0_grctx_init_base,
-       nve4_grctx_init_unk40xx,
-       nvc0_grctx_init_unk44xx,
-       nve4_grctx_init_unk46xx,
-       nve4_grctx_init_unk47xx,
-       nve4_grctx_init_unk58xx,
-       nve4_grctx_init_unk5bxx,
-       nve4_grctx_init_unk60xx,
-       nve4_grctx_init_unk64xx,
-       nve4_grctx_init_unk70xx,
-       nvc0_grctx_init_unk78xx,
-       nve4_grctx_init_unk80xx,
-       nve4_grctx_init_rop,
-       NULL
-};
-
-struct nvc0_graph_init *
-nve4_grctx_init_gpc[] = {
-       nve4_grctx_init_gpc_0,
-       nvc0_grctx_init_gpc_1,
-       nve4_grctx_init_tpc,
-       nve4_grctx_init_unk,
-       NULL
-};
-
-static struct nvc0_graph_mthd
-nve4_grctx_init_mthd[] = {
-       { 0xa097, nve4_grctx_init_a097, },
-       { 0x902d, nvc0_grctx_init_902d, },
-       { 0x902d, nvc0_grctx_init_mthd_magic, },
-       {}
-};
-
 struct nouveau_oclass *
 nve4_grctx_oclass = &(struct nvc0_grctx_oclass) {
        .base.handle = NV_ENGCTX(GR, 0xe4),
@@ -1008,11 +1008,14 @@ nve4_grctx_oclass = &(struct nvc0_grctx_oclass) {
                .rd32 = _nouveau_graph_context_rd32,
                .wr32 = _nouveau_graph_context_wr32,
        },
-       .main = nve4_grctx_generate_main,
-       .mods = nve4_grctx_generate_mods,
-       .unkn = nve4_grctx_generate_unkn,
-       .hub  = nve4_grctx_init_hub,
-       .gpc  = nve4_grctx_init_gpc,
-       .icmd = nve4_grctx_init_icmd,
-       .mthd = nve4_grctx_init_mthd,
+       .main  = nve4_grctx_generate_main,
+       .mods  = nve4_grctx_generate_mods,
+       .unkn  = nve4_grctx_generate_unkn,
+       .hub   = nve4_grctx_pack_hub,
+       .gpc   = nve4_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = nve4_grctx_pack_tpc,
+       .ppc   = nve4_grctx_pack_ppc,
+       .icmd  = nve4_grctx_pack_icmd,
+       .mthd  = nve4_grctx_pack_mthd,
 }.base;
index 44012c3..0fab95e 100644 (file)
  * Authors: Ben Skeggs <bskeggs@redhat.com>
  */
 
-#include "nvc0.h"
+#include "ctxnvc0.h"
 
-static struct nvc0_graph_init
-nvf0_grctx_init_unk40xx[] = {
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct nvc0_graph_init
+nvf0_grctx_init_icmd_0[] = {
+       { 0x001000,   1, 0x01, 0x00000004 },
+       { 0x000039,   3, 0x01, 0x00000000 },
+       { 0x0000a9,   1, 0x01, 0x0000ffff },
+       { 0x000038,   1, 0x01, 0x0fac6881 },
+       { 0x00003d,   1, 0x01, 0x00000001 },
+       { 0x0000e8,   8, 0x01, 0x00000400 },
+       { 0x000078,   8, 0x01, 0x00000300 },
+       { 0x000050,   1, 0x01, 0x00000011 },
+       { 0x000058,   8, 0x01, 0x00000008 },
+       { 0x000208,   8, 0x01, 0x00000001 },
+       { 0x000081,   1, 0x01, 0x00000001 },
+       { 0x000085,   1, 0x01, 0x00000004 },
+       { 0x000088,   1, 0x01, 0x00000400 },
+       { 0x000090,   1, 0x01, 0x00000300 },
+       { 0x000098,   1, 0x01, 0x00001001 },
+       { 0x0000e3,   1, 0x01, 0x00000001 },
+       { 0x0000da,   1, 0x01, 0x00000001 },
+       { 0x0000f8,   1, 0x01, 0x00000003 },
+       { 0x0000fa,   1, 0x01, 0x00000001 },
+       { 0x00009f,   4, 0x01, 0x0000ffff },
+       { 0x0000b1,   1, 0x01, 0x00000001 },
+       { 0x0000ad,   1, 0x01, 0x0000013e },
+       { 0x0000e1,   1, 0x01, 0x00000010 },
+       { 0x000290,  16, 0x01, 0x00000000 },
+       { 0x0003b0,  16, 0x01, 0x00000000 },
+       { 0x0002a0,  16, 0x01, 0x00000000 },
+       { 0x000420,  16, 0x01, 0x00000000 },
+       { 0x0002b0,  16, 0x01, 0x00000000 },
+       { 0x000430,  16, 0x01, 0x00000000 },
+       { 0x0002c0,  16, 0x01, 0x00000000 },
+       { 0x0004d0,  16, 0x01, 0x00000000 },
+       { 0x000720,  16, 0x01, 0x00000000 },
+       { 0x0008c0,  16, 0x01, 0x00000000 },
+       { 0x000890,  16, 0x01, 0x00000000 },
+       { 0x0008e0,  16, 0x01, 0x00000000 },
+       { 0x0008a0,  16, 0x01, 0x00000000 },
+       { 0x0008f0,  16, 0x01, 0x00000000 },
+       { 0x00094c,   1, 0x01, 0x000000ff },
+       { 0x00094d,   1, 0x01, 0xffffffff },
+       { 0x00094e,   1, 0x01, 0x00000002 },
+       { 0x0002ec,   1, 0x01, 0x00000001 },
+       { 0x0002f2,   2, 0x01, 0x00000001 },
+       { 0x0002f5,   1, 0x01, 0x00000001 },
+       { 0x0002f7,   1, 0x01, 0x00000001 },
+       { 0x000303,   1, 0x01, 0x00000001 },
+       { 0x0002e6,   1, 0x01, 0x00000001 },
+       { 0x000466,   1, 0x01, 0x00000052 },
+       { 0x000301,   1, 0x01, 0x3f800000 },
+       { 0x000304,   1, 0x01, 0x30201000 },
+       { 0x000305,   1, 0x01, 0x70605040 },
+       { 0x000306,   1, 0x01, 0xb8a89888 },
+       { 0x000307,   1, 0x01, 0xf8e8d8c8 },
+       { 0x00030a,   1, 0x01, 0x00ffff00 },
+       { 0x00030b,   1, 0x01, 0x0000001a },
+       { 0x00030c,   1, 0x01, 0x00000001 },
+       { 0x000318,   1, 0x01, 0x00000001 },
+       { 0x000340,   1, 0x01, 0x00000000 },
+       { 0x000375,   1, 0x01, 0x00000001 },
+       { 0x00037d,   1, 0x01, 0x00000006 },
+       { 0x0003a0,   1, 0x01, 0x00000002 },
+       { 0x0003aa,   1, 0x01, 0x00000001 },
+       { 0x0003a9,   1, 0x01, 0x00000001 },
+       { 0x000380,   1, 0x01, 0x00000001 },
+       { 0x000383,   1, 0x01, 0x00000011 },
+       { 0x000360,   1, 0x01, 0x00000040 },
+       { 0x000366,   2, 0x01, 0x00000000 },
+       { 0x000368,   1, 0x01, 0x00000fff },
+       { 0x000370,   2, 0x01, 0x00000000 },
+       { 0x000372,   1, 0x01, 0x000fffff },
+       { 0x00037a,   1, 0x01, 0x00000012 },
+       { 0x000619,   1, 0x01, 0x00000003 },
+       { 0x000811,   1, 0x01, 0x00000003 },
+       { 0x000812,   1, 0x01, 0x00000004 },
+       { 0x000813,   1, 0x01, 0x00000006 },
+       { 0x000814,   1, 0x01, 0x00000008 },
+       { 0x000815,   1, 0x01, 0x0000000b },
+       { 0x000800,   6, 0x01, 0x00000001 },
+       { 0x000632,   1, 0x01, 0x00000001 },
+       { 0x000633,   1, 0x01, 0x00000002 },
+       { 0x000634,   1, 0x01, 0x00000003 },
+       { 0x000635,   1, 0x01, 0x00000004 },
+       { 0x000654,   1, 0x01, 0x3f800000 },
+       { 0x000657,   1, 0x01, 0x3f800000 },
+       { 0x000655,   2, 0x01, 0x3f800000 },
+       { 0x0006cd,   1, 0x01, 0x3f800000 },
+       { 0x0007f5,   1, 0x01, 0x3f800000 },
+       { 0x0007dc,   1, 0x01, 0x39291909 },
+       { 0x0007dd,   1, 0x01, 0x79695949 },
+       { 0x0007de,   1, 0x01, 0xb9a99989 },
+       { 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+       { 0x0007e8,   1, 0x01, 0x00003210 },
+       { 0x0007e9,   1, 0x01, 0x00007654 },
+       { 0x0007ea,   1, 0x01, 0x00000098 },
+       { 0x0007ec,   1, 0x01, 0x39291909 },
+       { 0x0007ed,   1, 0x01, 0x79695949 },
+       { 0x0007ee,   1, 0x01, 0xb9a99989 },
+       { 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+       { 0x0007f0,   1, 0x01, 0x00003210 },
+       { 0x0007f1,   1, 0x01, 0x00007654 },
+       { 0x0007f2,   1, 0x01, 0x00000098 },
+       { 0x0005a5,   1, 0x01, 0x00000001 },
+       { 0x000980, 128, 0x01, 0x00000000 },
+       { 0x000468,   1, 0x01, 0x00000004 },
+       { 0x00046c,   1, 0x01, 0x00000001 },
+       { 0x000470,  96, 0x01, 0x00000000 },
+       { 0x000510,  16, 0x01, 0x3f800000 },
+       { 0x000520,   1, 0x01, 0x000002b6 },
+       { 0x000529,   1, 0x01, 0x00000001 },
+       { 0x000530,  16, 0x01, 0xffff0000 },
+       { 0x000585,   1, 0x01, 0x0000003f },
+       { 0x000576,   1, 0x01, 0x00000003 },
+       { 0x00057b,   1, 0x01, 0x00000059 },
+       { 0x000586,   1, 0x01, 0x00000040 },
+       { 0x000582,   2, 0x01, 0x00000080 },
+       { 0x0005c2,   1, 0x01, 0x00000001 },
+       { 0x000638,   2, 0x01, 0x00000001 },
+       { 0x00063a,   1, 0x01, 0x00000002 },
+       { 0x00063b,   2, 0x01, 0x00000001 },
+       { 0x00063d,   1, 0x01, 0x00000002 },
+       { 0x00063e,   1, 0x01, 0x00000001 },
+       { 0x0008b8,   8, 0x01, 0x00000001 },
+       { 0x000900,   8, 0x01, 0x00000001 },
+       { 0x000908,   8, 0x01, 0x00000002 },
+       { 0x000910,  16, 0x01, 0x00000001 },
+       { 0x000920,   8, 0x01, 0x00000002 },
+       { 0x000928,   8, 0x01, 0x00000001 },
+       { 0x000662,   1, 0x01, 0x00000001 },
+       { 0x000648,   9, 0x01, 0x00000001 },
+       { 0x000658,   1, 0x01, 0x0000000f },
+       { 0x0007ff,   1, 0x01, 0x0000000a },
+       { 0x00066a,   1, 0x01, 0x40000000 },
+       { 0x00066b,   1, 0x01, 0x10000000 },
+       { 0x00066c,   2, 0x01, 0xffff0000 },
+       { 0x0007af,   2, 0x01, 0x00000008 },
+       { 0x0007f6,   1, 0x01, 0x00000001 },
+       { 0x00080b,   1, 0x01, 0x00000002 },
+       { 0x0006b2,   1, 0x01, 0x00000055 },
+       { 0x0007ad,   1, 0x01, 0x00000003 },
+       { 0x000937,   1, 0x01, 0x00000001 },
+       { 0x000971,   1, 0x01, 0x00000008 },
+       { 0x000972,   1, 0x01, 0x00000040 },
+       { 0x000973,   1, 0x01, 0x0000012c },
+       { 0x00097c,   1, 0x01, 0x00000040 },
+       { 0x000979,   1, 0x01, 0x00000003 },
+       { 0x000975,   1, 0x01, 0x00000020 },
+       { 0x000976,   1, 0x01, 0x00000001 },
+       { 0x000977,   1, 0x01, 0x00000020 },
+       { 0x000978,   1, 0x01, 0x00000001 },
+       { 0x000957,   1, 0x01, 0x00000003 },
+       { 0x00095e,   1, 0x01, 0x20164010 },
+       { 0x00095f,   1, 0x01, 0x00000020 },
+       { 0x000a0d,   1, 0x01, 0x00000006 },
+       { 0x00097d,   1, 0x01, 0x00000020 },
+       { 0x000683,   1, 0x01, 0x00000006 },
+       { 0x000685,   1, 0x01, 0x003fffff },
+       { 0x000687,   1, 0x01, 0x003fffff },
+       { 0x0006a0,   1, 0x01, 0x00000005 },
+       { 0x000840,   1, 0x01, 0x00400008 },
+       { 0x000841,   1, 0x01, 0x08000080 },
+       { 0x000842,   1, 0x01, 0x00400008 },
+       { 0x000843,   1, 0x01, 0x08000080 },
+       { 0x0006aa,   1, 0x01, 0x00000001 },
+       { 0x0006ab,   1, 0x01, 0x00000002 },
+       { 0x0006ac,   1, 0x01, 0x00000080 },
+       { 0x0006ad,   2, 0x01, 0x00000100 },
+       { 0x0006b1,   1, 0x01, 0x00000011 },
+       { 0x0006bb,   1, 0x01, 0x000000cf },
+       { 0x0006ce,   1, 0x01, 0x2a712488 },
+       { 0x000739,   1, 0x01, 0x4085c000 },
+       { 0x00073a,   1, 0x01, 0x00000080 },
+       { 0x000786,   1, 0x01, 0x80000100 },
+       { 0x00073c,   1, 0x01, 0x00010100 },
+       { 0x00073d,   1, 0x01, 0x02800000 },
+       { 0x000787,   1, 0x01, 0x000000cf },
+       { 0x00078c,   1, 0x01, 0x00000008 },
+       { 0x000792,   1, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
+       { 0x000797,   1, 0x01, 0x000000cf },
+       { 0x000836,   1, 0x01, 0x00000001 },
+       { 0x00079a,   1, 0x01, 0x00000002 },
+       { 0x000833,   1, 0x01, 0x04444480 },
+       { 0x0007a1,   1, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
+       { 0x000831,   1, 0x01, 0x00000004 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x000a04,   1, 0x01, 0x000000ff },
+       { 0x000a0b,   1, 0x01, 0x00000040 },
+       { 0x00097f,   1, 0x01, 0x00000100 },
+       { 0x000a02,   1, 0x01, 0x00000001 },
+       { 0x000809,   1, 0x01, 0x00000007 },
+       { 0x00c221,   1, 0x01, 0x00000040 },
+       { 0x00c1b0,   8, 0x01, 0x0000000f },
+       { 0x00c1b8,   1, 0x01, 0x0fac6881 },
+       { 0x00c1b9,   1, 0x01, 0x00fac688 },
+       { 0x00c401,   1, 0x01, 0x00000001 },
+       { 0x00c402,   1, 0x01, 0x00010001 },
+       { 0x00c403,   2, 0x01, 0x00000001 },
+       { 0x00c40e,   1, 0x01, 0x00000020 },
+       { 0x00c500,   1, 0x01, 0x00000003 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000002 },
+       { 0x0006aa,   1, 0x01, 0x00000001 },
+       { 0x0006ad,   2, 0x01, 0x00000100 },
+       { 0x0006b1,   1, 0x01, 0x00000011 },
+       { 0x00078c,   1, 0x01, 0x00000008 },
+       { 0x000792,   1, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
+       { 0x000797,   1, 0x01, 0x000000cf },
+       { 0x00079a,   1, 0x01, 0x00000002 },
+       { 0x000833,   1, 0x01, 0x04444480 },
+       { 0x0007a1,   1, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
+       { 0x000831,   1, 0x01, 0x00000004 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000008 },
+       { 0x000039,   3, 0x01, 0x00000000 },
+       { 0x000380,   1, 0x01, 0x00000001 },
+       { 0x000366,   2, 0x01, 0x00000000 },
+       { 0x000368,   1, 0x01, 0x00000fff },
+       { 0x000370,   2, 0x01, 0x00000000 },
+       { 0x000372,   1, 0x01, 0x000fffff },
+       { 0x000813,   1, 0x01, 0x00000006 },
+       { 0x000814,   1, 0x01, 0x00000008 },
+       { 0x000957,   1, 0x01, 0x00000003 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x000a04,   1, 0x01, 0x000000ff },
+       { 0x000a0b,   1, 0x01, 0x00000040 },
+       { 0x00097f,   1, 0x01, 0x00000100 },
+       { 0x000a02,   1, 0x01, 0x00000001 },
+       { 0x000809,   1, 0x01, 0x00000007 },
+       { 0x00c221,   1, 0x01, 0x00000040 },
+       { 0x00c401,   1, 0x01, 0x00000001 },
+       { 0x00c402,   1, 0x01, 0x00010001 },
+       { 0x00c403,   2, 0x01, 0x00000001 },
+       { 0x00c40e,   1, 0x01, 0x00000020 },
+       { 0x00c500,   1, 0x01, 0x00000003 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000001 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+nvf0_grctx_pack_icmd[] = {
+       { nvf0_grctx_init_icmd_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvf0_grctx_init_a197_0[] = {
+       { 0x000800,   8, 0x40, 0x00000000 },
+       { 0x000804,   8, 0x40, 0x00000000 },
+       { 0x000808,   8, 0x40, 0x00000400 },
+       { 0x00080c,   8, 0x40, 0x00000300 },
+       { 0x000810,   1, 0x04, 0x000000cf },
+       { 0x000850,   7, 0x40, 0x00000000 },
+       { 0x000814,   8, 0x40, 0x00000040 },
+       { 0x000818,   8, 0x40, 0x00000001 },
+       { 0x00081c,   8, 0x40, 0x00000000 },
+       { 0x000820,   8, 0x40, 0x00000000 },
+       { 0x001c00,  16, 0x10, 0x00000000 },
+       { 0x001c04,  16, 0x10, 0x00000000 },
+       { 0x001c08,  16, 0x10, 0x00000000 },
+       { 0x001c0c,  16, 0x10, 0x00000000 },
+       { 0x001d00,  16, 0x10, 0x00000000 },
+       { 0x001d04,  16, 0x10, 0x00000000 },
+       { 0x001d08,  16, 0x10, 0x00000000 },
+       { 0x001d0c,  16, 0x10, 0x00000000 },
+       { 0x001f00,  16, 0x08, 0x00000000 },
+       { 0x001f04,  16, 0x08, 0x00000000 },
+       { 0x001f80,  16, 0x08, 0x00000000 },
+       { 0x001f84,  16, 0x08, 0x00000000 },
+       { 0x002000,   1, 0x04, 0x00000000 },
+       { 0x002040,   1, 0x04, 0x00000011 },
+       { 0x002080,   1, 0x04, 0x00000020 },
+       { 0x0020c0,   1, 0x04, 0x00000030 },
+       { 0x002100,   1, 0x04, 0x00000040 },
+       { 0x002140,   1, 0x04, 0x00000051 },
+       { 0x00200c,   6, 0x40, 0x00000001 },
+       { 0x002010,   1, 0x04, 0x00000000 },
+       { 0x002050,   1, 0x04, 0x00000000 },
+       { 0x002090,   1, 0x04, 0x00000001 },
+       { 0x0020d0,   1, 0x04, 0x00000002 },
+       { 0x002110,   1, 0x04, 0x00000003 },
+       { 0x002150,   1, 0x04, 0x00000004 },
+       { 0x000380,   4, 0x20, 0x00000000 },
+       { 0x000384,   4, 0x20, 0x00000000 },
+       { 0x000388,   4, 0x20, 0x00000000 },
+       { 0x00038c,   4, 0x20, 0x00000000 },
+       { 0x000700,   4, 0x10, 0x00000000 },
+       { 0x000704,   4, 0x10, 0x00000000 },
+       { 0x000708,   4, 0x10, 0x00000000 },
+       { 0x002800, 128, 0x04, 0x00000000 },
+       { 0x000a00,  16, 0x20, 0x00000000 },
+       { 0x000a04,  16, 0x20, 0x00000000 },
+       { 0x000a08,  16, 0x20, 0x00000000 },
+       { 0x000a0c,  16, 0x20, 0x00000000 },
+       { 0x000a10,  16, 0x20, 0x00000000 },
+       { 0x000a14,  16, 0x20, 0x00000000 },
+       { 0x000c00,  16, 0x10, 0x00000000 },
+       { 0x000c04,  16, 0x10, 0x00000000 },
+       { 0x000c08,  16, 0x10, 0x00000000 },
+       { 0x000c0c,  16, 0x10, 0x3f800000 },
+       { 0x000d00,   8, 0x08, 0xffff0000 },
+       { 0x000d04,   8, 0x08, 0xffff0000 },
+       { 0x000e00,  16, 0x10, 0x00000000 },
+       { 0x000e04,  16, 0x10, 0xffff0000 },
+       { 0x000e08,  16, 0x10, 0xffff0000 },
+       { 0x000d40,   4, 0x08, 0x00000000 },
+       { 0x000d44,   4, 0x08, 0x00000000 },
+       { 0x001e00,   8, 0x20, 0x00000001 },
+       { 0x001e04,   8, 0x20, 0x00000001 },
+       { 0x001e08,   8, 0x20, 0x00000002 },
+       { 0x001e0c,   8, 0x20, 0x00000001 },
+       { 0x001e10,   8, 0x20, 0x00000001 },
+       { 0x001e14,   8, 0x20, 0x00000002 },
+       { 0x001e18,   8, 0x20, 0x00000001 },
+       { 0x003400, 128, 0x04, 0x00000000 },
+       { 0x00030c,   1, 0x04, 0x00000001 },
+       { 0x001944,   1, 0x04, 0x00000000 },
+       { 0x001514,   1, 0x04, 0x00000000 },
+       { 0x000d68,   1, 0x04, 0x0000ffff },
+       { 0x00121c,   1, 0x04, 0x0fac6881 },
+       { 0x000fac,   1, 0x04, 0x00000001 },
+       { 0x001538,   1, 0x04, 0x00000001 },
+       { 0x000fe0,   2, 0x04, 0x00000000 },
+       { 0x000fe8,   1, 0x04, 0x00000014 },
+       { 0x000fec,   1, 0x04, 0x00000040 },
+       { 0x000ff0,   1, 0x04, 0x00000000 },
+       { 0x00179c,   1, 0x04, 0x00000000 },
+       { 0x001228,   1, 0x04, 0x00000400 },
+       { 0x00122c,   1, 0x04, 0x00000300 },
+       { 0x001230,   1, 0x04, 0x00010001 },
+       { 0x0007f8,   1, 0x04, 0x00000000 },
+       { 0x0015b4,   1, 0x04, 0x00000001 },
+       { 0x0015cc,   1, 0x04, 0x00000000 },
+       { 0x001534,   1, 0x04, 0x00000000 },
+       { 0x000fb0,   1, 0x04, 0x00000000 },
+       { 0x0015d0,   1, 0x04, 0x00000000 },
+       { 0x00153c,   1, 0x04, 0x00000000 },
+       { 0x0016b4,   1, 0x04, 0x00000003 },
+       { 0x000fbc,   4, 0x04, 0x0000ffff },
+       { 0x000df8,   2, 0x04, 0x00000000 },
+       { 0x001948,   1, 0x04, 0x00000000 },
+       { 0x001970,   1, 0x04, 0x00000001 },
+       { 0x00161c,   1, 0x04, 0x000009f0 },
+       { 0x000dcc,   1, 0x04, 0x00000010 },
+       { 0x00163c,   1, 0x04, 0x00000000 },
+       { 0x0015e4,   1, 0x04, 0x00000000 },
+       { 0x001160,  32, 0x04, 0x25e00040 },
+       { 0x001880,  32, 0x04, 0x00000000 },
+       { 0x000f84,   2, 0x04, 0x00000000 },
+       { 0x0017c8,   2, 0x04, 0x00000000 },
+       { 0x0017d0,   1, 0x04, 0x000000ff },
+       { 0x0017d4,   1, 0x04, 0xffffffff },
+       { 0x0017d8,   1, 0x04, 0x00000002 },
+       { 0x0017dc,   1, 0x04, 0x00000000 },
+       { 0x0015f4,   2, 0x04, 0x00000000 },
+       { 0x001434,   2, 0x04, 0x00000000 },
+       { 0x000d74,   1, 0x04, 0x00000000 },
+       { 0x000dec,   1, 0x04, 0x00000001 },
+       { 0x0013a4,   1, 0x04, 0x00000000 },
+       { 0x001318,   1, 0x04, 0x00000001 },
+       { 0x001644,   1, 0x04, 0x00000000 },
+       { 0x000748,   1, 0x04, 0x00000000 },
+       { 0x000de8,   1, 0x04, 0x00000000 },
+       { 0x001648,   1, 0x04, 0x00000000 },
+       { 0x0012a4,   1, 0x04, 0x00000000 },
+       { 0x001120,   4, 0x04, 0x00000000 },
+       { 0x001118,   1, 0x04, 0x00000000 },
+       { 0x00164c,   1, 0x04, 0x00000000 },
+       { 0x001658,   1, 0x04, 0x00000000 },
+       { 0x001910,   1, 0x04, 0x00000290 },
+       { 0x001518,   1, 0x04, 0x00000000 },
+       { 0x00165c,   1, 0x04, 0x00000001 },
+       { 0x001520,   1, 0x04, 0x00000000 },
+       { 0x001604,   1, 0x04, 0x00000000 },
+       { 0x001570,   1, 0x04, 0x00000000 },
+       { 0x0013b0,   2, 0x04, 0x3f800000 },
+       { 0x00020c,   1, 0x04, 0x00000000 },
+       { 0x001670,   1, 0x04, 0x30201000 },
+       { 0x001674,   1, 0x04, 0x70605040 },
+       { 0x001678,   1, 0x04, 0xb8a89888 },
+       { 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+       { 0x00166c,   1, 0x04, 0x00000000 },
+       { 0x001680,   1, 0x04, 0x00ffff00 },
+       { 0x0012d0,   1, 0x04, 0x00000003 },
+       { 0x0012d4,   1, 0x04, 0x00000002 },
+       { 0x001684,   2, 0x04, 0x00000000 },
+       { 0x000dac,   2, 0x04, 0x00001b02 },
+       { 0x000db4,   1, 0x04, 0x00000000 },
+       { 0x00168c,   1, 0x04, 0x00000000 },
+       { 0x0015bc,   1, 0x04, 0x00000000 },
+       { 0x00156c,   1, 0x04, 0x00000000 },
+       { 0x00187c,   1, 0x04, 0x00000000 },
+       { 0x001110,   1, 0x04, 0x00000001 },
+       { 0x000dc0,   3, 0x04, 0x00000000 },
+       { 0x001234,   1, 0x04, 0x00000000 },
+       { 0x001690,   1, 0x04, 0x00000000 },
+       { 0x0012ac,   1, 0x04, 0x00000001 },
+       { 0x0002c4,   1, 0x04, 0x00000000 },
+       { 0x000790,   5, 0x04, 0x00000000 },
+       { 0x00077c,   1, 0x04, 0x00000000 },
+       { 0x001000,   1, 0x04, 0x00000010 },
+       { 0x0010fc,   1, 0x04, 0x00000000 },
+       { 0x001290,   1, 0x04, 0x00000000 },
+       { 0x000218,   1, 0x04, 0x00000010 },
+       { 0x0012d8,   1, 0x04, 0x00000000 },
+       { 0x0012dc,   1, 0x04, 0x00000010 },
+       { 0x000d94,   1, 0x04, 0x00000001 },
+       { 0x00155c,   2, 0x04, 0x00000000 },
+       { 0x001564,   1, 0x04, 0x00000fff },
+       { 0x001574,   2, 0x04, 0x00000000 },
+       { 0x00157c,   1, 0x04, 0x000fffff },
+       { 0x001354,   1, 0x04, 0x00000000 },
+       { 0x001610,   1, 0x04, 0x00000012 },
+       { 0x001608,   2, 0x04, 0x00000000 },
+       { 0x00260c,   1, 0x04, 0x00000000 },
+       { 0x0007ac,   1, 0x04, 0x00000000 },
+       { 0x00162c,   1, 0x04, 0x00000003 },
+       { 0x000210,   1, 0x04, 0x00000000 },
+       { 0x000320,   1, 0x04, 0x00000000 },
+       { 0x000324,   6, 0x04, 0x3f800000 },
+       { 0x000750,   1, 0x04, 0x00000000 },
+       { 0x000760,   1, 0x04, 0x39291909 },
+       { 0x000764,   1, 0x04, 0x79695949 },
+       { 0x000768,   1, 0x04, 0xb9a99989 },
+       { 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+       { 0x000770,   1, 0x04, 0x30201000 },
+       { 0x000774,   1, 0x04, 0x70605040 },
+       { 0x000778,   1, 0x04, 0x00009080 },
+       { 0x000780,   1, 0x04, 0x39291909 },
+       { 0x000784,   1, 0x04, 0x79695949 },
+       { 0x000788,   1, 0x04, 0xb9a99989 },
+       { 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+       { 0x0007d0,   1, 0x04, 0x30201000 },
+       { 0x0007d4,   1, 0x04, 0x70605040 },
+       { 0x0007d8,   1, 0x04, 0x00009080 },
+       { 0x00037c,   1, 0x04, 0x00000001 },
+       { 0x000740,   2, 0x04, 0x00000000 },
+       { 0x002600,   1, 0x04, 0x00000000 },
+       { 0x001918,   1, 0x04, 0x00000000 },
+       { 0x00191c,   1, 0x04, 0x00000900 },
+       { 0x001920,   1, 0x04, 0x00000405 },
+       { 0x001308,   1, 0x04, 0x00000001 },
+       { 0x001924,   1, 0x04, 0x00000000 },
+       { 0x0013ac,   1, 0x04, 0x00000000 },
+       { 0x00192c,   1, 0x04, 0x00000001 },
+       { 0x00193c,   1, 0x04, 0x00002c1c },
+       { 0x000d7c,   1, 0x04, 0x00000000 },
+       { 0x000f8c,   1, 0x04, 0x00000000 },
+       { 0x0002c0,   1, 0x04, 0x00000001 },
+       { 0x001510,   1, 0x04, 0x00000000 },
+       { 0x001940,   1, 0x04, 0x00000000 },
+       { 0x000ff4,   2, 0x04, 0x00000000 },
+       { 0x00194c,   2, 0x04, 0x00000000 },
+       { 0x001968,   1, 0x04, 0x00000000 },
+       { 0x001590,   1, 0x04, 0x0000003f },
+       { 0x0007e8,   4, 0x04, 0x00000000 },
+       { 0x00196c,   1, 0x04, 0x00000011 },
+       { 0x0002e4,   1, 0x04, 0x0000b001 },
+       { 0x00036c,   2, 0x04, 0x00000000 },
+       { 0x00197c,   1, 0x04, 0x00000000 },
+       { 0x000fcc,   2, 0x04, 0x00000000 },
+       { 0x0002d8,   1, 0x04, 0x00000040 },
+       { 0x001980,   1, 0x04, 0x00000080 },
+       { 0x001504,   1, 0x04, 0x00000080 },
+       { 0x001984,   1, 0x04, 0x00000000 },
+       { 0x000300,   1, 0x04, 0x00000001 },
+       { 0x0013a8,   1, 0x04, 0x00000000 },
+       { 0x0012ec,   1, 0x04, 0x00000000 },
+       { 0x001310,   1, 0x04, 0x00000000 },
+       { 0x001314,   1, 0x04, 0x00000001 },
+       { 0x001380,   1, 0x04, 0x00000000 },
+       { 0x001384,   4, 0x04, 0x00000001 },
+       { 0x001394,   1, 0x04, 0x00000000 },
+       { 0x00139c,   1, 0x04, 0x00000000 },
+       { 0x001398,   1, 0x04, 0x00000000 },
+       { 0x001594,   1, 0x04, 0x00000000 },
+       { 0x001598,   4, 0x04, 0x00000001 },
+       { 0x000f54,   3, 0x04, 0x00000000 },
+       { 0x0019bc,   1, 0x04, 0x00000000 },
+       { 0x000f9c,   2, 0x04, 0x00000000 },
+       { 0x0012cc,   1, 0x04, 0x00000000 },
+       { 0x0012e8,   1, 0x04, 0x00000000 },
+       { 0x00130c,   1, 0x04, 0x00000001 },
+       { 0x001360,   8, 0x04, 0x00000000 },
+       { 0x00133c,   2, 0x04, 0x00000001 },
+       { 0x001344,   1, 0x04, 0x00000002 },
+       { 0x001348,   2, 0x04, 0x00000001 },
+       { 0x001350,   1, 0x04, 0x00000002 },
+       { 0x001358,   1, 0x04, 0x00000001 },
+       { 0x0012e4,   1, 0x04, 0x00000000 },
+       { 0x00131c,   4, 0x04, 0x00000000 },
+       { 0x0019c0,   1, 0x04, 0x00000000 },
+       { 0x001140,   1, 0x04, 0x00000000 },
+       { 0x0019c4,   1, 0x04, 0x00000000 },
+       { 0x0019c8,   1, 0x04, 0x00001500 },
+       { 0x00135c,   1, 0x04, 0x00000000 },
+       { 0x000f90,   1, 0x04, 0x00000000 },
+       { 0x0019e0,   8, 0x04, 0x00000001 },
+       { 0x0019cc,   1, 0x04, 0x00000001 },
+       { 0x0015b8,   1, 0x04, 0x00000000 },
+       { 0x001a00,   1, 0x04, 0x00001111 },
+       { 0x001a04,   7, 0x04, 0x00000000 },
+       { 0x000d6c,   2, 0x04, 0xffff0000 },
+       { 0x0010f8,   1, 0x04, 0x00001010 },
+       { 0x000d80,   5, 0x04, 0x00000000 },
+       { 0x000da0,   1, 0x04, 0x00000000 },
+       { 0x0007a4,   2, 0x04, 0x00000000 },
+       { 0x001508,   1, 0x04, 0x80000000 },
+       { 0x00150c,   1, 0x04, 0x40000000 },
+       { 0x001668,   1, 0x04, 0x00000000 },
+       { 0x000318,   2, 0x04, 0x00000008 },
+       { 0x000d9c,   1, 0x04, 0x00000001 },
+       { 0x000ddc,   1, 0x04, 0x00000002 },
+       { 0x000374,   1, 0x04, 0x00000000 },
+       { 0x000378,   1, 0x04, 0x00000020 },
+       { 0x0007dc,   1, 0x04, 0x00000000 },
+       { 0x00074c,   1, 0x04, 0x00000055 },
+       { 0x001420,   1, 0x04, 0x00000003 },
+       { 0x0017bc,   2, 0x04, 0x00000000 },
+       { 0x0017c4,   1, 0x04, 0x00000001 },
+       { 0x001008,   1, 0x04, 0x00000008 },
+       { 0x00100c,   1, 0x04, 0x00000040 },
+       { 0x001010,   1, 0x04, 0x0000012c },
+       { 0x000d60,   1, 0x04, 0x00000040 },
+       { 0x00075c,   1, 0x04, 0x00000003 },
+       { 0x001018,   1, 0x04, 0x00000020 },
+       { 0x00101c,   1, 0x04, 0x00000001 },
+       { 0x001020,   1, 0x04, 0x00000020 },
+       { 0x001024,   1, 0x04, 0x00000001 },
+       { 0x001444,   3, 0x04, 0x00000000 },
+       { 0x000360,   1, 0x04, 0x20164010 },
+       { 0x000364,   1, 0x04, 0x00000020 },
+       { 0x000368,   1, 0x04, 0x00000000 },
+       { 0x000de4,   1, 0x04, 0x00000000 },
+       { 0x000204,   1, 0x04, 0x00000006 },
+       { 0x000208,   1, 0x04, 0x00000000 },
+       { 0x0002cc,   2, 0x04, 0x003fffff },
+       { 0x001220,   1, 0x04, 0x00000005 },
+       { 0x000fdc,   1, 0x04, 0x00000000 },
+       { 0x000f98,   1, 0x04, 0x00400008 },
+       { 0x001284,   1, 0x04, 0x08000080 },
+       { 0x001450,   1, 0x04, 0x00400008 },
+       { 0x001454,   1, 0x04, 0x08000080 },
+       { 0x000214,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_pack
+nvf0_grctx_pack_mthd[] = {
+       { nvf0_grctx_init_a197_0, 0xa197 },
+       { nvc0_grctx_init_902d_0, 0x902d },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvf0_grctx_init_fe_0[] = {
        { 0x404004,   8, 0x04, 0x00000000 },
        { 0x404024,   1, 0x04, 0x0000e000 },
        { 0x404028,   8, 0x04, 0x00000000 },
@@ -50,8 +620,8 @@ nvf0_grctx_init_unk40xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvf0_grctx_init_unk44xx[] = {
+const struct nvc0_graph_init
+nvf0_grctx_init_pri_0[] = {
        { 0x404404,  12, 0x04, 0x00000000 },
        { 0x404438,   1, 0x04, 0x00000000 },
        { 0x404460,   2, 0x04, 0x00000000 },
@@ -62,23 +632,18 @@ nvf0_grctx_init_unk44xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvf0_grctx_init_unk5bxx[] = {
+const struct nvc0_graph_init
+nvf0_grctx_init_cwd_0[] = {
        { 0x405b00,   1, 0x04, 0x00000000 },
        { 0x405b10,   1, 0x04, 0x00001000 },
        { 0x405b20,   1, 0x04, 0x04000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvf0_grctx_init_unk60xx[] = {
+static const struct nvc0_graph_init
+nvf0_grctx_init_pd_0[] = {
        { 0x406020,   1, 0x04, 0x034103c1 },
        { 0x406028,   4, 0x04, 0x00000001 },
-       {}
-};
-
-static struct nvc0_graph_init
-nvf0_grctx_init_unk64xx[] = {
        { 0x4064a8,   1, 0x04, 0x00000000 },
        { 0x4064ac,   1, 0x04, 0x00003fff },
        { 0x4064b0,   3, 0x04, 0x00000000 },
@@ -90,8 +655,8 @@ nvf0_grctx_init_unk64xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvf0_grctx_init_unk88xx[] = {
+static const struct nvc0_graph_init
+nvf0_grctx_init_be_0[] = {
        { 0x408800,   1, 0x04, 0x12802a3c },
        { 0x408804,   1, 0x04, 0x00000040 },
        { 0x408808,   1, 0x04, 0x1003e005 },
@@ -103,22 +668,23 @@ nvf0_grctx_init_unk88xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvf0_grctx_init_gpc_0[] = {
-       { 0x418380,   1, 0x04, 0x00000016 },
-       { 0x418400,   1, 0x04, 0x38004e00 },
-       { 0x418404,   1, 0x04, 0x71e0ffff },
-       { 0x41840c,   1, 0x04, 0x00001008 },
-       { 0x418410,   1, 0x04, 0x0fff0fff },
-       { 0x418414,   1, 0x04, 0x02200fff },
-       { 0x418450,   6, 0x04, 0x00000000 },
-       { 0x418468,   1, 0x04, 0x00000001 },
-       { 0x41846c,   2, 0x04, 0x00000000 },
-       { 0x418600,   1, 0x04, 0x0000001f },
-       { 0x418684,   1, 0x04, 0x0000000f },
-       { 0x418700,   1, 0x04, 0x00000002 },
-       { 0x418704,   1, 0x04, 0x00000080 },
-       { 0x418708,   3, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nvf0_grctx_pack_hub[] = {
+       { nvc0_grctx_init_main_0 },
+       { nvf0_grctx_init_fe_0 },
+       { nvf0_grctx_init_pri_0 },
+       { nve4_grctx_init_memfmt_0 },
+       { nve4_grctx_init_ds_0 },
+       { nvf0_grctx_init_cwd_0 },
+       { nvf0_grctx_init_pd_0 },
+       { nvc0_grctx_init_rstr2d_0 },
+       { nve4_grctx_init_scc_0 },
+       { nvf0_grctx_init_be_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvf0_grctx_init_setup_0[] = {
        { 0x418800,   1, 0x04, 0x7006860a },
        { 0x418808,   1, 0x04, 0x00000000 },
        { 0x41880c,   1, 0x04, 0x00000030 },
@@ -129,36 +695,31 @@ nvf0_grctx_init_gpc_0[] = {
        { 0x4188e0,   1, 0x04, 0x01000000 },
        { 0x4188e8,   5, 0x04, 0x00000000 },
        { 0x4188fc,   1, 0x04, 0x20100018 },
-       { 0x41891c,   1, 0x04, 0x00ff00ff },
-       { 0x418924,   1, 0x04, 0x00000000 },
-       { 0x418928,   1, 0x04, 0x00ffff00 },
-       { 0x41892c,   1, 0x04, 0x0000ff00 },
-       { 0x418b00,   1, 0x04, 0x00000006 },
-       { 0x418b08,   1, 0x04, 0x0a418820 },
-       { 0x418b0c,   1, 0x04, 0x062080e6 },
-       { 0x418b10,   1, 0x04, 0x020398a4 },
-       { 0x418b14,   1, 0x04, 0x0e629062 },
-       { 0x418b18,   1, 0x04, 0x0a418820 },
-       { 0x418b1c,   1, 0x04, 0x000000e6 },
-       { 0x418bb8,   1, 0x04, 0x00000103 },
-       { 0x418c08,   1, 0x04, 0x00000001 },
-       { 0x418c10,   8, 0x04, 0x00000000 },
-       { 0x418c40,   1, 0x04, 0xffffffff },
-       { 0x418c6c,   1, 0x04, 0x00000001 },
-       { 0x418c80,   1, 0x04, 0x20200004 },
-       { 0x418c8c,   1, 0x04, 0x00000001 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvf0_grctx_init_gpc_unk_2[] = {
        { 0x418d24,   1, 0x04, 0x00000000 },
-       { 0x419000,   1, 0x04, 0x00000780 },
-       { 0x419004,   2, 0x04, 0x00000000 },
-       { 0x419014,   1, 0x04, 0x00000004 },
        {}
 };
 
-static struct nvc0_graph_init
-nvf0_grctx_init_tpc[] = {
-       { 0x419848,   1, 0x04, 0x00000000 },
-       { 0x419864,   1, 0x04, 0x00000129 },
-       { 0x419888,   1, 0x04, 0x00000000 },
+static const struct nvc0_graph_pack
+nvf0_grctx_pack_gpc[] = {
+       { nvc0_grctx_init_gpc_unk_0 },
+       { nvd9_grctx_init_prop_0 },
+       { nvd9_grctx_init_gpc_unk_1 },
+       { nvf0_grctx_init_setup_0 },
+       { nvc0_grctx_init_zcull_0 },
+       { nvd9_grctx_init_crstr_0 },
+       { nve4_grctx_init_gpm_0 },
+       { nvf0_grctx_init_gpc_unk_2 },
+       { nvc0_grctx_init_gcc_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvf0_grctx_init_tex_0[] = {
        { 0x419a00,   1, 0x04, 0x000000f0 },
        { 0x419a04,   1, 0x04, 0x00000001 },
        { 0x419a08,   1, 0x04, 0x00000021 },
@@ -169,14 +730,29 @@ nvf0_grctx_init_tpc[] = {
        { 0x419a20,   1, 0x04, 0x00020800 },
        { 0x419a30,   1, 0x04, 0x00000001 },
        { 0x419ac4,   1, 0x04, 0x0037f440 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvf0_grctx_init_mpc_0[] = {
        { 0x419c00,   1, 0x04, 0x0000001a },
        { 0x419c04,   1, 0x04, 0x80000006 },
        { 0x419c08,   1, 0x04, 0x00000002 },
        { 0x419c20,   1, 0x04, 0x00000000 },
        { 0x419c24,   1, 0x04, 0x00084210 },
        { 0x419c28,   1, 0x04, 0x3efbefbe },
+       {}
+};
+
+const struct nvc0_graph_init
+nvf0_grctx_init_l1c_0[] = {
        { 0x419ce8,   1, 0x04, 0x00000000 },
        { 0x419cf4,   1, 0x04, 0x00000203 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvf0_grctx_init_sm_0[] = {
        { 0x419e04,   1, 0x04, 0x00000000 },
        { 0x419e08,   1, 0x04, 0x0000001d },
        { 0x419e0c,   1, 0x04, 0x00000000 },
@@ -189,8 +765,8 @@ nvf0_grctx_init_tpc[] = {
        { 0x419e5c,   3, 0x04, 0x00000000 },
        { 0x419e68,   1, 0x04, 0x00000002 },
        { 0x419e6c,  12, 0x04, 0x00000000 },
-       { 0x419eac,   1, 0x04, 0x00001fcf },
-       { 0x419eb0,   1, 0x04, 0x0db00da0 },
+       { 0x419eac,   1, 0x04, 0x00001f8f },
+       { 0x419eb0,   1, 0x04, 0x0db00d2f },
        { 0x419eb8,   1, 0x04, 0x00000000 },
        { 0x419ec8,   1, 0x04, 0x0001304f },
        { 0x419f30,   4, 0x04, 0x00000000 },
@@ -203,24 +779,36 @@ nvf0_grctx_init_tpc[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nvf0_grctx_init_unk[] = {
-       { 0x41be24,   1, 0x04, 0x00000006 },
+static const struct nvc0_graph_pack
+nvf0_grctx_pack_tpc[] = {
+       { nvd7_grctx_init_pe_0 },
+       { nvf0_grctx_init_tex_0 },
+       { nvf0_grctx_init_mpc_0 },
+       { nvf0_grctx_init_l1c_0 },
+       { nvf0_grctx_init_sm_0 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvf0_grctx_init_cbm_0[] = {
        { 0x41bec0,   1, 0x04, 0x10000000 },
        { 0x41bec4,   1, 0x04, 0x00037f7f },
        { 0x41bee4,   1, 0x04, 0x00000000 },
-       { 0x41bf00,   1, 0x04, 0x0a418820 },
-       { 0x41bf04,   1, 0x04, 0x062080e6 },
-       { 0x41bf08,   1, 0x04, 0x020398a4 },
-       { 0x41bf0c,   1, 0x04, 0x0e629062 },
-       { 0x41bf10,   1, 0x04, 0x0a418820 },
-       { 0x41bf14,   1, 0x04, 0x000000e6 },
-       { 0x41bfd0,   1, 0x04, 0x00900103 },
-       { 0x41bfe0,   1, 0x04, 0x00400001 },
-       { 0x41bfe4,   1, 0x04, 0x00000000 },
        {}
 };
 
+static const struct nvc0_graph_pack
+nvf0_grctx_pack_ppc[] = {
+       { nve4_grctx_init_pes_0 },
+       { nvf0_grctx_init_cbm_0 },
+       { nvd7_grctx_init_wwdx_0 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
 static void
 nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
 {
@@ -273,39 +861,6 @@ nvf0_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
        mmio_list(0x17e920, 0x00090a05, 0, 0);
 }
 
-static struct nvc0_graph_init *
-nvf0_grctx_init_hub[] = {
-       nvc0_grctx_init_base,
-       nvf0_grctx_init_unk40xx,
-       nvf0_grctx_init_unk44xx,
-       nve4_grctx_init_unk46xx,
-       nve4_grctx_init_unk47xx,
-       nve4_grctx_init_unk58xx,
-       nvf0_grctx_init_unk5bxx,
-       nvf0_grctx_init_unk60xx,
-       nvf0_grctx_init_unk64xx,
-       nve4_grctx_init_unk80xx,
-       nvf0_grctx_init_unk88xx,
-       NULL
-};
-
-struct nvc0_graph_init *
-nvf0_grctx_init_gpc[] = {
-       nvf0_grctx_init_gpc_0,
-       nvc0_grctx_init_gpc_1,
-       nvf0_grctx_init_tpc,
-       nvf0_grctx_init_unk,
-       NULL
-};
-
-static struct nvc0_graph_mthd
-nvf0_grctx_init_mthd[] = {
-       { 0xa197, nvc1_grctx_init_9097, },
-       { 0x902d, nvc0_grctx_init_902d, },
-       { 0x902d, nvc0_grctx_init_mthd_magic, },
-       {}
-};
-
 struct nouveau_oclass *
 nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) {
        .base.handle = NV_ENGCTX(GR, 0xf0),
@@ -317,11 +872,14 @@ nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) {
                .rd32 = _nouveau_graph_context_rd32,
                .wr32 = _nouveau_graph_context_wr32,
        },
-       .main = nve4_grctx_generate_main,
-       .mods = nvf0_grctx_generate_mods,
-       .unkn = nve4_grctx_generate_unkn,
-       .hub  = nvf0_grctx_init_hub,
-       .gpc  = nvf0_grctx_init_gpc,
-       .icmd = nvc0_grctx_init_icmd,
-       .mthd = nvf0_grctx_init_mthd,
+       .main  = nve4_grctx_generate_main,
+       .mods  = nvf0_grctx_generate_mods,
+       .unkn  = nve4_grctx_generate_unkn,
+       .hub   = nvf0_grctx_pack_hub,
+       .gpc   = nvf0_grctx_pack_gpc,
+       .zcull = nvc0_grctx_pack_zcull,
+       .tpc   = nvf0_grctx_pack_tpc,
+       .ppc   = nvf0_grctx_pack_ppc,
+       .icmd  = nvf0_grctx_pack_icmd,
+       .mthd  = nvf0_grctx_pack_mthd,
 }.base;
index e148961..e37d810 100644 (file)
@@ -228,7 +228,7 @@ mmctx_xfer:
                        and $r11 0x1f
                        cmpu b32 $r11 0x10
                        bra ne #mmctx_fini_wait
-               mov $r10 2                              // DONE_MMCTX
+               mov $r10 5                      // DONE_MMCTX
                call(wait_donez)
                bra #mmctx_done
        mmctx_stop:
index 96cbcea..2f7345f 100644 (file)
@@ -78,7 +78,12 @@ error:
 //
 init:
        clear b32 $r0
-       mov $sp $r0
+
+       // setup stack
+       nv_iord($r1, NV_PGRAPH_GPCX_GPCCS_CAPS, 0)
+       extr $r1 $r1 9:17
+       shl b32 $r1 8
+       mov $sp $r1
 
        // enable fifo access
        mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5
new file mode 100644 (file)
index 0000000..e730603
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000002
+
+#define CHIPSET GK208
+#include "macros.fuc"
+
+.section #gm107_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gm107_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h
new file mode 100644 (file)
index 0000000..6d53b67
--- /dev/null
@@ -0,0 +1,473 @@
+uint32_t gm107_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+       0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+       0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+       0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+       0x0000006c,
+/* 0x0010: gpc_id */
+       0x00000000,
+/* 0x0014: tpc_count */
+       0x00000000,
+/* 0x0018: tpc_mask */
+       0x00000000,
+/* 0x001c: unk_count */
+       0x00000000,
+/* 0x0020: unk_mask */
+       0x00000000,
+/* 0x0024: cmd_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
+
+uint32_t gm107_grgpc_code[] = {
+       0x03140ef5,
+/* 0x0004: queue_put */
+       0x9800d898,
+       0x86f001d9,
+       0xf489a408,
+       0x020f0b1b,
+       0x0002f87e,
+/* 0x001a: queue_put_next */
+       0x98c400f8,
+       0x0384b607,
+       0xb6008dbb,
+       0x8eb50880,
+       0x018fb500,
+       0xf00190b6,
+       0xd9b50f94,
+/* 0x0037: queue_get */
+       0xf400f801,
+       0xd8980131,
+       0x01d99800,
+       0x0bf489a4,
+       0x0789c421,
+       0xbb0394b6,
+       0x90b6009d,
+       0x009e9808,
+       0xb6019f98,
+       0x84f00180,
+       0x00d8b50f,
+/* 0x0063: queue_get_done */
+       0xf80132f4,
+/* 0x0065: nv_rd32 */
+       0xf0ecb200,
+       0x00801fc9,
+       0x0cf601ca,
+/* 0x0073: nv_rd32_wait */
+       0x8c04bd00,
+       0xcf01ca00,
+       0xccc800cc,
+       0xf61bf41f,
+       0xec7e060a,
+       0x008f0000,
+       0xffcf01cb,
+/* 0x008f: nv_wr32 */
+       0x8000f800,
+       0xf601cc00,
+       0x04bd000f,
+       0xc9f0ecb2,
+       0x1ec9f01f,
+       0x01ca0080,
+       0xbd000cf6,
+/* 0x00a9: nv_wr32_wait */
+       0xca008c04,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f61b,
+/* 0x00b8: wait_donez */
+       0x99f094bd,
+       0x37008000,
+       0x0009f602,
+       0x008004bd,
+       0x0af60206,
+/* 0x00cf: wait_donez_ne */
+       0x8804bd00,
+       0xcf010000,
+       0x8aff0088,
+       0xf61bf488,
+       0x99f094bd,
+       0x17008000,
+       0x0009f602,
+       0x00f804bd,
+/* 0x00ec: wait_doneo */
+       0x99f094bd,
+       0x37008000,
+       0x0009f602,
+       0x008004bd,
+       0x0af60206,
+/* 0x0103: wait_doneo_e */
+       0x8804bd00,
+       0xcf010000,
+       0x8aff0088,
+       0xf60bf488,
+       0x99f094bd,
+       0x17008000,
+       0x0009f602,
+       0x00f804bd,
+/* 0x0120: mmctx_size */
+/* 0x0122: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0x1bf4efa4,
+       0xf89fb2ec,
+/* 0x013d: mmctx_xfer */
+       0xf094bd00,
+       0x00800199,
+       0x09f60237,
+       0xbd04bd00,
+       0x05bbfd94,
+       0x800f0bf4,
+       0xf601c400,
+       0x04bd000b,
+/* 0x015f: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0xc6008018,
+       0x000ef601,
+       0x008004bd,
+       0x0ff601c7,
+       0xf004bd00,
+/* 0x017a: mmctx_multi_disabled */
+       0xabc80199,
+       0x10b4b600,
+       0xc80cb9f0,
+       0xe4b601ae,
+       0x05befd11,
+       0x01c50080,
+       0xbd000bf6,
+/* 0x0195: mmctx_exec_loop */
+/* 0x0195: mmctx_wait_free */
+       0xc5008e04,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f60b,
+       0x05e9fd00,
+       0x01c80080,
+       0xbd000ef6,
+       0x04c0b604,
+       0x1bf4cda4,
+       0x02abc8df,
+/* 0x01bf: mmctx_fini_wait */
+       0x8b1c1bf4,
+       0xcf01c500,
+       0xb4f000bb,
+       0x10b4b01f,
+       0x0af31bf4,
+       0x00b87e05,
+       0x250ef400,
+/* 0x01d8: mmctx_stop */
+       0xb600abc8,
+       0xb9f010b4,
+       0x12b9f00c,
+       0x01c50080,
+       0xbd000bf6,
+/* 0x01ed: mmctx_stop_wait */
+       0xc5008b04,
+       0x00bbcf01,
+       0xf412bbc8,
+/* 0x01fa: mmctx_done */
+       0x94bdf61b,
+       0x800199f0,
+       0xf6021700,
+       0x04bd0009,
+/* 0x020a: strand_wait */
+       0xa0f900f8,
+       0xb87e020a,
+       0xa0fc0000,
+/* 0x0216: strand_pre */
+       0x0c0900f8,
+       0x024afc80,
+       0xbd0009f6,
+       0x020a7e04,
+/* 0x0227: strand_post */
+       0x0900f800,
+       0x4afc800d,
+       0x0009f602,
+       0x0a7e04bd,
+       0x00f80002,
+/* 0x0238: strand_set */
+       0xfc800f0c,
+       0x0cf6024f,
+       0x0c04bd00,
+       0x4afc800b,
+       0x000cf602,
+       0xfc8004bd,
+       0x0ef6024f,
+       0x0c04bd00,
+       0x4afc800a,
+       0x000cf602,
+       0x0a7e04bd,
+       0x00f80002,
+/* 0x0268: strand_ctx_init */
+       0x99f094bd,
+       0x37008003,
+       0x0009f602,
+       0x167e04bd,
+       0x030e0002,
+       0x0002387e,
+       0xfc80c4bd,
+       0x0cf60247,
+       0x0c04bd00,
+       0x4afc8001,
+       0x000cf602,
+       0x0a7e04bd,
+       0x0c920002,
+       0x46fc8001,
+       0x000cf602,
+       0x020c04bd,
+       0x024afc80,
+       0xbd000cf6,
+       0x020a7e04,
+       0x02277e00,
+       0x42008800,
+       0x20008902,
+       0x0099cf02,
+/* 0x02c7: ctx_init_strand_loop */
+       0xf608fe95,
+       0x8ef6008e,
+       0x808acf40,
+       0xb606a5b6,
+       0xeabb01a0,
+       0x0480b600,
+       0xf40192b6,
+       0xe4b6e81b,
+       0xf2efbc08,
+       0x99f094bd,
+       0x17008003,
+       0x0009f602,
+       0x00f804bd,
+/* 0x02f8: error */
+       0xffb2e0f9,
+       0x4098148e,
+       0x00008f7e,
+       0xffb2010f,
+       0x409c1c8e,
+       0x00008f7e,
+       0x00f8e0fc,
+/* 0x0314: init */
+       0x004104bd,
+       0x0011cf42,
+       0x010911e7,
+       0xfe0814b6,
+       0x02020014,
+       0xf6120040,
+       0x04bd0002,
+       0xfe047241,
+       0x00400010,
+       0x0000f607,
+       0x040204bd,
+       0xf6040040,
+       0x04bd0002,
+       0x821031f4,
+       0xcf018200,
+       0x01030022,
+       0xbb1f24f0,
+       0x32b60432,
+       0x0502b501,
+       0x820603b5,
+       0xcf018600,
+       0x02b50022,
+       0x0c308e04,
+       0xbd24bd50,
+/* 0x0377: init_unk_loop */
+       0x7e44bd34,
+       0xb0000065,
+       0x0bf400f6,
+       0xbb010f0e,
+       0x4ffd04f2,
+       0x0130b605,
+/* 0x038c: init_unk_next */
+       0xb60120b6,
+       0x26b004e0,
+       0xe21bf402,
+/* 0x0398: init_unk_done */
+       0xb50703b5,
+       0x00820804,
+       0x22cf0201,
+       0x9534bd00,
+       0x00800825,
+       0x05f601c0,
+       0x8004bd00,
+       0xf601c100,
+       0x04bd0005,
+       0x98000e98,
+       0x207e010f,
+       0x2fbb0001,
+       0x003fbb00,
+       0x98010e98,
+       0x207e020f,
+       0x0e980001,
+       0x00effd05,
+       0xbb002ebb,
+       0x0e98003e,
+       0x030f9802,
+       0x0001207e,
+       0xfd070e98,
+       0x2ebb00ef,
+       0x003ebb00,
+       0x800235b6,
+       0xf601d300,
+       0x04bd0003,
+       0xb60825b6,
+       0x20b60635,
+       0x0130b601,
+       0xb60824b6,
+       0x2fb20834,
+       0x0002687e,
+       0x80003fbb,
+       0xf6020100,
+       0x04bd0003,
+       0x29f024bd,
+       0x3000801f,
+       0x0002f602,
+/* 0x0436: main */
+       0x31f404bd,
+       0x0028f400,
+       0x377e240d,
+       0x01f40000,
+       0x04e4b0f4,
+       0xfe1d18f4,
+       0x06020181,
+       0x12fd20bd,
+       0x01e4b604,
+       0xfe051efd,
+       0x097e0018,
+       0x0ef40005,
+/* 0x0465: main_not_ctx_xfer */
+       0x10ef94d4,
+       0x7e01f5f0,
+       0xf40002f8,
+/* 0x0472: ih */
+       0x80f9c70e,
+       0xf90188fe,
+       0xf990f980,
+       0xf9b0f9a0,
+       0xf9e0f9d0,
+       0x4a04bdf0,
+       0xaacf0200,
+       0x04abc400,
+       0x0d1f0bf4,
+       0x1a004e24,
+       0x4f00eecf,
+       0xffcf1900,
+       0x00047e00,
+       0x40010e00,
+       0x0ef61d00,
+/* 0x04af: ih_no_fifo */
+       0x4004bd00,
+       0x0af60100,
+       0xfc04bd00,
+       0xfce0fcf0,
+       0xfcb0fcd0,
+       0xfc90fca0,
+       0x0088fe80,
+       0x32f480fc,
+/* 0x04cf: hub_barrier_done */
+       0x0f01f800,
+       0x040e9801,
+       0xb204febb,
+       0x94188eff,
+       0x008f7e40,
+/* 0x04e3: ctx_redswitch */
+       0x0f00f800,
+       0x85008020,
+       0x000ff601,
+       0x080e04bd,
+/* 0x04f0: ctx_redswitch_delay */
+       0xf401e2b6,
+       0xf5f1fd1b,
+       0xf5f10800,
+       0x00800200,
+       0x0ff60185,
+       0xf804bd00,
+/* 0x0509: ctx_xfer */
+       0x81008000,
+       0x000ff602,
+       0x11f404bd,
+       0x04e37e07,
+/* 0x0519: ctx_xfer_not_load */
+       0x02167e00,
+       0x8024bd00,
+       0xf60247fc,
+       0x04bd0002,
+       0xb6012cf0,
+       0xfc800320,
+       0x02f6024a,
+       0xf004bd00,
+       0xa5f001ac,
+       0x00008b02,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x010d9800,
+       0x3d7e000e,
+       0xacf00001,
+       0x40008b01,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x020d9801,
+       0x4e060f98,
+       0x3d7e0800,
+       0xacf00001,
+       0x04a5f001,
+       0x5030008b,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x020c9800,
+       0x98030d98,
+       0x004e080f,
+       0x013d7e02,
+       0x020a7e00,
+       0x0601f400,
+/* 0x05a3: ctx_xfer_post */
+       0x7e0712f4,
+/* 0x05a7: ctx_xfer_done */
+       0x7e000227,
+       0xf80004cf,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
index 27dc128..3192270 100644 (file)
@@ -177,7 +177,7 @@ uint32_t nv108_grgpc_code[] = {
        0xb4f000bb,
        0x10b4b01f,
        0x0af31bf4,
-       0x00b87e02,
+       0x00b87e05,
        0x250ef400,
 /* 0x01d8: mmctx_stop */
        0xb600abc8,
@@ -269,186 +269,186 @@ uint32_t nv108_grgpc_code[] = {
        0x00008f7e,
        0x00f8e0fc,
 /* 0x0314: init */
-       0x04fe04bd,
-       0x40020200,
-       0x02f61200,
-       0x4104bd00,
-       0x10fe0465,
-       0x07004000,
-       0xbd0000f6,
-       0x40040204,
-       0x02f60400,
-       0xf404bd00,
-       0x00821031,
-       0x22cf0182,
-       0xf0010300,
-       0x32bb1f24,
-       0x0132b604,
-       0xb50502b5,
-       0x00820603,
-       0x22cf0186,
-       0x0402b500,
-       0x500c308e,
-       0x34bd24bd,
-/* 0x036a: init_unk_loop */
-       0x657e44bd,
-       0xf6b00000,
-       0x0e0bf400,
-       0xf2bb010f,
-       0x054ffd04,
-/* 0x037f: init_unk_next */
-       0xb60130b6,
-       0xe0b60120,
-       0x0126b004,
-/* 0x038b: init_unk_done */
-       0xb5e21bf4,
-       0x04b50703,
-       0x01008208,
-       0x0022cf02,
-       0x259534bd,
-       0xc0008008,
-       0x0005f601,
-       0x008004bd,
-       0x05f601c1,
-       0x9804bd00,
-       0x0f98000e,
-       0x01207e01,
-       0x002fbb00,
-       0x98003fbb,
-       0x0f98010e,
-       0x01207e02,
-       0x050e9800,
-       0xbb00effd,
-       0x3ebb002e,
-       0x020e9800,
-       0x7e030f98,
-       0x98000120,
-       0xeffd070e,
-       0x002ebb00,
-       0xb6003ebb,
-       0x00800235,
-       0x03f601d3,
-       0xb604bd00,
-       0x35b60825,
-       0x0120b606,
-       0xb60130b6,
-       0x34b60824,
-       0x7e2fb208,
-       0xbb000268,
-       0x0080003f,
-       0x03f60201,
-       0xbd04bd00,
-       0x1f29f024,
-       0x02300080,
-       0xbd0002f6,
-/* 0x0429: main */
-       0x0031f404,
-       0x0d0028f4,
-       0x00377e24,
-       0xf401f400,
-       0xf404e4b0,
-       0x81fe1d18,
-       0xbd060201,
-       0x0412fd20,
-       0xfd01e4b6,
-       0x18fe051e,
-       0x04fc7e00,
-       0xd40ef400,
-/* 0x0458: main_not_ctx_xfer */
-       0xf010ef94,
-       0xf87e01f5,
-       0x0ef40002,
-/* 0x0465: ih */
-       0xfe80f9c7,
-       0x80f90188,
-       0xa0f990f9,
-       0xd0f9b0f9,
-       0xf0f9e0f9,
-       0x004a04bd,
-       0x00aacf02,
-       0xf404abc4,
-       0x240d1f0b,
-       0xcf1a004e,
-       0x004f00ee,
-       0x00ffcf19,
-       0x0000047e,
-       0x0040010e,
-       0x000ef61d,
-/* 0x04a2: ih_no_fifo */
-       0x004004bd,
-       0x000af601,
-       0xf0fc04bd,
-       0xd0fce0fc,
-       0xa0fcb0fc,
-       0x80fc90fc,
-       0xfc0088fe,
-       0x0032f480,
-/* 0x04c2: hub_barrier_done */
-       0x010f01f8,
-       0xbb040e98,
-       0xffb204fe,
-       0x4094188e,
-       0x00008f7e,
-/* 0x04d6: ctx_redswitch */
-       0x200f00f8,
-       0x01850080,
-       0xbd000ff6,
-/* 0x04e3: ctx_redswitch_delay */
-       0xb6080e04,
-       0x1bf401e2,
-       0x00f5f1fd,
-       0x00f5f108,
-       0x85008002,
+       0x004104bd,
+       0x0011cf42,
+       0x010911e7,
+       0xfe0814b6,
+       0x02020014,
+       0xf6120040,
+       0x04bd0002,
+       0xfe047241,
+       0x00400010,
+       0x0000f607,
+       0x040204bd,
+       0xf6040040,
+       0x04bd0002,
+       0x821031f4,
+       0xcf018200,
+       0x01030022,
+       0xbb1f24f0,
+       0x32b60432,
+       0x0502b501,
+       0x820603b5,
+       0xcf018600,
+       0x02b50022,
+       0x0c308e04,
+       0xbd24bd50,
+/* 0x0377: init_unk_loop */
+       0x7e44bd34,
+       0xb0000065,
+       0x0bf400f6,
+       0xbb010f0e,
+       0x4ffd04f2,
+       0x0130b605,
+/* 0x038c: init_unk_next */
+       0xb60120b6,
+       0x26b004e0,
+       0xe21bf401,
+/* 0x0398: init_unk_done */
+       0xb50703b5,
+       0x00820804,
+       0x22cf0201,
+       0x9534bd00,
+       0x00800825,
+       0x05f601c0,
+       0x8004bd00,
+       0xf601c100,
+       0x04bd0005,
+       0x98000e98,
+       0x207e010f,
+       0x2fbb0001,
+       0x003fbb00,
+       0x98010e98,
+       0x207e020f,
+       0x0e980001,
+       0x00effd05,
+       0xbb002ebb,
+       0x0e98003e,
+       0x030f9802,
+       0x0001207e,
+       0xfd070e98,
+       0x2ebb00ef,
+       0x003ebb00,
+       0x800235b6,
+       0xf601d300,
+       0x04bd0003,
+       0xb60825b6,
+       0x20b60635,
+       0x0130b601,
+       0xb60824b6,
+       0x2fb20834,
+       0x0002687e,
+       0x80003fbb,
+       0xf6020100,
+       0x04bd0003,
+       0x29f024bd,
+       0x3000801f,
+       0x0002f602,
+/* 0x0436: main */
+       0x31f404bd,
+       0x0028f400,
+       0x377e240d,
+       0x01f40000,
+       0x04e4b0f4,
+       0xfe1d18f4,
+       0x06020181,
+       0x12fd20bd,
+       0x01e4b604,
+       0xfe051efd,
+       0x097e0018,
+       0x0ef40005,
+/* 0x0465: main_not_ctx_xfer */
+       0x10ef94d4,
+       0x7e01f5f0,
+       0xf40002f8,
+/* 0x0472: ih */
+       0x80f9c70e,
+       0xf90188fe,
+       0xf990f980,
+       0xf9b0f9a0,
+       0xf9e0f9d0,
+       0x4a04bdf0,
+       0xaacf0200,
+       0x04abc400,
+       0x0d1f0bf4,
+       0x1a004e24,
+       0x4f00eecf,
+       0xffcf1900,
+       0x00047e00,
+       0x40010e00,
+       0x0ef61d00,
+/* 0x04af: ih_no_fifo */
+       0x4004bd00,
+       0x0af60100,
+       0xfc04bd00,
+       0xfce0fcf0,
+       0xfcb0fcd0,
+       0xfc90fca0,
+       0x0088fe80,
+       0x32f480fc,
+/* 0x04cf: hub_barrier_done */
+       0x0f01f800,
+       0x040e9801,
+       0xb204febb,
+       0x94188eff,
+       0x008f7e40,
+/* 0x04e3: ctx_redswitch */
+       0x0f00f800,
+       0x85008020,
        0x000ff601,
-       0x00f804bd,
-/* 0x04fc: ctx_xfer */
-       0x02810080,
-       0xbd000ff6,
-       0x0711f404,
-       0x0004d67e,
-/* 0x050c: ctx_xfer_not_load */
-       0x0002167e,
-       0xfc8024bd,
-       0x02f60247,
+       0x080e04bd,
+/* 0x04f0: ctx_redswitch_delay */
+       0xf401e2b6,
+       0xf5f1fd1b,
+       0xf5f10800,
+       0x00800200,
+       0x0ff60185,
+       0xf804bd00,
+/* 0x0509: ctx_xfer */
+       0x81008000,
+       0x000ff602,
+       0x11f404bd,
+       0x04e37e07,
+/* 0x0519: ctx_xfer_not_load */
+       0x02167e00,
+       0x8024bd00,
+       0xf60247fc,
+       0x04bd0002,
+       0xb6012cf0,
+       0xfc800320,
+       0x02f6024a,
        0xf004bd00,
-       0x20b6012c,
-       0x4afc8003,
-       0x0002f602,
-       0xacf004bd,
-       0x02a5f001,
-       0x5000008b,
+       0xa5f001ac,
+       0x00008b02,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x010d9800,
+       0x3d7e000e,
+       0xacf00001,
+       0x40008b01,
+       0x040c9850,
+       0xbb0fc4b6,
+       0x0c9800bc,
+       0x020d9801,
+       0x4e060f98,
+       0x3d7e0800,
+       0xacf00001,
+       0x04a5f001,
+       0x5030008b,
        0xb6040c98,
        0xbcbb0fc4,
-       0x000c9800,
-       0x0e010d98,
-       0x013d7e00,
-       0x01acf000,
-       0x5040008b,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x010c9800,
-       0x98020d98,
-       0x004e060f,
-       0x013d7e08,
-       0x01acf000,
-       0x8b04a5f0,
-       0x98503000,
-       0xc4b6040c,
-       0x00bcbb0f,
-       0x98020c98,
-       0x0f98030d,
-       0x02004e08,
-       0x00013d7e,
-       0x00020a7e,
-       0xf40601f4,
-/* 0x0596: ctx_xfer_post */
-       0x277e0712,
-/* 0x059a: ctx_xfer_done */
-       0xc27e0002,
-       0x00f80004,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x020c9800,
+       0x98030d98,
+       0x004e080f,
+       0x013d7e02,
+       0x020a7e00,
+       0x0601f400,
+/* 0x05a3: ctx_xfer_post */
+       0x7e0712f4,
+/* 0x05a7: ctx_xfer_done */
+       0x7e000227,
+       0xf80004cf,
        0x00000000,
        0x00000000,
        0x00000000,
index 0e7b01e..325cc7b 100644 (file)
@@ -192,7 +192,7 @@ uint32_t nvc0_grgpc_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
@@ -300,182 +300,182 @@ uint32_t nvc0_grgpc_code[] = {
        0x21f440e3,
        0xf8e0fc9d,
 /* 0x03a1: init */
-       0xfe04bd00,
-       0x27f00004,
-       0x0007f102,
-       0x0003f012,
-       0xbd0002d0,
-       0xd517f104,
-       0x0010fe04,
-       0x070007f1,
+       0xf104bd00,
+       0xf0420017,
+       0x11cf0013,
+       0x0911e700,
+       0x0814b601,
+       0xf00014fe,
+       0x07f10227,
+       0x03f01200,
+       0x0002d000,
+       0x17f104bd,
+       0x10fe04e6,
+       0x0007f100,
+       0x0003f007,
+       0xbd0000d0,
+       0x0427f004,
+       0x040007f1,
        0xd00003f0,
-       0x04bd0000,
-       0xf10427f0,
-       0xf0040007,
-       0x02d00003,
-       0xf404bd00,
-       0x27f11031,
-       0x23f08200,
-       0x0022cf01,
-       0xf00137f0,
-       0x32bb1f24,
-       0x0132b604,
-       0x80050280,
-       0x27f10603,
-       0x23f08600,
-       0x0022cf01,
-       0xf1040280,
-       0xf0010027,
-       0x22cf0223,
-       0x9534bd00,
-       0x07f10825,
-       0x03f0c000,
-       0x0005d001,
-       0x07f104bd,
-       0x03f0c100,
-       0x0005d001,
-       0x0e9804bd,
-       0x010f9800,
-       0x015021f5,
-       0xbb002fbb,
-       0x0e98003f,
-       0x020f9801,
-       0x015021f5,
-       0xfd050e98,
-       0x2ebb00ef,
-       0x003ebb00,
-       0xf10235b6,
-       0xf0d30007,
-       0x03d00103,
-       0xb604bd00,
-       0x35b60825,
-       0x0120b606,
-       0xb60130b6,
-       0x34b60824,
-       0x022fb908,
-       0x02d321f5,
-       0xf1003fbb,
-       0xf0010007,
-       0x03d00203,
-       0xbd04bd00,
-       0x1f29f024,
-       0x080007f1,
-       0xd00203f0,
        0x04bd0002,
-/* 0x0498: main */
-       0xf40031f4,
-       0xd7f00028,
-       0x3921f41c,
-       0xb0f401f4,
-       0x18f404e4,
-       0x0181fe1e,
-       0xbd0627f0,
-       0x0412fd20,
-       0xfd01e4b6,
-       0x18fe051e,
-       0x8d21f500,
-       0xd30ef405,
-/* 0x04c8: main_not_ctx_xfer */
-       0xf010ef94,
-       0x21f501f5,
-       0x0ef4037e,
-/* 0x04d5: ih */
-       0xfe80f9c6,
-       0x80f90188,
-       0xa0f990f9,
-       0xd0f9b0f9,
-       0xf0f9e0f9,
-       0xa7f104bd,
-       0xa3f00200,
-       0x00aacf00,
-       0xf404abc4,
-       0xd7f02c0b,
-       0x00e7f11c,
-       0x00e3f01a,
-       0xf100eecf,
-       0xf01900f7,
-       0xffcf00f3,
-       0x0421f400,
-       0xf101e7f0,
-       0xf01d0007,
-       0x0ed00003,
-/* 0x0523: ih_no_fifo */
+       0xf11031f4,
+       0xf0820027,
+       0x22cf0123,
+       0x0137f000,
+       0xbb1f24f0,
+       0x32b60432,
+       0x05028001,
+       0xf1060380,
+       0xf0860027,
+       0x22cf0123,
+       0x04028000,
+       0x010027f1,
+       0xcf0223f0,
+       0x34bd0022,
+       0xf1082595,
+       0xf0c00007,
+       0x05d00103,
        0xf104bd00,
-       0xf0010007,
-       0x0ad00003,
-       0xfc04bd00,
-       0xfce0fcf0,
-       0xfcb0fcd0,
-       0xfc90fca0,
-       0x0088fe80,
-       0x32f480fc,
-/* 0x0547: hub_barrier_done */
-       0xf001f800,
-       0x0e9801f7,
-       0x04febb04,
-       0xf102ffb9,
-       0xf09418e7,
-       0x21f440e3,
-/* 0x055f: ctx_redswitch */
-       0xf000f89d,
-       0x07f120f7,
-       0x03f08500,
-       0x000fd001,
-       0xe7f004bd,
-/* 0x0571: ctx_redswitch_delay */
-       0x01e2b608,
-       0xf1fd1bf4,
-       0xf10800f5,
-       0xf10200f5,
+       0xf0c10007,
+       0x05d00103,
+       0x9804bd00,
+       0x0f98000e,
+       0x5021f501,
+       0x002fbb01,
+       0x98003fbb,
+       0x0f98010e,
+       0x5021f502,
+       0x050e9801,
+       0xbb00effd,
+       0x3ebb002e,
+       0x0235b600,
+       0xd30007f1,
+       0xd00103f0,
+       0x04bd0003,
+       0xb60825b6,
+       0x20b60635,
+       0x0130b601,
+       0xb60824b6,
+       0x2fb90834,
+       0xd321f502,
+       0x003fbb02,
+       0x010007f1,
+       0xd00203f0,
+       0x04bd0003,
+       0x29f024bd,
+       0x0007f11f,
+       0x0203f008,
+       0xbd0002d0,
+/* 0x04a9: main */
+       0x0031f404,
+       0xf00028f4,
+       0x21f41cd7,
+       0xf401f439,
+       0xf404e4b0,
+       0x81fe1e18,
+       0x0627f001,
+       0x12fd20bd,
+       0x01e4b604,
+       0xfe051efd,
+       0x21f50018,
+       0x0ef4059e,
+/* 0x04d9: main_not_ctx_xfer */
+       0x10ef94d3,
+       0xf501f5f0,
+       0xf4037e21,
+/* 0x04e6: ih */
+       0x80f9c60e,
+       0xf90188fe,
+       0xf990f980,
+       0xf9b0f9a0,
+       0xf9e0f9d0,
+       0xf104bdf0,
+       0xf00200a7,
+       0xaacf00a3,
+       0x04abc400,
+       0xf02c0bf4,
+       0xe7f11cd7,
+       0xe3f01a00,
+       0x00eecf00,
+       0x1900f7f1,
+       0xcf00f3f0,
+       0x21f400ff,
+       0x01e7f004,
+       0x1d0007f1,
+       0xd00003f0,
+       0x04bd000e,
+/* 0x0534: ih_no_fifo */
+       0x010007f1,
+       0xd00003f0,
+       0x04bd000a,
+       0xe0fcf0fc,
+       0xb0fcd0fc,
+       0x90fca0fc,
+       0x88fe80fc,
+       0xf480fc00,
+       0x01f80032,
+/* 0x0558: hub_barrier_done */
+       0x9801f7f0,
+       0xfebb040e,
+       0x02ffb904,
+       0x9418e7f1,
+       0xf440e3f0,
+       0x00f89d21,
+/* 0x0570: ctx_redswitch */
+       0xf120f7f0,
        0xf0850007,
        0x0fd00103,
-       0xf804bd00,
-/* 0x058d: ctx_xfer */
-       0x0007f100,
-       0x0203f081,
-       0xbd000fd0,
-       0x0711f404,
-       0x055f21f5,
-/* 0x05a0: ctx_xfer_not_load */
-       0x026a21f5,
-       0x07f124bd,
-       0x03f047fc,
-       0x0002d002,
-       0x2cf004bd,
-       0x0320b601,
-       0x4afc07f1,
-       0xd00203f0,
-       0x04bd0002,
+       0xf004bd00,
+/* 0x0582: ctx_redswitch_delay */
+       0xe2b608e7,
+       0xfd1bf401,
+       0x0800f5f1,
+       0x0200f5f1,
+       0x850007f1,
+       0xd00103f0,
+       0x04bd000f,
+/* 0x059e: ctx_xfer */
+       0x07f100f8,
+       0x03f08100,
+       0x000fd002,
+       0x11f404bd,
+       0x7021f507,
+/* 0x05b1: ctx_xfer_not_load */
+       0x6a21f505,
+       0xf124bd02,
+       0xf047fc07,
+       0x02d00203,
+       0xf004bd00,
+       0x20b6012c,
+       0xfc07f103,
+       0x0203f04a,
+       0xbd0002d0,
+       0x01acf004,
+       0xf102a5f0,
+       0xf00000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98000c,
+       0x00e7f001,
+       0x016f21f5,
        0xf001acf0,
-       0xb7f102a5,
-       0xb3f00000,
+       0xb7f104a5,
+       0xb3f04000,
        0x040c9850,
        0xbb0fc4b6,
        0x0c9800bc,
-       0x010d9800,
-       0xf500e7f0,
-       0xf0016f21,
-       0xa5f001ac,
-       0x00b7f104,
-       0x50b3f040,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x010c9800,
-       0x98020d98,
-       0xe7f1060f,
-       0x21f50800,
-       0x21f5016f,
-       0x01f4025e,
-       0x0712f406,
-/* 0x0618: ctx_xfer_post */
-       0x027f21f5,
-/* 0x061c: ctx_xfer_done */
-       0x054721f5,
-       0x000000f8,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x020d9801,
+       0xf1060f98,
+       0xf50800e7,
+       0xf5016f21,
+       0xf4025e21,
+       0x12f40601,
+/* 0x0629: ctx_xfer_post */
+       0x7f21f507,
+/* 0x062d: ctx_xfer_done */
+       0x5821f502,
+       0x0000f805,
        0x00000000,
        0x00000000,
        0x00000000,
index 84dd32d..d1504a4 100644 (file)
@@ -196,7 +196,7 @@ uint32_t nvd7_grgpc_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
@@ -304,212 +304,212 @@ uint32_t nvd7_grgpc_code[] = {
        0x21f440e3,
        0xf8e0fc9d,
 /* 0x03a1: init */
-       0xfe04bd00,
-       0x27f00004,
-       0x0007f102,
-       0x0003f012,
-       0xbd0002d0,
-       0x1f17f104,
-       0x0010fe05,
-       0x070007f1,
+       0xf104bd00,
+       0xf0420017,
+       0x11cf0013,
+       0x0911e700,
+       0x0814b601,
+       0xf00014fe,
+       0x07f10227,
+       0x03f01200,
+       0x0002d000,
+       0x17f104bd,
+       0x10fe0530,
+       0x0007f100,
+       0x0003f007,
+       0xbd0000d0,
+       0x0427f004,
+       0x040007f1,
        0xd00003f0,
-       0x04bd0000,
-       0xf10427f0,
-       0xf0040007,
-       0x02d00003,
+       0x04bd0002,
+       0xf11031f4,
+       0xf0820027,
+       0x22cf0123,
+       0x0137f000,
+       0xbb1f24f0,
+       0x32b60432,
+       0x05028001,
+       0xf1060380,
+       0xf0860027,
+       0x22cf0123,
+       0x04028000,
+       0x0c30e7f1,
+       0xbd50e3f0,
+       0xbd34bd24,
+/* 0x0421: init_unk_loop */
+       0x6821f444,
+       0xf400f6b0,
+       0xf7f00f0b,
+       0x04f2bb01,
+       0xb6054ffd,
+/* 0x0436: init_unk_next */
+       0x20b60130,
+       0x04e0b601,
+       0xf40126b0,
+/* 0x0442: init_unk_done */
+       0x0380e21b,
+       0x08048007,
+       0x010027f1,
+       0xcf0223f0,
+       0x34bd0022,
+       0xf1082595,
+       0xf0c00007,
+       0x05d00103,
+       0xf104bd00,
+       0xf0c10007,
+       0x05d00103,
+       0x9804bd00,
+       0x0f98000e,
+       0x5021f501,
+       0x002fbb01,
+       0x98003fbb,
+       0x0f98010e,
+       0x5021f502,
+       0x050e9801,
+       0xbb00effd,
+       0x3ebb002e,
+       0x020e9800,
+       0xf5030f98,
+       0x98015021,
+       0xeffd070e,
+       0x002ebb00,
+       0xb6003ebb,
+       0x07f10235,
+       0x03f0d300,
+       0x0003d001,
+       0x25b604bd,
+       0x0635b608,
+       0xb60120b6,
+       0x24b60130,
+       0x0834b608,
+       0xf5022fb9,
+       0xbb02d321,
+       0x07f1003f,
+       0x03f00100,
+       0x0003d002,
+       0x24bd04bd,
+       0xf11f29f0,
+       0xf0080007,
+       0x02d00203,
+/* 0x04f3: main */
        0xf404bd00,
-       0x27f11031,
-       0x23f08200,
-       0x0022cf01,
-       0xf00137f0,
-       0x32bb1f24,
-       0x0132b604,
-       0x80050280,
-       0x27f10603,
-       0x23f08600,
-       0x0022cf01,
-       0xf1040280,
-       0xf00c30e7,
-       0x24bd50e3,
-       0x44bd34bd,
-/* 0x0410: init_unk_loop */
-       0xb06821f4,
-       0x0bf400f6,
-       0x01f7f00f,
-       0xfd04f2bb,
-       0x30b6054f,
-/* 0x0425: init_unk_next */
-       0x0120b601,
-       0xb004e0b6,
-       0x1bf40126,
-/* 0x0431: init_unk_done */
-       0x070380e2,
-       0xf1080480,
-       0xf0010027,
-       0x22cf0223,
-       0x9534bd00,
-       0x07f10825,
-       0x03f0c000,
-       0x0005d001,
+       0x28f40031,
+       0x24d7f000,
+       0xf43921f4,
+       0xe4b0f401,
+       0x1e18f404,
+       0xf00181fe,
+       0x20bd0627,
+       0xb60412fd,
+       0x1efd01e4,
+       0x0018fe05,
+       0x05e821f5,
+/* 0x0523: main_not_ctx_xfer */
+       0x94d30ef4,
+       0xf5f010ef,
+       0x7e21f501,
+       0xc60ef403,
+/* 0x0530: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x00a7f104,
+       0x00a3f002,
+       0xc400aacf,
+       0x0bf404ab,
+       0x24d7f02c,
+       0x1a00e7f1,
+       0xcf00e3f0,
+       0xf7f100ee,
+       0xf3f01900,
+       0x00ffcf00,
+       0xf00421f4,
+       0x07f101e7,
+       0x03f01d00,
+       0x000ed000,
+/* 0x057e: ih_no_fifo */
        0x07f104bd,
-       0x03f0c100,
-       0x0005d001,
-       0x0e9804bd,
-       0x010f9800,
-       0x015021f5,
-       0xbb002fbb,
-       0x0e98003f,
-       0x020f9801,
-       0x015021f5,
-       0xfd050e98,
-       0x2ebb00ef,
-       0x003ebb00,
-       0x98020e98,
-       0x21f5030f,
-       0x0e980150,
-       0x00effd07,
-       0xbb002ebb,
-       0x35b6003e,
-       0x0007f102,
-       0x0103f0d3,
-       0xbd0003d0,
-       0x0825b604,
-       0xb60635b6,
-       0x30b60120,
-       0x0824b601,
-       0xb90834b6,
-       0x21f5022f,
-       0x3fbb02d3,
-       0x0007f100,
-       0x0203f001,
-       0xbd0003d0,
-       0xf024bd04,
-       0x07f11f29,
-       0x03f00800,
-       0x0002d002,
-/* 0x04e2: main */
-       0x31f404bd,
-       0x0028f400,
-       0xf424d7f0,
-       0x01f43921,
-       0x04e4b0f4,
-       0xfe1e18f4,
-       0x27f00181,
-       0xfd20bd06,
-       0xe4b60412,
-       0x051efd01,
-       0xf50018fe,
-       0xf405d721,
-/* 0x0512: main_not_ctx_xfer */
-       0xef94d30e,
-       0x01f5f010,
-       0x037e21f5,
-/* 0x051f: ih */
-       0xf9c60ef4,
-       0x0188fe80,
-       0x90f980f9,
-       0xb0f9a0f9,
-       0xe0f9d0f9,
-       0x04bdf0f9,
-       0x0200a7f1,
-       0xcf00a3f0,
-       0xabc400aa,
-       0x2c0bf404,
-       0xf124d7f0,
-       0xf01a00e7,
-       0xeecf00e3,
-       0x00f7f100,
-       0x00f3f019,
-       0xf400ffcf,
-       0xe7f00421,
-       0x0007f101,
-       0x0003f01d,
-       0xbd000ed0,
-/* 0x056d: ih_no_fifo */
-       0x0007f104,
-       0x0003f001,
-       0xbd000ad0,
-       0xfcf0fc04,
-       0xfcd0fce0,
-       0xfca0fcb0,
-       0xfe80fc90,
-       0x80fc0088,
-       0xf80032f4,
-/* 0x0591: hub_barrier_done */
-       0x01f7f001,
-       0xbb040e98,
-       0xffb904fe,
-       0x18e7f102,
-       0x40e3f094,
-       0xf89d21f4,
-/* 0x05a9: ctx_redswitch */
-       0x20f7f000,
-       0x850007f1,
-       0xd00103f0,
-       0x04bd000f,
-/* 0x05bb: ctx_redswitch_delay */
-       0xb608e7f0,
-       0x1bf401e2,
-       0x00f5f1fd,
-       0x00f5f108,
-       0x0007f102,
+       0x03f00100,
+       0x000ad000,
+       0xf0fc04bd,
+       0xd0fce0fc,
+       0xa0fcb0fc,
+       0x80fc90fc,
+       0xfc0088fe,
+       0x0032f480,
+/* 0x05a2: hub_barrier_done */
+       0xf7f001f8,
+       0x040e9801,
+       0xb904febb,
+       0xe7f102ff,
+       0xe3f09418,
+       0x9d21f440,
+/* 0x05ba: ctx_redswitch */
+       0xf7f000f8,
+       0x0007f120,
        0x0103f085,
        0xbd000fd0,
-/* 0x05d7: ctx_xfer */
-       0xf100f804,
-       0xf0810007,
-       0x0fd00203,
-       0xf404bd00,
-       0x21f50711,
-/* 0x05ea: ctx_xfer_not_load */
-       0x21f505a9,
-       0x24bd026a,
-       0x47fc07f1,
+       0x08e7f004,
+/* 0x05cc: ctx_redswitch_delay */
+       0xf401e2b6,
+       0xf5f1fd1b,
+       0xf5f10800,
+       0x07f10200,
+       0x03f08500,
+       0x000fd001,
+       0x00f804bd,
+/* 0x05e8: ctx_xfer */
+       0x810007f1,
        0xd00203f0,
-       0x04bd0002,
-       0xb6012cf0,
-       0x07f10320,
-       0x03f04afc,
-       0x0002d002,
-       0xacf004bd,
-       0x02a5f001,
-       0x0000b7f1,
-       0x9850b3f0,
-       0xc4b6040c,
-       0x00bcbb0f,
-       0x98000c98,
-       0xe7f0010d,
-       0x6f21f500,
-       0x01acf001,
-       0x4000b7f1,
+       0x04bd000f,
+       0xf50711f4,
+/* 0x05fb: ctx_xfer_not_load */
+       0xf505ba21,
+       0xbd026a21,
+       0xfc07f124,
+       0x0203f047,
+       0xbd0002d0,
+       0x012cf004,
+       0xf10320b6,
+       0xf04afc07,
+       0x02d00203,
+       0xf004bd00,
+       0xa5f001ac,
+       0x00b7f102,
+       0x50b3f000,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x000c9800,
+       0xf0010d98,
+       0x21f500e7,
+       0xacf0016f,
+       0x00b7f101,
+       0x50b3f040,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x010c9800,
+       0x98020d98,
+       0xe7f1060f,
+       0x21f50800,
+       0xacf0016f,
+       0x04a5f001,
+       0x3000b7f1,
        0x9850b3f0,
        0xc4b6040c,
        0x00bcbb0f,
-       0x98010c98,
-       0x0f98020d,
-       0x00e7f106,
-       0x6f21f508,
-       0x01acf001,
-       0xf104a5f0,
-       0xf03000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98020c,
-       0x080f9803,
-       0x0200e7f1,
-       0x016f21f5,
-       0x025e21f5,
-       0xf40601f4,
-/* 0x0686: ctx_xfer_post */
-       0x21f50712,
-/* 0x068a: ctx_xfer_done */
-       0x21f5027f,
-       0x00f80591,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x98020c98,
+       0x0f98030d,
+       0x00e7f108,
+       0x6f21f502,
+       0x5e21f501,
+       0x0601f402,
+/* 0x0697: ctx_xfer_post */
+       0xf50712f4,
+/* 0x069b: ctx_xfer_done */
+       0xf5027f21,
+       0xf805a221,
        0x00000000,
        0x00000000,
        0x00000000,
index b6da800..855b220 100644 (file)
@@ -196,7 +196,7 @@ uint32_t nve0_grgpc_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
@@ -304,212 +304,212 @@ uint32_t nve0_grgpc_code[] = {
        0x21f440e3,
        0xf8e0fc9d,
 /* 0x03a1: init */
-       0xfe04bd00,
-       0x27f00004,
-       0x0007f102,
-       0x0003f012,
-       0xbd0002d0,
-       0x1f17f104,
-       0x0010fe05,
-       0x070007f1,
+       0xf104bd00,
+       0xf0420017,
+       0x11cf0013,
+       0x0911e700,
+       0x0814b601,
+       0xf00014fe,
+       0x07f10227,
+       0x03f01200,
+       0x0002d000,
+       0x17f104bd,
+       0x10fe0530,
+       0x0007f100,
+       0x0003f007,
+       0xbd0000d0,
+       0x0427f004,
+       0x040007f1,
        0xd00003f0,
-       0x04bd0000,
-       0xf10427f0,
-       0xf0040007,
-       0x02d00003,
+       0x04bd0002,
+       0xf11031f4,
+       0xf0820027,
+       0x22cf0123,
+       0x0137f000,
+       0xbb1f24f0,
+       0x32b60432,
+       0x05028001,
+       0xf1060380,
+       0xf0860027,
+       0x22cf0123,
+       0x04028000,
+       0x0c30e7f1,
+       0xbd50e3f0,
+       0xbd34bd24,
+/* 0x0421: init_unk_loop */
+       0x6821f444,
+       0xf400f6b0,
+       0xf7f00f0b,
+       0x04f2bb01,
+       0xb6054ffd,
+/* 0x0436: init_unk_next */
+       0x20b60130,
+       0x04e0b601,
+       0xf40126b0,
+/* 0x0442: init_unk_done */
+       0x0380e21b,
+       0x08048007,
+       0x010027f1,
+       0xcf0223f0,
+       0x34bd0022,
+       0xf1082595,
+       0xf0c00007,
+       0x05d00103,
+       0xf104bd00,
+       0xf0c10007,
+       0x05d00103,
+       0x9804bd00,
+       0x0f98000e,
+       0x5021f501,
+       0x002fbb01,
+       0x98003fbb,
+       0x0f98010e,
+       0x5021f502,
+       0x050e9801,
+       0xbb00effd,
+       0x3ebb002e,
+       0x020e9800,
+       0xf5030f98,
+       0x98015021,
+       0xeffd070e,
+       0x002ebb00,
+       0xb6003ebb,
+       0x07f10235,
+       0x03f0d300,
+       0x0003d001,
+       0x25b604bd,
+       0x0635b608,
+       0xb60120b6,
+       0x24b60130,
+       0x0834b608,
+       0xf5022fb9,
+       0xbb02d321,
+       0x07f1003f,
+       0x03f00100,
+       0x0003d002,
+       0x24bd04bd,
+       0xf11f29f0,
+       0xf0080007,
+       0x02d00203,
+/* 0x04f3: main */
        0xf404bd00,
-       0x27f11031,
-       0x23f08200,
-       0x0022cf01,
-       0xf00137f0,
-       0x32bb1f24,
-       0x0132b604,
-       0x80050280,
-       0x27f10603,
-       0x23f08600,
-       0x0022cf01,
-       0xf1040280,
-       0xf00c30e7,
-       0x24bd50e3,
-       0x44bd34bd,
-/* 0x0410: init_unk_loop */
-       0xb06821f4,
-       0x0bf400f6,
-       0x01f7f00f,
-       0xfd04f2bb,
-       0x30b6054f,
-/* 0x0425: init_unk_next */
-       0x0120b601,
-       0xb004e0b6,
-       0x1bf40126,
-/* 0x0431: init_unk_done */
-       0x070380e2,
-       0xf1080480,
-       0xf0010027,
-       0x22cf0223,
-       0x9534bd00,
-       0x07f10825,
-       0x03f0c000,
-       0x0005d001,
+       0x28f40031,
+       0x24d7f000,
+       0xf43921f4,
+       0xe4b0f401,
+       0x1e18f404,
+       0xf00181fe,
+       0x20bd0627,
+       0xb60412fd,
+       0x1efd01e4,
+       0x0018fe05,
+       0x05e821f5,
+/* 0x0523: main_not_ctx_xfer */
+       0x94d30ef4,
+       0xf5f010ef,
+       0x7e21f501,
+       0xc60ef403,
+/* 0x0530: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x00a7f104,
+       0x00a3f002,
+       0xc400aacf,
+       0x0bf404ab,
+       0x24d7f02c,
+       0x1a00e7f1,
+       0xcf00e3f0,
+       0xf7f100ee,
+       0xf3f01900,
+       0x00ffcf00,
+       0xf00421f4,
+       0x07f101e7,
+       0x03f01d00,
+       0x000ed000,
+/* 0x057e: ih_no_fifo */
        0x07f104bd,
-       0x03f0c100,
-       0x0005d001,
-       0x0e9804bd,
-       0x010f9800,
-       0x015021f5,
-       0xbb002fbb,
-       0x0e98003f,
-       0x020f9801,
-       0x015021f5,
-       0xfd050e98,
-       0x2ebb00ef,
-       0x003ebb00,
-       0x98020e98,
-       0x21f5030f,
-       0x0e980150,
-       0x00effd07,
-       0xbb002ebb,
-       0x35b6003e,
-       0x0007f102,
-       0x0103f0d3,
-       0xbd0003d0,
-       0x0825b604,
-       0xb60635b6,
-       0x30b60120,
-       0x0824b601,
-       0xb90834b6,
-       0x21f5022f,
-       0x3fbb02d3,
-       0x0007f100,
-       0x0203f001,
-       0xbd0003d0,
-       0xf024bd04,
-       0x07f11f29,
-       0x03f00800,
-       0x0002d002,
-/* 0x04e2: main */
-       0x31f404bd,
-       0x0028f400,
-       0xf424d7f0,
-       0x01f43921,
-       0x04e4b0f4,
-       0xfe1e18f4,
-       0x27f00181,
-       0xfd20bd06,
-       0xe4b60412,
-       0x051efd01,
-       0xf50018fe,
-       0xf405d721,
-/* 0x0512: main_not_ctx_xfer */
-       0xef94d30e,
-       0x01f5f010,
-       0x037e21f5,
-/* 0x051f: ih */
-       0xf9c60ef4,
-       0x0188fe80,
-       0x90f980f9,
-       0xb0f9a0f9,
-       0xe0f9d0f9,
-       0x04bdf0f9,
-       0x0200a7f1,
-       0xcf00a3f0,
-       0xabc400aa,
-       0x2c0bf404,
-       0xf124d7f0,
-       0xf01a00e7,
-       0xeecf00e3,
-       0x00f7f100,
-       0x00f3f019,
-       0xf400ffcf,
-       0xe7f00421,
-       0x0007f101,
-       0x0003f01d,
-       0xbd000ed0,
-/* 0x056d: ih_no_fifo */
-       0x0007f104,
-       0x0003f001,
-       0xbd000ad0,
-       0xfcf0fc04,
-       0xfcd0fce0,
-       0xfca0fcb0,
-       0xfe80fc90,
-       0x80fc0088,
-       0xf80032f4,
-/* 0x0591: hub_barrier_done */
-       0x01f7f001,
-       0xbb040e98,
-       0xffb904fe,
-       0x18e7f102,
-       0x40e3f094,
-       0xf89d21f4,
-/* 0x05a9: ctx_redswitch */
-       0x20f7f000,
-       0x850007f1,
-       0xd00103f0,
-       0x04bd000f,
-/* 0x05bb: ctx_redswitch_delay */
-       0xb608e7f0,
-       0x1bf401e2,
-       0x00f5f1fd,
-       0x00f5f108,
-       0x0007f102,
+       0x03f00100,
+       0x000ad000,
+       0xf0fc04bd,
+       0xd0fce0fc,
+       0xa0fcb0fc,
+       0x80fc90fc,
+       0xfc0088fe,
+       0x0032f480,
+/* 0x05a2: hub_barrier_done */
+       0xf7f001f8,
+       0x040e9801,
+       0xb904febb,
+       0xe7f102ff,
+       0xe3f09418,
+       0x9d21f440,
+/* 0x05ba: ctx_redswitch */
+       0xf7f000f8,
+       0x0007f120,
        0x0103f085,
        0xbd000fd0,
-/* 0x05d7: ctx_xfer */
-       0xf100f804,
-       0xf0810007,
-       0x0fd00203,
-       0xf404bd00,
-       0x21f50711,
-/* 0x05ea: ctx_xfer_not_load */
-       0x21f505a9,
-       0x24bd026a,
-       0x47fc07f1,
+       0x08e7f004,
+/* 0x05cc: ctx_redswitch_delay */
+       0xf401e2b6,
+       0xf5f1fd1b,
+       0xf5f10800,
+       0x07f10200,
+       0x03f08500,
+       0x000fd001,
+       0x00f804bd,
+/* 0x05e8: ctx_xfer */
+       0x810007f1,
        0xd00203f0,
-       0x04bd0002,
-       0xb6012cf0,
-       0x07f10320,
-       0x03f04afc,
-       0x0002d002,
-       0xacf004bd,
-       0x02a5f001,
-       0x0000b7f1,
-       0x9850b3f0,
-       0xc4b6040c,
-       0x00bcbb0f,
-       0x98000c98,
-       0xe7f0010d,
-       0x6f21f500,
-       0x01acf001,
-       0x4000b7f1,
+       0x04bd000f,
+       0xf50711f4,
+/* 0x05fb: ctx_xfer_not_load */
+       0xf505ba21,
+       0xbd026a21,
+       0xfc07f124,
+       0x0203f047,
+       0xbd0002d0,
+       0x012cf004,
+       0xf10320b6,
+       0xf04afc07,
+       0x02d00203,
+       0xf004bd00,
+       0xa5f001ac,
+       0x00b7f102,
+       0x50b3f000,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x000c9800,
+       0xf0010d98,
+       0x21f500e7,
+       0xacf0016f,
+       0x00b7f101,
+       0x50b3f040,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x010c9800,
+       0x98020d98,
+       0xe7f1060f,
+       0x21f50800,
+       0xacf0016f,
+       0x04a5f001,
+       0x3000b7f1,
        0x9850b3f0,
        0xc4b6040c,
        0x00bcbb0f,
-       0x98010c98,
-       0x0f98020d,
-       0x00e7f106,
-       0x6f21f508,
-       0x01acf001,
-       0xf104a5f0,
-       0xf03000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98020c,
-       0x080f9803,
-       0x0200e7f1,
-       0x016f21f5,
-       0x025e21f5,
-       0xf40601f4,
-/* 0x0686: ctx_xfer_post */
-       0x21f50712,
-/* 0x068a: ctx_xfer_done */
-       0x21f5027f,
-       0x00f80591,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x98020c98,
+       0x0f98030d,
+       0x00e7f108,
+       0x6f21f502,
+       0x5e21f501,
+       0x0601f402,
+/* 0x0697: ctx_xfer_post */
+       0xf50712f4,
+/* 0x069b: ctx_xfer_done */
+       0xf5027f21,
+       0xf805a221,
        0x00000000,
        0x00000000,
        0x00000000,
index 6316eba..1b80319 100644 (file)
@@ -196,7 +196,7 @@ uint32_t nvf0_grgpc_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
@@ -304,212 +304,212 @@ uint32_t nvf0_grgpc_code[] = {
        0x21f440e3,
        0xf8e0fc9d,
 /* 0x03a1: init */
-       0xfe04bd00,
-       0x27f00004,
-       0x0007f102,
-       0x0003f012,
-       0xbd0002d0,
-       0x1f17f104,
-       0x0010fe05,
-       0x070007f1,
+       0xf104bd00,
+       0xf0420017,
+       0x11cf0013,
+       0x0911e700,
+       0x0814b601,
+       0xf00014fe,
+       0x07f10227,
+       0x03f01200,
+       0x0002d000,
+       0x17f104bd,
+       0x10fe0530,
+       0x0007f100,
+       0x0003f007,
+       0xbd0000d0,
+       0x0427f004,
+       0x040007f1,
        0xd00003f0,
-       0x04bd0000,
-       0xf10427f0,
-       0xf0040007,
-       0x02d00003,
+       0x04bd0002,
+       0xf11031f4,
+       0xf0820027,
+       0x22cf0123,
+       0x0137f000,
+       0xbb1f24f0,
+       0x32b60432,
+       0x05028001,
+       0xf1060380,
+       0xf0860027,
+       0x22cf0123,
+       0x04028000,
+       0x0c30e7f1,
+       0xbd50e3f0,
+       0xbd34bd24,
+/* 0x0421: init_unk_loop */
+       0x6821f444,
+       0xf400f6b0,
+       0xf7f00f0b,
+       0x04f2bb01,
+       0xb6054ffd,
+/* 0x0436: init_unk_next */
+       0x20b60130,
+       0x04e0b601,
+       0xf40226b0,
+/* 0x0442: init_unk_done */
+       0x0380e21b,
+       0x08048007,
+       0x010027f1,
+       0xcf0223f0,
+       0x34bd0022,
+       0xf1082595,
+       0xf0c00007,
+       0x05d00103,
+       0xf104bd00,
+       0xf0c10007,
+       0x05d00103,
+       0x9804bd00,
+       0x0f98000e,
+       0x5021f501,
+       0x002fbb01,
+       0x98003fbb,
+       0x0f98010e,
+       0x5021f502,
+       0x050e9801,
+       0xbb00effd,
+       0x3ebb002e,
+       0x020e9800,
+       0xf5030f98,
+       0x98015021,
+       0xeffd070e,
+       0x002ebb00,
+       0xb6003ebb,
+       0x07f10235,
+       0x03f0d300,
+       0x0003d001,
+       0x25b604bd,
+       0x0635b608,
+       0xb60120b6,
+       0x24b60130,
+       0x0834b608,
+       0xf5022fb9,
+       0xbb02d321,
+       0x07f1003f,
+       0x03f00100,
+       0x0003d002,
+       0x24bd04bd,
+       0xf11f29f0,
+       0xf0300007,
+       0x02d00203,
+/* 0x04f3: main */
        0xf404bd00,
-       0x27f11031,
-       0x23f08200,
-       0x0022cf01,
-       0xf00137f0,
-       0x32bb1f24,
-       0x0132b604,
-       0x80050280,
-       0x27f10603,
-       0x23f08600,
-       0x0022cf01,
-       0xf1040280,
-       0xf00c30e7,
-       0x24bd50e3,
-       0x44bd34bd,
-/* 0x0410: init_unk_loop */
-       0xb06821f4,
-       0x0bf400f6,
-       0x01f7f00f,
-       0xfd04f2bb,
-       0x30b6054f,
-/* 0x0425: init_unk_next */
-       0x0120b601,
-       0xb004e0b6,
-       0x1bf40226,
-/* 0x0431: init_unk_done */
-       0x070380e2,
-       0xf1080480,
-       0xf0010027,
-       0x22cf0223,
-       0x9534bd00,
-       0x07f10825,
-       0x03f0c000,
-       0x0005d001,
+       0x28f40031,
+       0x24d7f000,
+       0xf43921f4,
+       0xe4b0f401,
+       0x1e18f404,
+       0xf00181fe,
+       0x20bd0627,
+       0xb60412fd,
+       0x1efd01e4,
+       0x0018fe05,
+       0x05e821f5,
+/* 0x0523: main_not_ctx_xfer */
+       0x94d30ef4,
+       0xf5f010ef,
+       0x7e21f501,
+       0xc60ef403,
+/* 0x0530: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x00a7f104,
+       0x00a3f002,
+       0xc400aacf,
+       0x0bf404ab,
+       0x24d7f02c,
+       0x1a00e7f1,
+       0xcf00e3f0,
+       0xf7f100ee,
+       0xf3f01900,
+       0x00ffcf00,
+       0xf00421f4,
+       0x07f101e7,
+       0x03f01d00,
+       0x000ed000,
+/* 0x057e: ih_no_fifo */
        0x07f104bd,
-       0x03f0c100,
-       0x0005d001,
-       0x0e9804bd,
-       0x010f9800,
-       0x015021f5,
-       0xbb002fbb,
-       0x0e98003f,
-       0x020f9801,
-       0x015021f5,
-       0xfd050e98,
-       0x2ebb00ef,
-       0x003ebb00,
-       0x98020e98,
-       0x21f5030f,
-       0x0e980150,
-       0x00effd07,
-       0xbb002ebb,
-       0x35b6003e,
-       0x0007f102,
-       0x0103f0d3,
-       0xbd0003d0,
-       0x0825b604,
-       0xb60635b6,
-       0x30b60120,
-       0x0824b601,
-       0xb90834b6,
-       0x21f5022f,
-       0x3fbb02d3,
-       0x0007f100,
-       0x0203f001,
-       0xbd0003d0,
-       0xf024bd04,
-       0x07f11f29,
-       0x03f03000,
-       0x0002d002,
-/* 0x04e2: main */
-       0x31f404bd,
-       0x0028f400,
-       0xf424d7f0,
-       0x01f43921,
-       0x04e4b0f4,
-       0xfe1e18f4,
-       0x27f00181,
-       0xfd20bd06,
-       0xe4b60412,
-       0x051efd01,
-       0xf50018fe,
-       0xf405d721,
-/* 0x0512: main_not_ctx_xfer */
-       0xef94d30e,
-       0x01f5f010,
-       0x037e21f5,
-/* 0x051f: ih */
-       0xf9c60ef4,
-       0x0188fe80,
-       0x90f980f9,
-       0xb0f9a0f9,
-       0xe0f9d0f9,
-       0x04bdf0f9,
-       0x0200a7f1,
-       0xcf00a3f0,
-       0xabc400aa,
-       0x2c0bf404,
-       0xf124d7f0,
-       0xf01a00e7,
-       0xeecf00e3,
-       0x00f7f100,
-       0x00f3f019,
-       0xf400ffcf,
-       0xe7f00421,
-       0x0007f101,
-       0x0003f01d,
-       0xbd000ed0,
-/* 0x056d: ih_no_fifo */
-       0x0007f104,
-       0x0003f001,
-       0xbd000ad0,
-       0xfcf0fc04,
-       0xfcd0fce0,
-       0xfca0fcb0,
-       0xfe80fc90,
-       0x80fc0088,
-       0xf80032f4,
-/* 0x0591: hub_barrier_done */
-       0x01f7f001,
-       0xbb040e98,
-       0xffb904fe,
-       0x18e7f102,
-       0x40e3f094,
-       0xf89d21f4,
-/* 0x05a9: ctx_redswitch */
-       0x20f7f000,
-       0x850007f1,
-       0xd00103f0,
-       0x04bd000f,
-/* 0x05bb: ctx_redswitch_delay */
-       0xb608e7f0,
-       0x1bf401e2,
-       0x00f5f1fd,
-       0x00f5f108,
-       0x0007f102,
+       0x03f00100,
+       0x000ad000,
+       0xf0fc04bd,
+       0xd0fce0fc,
+       0xa0fcb0fc,
+       0x80fc90fc,
+       0xfc0088fe,
+       0x0032f480,
+/* 0x05a2: hub_barrier_done */
+       0xf7f001f8,
+       0x040e9801,
+       0xb904febb,
+       0xe7f102ff,
+       0xe3f09418,
+       0x9d21f440,
+/* 0x05ba: ctx_redswitch */
+       0xf7f000f8,
+       0x0007f120,
        0x0103f085,
        0xbd000fd0,
-/* 0x05d7: ctx_xfer */
-       0xf100f804,
-       0xf0810007,
-       0x0fd00203,
-       0xf404bd00,
-       0x21f50711,
-/* 0x05ea: ctx_xfer_not_load */
-       0x21f505a9,
-       0x24bd026a,
-       0x47fc07f1,
+       0x08e7f004,
+/* 0x05cc: ctx_redswitch_delay */
+       0xf401e2b6,
+       0xf5f1fd1b,
+       0xf5f10800,
+       0x07f10200,
+       0x03f08500,
+       0x000fd001,
+       0x00f804bd,
+/* 0x05e8: ctx_xfer */
+       0x810007f1,
        0xd00203f0,
-       0x04bd0002,
-       0xb6012cf0,
-       0x07f10320,
-       0x03f04afc,
-       0x0002d002,
-       0xacf004bd,
-       0x02a5f001,
-       0x0000b7f1,
-       0x9850b3f0,
-       0xc4b6040c,
-       0x00bcbb0f,
-       0x98000c98,
-       0xe7f0010d,
-       0x6f21f500,
-       0x01acf001,
-       0x4000b7f1,
+       0x04bd000f,
+       0xf50711f4,
+/* 0x05fb: ctx_xfer_not_load */
+       0xf505ba21,
+       0xbd026a21,
+       0xfc07f124,
+       0x0203f047,
+       0xbd0002d0,
+       0x012cf004,
+       0xf10320b6,
+       0xf04afc07,
+       0x02d00203,
+       0xf004bd00,
+       0xa5f001ac,
+       0x00b7f102,
+       0x50b3f000,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x000c9800,
+       0xf0010d98,
+       0x21f500e7,
+       0xacf0016f,
+       0x00b7f101,
+       0x50b3f040,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x010c9800,
+       0x98020d98,
+       0xe7f1060f,
+       0x21f50800,
+       0xacf0016f,
+       0x04a5f001,
+       0x3000b7f1,
        0x9850b3f0,
        0xc4b6040c,
        0x00bcbb0f,
-       0x98010c98,
-       0x0f98020d,
-       0x00e7f106,
-       0x6f21f508,
-       0x01acf001,
-       0xf104a5f0,
-       0xf03000b7,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98020c,
-       0x080f9803,
-       0x0200e7f1,
-       0x016f21f5,
-       0x025e21f5,
-       0xf40601f4,
-/* 0x0686: ctx_xfer_post */
-       0x21f50712,
-/* 0x068a: ctx_xfer_done */
-       0x21f5027f,
-       0x00f80591,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x98020c98,
+       0x0f98030d,
+       0x00e7f108,
+       0x6f21f502,
+       0x5e21f501,
+       0x0601f402,
+/* 0x0697: ctx_xfer_post */
+       0xf50712f4,
+/* 0x069b: ctx_xfer_done */
+       0xf5027f21,
+       0xf805a221,
        0x00000000,
        0x00000000,
        0x00000000,
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5
new file mode 100644 (file)
index 0000000..27591b3
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK208
+#include "macros.fuc"
+
+.section #gm107_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gm107_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h
new file mode 100644 (file)
index 0000000..214dd16
--- /dev/null
@@ -0,0 +1,916 @@
+uint32_t gm107_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+       0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+       0x00000304,
+/* 0x0008: gpc_count */
+       0x00000000,
+/* 0x000c: rop_count */
+       0x00000000,
+/* 0x0010: cmd_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0058: ctx_current */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+       0x00000000,
+/* 0x0104: chan_mmio_address */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0200: xfer_data */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0300: hub_mmio_list_base */
+       0x0417e91c,
+};
+
+uint32_t gm107_grhub_code[] = {
+       0x030e0ef5,
+/* 0x0004: queue_put */
+       0x9800d898,
+       0x86f001d9,
+       0xf489a408,
+       0x020f0b1b,
+       0x0002f87e,
+/* 0x001a: queue_put_next */
+       0x98c400f8,
+       0x0384b607,
+       0xb6008dbb,
+       0x8eb50880,
+       0x018fb500,
+       0xf00190b6,
+       0xd9b50f94,
+/* 0x0037: queue_get */
+       0xf400f801,
+       0xd8980131,
+       0x01d99800,
+       0x0bf489a4,
+       0x0789c421,
+       0xbb0394b6,
+       0x90b6009d,
+       0x009e9808,
+       0xb6019f98,
+       0x84f00180,
+       0x00d8b50f,
+/* 0x0063: queue_get_done */
+       0xf80132f4,
+/* 0x0065: nv_rd32 */
+       0xf0ecb200,
+       0x00801fc9,
+       0x0cf601ca,
+/* 0x0073: nv_rd32_wait */
+       0x8c04bd00,
+       0xcf01ca00,
+       0xccc800cc,
+       0xf61bf41f,
+       0xec7e060a,
+       0x008f0000,
+       0xffcf01cb,
+/* 0x008f: nv_wr32 */
+       0x8000f800,
+       0xf601cc00,
+       0x04bd000f,
+       0xc9f0ecb2,
+       0x1ec9f01f,
+       0x01ca0080,
+       0xbd000cf6,
+/* 0x00a9: nv_wr32_wait */
+       0xca008c04,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f61b,
+/* 0x00b8: wait_donez */
+       0x99f094bd,
+       0x37008000,
+       0x0009f602,
+       0x008004bd,
+       0x0af60206,
+/* 0x00cf: wait_donez_ne */
+       0x8804bd00,
+       0xcf010000,
+       0x8aff0088,
+       0xf61bf488,
+       0x99f094bd,
+       0x17008000,
+       0x0009f602,
+       0x00f804bd,
+/* 0x00ec: wait_doneo */
+       0x99f094bd,
+       0x37008000,
+       0x0009f602,
+       0x008004bd,
+       0x0af60206,
+/* 0x0103: wait_doneo_e */
+       0x8804bd00,
+       0xcf010000,
+       0x8aff0088,
+       0xf60bf488,
+       0x99f094bd,
+       0x17008000,
+       0x0009f602,
+       0x00f804bd,
+/* 0x0120: mmctx_size */
+/* 0x0122: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0x1bf4efa4,
+       0xf89fb2ec,
+/* 0x013d: mmctx_xfer */
+       0xf094bd00,
+       0x00800199,
+       0x09f60237,
+       0xbd04bd00,
+       0x05bbfd94,
+       0x800f0bf4,
+       0xf601c400,
+       0x04bd000b,
+/* 0x015f: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0xc6008018,
+       0x000ef601,
+       0x008004bd,
+       0x0ff601c7,
+       0xf004bd00,
+/* 0x017a: mmctx_multi_disabled */
+       0xabc80199,
+       0x10b4b600,
+       0xc80cb9f0,
+       0xe4b601ae,
+       0x05befd11,
+       0x01c50080,
+       0xbd000bf6,
+/* 0x0195: mmctx_exec_loop */
+/* 0x0195: mmctx_wait_free */
+       0xc5008e04,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f60b,
+       0x05e9fd00,
+       0x01c80080,
+       0xbd000ef6,
+       0x04c0b604,
+       0x1bf4cda4,
+       0x02abc8df,
+/* 0x01bf: mmctx_fini_wait */
+       0x8b1c1bf4,
+       0xcf01c500,
+       0xb4f000bb,
+       0x10b4b01f,
+       0x0af31bf4,
+       0x00b87e05,
+       0x250ef400,
+/* 0x01d8: mmctx_stop */
+       0xb600abc8,
+       0xb9f010b4,
+       0x12b9f00c,
+       0x01c50080,
+       0xbd000bf6,
+/* 0x01ed: mmctx_stop_wait */
+       0xc5008b04,
+       0x00bbcf01,
+       0xf412bbc8,
+/* 0x01fa: mmctx_done */
+       0x94bdf61b,
+       0x800199f0,
+       0xf6021700,
+       0x04bd0009,
+/* 0x020a: strand_wait */
+       0xa0f900f8,
+       0xb87e020a,
+       0xa0fc0000,
+/* 0x0216: strand_pre */
+       0x0c0900f8,
+       0x024afc80,
+       0xbd0009f6,
+       0x020a7e04,
+/* 0x0227: strand_post */
+       0x0900f800,
+       0x4afc800d,
+       0x0009f602,
+       0x0a7e04bd,
+       0x00f80002,
+/* 0x0238: strand_set */
+       0xfc800f0c,
+       0x0cf6024f,
+       0x0c04bd00,
+       0x4afc800b,
+       0x000cf602,
+       0xfc8004bd,
+       0x0ef6024f,
+       0x0c04bd00,
+       0x4afc800a,
+       0x000cf602,
+       0x0a7e04bd,
+       0x00f80002,
+/* 0x0268: strand_ctx_init */
+       0x99f094bd,
+       0x37008003,
+       0x0009f602,
+       0x167e04bd,
+       0x030e0002,
+       0x0002387e,
+       0xfc80c4bd,
+       0x0cf60247,
+       0x0c04bd00,
+       0x4afc8001,
+       0x000cf602,
+       0x0a7e04bd,
+       0x0c920002,
+       0x46fc8001,
+       0x000cf602,
+       0x020c04bd,
+       0x024afc80,
+       0xbd000cf6,
+       0x020a7e04,
+       0x02277e00,
+       0x42008800,
+       0x20008902,
+       0x0099cf02,
+/* 0x02c7: ctx_init_strand_loop */
+       0xf608fe95,
+       0x8ef6008e,
+       0x808acf40,
+       0xb606a5b6,
+       0xeabb01a0,
+       0x0480b600,
+       0xf40192b6,
+       0xe4b6e81b,
+       0xf2efbc08,
+       0x99f094bd,
+       0x17008003,
+       0x0009f602,
+       0x00f804bd,
+/* 0x02f8: error */
+       0x02050080,
+       0xbd000ff6,
+       0x80010f04,
+       0xf6030700,
+       0x04bd000f,
+/* 0x030e: init */
+       0x04bd00f8,
+       0x410007fe,
+       0x11cf4200,
+       0x0911e700,
+       0x0814b601,
+       0x020014fe,
+       0x12004002,
+       0xbd0002f6,
+       0x05c94104,
+       0xbd0010fe,
+       0x07004024,
+       0xbd0002f6,
+       0x20034204,
+       0x01010080,
+       0xbd0002f6,
+       0x20044204,
+       0x01010480,
+       0xbd0002f6,
+       0x200b4204,
+       0x01010880,
+       0xbd0002f6,
+       0x200c4204,
+       0x01011c80,
+       0xbd0002f6,
+       0x01039204,
+       0x03090080,
+       0xbd0003f6,
+       0x87044204,
+       0xf6040040,
+       0x04bd0002,
+       0x00400402,
+       0x0002f603,
+       0x31f404bd,
+       0x96048e10,
+       0x00657e40,
+       0xc7feb200,
+       0x01b590f1,
+       0x1ff4f003,
+       0x01020fb5,
+       0x041fbb01,
+       0x800112b6,
+       0xf6010300,
+       0x04bd0001,
+       0x01040080,
+       0xbd0001f6,
+       0x01004104,
+       0x627e020f,
+       0x717e0006,
+       0x100f0006,
+       0x0006b37e,
+       0x98000e98,
+       0x207e010f,
+       0x14950001,
+       0xc0008008,
+       0x0004f601,
+       0x008004bd,
+       0x04f601c1,
+       0xb704bd00,
+       0xbb130030,
+       0xf5b6001f,
+       0xd3008002,
+       0x000ff601,
+       0x15b604bd,
+       0x0110b608,
+       0xb20814b6,
+       0x02687e1f,
+       0x001fbb00,
+       0x84020398,
+/* 0x041f: init_gpc */
+       0xb8502000,
+       0x0008044e,
+       0x8f7e1fb2,
+       0x4eb80000,
+       0xbd00010c,
+       0x008f7ef4,
+       0x044eb800,
+       0x8f7e0001,
+       0x4eb80000,
+       0x0f000100,
+       0x008f7e02,
+       0x004eb800,
+/* 0x044e: init_gpc_wait */
+       0x657e0008,
+       0xffc80000,
+       0xf90bf41f,
+       0x08044eb8,
+       0x00657e00,
+       0x001fbb00,
+       0x800040b7,
+       0xf40132b6,
+       0x000fb41b,
+       0x0006b37e,
+       0x627e000f,
+       0x00800006,
+       0x01f60201,
+       0xbd04bd00,
+       0x1f19f014,
+       0x02300080,
+       0xbd0001f6,
+/* 0x0491: main */
+       0x0031f404,
+       0x0d0028f4,
+       0x00377e10,
+       0xf401f400,
+       0x4001e4b1,
+       0x00c71bf5,
+       0x99f094bd,
+       0x37008004,
+       0x0009f602,
+       0x008104bd,
+       0x11cf02c0,
+       0xc1008200,
+       0x0022cf02,
+       0xf41f13c8,
+       0x23c8770b,
+       0x550bf41f,
+       0x12b220f9,
+       0x99f094bd,
+       0x37008007,
+       0x0009f602,
+       0x32f404bd,
+       0x0231f401,
+       0x0008367e,
+       0x99f094bd,
+       0x17008007,
+       0x0009f602,
+       0x20fc04bd,
+       0x99f094bd,
+       0x37008006,
+       0x0009f602,
+       0x31f404bd,
+       0x08367e01,
+       0xf094bd00,
+       0x00800699,
+       0x09f60217,
+       0xf404bd00,
+/* 0x0522: chsw_prev_no_next */
+       0x20f92f0e,
+       0x32f412b2,
+       0x0232f401,
+       0x0008367e,
+       0x008020fc,
+       0x02f602c0,
+       0xf404bd00,
+/* 0x053e: chsw_no_prev */
+       0x23c8130e,
+       0x0d0bf41f,
+       0xf40131f4,
+       0x367e0232,
+/* 0x054e: chsw_done */
+       0x01020008,
+       0x02c30080,
+       0xbd0002f6,
+       0xf094bd04,
+       0x00800499,
+       0x09f60217,
+       0xf504bd00,
+/* 0x056b: main_not_ctx_switch */
+       0xb0ff2a0e,
+       0x1bf401e4,
+       0x7ef2b20c,
+       0xf40007d6,
+/* 0x057a: main_not_ctx_chan */
+       0xe4b0400e,
+       0x2c1bf402,
+       0x99f094bd,
+       0x37008007,
+       0x0009f602,
+       0x32f404bd,
+       0x0232f401,
+       0x0008367e,
+       0x99f094bd,
+       0x17008007,
+       0x0009f602,
+       0x0ef404bd,
+/* 0x05a9: main_not_ctx_save */
+       0x10ef9411,
+       0x7e01f5f0,
+       0xf50002f8,
+/* 0x05b7: main_done */
+       0xbdfede0e,
+       0x1f29f024,
+       0x02300080,
+       0xbd0002f6,
+       0xcc0ef504,
+/* 0x05c9: ih */
+       0xfe80f9fe,
+       0x80f90188,
+       0xa0f990f9,
+       0xd0f9b0f9,
+       0xf0f9e0f9,
+       0x004a04bd,
+       0x00aacf02,
+       0xf404abc4,
+       0x100d230b,
+       0xcf1a004e,
+       0x004f00ee,
+       0x00ffcf19,
+       0x0000047e,
+       0x0400b0b7,
+       0x0040010e,
+       0x000ef61d,
+/* 0x060a: ih_no_fifo */
+       0xabe404bd,
+       0x0bf40100,
+       0x4e100d0c,
+       0x047e4001,
+/* 0x061a: ih_no_ctxsw */
+       0xabe40000,
+       0x0bf40400,
+       0x01004b10,
+       0x448ebfb2,
+       0x8f7e4001,
+/* 0x062e: ih_no_fwmthd */
+       0x044b0000,
+       0xffb0bd01,
+       0x0bf4b4ab,
+       0x0700800c,
+       0x000bf603,
+/* 0x0642: ih_no_other */
+       0x004004bd,
+       0x000af601,
+       0xf0fc04bd,
+       0xd0fce0fc,
+       0xa0fcb0fc,
+       0x80fc90fc,
+       0xfc0088fe,
+       0x0032f480,
+/* 0x0662: ctx_4170s */
+       0xf5f001f8,
+       0x8effb210,
+       0x7e404170,
+       0xf800008f,
+/* 0x0671: ctx_4170w */
+       0x41708e00,
+       0x00657e40,
+       0xf0ffb200,
+       0x1bf410f4,
+/* 0x0683: ctx_redswitch */
+       0x4e00f8f3,
+       0xe5f00200,
+       0x20e5f040,
+       0x8010e5f0,
+       0xf6018500,
+       0x04bd000e,
+/* 0x069a: ctx_redswitch_delay */
+       0xf2b6080f,
+       0xfd1bf401,
+       0x0400e5f1,
+       0x0100e5f1,
+       0x01850080,
+       0xbd000ef6,
+/* 0x06b3: ctx_86c */
+       0x8000f804,
+       0xf6022300,
+       0x04bd000f,
+       0x148effb2,
+       0x8f7e408a,
+       0xffb20000,
+       0x41a88c8e,
+       0x00008f7e,
+/* 0x06d2: ctx_mem */
+       0x008000f8,
+       0x0ff60284,
+/* 0x06db: ctx_mem_wait */
+       0x8f04bd00,
+       0xcf028400,
+       0xfffd00ff,
+       0xf61bf405,
+/* 0x06ea: ctx_load */
+       0x94bd00f8,
+       0x800599f0,
+       0xf6023700,
+       0x04bd0009,
+       0xb87e0c0a,
+       0xf4bd0000,
+       0x02890080,
+       0xbd000ff6,
+       0xc1008004,
+       0x0002f602,
+       0x008004bd,
+       0x02f60283,
+       0x0f04bd00,
+       0x06d27e07,
+       0xc0008000,
+       0x0002f602,
+       0x0bfe04bd,
+       0x1f2af000,
+       0xb60424b6,
+       0x94bd0220,
+       0x800899f0,
+       0xf6023700,
+       0x04bd0009,
+       0x02810080,
+       0xbd0002f6,
+       0x0000d204,
+       0x25f08000,
+       0x88008002,
+       0x0002f602,
+       0x100104bd,
+       0xf0020042,
+       0x12fa0223,
+       0xbd03f805,
+       0x0899f094,
+       0x02170080,
+       0xbd0009f6,
+       0x81019804,
+       0x981814b6,
+       0x25b68002,
+       0x0512fd08,
+       0xbd1601b5,
+       0x0999f094,
+       0x02370080,
+       0xbd0009f6,
+       0x81008004,
+       0x0001f602,
+       0x010204bd,
+       0x02880080,
+       0xbd0002f6,
+       0x01004104,
+       0xfa0613f0,
+       0x03f80501,
+       0x99f094bd,
+       0x17008009,
+       0x0009f602,
+       0x94bd04bd,
+       0x800599f0,
+       0xf6021700,
+       0x04bd0009,
+/* 0x07d6: ctx_chan */
+       0xea7e00f8,
+       0x0c0a0006,
+       0x0000b87e,
+       0xd27e050f,
+       0x00f80006,
+/* 0x07e8: ctx_mmio_exec */
+       0x80410398,
+       0xf6028100,
+       0x04bd0003,
+/* 0x07f6: ctx_mmio_loop */
+       0x34c434bd,
+       0x0e1bf4ff,
+       0xf0020045,
+       0x35fa0653,
+/* 0x0807: ctx_mmio_pull */
+       0x9803f805,
+       0x4f98804e,
+       0x008f7e81,
+       0x0830b600,
+       0xf40112b6,
+/* 0x081a: ctx_mmio_done */
+       0x0398df1b,
+       0x81008016,
+       0x0003f602,
+       0x00b504bd,
+       0x01004140,
+       0xfa0613f0,
+       0x03f80601,
+/* 0x0836: ctx_xfer */
+       0x040e00f8,
+       0x03020080,
+       0xbd000ef6,
+/* 0x0841: ctx_xfer_idle */
+       0x00008e04,
+       0x00eecf03,
+       0x2000e4f1,
+       0xf4f51bf4,
+       0x02f40611,
+/* 0x0855: ctx_xfer_pre */
+       0x7e100f0c,
+       0xf40006b3,
+/* 0x085e: ctx_xfer_pre_load */
+       0x020f1b11,
+       0x0006627e,
+       0x0006717e,
+       0x0006837e,
+       0x627ef4bd,
+       0xea7e0006,
+/* 0x0876: ctx_xfer_exec */
+       0x01980006,
+       0x8024bd16,
+       0xf6010500,
+       0x04bd0002,
+       0x008e1fb2,
+       0x8f7e41a5,
+       0xfcf00000,
+       0x022cf001,
+       0xfd0124b6,
+       0xffb205f2,
+       0x41a5048e,
+       0x00008f7e,
+       0x0002167e,
+       0xfc8024bd,
+       0x02f60247,
+       0xf004bd00,
+       0x20b6012c,
+       0x4afc8003,
+       0x0002f602,
+       0xacf004bd,
+       0x06a5f001,
+       0x0c98000b,
+       0x010d9800,
+       0x3d7e000e,
+       0x080a0001,
+       0x0000ec7e,
+       0x00020a7e,
+       0x0a1201f4,
+       0x00b87e0c,
+       0x7e050f00,
+       0xf40006d2,
+/* 0x08f2: ctx_xfer_post */
+       0x020f2d02,
+       0x0006627e,
+       0xb37ef4bd,
+       0x277e0006,
+       0x717e0002,
+       0xf4bd0006,
+       0x0006627e,
+       0x981011f4,
+       0x11fd4001,
+       0x070bf405,
+       0x0007e87e,
+/* 0x091c: ctx_xfer_no_post_mmio */
+/* 0x091c: ctx_xfer_done */
+       0x000000f8,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
index 4750984..64dfd75 100644 (file)
@@ -342,7 +342,7 @@ uint32_t nv108_grhub_code[] = {
        0xb4f000bb,
        0x10b4b01f,
        0x0af31bf4,
-       0x00b87e02,
+       0x00b87e05,
        0x250ef400,
 /* 0x01d8: mmctx_stop */
        0xb600abc8,
index 132f684..f8f7b27 100644 (file)
@@ -361,7 +361,7 @@ uint32_t nvc0_grhub_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
index 84af824..624215a 100644 (file)
@@ -361,7 +361,7 @@ uint32_t nvd7_grhub_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
index 1c179bd..6547b3d 100644 (file)
@@ -361,7 +361,7 @@ uint32_t nve0_grhub_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
index 229c0ae..a5aee5a 100644 (file)
@@ -361,7 +361,7 @@ uint32_t nvf0_grhub_code[] = {
        0x1fb4f000,
        0xf410b4b0,
        0xa7f0f01b,
-       0xd021f402,
+       0xd021f405,
 /* 0x0223: mmctx_stop */
        0xc82b0ef4,
        0xb4b600ab,
index 6ffe283..a47d49d 100644 (file)
 #define NV_PGRAPH_GPCX_GPCCS_FIFO_CMD                                  0x41a068
 #define NV_PGRAPH_GPCX_GPCCS_FIFO_ACK                                  0x41a074
 #define NV_PGRAPH_GPCX_GPCCS_UNITS                                     0x41a608
+#define NV_PGRAPH_GPCX_GPCCS_CAPS                                      0x41a108
 #define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH                                0x41a614
 #define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11                        0x00000800
 #define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE                       0x00000200
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c
new file mode 100644 (file)
index 0000000..21c5f31
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/P0260.h>
+
+#include "nvc0.h"
+#include "ctxnvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+gm107_graph_sclass[] = {
+       { 0x902d, &nouveau_object_ofuncs },
+       { 0xa140, &nouveau_object_ofuncs },
+       { 0xb097, &nouveau_object_ofuncs },
+       { 0xb0c0, &nouveau_object_ofuncs },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct nvc0_graph_init
+gm107_graph_init_main_0[] = {
+       { 0x400080,   1, 0x04, 0x003003c2 },
+       { 0x400088,   1, 0x04, 0x0001bfe7 },
+       { 0x40008c,   1, 0x04, 0x00060000 },
+       { 0x400090,   1, 0x04, 0x00000030 },
+       { 0x40013c,   1, 0x04, 0x003901f3 },
+       { 0x400140,   1, 0x04, 0x00000100 },
+       { 0x400144,   1, 0x04, 0x00000000 },
+       { 0x400148,   1, 0x04, 0x00000110 },
+       { 0x400138,   1, 0x04, 0x00000000 },
+       { 0x400130,   2, 0x04, 0x00000000 },
+       { 0x400124,   1, 0x04, 0x00000002 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_ds_0[] = {
+       { 0x405844,   1, 0x04, 0x00ffffff },
+       { 0x405850,   1, 0x04, 0x00000000 },
+       { 0x405900,   1, 0x04, 0x00000000 },
+       { 0x405908,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_scc_0[] = {
+       { 0x40803c,   1, 0x04, 0x00000010 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_sked_0[] = {
+       { 0x407010,   1, 0x04, 0x00000000 },
+       { 0x407040,   1, 0x04, 0x40440424 },
+       { 0x407048,   1, 0x04, 0x0000000a },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_prop_0[] = {
+       { 0x418408,   1, 0x04, 0x00000000 },
+       { 0x4184a0,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_setup_1[] = {
+       { 0x4188c8,   2, 0x04, 0x00000000 },
+       { 0x4188d0,   1, 0x04, 0x00010000 },
+       { 0x4188d4,   1, 0x04, 0x00010201 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_zcull_0[] = {
+       { 0x418910,   1, 0x04, 0x00010001 },
+       { 0x418914,   1, 0x04, 0x00000301 },
+       { 0x418918,   1, 0x04, 0x00800000 },
+       { 0x418930,   2, 0x04, 0x00000000 },
+       { 0x418980,   1, 0x04, 0x77777770 },
+       { 0x418984,   3, 0x04, 0x77777777 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_gpc_unk_1[] = {
+       { 0x418d00,   1, 0x04, 0x00000000 },
+       { 0x418f00,   1, 0x04, 0x00000400 },
+       { 0x418f08,   1, 0x04, 0x00000000 },
+       { 0x418e08,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_tpccs_0[] = {
+       { 0x419dc4,   1, 0x04, 0x00000000 },
+       { 0x419dc8,   1, 0x04, 0x00000501 },
+       { 0x419dd0,   1, 0x04, 0x00000000 },
+       { 0x419dd4,   1, 0x04, 0x00000100 },
+       { 0x419dd8,   1, 0x04, 0x00000001 },
+       { 0x419ddc,   1, 0x04, 0x00000002 },
+       { 0x419de0,   1, 0x04, 0x00000001 },
+       { 0x419d0c,   1, 0x04, 0x00000000 },
+       { 0x419d10,   1, 0x04, 0x00000014 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_tex_0[] = {
+       { 0x419ab0,   1, 0x04, 0x00000000 },
+       { 0x419ab8,   1, 0x04, 0x000000e7 },
+       { 0x419abc,   1, 0x04, 0x00000000 },
+       { 0x419acc,   1, 0x04, 0x000000ff },
+       { 0x419ac0,   1, 0x04, 0x00000000 },
+       { 0x419aa8,   2, 0x04, 0x00000000 },
+       { 0x419ad0,   2, 0x04, 0x00000000 },
+       { 0x419ae0,   2, 0x04, 0x00000000 },
+       { 0x419af0,   4, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_pe_0[] = {
+       { 0x419900,   1, 0x04, 0x000000ff },
+       { 0x41980c,   1, 0x04, 0x00000010 },
+       { 0x419844,   1, 0x04, 0x00000000 },
+       { 0x419838,   1, 0x04, 0x000000ff },
+       { 0x419850,   1, 0x04, 0x00000004 },
+       { 0x419854,   2, 0x04, 0x00000000 },
+       { 0x419894,   3, 0x04, 0x00100401 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_l1c_0[] = {
+       { 0x419c98,   1, 0x04, 0x00000000 },
+       { 0x419cc0,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_sm_0[] = {
+       { 0x419e30,   1, 0x04, 0x000000ff },
+       { 0x419e00,   1, 0x04, 0x00000000 },
+       { 0x419ea0,   1, 0x04, 0x00000000 },
+       { 0x419ee4,   1, 0x04, 0x00000000 },
+       { 0x419ea4,   1, 0x04, 0x00000100 },
+       { 0x419ea8,   1, 0x04, 0x01000000 },
+       { 0x419ee8,   1, 0x04, 0x00000091 },
+       { 0x419eb4,   1, 0x04, 0x00000000 },
+       { 0x419ebc,   2, 0x04, 0x00000000 },
+       { 0x419edc,   1, 0x04, 0x000c1810 },
+       { 0x419ed8,   1, 0x04, 0x00000000 },
+       { 0x419ee0,   1, 0x04, 0x00000000 },
+       { 0x419f74,   1, 0x04, 0x00005155 },
+       { 0x419f80,   4, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_l1c_1[] = {
+       { 0x419ccc,   2, 0x04, 0x00000000 },
+       { 0x419c80,   1, 0x04, 0x3f006022 },
+       { 0x419c88,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_pes_0[] = {
+       { 0x41be50,   1, 0x04, 0x000000ff },
+       { 0x41be04,   1, 0x04, 0x00000000 },
+       { 0x41be08,   1, 0x04, 0x00000004 },
+       { 0x41be0c,   1, 0x04, 0x00000008 },
+       { 0x41be10,   1, 0x04, 0x0e3b8bc7 },
+       { 0x41be14,   2, 0x04, 0x00000000 },
+       { 0x41be3c,   5, 0x04, 0x00100401 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_wwdx_0[] = {
+       { 0x41bfd4,   1, 0x04, 0x00800000 },
+       { 0x41bfdc,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_cbm_0[] = {
+       { 0x41becc,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_be_0[] = {
+       { 0x408890,   1, 0x04, 0x000000ff },
+       { 0x40880c,   1, 0x04, 0x00000000 },
+       { 0x408850,   1, 0x04, 0x00000004 },
+       { 0x408878,   1, 0x04, 0x00c81603 },
+       { 0x40887c,   1, 0x04, 0x80543432 },
+       { 0x408880,   1, 0x04, 0x0010581e },
+       { 0x408884,   1, 0x04, 0x00001205 },
+       { 0x408974,   1, 0x04, 0x000000ff },
+       { 0x408910,   9, 0x04, 0x00000000 },
+       { 0x408950,   1, 0x04, 0x00000000 },
+       { 0x408954,   1, 0x04, 0x0000ffff },
+       { 0x408958,   1, 0x04, 0x00000034 },
+       { 0x40895c,   1, 0x04, 0x8531a003 },
+       { 0x408960,   1, 0x04, 0x0561985a },
+       { 0x408964,   1, 0x04, 0x04e15c4f },
+       { 0x408968,   1, 0x04, 0x02808833 },
+       { 0x40896c,   1, 0x04, 0x01f02438 },
+       { 0x408970,   1, 0x04, 0x00012c00 },
+       { 0x408984,   1, 0x04, 0x00000000 },
+       { 0x408988,   1, 0x04, 0x08040201 },
+       { 0x40898c,   1, 0x04, 0x80402010 },
+       {}
+};
+
+static const struct nvc0_graph_init
+gm107_graph_init_sm_1[] = {
+       { 0x419e5c,   1, 0x04, 0x00000000 },
+       { 0x419e58,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+gm107_graph_pack_mmio[] = {
+       { gm107_graph_init_main_0 },
+       { nvf0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvc0_graph_init_pd_0 },
+       { gm107_graph_init_ds_0 },
+       { gm107_graph_init_scc_0 },
+       { gm107_graph_init_sked_0 },
+       { nvf0_graph_init_cwd_0 },
+       { gm107_graph_init_prop_0 },
+       { nv108_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { gm107_graph_init_setup_1 },
+       { gm107_graph_init_zcull_0 },
+       { nvc0_graph_init_gpm_0 },
+       { gm107_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { gm107_graph_init_tpccs_0 },
+       { gm107_graph_init_tex_0 },
+       { gm107_graph_init_pe_0 },
+       { gm107_graph_init_l1c_0 },
+       { nvc0_graph_init_mpc_0 },
+       { gm107_graph_init_sm_0 },
+       { gm107_graph_init_l1c_1 },
+       { gm107_graph_init_pes_0 },
+       { gm107_graph_init_wwdx_0 },
+       { gm107_graph_init_cbm_0 },
+       { gm107_graph_init_be_0 },
+       { gm107_graph_init_sm_1 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+gm107_graph_init_bios(struct nvc0_graph_priv *priv)
+{
+       static const struct {
+               u32 ctrl;
+               u32 data;
+       } regs[] = {
+               { 0x419ed8, 0x419ee0 },
+               { 0x419ad0, 0x419ad4 },
+               { 0x419ae0, 0x419ae4 },
+               { 0x419af0, 0x419af4 },
+               { 0x419af8, 0x419afc },
+       };
+       struct nouveau_bios *bios = nouveau_bios(priv);
+       struct nvbios_P0260E infoE;
+       struct nvbios_P0260X infoX;
+       int E = -1, X;
+       u8 ver, hdr;
+
+       while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) {
+               if (X = -1, E < ARRAY_SIZE(regs)) {
+                       nv_wr32(priv, regs[E].ctrl, infoE.data);
+                       while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX))
+                               nv_wr32(priv, regs[E].data, infoX.data);
+               }
+       }
+}
+
+int
+gm107_graph_init(struct nouveau_object *object)
+{
+       struct nvc0_graph_oclass *oclass = (void *)object->oclass;
+       struct nvc0_graph_priv *priv = (void *)object;
+       const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+       u32 data[TPC_MAX / 8] = {};
+       u8  tpcnr[GPC_MAX];
+       int gpc, tpc, ppc, rop;
+       int ret, i;
+
+       ret = nouveau_graph_init(&priv->base);
+       if (ret)
+               return ret;
+
+       nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+       nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+       nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+       nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+       nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+       nvc0_graph_mmio(priv, oclass->mmio);
+
+       gm107_graph_init_bios(priv);
+
+       nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
+
+       memset(data, 0x00, sizeof(data));
+       memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+       for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+               do {
+                       gpc = (gpc + 1) % priv->gpc_nr;
+               } while (!tpcnr[gpc]);
+               tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+               data[i / 8] |= tpc << ((i % 8) * 4);
+       }
+
+       nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+       nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+       nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+       nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+                       priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+                       priv->tpc_total);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+       }
+
+       nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+       nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+       nv_wr32(priv, 0x400500, 0x00010001);
+
+       nv_wr32(priv, 0x400100, 0xffffffff);
+       nv_wr32(priv, 0x40013c, 0xffffffff);
+       nv_wr32(priv, 0x400124, 0x00000002);
+       nv_wr32(priv, 0x409c24, 0x000e0000);
+
+       nv_wr32(priv, 0x404000, 0xc0000000);
+       nv_wr32(priv, 0x404600, 0xc0000000);
+       nv_wr32(priv, 0x408030, 0xc0000000);
+       nv_wr32(priv, 0x404490, 0xc0000000);
+       nv_wr32(priv, 0x406018, 0xc0000000);
+       nv_wr32(priv, 0x407020, 0x40000000);
+       nv_wr32(priv, 0x405840, 0xc0000000);
+       nv_wr32(priv, 0x405844, 0x00ffffff);
+       nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+
+       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+               for (ppc = 0; ppc < 2 /* priv->ppc_nr[gpc] */; ppc++)
+                       nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+               for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe);
+                       nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005);
+               }
+               nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+               nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+       }
+
+       for (rop = 0; rop < priv->rop_nr; rop++) {
+               nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000);
+               nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000);
+               nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+               nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+       }
+
+       nv_wr32(priv, 0x400108, 0xffffffff);
+       nv_wr32(priv, 0x400138, 0xffffffff);
+       nv_wr32(priv, 0x400118, 0xffffffff);
+       nv_wr32(priv, 0x400130, 0xffffffff);
+       nv_wr32(priv, 0x40011c, 0xffffffff);
+       nv_wr32(priv, 0x400134, 0xffffffff);
+
+       nv_wr32(priv, 0x400054, 0x2c350f63);
+       return nvc0_graph_init_ctxctl(priv);
+}
+
+#include "fuc/hubgm107.fuc5.h"
+
+static struct nvc0_graph_ucode
+gm107_graph_fecs_ucode = {
+       .code.data = gm107_grhub_code,
+       .code.size = sizeof(gm107_grhub_code),
+       .data.data = gm107_grhub_data,
+       .data.size = sizeof(gm107_grhub_data),
+};
+
+#include "fuc/gpcgm107.fuc5.h"
+
+static struct nvc0_graph_ucode
+gm107_graph_gpccs_ucode = {
+       .code.data = gm107_grgpc_code,
+       .code.size = sizeof(gm107_grgpc_code),
+       .data.data = gm107_grgpc_data,
+       .data.size = sizeof(gm107_grgpc_data),
+};
+
+struct nouveau_oclass *
+gm107_graph_oclass = &(struct nvc0_graph_oclass) {
+       .base.handle = NV_ENGINE(GR, 0x07),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_graph_ctor,
+               .dtor = nvc0_graph_dtor,
+               .init = gm107_graph_init,
+               .fini = _nouveau_graph_fini,
+       },
+       .cclass = &gm107_grctx_oclass,
+       .sclass =  gm107_graph_sclass,
+       .mmio = gm107_graph_pack_mmio,
+       .fecs.ucode = 0 ? &gm107_graph_fecs_ucode : NULL,
+       .gpccs.ucode = &gm107_graph_gpccs_ucode,
+}.base;
index e1af65e..00ea1a0 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include "nvc0.h"
+#include "ctxnvc0.h"
 
 /*******************************************************************************
  * Graphics object classes
@@ -38,11 +39,11 @@ nv108_graph_sclass[] = {
 };
 
 /*******************************************************************************
- * PGRAPH engine/subdev functions
+ * PGRAPH register lists
  ******************************************************************************/
 
-static struct nvc0_graph_init
-nv108_graph_init_regs[] = {
+static const struct nvc0_graph_init
+nv108_graph_init_main_0[] = {
        { 0x400080,   1, 0x04, 0x003083c2 },
        { 0x400088,   1, 0x04, 0x0001bfe7 },
        { 0x40008c,   1, 0x04, 0x00000000 },
@@ -57,66 +58,46 @@ nv108_graph_init_regs[] = {
        {}
 };
 
-struct nvc0_graph_init
-nv108_graph_init_unk58xx[] = {
+static const struct nvc0_graph_init
+nv108_graph_init_ds_0[] = {
        { 0x405844,   1, 0x04, 0x00ffffff },
        { 0x405850,   1, 0x04, 0x00000000 },
        { 0x405900,   1, 0x04, 0x00000000 },
        { 0x405908,   1, 0x04, 0x00000000 },
-       { 0x405928,   1, 0x04, 0x00000000 },
-       { 0x40592c,   1, 0x04, 0x00000000 },
+       { 0x405928,   2, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nv108_graph_init_gpc[] = {
-       { 0x418408,   1, 0x04, 0x00000000 },
-       { 0x4184a0,   3, 0x04, 0x00000000 },
+const struct nvc0_graph_init
+nv108_graph_init_gpc_unk_0[] = {
        { 0x418604,   1, 0x04, 0x00000000 },
        { 0x418680,   1, 0x04, 0x00000000 },
        { 0x418714,   1, 0x04, 0x00000000 },
        { 0x418384,   2, 0x04, 0x00000000 },
-       { 0x418814,   3, 0x04, 0x00000000 },
-       { 0x418b04,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nv108_graph_init_setup_1[] = {
        { 0x4188c8,   2, 0x04, 0x00000000 },
        { 0x4188d0,   1, 0x04, 0x00010000 },
        { 0x4188d4,   1, 0x04, 0x00000201 },
-       { 0x418910,   1, 0x04, 0x00010001 },
-       { 0x418914,   1, 0x04, 0x00000301 },
-       { 0x418918,   1, 0x04, 0x00800000 },
-       { 0x418980,   1, 0x04, 0x77777770 },
-       { 0x418984,   3, 0x04, 0x77777777 },
-       { 0x418c04,   1, 0x04, 0x00000000 },
-       { 0x418c64,   2, 0x04, 0x00000000 },
-       { 0x418c88,   1, 0x04, 0x00000000 },
-       { 0x418cb4,   2, 0x04, 0x00000000 },
-       { 0x418d00,   1, 0x04, 0x00000000 },
-       { 0x418d28,   2, 0x04, 0x00000000 },
-       { 0x418f00,   1, 0x04, 0x00000400 },
-       { 0x418f08,   1, 0x04, 0x00000000 },
-       { 0x418f20,   2, 0x04, 0x00000000 },
-       { 0x418e00,   1, 0x04, 0x00000000 },
-       { 0x418e08,   1, 0x04, 0x00000000 },
-       { 0x418e1c,   2, 0x04, 0x00000000 },
-       { 0x41900c,   1, 0x04, 0x00000000 },
-       { 0x419018,   1, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nv108_graph_init_tpc[] = {
-       { 0x419d0c,   1, 0x04, 0x00000000 },
-       { 0x419d10,   1, 0x04, 0x00000014 },
+static const struct nvc0_graph_init
+nv108_graph_init_tex_0[] = {
        { 0x419ab0,   1, 0x04, 0x00000000 },
        { 0x419ac8,   1, 0x04, 0x00000000 },
        { 0x419ab8,   1, 0x04, 0x000000e7 },
        { 0x419abc,   2, 0x04, 0x00000000 },
        { 0x419ab4,   1, 0x04, 0x00000000 },
        { 0x419aa8,   2, 0x04, 0x00000000 },
-       { 0x41980c,   1, 0x04, 0x00000010 },
-       { 0x419844,   1, 0x04, 0x00000000 },
-       { 0x419850,   1, 0x04, 0x00000004 },
-       { 0x419854,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nv108_graph_init_l1c_0[] = {
        { 0x419c98,   1, 0x04, 0x00000000 },
        { 0x419ca8,   1, 0x04, 0x00000000 },
        { 0x419cb0,   1, 0x04, 0x01000000 },
@@ -127,22 +108,47 @@ nv108_graph_init_tpc[] = {
        { 0x419cc0,   2, 0x04, 0x00000000 },
        { 0x419c80,   1, 0x04, 0x00000230 },
        { 0x419ccc,   2, 0x04, 0x00000000 },
-       { 0x419c0c,   1, 0x04, 0x00000000 },
-       { 0x419e00,   1, 0x04, 0x00000080 },
-       { 0x419ea0,   1, 0x04, 0x00000000 },
-       { 0x419ee4,   1, 0x04, 0x00000000 },
-       { 0x419ea4,   1, 0x04, 0x00000100 },
-       { 0x419ea8,   1, 0x04, 0x00000000 },
-       { 0x419eb4,   1, 0x04, 0x00000000 },
-       { 0x419ebc,   2, 0x04, 0x00000000 },
-       { 0x419edc,   1, 0x04, 0x00000000 },
-       { 0x419f00,   1, 0x04, 0x00000000 },
-       { 0x419ed0,   1, 0x04, 0x00003234 },
-       { 0x419f74,   1, 0x04, 0x00015555 },
-       { 0x419f80,   4, 0x04, 0x00000000 },
        {}
 };
 
+static const struct nvc0_graph_pack
+nv108_graph_pack_mmio[] = {
+       { nv108_graph_init_main_0 },
+       { nvf0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvd9_graph_init_pd_0 },
+       { nv108_graph_init_ds_0 },
+       { nvc0_graph_init_scc_0 },
+       { nvf0_graph_init_sked_0 },
+       { nvf0_graph_init_cwd_0 },
+       { nvd9_graph_init_prop_0 },
+       { nv108_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { nv108_graph_init_setup_1 },
+       { nvc0_graph_init_zcull_0 },
+       { nvd9_graph_init_gpm_0 },
+       { nvf0_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { nve4_graph_init_tpccs_0 },
+       { nv108_graph_init_tex_0 },
+       { nve4_graph_init_pe_0 },
+       { nv108_graph_init_l1c_0 },
+       { nvc0_graph_init_mpc_0 },
+       { nvf0_graph_init_sm_0 },
+       { nvd7_graph_init_pes_0 },
+       { nvd7_graph_init_wwdx_0 },
+       { nvd7_graph_init_cbm_0 },
+       { nve4_graph_init_be_0 },
+       { nvc0_graph_init_fe_1 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
 static int
 nv108_graph_fini(struct nouveau_object *object, bool suspend)
 {
@@ -180,25 +186,6 @@ nv108_graph_fini(struct nouveau_object *object, bool suspend)
        return nouveau_graph_fini(&priv->base, suspend);
 }
 
-static struct nvc0_graph_init *
-nv108_graph_init_mmio[] = {
-       nv108_graph_init_regs,
-       nvf0_graph_init_unk40xx,
-       nvc0_graph_init_unk44xx,
-       nvc0_graph_init_unk78xx,
-       nvc0_graph_init_unk60xx,
-       nvd9_graph_init_unk64xx,
-       nv108_graph_init_unk58xx,
-       nvc0_graph_init_unk80xx,
-       nvf0_graph_init_unk70xx,
-       nvf0_graph_init_unk5bxx,
-       nv108_graph_init_gpc,
-       nv108_graph_init_tpc,
-       nve4_graph_init_unk,
-       nve4_graph_init_unk88xx,
-       NULL
-};
-
 #include "fuc/hubnv108.fuc5.h"
 
 static struct nvc0_graph_ucode
@@ -230,7 +217,7 @@ nv108_graph_oclass = &(struct nvc0_graph_oclass) {
        },
        .cclass = &nv108_grctx_oclass,
        .sclass =  nv108_graph_sclass,
-       .mmio = nv108_graph_init_mmio,
+       .mmio = nv108_graph_pack_mmio,
        .fecs.ucode = &nv108_graph_fecs_ucode,
        .gpccs.ucode = &nv108_graph_gpccs_ucode,
 }.base;
index b245593..d145e08 100644 (file)
@@ -349,7 +349,7 @@ nv20_graph_init(struct nouveau_object *object)
        nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
 
        /* begin RAM config */
-       vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
+       vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
        nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
        nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
        nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
index 193a5de..6477fbf 100644 (file)
@@ -484,7 +484,7 @@ nv40_graph_init(struct nouveau_object *object)
                engine->tile_prog(engine, i);
 
        /* begin RAM config */
-       vramsz = pci_resource_len(nv_device(priv)->pdev, 0) - 1;
+       vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
        switch (nv_device(priv)->chipset) {
        case 0x40:
                nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
index 7a367c4..2c7809e 100644 (file)
@@ -197,34 +197,35 @@ static const struct nouveau_bitfield nv50_pgraph_status[] = {
        { 0x00000080, "UNK7" },
        { 0x00000100, "CTXPROG" },
        { 0x00000200, "VFETCH" },
-       { 0x00000400, "CCACHE_UNK4" },
-       { 0x00000800, "STRMOUT_GSCHED_UNK5" },
-       { 0x00001000, "UNK14XX" },
-       { 0x00002000, "UNK24XX_CSCHED" },
-       { 0x00004000, "UNK1CXX" },
+       { 0x00000400, "CCACHE_PREGEOM" },
+       { 0x00000800, "STRMOUT_VATTR_POSTGEOM" },
+       { 0x00001000, "VCLIP" },
+       { 0x00002000, "RATTR_APLANE" },
+       { 0x00004000, "TRAST" },
        { 0x00008000, "CLIPID" },
        { 0x00010000, "ZCULL" },
        { 0x00020000, "ENG2D" },
-       { 0x00040000, "UNK34XX" },
-       { 0x00080000, "TPRAST" },
-       { 0x00100000, "TPROP" },
-       { 0x00200000, "TEX" },
-       { 0x00400000, "TPVP" },
-       { 0x00800000, "MP" },
+       { 0x00040000, "RMASK" },
+       { 0x00080000, "TPC_RAST" },
+       { 0x00100000, "TPC_PROP" },
+       { 0x00200000, "TPC_TEX" },
+       { 0x00400000, "TPC_GEOM" },
+       { 0x00800000, "TPC_MP" },
        { 0x01000000, "ROP" },
        {}
 };
 
 static const char *const nv50_pgraph_vstatus_0[] = {
-       "VFETCH", "CCACHE", "UNK4", "UNK5", "GSCHED", "STRMOUT", "UNK14XX", NULL
+       "VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP",
+       NULL
 };
 
 static const char *const nv50_pgraph_vstatus_1[] = {
-       "TPRAST", "TPROP", "TEXTURE", "TPVP", "MP", NULL
+       "TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL
 };
 
 static const char *const nv50_pgraph_vstatus_2[] = {
-       "UNK24XX", "CSCHED", "UNK1CXX", "CLIPID", "ZCULL", "ENG2D", "UNK34XX",
+       "RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK",
        "ROP", NULL
 };
 
@@ -329,6 +330,15 @@ static const struct nouveau_bitfield nv50_mpc_traps[] = {
        {}
 };
 
+static const struct nouveau_bitfield nv50_tex_traps[] = {
+       { 0x00000001, "" }, /* any bit set? */
+       { 0x00000002, "FAULT" },
+       { 0x00000004, "STORAGE_TYPE_MISMATCH" },
+       { 0x00000008, "LINEAR_MISMATCH" },
+       { 0x00000020, "WRONG_MEMTYPE" },
+       {}
+};
+
 static const struct nouveau_bitfield nv50_graph_trap_m2mf[] = {
        { 0x00000001, "NOTIFY" },
        { 0x00000002, "IN" },
@@ -531,6 +541,13 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
                                for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
                                        nv_error(priv, "\t0x%08x: 0x%08x\n", r,
                                                nv_rd32(priv, r));
+                               if (ustatus) {
+                                       nv_error(priv, "%s - TP%d:", name, i);
+                                       nouveau_bitfield_print(nv50_tex_traps,
+                                                              ustatus);
+                                       pr_cont("\n");
+                                       ustatus = 0;
+                               }
                        }
                        break;
                case 7: /* MP error */
index a73ab20..f3c7329 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include "nvc0.h"
+#include "ctxnvc0.h"
 
 /*******************************************************************************
  * Graphics object classes
@@ -146,11 +147,11 @@ nvc0_graph_context_dtor(struct nouveau_object *object)
 }
 
 /*******************************************************************************
- * PGRAPH engine/subdev functions
+ * PGRAPH register lists
  ******************************************************************************/
 
-struct nvc0_graph_init
-nvc0_graph_init_regs[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_main_0[] = {
        { 0x400080,   1, 0x04, 0x003083c2 },
        { 0x400088,   1, 0x04, 0x00006fe7 },
        { 0x40008c,   1, 0x04, 0x00000000 },
@@ -165,95 +166,170 @@ nvc0_graph_init_regs[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_graph_init_unk40xx[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_fe_0[] = {
        { 0x40415c,   1, 0x04, 0x00000000 },
        { 0x404170,   1, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_graph_init_unk44xx[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_pri_0[] = {
        { 0x404488,   2, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_graph_init_unk78xx[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_rstr2d_0[] = {
        { 0x407808,   1, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_graph_init_unk60xx[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_pd_0[] = {
        { 0x406024,   1, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_graph_init_unk58xx[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_ds_0[] = {
        { 0x405844,   1, 0x04, 0x00ffffff },
        { 0x405850,   1, 0x04, 0x00000000 },
        { 0x405908,   1, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_graph_init_unk80xx[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_scc_0[] = {
        { 0x40803c,   1, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvc0_graph_init_gpc[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_prop_0[] = {
        { 0x4184a0,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_gpc_unk_0[] = {
        { 0x418604,   1, 0x04, 0x00000000 },
        { 0x418680,   1, 0x04, 0x00000000 },
        { 0x418714,   1, 0x04, 0x80000000 },
        { 0x418384,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_setup_0[] = {
        { 0x418814,   3, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_crstr_0[] = {
        { 0x418b04,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_setup_1[] = {
        { 0x4188c8,   1, 0x04, 0x80000000 },
        { 0x4188cc,   1, 0x04, 0x00000000 },
        { 0x4188d0,   1, 0x04, 0x00010000 },
        { 0x4188d4,   1, 0x04, 0x00000001 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_zcull_0[] = {
        { 0x418910,   1, 0x04, 0x00010001 },
        { 0x418914,   1, 0x04, 0x00000301 },
        { 0x418918,   1, 0x04, 0x00800000 },
        { 0x418980,   1, 0x04, 0x77777770 },
        { 0x418984,   3, 0x04, 0x77777777 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_gpm_0[] = {
        { 0x418c04,   1, 0x04, 0x00000000 },
        { 0x418c88,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_gpc_unk_1[] = {
        { 0x418d00,   1, 0x04, 0x00000000 },
        { 0x418f08,   1, 0x04, 0x00000000 },
        { 0x418e00,   1, 0x04, 0x00000050 },
        { 0x418e08,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_gcc_0[] = {
        { 0x41900c,   1, 0x04, 0x00000000 },
        { 0x419018,   1, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nvc0_graph_init_tpc[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_tpccs_0[] = {
        { 0x419d08,   2, 0x04, 0x00000000 },
        { 0x419d10,   1, 0x04, 0x00000014 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_tex_0[] = {
        { 0x419ab0,   1, 0x04, 0x00000000 },
        { 0x419ab8,   1, 0x04, 0x000000e7 },
        { 0x419abc,   2, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_pe_0[] = {
        { 0x41980c,   3, 0x04, 0x00000000 },
        { 0x419844,   1, 0x04, 0x00000000 },
        { 0x41984c,   1, 0x04, 0x00005bc5 },
        { 0x419850,   4, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_l1c_0[] = {
        { 0x419c98,   1, 0x04, 0x00000000 },
        { 0x419ca8,   1, 0x04, 0x80000000 },
        { 0x419cb4,   1, 0x04, 0x00000000 },
        { 0x419cb8,   1, 0x04, 0x00008bf4 },
        { 0x419cbc,   1, 0x04, 0x28137606 },
        { 0x419cc0,   2, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_wwdx_0[] = {
        { 0x419bd4,   1, 0x04, 0x00800000 },
        { 0x419bdc,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_tpccs_1[] = {
        { 0x419d2c,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc0_graph_init_mpc_0[] = {
        { 0x419c0c,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc0_graph_init_sm_0[] = {
        { 0x419e00,   1, 0x04, 0x00000000 },
        { 0x419ea0,   1, 0x04, 0x00000000 },
        { 0x419ea4,   1, 0x04, 0x00000100 },
@@ -270,8 +346,8 @@ nvc0_graph_init_tpc[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_graph_init_unk88xx[] = {
+const struct nvc0_graph_init
+nvc0_graph_init_be_0[] = {
        { 0x40880c,   1, 0x04, 0x00000000 },
        { 0x408910,   9, 0x04, 0x00000000 },
        { 0x408950,   1, 0x04, 0x00000000 },
@@ -282,18 +358,64 @@ nvc0_graph_init_unk88xx[] = {
        {}
 };
 
-struct nvc0_graph_init
-nvc0_graph_tpc_0[] = {
-       { 0x50405c,   1, 0x04, 0x00000001 },
+const struct nvc0_graph_init
+nvc0_graph_init_fe_1[] = {
+       { 0x4040f0,   1, 0x04, 0x00000000 },
        {}
 };
 
+const struct nvc0_graph_init
+nvc0_graph_init_pe_1[] = {
+       { 0x419880,   1, 0x04, 0x00000002 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+nvc0_graph_pack_mmio[] = {
+       { nvc0_graph_init_main_0 },
+       { nvc0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvc0_graph_init_pd_0 },
+       { nvc0_graph_init_ds_0 },
+       { nvc0_graph_init_scc_0 },
+       { nvc0_graph_init_prop_0 },
+       { nvc0_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { nvc0_graph_init_setup_1 },
+       { nvc0_graph_init_zcull_0 },
+       { nvc0_graph_init_gpm_0 },
+       { nvc0_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { nvc0_graph_init_tpccs_0 },
+       { nvc0_graph_init_tex_0 },
+       { nvc0_graph_init_pe_0 },
+       { nvc0_graph_init_l1c_0 },
+       { nvc0_graph_init_wwdx_0 },
+       { nvc0_graph_init_tpccs_1 },
+       { nvc0_graph_init_mpc_0 },
+       { nvc0_graph_init_sm_0 },
+       { nvc0_graph_init_be_0 },
+       { nvc0_graph_init_fe_1 },
+       { nvc0_graph_init_pe_1 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
 void
-nvc0_graph_mmio(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init)
+nvc0_graph_mmio(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p)
 {
-       for (; init && init->count; init++) {
-               u32 addr = init->addr, i;
-               for (i = 0; i < init->count; i++) {
+       const struct nvc0_graph_pack *pack;
+       const struct nvc0_graph_init *init;
+
+       pack_for_each_init(init, pack, p) {
+               u32 next = init->addr + init->count * init->pitch;
+               u32 addr = init->addr;
+               while (addr < next) {
                        nv_wr32(priv, addr, init->data);
                        addr += init->pitch;
                }
@@ -301,49 +423,53 @@ nvc0_graph_mmio(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init)
 }
 
 void
-nvc0_graph_icmd(struct nvc0_graph_priv *priv, struct nvc0_graph_init *init)
+nvc0_graph_icmd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p)
 {
-       u32 addr, data;
-       int i, j;
+       const struct nvc0_graph_pack *pack;
+       const struct nvc0_graph_init *init;
+       u32 data = 0;
 
        nv_wr32(priv, 0x400208, 0x80000000);
-       for (i = 0; init->count; init++, i++) {
-               if (!i || data != init->data) {
+
+       pack_for_each_init(init, pack, p) {
+               u32 next = init->addr + init->count * init->pitch;
+               u32 addr = init->addr;
+
+               if ((pack == p && init == p->init) || data != init->data) {
                        nv_wr32(priv, 0x400204, init->data);
                        data = init->data;
                }
 
-               addr = init->addr;
-               for (j = 0; j < init->count; j++) {
+               while (addr < next) {
                        nv_wr32(priv, 0x400200, addr);
+                       nv_wait(priv, 0x400700, 0x00000002, 0x00000000);
                        addr += init->pitch;
-                       while (nv_rd32(priv, 0x400700) & 0x00000002) {}
                }
        }
+
        nv_wr32(priv, 0x400208, 0x00000000);
 }
 
 void
-nvc0_graph_mthd(struct nvc0_graph_priv *priv, struct nvc0_graph_mthd *mthds)
+nvc0_graph_mthd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p)
 {
-       struct nvc0_graph_mthd *mthd;
-       struct nvc0_graph_init *init;
-       int i = 0, j;
-       u32 data;
-
-       while ((mthd = &mthds[i++]) && (init = mthd->init)) {
-               u32  addr = 0x80000000 | mthd->oclass;
-               for (data = 0; init->count; init++) {
-                       if (init == mthd->init || data != init->data) {
-                               nv_wr32(priv, 0x40448c, init->data);
-                               data = init->data;
-                       }
+       const struct nvc0_graph_pack *pack;
+       const struct nvc0_graph_init *init;
+       u32 data = 0;
 
-                       addr = (addr & 0x8000ffff) | (init->addr << 14);
-                       for (j = 0; j < init->count; j++) {
-                               nv_wr32(priv, 0x404488, addr);
-                               addr += init->pitch << 14;
-                       }
+       pack_for_each_init(init, pack, p) {
+               u32 ctrl = 0x80000000 | pack->type;
+               u32 next = init->addr + init->count * init->pitch;
+               u32 addr = init->addr;
+
+               if ((pack == p && init == p->init) || data != init->data) {
+                       nv_wr32(priv, 0x40448c, init->data);
+                       data = init->data;
+               }
+
+               while (addr < next) {
+                       nv_wr32(priv, 0x404488, ctrl | (addr << 14));
+                       addr += init->pitch;
                }
        }
 }
@@ -772,11 +898,12 @@ nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base,
 
 static void
 nvc0_graph_init_csdata(struct nvc0_graph_priv *priv,
-                      struct nvc0_graph_init *init,
+                      const struct nvc0_graph_pack *pack,
                       u32 falcon, u32 starstar, u32 base)
 {
-       u32 addr = init->addr;
-       u32 next = addr;
+       const struct nvc0_graph_pack *iter;
+       const struct nvc0_graph_init *init;
+       u32 addr = ~0, prev = ~0, xfer = 0;
        u32 star, temp;
 
        nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar);
@@ -786,22 +913,28 @@ nvc0_graph_init_csdata(struct nvc0_graph_priv *priv,
                star = temp;
        nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star);
 
-       do {
-               if (init->addr != next) {
-                       while (addr < next) {
-                               u32 nr = min((int)(next - addr) / 4, 32);
-                               nv_wr32(priv, falcon + 0x01c4,
-                                       ((nr - 1) << 26) | (addr - base));
-                               addr += nr * 4;
-                               star += 4;
+       pack_for_each_init(init, iter, pack) {
+               u32 head = init->addr - base;
+               u32 tail = head + init->count * init->pitch;
+               while (head < tail) {
+                       if (head != prev + 4 || xfer >= 32) {
+                               if (xfer) {
+                                       u32 data = ((--xfer << 26) | addr);
+                                       nv_wr32(priv, falcon + 0x01c4, data);
+                                       star += 4;
+                               }
+                               addr = head;
+                               xfer = 0;
                        }
-                       addr = next = init->addr;
+                       prev = head;
+                       xfer = xfer + 1;
+                       head = head + init->pitch;
                }
-               next += init->count * 4;
-       } while ((init++)->count);
+       }
 
+       nv_wr32(priv, falcon + 0x01c4, (--xfer << 26) | addr);
        nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar);
-       nv_wr32(priv, falcon + 0x01c4, star);
+       nv_wr32(priv, falcon + 0x01c4, star + 4);
 }
 
 int
@@ -809,7 +942,6 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
 {
        struct nvc0_graph_oclass *oclass = (void *)nv_object(priv)->oclass;
        struct nvc0_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass;
-       struct nvc0_graph_init *init;
        u32 r000260;
        int i;
 
@@ -919,10 +1051,6 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
                nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]);
        }
 
-       for (i = 0; (init = cclass->hub[i]); i++) {
-               nvc0_graph_init_csdata(priv, init, 0x409000, 0x000, 0x000000);
-       }
-
        /* load GPC microcode */
        nv_wr32(priv, 0x41a1c0, 0x01000000);
        for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++)
@@ -936,12 +1064,11 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
        }
        nv_wr32(priv, 0x000260, r000260);
 
-       if ((init = cclass->gpc[0]))
-               nvc0_graph_init_csdata(priv, init, 0x41a000, 0x000, 0x418000);
-       if ((init = cclass->gpc[2]))
-               nvc0_graph_init_csdata(priv, init, 0x41a000, 0x004, 0x419800);
-       if ((init = cclass->gpc[3]))
-               nvc0_graph_init_csdata(priv, init, 0x41a000, 0x008, 0x41be00);
+       /* load register lists */
+       nvc0_graph_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000);
+       nvc0_graph_init_csdata(priv, cclass->gpc, 0x41a000, 0x000, 0x418000);
+       nvc0_graph_init_csdata(priv, cclass->tpc, 0x41a000, 0x004, 0x419800);
+       nvc0_graph_init_csdata(priv, cclass->ppc, 0x41a000, 0x008, 0x41be00);
 
        /* start HUB ucode running, it'll init the GPCs */
        nv_wr32(priv, 0x40910c, 0x00000000);
@@ -988,8 +1115,7 @@ nvc0_graph_init(struct nouveau_object *object)
        nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
        nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
 
-       for (i = 0; oclass->mmio[i]; i++)
-               nvc0_graph_mmio(priv, oclass->mmio[i]);
+       nvc0_graph_mmio(priv, oclass->mmio);
 
        memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
        for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
@@ -1091,10 +1217,10 @@ nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
        int ret;
 
        snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
-       ret = request_firmware(&fw, f, &device->pdev->dev);
+       ret = request_firmware(&fw, f, nv_device_base(device));
        if (ret) {
                snprintf(f, sizeof(f), "nouveau/%s", fwname);
-               ret = request_firmware(&fw, f, &device->pdev->dev);
+               ret = request_firmware(&fw, f, nv_device_base(device));
                if (ret) {
                        nv_error(priv, "failed to load %s\n", fwname);
                        return ret;
@@ -1220,22 +1346,6 @@ nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-struct nvc0_graph_init *
-nvc0_graph_init_mmio[] = {
-       nvc0_graph_init_regs,
-       nvc0_graph_init_unk40xx,
-       nvc0_graph_init_unk44xx,
-       nvc0_graph_init_unk78xx,
-       nvc0_graph_init_unk60xx,
-       nvc0_graph_init_unk58xx,
-       nvc0_graph_init_unk80xx,
-       nvc0_graph_init_gpc,
-       nvc0_graph_init_tpc,
-       nvc0_graph_init_unk88xx,
-       nvc0_graph_tpc_0,
-       NULL
-};
-
 #include "fuc/hubnvc0.fuc.h"
 
 struct nvc0_graph_ucode
@@ -1267,7 +1377,7 @@ nvc0_graph_oclass = &(struct nvc0_graph_oclass) {
        },
        .cclass = &nvc0_grctx_oclass,
        .sclass =  nvc0_graph_sclass,
-       .mmio = nvc0_graph_init_mmio,
+       .mmio = nvc0_graph_pack_mmio,
        .fecs.ucode = &nvc0_graph_fecs_ucode,
        .gpccs.ucode = &nvc0_graph_gpccs_ucode,
 }.base;
index b0ab6de..90d4461 100644 (file)
@@ -45,6 +45,7 @@
 #define ROP_UNIT(u, r)    (0x410000 + (u) * 0x400 + (r))
 #define GPC_BCAST(r)      (0x418000 + (r))
 #define GPC_UNIT(t, r)    (0x500000 + (t) * 0x8000 + (r))
+#define PPC_UNIT(t, m, r) (0x503000 + (t) * 0x8000 + (m) * 0x200 + (r))
 #define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
 
 struct nvc0_graph_data {
@@ -102,8 +103,6 @@ struct nvc0_graph_chan {
        } data[4];
 };
 
-int  nvc0_grctx_generate(struct nvc0_graph_priv *);
-
 int  nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *,
                             struct nouveau_oclass *, void *, u32,
                             struct nouveau_object **);
@@ -130,34 +129,14 @@ struct nvc0_graph_init {
        u32 data;
 };
 
-struct nvc0_graph_mthd {
-       u16 oclass;
-       struct nvc0_graph_init *init;
-};
-
-struct nvc0_grctx {
-       struct nvc0_graph_priv *priv;
-       struct nvc0_graph_data *data;
-       struct nvc0_graph_mmio *mmio;
-       int buffer_nr;
-       u64 buffer[4];
-       u64 addr;
+struct nvc0_graph_pack {
+       const struct nvc0_graph_init *init;
+       u32 type;
 };
 
-struct nvc0_grctx_oclass {
-       struct nouveau_oclass base;
-       /* main context generation function */
-       void  (*main)(struct nvc0_graph_priv *, struct nvc0_grctx *);
-       /* context-specific modify-on-first-load list generation function */
-       void  (*mods)(struct nvc0_graph_priv *, struct nvc0_grctx *);
-       void  (*unkn)(struct nvc0_graph_priv *);
-       /* mmio context data */
-       struct nvc0_graph_init **hub;
-       struct nvc0_graph_init **gpc;
-       /* indirect context data, generated with icmds/mthds */
-       struct nvc0_graph_init *icmd;
-       struct nvc0_graph_mthd *mthd;
-};
+#define pack_for_each_init(init, pack, head)                                   \
+       for (pack = head; pack && pack->init; pack++)                          \
+                 for (init = pack->init; init && init->count; init++)
 
 struct nvc0_graph_ucode {
        struct nvc0_graph_fuc code;
@@ -171,7 +150,7 @@ struct nvc0_graph_oclass {
        struct nouveau_oclass base;
        struct nouveau_oclass **cclass;
        struct nouveau_oclass *sclass;
-       struct nvc0_graph_init **mmio;
+       const struct nvc0_graph_pack *mmio;
        struct {
                struct nvc0_graph_ucode *ucode;
        } fecs;
@@ -180,119 +159,72 @@ struct nvc0_graph_oclass {
        } gpccs;
 };
 
-void nvc0_graph_mmio(struct nvc0_graph_priv *, struct nvc0_graph_init *);
-void nvc0_graph_icmd(struct nvc0_graph_priv *, struct nvc0_graph_init *);
-void nvc0_graph_mthd(struct nvc0_graph_priv *, struct nvc0_graph_mthd *);
+void nvc0_graph_mmio(struct nvc0_graph_priv *, const struct nvc0_graph_pack *);
+void nvc0_graph_icmd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *);
+void nvc0_graph_mthd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *);
 int  nvc0_graph_init_ctxctl(struct nvc0_graph_priv *);
 
-extern struct nvc0_graph_init nvc0_graph_init_regs[];
-extern struct nvc0_graph_init nvc0_graph_init_unk40xx[];
-extern struct nvc0_graph_init nvc0_graph_init_unk44xx[];
-extern struct nvc0_graph_init nvc0_graph_init_unk78xx[];
-extern struct nvc0_graph_init nvc0_graph_init_unk60xx[];
-extern struct nvc0_graph_init nvc0_graph_init_unk58xx[];
-extern struct nvc0_graph_init nvc0_graph_init_unk80xx[];
-extern struct nvc0_graph_init nvc0_graph_init_gpc[];
-extern struct nvc0_graph_init nvc0_graph_init_unk88xx[];
-extern struct nvc0_graph_init nvc0_graph_tpc_0[];
-
-extern struct nvc0_graph_init nvc3_graph_init_unk58xx[];
-
-extern struct nvc0_graph_init nvd9_graph_init_unk58xx[];
-extern struct nvc0_graph_init nvd9_graph_init_unk64xx[];
-
-extern struct nvc0_graph_init nve4_graph_init_regs[];
-extern struct nvc0_graph_init nve4_graph_init_unk[];
-extern struct nvc0_graph_init nve4_graph_init_unk88xx[];
-
-extern struct nvc0_graph_init nvf0_graph_init_unk40xx[];
-extern struct nvc0_graph_init nvf0_graph_init_unk70xx[];
-extern struct nvc0_graph_init nvf0_graph_init_unk5bxx[];
-extern struct nvc0_graph_init nvf0_graph_init_tpc[];
-
-int  nvc0_grctx_generate(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nvc0_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nvc0_grctx_generate_unkn(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *);
-void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *);
-
-extern struct nouveau_oclass *nvc0_grctx_oclass;
-extern struct nvc0_graph_init *nvc0_grctx_init_hub[];
-extern struct nvc0_graph_init nvc0_grctx_init_base[];
-extern struct nvc0_graph_init nvc0_grctx_init_unk40xx[];
-extern struct nvc0_graph_init nvc0_grctx_init_unk44xx[];
-extern struct nvc0_graph_init nvc0_grctx_init_unk46xx[];
-extern struct nvc0_graph_init nvc0_grctx_init_unk47xx[];
-extern struct nvc0_graph_init nvc0_grctx_init_unk60xx[];
-extern struct nvc0_graph_init nvc0_grctx_init_unk64xx[];
-extern struct nvc0_graph_init nvc0_grctx_init_unk78xx[];
-extern struct nvc0_graph_init nvc0_grctx_init_unk80xx[];
-extern struct nvc0_graph_init nvc0_grctx_init_gpc_0[];
-extern struct nvc0_graph_init nvc0_grctx_init_gpc_1[];
-extern struct nvc0_graph_init nvc0_grctx_init_tpc[];
-extern struct nvc0_graph_init nvc0_grctx_init_icmd[];
-extern struct nvc0_graph_init nvd9_grctx_init_icmd[]; //
-
-extern struct nvc0_graph_mthd nvc0_grctx_init_mthd[];
-extern struct nvc0_graph_init nvc0_grctx_init_902d[];
-extern struct nvc0_graph_init nvc0_grctx_init_9039[];
-extern struct nvc0_graph_init nvc0_grctx_init_90c0[];
-extern struct nvc0_graph_init nvc0_grctx_init_mthd_magic[];
-
-void nvc1_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *);
-extern struct nouveau_oclass *nvc1_grctx_oclass;
-extern struct nvc0_graph_init nvc1_grctx_init_9097[];
-
-extern struct nouveau_oclass *nvc3_grctx_oclass;
-
-extern struct nouveau_oclass *nvc8_grctx_oclass;
-extern struct nvc0_graph_init nvc8_grctx_init_9197[];
-extern struct nvc0_graph_init nvc8_grctx_init_9297[];
-
-extern struct nouveau_oclass *nvd7_grctx_oclass;
-
-extern struct nouveau_oclass *nvd9_grctx_oclass;
-extern struct nvc0_graph_init nvd9_grctx_init_rop[];
-extern struct nvc0_graph_mthd nvd9_grctx_init_mthd[];
-
-void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nve4_grctx_generate_unkn(struct nvc0_graph_priv *);
-extern struct nouveau_oclass *nve4_grctx_oclass;
-extern struct nvc0_graph_init nve4_grctx_init_unk46xx[];
-extern struct nvc0_graph_init nve4_grctx_init_unk47xx[];
-extern struct nvc0_graph_init nve4_grctx_init_unk58xx[];
-extern struct nvc0_graph_init nve4_grctx_init_unk80xx[];
-extern struct nvc0_graph_init nve4_grctx_init_unk90xx[];
-
-extern struct nouveau_oclass *nvf0_grctx_oclass;
-extern struct nvc0_graph_init nvf0_grctx_init_unk44xx[];
-extern struct nvc0_graph_init nvf0_grctx_init_unk5bxx[];
-extern struct nvc0_graph_init nvf0_grctx_init_unk60xx[];
-
-extern struct nouveau_oclass *nv108_grctx_oclass;
-
-#define mmio_data(s,a,p) do {                                                  \
-       info->buffer[info->buffer_nr] = round_up(info->addr, (a));             \
-       info->addr = info->buffer[info->buffer_nr++] + (s);                    \
-       info->data->size = (s);                                                \
-       info->data->align = (a);                                               \
-       info->data->access = (p);                                              \
-       info->data++;                                                          \
-} while(0)
-
-#define mmio_list(r,d,s,b) do {                                                \
-       info->mmio->addr = (r);                                                \
-       info->mmio->data = (d);                                                \
-       info->mmio->shift = (s);                                               \
-       info->mmio->buffer = (b);                                              \
-       info->mmio++;                                                          \
-       nv_wr32(priv, (r), (d) | ((s) ? (info->buffer[(b)] >> (s)) : 0));      \
-} while(0)
+/* register init value lists */
+
+extern const struct nvc0_graph_init nvc0_graph_init_main_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_fe_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_pri_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_rstr2d_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_pd_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_ds_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_scc_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_prop_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_setup_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_crstr_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_setup_1[];
+extern const struct nvc0_graph_init nvc0_graph_init_zcull_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_gpm_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_1[];
+extern const struct nvc0_graph_init nvc0_graph_init_gcc_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_tpccs_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_tex_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_pe_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_l1c_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_wwdx_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_tpccs_1[];
+extern const struct nvc0_graph_init nvc0_graph_init_mpc_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_be_0[];
+extern const struct nvc0_graph_init nvc0_graph_init_fe_1[];
+extern const struct nvc0_graph_init nvc0_graph_init_pe_1[];
+
+extern const struct nvc0_graph_init nvc4_graph_init_ds_0[];
+extern const struct nvc0_graph_init nvc4_graph_init_tex_0[];
+extern const struct nvc0_graph_init nvc4_graph_init_sm_0[];
+
+extern const struct nvc0_graph_init nvc1_graph_init_gpc_unk_0[];
+extern const struct nvc0_graph_init nvc1_graph_init_setup_1[];
+
+extern const struct nvc0_graph_init nvd9_graph_init_pd_0[];
+extern const struct nvc0_graph_init nvd9_graph_init_ds_0[];
+extern const struct nvc0_graph_init nvd9_graph_init_prop_0[];
+extern const struct nvc0_graph_init nvd9_graph_init_gpm_0[];
+extern const struct nvc0_graph_init nvd9_graph_init_gpc_unk_1[];
+extern const struct nvc0_graph_init nvd9_graph_init_tex_0[];
+extern const struct nvc0_graph_init nvd9_graph_init_sm_0[];
+extern const struct nvc0_graph_init nvd9_graph_init_fe_1[];
+
+extern const struct nvc0_graph_init nvd7_graph_init_pes_0[];
+extern const struct nvc0_graph_init nvd7_graph_init_wwdx_0[];
+extern const struct nvc0_graph_init nvd7_graph_init_cbm_0[];
+
+extern const struct nvc0_graph_init nve4_graph_init_main_0[];
+extern const struct nvc0_graph_init nve4_graph_init_tpccs_0[];
+extern const struct nvc0_graph_init nve4_graph_init_pe_0[];
+extern const struct nvc0_graph_init nve4_graph_init_be_0[];
+
+extern const struct nvc0_graph_init nvf0_graph_init_fe_0[];
+extern const struct nvc0_graph_init nvf0_graph_init_sked_0[];
+extern const struct nvc0_graph_init nvf0_graph_init_cwd_0[];
+extern const struct nvc0_graph_init nvf0_graph_init_gpc_unk_1[];
+extern const struct nvc0_graph_init nvf0_graph_init_sm_0[];
+
+extern const struct nvc0_graph_init nv108_graph_init_gpc_unk_0[];
+
 
 #endif
index bc4a469..30cab0b 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include "nvc0.h"
+#include "ctxnvc0.h"
 
 /*******************************************************************************
  * Graphics object classes
@@ -39,94 +40,82 @@ nvc1_graph_sclass[] = {
 };
 
 /*******************************************************************************
- * PGRAPH engine/subdev functions
+ * PGRAPH register lists
  ******************************************************************************/
 
-static struct nvc0_graph_init
-nvc1_graph_init_gpc[] = {
-       { 0x4184a0,   1, 0x04, 0x00000000 },
+const struct nvc0_graph_init
+nvc1_graph_init_gpc_unk_0[] = {
        { 0x418604,   1, 0x04, 0x00000000 },
        { 0x418680,   1, 0x04, 0x00000000 },
        { 0x418714,   1, 0x04, 0x00000000 },
        { 0x418384,   1, 0x04, 0x00000000 },
-       { 0x418814,   3, 0x04, 0x00000000 },
-       { 0x418b04,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc1_graph_init_setup_1[] = {
        { 0x4188c8,   2, 0x04, 0x00000000 },
        { 0x4188d0,   1, 0x04, 0x00010000 },
        { 0x4188d4,   1, 0x04, 0x00000001 },
-       { 0x418910,   1, 0x04, 0x00010001 },
-       { 0x418914,   1, 0x04, 0x00000301 },
-       { 0x418918,   1, 0x04, 0x00800000 },
-       { 0x418980,   1, 0x04, 0x77777770 },
-       { 0x418984,   3, 0x04, 0x77777777 },
-       { 0x418c04,   1, 0x04, 0x00000000 },
-       { 0x418c88,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc1_graph_init_gpc_unk_1[] = {
        { 0x418d00,   1, 0x04, 0x00000000 },
        { 0x418f08,   1, 0x04, 0x00000000 },
        { 0x418e00,   1, 0x04, 0x00000003 },
        { 0x418e08,   1, 0x04, 0x00000000 },
-       { 0x41900c,   1, 0x04, 0x00000000 },
-       { 0x419018,   1, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nvc1_graph_init_tpc[] = {
-       { 0x419d08,   2, 0x04, 0x00000000 },
-       { 0x419d10,   1, 0x04, 0x00000014 },
-       { 0x419ab0,   1, 0x04, 0x00000000 },
-       { 0x419ac8,   1, 0x04, 0x00000000 },
-       { 0x419ab8,   1, 0x04, 0x000000e7 },
-       { 0x419abc,   2, 0x04, 0x00000000 },
-       { 0x41980c,   2, 0x04, 0x00000000 },
+static const struct nvc0_graph_init
+nvc1_graph_init_pe_0[] = {
+       { 0x41980c,   1, 0x04, 0x00000010 },
+       { 0x419810,   1, 0x04, 0x00000000 },
        { 0x419814,   1, 0x04, 0x00000004 },
        { 0x419844,   1, 0x04, 0x00000000 },
        { 0x41984c,   1, 0x04, 0x00005bc5 },
        { 0x419850,   4, 0x04, 0x00000000 },
        { 0x419880,   1, 0x04, 0x00000002 },
-       { 0x419c98,   1, 0x04, 0x00000000 },
-       { 0x419ca8,   1, 0x04, 0x80000000 },
-       { 0x419cb4,   1, 0x04, 0x00000000 },
-       { 0x419cb8,   1, 0x04, 0x00008bf4 },
-       { 0x419cbc,   1, 0x04, 0x28137606 },
-       { 0x419cc0,   2, 0x04, 0x00000000 },
-       { 0x419bd4,   1, 0x04, 0x00800000 },
-       { 0x419bdc,   1, 0x04, 0x00000000 },
-       { 0x419d2c,   1, 0x04, 0x00000000 },
-       { 0x419c0c,   1, 0x04, 0x00000000 },
-       { 0x419e00,   1, 0x04, 0x00000000 },
-       { 0x419ea0,   1, 0x04, 0x00000000 },
-       { 0x419ea4,   1, 0x04, 0x00000100 },
-       { 0x419ea8,   1, 0x04, 0x00001100 },
-       { 0x419eac,   1, 0x04, 0x11100702 },
-       { 0x419eb0,   1, 0x04, 0x00000003 },
-       { 0x419eb4,   4, 0x04, 0x00000000 },
-       { 0x419ec8,   1, 0x04, 0x0e063818 },
-       { 0x419ecc,   1, 0x04, 0x0e060e06 },
-       { 0x419ed0,   1, 0x04, 0x00003818 },
-       { 0x419ed4,   1, 0x04, 0x011104f1 },
-       { 0x419edc,   1, 0x04, 0x00000000 },
-       { 0x419f00,   1, 0x04, 0x00000000 },
-       { 0x419f2c,   1, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init *
-nvc1_graph_init_mmio[] = {
-       nvc0_graph_init_regs,
-       nvc0_graph_init_unk40xx,
-       nvc0_graph_init_unk44xx,
-       nvc0_graph_init_unk78xx,
-       nvc0_graph_init_unk60xx,
-       nvc3_graph_init_unk58xx,
-       nvc0_graph_init_unk80xx,
-       nvc1_graph_init_gpc,
-       nvc1_graph_init_tpc,
-       nvc0_graph_init_unk88xx,
-       nvc0_graph_tpc_0,
-       NULL
+static const struct nvc0_graph_pack
+nvc1_graph_pack_mmio[] = {
+       { nvc0_graph_init_main_0 },
+       { nvc0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvc0_graph_init_pd_0 },
+       { nvc4_graph_init_ds_0 },
+       { nvc0_graph_init_scc_0 },
+       { nvc0_graph_init_prop_0 },
+       { nvc1_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { nvc1_graph_init_setup_1 },
+       { nvc0_graph_init_zcull_0 },
+       { nvc0_graph_init_gpm_0 },
+       { nvc1_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { nvc0_graph_init_tpccs_0 },
+       { nvc4_graph_init_tex_0 },
+       { nvc1_graph_init_pe_0 },
+       { nvc0_graph_init_l1c_0 },
+       { nvc0_graph_init_wwdx_0 },
+       { nvc0_graph_init_tpccs_1 },
+       { nvc0_graph_init_mpc_0 },
+       { nvc4_graph_init_sm_0 },
+       { nvc0_graph_init_be_0 },
+       { nvc0_graph_init_fe_1 },
+       {}
 };
 
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
 struct nouveau_oclass *
 nvc1_graph_oclass = &(struct nvc0_graph_oclass) {
        .base.handle = NV_ENGINE(GR, 0xc1),
@@ -138,7 +127,7 @@ nvc1_graph_oclass = &(struct nvc0_graph_oclass) {
        },
        .cclass = &nvc1_grctx_oclass,
        .sclass = nvc1_graph_sclass,
-       .mmio = nvc1_graph_init_mmio,
+       .mmio = nvc1_graph_pack_mmio,
        .fecs.ucode = &nvc0_graph_fecs_ucode,
        .gpccs.ucode = &nvc0_graph_gpccs_ucode,
 }.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc3.c
deleted file mode 100644 (file)
index d44b3b3..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nvc0_graph_init
-nvc3_graph_init_unk58xx[] = {
-       { 0x405844,   1, 0x04, 0x00ffffff },
-       { 0x405850,   1, 0x04, 0x00000000 },
-       { 0x405900,   1, 0x04, 0x00002834 },
-       { 0x405908,   1, 0x04, 0x00000000 },
-       {}
-};
-
-static struct nvc0_graph_init
-nvc3_graph_init_tpc[] = {
-       { 0x419d08,   2, 0x04, 0x00000000 },
-       { 0x419d10,   1, 0x04, 0x00000014 },
-       { 0x419ab0,   1, 0x04, 0x00000000 },
-       { 0x419ac8,   1, 0x04, 0x00000000 },
-       { 0x419ab8,   1, 0x04, 0x000000e7 },
-       { 0x419abc,   2, 0x04, 0x00000000 },
-       { 0x41980c,   3, 0x04, 0x00000000 },
-       { 0x419844,   1, 0x04, 0x00000000 },
-       { 0x41984c,   1, 0x04, 0x00005bc5 },
-       { 0x419850,   4, 0x04, 0x00000000 },
-       { 0x419880,   1, 0x04, 0x00000002 },
-       { 0x419c98,   1, 0x04, 0x00000000 },
-       { 0x419ca8,   1, 0x04, 0x80000000 },
-       { 0x419cb4,   1, 0x04, 0x00000000 },
-       { 0x419cb8,   1, 0x04, 0x00008bf4 },
-       { 0x419cbc,   1, 0x04, 0x28137606 },
-       { 0x419cc0,   2, 0x04, 0x00000000 },
-       { 0x419bd4,   1, 0x04, 0x00800000 },
-       { 0x419bdc,   1, 0x04, 0x00000000 },
-       { 0x419d2c,   1, 0x04, 0x00000000 },
-       { 0x419c0c,   1, 0x04, 0x00000000 },
-       { 0x419e00,   1, 0x04, 0x00000000 },
-       { 0x419ea0,   1, 0x04, 0x00000000 },
-       { 0x419ea4,   1, 0x04, 0x00000100 },
-       { 0x419ea8,   1, 0x04, 0x00001100 },
-       { 0x419eac,   1, 0x04, 0x11100702 },
-       { 0x419eb0,   1, 0x04, 0x00000003 },
-       { 0x419eb4,   4, 0x04, 0x00000000 },
-       { 0x419ec8,   1, 0x04, 0x0e063818 },
-       { 0x419ecc,   1, 0x04, 0x0e060e06 },
-       { 0x419ed0,   1, 0x04, 0x00003818 },
-       { 0x419ed4,   1, 0x04, 0x011104f1 },
-       { 0x419edc,   1, 0x04, 0x00000000 },
-       { 0x419f00,   1, 0x04, 0x00000000 },
-       { 0x419f2c,   1, 0x04, 0x00000000 },
-       {}
-};
-
-static struct nvc0_graph_init *
-nvc3_graph_init_mmio[] = {
-       nvc0_graph_init_regs,
-       nvc0_graph_init_unk40xx,
-       nvc0_graph_init_unk44xx,
-       nvc0_graph_init_unk78xx,
-       nvc0_graph_init_unk60xx,
-       nvc3_graph_init_unk58xx,
-       nvc0_graph_init_unk80xx,
-       nvc0_graph_init_gpc,
-       nvc3_graph_init_tpc,
-       nvc0_graph_init_unk88xx,
-       nvc0_graph_tpc_0,
-       NULL
-};
-
-struct nouveau_oclass *
-nvc3_graph_oclass = &(struct nvc0_graph_oclass) {
-       .base.handle = NV_ENGINE(GR, 0xc3),
-       .base.ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nvc0_graph_ctor,
-               .dtor = nvc0_graph_dtor,
-               .init = nvc0_graph_init,
-               .fini = _nouveau_graph_fini,
-       },
-       .cclass = &nvc3_grctx_oclass,
-       .sclass = nvc0_graph_sclass,
-       .mmio = nvc3_graph_init_mmio,
-       .fecs.ucode = &nvc0_graph_fecs_ucode,
-       .gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c
new file mode 100644 (file)
index 0000000..e82e70c
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+#include "ctxnvc0.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct nvc0_graph_init
+nvc4_graph_init_ds_0[] = {
+       { 0x405844,   1, 0x04, 0x00ffffff },
+       { 0x405850,   1, 0x04, 0x00000000 },
+       { 0x405900,   1, 0x04, 0x00002834 },
+       { 0x405908,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc4_graph_init_tex_0[] = {
+       { 0x419ab0,   1, 0x04, 0x00000000 },
+       { 0x419ac8,   1, 0x04, 0x00000000 },
+       { 0x419ab8,   1, 0x04, 0x000000e7 },
+       { 0x419abc,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvc4_graph_init_pe_0[] = {
+       { 0x41980c,   3, 0x04, 0x00000000 },
+       { 0x419844,   1, 0x04, 0x00000000 },
+       { 0x41984c,   1, 0x04, 0x00005bc5 },
+       { 0x419850,   4, 0x04, 0x00000000 },
+       { 0x419880,   1, 0x04, 0x00000002 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvc4_graph_init_sm_0[] = {
+       { 0x419e00,   1, 0x04, 0x00000000 },
+       { 0x419ea0,   1, 0x04, 0x00000000 },
+       { 0x419ea4,   1, 0x04, 0x00000100 },
+       { 0x419ea8,   1, 0x04, 0x00001100 },
+       { 0x419eac,   1, 0x04, 0x11100702 },
+       { 0x419eb0,   1, 0x04, 0x00000003 },
+       { 0x419eb4,   4, 0x04, 0x00000000 },
+       { 0x419ec8,   1, 0x04, 0x0e063818 },
+       { 0x419ecc,   1, 0x04, 0x0e060e06 },
+       { 0x419ed0,   1, 0x04, 0x00003818 },
+       { 0x419ed4,   1, 0x04, 0x011104f1 },
+       { 0x419edc,   1, 0x04, 0x00000000 },
+       { 0x419f00,   1, 0x04, 0x00000000 },
+       { 0x419f2c,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+nvc4_graph_pack_mmio[] = {
+       { nvc0_graph_init_main_0 },
+       { nvc0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvc0_graph_init_pd_0 },
+       { nvc4_graph_init_ds_0 },
+       { nvc0_graph_init_scc_0 },
+       { nvc0_graph_init_prop_0 },
+       { nvc0_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { nvc0_graph_init_setup_1 },
+       { nvc0_graph_init_zcull_0 },
+       { nvc0_graph_init_gpm_0 },
+       { nvc0_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { nvc0_graph_init_tpccs_0 },
+       { nvc4_graph_init_tex_0 },
+       { nvc4_graph_init_pe_0 },
+       { nvc0_graph_init_l1c_0 },
+       { nvc0_graph_init_wwdx_0 },
+       { nvc0_graph_init_tpccs_1 },
+       { nvc0_graph_init_mpc_0 },
+       { nvc4_graph_init_sm_0 },
+       { nvc0_graph_init_be_0 },
+       { nvc0_graph_init_fe_1 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nouveau_oclass *
+nvc4_graph_oclass = &(struct nvc0_graph_oclass) {
+       .base.handle = NV_ENGINE(GR, 0xc3),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_graph_ctor,
+               .dtor = nvc0_graph_dtor,
+               .init = nvc0_graph_init,
+               .fini = _nouveau_graph_fini,
+       },
+       .cclass = &nvc4_grctx_oclass,
+       .sclass = nvc0_graph_sclass,
+       .mmio = nvc4_graph_pack_mmio,
+       .fecs.ucode = &nvc0_graph_fecs_ucode,
+       .gpccs.ucode = &nvc0_graph_gpccs_ucode,
+}.base;
index 02845e5..a6bf783 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include "nvc0.h"
+#include "ctxnvc0.h"
 
 /*******************************************************************************
  * Graphics object classes
@@ -40,58 +41,11 @@ nvc8_graph_sclass[] = {
 };
 
 /*******************************************************************************
- * PGRAPH engine/subdev functions
+ * PGRAPH register lists
  ******************************************************************************/
 
-static struct nvc0_graph_init
-nvc8_graph_init_gpc[] = {
-       { 0x4184a0,   1, 0x04, 0x00000000 },
-       { 0x418604,   1, 0x04, 0x00000000 },
-       { 0x418680,   1, 0x04, 0x00000000 },
-       { 0x418714,   1, 0x04, 0x80000000 },
-       { 0x418384,   1, 0x04, 0x00000000 },
-       { 0x418814,   3, 0x04, 0x00000000 },
-       { 0x418b04,   1, 0x04, 0x00000000 },
-       { 0x4188c8,   2, 0x04, 0x00000000 },
-       { 0x4188d0,   1, 0x04, 0x00010000 },
-       { 0x4188d4,   1, 0x04, 0x00000001 },
-       { 0x418910,   1, 0x04, 0x00010001 },
-       { 0x418914,   1, 0x04, 0x00000301 },
-       { 0x418918,   1, 0x04, 0x00800000 },
-       { 0x418980,   1, 0x04, 0x77777770 },
-       { 0x418984,   3, 0x04, 0x77777777 },
-       { 0x418c04,   1, 0x04, 0x00000000 },
-       { 0x418c88,   1, 0x04, 0x00000000 },
-       { 0x418d00,   1, 0x04, 0x00000000 },
-       { 0x418f08,   1, 0x04, 0x00000000 },
-       { 0x418e00,   1, 0x04, 0x00000050 },
-       { 0x418e08,   1, 0x04, 0x00000000 },
-       { 0x41900c,   1, 0x04, 0x00000000 },
-       { 0x419018,   1, 0x04, 0x00000000 },
-       {}
-};
-
-static struct nvc0_graph_init
-nvc8_graph_init_tpc[] = {
-       { 0x419d08,   2, 0x04, 0x00000000 },
-       { 0x419d10,   1, 0x04, 0x00000014 },
-       { 0x419ab0,   1, 0x04, 0x00000000 },
-       { 0x419ab8,   1, 0x04, 0x000000e7 },
-       { 0x419abc,   2, 0x04, 0x00000000 },
-       { 0x41980c,   3, 0x04, 0x00000000 },
-       { 0x419844,   1, 0x04, 0x00000000 },
-       { 0x41984c,   1, 0x04, 0x00005bc5 },
-       { 0x419850,   4, 0x04, 0x00000000 },
-       { 0x419c98,   1, 0x04, 0x00000000 },
-       { 0x419ca8,   1, 0x04, 0x80000000 },
-       { 0x419cb4,   1, 0x04, 0x00000000 },
-       { 0x419cb8,   1, 0x04, 0x00008bf4 },
-       { 0x419cbc,   1, 0x04, 0x28137606 },
-       { 0x419cc0,   2, 0x04, 0x00000000 },
-       { 0x419bd4,   1, 0x04, 0x00800000 },
-       { 0x419bdc,   1, 0x04, 0x00000000 },
-       { 0x419d2c,   1, 0x04, 0x00000000 },
-       { 0x419c0c,   1, 0x04, 0x00000000 },
+static const struct nvc0_graph_init
+nvc8_graph_init_sm_0[] = {
        { 0x419e00,   1, 0x04, 0x00000000 },
        { 0x419ea0,   1, 0x04, 0x00000000 },
        { 0x419ea4,   1, 0x04, 0x00000100 },
@@ -108,22 +62,42 @@ nvc8_graph_init_tpc[] = {
        {}
 };
 
-static struct nvc0_graph_init *
-nvc8_graph_init_mmio[] = {
-       nvc0_graph_init_regs,
-       nvc0_graph_init_unk40xx,
-       nvc0_graph_init_unk44xx,
-       nvc0_graph_init_unk78xx,
-       nvc0_graph_init_unk60xx,
-       nvc0_graph_init_unk58xx,
-       nvc0_graph_init_unk80xx,
-       nvc8_graph_init_gpc,
-       nvc8_graph_init_tpc,
-       nvc0_graph_init_unk88xx,
-       nvc0_graph_tpc_0,
-       NULL
+static const struct nvc0_graph_pack
+nvc8_graph_pack_mmio[] = {
+       { nvc0_graph_init_main_0 },
+       { nvc0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvc0_graph_init_pd_0 },
+       { nvc0_graph_init_ds_0 },
+       { nvc0_graph_init_scc_0 },
+       { nvc0_graph_init_prop_0 },
+       { nvc0_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { nvc1_graph_init_setup_1 },
+       { nvc0_graph_init_zcull_0 },
+       { nvc0_graph_init_gpm_0 },
+       { nvc0_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { nvc0_graph_init_tpccs_0 },
+       { nvc0_graph_init_tex_0 },
+       { nvc0_graph_init_pe_0 },
+       { nvc0_graph_init_l1c_0 },
+       { nvc0_graph_init_wwdx_0 },
+       { nvc0_graph_init_tpccs_1 },
+       { nvc0_graph_init_mpc_0 },
+       { nvc8_graph_init_sm_0 },
+       { nvc0_graph_init_be_0 },
+       { nvc0_graph_init_fe_1 },
+       { nvc0_graph_init_pe_1 },
+       {}
 };
 
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
 struct nouveau_oclass *
 nvc8_graph_oclass = &(struct nvc0_graph_oclass) {
        .base.handle = NV_ENGINE(GR, 0xc8),
@@ -135,7 +109,7 @@ nvc8_graph_oclass = &(struct nvc0_graph_oclass) {
        },
        .cclass = &nvc8_grctx_oclass,
        .sclass = nvc8_graph_sclass,
-       .mmio = nvc8_graph_init_mmio,
+       .mmio = nvc8_graph_pack_mmio,
        .fecs.ucode = &nvc0_graph_fecs_ucode,
        .gpccs.ucode = &nvc0_graph_gpccs_ucode,
 }.base;
index 5052d7a..2a6a94e 100644 (file)
  */
 
 #include "nvc0.h"
+#include "ctxnvc0.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct nvc0_graph_init
+nvd7_graph_init_pe_0[] = {
+       { 0x41980c,   1, 0x04, 0x00000010 },
+       { 0x419844,   1, 0x04, 0x00000000 },
+       { 0x41984c,   1, 0x04, 0x00005bc8 },
+       { 0x419850,   3, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd7_graph_init_pes_0[] = {
+       { 0x41be04,   1, 0x04, 0x00000000 },
+       { 0x41be08,   1, 0x04, 0x00000004 },
+       { 0x41be0c,   1, 0x04, 0x00000000 },
+       { 0x41be10,   1, 0x04, 0x003b8bc7 },
+       { 0x41be14,   2, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd7_graph_init_wwdx_0[] = {
+       { 0x41bfd4,   1, 0x04, 0x00800000 },
+       { 0x41bfdc,   1, 0x04, 0x00000000 },
+       { 0x41bff8,   2, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd7_graph_init_cbm_0[] = {
+       { 0x41becc,   1, 0x04, 0x00000000 },
+       { 0x41bee8,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_pack
+nvd7_graph_pack_mmio[] = {
+       { nvc0_graph_init_main_0 },
+       { nvc0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvd9_graph_init_pd_0 },
+       { nvd9_graph_init_ds_0 },
+       { nvc0_graph_init_scc_0 },
+       { nvd9_graph_init_prop_0 },
+       { nvc1_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { nvc1_graph_init_setup_1 },
+       { nvc0_graph_init_zcull_0 },
+       { nvd9_graph_init_gpm_0 },
+       { nvd9_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { nvc0_graph_init_tpccs_0 },
+       { nvd9_graph_init_tex_0 },
+       { nvd7_graph_init_pe_0 },
+       { nvc0_graph_init_l1c_0 },
+       { nvc0_graph_init_mpc_0 },
+       { nvd9_graph_init_sm_0 },
+       { nvd7_graph_init_pes_0 },
+       { nvd7_graph_init_wwdx_0 },
+       { nvd7_graph_init_cbm_0 },
+       { nvc0_graph_init_be_0 },
+       { nvd9_graph_init_fe_1 },
+       {}
+};
 
 /*******************************************************************************
  * PGRAPH engine/subdev functions
@@ -48,108 +119,6 @@ nvd7_graph_gpccs_ucode = {
        .data.size = sizeof(nvd7_grgpc_data),
 };
 
-static struct nvc0_graph_init
-nvd7_graph_init_gpc[] = {
-       { 0x418408,   1, 0x04, 0x00000000 },
-       { 0x4184a0,   1, 0x04, 0x00000000 },
-       { 0x4184a4,   2, 0x04, 0x00000000 },
-       { 0x418604,   1, 0x04, 0x00000000 },
-       { 0x418680,   1, 0x04, 0x00000000 },
-       { 0x418714,   1, 0x04, 0x00000000 },
-       { 0x418384,   1, 0x04, 0x00000000 },
-       { 0x418814,   3, 0x04, 0x00000000 },
-       { 0x418b04,   1, 0x04, 0x00000000 },
-       { 0x4188c8,   2, 0x04, 0x00000000 },
-       { 0x4188d0,   1, 0x04, 0x00010000 },
-       { 0x4188d4,   1, 0x04, 0x00000001 },
-       { 0x418910,   1, 0x04, 0x00010001 },
-       { 0x418914,   1, 0x04, 0x00000301 },
-       { 0x418918,   1, 0x04, 0x00800000 },
-       { 0x418980,   1, 0x04, 0x77777770 },
-       { 0x418984,   3, 0x04, 0x77777777 },
-       { 0x418c04,   1, 0x04, 0x00000000 },
-       { 0x418c64,   1, 0x04, 0x00000000 },
-       { 0x418c68,   1, 0x04, 0x00000000 },
-       { 0x418c88,   1, 0x04, 0x00000000 },
-       { 0x418cb4,   2, 0x04, 0x00000000 },
-       { 0x418d00,   1, 0x04, 0x00000000 },
-       { 0x418d28,   1, 0x04, 0x00000000 },
-       { 0x418f00,   1, 0x04, 0x00000000 },
-       { 0x418f08,   1, 0x04, 0x00000000 },
-       { 0x418f20,   2, 0x04, 0x00000000 },
-       { 0x418e00,   1, 0x04, 0x00000003 },
-       { 0x418e08,   1, 0x04, 0x00000000 },
-       { 0x418e1c,   1, 0x04, 0x00000000 },
-       { 0x418e20,   1, 0x04, 0x00000000 },
-       { 0x41900c,   1, 0x04, 0x00000000 },
-       { 0x419018,   1, 0x04, 0x00000000 },
-       {}
-};
-
-static struct nvc0_graph_init
-nvd7_graph_init_tpc[] = {
-       { 0x419d08,   2, 0x04, 0x00000000 },
-       { 0x419d10,   1, 0x04, 0x00000014 },
-       { 0x419ab0,   1, 0x04, 0x00000000 },
-       { 0x419ac8,   1, 0x04, 0x00000000 },
-       { 0x419ab8,   1, 0x04, 0x000000e7 },
-       { 0x419abc,   2, 0x04, 0x00000000 },
-       { 0x419ab4,   1, 0x04, 0x00000000 },
-       { 0x41980c,   1, 0x04, 0x00000010 },
-       { 0x419844,   1, 0x04, 0x00000000 },
-       { 0x41984c,   1, 0x04, 0x00005bc8 },
-       { 0x419850,   2, 0x04, 0x00000000 },
-       { 0x419c98,   1, 0x04, 0x00000000 },
-       { 0x419ca8,   1, 0x04, 0x80000000 },
-       { 0x419cb4,   1, 0x04, 0x00000000 },
-       { 0x419cb8,   1, 0x04, 0x00008bf4 },
-       { 0x419cbc,   1, 0x04, 0x28137606 },
-       { 0x419cc0,   2, 0x04, 0x00000000 },
-       { 0x419c0c,   1, 0x04, 0x00000000 },
-       { 0x419e00,   1, 0x04, 0x00000000 },
-       { 0x419ea0,   1, 0x04, 0x00000000 },
-       { 0x419ea4,   1, 0x04, 0x00000100 },
-       { 0x419ea8,   1, 0x04, 0x02001100 },
-       { 0x419eac,   1, 0x04, 0x11100702 },
-       { 0x419eb0,   1, 0x04, 0x00000003 },
-       { 0x419eb4,   4, 0x04, 0x00000000 },
-       { 0x419ec8,   1, 0x04, 0x0e063818 },
-       { 0x419ecc,   1, 0x04, 0x0e060e06 },
-       { 0x419ed0,   1, 0x04, 0x00003818 },
-       { 0x419ed4,   1, 0x04, 0x011104f1 },
-       { 0x419edc,   1, 0x04, 0x00000000 },
-       { 0x419f00,   1, 0x04, 0x00000000 },
-       { 0x419f2c,   1, 0x04, 0x00000000 },
-       {}
-};
-
-static struct nvc0_graph_init
-nvd7_graph_init_tpc_0[] = {
-       { 0x40402c,   1, 0x04, 0x00000000 },
-       { 0x4040f0,   1, 0x04, 0x00000000 },
-       { 0x404174,   1, 0x04, 0x00000000 },
-       { 0x503018,   1, 0x04, 0x00000001 },
-       {}
-};
-
-static struct nvc0_graph_init *
-nvd7_graph_init_mmio[] = {
-       nvc0_graph_init_regs,
-       nvc0_graph_init_unk40xx,
-       nvc0_graph_init_unk44xx,
-       nvc0_graph_init_unk78xx,
-       nvc0_graph_init_unk60xx,
-       nvd9_graph_init_unk64xx,
-       nvd9_graph_init_unk58xx,
-       nvc0_graph_init_unk80xx,
-       nvd7_graph_init_gpc,
-       nvd7_graph_init_tpc,
-       nve4_graph_init_unk,
-       nvc0_graph_init_unk88xx,
-       nvd7_graph_init_tpc_0,
-       NULL
-};
-
 struct nouveau_oclass *
 nvd7_graph_oclass = &(struct nvc0_graph_oclass) {
        .base.handle = NV_ENGINE(GR, 0xd7),
@@ -161,7 +130,7 @@ nvd7_graph_oclass = &(struct nvc0_graph_oclass) {
        },
        .cclass = &nvd7_grctx_oclass,
        .sclass = nvc8_graph_sclass,
-       .mmio = nvd7_graph_init_mmio,
+       .mmio = nvd7_graph_pack_mmio,
        .fecs.ucode = &nvd7_graph_fecs_ucode,
        .gpccs.ucode = &nvd7_graph_gpccs_ucode,
 }.base;
index 652098e..00fdf20 100644 (file)
  */
 
 #include "nvc0.h"
+#include "ctxnvc0.h"
 
 /*******************************************************************************
- * PGRAPH engine/subdev functions
+ * PGRAPH register lists
  ******************************************************************************/
 
-struct nvc0_graph_init
-nvd9_graph_init_unk64xx[] = {
+const struct nvc0_graph_init
+nvd9_graph_init_pd_0[] = {
+       { 0x406024,   1, 0x04, 0x00000000 },
        { 0x4064f0,   3, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvd9_graph_init_unk58xx[] = {
+const struct nvc0_graph_init
+nvd9_graph_init_ds_0[] = {
        { 0x405844,   1, 0x04, 0x00ffffff },
        { 0x405850,   1, 0x04, 0x00000000 },
        { 0x405900,   1, 0x04, 0x00002834 },
        { 0x405908,   1, 0x04, 0x00000000 },
-       { 0x405928,   1, 0x04, 0x00000000 },
-       { 0x40592c,   1, 0x04, 0x00000000 },
+       { 0x405928,   2, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nvd9_graph_init_gpc[] = {
+const struct nvc0_graph_init
+nvd9_graph_init_prop_0[] = {
        { 0x418408,   1, 0x04, 0x00000000 },
-       { 0x4184a0,   1, 0x04, 0x00000000 },
-       { 0x4184a4,   2, 0x04, 0x00000000 },
-       { 0x418604,   1, 0x04, 0x00000000 },
-       { 0x418680,   1, 0x04, 0x00000000 },
-       { 0x418714,   1, 0x04, 0x00000000 },
-       { 0x418384,   1, 0x04, 0x00000000 },
-       { 0x418814,   3, 0x04, 0x00000000 },
-       { 0x418b04,   1, 0x04, 0x00000000 },
-       { 0x4188c8,   2, 0x04, 0x00000000 },
-       { 0x4188d0,   1, 0x04, 0x00010000 },
-       { 0x4188d4,   1, 0x04, 0x00000001 },
-       { 0x418910,   1, 0x04, 0x00010001 },
-       { 0x418914,   1, 0x04, 0x00000301 },
-       { 0x418918,   1, 0x04, 0x00800000 },
-       { 0x418980,   1, 0x04, 0x77777770 },
-       { 0x418984,   3, 0x04, 0x77777777 },
+       { 0x4184a0,   3, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd9_graph_init_gpm_0[] = {
        { 0x418c04,   1, 0x04, 0x00000000 },
-       { 0x418c64,   1, 0x04, 0x00000000 },
-       { 0x418c68,   1, 0x04, 0x00000000 },
+       { 0x418c64,   2, 0x04, 0x00000000 },
        { 0x418c88,   1, 0x04, 0x00000000 },
        { 0x418cb4,   2, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd9_graph_init_gpc_unk_1[] = {
        { 0x418d00,   1, 0x04, 0x00000000 },
-       { 0x418d28,   1, 0x04, 0x00000000 },
-       { 0x418d2c,   1, 0x04, 0x00000000 },
+       { 0x418d28,   2, 0x04, 0x00000000 },
        { 0x418f00,   1, 0x04, 0x00000000 },
        { 0x418f08,   1, 0x04, 0x00000000 },
        { 0x418f20,   2, 0x04, 0x00000000 },
        { 0x418e00,   1, 0x04, 0x00000003 },
        { 0x418e08,   1, 0x04, 0x00000000 },
-       { 0x418e1c,   1, 0x04, 0x00000000 },
-       { 0x418e20,   1, 0x04, 0x00000000 },
-       { 0x41900c,   1, 0x04, 0x00000000 },
-       { 0x419018,   1, 0x04, 0x00000000 },
+       { 0x418e1c,   2, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nvd9_graph_init_tpc[] = {
-       { 0x419d08,   2, 0x04, 0x00000000 },
-       { 0x419d10,   1, 0x04, 0x00000014 },
+const struct nvc0_graph_init
+nvd9_graph_init_tex_0[] = {
        { 0x419ab0,   1, 0x04, 0x00000000 },
        { 0x419ac8,   1, 0x04, 0x00000000 },
        { 0x419ab8,   1, 0x04, 0x000000e7 },
        { 0x419abc,   2, 0x04, 0x00000000 },
        { 0x419ab4,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd9_graph_init_pe_0[] = {
        { 0x41980c,   1, 0x04, 0x00000010 },
        { 0x419810,   1, 0x04, 0x00000000 },
        { 0x419814,   1, 0x04, 0x00000004 },
@@ -100,20 +94,26 @@ nvd9_graph_init_tpc[] = {
        { 0x41984c,   1, 0x04, 0x0000a918 },
        { 0x419850,   4, 0x04, 0x00000000 },
        { 0x419880,   1, 0x04, 0x00000002 },
-       { 0x419c98,   1, 0x04, 0x00000000 },
-       { 0x419ca8,   1, 0x04, 0x80000000 },
-       { 0x419cb4,   1, 0x04, 0x00000000 },
-       { 0x419cb8,   1, 0x04, 0x00008bf4 },
-       { 0x419cbc,   1, 0x04, 0x28137606 },
-       { 0x419cc0,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd9_graph_init_wwdx_0[] = {
        { 0x419bd4,   1, 0x04, 0x00800000 },
        { 0x419bdc,   1, 0x04, 0x00000000 },
-       { 0x419bf8,   1, 0x04, 0x00000000 },
-       { 0x419bfc,   1, 0x04, 0x00000000 },
+       { 0x419bf8,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvd9_graph_init_tpccs_1[] = {
        { 0x419d2c,   1, 0x04, 0x00000000 },
-       { 0x419d48,   1, 0x04, 0x00000000 },
-       { 0x419d4c,   1, 0x04, 0x00000000 },
-       { 0x419c0c,   1, 0x04, 0x00000000 },
+       { 0x419d48,   2, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvd9_graph_init_sm_0[] = {
        { 0x419e00,   1, 0x04, 0x00000000 },
        { 0x419ea0,   1, 0x04, 0x00000000 },
        { 0x419ea4,   1, 0x04, 0x00000100 },
@@ -131,23 +131,49 @@ nvd9_graph_init_tpc[] = {
        {}
 };
 
-static struct nvc0_graph_init *
-nvd9_graph_init_mmio[] = {
-       nvc0_graph_init_regs,
-       nvc0_graph_init_unk40xx,
-       nvc0_graph_init_unk44xx,
-       nvc0_graph_init_unk78xx,
-       nvc0_graph_init_unk60xx,
-       nvd9_graph_init_unk64xx,
-       nvd9_graph_init_unk58xx,
-       nvc0_graph_init_unk80xx,
-       nvd9_graph_init_gpc,
-       nvd9_graph_init_tpc,
-       nvc0_graph_init_unk88xx,
-       nvc0_graph_tpc_0,
-       NULL
+const struct nvc0_graph_init
+nvd9_graph_init_fe_1[] = {
+       { 0x40402c,   1, 0x04, 0x00000000 },
+       { 0x4040f0,   1, 0x04, 0x00000000 },
+       { 0x404174,   1, 0x04, 0x00000000 },
+       {}
 };
 
+static const struct nvc0_graph_pack
+nvd9_graph_pack_mmio[] = {
+       { nvc0_graph_init_main_0 },
+       { nvc0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvd9_graph_init_pd_0 },
+       { nvd9_graph_init_ds_0 },
+       { nvc0_graph_init_scc_0 },
+       { nvd9_graph_init_prop_0 },
+       { nvc1_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { nvc1_graph_init_setup_1 },
+       { nvc0_graph_init_zcull_0 },
+       { nvd9_graph_init_gpm_0 },
+       { nvd9_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { nvc0_graph_init_tpccs_0 },
+       { nvd9_graph_init_tex_0 },
+       { nvd9_graph_init_pe_0 },
+       { nvc0_graph_init_l1c_0 },
+       { nvd9_graph_init_wwdx_0 },
+       { nvd9_graph_init_tpccs_1 },
+       { nvc0_graph_init_mpc_0 },
+       { nvd9_graph_init_sm_0 },
+       { nvc0_graph_init_be_0 },
+       { nvd9_graph_init_fe_1 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
 struct nouveau_oclass *
 nvd9_graph_oclass = &(struct nvc0_graph_oclass) {
        .base.handle = NV_ENGINE(GR, 0xd9),
@@ -159,7 +185,7 @@ nvd9_graph_oclass = &(struct nvc0_graph_oclass) {
        },
        .cclass = &nvd9_grctx_oclass,
        .sclass = nvc8_graph_sclass,
-       .mmio = nvd9_graph_init_mmio,
+       .mmio = nvd9_graph_pack_mmio,
        .fecs.ucode = &nvc0_graph_fecs_ucode,
        .gpccs.ucode = &nvc0_graph_gpccs_ucode,
 }.base;
index 05ec09c..f7c0112 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include "nvc0.h"
+#include "ctxnvc0.h"
 
 /*******************************************************************************
  * Graphics object classes
@@ -38,11 +39,11 @@ nve4_graph_sclass[] = {
 };
 
 /*******************************************************************************
- * PGRAPH engine/subdev functions
+ * PGRAPH register lists
  ******************************************************************************/
 
-struct nvc0_graph_init
-nve4_graph_init_regs[] = {
+const struct nvc0_graph_init
+nve4_graph_init_main_0[] = {
        { 0x400080,   1, 0x04, 0x003083c2 },
        { 0x400088,   1, 0x04, 0x0001ffe7 },
        { 0x40008c,   1, 0x04, 0x00000000 },
@@ -57,81 +58,59 @@ nve4_graph_init_regs[] = {
        {}
 };
 
-static struct nvc0_graph_init
-nve4_graph_init_unk58xx[] = {
+static const struct nvc0_graph_init
+nve4_graph_init_ds_0[] = {
        { 0x405844,   1, 0x04, 0x00ffffff },
        { 0x405850,   1, 0x04, 0x00000000 },
        { 0x405900,   1, 0x04, 0x0000ff34 },
        { 0x405908,   1, 0x04, 0x00000000 },
-       { 0x405928,   1, 0x04, 0x00000000 },
-       { 0x40592c,   1, 0x04, 0x00000000 },
+       { 0x405928,   2, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nve4_graph_init_unk70xx[] = {
+static const struct nvc0_graph_init
+nve4_graph_init_sked_0[] = {
        { 0x407010,   1, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nve4_graph_init_unk5bxx[] = {
+static const struct nvc0_graph_init
+nve4_graph_init_cwd_0[] = {
        { 0x405b50,   1, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nve4_graph_init_gpc[] = {
-       { 0x418408,   1, 0x04, 0x00000000 },
-       { 0x4184a0,   1, 0x04, 0x00000000 },
-       { 0x4184a4,   2, 0x04, 0x00000000 },
-       { 0x418604,   1, 0x04, 0x00000000 },
-       { 0x418680,   1, 0x04, 0x00000000 },
-       { 0x418714,   1, 0x04, 0x00000000 },
-       { 0x418384,   1, 0x04, 0x00000000 },
-       { 0x418814,   3, 0x04, 0x00000000 },
-       { 0x418b04,   1, 0x04, 0x00000000 },
-       { 0x4188c8,   2, 0x04, 0x00000000 },
-       { 0x4188d0,   1, 0x04, 0x00010000 },
-       { 0x4188d4,   1, 0x04, 0x00000001 },
-       { 0x418910,   1, 0x04, 0x00010001 },
-       { 0x418914,   1, 0x04, 0x00000301 },
-       { 0x418918,   1, 0x04, 0x00800000 },
-       { 0x418980,   1, 0x04, 0x77777770 },
-       { 0x418984,   3, 0x04, 0x77777777 },
-       { 0x418c04,   1, 0x04, 0x00000000 },
-       { 0x418c64,   1, 0x04, 0x00000000 },
-       { 0x418c68,   1, 0x04, 0x00000000 },
-       { 0x418c88,   1, 0x04, 0x00000000 },
-       { 0x418cb4,   2, 0x04, 0x00000000 },
+static const struct nvc0_graph_init
+nve4_graph_init_gpc_unk_1[] = {
        { 0x418d00,   1, 0x04, 0x00000000 },
-       { 0x418d28,   1, 0x04, 0x00000000 },
-       { 0x418d2c,   1, 0x04, 0x00000000 },
+       { 0x418d28,   2, 0x04, 0x00000000 },
        { 0x418f00,   1, 0x04, 0x00000000 },
        { 0x418f08,   1, 0x04, 0x00000000 },
        { 0x418f20,   2, 0x04, 0x00000000 },
        { 0x418e00,   1, 0x04, 0x00000060 },
        { 0x418e08,   1, 0x04, 0x00000000 },
-       { 0x418e1c,   1, 0x04, 0x00000000 },
-       { 0x418e20,   1, 0x04, 0x00000000 },
-       { 0x41900c,   1, 0x04, 0x00000000 },
-       { 0x419018,   1, 0x04, 0x00000000 },
+       { 0x418e1c,   2, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nve4_graph_init_tpc[] = {
+const struct nvc0_graph_init
+nve4_graph_init_tpccs_0[] = {
        { 0x419d0c,   1, 0x04, 0x00000000 },
        { 0x419d10,   1, 0x04, 0x00000014 },
-       { 0x419ab0,   1, 0x04, 0x00000000 },
-       { 0x419ac8,   1, 0x04, 0x00000000 },
-       { 0x419ab8,   1, 0x04, 0x000000e7 },
-       { 0x419abc,   2, 0x04, 0x00000000 },
-       { 0x419ab4,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nve4_graph_init_pe_0[] = {
        { 0x41980c,   1, 0x04, 0x00000010 },
        { 0x419844,   1, 0x04, 0x00000000 },
        { 0x419850,   1, 0x04, 0x00000004 },
        { 0x419854,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_graph_init_l1c_0[] = {
        { 0x419c98,   1, 0x04, 0x00000000 },
        { 0x419ca8,   1, 0x04, 0x00000000 },
        { 0x419cb0,   1, 0x04, 0x01000000 },
@@ -141,39 +120,25 @@ nve4_graph_init_tpc[] = {
        { 0x419cbc,   1, 0x04, 0x28137646 },
        { 0x419cc0,   2, 0x04, 0x00000000 },
        { 0x419c80,   1, 0x04, 0x00020232 },
-       { 0x419c0c,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nve4_graph_init_sm_0[] = {
        { 0x419e00,   1, 0x04, 0x00000000 },
        { 0x419ea0,   1, 0x04, 0x00000000 },
        { 0x419ee4,   1, 0x04, 0x00000000 },
        { 0x419ea4,   1, 0x04, 0x00000100 },
        { 0x419ea8,   1, 0x04, 0x00000000 },
-       { 0x419eb4,   1, 0x04, 0x00000000 },
-       { 0x419eb8,   3, 0x04, 0x00000000 },
+       { 0x419eb4,   4, 0x04, 0x00000000 },
        { 0x419edc,   1, 0x04, 0x00000000 },
        { 0x419f00,   1, 0x04, 0x00000000 },
        { 0x419f74,   1, 0x04, 0x00000555 },
        {}
 };
 
-struct nvc0_graph_init
-nve4_graph_init_unk[] = {
-       { 0x41be04,   1, 0x04, 0x00000000 },
-       { 0x41be08,   1, 0x04, 0x00000004 },
-       { 0x41be0c,   1, 0x04, 0x00000000 },
-       { 0x41be10,   1, 0x04, 0x003b8bc7 },
-       { 0x41be14,   2, 0x04, 0x00000000 },
-       { 0x41bfd4,   1, 0x04, 0x00800000 },
-       { 0x41bfdc,   1, 0x04, 0x00000000 },
-       { 0x41bff8,   1, 0x04, 0x00000000 },
-       { 0x41bffc,   1, 0x04, 0x00000000 },
-       { 0x41becc,   1, 0x04, 0x00000000 },
-       { 0x41bee8,   1, 0x04, 0x00000000 },
-       { 0x41beec,   1, 0x04, 0x00000000 },
-       {}
-};
-
-struct nvc0_graph_init
-nve4_graph_init_unk88xx[] = {
+const struct nvc0_graph_init
+nve4_graph_init_be_0[] = {
        { 0x40880c,   1, 0x04, 0x00000000 },
        { 0x408850,   1, 0x04, 0x00000004 },
        { 0x408910,   9, 0x04, 0x00000000 },
@@ -186,6 +151,67 @@ nve4_graph_init_unk88xx[] = {
        {}
 };
 
+static const struct nvc0_graph_pack
+nve4_graph_pack_mmio[] = {
+       { nve4_graph_init_main_0 },
+       { nvc0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvd9_graph_init_pd_0 },
+       { nve4_graph_init_ds_0 },
+       { nvc0_graph_init_scc_0 },
+       { nve4_graph_init_sked_0 },
+       { nve4_graph_init_cwd_0 },
+       { nvd9_graph_init_prop_0 },
+       { nvc1_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { nvc1_graph_init_setup_1 },
+       { nvc0_graph_init_zcull_0 },
+       { nvd9_graph_init_gpm_0 },
+       { nve4_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { nve4_graph_init_tpccs_0 },
+       { nvd9_graph_init_tex_0 },
+       { nve4_graph_init_pe_0 },
+       { nve4_graph_init_l1c_0 },
+       { nvc0_graph_init_mpc_0 },
+       { nve4_graph_init_sm_0 },
+       { nvd7_graph_init_pes_0 },
+       { nvd7_graph_init_wwdx_0 },
+       { nvd7_graph_init_cbm_0 },
+       { nve4_graph_init_be_0 },
+       { nvc0_graph_init_fe_1 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nve4_graph_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nvc0_graph_priv *priv = (void *)object;
+
+       /*XXX: this is a nasty hack to power on gr on certain boards
+        *     where it's disabled by therm, somehow.  ideally it'd
+        *     be nice to know when we should be doing this, and why,
+        *     but, it's yet to be determined.  for now we test for
+        *     the particular mmio error that occurs in the situation,
+        *     and then bash therm in the way nvidia do.
+        */
+       nv_mask(priv, 0x000200, 0x08001000, 0x08001000);
+       nv_rd32(priv, 0x000200);
+       if (nv_rd32(priv, 0x400700) == 0xbadf1000) {
+               nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
+               nv_rd32(priv, 0x000200);
+               nv_mask(priv, 0x020004, 0xc0000000, 0x40000000);
+       }
+
+       return nouveau_graph_fini(&priv->base, suspend);
+}
+
 int
 nve4_graph_init(struct nouveau_object *object)
 {
@@ -210,8 +236,7 @@ nve4_graph_init(struct nouveau_object *object)
        nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
        nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
 
-       for (i = 0; oclass->mmio[i]; i++)
-               nvc0_graph_mmio(priv, oclass->mmio[i]);
+       nvc0_graph_mmio(priv, oclass->mmio);
 
        nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
 
@@ -298,25 +323,6 @@ nve4_graph_init(struct nouveau_object *object)
        return nvc0_graph_init_ctxctl(priv);
 }
 
-static struct nvc0_graph_init *
-nve4_graph_init_mmio[] = {
-       nve4_graph_init_regs,
-       nvc0_graph_init_unk40xx,
-       nvc0_graph_init_unk44xx,
-       nvc0_graph_init_unk78xx,
-       nvc0_graph_init_unk60xx,
-       nvd9_graph_init_unk64xx,
-       nve4_graph_init_unk58xx,
-       nvc0_graph_init_unk80xx,
-       nve4_graph_init_unk70xx,
-       nve4_graph_init_unk5bxx,
-       nve4_graph_init_gpc,
-       nve4_graph_init_tpc,
-       nve4_graph_init_unk,
-       nve4_graph_init_unk88xx,
-       NULL
-};
-
 #include "fuc/hubnve0.fuc.h"
 
 static struct nvc0_graph_ucode
@@ -344,11 +350,11 @@ nve4_graph_oclass = &(struct nvc0_graph_oclass) {
                .ctor = nvc0_graph_ctor,
                .dtor = nvc0_graph_dtor,
                .init = nve4_graph_init,
-               .fini = _nouveau_graph_fini,
+               .fini = nve4_graph_fini,
        },
        .cclass = &nve4_grctx_oclass,
        .sclass = nve4_graph_sclass,
-       .mmio = nve4_graph_init_mmio,
+       .mmio = nve4_graph_pack_mmio,
        .fecs.ucode = &nve4_graph_fecs_ucode,
        .gpccs.ucode = &nve4_graph_gpccs_ucode,
 }.base;
index b1acb99..c967621 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include "nvc0.h"
+#include "ctxnvc0.h"
 
 /*******************************************************************************
  * Graphics object classes
@@ -38,86 +39,57 @@ nvf0_graph_sclass[] = {
 };
 
 /*******************************************************************************
- * PGRAPH engine/subdev functions
+ * PGRAPH register lists
  ******************************************************************************/
 
-struct nvc0_graph_init
-nvf0_graph_init_unk40xx[] = {
+const struct nvc0_graph_init
+nvf0_graph_init_fe_0[] = {
        { 0x40415c,   1, 0x04, 0x00000000 },
        { 0x404170,   1, 0x04, 0x00000000 },
        { 0x4041b4,   1, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nvf0_graph_init_unk58xx[] = {
+static const struct nvc0_graph_init
+nvf0_graph_init_ds_0[] = {
        { 0x405844,   1, 0x04, 0x00ffffff },
        { 0x405850,   1, 0x04, 0x00000000 },
        { 0x405900,   1, 0x04, 0x0000ff00 },
        { 0x405908,   1, 0x04, 0x00000000 },
-       { 0x405928,   1, 0x04, 0x00000000 },
-       { 0x40592c,   1, 0x04, 0x00000000 },
+       { 0x405928,   2, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvf0_graph_init_unk70xx[] = {
+const struct nvc0_graph_init
+nvf0_graph_init_sked_0[] = {
        { 0x407010,   1, 0x04, 0x00000000 },
        { 0x407040,   1, 0x04, 0x80440424 },
        { 0x407048,   1, 0x04, 0x0000000a },
        {}
 };
 
-struct nvc0_graph_init
-nvf0_graph_init_unk5bxx[] = {
+const struct nvc0_graph_init
+nvf0_graph_init_cwd_0[] = {
        { 0x405b44,   1, 0x04, 0x00000000 },
        { 0x405b50,   1, 0x04, 0x00000000 },
        {}
 };
 
-static struct nvc0_graph_init
-nvf0_graph_init_gpc[] = {
-       { 0x418408,   1, 0x04, 0x00000000 },
-       { 0x4184a0,   1, 0x04, 0x00000000 },
-       { 0x4184a4,   2, 0x04, 0x00000000 },
-       { 0x418604,   1, 0x04, 0x00000000 },
-       { 0x418680,   1, 0x04, 0x00000000 },
-       { 0x418714,   1, 0x04, 0x00000000 },
-       { 0x418384,   1, 0x04, 0x00000000 },
-       { 0x418814,   3, 0x04, 0x00000000 },
-       { 0x418b04,   1, 0x04, 0x00000000 },
-       { 0x4188c8,   2, 0x04, 0x00000000 },
-       { 0x4188d0,   1, 0x04, 0x00010000 },
-       { 0x4188d4,   1, 0x04, 0x00000001 },
-       { 0x418910,   1, 0x04, 0x00010001 },
-       { 0x418914,   1, 0x04, 0x00000301 },
-       { 0x418918,   1, 0x04, 0x00800000 },
-       { 0x418980,   1, 0x04, 0x77777770 },
-       { 0x418984,   3, 0x04, 0x77777777 },
-       { 0x418c04,   1, 0x04, 0x00000000 },
-       { 0x418c64,   1, 0x04, 0x00000000 },
-       { 0x418c68,   1, 0x04, 0x00000000 },
-       { 0x418c88,   1, 0x04, 0x00000000 },
-       { 0x418cb4,   2, 0x04, 0x00000000 },
+const struct nvc0_graph_init
+nvf0_graph_init_gpc_unk_1[] = {
        { 0x418d00,   1, 0x04, 0x00000000 },
-       { 0x418d28,   1, 0x04, 0x00000000 },
-       { 0x418d2c,   1, 0x04, 0x00000000 },
+       { 0x418d28,   2, 0x04, 0x00000000 },
        { 0x418f00,   1, 0x04, 0x00000400 },
        { 0x418f08,   1, 0x04, 0x00000000 },
-       { 0x418f20,   1, 0x04, 0x00000000 },
-       { 0x418f24,   1, 0x04, 0x00000000 },
+       { 0x418f20,   2, 0x04, 0x00000000 },
        { 0x418e00,   1, 0x04, 0x00000000 },
        { 0x418e08,   1, 0x04, 0x00000000 },
        { 0x418e1c,   2, 0x04, 0x00000000 },
-       { 0x41900c,   1, 0x04, 0x00000000 },
-       { 0x419018,   1, 0x04, 0x00000000 },
        {}
 };
 
-struct nvc0_graph_init
-nvf0_graph_init_tpc[] = {
-       { 0x419d0c,   1, 0x04, 0x00000000 },
-       { 0x419d10,   1, 0x04, 0x00000014 },
+static const struct nvc0_graph_init
+nvf0_graph_init_tex_0[] = {
        { 0x419ab0,   1, 0x04, 0x00000000 },
        { 0x419ac8,   1, 0x04, 0x00000000 },
        { 0x419ab8,   1, 0x04, 0x000000e7 },
@@ -125,10 +97,11 @@ nvf0_graph_init_tpc[] = {
        { 0x419abc,   2, 0x04, 0x00000000 },
        { 0x419ab4,   1, 0x04, 0x00000000 },
        { 0x419aa8,   2, 0x04, 0x00000000 },
-       { 0x41980c,   1, 0x04, 0x00000010 },
-       { 0x419844,   1, 0x04, 0x00000000 },
-       { 0x419850,   1, 0x04, 0x00000004 },
-       { 0x419854,   2, 0x04, 0x00000000 },
+       {}
+};
+
+static const struct nvc0_graph_init
+nvf0_graph_init_l1c_0[] = {
        { 0x419c98,   1, 0x04, 0x00000000 },
        { 0x419ca8,   1, 0x04, 0x00000000 },
        { 0x419cb0,   1, 0x04, 0x01000000 },
@@ -139,7 +112,11 @@ nvf0_graph_init_tpc[] = {
        { 0x419cc0,   2, 0x04, 0x00000000 },
        { 0x419c80,   1, 0x04, 0x00020230 },
        { 0x419ccc,   2, 0x04, 0x00000000 },
-       { 0x419c0c,   1, 0x04, 0x00000000 },
+       {}
+};
+
+const struct nvc0_graph_init
+nvf0_graph_init_sm_0[] = {
        { 0x419e00,   1, 0x04, 0x00000080 },
        { 0x419ea0,   1, 0x04, 0x00000000 },
        { 0x419ee4,   1, 0x04, 0x00000000 },
@@ -155,6 +132,44 @@ nvf0_graph_init_tpc[] = {
        {}
 };
 
+static const struct nvc0_graph_pack
+nvf0_graph_pack_mmio[] = {
+       { nve4_graph_init_main_0 },
+       { nvf0_graph_init_fe_0 },
+       { nvc0_graph_init_pri_0 },
+       { nvc0_graph_init_rstr2d_0 },
+       { nvd9_graph_init_pd_0 },
+       { nvf0_graph_init_ds_0 },
+       { nvc0_graph_init_scc_0 },
+       { nvf0_graph_init_sked_0 },
+       { nvf0_graph_init_cwd_0 },
+       { nvd9_graph_init_prop_0 },
+       { nvc1_graph_init_gpc_unk_0 },
+       { nvc0_graph_init_setup_0 },
+       { nvc0_graph_init_crstr_0 },
+       { nvc1_graph_init_setup_1 },
+       { nvc0_graph_init_zcull_0 },
+       { nvd9_graph_init_gpm_0 },
+       { nvf0_graph_init_gpc_unk_1 },
+       { nvc0_graph_init_gcc_0 },
+       { nve4_graph_init_tpccs_0 },
+       { nvf0_graph_init_tex_0 },
+       { nve4_graph_init_pe_0 },
+       { nvf0_graph_init_l1c_0 },
+       { nvc0_graph_init_mpc_0 },
+       { nvf0_graph_init_sm_0 },
+       { nvd7_graph_init_pes_0 },
+       { nvd7_graph_init_wwdx_0 },
+       { nvd7_graph_init_cbm_0 },
+       { nve4_graph_init_be_0 },
+       { nvc0_graph_init_fe_1 },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
 static int
 nvf0_graph_fini(struct nouveau_object *object, bool suspend)
 {
@@ -192,25 +207,6 @@ nvf0_graph_fini(struct nouveau_object *object, bool suspend)
        return nouveau_graph_fini(&priv->base, suspend);
 }
 
-static struct nvc0_graph_init *
-nvf0_graph_init_mmio[] = {
-       nve4_graph_init_regs,
-       nvf0_graph_init_unk40xx,
-       nvc0_graph_init_unk44xx,
-       nvc0_graph_init_unk78xx,
-       nvc0_graph_init_unk60xx,
-       nvd9_graph_init_unk64xx,
-       nvf0_graph_init_unk58xx,
-       nvc0_graph_init_unk80xx,
-       nvf0_graph_init_unk70xx,
-       nvf0_graph_init_unk5bxx,
-       nvf0_graph_init_gpc,
-       nvf0_graph_init_tpc,
-       nve4_graph_init_unk,
-       nve4_graph_init_unk88xx,
-       NULL
-};
-
 #include "fuc/hubnvf0.fuc.h"
 
 static struct nvc0_graph_ucode
@@ -242,7 +238,7 @@ nvf0_graph_oclass = &(struct nvc0_graph_oclass) {
        },
        .cclass = &nvf0_grctx_oclass,
        .sclass =  nvf0_graph_sclass,
-       .mmio = nvf0_graph_init_mmio,
+       .mmio = nvf0_graph_pack_mmio,
        .fecs.ucode = &nvf0_graph_fecs_ucode,
        .gpccs.ucode = &nvf0_graph_gpccs_ucode,
 }.base;
index 5f6ede7..9238475 100644 (file)
@@ -112,7 +112,7 @@ _nouveau_xtensa_init(struct nouveau_object *object)
                snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
                         xtensa->addr >> 12);
 
-               ret = request_firmware(&fw, name, &device->pdev->dev);
+               ret = request_firmware(&fw, name, nv_device_base(device));
                if (ret) {
                        nv_warn(xtensa, "unable to load firmware %s\n", name);
                        return ret;
index e71a432..9c0cd73 100644 (file)
@@ -258,6 +258,7 @@ struct nv04_display_scanoutpos {
  * 9070: NVD0_DISP
  * 9170: NVE0_DISP
  * 9270: NVF0_DISP
+ * 9470: GM107_DISP
  */
 
 #define NV50_DISP_CLASS                                              0x00005070
@@ -268,6 +269,7 @@ struct nv04_display_scanoutpos {
 #define NVD0_DISP_CLASS                                              0x00009070
 #define NVE0_DISP_CLASS                                              0x00009170
 #define NVF0_DISP_CLASS                                              0x00009270
+#define GM107_DISP_CLASS                                             0x00009470
 
 #define NV50_DISP_MTHD                                               0x00000000
 #define NV50_DISP_MTHD_HEAD                                          0x00000003
@@ -342,6 +344,7 @@ struct nv50_display_class {
  * 907a: NVD0_DISP_CURS
  * 917a: NVE0_DISP_CURS
  * 927a: NVF0_DISP_CURS
+ * 947a: GM107_DISP_CURS
  */
 
 #define NV50_DISP_CURS_CLASS                                         0x0000507a
@@ -352,6 +355,7 @@ struct nv50_display_class {
 #define NVD0_DISP_CURS_CLASS                                         0x0000907a
 #define NVE0_DISP_CURS_CLASS                                         0x0000917a
 #define NVF0_DISP_CURS_CLASS                                         0x0000927a
+#define GM107_DISP_CURS_CLASS                                        0x0000947a
 
 struct nv50_display_curs_class {
        u32 head;
@@ -365,6 +369,7 @@ struct nv50_display_curs_class {
  * 907b: NVD0_DISP_OIMM
  * 917b: NVE0_DISP_OIMM
  * 927b: NVE0_DISP_OIMM
+ * 947b: GM107_DISP_OIMM
  */
 
 #define NV50_DISP_OIMM_CLASS                                         0x0000507b
@@ -375,6 +380,7 @@ struct nv50_display_curs_class {
 #define NVD0_DISP_OIMM_CLASS                                         0x0000907b
 #define NVE0_DISP_OIMM_CLASS                                         0x0000917b
 #define NVF0_DISP_OIMM_CLASS                                         0x0000927b
+#define GM107_DISP_OIMM_CLASS                                        0x0000947b
 
 struct nv50_display_oimm_class {
        u32 head;
@@ -388,6 +394,7 @@ struct nv50_display_oimm_class {
  * 907c: NVD0_DISP_SYNC
  * 917c: NVE0_DISP_SYNC
  * 927c: NVF0_DISP_SYNC
+ * 947c: GM107_DISP_SYNC
  */
 
 #define NV50_DISP_SYNC_CLASS                                         0x0000507c
@@ -398,6 +405,7 @@ struct nv50_display_oimm_class {
 #define NVD0_DISP_SYNC_CLASS                                         0x0000907c
 #define NVE0_DISP_SYNC_CLASS                                         0x0000917c
 #define NVF0_DISP_SYNC_CLASS                                         0x0000927c
+#define GM107_DISP_SYNC_CLASS                                        0x0000947c
 
 struct nv50_display_sync_class {
        u32 pushbuf;
@@ -412,6 +420,7 @@ struct nv50_display_sync_class {
  * 907d: NVD0_DISP_MAST
  * 917d: NVE0_DISP_MAST
  * 927d: NVF0_DISP_MAST
+ * 947d: GM107_DISP_MAST
  */
 
 #define NV50_DISP_MAST_CLASS                                         0x0000507d
@@ -422,6 +431,7 @@ struct nv50_display_sync_class {
 #define NVD0_DISP_MAST_CLASS                                         0x0000907d
 #define NVE0_DISP_MAST_CLASS                                         0x0000917d
 #define NVF0_DISP_MAST_CLASS                                         0x0000927d
+#define GM107_DISP_MAST_CLASS                                        0x0000947d
 
 struct nv50_display_mast_class {
        u32 pushbuf;
@@ -435,6 +445,7 @@ struct nv50_display_mast_class {
  * 907e: NVD0_DISP_OVLY
  * 917e: NVE0_DISP_OVLY
  * 927e: NVF0_DISP_OVLY
+ * 947e: GM107_DISP_OVLY
  */
 
 #define NV50_DISP_OVLY_CLASS                                         0x0000507e
@@ -445,6 +456,7 @@ struct nv50_display_mast_class {
 #define NVD0_DISP_OVLY_CLASS                                         0x0000907e
 #define NVE0_DISP_OVLY_CLASS                                         0x0000917e
 #define NVF0_DISP_OVLY_CLASS                                         0x0000927e
+#define GM107_DISP_OVLY_CLASS                                        0x0000947e
 
 struct nv50_display_ovly_class {
        u32 pushbuf;
index 7b8ea22..a8a9a9c 100644 (file)
@@ -40,6 +40,7 @@ enum nv_subdev_type {
 
        NVDEV_ENGINE_FIRST,
        NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST,
+       NVDEV_ENGINE_IFB,
        NVDEV_ENGINE_FIFO,
        NVDEV_ENGINE_SW,
        NVDEV_ENGINE_GR,
@@ -65,6 +66,7 @@ struct nouveau_device {
        struct list_head head;
 
        struct pci_dev *pdev;
+       struct platform_device *platformdev;
        u64 handle;
 
        const char *cfgopt;
@@ -84,6 +86,7 @@ struct nouveau_device {
                NV_C0    = 0xc0,
                NV_D0    = 0xd0,
                NV_E0    = 0xe0,
+               GM100    = 0x110,
        } card_type;
        u32 chipset;
        u32 crystal;
@@ -140,4 +143,32 @@ nv_device_match(struct nouveau_object *object, u16 dev, u16 ven, u16 sub)
               device->pdev->subsystem_device == sub;
 }
 
+static inline bool
+nv_device_is_pci(struct nouveau_device *device)
+{
+       return device->pdev != NULL;
+}
+
+static inline struct device *
+nv_device_base(struct nouveau_device *device)
+{
+       return nv_device_is_pci(device) ? &device->pdev->dev :
+                                         &device->platformdev->dev;
+}
+
+resource_size_t
+nv_device_resource_start(struct nouveau_device *device, unsigned int bar);
+
+resource_size_t
+nv_device_resource_len(struct nouveau_device *device, unsigned int bar);
+
+dma_addr_t
+nv_device_map_page(struct nouveau_device *device, struct page *page);
+
+void
+nv_device_unmap_page(struct nouveau_device *device, dma_addr_t addr);
+
+int
+nv_device_get_irq(struct nouveau_device *device, bool stall);
+
 #endif
index 8897e08..f5b5fd8 100644 (file)
@@ -33,7 +33,7 @@ nv_namedb(void *obj)
 
 int  nouveau_namedb_create_(struct nouveau_object *, struct nouveau_object *,
                            struct nouveau_oclass *, u32 pclass,
-                           struct nouveau_oclass *, u32 engcls,
+                           struct nouveau_oclass *, u64 engcls,
                            int size, void **);
 
 int  _nouveau_namedb_ctor(struct nouveau_object *, struct nouveau_object *,
index b3dd2c4..672d3c8 100644 (file)
@@ -3,11 +3,20 @@
 
 #include <core/device.h>
 
-#define nouveau_device_create(p,n,s,c,d,u)                                     \
-       nouveau_device_create_((p), (n), (s), (c), (d), sizeof(**u), (void **)u)
+struct platform_device;
 
-int  nouveau_device_create_(struct pci_dev *, u64 name, const char *sname,
-                           const char *cfg, const char *dbg, int, void **);
+enum nv_bus_type {
+       NOUVEAU_BUS_PCI,
+       NOUVEAU_BUS_PLATFORM,
+};
+
+#define nouveau_device_create(p,t,n,s,c,d,u)                                   \
+       nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d),           \
+                              sizeof(**u), (void **)u)
+
+int  nouveau_device_create_(void *, enum nv_bus_type type, u64 name,
+                           const char *sname, const char *cfg, const char *dbg,
+                           int, void **);
 
 int nv04_identify(struct nouveau_device *);
 int nv10_identify(struct nouveau_device *);
@@ -17,6 +26,7 @@ int nv40_identify(struct nouveau_device *);
 int nv50_identify(struct nouveau_device *);
 int nvc0_identify(struct nouveau_device *);
 int nve0_identify(struct nouveau_device *);
+int gm100_identify(struct nouveau_device *);
 
 struct nouveau_device *nouveau_device_find(u64 name);
 
index 4b21fab..fd0c688 100644 (file)
@@ -36,14 +36,15 @@ void _nouveau_disp_dtor(struct nouveau_object *);
 #define _nouveau_disp_init _nouveau_engine_init
 #define _nouveau_disp_fini _nouveau_engine_fini
 
-extern struct nouveau_oclass nv04_disp_oclass;
-extern struct nouveau_oclass nv50_disp_oclass;
-extern struct nouveau_oclass nv84_disp_oclass;
-extern struct nouveau_oclass nva0_disp_oclass;
-extern struct nouveau_oclass nv94_disp_oclass;
-extern struct nouveau_oclass nva3_disp_oclass;
-extern struct nouveau_oclass nvd0_disp_oclass;
-extern struct nouveau_oclass nve0_disp_oclass;
-extern struct nouveau_oclass nvf0_disp_oclass;
+extern struct nouveau_oclass *nv04_disp_oclass;
+extern struct nouveau_oclass *nv50_disp_oclass;
+extern struct nouveau_oclass *nv84_disp_oclass;
+extern struct nouveau_oclass *nva0_disp_oclass;
+extern struct nouveau_oclass *nv94_disp_oclass;
+extern struct nouveau_oclass *nva3_disp_oclass;
+extern struct nouveau_oclass *nvd0_disp_oclass;
+extern struct nouveau_oclass *nve0_disp_oclass;
+extern struct nouveau_oclass *nvf0_disp_oclass;
+extern struct nouveau_oclass *gm107_disp_oclass;
 
 #endif
index 9770561..871edfd 100644 (file)
@@ -63,13 +63,14 @@ extern struct nouveau_oclass nv40_graph_oclass;
 extern struct nouveau_oclass nv50_graph_oclass;
 extern struct nouveau_oclass *nvc0_graph_oclass;
 extern struct nouveau_oclass *nvc1_graph_oclass;
-extern struct nouveau_oclass *nvc3_graph_oclass;
+extern struct nouveau_oclass *nvc4_graph_oclass;
 extern struct nouveau_oclass *nvc8_graph_oclass;
 extern struct nouveau_oclass *nvd7_graph_oclass;
 extern struct nouveau_oclass *nvd9_graph_oclass;
 extern struct nouveau_oclass *nve4_graph_oclass;
 extern struct nouveau_oclass *nvf0_graph_oclass;
 extern struct nouveau_oclass *nv108_graph_oclass;
+extern struct nouveau_oclass *gm107_graph_oclass;
 
 extern const struct nouveau_bitfield nv04_graph_nsource[];
 extern struct nouveau_ofuncs nv04_graph_ofuncs;
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h
new file mode 100644 (file)
index 0000000..bba01ab
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __NVBIOS_P0260_H__
+#define __NVBIOS_P0260_H__
+
+u32 nvbios_P0260Te(struct nouveau_bios *,
+                  u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
+
+struct nvbios_P0260E {
+       u32 data;
+};
+
+u32 nvbios_P0260Ee(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_P0260Ep(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
+                  struct nvbios_P0260E *);
+
+struct nvbios_P0260X {
+       u32 data;
+};
+
+u32 nvbios_P0260Xe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_P0260Xp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
+                  struct nvbios_P0260X *);
+
+#endif
index c127054..a32feb3 100644 (file)
@@ -16,6 +16,7 @@ enum dcb_connector_type {
        DCB_CONNECTOR_eDP = 0x47,
        DCB_CONNECTOR_HDMI_0 = 0x60,
        DCB_CONNECTOR_HDMI_1 = 0x61,
+       DCB_CONNECTOR_HDMI_C = 0x63,
        DCB_CONNECTOR_DMS59_DP0 = 0x64,
        DCB_CONNECTOR_DMS59_DP1 = 0x65,
        DCB_CONNECTOR_NONE = 0xff
index c5e6d1e..c086ac6 100644 (file)
@@ -61,6 +61,6 @@ struct nvbios_ramcfg {
 };
 
 u8 nvbios_ramcfg_count(struct nouveau_bios *);
-u8 nvbios_ramcfg_index(struct nouveau_bios *);
+u8 nvbios_ramcfg_index(struct nouveau_subdev *);
 
 #endif
index 083541d..8dc5051 100644 (file)
@@ -31,6 +31,12 @@ struct nouveau_therm_trip_point {
        int hysteresis;
 };
 
+enum nvbios_therm_fan_mode {
+       NVBIOS_THERM_FAN_TRIP = 0,
+       NVBIOS_THERM_FAN_LINEAR = 1,
+       NVBIOS_THERM_FAN_OTHER = 2,
+};
+
 struct nvbios_therm_fan {
        u16 pwm_freq;
 
@@ -40,6 +46,7 @@ struct nvbios_therm_fan {
        u16 bump_period;
        u16 slow_down_period;
 
+       enum nvbios_therm_fan_mode fan_mode;
        struct nouveau_therm_trip_point trip[NOUVEAU_TEMP_FAN_TRIP_MAX];
        u8 nr_fan_trip;
        u8 linear_min_temp;
index ed1ac68..e292271 100644 (file)
@@ -9,6 +9,7 @@ struct nouveau_devinit {
        bool post;
        void (*meminit)(struct nouveau_devinit *);
        int  (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
+       u32  (*mmio)(struct nouveau_devinit *, u32 addr);
 };
 
 static inline struct nouveau_devinit *
@@ -28,5 +29,6 @@ extern struct nouveau_oclass *nv98_devinit_oclass;
 extern struct nouveau_oclass *nva3_devinit_oclass;
 extern struct nouveau_oclass *nvaf_devinit_oclass;
 extern struct nouveau_oclass *nvc0_devinit_oclass;
+extern struct nouveau_oclass *gm107_devinit_oclass;
 
 #endif
index d7ecafb..58c7ccd 100644 (file)
@@ -105,6 +105,7 @@ extern struct nouveau_oclass *nvaa_fb_oclass;
 extern struct nouveau_oclass *nvaf_fb_oclass;
 extern struct nouveau_oclass *nvc0_fb_oclass;
 extern struct nouveau_oclass *nve0_fb_oclass;
+extern struct nouveau_oclass *gm107_fb_oclass;
 
 #include <subdev/bios/ramcfg.h>
 
index a1985ed..c9c1950 100644 (file)
@@ -35,6 +35,7 @@ nouveau_ltcg(void *obj)
 #define _nouveau_ltcg_init _nouveau_subdev_init
 #define _nouveau_ltcg_fini _nouveau_subdev_fini
 
-extern struct nouveau_oclass nvc0_ltcg_oclass;
+extern struct nouveau_oclass *gf100_ltcg_oclass;
+extern struct nouveau_oclass *gm107_ltcg_oclass;
 
 #endif
index 3c6738e..72b1768 100644 (file)
@@ -12,6 +12,7 @@ struct nouveau_mc_intr {
 struct nouveau_mc {
        struct nouveau_subdev base;
        bool use_msi;
+       unsigned int irq;
 };
 
 static inline struct nouveau_mc *
index 69891d4..d4a6817 100644 (file)
@@ -31,7 +31,7 @@ struct nouveau_therm {
        int (*pwm_ctrl)(struct nouveau_therm *, int line, bool);
        int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *);
        int (*pwm_set)(struct nouveau_therm *, int line, u32, u32);
-       int (*pwm_clock)(struct nouveau_therm *);
+       int (*pwm_clock)(struct nouveau_therm *, int line);
 
        int (*fan_get)(struct nouveau_therm *);
        int (*fan_set)(struct nouveau_therm *, int);
index 9ab70df..db9be80 100644 (file)
@@ -59,5 +59,6 @@ int nouveau_timer_create_(struct nouveau_object *, struct nouveau_engine *,
                          struct nouveau_oclass *, int size, void **);
 
 extern struct nouveau_oclass nv04_timer_oclass;
+extern struct nouveau_oclass gk20a_timer_oclass;
 
 #endif
index 191e739..d0ced94 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/pci.h>
+#include <linux/platform_device.h>
 #include <linux/printk.h>
 #include <linux/bitops.h>
 #include <linux/firmware.h>
 
 #include <asm/unaligned.h>
 
-static inline int
-ffsll(u64 mask)
-{
-       int i;
-       for (i = 0; i < 64; i++) {
-               if (mask & (1ULL << i))
-                       return i + 1;
-       }
-       return 0;
-}
-
 #ifndef ioread32_native
 #ifdef __BIG_ENDIAN
 #define ioread16_native ioread16be
index 7098ddd..bdf5941 100644 (file)
@@ -118,8 +118,8 @@ nouveau_bar_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       bar->iomem = ioremap(pci_resource_start(device->pdev, 3),
-                            pci_resource_len(device->pdev, 3));
+       bar->iomem = ioremap(nv_device_resource_start(device, 3),
+                            nv_device_resource_len(device, 3));
        return 0;
 }
 
index 090d594..f748ba4 100644 (file)
@@ -139,7 +139,7 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        /* BAR3 */
        start = 0x0100000000ULL;
-       limit = start + pci_resource_len(device->pdev, 3);
+       limit = start + nv_device_resource_len(device, 3);
 
        ret = nouveau_vm_new(device, start, limit, start, &vm);
        if (ret)
@@ -173,7 +173,7 @@ nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        /* BAR1 */
        start = 0x0000000000ULL;
-       limit = start + pci_resource_len(device->pdev, 1);
+       limit = start + nv_device_resource_len(device, 1);
 
        ret = nouveau_vm_new(device, start, limit--, start, &vm);
        if (ret)
@@ -231,7 +231,7 @@ static int
 nv50_bar_init(struct nouveau_object *object)
 {
        struct nv50_bar_priv *priv = (void *)object;
-       int ret;
+       int ret, i;
 
        ret = nouveau_bar_init(&priv->base);
        if (ret)
@@ -249,6 +249,8 @@ nv50_bar_init(struct nouveau_object *object)
        nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12);
        nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4);
        nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4);
+       for (i = 0; i < 8; i++)
+               nv_wr32(priv, 0x001900 + (i * 4), 0x00000000);
        return 0;
 }
 
index bac5e75..3f30db6 100644 (file)
@@ -84,7 +84,6 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
              struct nouveau_object **pobject)
 {
        struct nouveau_device *device = nv_device(parent);
-       struct pci_dev *pdev = device->pdev;
        struct nvc0_bar_priv *priv;
        struct nouveau_gpuobj *mem;
        struct nouveau_vm *vm;
@@ -107,14 +106,14 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 3), 0, &vm);
+       ret = nouveau_vm_new(device, 0, nv_device_resource_len(device, 3), 0, &vm);
        if (ret)
                return ret;
 
        atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
 
        ret = nouveau_gpuobj_new(nv_object(priv), NULL,
-                                (pci_resource_len(pdev, 3) >> 12) * 8,
+                                (nv_device_resource_len(device, 3) >> 12) * 8,
                                 0x1000, NVOBJ_FLAG_ZERO_ALLOC,
                                 &vm->pgt[0].obj[0]);
        vm->pgt[0].refcount[0] = 1;
@@ -128,8 +127,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[0].pgd->addr));
        nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[0].pgd->addr));
-       nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 3) - 1));
-       nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 3) - 1));
+       nv_wo32(mem, 0x0208, lower_32_bits(nv_device_resource_len(device, 3) - 1));
+       nv_wo32(mem, 0x020c, upper_32_bits(nv_device_resource_len(device, 3) - 1));
 
        /* BAR1 */
        ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0,
@@ -143,7 +142,7 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       ret = nouveau_vm_new(device, 0, pci_resource_len(pdev, 1), 0, &vm);
+       ret = nouveau_vm_new(device, 0, nv_device_resource_len(device, 1), 0, &vm);
        if (ret)
                return ret;
 
@@ -156,8 +155,8 @@ nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        nv_wo32(mem, 0x0200, lower_32_bits(priv->bar[1].pgd->addr));
        nv_wo32(mem, 0x0204, upper_32_bits(priv->bar[1].pgd->addr));
-       nv_wo32(mem, 0x0208, lower_32_bits(pci_resource_len(pdev, 1) - 1));
-       nv_wo32(mem, 0x020c, upper_32_bits(pci_resource_len(pdev, 1) - 1));
+       nv_wo32(mem, 0x0208, lower_32_bits(nv_device_resource_len(device, 1) - 1));
+       nv_wo32(mem, 0x020c, upper_32_bits(nv_device_resource_len(device, 1) - 1));
 
        priv->base.alloc = nouveau_bar_alloc;
        priv->base.kmap = nvc0_bar_kmap;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c b/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c
new file mode 100644 (file)
index 0000000..199f4e5
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/ramcfg.h>
+#include <subdev/bios/P0260.h>
+
+u32
+nvbios_P0260Te(struct nouveau_bios *bios,
+              u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
+{
+       struct bit_entry bit_P;
+       u32 data = 0x00000000;
+
+       if (!bit_entry(bios, 'P', &bit_P)) {
+               if (bit_P.version == 2 && bit_P.length > 0x63)
+                       data = nv_ro32(bios, bit_P.offset + 0x60);
+               if (data) {
+                       *ver = nv_ro08(bios, data + 0);
+                       switch (*ver) {
+                       case 0x10:
+                               *hdr = nv_ro08(bios, data + 1);
+                               *cnt = nv_ro08(bios, data + 2);
+                               *len = 4;
+                               *xnr = nv_ro08(bios, data + 3);
+                               *xsz = 4;
+                               return data;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+       return 0x00000000;
+}
+
+u32
+nvbios_P0260Ee(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
+{
+       u8  hdr, cnt, xnr, xsz;
+       u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, len, &xnr, &xsz);
+       if (data && idx < cnt)
+               return data + hdr + (idx * *len);
+       return 0x00000000;
+}
+
+u32
+nvbios_P0260Ep(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
+              struct nvbios_P0260E *info)
+{
+       u32 data = nvbios_P0260Ee(bios, idx, ver, len);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       case 0x10:
+               info->data = nv_ro32(bios, data);
+               return data;
+       default:
+               break;
+       }
+       return 0x00000000;
+}
+
+u32
+nvbios_P0260Xe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *xsz)
+{
+       u8  hdr, cnt, len, xnr;
+       u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, &len, &xnr, xsz);
+       if (data && idx < xnr)
+               return data + hdr + (cnt * len) + (idx * *xsz);
+       return 0x00000000;
+}
+
+u32
+nvbios_P0260Xp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
+              struct nvbios_P0260X *info)
+{
+       u32 data = nvbios_P0260Xe(bios, idx, ver, hdr);
+       memset(info, 0x00, sizeof(*info));
+       switch (!!data * *ver) {
+       case 0x10:
+               info->data = nv_ro32(bios, data);
+               return data;
+       default:
+               break;
+       }
+       return 0x00000000;
+}
index ef0c9c4..e9df94f 100644 (file)
@@ -90,10 +90,26 @@ nouveau_bios_shadow_pramin(struct nouveau_bios *bios)
        int i;
 
        if (device->card_type >= NV_50) {
-               if (  device->card_type < NV_C0 ||
-                   !(nv_rd32(bios, 0x022500) & 0x00000001))
-                       addr = (u64)(nv_rd32(bios, 0x619f04) & 0xffffff00) << 8;
+               if (device->card_type >= NV_C0 && device->card_type < GM100) {
+                       if (nv_rd32(bios, 0x022500) & 0x00000001)
+                               return;
+               } else
+               if (device->card_type >= GM100) {
+                       if (nv_rd32(bios, 0x021c04) & 0x00000001)
+                               return;
+               }
+
+               addr = nv_rd32(bios, 0x619f04);
+               if (!(addr & 0x00000008)) {
+                       nv_debug(bios, "... not enabled\n");
+                       return;
+               }
+               if ( (addr & 0x00000003) != 1) {
+                       nv_debug(bios, "... not in vram\n");
+                       return;
+               }
 
+               addr = (u64)(addr >> 8) << 8;
                if (!addr) {
                        addr  = (u64)nv_rd32(bios, 0x001700) << 16;
                        addr += 0xf0000;
@@ -141,6 +157,10 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios)
                pcireg = 0x001850;
        access = nv_mask(bios, pcireg, 0x00000001, 0x00000000);
 
+       /* WARNING: PROM accesses should always be 32-bits aligned. Other
+        * accesses work on most chipset but do not on Kepler chipsets
+        */
+
        /* bail if no rom signature, with a workaround for a PROM reading
         * issue on some chipsets.  the first read after a period of
         * inactivity returns the wrong result, so retry the first header
@@ -148,31 +168,32 @@ nouveau_bios_shadow_prom(struct nouveau_bios *bios)
         */
        i = 16;
        do {
-               if (nv_rd08(bios, 0x300000) == 0x55)
+               if ((nv_rd32(bios, 0x300000) & 0xffff) == 0xaa55)
                        break;
        } while (i--);
 
-       if (!i || nv_rd08(bios, 0x300001) != 0xaa)
-               goto out;
-
-       /* additional check (see note below) - read PCI record header */
-       pcir = nv_rd08(bios, 0x300018) |
-              nv_rd08(bios, 0x300019) << 8;
-       if (nv_rd08(bios, 0x300000 + pcir) != 'P' ||
-           nv_rd08(bios, 0x300001 + pcir) != 'C' ||
-           nv_rd08(bios, 0x300002 + pcir) != 'I' ||
-           nv_rd08(bios, 0x300003 + pcir) != 'R')
+       if (!i)
                goto out;
 
        /* read entire bios image to system memory */
-       bios->size = nv_rd08(bios, 0x300002) * 512;
+       bios->size = ((nv_rd32(bios, 0x300000) >> 16) & 0xff) * 512;
        if (!bios->size)
                goto out;
 
        bios->data = kmalloc(bios->size, GFP_KERNEL);
        if (bios->data) {
-               for (i = 0; i < bios->size; i++)
-                       nv_wo08(bios, i, nv_rd08(bios, 0x300000 + i));
+               for (i = 0; i < bios->size; i+=4)
+                       nv_wo32(bios, i, nv_rd32(bios, 0x300000 + i));
+       }
+
+       /* check the PCI record header */
+       pcir = nv_ro16(bios, 0x0018);
+       if (bios->data[pcir + 0] != 'P' ||
+           bios->data[pcir + 1] != 'C' ||
+           bios->data[pcir + 2] != 'I' ||
+           bios->data[pcir + 3] != 'R') {
+               bios->size = 0;
+               kfree(bios->data);
        }
 
 out:
index 2d9b9d7..88606bf 100644 (file)
@@ -142,9 +142,36 @@ dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
                if (*ver >= 0x40) {
                        u32 conf = nv_ro32(bios, dcb + 0x04);
                        switch (outp->type) {
+                       case DCB_OUTPUT_DP:
+                               switch (conf & 0x00e00000) {
+                               case 0x00000000:
+                                       outp->dpconf.link_bw = 0x06;
+                                       break;
+                               case 0x00200000:
+                                       outp->dpconf.link_bw = 0x0a;
+                                       break;
+                               case 0x00400000:
+                               default:
+                                       outp->dpconf.link_bw = 0x14;
+                                       break;
+                               }
+
+                               switch (conf & 0x0f000000) {
+                               case 0x0f000000:
+                                       outp->dpconf.link_nr = 4;
+                                       break;
+                               case 0x03000000:
+                                       outp->dpconf.link_nr = 2;
+                                       break;
+                               case 0x01000000:
+                               default:
+                                       outp->dpconf.link_nr = 1;
+                                       break;
+                               }
+
+                               /* fall-through... */
                        case DCB_OUTPUT_TMDS:
                        case DCB_OUTPUT_LVDS:
-                       case DCB_OUTPUT_DP:
                                outp->link = (conf & 0x00000030) >> 4;
                                outp->sorconf.link = outp->link; /*XXX*/
                                outp->extdev = 0x00;
index de201ba..acaeaf7 100644 (file)
@@ -118,6 +118,8 @@ init_conn(struct nvbios_init *init)
 static inline u32
 init_nvreg(struct nvbios_init *init, u32 reg)
 {
+       struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
+
        /* C51 (at least) sometimes has the lower bits set which the VBIOS
         * interprets to mean that access needs to go through certain IO
         * ports instead.  The NVIDIA binary driver has been seen to access
@@ -147,6 +149,9 @@ init_nvreg(struct nvbios_init *init, u32 reg)
 
        if (reg & ~0x00fffffc)
                warn("unknown bits in register 0x%08x\n", reg);
+
+       if (devinit->mmio)
+               reg = devinit->mmio(devinit, reg);
        return reg;
 }
 
@@ -154,7 +159,7 @@ static u32
 init_rd32(struct nvbios_init *init, u32 reg)
 {
        reg = init_nvreg(init, reg);
-       if (init_exec(init))
+       if (reg != ~0 && init_exec(init))
                return nv_rd32(init->subdev, reg);
        return 0x00000000;
 }
@@ -163,7 +168,7 @@ static void
 init_wr32(struct nvbios_init *init, u32 reg, u32 val)
 {
        reg = init_nvreg(init, reg);
-       if (init_exec(init))
+       if (reg != ~0 && init_exec(init))
                nv_wr32(init->subdev, reg, val);
 }
 
@@ -171,7 +176,7 @@ static u32
 init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val)
 {
        reg = init_nvreg(init, reg);
-       if (init_exec(init)) {
+       if (reg != ~0 && init_exec(init)) {
                u32 tmp = nv_rd32(init->subdev, reg);
                nv_wr32(init->subdev, reg, (tmp & ~mask) | val);
                return tmp;
@@ -410,7 +415,7 @@ init_ram_restrict(struct nvbios_init *init)
         * in case *not* re-reading the strap causes similar breakage.
         */
        if (!init->ramcfg || init->bios->version.major < 0x70)
-               init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->bios);
+               init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev);
        return (init->ramcfg & 0x7fffffff);
 }
 
@@ -845,9 +850,8 @@ init_idx_addr_latched(struct nvbios_init *init)
        u32 data = nv_ro32(bios, init->offset + 13);
        u8 count = nv_ro08(bios, init->offset + 17);
 
-       trace("INDEX_ADDRESS_LATCHED\t"
-             "R[0x%06x] : R[0x%06x]\n\tCTRL &= 0x%08x |= 0x%08x\n",
-             creg, dreg, mask, data);
+       trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg);
+       trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data);
        init->offset += 18;
 
        while (count--) {
index 991aedd..6c401f7 100644 (file)
@@ -27,9 +27,9 @@
 #include <subdev/bios/ramcfg.h>
 
 static u8
-nvbios_ramcfg_strap(struct nouveau_bios *bios)
+nvbios_ramcfg_strap(struct nouveau_subdev *subdev)
 {
-       return (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
+       return (nv_rd32(subdev, 0x101000) & 0x0000003c) >> 2;
 }
 
 u8
@@ -48,9 +48,10 @@ nvbios_ramcfg_count(struct nouveau_bios *bios)
 }
 
 u8
-nvbios_ramcfg_index(struct nouveau_bios *bios)
+nvbios_ramcfg_index(struct nouveau_subdev *subdev)
 {
-       u8 strap = nvbios_ramcfg_strap(bios);
+       struct nouveau_bios *bios = nouveau_bios(subdev);
+       u8 strap = nvbios_ramcfg_strap(subdev);
        u32 xlat = 0x00000000;
        struct bit_entry bit_M;
 
index 22ac6db..d158540 100644 (file)
@@ -164,6 +164,7 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios,
 
        i = 0;
        fan->nr_fan_trip = 0;
+       fan->fan_mode = NVBIOS_THERM_FAN_OTHER;
        while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
                s16 value = nv_ro16(bios, entry + 1);
 
@@ -174,6 +175,8 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios,
                        break;
                case 0x24:
                        fan->nr_fan_trip++;
+                       if (fan->fan_mode > NVBIOS_THERM_FAN_TRIP)
+                               fan->fan_mode = NVBIOS_THERM_FAN_TRIP;
                        cur_trip = &fan->trip[fan->nr_fan_trip - 1];
                        cur_trip->hysteresis = value & 0xf;
                        cur_trip->temp = (value & 0xff0) >> 4;
@@ -194,11 +197,19 @@ nvbios_therm_fan_parse(struct nouveau_bios *bios,
                        fan->slow_down_period = value;
                        break;
                case 0x46:
+                       if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR)
+                               fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
                        fan->linear_min_temp = nv_ro08(bios, entry + 1);
                        fan->linear_max_temp = nv_ro08(bios, entry + 2);
                        break;
                }
        }
 
+       /* starting from fermi, fan management is always linear */
+       if (nv_device(bios)->card_type >= NV_C0 &&
+               fan->fan_mode == NVBIOS_THERM_FAN_OTHER) {
+               fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
+       }
+
        return 0;
 }
index 8fa34e8..239acfe 100644 (file)
@@ -96,5 +96,6 @@ nouveau_devinit_create_(struct nouveau_object *parent,
        devinit->post = nouveau_boolopt(device->cfgopt, "NvForcePost", false);
        devinit->meminit = impl->meminit;
        devinit->pll_set = impl->pll_set;
+       devinit->mmio    = impl->mmio;
        return 0;
 }
index 6b56a0f..4fe49cf 100644 (file)
@@ -24,6 +24,8 @@
  *
  */
 
+#include <core/device.h>
+
 #define NV04_PFB_BOOT_0                                                0x00100000
 #      define NV04_PFB_BOOT_0_RAM_AMOUNT                       0x00000003
 #      define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB                  0x00000000
 #      define NV10_PFB_REFCTRL_VALID_1                         (1 << 31)
 
 static inline struct io_mapping *
-fbmem_init(struct pci_dev *pdev)
+fbmem_init(struct nouveau_device *dev)
 {
-       return io_mapping_create_wc(pci_resource_start(pdev, 1),
-                                   pci_resource_len(pdev, 1));
+       return io_mapping_create_wc(nv_device_resource_start(dev, 1),
+                                   nv_device_resource_len(dev, 1));
 }
 
 static inline void
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c
new file mode 100644 (file)
index 0000000..c69bc7f
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv50.h"
+
+static u64
+gm107_devinit_disable(struct nouveau_devinit *devinit)
+{
+       struct nv50_devinit_priv *priv = (void *)devinit;
+       u32 r021c00 = nv_rd32(priv, 0x021c00);
+       u32 r021c04 = nv_rd32(priv, 0x021c04);
+       u64 disable = 0ULL;
+
+       if (r021c00 & 0x00000001)
+               disable |= (1ULL << NVDEV_ENGINE_COPY0);
+       if (r021c00 & 0x00000004)
+               disable |= (1ULL << NVDEV_ENGINE_COPY2);
+       if (r021c04 & 0x00000001)
+               disable |= (1ULL << NVDEV_ENGINE_DISP);
+
+       return disable;
+}
+
+struct nouveau_oclass *
+gm107_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x07),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_devinit_ctor,
+               .dtor = _nouveau_devinit_dtor,
+               .init = nv50_devinit_init,
+               .fini = _nouveau_devinit_fini,
+       },
+       .pll_set = nvc0_devinit_pll_set,
+       .disable = gm107_devinit_disable,
+}.base;
index 7037eae..052ad69 100644 (file)
@@ -38,7 +38,7 @@ nv04_devinit_meminit(struct nouveau_devinit *devinit)
        int i;
 
        /* Map the framebuffer aperture */
-       fb = fbmem_init(nv_device(priv)->pdev);
+       fb = fbmem_init(nv_device(priv));
        if (!fb) {
                nv_error(priv, "failed to map fb\n");
                return;
index 98b7e67..4a19c10 100644 (file)
@@ -53,7 +53,7 @@ nv05_devinit_meminit(struct nouveau_devinit *devinit)
        int i, v;
 
        /* Map the framebuffer aperture */
-       fb = fbmem_init(nv_device(priv)->pdev);
+       fb = fbmem_init(nv_device(priv));
        if (!fb) {
                nv_error(priv, "failed to map fb\n");
                return;
index 32b3d21..3b8d657 100644 (file)
@@ -46,7 +46,7 @@ nv10_devinit_meminit(struct nouveau_devinit *devinit)
                mem_width_count = 2;
 
        /* Map the framebuffer aperture */
-       fb = fbmem_init(nv_device(priv)->pdev);
+       fb = fbmem_init(nv_device(priv));
        if (!fb) {
                nv_error(priv, "failed to map fb\n");
                return;
index 4689ba3..04bc973 100644 (file)
@@ -37,7 +37,7 @@ nv20_devinit_meminit(struct nouveau_devinit *devinit)
        struct io_mapping *fb;
 
        /* Map the framebuffer aperture */
-       fb = fbmem_init(nv_device(priv)->pdev);
+       fb = fbmem_init(nv_device(priv));
        if (!fb) {
                nv_error(priv, "failed to map fb\n");
                return;
index 141c27e..51d5076 100644 (file)
@@ -5,6 +5,7 @@
 
 struct nv50_devinit_priv {
        struct nouveau_devinit base;
+       u32 r001540;
 };
 
 int  nv50_devinit_ctor(struct nouveau_object *, struct nouveau_object *,
@@ -15,4 +16,6 @@ int  nv50_devinit_pll_set(struct nouveau_devinit *, u32, u32);
 
 int  nva3_devinit_pll_set(struct nouveau_devinit *, u32, u32);
 
+int  nvc0_devinit_pll_set(struct nouveau_devinit *, u32, u32);
+
 #endif
index 6dedf1d..006cf34 100644 (file)
@@ -81,6 +81,55 @@ nva3_devinit_disable(struct nouveau_devinit *devinit)
        return disable;
 }
 
+static u32
+nva3_devinit_mmio_part[] = {
+       0x100720, 0x1008bc, 4,
+       0x100a20, 0x100adc, 4,
+       0x100d80, 0x100ddc, 4,
+       0x110000, 0x110f9c, 4,
+       0x111000, 0x11103c, 8,
+       0x111080, 0x1110fc, 4,
+       0x111120, 0x1111fc, 4,
+       0x111300, 0x1114bc, 4,
+       0,
+};
+
+static u32
+nva3_devinit_mmio(struct nouveau_devinit *devinit, u32 addr)
+{
+       struct nv50_devinit_priv *priv = (void *)devinit;
+       u32 *mmio = nva3_devinit_mmio_part;
+
+       /* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP
+        * instructions which touch registers that may not even exist on
+        * some configurations (Quadro 400), which causes the register
+        * interface to screw up for some amount of time after attempting to
+        * write to one of these, and results in all sorts of things going
+        * horribly wrong.
+        *
+        * the binary driver avoids touching these registers at all, however,
+        * the video bios doesn't care and does what the scripts say.  it's
+        * presumed that the io-port access to priv registers isn't effected
+        * by the screw-up bug mentioned above.
+        *
+        * really, a new opcode should've been invented to handle these
+        * requirements, but whatever, it's too late for that now.
+        */
+       while (mmio[0]) {
+               if (addr >= mmio[0] && addr <= mmio[1]) {
+                       u32 part = (addr / mmio[2]) & 7;
+                       if (!priv->r001540)
+                               priv->r001540 = nv_rd32(priv, 0x001540);
+                       if (part >= hweight8((priv->r001540 >> 16) & 0xff))
+                               return ~0;
+                       return addr;
+               }
+               mmio += 3;
+       }
+
+       return addr;
+}
+
 struct nouveau_oclass *
 nva3_devinit_oclass = &(struct nouveau_devinit_impl) {
        .base.handle = NV_SUBDEV(DEVINIT, 0xa3),
@@ -92,4 +141,5 @@ nva3_devinit_oclass = &(struct nouveau_devinit_impl) {
        },
        .pll_set = nva3_devinit_pll_set,
        .disable = nva3_devinit_disable,
+       .mmio    = nva3_devinit_mmio,
 }.base;
index fa7e637..30c7657 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "nv50.h"
 
-static int
+int
 nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
 {
        struct nv50_devinit_priv *priv = (void *)devinit;
index 822a2fb..f0e8683 100644 (file)
@@ -11,6 +11,7 @@ struct nouveau_devinit_impl {
        void (*meminit)(struct nouveau_devinit *);
        int  (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
        u64  (*disable)(struct nouveau_devinit *);
+       u32  (*mmio)(struct nouveau_devinit *, u32);
 };
 
 #define nouveau_devinit_create(p,e,o,d)                                        \
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c
new file mode 100644 (file)
index 0000000..c4840ae
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nvc0.h"
+
+struct nouveau_oclass *
+gm107_fb_oclass = &(struct nouveau_fb_impl) {
+       .base.handle = NV_SUBDEV(FB, 0x07),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_fb_ctor,
+               .dtor = nvc0_fb_dtor,
+               .init = nvc0_fb_init,
+               .fini = _nouveau_fb_fini,
+       },
+       .memtype = nvc0_fb_memtype_valid,
+       .ram = &gm107_ram_oclass,
+}.base;
index cbc7f00..1fc55c1 100644 (file)
@@ -250,10 +250,8 @@ nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
        if (priv->r100c08_page) {
-               priv->r100c08 = pci_map_page(device->pdev, priv->r100c08_page,
-                                            0, PAGE_SIZE,
-                                            PCI_DMA_BIDIRECTIONAL);
-               if (pci_dma_mapping_error(device->pdev, priv->r100c08))
+               priv->r100c08 = nv_device_map_page(device, priv->r100c08_page);
+               if (!priv->r100c08)
                        nv_warn(priv, "failed 0x100c08 page map\n");
        } else {
                nv_warn(priv, "failed 0x100c08 page alloc\n");
@@ -270,8 +268,7 @@ nv50_fb_dtor(struct nouveau_object *object)
        struct nv50_fb_priv *priv = (void *)object;
 
        if (priv->r100c08_page) {
-               pci_unmap_page(device->pdev, priv->r100c08, PAGE_SIZE,
-                              PCI_DMA_BIDIRECTIONAL);
+               nv_device_unmap_page(device, priv->r100c08);
                __free_page(priv->r100c08_page);
        }
 
index 45470e1..0670ae3 100644 (file)
@@ -70,8 +70,7 @@ nvc0_fb_dtor(struct nouveau_object *object)
        struct nvc0_fb_priv *priv = (void *)object;
 
        if (priv->r100c10_page) {
-               pci_unmap_page(device->pdev, priv->r100c10, PAGE_SIZE,
-                              PCI_DMA_BIDIRECTIONAL);
+               nv_device_unmap_page(device, priv->r100c10);
                __free_page(priv->r100c10_page);
        }
 
@@ -94,10 +93,8 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
        if (priv->r100c10_page) {
-               priv->r100c10 = pci_map_page(device->pdev, priv->r100c10_page,
-                                            0, PAGE_SIZE,
-                                            PCI_DMA_BIDIRECTIONAL);
-               if (pci_dma_mapping_error(device->pdev, priv->r100c10))
+               priv->r100c10 = nv_device_map_page(device, priv->r100c10_page);
+               if (!priv->r100c10)
                        return -EFAULT;
        }
 
index 9e1931e..705a06d 100644 (file)
@@ -18,12 +18,14 @@ int  nvc0_fb_init(struct nouveau_object *);
 bool nvc0_fb_memtype_valid(struct nouveau_fb *, u32);
 
 
-#define nvc0_ram_create(p,e,o,d)                                               \
-       nvc0_ram_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvc0_ram_create(p,e,o,m,d)                                             \
+       nvc0_ram_create_((p), (e), (o), (m), sizeof(**d), (void **)d)
 int  nvc0_ram_create_(struct nouveau_object *, struct nouveau_object *,
-                     struct nouveau_oclass *, int, void **);
+                     struct nouveau_oclass *, u32, int, void **);
 int  nvc0_ram_get(struct nouveau_fb *, u64, u32, u32, u32,
                  struct nouveau_mem **);
 void nvc0_ram_put(struct nouveau_fb *, struct nouveau_mem **);
 
+int  nve0_ram_init(struct nouveau_object*);
+
 #endif
index edaf95d..da74c88 100644 (file)
@@ -32,6 +32,7 @@ extern struct nouveau_oclass nva3_ram_oclass;
 extern struct nouveau_oclass nvaa_ram_oclass;
 extern struct nouveau_oclass nvc0_ram_oclass;
 extern struct nouveau_oclass nve0_ram_oclass;
+extern struct nouveau_oclass gm107_ram_oclass;
 
 int nouveau_sddr3_calc(struct nouveau_ram *ram);
 int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c
new file mode 100644 (file)
index 0000000..4c63635
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nvc0.h"
+
+struct gm107_ram {
+       struct nouveau_ram base;
+};
+
+static int
+gm107_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct gm107_ram *ram;
+       int ret;
+
+       ret = nvc0_ram_create(parent, engine, oclass, 0x021c14, &ram);
+       *pobject = nv_object(ram);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+struct nouveau_oclass
+gm107_ram_oclass = {
+       .handle = 0,
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gm107_ram_ctor,
+               .dtor = _nouveau_ram_dtor,
+               .init = nve0_ram_init,
+               .fini = _nouveau_ram_fini,
+       }
+};
index c7fdb3a..ef91b6e 100644 (file)
@@ -91,7 +91,7 @@ nv50_ram_calc(struct nouveau_fb *pfb, u32 freq)
        } while (perfE.memory < freq);
 
        /* locate specific data set for the attached memory */
-       strap = nvbios_ramcfg_index(bios);
+       strap = nvbios_ramcfg_index(nv_subdev(pfb));
        if (strap >= cnt) {
                nv_error(pfb, "invalid ramcfg strap\n");
                return -EINVAL;
index f4ae8aa..6eb97f1 100644 (file)
@@ -98,7 +98,7 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
        }
 
        /* locate specific data set for the attached memory */
-       strap = nvbios_ramcfg_index(bios);
+       strap = nvbios_ramcfg_index(nv_subdev(pfb));
        if (strap >= cnt) {
                nv_error(pfb, "invalid ramcfg strap\n");
                return -EINVAL;
@@ -335,21 +335,23 @@ nva3_ram_init(struct nouveau_object *object)
        /* prepare for ddr link training, and load training patterns */
        switch (ram->base.type) {
        case NV_MEM_TYPE_DDR3: {
-               static const u32 pattern[16] = {
-                       0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
-                       0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
-                       0x33333333, 0x55555555, 0x77777777, 0x66666666,
-                       0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
-               };
-
-               nv_wr32(pfb, 0x100538, 0x10001ff6); /*XXX*/
-               nv_wr32(pfb, 0x1005a8, 0x0000ffff);
-               nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001);
-               for (i = 0; i < 0x30; i++) {
-                       nv_wr32(pfb, 0x10f8c0, (i << 8) | i);
-                       nv_wr32(pfb, 0x10f8e0, (i << 8) | i);
-                       nv_wr32(pfb, 0x10f900, pattern[i % 16]);
-                       nv_wr32(pfb, 0x10f920, pattern[i % 16]);
+               if (nv_device(pfb)->chipset == 0xa8) {
+                       static const u32 pattern[16] = {
+                               0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
+                               0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
+                               0x33333333, 0x55555555, 0x77777777, 0x66666666,
+                               0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
+                       };
+
+                       nv_wr32(pfb, 0x100538, 0x10001ff6); /*XXX*/
+                       nv_wr32(pfb, 0x1005a8, 0x0000ffff);
+                       nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001);
+                       for (i = 0; i < 0x30; i++) {
+                               nv_wr32(pfb, 0x10f8c0, (i << 8) | i);
+                               nv_wr32(pfb, 0x10f8e0, (i << 8) | i);
+                               nv_wr32(pfb, 0x10f900, pattern[i % 16]);
+                               nv_wr32(pfb, 0x10f920, pattern[i % 16]);
+                       }
                }
        }
                break;
index 0391b82..8edc922 100644 (file)
@@ -152,7 +152,7 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
        }
 
        /* locate specific data set for the attached memory */
-       strap = nvbios_ramcfg_index(bios);
+       strap = nvbios_ramcfg_index(nv_subdev(pfb));
        if (strap >= cnt) {
                nv_error(pfb, "invalid ramcfg strap\n");
                return -EINVAL;
@@ -505,7 +505,8 @@ nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
 
 int
 nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
-                struct nouveau_oclass *oclass, int size, void **pobject)
+                struct nouveau_oclass *oclass, u32 maskaddr, int size,
+                void **pobject)
 {
        struct nouveau_fb *pfb = nouveau_fb(parent);
        struct nouveau_bios *bios = nouveau_bios(pfb);
@@ -513,7 +514,7 @@ nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
        const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
        const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
        u32 parts = nv_rd32(pfb, 0x022438);
-       u32 pmask = nv_rd32(pfb, 0x022554);
+       u32 pmask = nv_rd32(pfb, maskaddr);
        u32 bsize = nv_rd32(pfb, 0x10f20c);
        u32 offset, length;
        bool uniform = true;
@@ -630,7 +631,7 @@ nvc0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nvc0_ram *ram;
        int ret;
 
-       ret = nvc0_ram_create(parent, engine, oclass, &ram);
+       ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
        *pobject = nv_object(ram);
        if (ret)
                return ret;
index 3257c52..1675219 100644 (file)
@@ -950,10 +950,11 @@ nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq,
        }
 
        /* locate specific data set for the attached memory */
+       strap = nvbios_ramcfg_index(nv_subdev(pfb));
        ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data,
                                                ram->base.rammap.version,
-                                               ram->base.rammap.size, cnt, len,
-                                               nvbios_ramcfg_index(bios),
+                                               ram->base.rammap.size,
+                                               cnt, len, strap,
                                                &ram->base.ramcfg.version,
                                                &ram->base.ramcfg.size,
                                                &data->bios);
@@ -1123,7 +1124,7 @@ nve0_ram_tidy(struct nouveau_fb *pfb)
        ram_exec(fuc, false);
 }
 
-static int
+int
 nve0_ram_init(struct nouveau_object *object)
 {
        struct nouveau_fb *pfb = (void *)object->parent;
@@ -1226,7 +1227,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        int ret, i;
        u32 tmp;
 
-       ret = nvc0_ram_create(parent, engine, oclass, &ram);
+       ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
        *pobject = nv_object(ram);
        if (ret)
                return ret;
index c4c1d41..2ef7747 100644 (file)
@@ -46,7 +46,8 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
                u8  unk0 = !!(data & 0x02000000);
                u8  unk1 = !!(data & 0x04000000);
                u32 val = (unk1 << 16) | unk0;
-               u32 reg = regs[line >> 4]; line &= 0x0f;
+               u32 reg = regs[line >> 4];
+               u32 lsh = line & 0x0f;
 
                if ( func  == DCB_GPIO_UNUSED ||
                    (match != DCB_GPIO_UNUSED && match != func))
@@ -54,7 +55,7 @@ nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
 
                gpio->set(gpio, 0, func, line, defs);
 
-               nv_mask(priv, reg, 0x00010001 << line, val << line);
+               nv_mask(priv, reg, 0x00010001 << lsh, val << lsh);
        }
 }
 
@@ -79,7 +80,7 @@ nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
        if (nv50_gpio_location(line, &reg, &shift))
                return -EINVAL;
 
-       nv_mask(gpio, reg, 7 << shift, (((dir ^ 1) << 1) | out) << shift);
+       nv_mask(gpio, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift);
        return 0;
 }
 
index c33c03d..378e05b 100644 (file)
@@ -111,7 +111,7 @@ nouveau_i2c_port_create_(struct nouveau_object *parent,
        snprintf(port->adapter.name, sizeof(port->adapter.name),
                 "nouveau-%s-%d", device->name, index);
        port->adapter.owner = THIS_MODULE;
-       port->adapter.dev.parent = &device->pdev->dev;
+       port->adapter.dev.parent = nv_device_base(device);
        port->index = index;
        port->func = func;
        i2c_set_adapdata(&port->adapter, i2c);
index ec0b966..8803809 100644 (file)
@@ -50,7 +50,6 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                  struct nouveau_object **pobject)
 {
        struct nouveau_device *device = nv_device(parent);
-       struct pci_dev *pdev = device->pdev;
        struct nv04_instmem_priv *priv;
        int ret, bar, vs;
 
@@ -60,13 +59,13 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        /* map bar */
-       if (pci_resource_len(pdev, 2))
+       if (nv_device_resource_len(device, 2))
                bar = 2;
        else
                bar = 3;
 
-       priv->iomem = ioremap(pci_resource_start(pdev, bar),
-                             pci_resource_len(pdev, bar));
+       priv->iomem = ioremap(nv_device_resource_start(device, bar),
+                             nv_device_resource_len(device, bar));
        if (!priv->iomem) {
                nv_error(priv, "unable to map PRAMIN BAR\n");
                return -EFAULT;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.c
new file mode 100644 (file)
index 0000000..f2f3338
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+#include "gf100.h"
+
+static void
+gf100_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts)
+{
+       u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400);
+       u32 stat = nv_rd32(priv, base + 0x020);
+
+       if (stat) {
+               nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
+               nv_wr32(priv, base + 0x020, stat);
+       }
+}
+
+static void
+gf100_ltcg_intr(struct nouveau_subdev *subdev)
+{
+       struct gf100_ltcg_priv *priv = (void *)subdev;
+       u32 mask;
+
+       mask = nv_rd32(priv, 0x00017c);
+       while (mask) {
+               u32 lts, ltc = __ffs(mask);
+               for (lts = 0; lts < priv->lts_nr; lts++)
+                       gf100_ltcg_lts_isr(priv, ltc, lts);
+               mask &= ~(1 << ltc);
+       }
+
+       /* we do something horribly wrong and upset PMFB a lot, so mask off
+        * interrupts from it after the first one until it's fixed
+        */
+       nv_mask(priv, 0x000640, 0x02000000, 0x00000000);
+}
+
+int
+gf100_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n,
+                    struct nouveau_mm_node **pnode)
+{
+       struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg;
+       int ret;
+
+       ret = nouveau_mm_head(&priv->tags, 1, n, n, 1, pnode);
+       if (ret)
+               *pnode = NULL;
+
+       return ret;
+}
+
+void
+gf100_ltcg_tags_free(struct nouveau_ltcg *ltcg, struct nouveau_mm_node **pnode)
+{
+       struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg;
+
+       nouveau_mm_free(&priv->tags, pnode);
+}
+
+static void
+gf100_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count)
+{
+       struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg;
+       u32 last = first + count - 1;
+       int p, i;
+
+       BUG_ON((first > last) || (last >= priv->num_tags));
+
+       nv_wr32(priv, 0x17e8cc, first);
+       nv_wr32(priv, 0x17e8d0, last);
+       nv_wr32(priv, 0x17e8c8, 0x4); /* trigger clear */
+
+       /* wait until it's finished with clearing */
+       for (p = 0; p < priv->ltc_nr; ++p) {
+               for (i = 0; i < priv->lts_nr; ++i)
+                       nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0);
+       }
+}
+
+/* TODO: Figure out tag memory details and drop the over-cautious allocation.
+ */
+int
+gf100_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct gf100_ltcg_priv *priv)
+{
+       u32 tag_size, tag_margin, tag_align;
+       int ret;
+
+       /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
+       priv->num_tags = (pfb->ram->size >> 17) / 4;
+       if (priv->num_tags > (1 << 17))
+               priv->num_tags = 1 << 17; /* we have 17 bits in PTE */
+       priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */
+
+       tag_align = priv->ltc_nr * 0x800;
+       tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align;
+
+       /* 4 part 4 sub: 0x2000 bytes for 56 tags */
+       /* 3 part 4 sub: 0x6000 bytes for 168 tags */
+       /*
+        * About 147 bytes per tag. Let's be safe and allocate x2, which makes
+        * 0x4980 bytes for 64 tags, and round up to 0x6000 bytes for 64 tags.
+        *
+        * For 4 GiB of memory we'll have 8192 tags which makes 3 MiB, < 0.1 %.
+        */
+       tag_size  = (priv->num_tags / 64) * 0x6000 + tag_margin;
+       tag_size += tag_align;
+       tag_size  = (tag_size + 0xfff) >> 12; /* round up */
+
+       ret = nouveau_mm_tail(&pfb->vram, 1, tag_size, tag_size, 1,
+                             &priv->tag_ram);
+       if (ret) {
+               priv->num_tags = 0;
+       } else {
+               u64 tag_base = (priv->tag_ram->offset << 12) + tag_margin;
+
+               tag_base += tag_align - 1;
+               ret = do_div(tag_base, tag_align);
+
+               priv->tag_base = tag_base;
+       }
+       ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1);
+
+       return ret;
+}
+
+static int
+gf100_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct gf100_ltcg_priv *priv;
+       struct nouveau_fb *pfb = nouveau_fb(parent);
+       u32 parts, mask;
+       int ret, i;
+
+       ret = nouveau_ltcg_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       parts = nv_rd32(priv, 0x022438);
+       mask = nv_rd32(priv, 0x022554);
+       for (i = 0; i < parts; i++) {
+               if (!(mask & (1 << i)))
+                       priv->ltc_nr++;
+       }
+       priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28;
+
+       ret = gf100_ltcg_init_tag_ram(pfb, priv);
+       if (ret)
+               return ret;
+
+       priv->base.tags_alloc = gf100_ltcg_tags_alloc;
+       priv->base.tags_free  = gf100_ltcg_tags_free;
+       priv->base.tags_clear = gf100_ltcg_tags_clear;
+
+       nv_subdev(priv)->intr = gf100_ltcg_intr;
+       return 0;
+}
+
+void
+gf100_ltcg_dtor(struct nouveau_object *object)
+{
+       struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
+       struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg;
+       struct nouveau_fb *pfb = nouveau_fb(ltcg->base.base.parent);
+
+       nouveau_mm_fini(&priv->tags);
+       nouveau_mm_free(&pfb->vram, &priv->tag_ram);
+
+       nouveau_ltcg_destroy(ltcg);
+}
+
+static int
+gf100_ltcg_init(struct nouveau_object *object)
+{
+       struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
+       struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg;
+       int ret;
+
+       ret = nouveau_ltcg_init(ltcg);
+       if (ret)
+               return ret;
+
+       nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
+       nv_wr32(priv, 0x17e8d8, priv->ltc_nr);
+       if (nv_device(ltcg)->card_type >= NV_E0)
+               nv_wr32(priv, 0x17e000, priv->ltc_nr);
+       nv_wr32(priv, 0x17e8d4, priv->tag_base);
+       return 0;
+}
+
+struct nouveau_oclass *
+gf100_ltcg_oclass = &(struct nouveau_oclass) {
+       .handle = NV_SUBDEV(LTCG, 0xc0),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gf100_ltcg_ctor,
+               .dtor = gf100_ltcg_dtor,
+               .init = gf100_ltcg_init,
+               .fini = _nouveau_ltcg_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gf100.h
new file mode 100644 (file)
index 0000000..87b10b8
--- /dev/null
@@ -0,0 +1,21 @@
+#ifndef __NVKM_LTCG_PRIV_GF100_H__
+#define __NVKM_LTCG_PRIV_GF100_H__
+
+#include <subdev/ltcg.h>
+
+struct gf100_ltcg_priv {
+       struct nouveau_ltcg base;
+       u32 ltc_nr;
+       u32 lts_nr;
+       u32 num_tags;
+       u32 tag_base;
+       struct nouveau_mm tags;
+       struct nouveau_mm_node *tag_ram;
+};
+
+void gf100_ltcg_dtor(struct nouveau_object *);
+int  gf100_ltcg_init_tag_ram(struct nouveau_fb *, struct gf100_ltcg_priv *);
+int  gf100_ltcg_tags_alloc(struct nouveau_ltcg *, u32, struct nouveau_mm_node **);
+void gf100_ltcg_tags_free(struct nouveau_ltcg *, struct nouveau_mm_node **);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/gm107.c
new file mode 100644 (file)
index 0000000..e79d0e8
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+#include "gf100.h"
+
+static void
+gm107_ltcg_lts_isr(struct gf100_ltcg_priv *priv, int ltc, int lts)
+{
+       u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400);
+       u32 stat = nv_rd32(priv, base + 0x00c);
+
+       if (stat) {
+               nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
+               nv_wr32(priv, base + 0x00c, stat);
+       }
+}
+
+static void
+gm107_ltcg_intr(struct nouveau_subdev *subdev)
+{
+       struct gf100_ltcg_priv *priv = (void *)subdev;
+       u32 mask;
+
+       mask = nv_rd32(priv, 0x00017c);
+       while (mask) {
+               u32 lts, ltc = __ffs(mask);
+               for (lts = 0; lts < priv->lts_nr; lts++)
+                       gm107_ltcg_lts_isr(priv, ltc, lts);
+               mask &= ~(1 << ltc);
+       }
+
+       /* we do something horribly wrong and upset PMFB a lot, so mask off
+        * interrupts from it after the first one until it's fixed
+        */
+       nv_mask(priv, 0x000640, 0x02000000, 0x00000000);
+}
+
+static void
+gm107_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count)
+{
+       struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg;
+       u32 last = first + count - 1;
+       int p, i;
+
+       BUG_ON((first > last) || (last >= priv->num_tags));
+
+       nv_wr32(priv, 0x17e270, first);
+       nv_wr32(priv, 0x17e274, last);
+       nv_wr32(priv, 0x17e26c, 0x4); /* trigger clear */
+
+       /* wait until it's finished with clearing */
+       for (p = 0; p < priv->ltc_nr; ++p) {
+               for (i = 0; i < priv->lts_nr; ++i)
+                       nv_wait(priv, 0x14046c + p * 0x2000 + i * 0x200, ~0, 0);
+       }
+}
+
+static int
+gm107_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
+{
+       struct gf100_ltcg_priv *priv;
+       struct nouveau_fb *pfb = nouveau_fb(parent);
+       u32 parts, mask;
+       int ret, i;
+
+       ret = nouveau_ltcg_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       parts = nv_rd32(priv, 0x022438);
+       mask = nv_rd32(priv, 0x021c14);
+       for (i = 0; i < parts; i++) {
+               if (!(mask & (1 << i)))
+                       priv->ltc_nr++;
+       }
+       priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28;
+
+       ret = gf100_ltcg_init_tag_ram(pfb, priv);
+       if (ret)
+               return ret;
+
+       priv->base.tags_alloc = gf100_ltcg_tags_alloc;
+       priv->base.tags_free  = gf100_ltcg_tags_free;
+       priv->base.tags_clear = gm107_ltcg_tags_clear;
+
+       nv_subdev(priv)->intr = gm107_ltcg_intr;
+       return 0;
+}
+
+static int
+gm107_ltcg_init(struct nouveau_object *object)
+{
+       struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
+       struct gf100_ltcg_priv *priv = (struct gf100_ltcg_priv *)ltcg;
+       int ret;
+
+       ret = nouveau_ltcg_init(ltcg);
+       if (ret)
+               return ret;
+
+       nv_wr32(priv, 0x17e27c, priv->ltc_nr);
+       nv_wr32(priv, 0x17e278, priv->tag_base);
+       return 0;
+}
+
+struct nouveau_oclass *
+gm107_ltcg_oclass = &(struct nouveau_oclass) {
+       .handle = NV_SUBDEV(LTCG, 0xff),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = gm107_ltcg_ctor,
+               .dtor = gf100_ltcg_dtor,
+               .init = gm107_ltcg_init,
+               .fini = _nouveau_ltcg_fini,
+       },
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ltcg/nvc0.c
deleted file mode 100644 (file)
index cce65cc..0000000
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/ltcg.h>
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-struct nvc0_ltcg_priv {
-       struct nouveau_ltcg base;
-       u32 part_nr;
-       u32 subp_nr;
-       u32 num_tags;
-       u32 tag_base;
-       struct nouveau_mm tags;
-       struct nouveau_mm_node *tag_ram;
-};
-
-static void
-nvc0_ltcg_subp_isr(struct nvc0_ltcg_priv *priv, int unit, int subp)
-{
-       u32 subp_base = 0x141000 + (unit * 0x2000) + (subp * 0x400);
-       u32 stat = nv_rd32(priv, subp_base + 0x020);
-
-       if (stat) {
-               nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", unit, subp, stat);
-               nv_wr32(priv, subp_base + 0x020, stat);
-       }
-}
-
-static void
-nvc0_ltcg_intr(struct nouveau_subdev *subdev)
-{
-       struct nvc0_ltcg_priv *priv = (void *)subdev;
-       u32 units;
-
-       units = nv_rd32(priv, 0x00017c);
-       while (units) {
-               u32 subp, unit = ffs(units) - 1;
-               for (subp = 0; subp < priv->subp_nr; subp++)
-                       nvc0_ltcg_subp_isr(priv, unit, subp);
-               units &= ~(1 << unit);
-       }
-
-       /* we do something horribly wrong and upset PMFB a lot, so mask off
-        * interrupts from it after the first one until it's fixed
-        */
-       nv_mask(priv, 0x000640, 0x02000000, 0x00000000);
-}
-
-static int
-nvc0_ltcg_tags_alloc(struct nouveau_ltcg *ltcg, u32 n,
-                    struct nouveau_mm_node **pnode)
-{
-       struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
-       int ret;
-
-       ret = nouveau_mm_head(&priv->tags, 1, n, n, 1, pnode);
-       if (ret)
-               *pnode = NULL;
-
-       return ret;
-}
-
-static void
-nvc0_ltcg_tags_free(struct nouveau_ltcg *ltcg, struct nouveau_mm_node **pnode)
-{
-       struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
-
-       nouveau_mm_free(&priv->tags, pnode);
-}
-
-static void
-nvc0_ltcg_tags_clear(struct nouveau_ltcg *ltcg, u32 first, u32 count)
-{
-       struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
-       u32 last = first + count - 1;
-       int p, i;
-
-       BUG_ON((first > last) || (last >= priv->num_tags));
-
-       nv_wr32(priv, 0x17e8cc, first);
-       nv_wr32(priv, 0x17e8d0, last);
-       nv_wr32(priv, 0x17e8c8, 0x4); /* trigger clear */
-
-       /* wait until it's finished with clearing */
-       for (p = 0; p < priv->part_nr; ++p) {
-               for (i = 0; i < priv->subp_nr; ++i)
-                       nv_wait(priv, 0x1410c8 + p * 0x2000 + i * 0x400, ~0, 0);
-       }
-}
-
-/* TODO: Figure out tag memory details and drop the over-cautious allocation.
- */
-static int
-nvc0_ltcg_init_tag_ram(struct nouveau_fb *pfb, struct nvc0_ltcg_priv *priv)
-{
-       u32 tag_size, tag_margin, tag_align;
-       int ret;
-
-       /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
-       priv->num_tags = (pfb->ram->size >> 17) / 4;
-       if (priv->num_tags > (1 << 17))
-               priv->num_tags = 1 << 17; /* we have 17 bits in PTE */
-       priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */
-
-       tag_align = priv->part_nr * 0x800;
-       tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align;
-
-       /* 4 part 4 sub: 0x2000 bytes for 56 tags */
-       /* 3 part 4 sub: 0x6000 bytes for 168 tags */
-       /*
-        * About 147 bytes per tag. Let's be safe and allocate x2, which makes
-        * 0x4980 bytes for 64 tags, and round up to 0x6000 bytes for 64 tags.
-        *
-        * For 4 GiB of memory we'll have 8192 tags which makes 3 MiB, < 0.1 %.
-        */
-       tag_size  = (priv->num_tags / 64) * 0x6000 + tag_margin;
-       tag_size += tag_align;
-       tag_size  = (tag_size + 0xfff) >> 12; /* round up */
-
-       ret = nouveau_mm_tail(&pfb->vram, 1, tag_size, tag_size, 1,
-                             &priv->tag_ram);
-       if (ret) {
-               priv->num_tags = 0;
-       } else {
-               u64 tag_base = (priv->tag_ram->offset << 12) + tag_margin;
-
-               tag_base += tag_align - 1;
-               ret = do_div(tag_base, tag_align);
-
-               priv->tag_base = tag_base;
-       }
-       ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1);
-
-       return ret;
-}
-
-static int
-nvc0_ltcg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-              struct nouveau_oclass *oclass, void *data, u32 size,
-              struct nouveau_object **pobject)
-{
-       struct nvc0_ltcg_priv *priv;
-       struct nouveau_fb *pfb = nouveau_fb(parent);
-       u32 parts, mask;
-       int ret, i;
-
-       ret = nouveau_ltcg_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       parts = nv_rd32(priv, 0x022438);
-       mask = nv_rd32(priv, 0x022554);
-       for (i = 0; i < parts; i++) {
-               if (!(mask & (1 << i)))
-                       priv->part_nr++;
-       }
-       priv->subp_nr = nv_rd32(priv, 0x17e8dc) >> 28;
-
-       ret = nvc0_ltcg_init_tag_ram(pfb, priv);
-       if (ret)
-               return ret;
-
-       priv->base.tags_alloc = nvc0_ltcg_tags_alloc;
-       priv->base.tags_free  = nvc0_ltcg_tags_free;
-       priv->base.tags_clear = nvc0_ltcg_tags_clear;
-
-       nv_subdev(priv)->intr = nvc0_ltcg_intr;
-       return 0;
-}
-
-static void
-nvc0_ltcg_dtor(struct nouveau_object *object)
-{
-       struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
-       struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
-       struct nouveau_fb *pfb = nouveau_fb(ltcg->base.base.parent);
-
-       nouveau_mm_fini(&priv->tags);
-       nouveau_mm_free(&pfb->vram, &priv->tag_ram);
-
-       nouveau_ltcg_destroy(ltcg);
-}
-
-static int
-nvc0_ltcg_init(struct nouveau_object *object)
-{
-       struct nouveau_ltcg *ltcg = (struct nouveau_ltcg *)object;
-       struct nvc0_ltcg_priv *priv = (struct nvc0_ltcg_priv *)ltcg;
-       int ret;
-
-       ret = nouveau_ltcg_init(ltcg);
-       if (ret)
-               return ret;
-
-       nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
-       nv_wr32(priv, 0x17e8d8, priv->part_nr);
-       if (nv_device(ltcg)->card_type >= NV_E0)
-               nv_wr32(priv, 0x17e000, priv->part_nr);
-       nv_wr32(priv, 0x17e8d4, priv->tag_base);
-       return 0;
-}
-
-struct nouveau_oclass
-nvc0_ltcg_oclass = {
-       .handle = NV_SUBDEV(LTCG, 0xc0),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nvc0_ltcg_ctor,
-               .dtor = nvc0_ltcg_dtor,
-               .init = nvc0_ltcg_init,
-               .fini = _nouveau_ltcg_fini,
-       },
-};
index b4b9943..8a55551 100644 (file)
@@ -93,7 +93,7 @@ _nouveau_mc_dtor(struct nouveau_object *object)
 {
        struct nouveau_device *device = nv_device(object);
        struct nouveau_mc *pmc = (void *)object;
-       free_irq(device->pdev->irq, pmc);
+       free_irq(pmc->irq, pmc);
        if (pmc->use_msi)
                pci_disable_msi(device->pdev);
        nouveau_subdev_destroy(&pmc->base);
@@ -114,33 +114,44 @@ nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       switch (device->pdev->device & 0x0ff0) {
-       case 0x00f0:
-       case 0x02e0:
-               /* BR02? NFI how these would be handled yet exactly */
-               break;
-       default:
-               switch (device->chipset) {
-               case 0xaa: break; /* reported broken, nv also disable it */
-               default:
-                       pmc->use_msi = true;
+       if (nv_device_is_pci(device))
+               switch (device->pdev->device & 0x0ff0) {
+               case 0x00f0:
+               case 0x02e0:
+                       /* BR02? NFI how these would be handled yet exactly */
                        break;
+               default:
+                       switch (device->chipset) {
+                       case 0xaa:
+                               /* reported broken, nv also disable it */
+                               break;
+                       default:
+                               pmc->use_msi = true;
+                               break;
                }
-       }
 
-       pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI", pmc->use_msi);
-       if (pmc->use_msi && oclass->msi_rearm) {
-               pmc->use_msi = pci_enable_msi(device->pdev) == 0;
-               if (pmc->use_msi) {
-                       nv_info(pmc, "MSI interrupts enabled\n");
-                       oclass->msi_rearm(pmc);
+               pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI",
+                                              pmc->use_msi);
+
+               if (pmc->use_msi && oclass->msi_rearm) {
+                       pmc->use_msi = pci_enable_msi(device->pdev) == 0;
+                       if (pmc->use_msi) {
+                               nv_info(pmc, "MSI interrupts enabled\n");
+                               oclass->msi_rearm(pmc);
+                       }
+               } else {
+                       pmc->use_msi = false;
                }
-       } else {
-               pmc->use_msi = false;
        }
 
-       ret = request_irq(device->pdev->irq, nouveau_mc_intr,
-                         IRQF_SHARED, "nouveau", pmc);
+       ret = nv_device_get_irq(device, true);
+       if (ret < 0)
+               return ret;
+       pmc->irq = ret;
+
+       ret = request_irq(pmc->irq, nouveau_mc_intr, IRQF_SHARED, "nouveau",
+                         pmc);
+
        if (ret < 0)
                return ret;
 
index 13c5af8..51fcf79 100644 (file)
@@ -96,7 +96,7 @@ mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version)
        acpi_handle handle;
        int rev;
 
-       handle = ACPI_HANDLE(&device->pdev->dev);
+       handle = ACPI_HANDLE(nv_device_base(device));
        if (!handle)
                return false;
 
index 80e584a..9ad01da 100644 (file)
@@ -110,16 +110,18 @@ nouveau_therm_update(struct nouveau_therm *therm, int mode)
                poll = false;
                break;
        case NOUVEAU_THERM_CTRL_AUTO:
-               if (priv->fan->bios.nr_fan_trip) {
+               switch(priv->fan->bios.fan_mode) {
+               case NVBIOS_THERM_FAN_TRIP:
                        duty = nouveau_therm_update_trip(therm);
-               } else
-               if (priv->fan->bios.linear_min_temp ||
-                   priv->fan->bios.linear_max_temp) {
+                       break;
+               case NVBIOS_THERM_FAN_LINEAR:
                        duty = nouveau_therm_update_linear(therm);
-               } else {
+                       break;
+               case NVBIOS_THERM_FAN_OTHER:
                        if (priv->cstate)
                                duty = priv->cstate;
                        poll = false;
+                       break;
                }
                immd = false;
                break;
@@ -179,7 +181,7 @@ nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode)
 
        /* do not allow automatic fan management if the thermal sensor is
         * not available */
-       if (priv->mode == NOUVEAU_THERM_CTRL_AUTO && therm->temp_get(therm) < 0)
+       if (mode == NOUVEAU_THERM_CTRL_AUTO && therm->temp_get(therm) < 0)
                return -EINVAL;
 
        if (priv->mode == mode)
index 95f6129..016990a 100644 (file)
@@ -54,8 +54,10 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
 
        /* check that we're not already at the target duty cycle */
        duty = fan->get(therm);
-       if (duty == target)
-               goto done;
+       if (duty == target) {
+               spin_unlock_irqrestore(&fan->lock, flags);
+               return 0;
+       }
 
        /* smooth out the fanspeed increase/decrease */
        if (!immediate && duty >= 0) {
@@ -73,8 +75,15 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
 
        nv_debug(therm, "FAN update: %d\n", duty);
        ret = fan->set(therm, duty);
-       if (ret)
-               goto done;
+       if (ret) {
+               spin_unlock_irqrestore(&fan->lock, flags);
+               return ret;
+       }
+
+       /* fan speed updated, drop the fan lock before grabbing the
+        * alarm-scheduling lock and risking a deadlock
+        */
+       spin_unlock_irqrestore(&fan->lock, flags);
 
        /* schedule next fan update, if not at target speed already */
        if (list_empty(&fan->alarm.head) && target != duty) {
@@ -92,8 +101,6 @@ nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
                ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm);
        }
 
-done:
-       spin_unlock_irqrestore(&fan->lock, flags);
        return ret;
 }
 
@@ -185,11 +192,8 @@ nouveau_therm_fan_set_defaults(struct nouveau_therm *therm)
        priv->fan->bios.max_duty = 100;
        priv->fan->bios.bump_period = 500;
        priv->fan->bios.slow_down_period = 2000;
-/*XXX: talk to mupuf */
-#if 0
        priv->fan->bios.linear_min_temp = 40;
        priv->fan->bios.linear_max_temp = 85;
-#endif
 }
 
 static void
@@ -235,7 +239,8 @@ nouveau_therm_fan_ctor(struct nouveau_therm *therm)
        /* attempt to locate a drivable fan, and determine control method */
        ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func);
        if (ret == 0) {
-               if (func.log[0] & DCB_GPIO_LOG_DIR_IN) {
+               /* FIXME: is this really the place to perform such checks ? */
+               if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) {
                        nv_debug(therm, "GPIO_FAN is in input mode\n");
                        ret = -EINVAL;
                } else {
index 5f71db8..9a5c073 100644 (file)
@@ -67,7 +67,7 @@ nouveau_fanpwm_set(struct nouveau_therm *therm, int percent)
        if (priv->base.bios.pwm_freq) {
                divs = 1;
                if (therm->pwm_clock)
-                       divs = therm->pwm_clock(therm);
+                       divs = therm->pwm_clock(therm, priv->func.line);
                divs /= priv->base.bios.pwm_freq;
        }
 
index 8cf7597..321db92 100644 (file)
@@ -93,7 +93,7 @@ nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
 }
 
 int
-nv50_fan_pwm_clock(struct nouveau_therm *therm)
+nv50_fan_pwm_clock(struct nouveau_therm *therm, int line)
 {
        int chipset = nv_device(therm)->chipset;
        int crystal = nv_device(therm)->crystal;
index 4dd4f81..43fec17 100644 (file)
@@ -32,10 +32,12 @@ static int
 pwm_info(struct nouveau_therm *therm, int line)
 {
        u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04));
+
        switch (gpio & 0x000000c0) {
        case 0x00000000: /* normal mode, possibly pwm forced off by us */
        case 0x00000040: /* nvio special */
                switch (gpio & 0x0000001f) {
+               case 0x00: return 2;
                case 0x19: return 1;
                case 0x1c: return 0;
                default:
@@ -56,8 +58,9 @@ nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
        int indx = pwm_info(therm, line);
        if (indx < 0)
                return indx;
-
-       nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data);
+       else if (indx < 2)
+               nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data);
+       /* nothing to do for indx == 2, it seems hardwired to PTHERM */
        return 0;
 }
 
@@ -67,10 +70,15 @@ nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
        int indx = pwm_info(therm, line);
        if (indx < 0)
                return indx;
-
-       if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) {
-               *divs = nv_rd32(therm, 0x00e114 + (indx * 8));
-               *duty = nv_rd32(therm, 0x00e118 + (indx * 8));
+       else if (indx < 2) {
+               if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) {
+                       *divs = nv_rd32(therm, 0x00e114 + (indx * 8));
+                       *duty = nv_rd32(therm, 0x00e118 + (indx * 8));
+                       return 0;
+               }
+       } else if (indx == 2) {
+               *divs = nv_rd32(therm, 0x0200d8) & 0x1fff;
+               *duty = nv_rd32(therm, 0x0200dc) & 0x1fff;
                return 0;
        }
 
@@ -83,16 +91,26 @@ nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
        int indx = pwm_info(therm, line);
        if (indx < 0)
                return indx;
-
-       nv_wr32(therm, 0x00e114 + (indx * 8), divs);
-       nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000);
+       else if (indx < 2) {
+               nv_wr32(therm, 0x00e114 + (indx * 8), divs);
+               nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000);
+       } else if (indx == 2) {
+               nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */
+               nv_wr32(therm, 0x0200dc, duty | 0x40000000);
+       }
        return 0;
 }
 
 static int
-nvd0_fan_pwm_clock(struct nouveau_therm *therm)
+nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line)
 {
-       return (nv_device(therm)->crystal * 1000) / 20;
+       int indx = pwm_info(therm, line);
+       if (indx < 0)
+               return 0;
+       else if (indx < 2)
+               return (nv_device(therm)->crystal * 1000) / 20;
+       else
+               return nv_device(therm)->crystal * 1000 / 10;
 }
 
 static int
index 96f8f95..916fca5 100644 (file)
@@ -143,7 +143,7 @@ void nv40_therm_intr(struct nouveau_subdev *);
 int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool);
 int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *);
 int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32);
-int nv50_fan_pwm_clock(struct nouveau_therm *);
+int nv50_fan_pwm_clock(struct nouveau_therm *, int);
 int nv84_temp_get(struct nouveau_therm *therm);
 int nv84_therm_fini(struct nouveau_object *object, bool suspend);
 
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c
new file mode 100644 (file)
index 0000000..37484db
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#include "nv04.h"
+
+static int
+gk20a_timer_init(struct nouveau_object *object)
+{
+       struct nv04_timer_priv *priv = (void *)object;
+       u32 hi = upper_32_bits(priv->suspend_time);
+       u32 lo = lower_32_bits(priv->suspend_time);
+       int ret;
+
+       ret = nouveau_timer_init(&priv->base);
+       if (ret)
+               return ret;
+
+       nv_debug(priv, "time low        : 0x%08x\n", lo);
+       nv_debug(priv, "time high       : 0x%08x\n", hi);
+
+       /* restore the time before suspend */
+       nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
+       nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
+       return 0;
+}
+
+struct nouveau_oclass
+gk20a_timer_oclass = {
+       .handle = NV_SUBDEV(TIMER, 0xff),
+       .ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_timer_ctor,
+               .dtor = nv04_timer_dtor,
+               .init = gk20a_timer_init,
+               .fini = nv04_timer_fini,
+       }
+};
index c0bdd10..240ed0b 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/timer.h>
-
-#define NV04_PTIMER_INTR_0      0x009100
-#define NV04_PTIMER_INTR_EN_0   0x009140
-#define NV04_PTIMER_NUMERATOR   0x009200
-#define NV04_PTIMER_DENOMINATOR 0x009210
-#define NV04_PTIMER_TIME_0      0x009400
-#define NV04_PTIMER_TIME_1      0x009410
-#define NV04_PTIMER_ALARM_0     0x009420
-
-struct nv04_timer_priv {
-       struct nouveau_timer base;
-       struct list_head alarms;
-       spinlock_t lock;
-       u64 suspend_time;
-};
+#include "nv04.h"
 
 static u64
 nv04_timer_read(struct nouveau_timer *ptimer)
@@ -142,35 +127,14 @@ nv04_timer_intr(struct nouveau_subdev *subdev)
        }
 }
 
-static int
-nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-               struct nouveau_oclass *oclass, void *data, u32 size,
-               struct nouveau_object **pobject)
-{
-       struct nv04_timer_priv *priv;
-       int ret;
-
-       ret = nouveau_timer_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.base.intr = nv04_timer_intr;
-       priv->base.read = nv04_timer_read;
-       priv->base.alarm = nv04_timer_alarm;
-       priv->base.alarm_cancel = nv04_timer_alarm_cancel;
-       priv->suspend_time = 0;
-
-       INIT_LIST_HEAD(&priv->alarms);
-       spin_lock_init(&priv->lock);
-       return 0;
-}
-
-static void
-nv04_timer_dtor(struct nouveau_object *object)
+int
+nv04_timer_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv04_timer_priv *priv = (void *)object;
-       return nouveau_timer_destroy(&priv->base);
+       if (suspend)
+               priv->suspend_time = nv04_timer_read(&priv->base);
+       nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
+       return nouveau_timer_fini(&priv->base, suspend);
 }
 
 static int
@@ -257,14 +221,35 @@ nv04_timer_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
-nv04_timer_fini(struct nouveau_object *object, bool suspend)
+void
+nv04_timer_dtor(struct nouveau_object *object)
 {
        struct nv04_timer_priv *priv = (void *)object;
-       if (suspend)
-               priv->suspend_time = nv04_timer_read(&priv->base);
-       nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
-       return nouveau_timer_fini(&priv->base, suspend);
+       return nouveau_timer_destroy(&priv->base);
+}
+
+int
+nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+               struct nouveau_oclass *oclass, void *data, u32 size,
+               struct nouveau_object **pobject)
+{
+       struct nv04_timer_priv *priv;
+       int ret;
+
+       ret = nouveau_timer_create(parent, engine, oclass, &priv);
+       *pobject = nv_object(priv);
+       if (ret)
+               return ret;
+
+       priv->base.base.intr = nv04_timer_intr;
+       priv->base.read = nv04_timer_read;
+       priv->base.alarm = nv04_timer_alarm;
+       priv->base.alarm_cancel = nv04_timer_alarm_cancel;
+       priv->suspend_time = 0;
+
+       INIT_LIST_HEAD(&priv->alarms);
+       spin_lock_init(&priv->lock);
+       return 0;
 }
 
 struct nouveau_oclass
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h
new file mode 100644 (file)
index 0000000..4bc1526
--- /dev/null
@@ -0,0 +1,27 @@
+#ifndef __NVKM_TIMER_NV04_H__
+#define __NVKM_TIMER_NV04_H__
+
+#include "priv.h"
+
+#define NV04_PTIMER_INTR_0      0x009100
+#define NV04_PTIMER_INTR_EN_0   0x009140
+#define NV04_PTIMER_NUMERATOR   0x009200
+#define NV04_PTIMER_DENOMINATOR 0x009210
+#define NV04_PTIMER_TIME_0      0x009400
+#define NV04_PTIMER_TIME_1      0x009410
+#define NV04_PTIMER_ALARM_0     0x009420
+
+struct nv04_timer_priv {
+       struct nouveau_timer base;
+       struct list_head alarms;
+       spinlock_t lock;
+       u64 suspend_time;
+};
+
+int  nv04_timer_ctor(struct nouveau_object *, struct nouveau_object *,
+                    struct nouveau_oclass *, void *, u32,
+                    struct nouveau_object **);
+void nv04_timer_dtor(struct nouveau_object *);
+int  nv04_timer_fini(struct nouveau_object *, bool);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h b/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h
new file mode 100644 (file)
index 0000000..799dae3
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __NVKM_TIMER_PRIV_H__
+#define __NVKM_TIMER_PRIV_H__
+
+#include <subdev/timer.h>
+
+#endif
index 0e3270c..41be342 100644 (file)
@@ -239,7 +239,7 @@ nv_crtc_mode_set_vga(struct drm_crtc *crtc, struct drm_display_mode *mode)
        struct drm_device *dev = crtc->dev;
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        struct nv04_crtc_reg *regp = &nv04_display(dev)->mode_reg.crtc_reg[nv_crtc->index];
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_framebuffer *fb = crtc->primary->fb;
 
        /* Calculate our timings */
        int horizDisplay        = (mode->crtc_hdisplay >> 3)            - 1;
@@ -574,7 +574,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
                regp->CRTC[NV_CIO_CRE_86] = 0x1;
        }
 
-       regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->fb->depth + 1) / 8;
+       regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] = (crtc->primary->fb->depth + 1) / 8;
        /* Enable slaved mode (called MODE_TV in nv4ref.h) */
        if (lvds_output || tmds_output || tv_output)
                regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (1 << 7);
@@ -588,7 +588,7 @@ nv_crtc_mode_set_regs(struct drm_crtc *crtc, struct drm_display_mode * mode)
        regp->ramdac_gen_ctrl = NV_PRAMDAC_GENERAL_CONTROL_BPC_8BITS |
                                NV_PRAMDAC_GENERAL_CONTROL_VGA_STATE_SEL |
                                NV_PRAMDAC_GENERAL_CONTROL_PIXMIX_ON;
-       if (crtc->fb->depth == 16)
+       if (crtc->primary->fb->depth == 16)
                regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
        if (nv_device(drm->device)->chipset >= 0x11)
                regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_PIPE_LONG;
@@ -609,7 +609,7 @@ static int
 nv_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
 {
        struct nv04_display *disp = nv04_display(crtc->dev);
-       struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
+       struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        int ret;
 
@@ -808,7 +808,7 @@ nv_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b, uint32_t start,
         * mark the lut values as dirty by setting depth==0, and it'll be
         * uploaded on the first mode_set_base()
         */
-       if (!nv_crtc->base.fb) {
+       if (!nv_crtc->base.primary->fb) {
                nv_crtc->lut.depth = 0;
                return;
        }
@@ -832,7 +832,7 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
        NV_DEBUG(drm, "index %d\n", nv_crtc->index);
 
        /* no fb bound */
-       if (!atomic && !crtc->fb) {
+       if (!atomic && !crtc->primary->fb) {
                NV_DEBUG(drm, "No FB bound\n");
                return 0;
        }
@@ -844,8 +844,8 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
                drm_fb = passed_fb;
                fb = nouveau_framebuffer(passed_fb);
        } else {
-               drm_fb = crtc->fb;
-               fb = nouveau_framebuffer(crtc->fb);
+               drm_fb = crtc->primary->fb;
+               fb = nouveau_framebuffer(crtc->primary->fb);
        }
 
        nv_crtc->fb.offset = fb->nvbo->bo.offset;
@@ -857,9 +857,9 @@ nv04_crtc_do_mode_set_base(struct drm_crtc *crtc,
 
        /* Update the framebuffer format. */
        regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] &= ~3;
-       regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->fb->depth + 1) / 8;
+       regp->CRTC[NV_CIO_CRE_PIXEL_INDEX] |= (crtc->primary->fb->depth + 1) / 8;
        regp->ramdac_gen_ctrl &= ~NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
-       if (crtc->fb->depth == 16)
+       if (crtc->primary->fb->depth == 16)
                regp->ramdac_gen_ctrl |= NV_PRAMDAC_GENERAL_CONTROL_ALT_MODE_SEL;
        crtc_wr_cio_state(crtc, regp, NV_CIO_CRE_PIXEL_INDEX);
        NVWriteRAMDAC(dev, nv_crtc->index, NV_PRAMDAC_GENERAL_CONTROL,
@@ -1048,7 +1048,7 @@ nouveau_crtc_set_config(struct drm_mode_set *set)
 
        /* get a pm reference here */
        ret = pm_runtime_get_sync(dev->dev);
-       if (ret < 0)
+       if (ret < 0 && ret != -EACCES)
                return ret;
 
        ret = drm_crtc_helper_set_config(set);
index 7fdc51e..a2d669b 100644 (file)
@@ -415,7 +415,7 @@ static void nv04_dfp_mode_set(struct drm_encoder *encoder,
        /* Output property. */
        if ((nv_connector->dithering_mode == DITHERING_MODE_ON) ||
            (nv_connector->dithering_mode == DITHERING_MODE_AUTO &&
-            encoder->crtc->fb->depth > connector->display_info.bpc * 3)) {
+            encoder->crtc->primary->fb->depth > connector->display_info.bpc * 3)) {
                if (nv_device(drm->device)->chipset == 0x11)
                        regp->dither = savep->dither | 0x00010000;
                else {
index 900fae0..b13f441 100644 (file)
@@ -97,6 +97,7 @@ nouveau_abi16_swclass(struct nouveau_drm *drm)
        case NV_C0:
        case NV_D0:
        case NV_E0:
+       case GM100:
                return 0x906e;
        }
 
@@ -139,7 +140,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
 
        /* destroy channel object, all children will be killed too */
        if (chan->chan) {
-               abi16->handles &= ~(1 << (chan->chan->handle & 0xffff));
+               abi16->handles &= ~(1ULL << (chan->chan->handle & 0xffff));
                nouveau_channel_del(&chan->chan);
        }
 
@@ -179,12 +180,21 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
                getparam->value = device->chipset;
                break;
        case NOUVEAU_GETPARAM_PCI_VENDOR:
-               getparam->value = dev->pdev->vendor;
+               if (nv_device_is_pci(device))
+                       getparam->value = dev->pdev->vendor;
+               else
+                       getparam->value = 0;
                break;
        case NOUVEAU_GETPARAM_PCI_DEVICE:
-               getparam->value = dev->pdev->device;
+               if (nv_device_is_pci(device))
+                       getparam->value = dev->pdev->device;
+               else
+                       getparam->value = 0;
                break;
        case NOUVEAU_GETPARAM_BUS_TYPE:
+               if (!nv_device_is_pci(device))
+                       getparam->value = 3;
+               else
                if (drm_pci_device_is_agp(dev))
                        getparam->value = 0;
                else
@@ -270,8 +280,8 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
                return nouveau_abi16_put(abi16, -EINVAL);
 
        /* allocate "abi16 channel" data and make up a handle for it */
-       init->channel = ffsll(~abi16->handles);
-       if (!init->channel--)
+       init->channel = __ffs64(~abi16->handles);
+       if (~abi16->handles == 0)
                return nouveau_abi16_put(abi16, -ENOSPC);
 
        chan = kzalloc(sizeof(*chan), GFP_KERNEL);
@@ -280,7 +290,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
 
        INIT_LIST_HEAD(&chan->notifiers);
        list_add(&chan->head, &abi16->channels);
-       abi16->handles |= (1 << init->channel);
+       abi16->handles |= (1ULL << init->channel);
 
        /* create channel object and initialise dma and fence management */
        ret = nouveau_channel_new(drm, cli, NVDRM_DEVICE, NVDRM_CHAN |
index 2953c4e..51666da 100644 (file)
@@ -75,7 +75,7 @@ nouveau_agp_enabled(struct nouveau_drm *drm)
 {
        struct drm_device *dev = drm->dev;
 
-       if (!drm_pci_device_is_agp(dev) || !dev->agp)
+       if (!dev->pdev || !drm_pci_device_is_agp(dev) || !dev->agp)
                return false;
 
        if (drm->agp.stat == UNKNOWN) {
index 4c3feaa..8268a4c 100644 (file)
@@ -1474,9 +1474,12 @@ parse_dcb20_entry(struct drm_device *dev, struct dcb_table *dcb,
                case 0:
                        entry->dpconf.link_bw = 162000;
                        break;
-               default:
+               case 1:
                        entry->dpconf.link_bw = 270000;
                        break;
+               default:
+                       entry->dpconf.link_bw = 540000;
+                       break;
                }
                switch ((conf & 0x0f000000) >> 24) {
                case 0xf:
@@ -2069,6 +2072,10 @@ nouveau_bios_init(struct drm_device *dev)
        struct nvbios *bios = &drm->vbios;
        int ret;
 
+       /* only relevant for PCI devices */
+       if (!dev->pdev)
+               return 0;
+
        if (!NVInitVBIOS(dev))
                return -ENODEV;
 
index 4aed171..b6dc85c 100644 (file)
@@ -1255,7 +1255,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
                /* fallthrough, tiled memory */
        case TTM_PL_VRAM:
                mem->bus.offset = mem->start << PAGE_SHIFT;
-               mem->bus.base = pci_resource_start(dev->pdev, 1);
+               mem->bus.base = nv_device_resource_start(nouveau_dev(dev), 1);
                mem->bus.is_iomem = true;
                if (nv_device(drm->device)->card_type >= NV_50) {
                        struct nouveau_bar *bar = nouveau_bar(drm->device);
@@ -1293,7 +1293,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
        struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct nouveau_device *device = nv_device(drm->device);
-       u32 mappable = pci_resource_len(device->pdev, 1) >> PAGE_SHIFT;
+       u32 mappable = nv_device_resource_len(device, 1) >> PAGE_SHIFT;
        int ret;
 
        /* as long as the bo isn't in vram, and isn't tiled, we've got
@@ -1331,6 +1331,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
 {
        struct ttm_dma_tt *ttm_dma = (void *)ttm;
        struct nouveau_drm *drm;
+       struct nouveau_device *device;
        struct drm_device *dev;
        unsigned i;
        int r;
@@ -1348,6 +1349,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
        }
 
        drm = nouveau_bdev(ttm->bdev);
+       device = nv_device(drm->device);
        dev = drm->dev;
 
 #if __OS_HAS_AGP
@@ -1368,13 +1370,12 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
        }
 
        for (i = 0; i < ttm->num_pages; i++) {
-               ttm_dma->dma_address[i] = pci_map_page(dev->pdev, ttm->pages[i],
-                                                  0, PAGE_SIZE,
-                                                  PCI_DMA_BIDIRECTIONAL);
-               if (pci_dma_mapping_error(dev->pdev, ttm_dma->dma_address[i])) {
+               ttm_dma->dma_address[i] = nv_device_map_page(device,
+                                                            ttm->pages[i]);
+               if (!ttm_dma->dma_address[i]) {
                        while (--i) {
-                               pci_unmap_page(dev->pdev, ttm_dma->dma_address[i],
-                                              PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+                               nv_device_unmap_page(device,
+                                                    ttm_dma->dma_address[i]);
                                ttm_dma->dma_address[i] = 0;
                        }
                        ttm_pool_unpopulate(ttm);
@@ -1389,6 +1390,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
 {
        struct ttm_dma_tt *ttm_dma = (void *)ttm;
        struct nouveau_drm *drm;
+       struct nouveau_device *device;
        struct drm_device *dev;
        unsigned i;
        bool slave = !!(ttm->page_flags & TTM_PAGE_FLAG_SG);
@@ -1397,6 +1399,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
                return;
 
        drm = nouveau_bdev(ttm->bdev);
+       device = nv_device(drm->device);
        dev = drm->dev;
 
 #if __OS_HAS_AGP
@@ -1415,8 +1418,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
 
        for (i = 0; i < ttm->num_pages; i++) {
                if (ttm_dma->dma_address[i]) {
-                       pci_unmap_page(dev->pdev, ttm_dma->dma_address[i],
-                                      PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
+                       nv_device_unmap_page(device, ttm_dma->dma_address[i]);
                }
        }
 
index cc5152b..ccb6b45 100644 (file)
@@ -154,7 +154,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nouveau_cli *cli,
                         * nfi why this exists, it came from the -nv ddx.
                         */
                        args.flags = NV_DMA_TARGET_PCI | NV_DMA_ACCESS_RDWR;
-                       args.start = pci_resource_start(device->pdev, 1);
+                       args.start = nv_device_resource_start(device, 1);
                        args.limit = args.start + limit;
                } else {
                        args.flags = NV_DMA_TARGET_VRAM | NV_DMA_ACCESS_RDWR;
index 1674882..d07ce02 100644 (file)
@@ -255,7 +255,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
        }
 
        ret = pm_runtime_get_sync(connector->dev->dev);
-       if (ret < 0)
+       if (ret < 0 && ret != -EACCES)
                return conn_status;
 
        i2c = nouveau_connector_ddc_detect(connector, &nv_encoder);
@@ -960,7 +960,8 @@ drm_conntype_from_dcb(enum dcb_connector_type dcb)
        case DCB_CONNECTOR_DP       : return DRM_MODE_CONNECTOR_DisplayPort;
        case DCB_CONNECTOR_eDP      : return DRM_MODE_CONNECTOR_eDP;
        case DCB_CONNECTOR_HDMI_0   :
-       case DCB_CONNECTOR_HDMI_1   : return DRM_MODE_CONNECTOR_HDMIA;
+       case DCB_CONNECTOR_HDMI_1   :
+       case DCB_CONNECTOR_HDMI_C   : return DRM_MODE_CONNECTOR_HDMIA;
        default:
                break;
        }
index 2401159..3ff030d 100644 (file)
@@ -105,7 +105,7 @@ nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
                if (retry) ndelay(crtc->linedur_ns);
        } while (retry--);
 
-       *hpos = calc(args.hblanks, args.hblanke, args.htotal, args.hline);
+       *hpos = args.hline;
        *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline);
        if (stime) *stime = ns_to_ktime(args.time[0]);
        if (etime) *etime = ns_to_ktime(args.time[1]);
@@ -419,6 +419,7 @@ int
 nouveau_display_create(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nouveau_dev(dev);
        struct nouveau_display *disp;
        int ret, gen;
 
@@ -459,7 +460,7 @@ nouveau_display_create(struct drm_device *dev)
        }
 
        dev->mode_config.funcs = &nouveau_mode_config_funcs;
-       dev->mode_config.fb_base = pci_resource_start(dev->pdev, 1);
+       dev->mode_config.fb_base = nv_device_resource_start(device, 1);
 
        dev->mode_config.min_width = 0;
        dev->mode_config.min_height = 0;
@@ -488,6 +489,7 @@ nouveau_display_create(struct drm_device *dev)
 
        if (drm->vbios.dcb.entries) {
                static const u16 oclass[] = {
+                       GM107_DISP_CLASS,
                        NVF0_DISP_CLASS,
                        NVE0_DISP_CLASS,
                        NVD0_DISP_CLASS,
@@ -569,7 +571,7 @@ nouveau_display_suspend(struct drm_device *dev)
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_framebuffer *nouveau_fb;
 
-               nouveau_fb = nouveau_framebuffer(crtc->fb);
+               nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
                if (!nouveau_fb || !nouveau_fb->nvbo)
                        continue;
 
@@ -596,7 +598,7 @@ nouveau_display_repin(struct drm_device *dev)
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                struct nouveau_framebuffer *nouveau_fb;
 
-               nouveau_fb = nouveau_framebuffer(crtc->fb);
+               nouveau_fb = nouveau_framebuffer(crtc->primary->fb);
                if (!nouveau_fb || !nouveau_fb->nvbo)
                        continue;
 
@@ -693,7 +695,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        const int swap_interval = (flags & DRM_MODE_PAGE_FLIP_ASYNC) ? 0 : 1;
        struct drm_device *dev = crtc->dev;
        struct nouveau_drm *drm = nouveau_drm(dev);
-       struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->fb)->nvbo;
+       struct nouveau_bo *old_bo = nouveau_framebuffer(crtc->primary->fb)->nvbo;
        struct nouveau_bo *new_bo = nouveau_framebuffer(fb)->nvbo;
        struct nouveau_page_flip_state *s;
        struct nouveau_channel *chan = drm->channel;
@@ -767,7 +769,7 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                goto fail_unreserve;
 
        /* Update the crtc struct and cleanup */
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
 
        nouveau_bo_fence(old_bo, fence);
        ttm_bo_unreserve(&old_bo->bo);
index 4ee702a..ddd8375 100644 (file)
@@ -33,6 +33,7 @@
 #include <core/client.h>
 #include <core/gpuobj.h>
 #include <core/class.h>
+#include <core/option.h>
 
 #include <engine/device.h>
 #include <engine/disp.h>
@@ -81,7 +82,7 @@ module_param_named(runpm, nouveau_runtime_pm, int, 0400);
 static struct drm_driver driver;
 
 static u64
-nouveau_name(struct pci_dev *pdev)
+nouveau_pci_name(struct pci_dev *pdev)
 {
        u64 name = (u64)pci_domain_nr(pdev->bus) << 32;
        name |= pdev->bus->number << 16;
@@ -89,15 +90,30 @@ nouveau_name(struct pci_dev *pdev)
        return name | PCI_FUNC(pdev->devfn);
 }
 
+static u64
+nouveau_platform_name(struct platform_device *platformdev)
+{
+       return platformdev->id;
+}
+
+static u64
+nouveau_name(struct drm_device *dev)
+{
+       if (dev->pdev)
+               return nouveau_pci_name(dev->pdev);
+       else
+               return nouveau_platform_name(dev->platformdev);
+}
+
 static int
-nouveau_cli_create(struct pci_dev *pdev, const char *name,
+nouveau_cli_create(u64 name, const char *sname,
                   int size, void **pcli)
 {
        struct nouveau_cli *cli;
        int ret;
 
        *pcli = NULL;
-       ret = nouveau_client_create_(name, nouveau_name(pdev), nouveau_config,
+       ret = nouveau_client_create_(sname, name, nouveau_config,
                                     nouveau_debug, size, pcli);
        cli = *pcli;
        if (ret) {
@@ -281,7 +297,8 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
        remove_conflicting_framebuffers(aper, "nouveaufb", boot);
        kfree(aper);
 
-       ret = nouveau_device_create(pdev, nouveau_name(pdev), pci_name(pdev),
+       ret = nouveau_device_create(pdev, NOUVEAU_BUS_PCI,
+                                   nouveau_pci_name(pdev), pci_name(pdev),
                                    nouveau_config, nouveau_debug, &device);
        if (ret)
                return ret;
@@ -300,22 +317,27 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
 #define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
 
 static void
-nouveau_get_hdmi_dev(struct drm_device *dev)
+nouveau_get_hdmi_dev(struct nouveau_drm *drm)
 {
-       struct nouveau_drm *drm = dev->dev_private;
-       struct pci_dev *pdev = dev->pdev;
+       struct pci_dev *pdev = drm->dev->pdev;
+
+       if (!pdev) {
+               DRM_INFO("not a PCI device; no HDMI\n");
+               drm->hdmi_device = NULL;
+               return;
+       }
 
        /* subfunction one is a hdmi audio device? */
        drm->hdmi_device = pci_get_bus_and_slot((unsigned int)pdev->bus->number,
                                                PCI_DEVFN(PCI_SLOT(pdev->devfn), 1));
 
        if (!drm->hdmi_device) {
-               DRM_INFO("hdmi device  not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1);
+               NV_DEBUG(drm, "hdmi device not found %d %d %d\n", pdev->bus->number, PCI_SLOT(pdev->devfn), 1);
                return;
        }
 
        if ((drm->hdmi_device->class >> 8) != PCI_CLASS_MULTIMEDIA_HD_AUDIO) {
-               DRM_INFO("possible hdmi device  not audio %d\n", drm->hdmi_device->class);
+               NV_DEBUG(drm, "possible hdmi device not audio %d\n", drm->hdmi_device->class);
                pci_dev_put(drm->hdmi_device);
                drm->hdmi_device = NULL;
                return;
@@ -330,22 +352,24 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
        struct nouveau_drm *drm;
        int ret;
 
-       ret = nouveau_cli_create(pdev, "DRM", sizeof(*drm), (void**)&drm);
+       ret = nouveau_cli_create(nouveau_name(dev), "DRM", sizeof(*drm),
+                                (void **)&drm);
        if (ret)
                return ret;
 
        dev->dev_private = drm;
        drm->dev = dev;
+       nouveau_client(drm)->debug = nouveau_dbgopt(nouveau_debug, "DRM");
 
        INIT_LIST_HEAD(&drm->clients);
        spin_lock_init(&drm->tile.lock);
 
-       nouveau_get_hdmi_dev(dev);
+       nouveau_get_hdmi_dev(drm);
 
        /* make sure AGP controller is in a consistent state before we
         * (possibly) execute vbios init tables (see nouveau_agp.h)
         */
-       if (drm_pci_device_is_agp(dev) && dev->agp) {
+       if (pdev && drm_pci_device_is_agp(dev) && dev->agp) {
                /* dummy device object, doesn't init anything, but allows
                 * agp code access to registers
                 */
@@ -486,13 +510,13 @@ nouveau_drm_remove(struct pci_dev *pdev)
 }
 
 static int
-nouveau_do_suspend(struct drm_device *dev)
+nouveau_do_suspend(struct drm_device *dev, bool runtime)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_cli *cli;
        int ret;
 
-       if (dev->mode_config.num_crtc) {
+       if (dev->mode_config.num_crtc && !runtime) {
                NV_INFO(drm, "suspending display...\n");
                ret = nouveau_display_suspend(dev);
                if (ret)
@@ -566,7 +590,7 @@ int nouveau_pmops_suspend(struct device *dev)
        if (drm_dev->mode_config.num_crtc)
                nouveau_fbcon_set_suspend(drm_dev, 1);
 
-       ret = nouveau_do_suspend(drm_dev);
+       ret = nouveau_do_suspend(drm_dev, false);
        if (ret)
                return ret;
 
@@ -646,7 +670,7 @@ static int nouveau_pmops_freeze(struct device *dev)
        if (drm_dev->mode_config.num_crtc)
                nouveau_fbcon_set_suspend(drm_dev, 1);
 
-       ret = nouveau_do_suspend(drm_dev);
+       ret = nouveau_do_suspend(drm_dev, false);
        return ret;
 }
 
@@ -671,7 +695,6 @@ static int nouveau_pmops_thaw(struct device *dev)
 static int
 nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
 {
-       struct pci_dev *pdev = dev->pdev;
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct nouveau_cli *cli;
        char name[32], tmpname[TASK_COMM_LEN];
@@ -679,13 +702,15 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
 
        /* need to bring up power immediately if opening device */
        ret = pm_runtime_get_sync(dev->dev);
-       if (ret < 0)
+       if (ret < 0 && ret != -EACCES)
                return ret;
 
        get_task_comm(tmpname, current);
        snprintf(name, sizeof(name), "%s[%d]", tmpname, pid_nr(fpriv->pid));
 
-       ret = nouveau_cli_create(pdev, name, sizeof(*cli), (void **)&cli);
+       ret = nouveau_cli_create(nouveau_name(dev), name, sizeof(*cli),
+                       (void **)&cli);
+
        if (ret)
                goto out_suspend;
 
@@ -762,7 +787,7 @@ long nouveau_drm_ioctl(struct file *filp,
        dev = file_priv->minor->dev;
 
        ret = pm_runtime_get_sync(dev->dev);
-       if (ret < 0)
+       if (ret < 0 && ret != -EACCES)
                return ret;
 
        ret = drm_ioctl(filp, cmd, arg);
@@ -882,7 +907,7 @@ static int nouveau_pmops_runtime_suspend(struct device *dev)
        drm_kms_helper_poll_disable(drm_dev);
        vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
        nouveau_switcheroo_optimus_dsm();
-       ret = nouveau_do_suspend(drm_dev);
+       ret = nouveau_do_suspend(drm_dev, true);
        pci_save_state(pdev);
        pci_disable_device(pdev);
        pci_set_power_state(pdev, PCI_D3cold);
@@ -908,8 +933,6 @@ static int nouveau_pmops_runtime_resume(struct device *dev)
        pci_set_master(pdev);
 
        ret = nouveau_do_resume(drm_dev);
-       if (drm_dev->mode_config.num_crtc)
-               nouveau_display_resume(drm_dev);
        drm_kms_helper_poll_enable(drm_dev);
        /* do magic */
        nv_mask(device, 0x88488, (1 << 25), (1 << 25));
@@ -980,6 +1003,25 @@ nouveau_drm_pci_driver = {
        .driver.pm = &nouveau_pm_ops,
 };
 
+int nouveau_drm_platform_probe(struct platform_device *pdev)
+{
+       struct nouveau_device *device;
+       int ret;
+
+       ret = nouveau_device_create(pdev, NOUVEAU_BUS_PLATFORM,
+                                   nouveau_platform_name(pdev),
+                                   dev_name(&pdev->dev), nouveau_config,
+                                   nouveau_debug, &device);
+
+       ret = drm_platform_init(&driver, pdev);
+       if (ret) {
+               nouveau_object_ref(NULL, (struct nouveau_object **)&device);
+               return ret;
+       }
+
+       return ret;
+}
+
 static int __init
 nouveau_drm_init(void)
 {
index 23ca7a5..7efbafa 100644 (file)
@@ -161,10 +161,7 @@ int nouveau_pmops_resume(struct device *);
 #define NV_ERROR(cli, fmt, args...) nv_error((cli), fmt, ##args)
 #define NV_WARN(cli, fmt, args...) nv_warn((cli), fmt, ##args)
 #define NV_INFO(cli, fmt, args...) nv_info((cli), fmt, ##args)
-#define NV_DEBUG(cli, fmt, args...) do {                                       \
-       if (drm_debug & DRM_UT_DRIVER)                                         \
-               nv_info((cli), fmt, ##args);                                   \
-} while (0)
+#define NV_DEBUG(cli, fmt, args...) nv_debug((cli), fmt, ##args)
 
 extern int nouveau_modeset;
 
index 7903e0e..64a42cf 100644 (file)
@@ -528,10 +528,10 @@ nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
        struct nouveau_drm *drm = nouveau_drm(dev);
        if (drm->fbcon) {
                console_lock();
-               if (state == 0)
+               if (state == 1)
                        nouveau_fbcon_save_disable_accel(dev);
                fb_set_suspend(drm->fbcon->helper.fbdev, state);
-               if (state == 1)
+               if (state == 0)
                        nouveau_fbcon_restore_accel(dev);
                console_unlock();
        }
index 27c3fd8..c90c0dc 100644 (file)
@@ -228,8 +228,6 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
        struct nouveau_bo *nvbo = NULL;
        int ret = 0;
 
-       drm->ttm.bdev.dev_mapping = drm->dev->dev_mapping;
-
        if (!pfb->memtype_valid(pfb, req->info.tile_flags)) {
                NV_ERROR(cli, "bad page flags: 0x%08x\n", req->info.tile_flags);
                return -EINVAL;
index 4aff04f..19fd767 100644 (file)
@@ -383,8 +383,9 @@ nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a,
        long value;
        int ret;
 
-       if (strict_strtol(buf, 10, &value) == -EINVAL)
-               return -EINVAL;
+       ret = kstrtol(buf, 10, &value);
+       if (ret)
+               return ret;
 
        ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value);
        if (ret)
@@ -587,18 +588,14 @@ nouveau_hwmon_init(struct drm_device *dev)
 
        /* set the default attributes */
        ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_default_attrgroup);
-       if (ret) {
-               if (ret)
-                       goto error;
-       }
+       if (ret)
+               goto error;
 
        /* if the card has a working thermal sensor */
        if (therm->temp_get(therm) >= 0) {
                ret = sysfs_create_group(&hwmon_dev->kobj, &hwmon_temp_attrgroup);
-               if (ret) {
-                       if (ret)
-                               goto error;
-               }
+               if (ret)
+                       goto error;
        }
 
        /* if the card has a pwm fan */
index 89201a1..75dda2b 100644 (file)
@@ -30,7 +30,7 @@
 static inline struct drm_device *
 drm_device(struct device *d)
 {
-       return pci_get_drvdata(to_pci_dev(d));
+       return dev_get_drvdata(d);
 }
 
 #define snappendf(p,r,f,a...) do {                                             \
@@ -132,9 +132,10 @@ nouveau_sysfs_fini(struct drm_device *dev)
 {
        struct nouveau_sysfs *sysfs = nouveau_sysfs(dev);
        struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
 
        if (sysfs->ctrl) {
-               device_remove_file(&dev->pdev->dev, &dev_attr_pstate);
+               device_remove_file(nv_device_base(device), &dev_attr_pstate);
                nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL);
        }
 
@@ -146,6 +147,7 @@ int
 nouveau_sysfs_init(struct drm_device *dev)
 {
        struct nouveau_drm *drm = nouveau_drm(dev);
+       struct nouveau_device *device = nv_device(drm->device);
        struct nouveau_sysfs *sysfs;
        int ret;
 
@@ -156,7 +158,7 @@ nouveau_sysfs_init(struct drm_device *dev)
        ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, NVDRM_CONTROL,
                                 NV_CONTROL_CLASS, NULL, 0, &sysfs->ctrl);
        if (ret == 0)
-               device_create_file(&dev->pdev->dev, &dev_attr_pstate);
+               device_create_file(nv_device_base(device), &dev_attr_pstate);
 
        return 0;
 }
index d45d50d..ab0228f 100644 (file)
@@ -354,21 +354,26 @@ int
 nouveau_ttm_init(struct nouveau_drm *drm)
 {
        struct drm_device *dev = drm->dev;
+       struct nouveau_device *device = nv_device(drm->device);
        u32 bits;
        int ret;
 
        bits = nouveau_vmmgr(drm->device)->dma_bits;
-       if ( drm->agp.stat == ENABLED ||
-           !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits)))
-               bits = 32;
-
-       ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
-       if (ret)
-               return ret;
-
-       ret = pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
-       if (ret)
-               pci_set_consistent_dma_mask(dev->pdev, DMA_BIT_MASK(32));
+       if (nv_device_is_pci(device)) {
+               if (drm->agp.stat == ENABLED ||
+                    !pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits)))
+                       bits = 32;
+
+               ret = pci_set_dma_mask(dev->pdev, DMA_BIT_MASK(bits));
+               if (ret)
+                       return ret;
+
+               ret = pci_set_consistent_dma_mask(dev->pdev,
+                                                 DMA_BIT_MASK(bits));
+               if (ret)
+                       pci_set_consistent_dma_mask(dev->pdev,
+                                                   DMA_BIT_MASK(32));
+       }
 
        ret = nouveau_ttm_global_init(drm);
        if (ret)
@@ -376,7 +381,9 @@ nouveau_ttm_init(struct nouveau_drm *drm)
 
        ret = ttm_bo_device_init(&drm->ttm.bdev,
                                  drm->ttm.bo_global_ref.ref.object,
-                                 &nouveau_bo_driver, DRM_FILE_PAGE_OFFSET,
+                                 &nouveau_bo_driver,
+                                 dev->anon_inode->i_mapping,
+                                 DRM_FILE_PAGE_OFFSET,
                                  bits <= 32 ? true : false);
        if (ret) {
                NV_ERROR(drm, "error initialising bo driver, %d\n", ret);
@@ -394,8 +401,8 @@ nouveau_ttm_init(struct nouveau_drm *drm)
                return ret;
        }
 
-       drm->ttm.mtrr = arch_phys_wc_add(pci_resource_start(dev->pdev, 1),
-                                        pci_resource_len(dev->pdev, 1));
+       drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(device, 1),
+                                        nv_device_resource_len(device, 1));
 
        /* GART init */
        if (drm->agp.stat != ENABLED) {
index 471347e..fb84da3 100644 (file)
@@ -84,6 +84,11 @@ nouveau_vga_init(struct nouveau_drm *drm)
 {
        struct drm_device *dev = drm->dev;
        bool runtime = false;
+
+       /* only relevant for PCI devices */
+       if (!dev->pdev)
+               return;
+
        vga_client_register(dev->pdev, dev, NULL, nouveau_vga_set_decode);
 
        if (nouveau_runtime_pm == 1)
index 2dccafc..58af547 100644 (file)
@@ -651,7 +651,7 @@ nv50_crtc_set_dither(struct nouveau_crtc *nv_crtc, bool update)
        nv_connector = nouveau_crtc_connector_get(nv_crtc);
        connector = &nv_connector->base;
        if (nv_connector->dithering_mode == DITHERING_MODE_AUTO) {
-               if (nv_crtc->base.fb->depth > connector->display_info.bpc * 3)
+               if (nv_crtc->base.primary->fb->depth > connector->display_info.bpc * 3)
                        mode = DITHERING_MODE_DYNAMIC2X2;
        } else {
                mode = nv_connector->dithering_mode;
@@ -785,7 +785,8 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
 
                if (update) {
                        nv50_display_flip_stop(crtc);
-                       nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
+                       nv50_display_flip_next(crtc, crtc->primary->fb,
+                                              NULL, 1);
                }
        }
 
@@ -1028,7 +1029,7 @@ nv50_crtc_commit(struct drm_crtc *crtc)
        }
 
        nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true);
-       nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
+       nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
 }
 
 static bool
@@ -1042,7 +1043,7 @@ nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
 static int
 nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb)
 {
-       struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->fb);
+       struct nouveau_framebuffer *nvfb = nouveau_framebuffer(crtc->primary->fb);
        struct nv50_head *head = nv50_head(crtc);
        int ret;
 
@@ -1139,7 +1140,7 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode,
        nv50_crtc_set_dither(nv_crtc, false);
        nv50_crtc_set_scale(nv_crtc, false);
        nv50_crtc_set_color_vibrance(nv_crtc, false);
-       nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, false);
+       nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false);
        return 0;
 }
 
@@ -1151,7 +1152,7 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
        int ret;
 
-       if (!crtc->fb) {
+       if (!crtc->primary->fb) {
                NV_DEBUG(drm, "No FB bound\n");
                return 0;
        }
@@ -1161,8 +1162,8 @@ nv50_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
                return ret;
 
        nv50_display_flip_stop(crtc);
-       nv50_crtc_set_image(nv_crtc, crtc->fb, x, y, true);
-       nv50_display_flip_next(crtc, crtc->fb, NULL, 1);
+       nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, true);
+       nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);
        return 0;
 }
 
index 4313bb0..355157e 100644 (file)
@@ -245,7 +245,7 @@ static int omap_crtc_mode_set(struct drm_crtc *crtc,
        copy_timings_drm_to_omap(&omap_crtc->timings, mode);
        omap_crtc->full_update = true;
 
-       return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
+       return omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16,
@@ -273,7 +273,7 @@ static int omap_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        struct drm_plane *plane = omap_crtc->plane;
        struct drm_display_mode *mode = &crtc->mode;
 
-       return omap_plane_mode_set(plane, crtc, crtc->fb,
+       return omap_plane_mode_set(plane, crtc, crtc->primary->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        x << 16, y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16,
@@ -308,14 +308,14 @@ static void page_flip_worker(struct work_struct *work)
        struct drm_gem_object *bo;
 
        mutex_lock(&crtc->mutex);
-       omap_plane_mode_set(omap_crtc->plane, crtc, crtc->fb,
+       omap_plane_mode_set(omap_crtc->plane, crtc, crtc->primary->fb,
                        0, 0, mode->hdisplay, mode->vdisplay,
                        crtc->x << 16, crtc->y << 16,
                        mode->hdisplay << 16, mode->vdisplay << 16,
                        vblank_cb, crtc);
        mutex_unlock(&crtc->mutex);
 
-       bo = omap_framebuffer_bo(crtc->fb, 0);
+       bo = omap_framebuffer_bo(crtc->primary->fb, 0);
        drm_gem_object_unreference_unlocked(bo);
 }
 
@@ -336,9 +336,10 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct omap_crtc *omap_crtc = to_omap_crtc(crtc);
+       struct drm_plane *primary = crtc->primary;
        struct drm_gem_object *bo;
 
-       DBG("%d -> %d (event=%p)", crtc->fb ? crtc->fb->base.id : -1,
+       DBG("%d -> %d (event=%p)", primary->fb ? primary->fb->base.id : -1,
                        fb->base.id, event);
 
        if (omap_crtc->old_fb) {
@@ -347,7 +348,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc,
        }
 
        omap_crtc->event = event;
-       crtc->fb = fb;
+       primary->fb = fb;
 
        /*
         * Hold a reference temporarily until the crtc is updated
index f466c4a..d2b8c49 100644 (file)
@@ -306,13 +306,14 @@ struct drm_connector *omap_framebuffer_get_next_connector(
        struct drm_connector *connector = from;
 
        if (!from)
-               return list_first_entry(connector_list, typeof(*from), head);
+               return list_first_entry_or_null(connector_list, typeof(*from),
+                                               head);
 
        list_for_each_entry_from(connector, connector_list, head) {
                if (connector != from) {
                        struct drm_encoder *encoder = connector->encoder;
                        struct drm_crtc *crtc = encoder ? encoder->crtc : NULL;
-                       if (crtc && crtc->fb == fb)
+                       if (crtc && crtc->primary->fb == fb)
                                return connector;
 
                }
index 5aec3e8..c8d9727 100644 (file)
@@ -153,24 +153,24 @@ static struct {
 static void evict_entry(struct drm_gem_object *obj,
                enum tiler_fmt fmt, struct usergart_entry *entry)
 {
-       if (obj->dev->dev_mapping) {
-               struct omap_gem_object *omap_obj = to_omap_bo(obj);
-               int n = usergart[fmt].height;
-               size_t size = PAGE_SIZE * n;
-               loff_t off = mmap_offset(obj) +
-                               (entry->obj_pgoff << PAGE_SHIFT);
-               const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
-               if (m > 1) {
-                       int i;
-                       /* if stride > than PAGE_SIZE then sparse mapping: */
-                       for (i = n; i > 0; i--) {
-                               unmap_mapping_range(obj->dev->dev_mapping,
-                                               off, PAGE_SIZE, 1);
-                               off += PAGE_SIZE * m;
-                       }
-               } else {
-                       unmap_mapping_range(obj->dev->dev_mapping, off, size, 1);
+       struct omap_gem_object *omap_obj = to_omap_bo(obj);
+       int n = usergart[fmt].height;
+       size_t size = PAGE_SIZE * n;
+       loff_t off = mmap_offset(obj) +
+                       (entry->obj_pgoff << PAGE_SHIFT);
+       const int m = 1 + ((omap_obj->width << fmt) / PAGE_SIZE);
+
+       if (m > 1) {
+               int i;
+               /* if stride > than PAGE_SIZE then sparse mapping: */
+               for (i = n; i > 0; i--) {
+                       unmap_mapping_range(obj->dev->anon_inode->i_mapping,
+                                           off, PAGE_SIZE, 1);
+                       off += PAGE_SIZE * m;
                }
+       } else {
+               unmap_mapping_range(obj->dev->anon_inode->i_mapping,
+                                   off, size, 1);
        }
 
        entry->obj = NULL;
index 3e0f13d..4ec874d 100644 (file)
@@ -16,4 +16,18 @@ config DRM_PANEL_SIMPLE
          that it can be automatically turned off when the panel goes into a
          low power state.
 
+config DRM_PANEL_LD9040
+       tristate "LD9040 RGB/SPI panel"
+       depends on DRM && DRM_PANEL
+       depends on OF
+       select SPI
+       select VIDEOMODE_HELPERS
+
+config DRM_PANEL_S6E8AA0
+       tristate "S6E8AA0 DSI video mode panel"
+       depends on DRM && DRM_PANEL
+       depends on OF
+       select DRM_MIPI_DSI
+       select VIDEOMODE_HELPERS
+
 endmenu
index af9dfa2..8b92921 100644 (file)
@@ -1 +1,3 @@
 obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
+obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o
+obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o
diff --git a/drivers/gpu/drm/panel/panel-ld9040.c b/drivers/gpu/drm/panel/panel-ld9040.c
new file mode 100644 (file)
index 0000000..1f1f837
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * ld9040 AMOLED LCD drm_panel driver.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ * Derived from drivers/video/backlight/ld9040.c
+ *
+ * Andrzej Hajda <a.hajda@samsung.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 <drm/drmP.h>
+#include <drm/drm_panel.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+#include <linux/spi/spi.h>
+
+#include <video/mipi_display.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+/* Manufacturer Command Set */
+#define MCS_MANPWR             0xb0
+#define MCS_ELVSS_ON           0xb1
+#define MCS_USER_SETTING       0xf0
+#define MCS_DISPCTL            0xf2
+#define MCS_GTCON              0xf7
+#define MCS_PANEL_CONDITION    0xf8
+#define MCS_GAMMA_SET1         0xf9
+#define MCS_GAMMA_CTRL         0xfb
+
+/* array of gamma tables for gamma value 2.2 */
+static u8 const ld9040_gammas[25][22] = {
+       { 0xf9, 0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30, 0x00, 0xaf, 0xc0,
+         0xb8, 0xcd, 0x00, 0x3d, 0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44 },
+       { 0xf9, 0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c, 0x00, 0xaf, 0xbf,
+         0xb6, 0xcb, 0x00, 0x4b, 0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52 },
+       { 0xf9, 0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41, 0x00, 0xb0, 0xbe,
+         0xb5, 0xc9, 0x00, 0x51, 0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57 },
+       { 0xf9, 0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46, 0x00, 0xb1, 0xbc,
+         0xb5, 0xc8, 0x00, 0x56, 0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d },
+       { 0xf9, 0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b, 0x00, 0xb3, 0xbc,
+         0xb4, 0xc7, 0x00, 0x5c, 0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62 },
+       { 0xf9, 0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f, 0x00, 0xb4, 0xbb,
+         0xb3, 0xc7, 0x00, 0x60, 0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67 },
+       { 0xf9, 0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53, 0x00, 0xb5, 0xbb,
+         0xb3, 0xc6, 0x00, 0x65, 0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c },
+       { 0xf9, 0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57, 0x00, 0xb5, 0xbb,
+         0xb0, 0xc5, 0x00, 0x6a, 0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70 },
+       { 0xf9, 0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b, 0x00, 0xb5, 0xba,
+         0xb1, 0xc4, 0x00, 0x6e, 0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75 },
+       { 0xf9, 0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f, 0x00, 0xb5, 0xba,
+         0xb0, 0xc3, 0x00, 0x72, 0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a },
+       { 0xf9, 0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62, 0x00, 0xb6, 0xba,
+         0xaf, 0xc3, 0x00, 0x76, 0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e },
+       { 0xf9, 0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65, 0x00, 0xb7, 0xb8,
+         0xaf, 0xc3, 0x00, 0x7a, 0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81 },
+       { 0xf9, 0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69, 0x00, 0xb8, 0xb9,
+         0xae, 0xc1, 0x00, 0x7f, 0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85 },
+       { 0xf9, 0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c, 0x00, 0xb8, 0xb8,
+         0xae, 0xc1, 0x00, 0x82, 0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89 },
+       { 0xf9, 0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f, 0x00, 0xb8, 0xb8,
+         0xad, 0xc0, 0x00, 0x86, 0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d },
+       { 0xf9, 0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72, 0x00, 0xb8, 0xb8,
+         0xac, 0xbf, 0x00, 0x8a, 0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91 },
+       { 0xf9, 0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75, 0x00, 0xb9, 0xb8,
+         0xab, 0xbe, 0x00, 0x8e, 0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94 },
+       { 0xf9, 0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77, 0x00, 0xb9, 0xb7,
+         0xab, 0xbe, 0x00, 0x90, 0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97 },
+       { 0xf9, 0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a, 0x00, 0xb9, 0xb7,
+         0xaa, 0xbd, 0x00, 0x94, 0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a },
+       { 0xf9, 0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d, 0x00, 0xb9, 0xb6,
+         0xaa, 0xbb, 0x00, 0x97, 0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d },
+       { 0xf9, 0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80, 0x00, 0xb8, 0xb6,
+         0xaa, 0xbc, 0x00, 0x9a, 0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0 },
+       { 0xf9, 0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84, 0x00, 0xb9, 0xb7,
+         0xa8, 0xbc, 0x00, 0x9d, 0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4 },
+       { 0xf9, 0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86, 0x00, 0xb8, 0xb5,
+         0xa8, 0xbc, 0x00, 0xa0, 0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7 },
+       { 0xf9, 0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89, 0x00, 0xb7, 0xb6,
+         0xa8, 0xba, 0x00, 0xa4, 0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa },
+       { 0xf9, 0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91, 0x00, 0xb2, 0xb4,
+         0xaa, 0xbb, 0x00, 0xac, 0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3 },
+};
+
+struct ld9040 {
+       struct device *dev;
+       struct drm_panel panel;
+
+       struct regulator_bulk_data supplies[2];
+       struct gpio_desc *reset_gpio;
+       u32 power_on_delay;
+       u32 reset_delay;
+       struct videomode vm;
+       u32 width_mm;
+       u32 height_mm;
+
+       int brightness;
+
+       /* This field is tested by functions directly accessing bus before
+        * transfer, transfer is skipped if it is set. In case of transfer
+        * failure or unexpected response the field is set to error value.
+        * Such construct allows to eliminate many checks in higher level
+        * functions.
+        */
+       int error;
+};
+
+#define panel_to_ld9040(p) container_of(p, struct ld9040, panel)
+
+static int ld9040_clear_error(struct ld9040 *ctx)
+{
+       int ret = ctx->error;
+
+       ctx->error = 0;
+       return ret;
+}
+
+static int ld9040_spi_write_word(struct ld9040 *ctx, u16 data)
+{
+       struct spi_device *spi = to_spi_device(ctx->dev);
+       struct spi_transfer xfer = {
+               .len            = 2,
+               .tx_buf         = &data,
+       };
+       struct spi_message msg;
+
+       spi_message_init(&msg);
+       spi_message_add_tail(&xfer, &msg);
+
+       return spi_sync(spi, &msg);
+}
+
+static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len)
+{
+       int ret = 0;
+
+       if (ctx->error < 0 || len == 0)
+               return;
+
+       dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", len, data);
+       ret = ld9040_spi_write_word(ctx, *data);
+
+       while (!ret && --len) {
+               ++data;
+               ret = ld9040_spi_write_word(ctx, *data | 0x100);
+       }
+
+       if (ret) {
+               dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len,
+                       data);
+               ctx->error = ret;
+       }
+
+       usleep_range(300, 310);
+}
+
+#define ld9040_dcs_write_seq_static(ctx, seq...) \
+({\
+       static const u8 d[] = { seq };\
+       ld9040_dcs_write(ctx, d, ARRAY_SIZE(d));\
+})
+
+static void ld9040_brightness_set(struct ld9040 *ctx)
+{
+       ld9040_dcs_write(ctx, ld9040_gammas[ctx->brightness],
+                        ARRAY_SIZE(ld9040_gammas[ctx->brightness]));
+
+       ld9040_dcs_write_seq_static(ctx, MCS_GAMMA_CTRL, 0x02, 0x5a);
+}
+
+static void ld9040_init(struct ld9040 *ctx)
+{
+       ld9040_dcs_write_seq_static(ctx, MCS_USER_SETTING, 0x5a, 0x5a);
+       ld9040_dcs_write_seq_static(ctx, MCS_PANEL_CONDITION,
+               0x05, 0x65, 0x96, 0x71, 0x7d, 0x19, 0x3b, 0x0d,
+               0x19, 0x7e, 0x0d, 0xe2, 0x00, 0x00, 0x7e, 0x7d,
+               0x07, 0x07, 0x20, 0x20, 0x20, 0x02, 0x02);
+       ld9040_dcs_write_seq_static(ctx, MCS_DISPCTL,
+               0x02, 0x08, 0x08, 0x10, 0x10);
+       ld9040_dcs_write_seq_static(ctx, MCS_MANPWR, 0x04);
+       ld9040_dcs_write_seq_static(ctx, MCS_ELVSS_ON, 0x0d, 0x00, 0x16);
+       ld9040_dcs_write_seq_static(ctx, MCS_GTCON, 0x09, 0x00, 0x00);
+       ld9040_brightness_set(ctx);
+       ld9040_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
+       ld9040_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
+}
+
+static int ld9040_power_on(struct ld9040 *ctx)
+{
+       int ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+       if (ret < 0)
+               return ret;
+
+       msleep(ctx->power_on_delay);
+       gpiod_set_value(ctx->reset_gpio, 0);
+       msleep(ctx->reset_delay);
+       gpiod_set_value(ctx->reset_gpio, 1);
+       msleep(ctx->reset_delay);
+
+       return 0;
+}
+
+static int ld9040_power_off(struct ld9040 *ctx)
+{
+       return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+}
+
+static int ld9040_disable(struct drm_panel *panel)
+{
+       struct ld9040 *ctx = panel_to_ld9040(panel);
+
+       msleep(120);
+       ld9040_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
+       ld9040_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
+       msleep(40);
+
+       ld9040_clear_error(ctx);
+
+       return ld9040_power_off(ctx);
+}
+
+static int ld9040_enable(struct drm_panel *panel)
+{
+       struct ld9040 *ctx = panel_to_ld9040(panel);
+       int ret;
+
+       ret = ld9040_power_on(ctx);
+       if (ret < 0)
+               return ret;
+
+       ld9040_init(ctx);
+
+       ret = ld9040_clear_error(ctx);
+
+       if (ret < 0)
+               ld9040_disable(panel);
+
+       return ret;
+}
+
+static int ld9040_get_modes(struct drm_panel *panel)
+{
+       struct drm_connector *connector = panel->connector;
+       struct ld9040 *ctx = panel_to_ld9040(panel);
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_create(connector->dev);
+       if (!mode) {
+               DRM_ERROR("failed to create a new display mode\n");
+               return 0;
+       }
+
+       drm_display_mode_from_videomode(&ctx->vm, mode);
+       mode->width_mm = ctx->width_mm;
+       mode->height_mm = ctx->height_mm;
+       connector->display_info.width_mm = mode->width_mm;
+       connector->display_info.height_mm = mode->height_mm;
+
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+       drm_mode_probed_add(connector, mode);
+
+       return 1;
+}
+
+static const struct drm_panel_funcs ld9040_drm_funcs = {
+       .disable = ld9040_disable,
+       .enable = ld9040_enable,
+       .get_modes = ld9040_get_modes,
+};
+
+static int ld9040_parse_dt(struct ld9040 *ctx)
+{
+       struct device *dev = ctx->dev;
+       struct device_node *np = dev->of_node;
+       int ret;
+
+       ret = of_get_videomode(np, &ctx->vm, 0);
+       if (ret < 0)
+               return ret;
+
+       of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay);
+       of_property_read_u32(np, "reset-delay", &ctx->reset_delay);
+       of_property_read_u32(np, "panel-width-mm", &ctx->width_mm);
+       of_property_read_u32(np, "panel-height-mm", &ctx->height_mm);
+
+       return 0;
+}
+
+static int ld9040_probe(struct spi_device *spi)
+{
+       struct device *dev = &spi->dev;
+       struct ld9040 *ctx;
+       int ret;
+
+       ctx = devm_kzalloc(dev, sizeof(struct ld9040), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       spi_set_drvdata(spi, ctx);
+
+       ctx->dev = dev;
+       ctx->brightness = ARRAY_SIZE(ld9040_gammas) - 1;
+
+       ret = ld9040_parse_dt(ctx);
+       if (ret < 0)
+               return ret;
+
+       ctx->supplies[0].supply = "vdd3";
+       ctx->supplies[1].supply = "vci";
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+                                     ctx->supplies);
+       if (ret < 0)
+               return ret;
+
+       ctx->reset_gpio = devm_gpiod_get(dev, "reset");
+       if (IS_ERR(ctx->reset_gpio)) {
+               dev_err(dev, "cannot get reset-gpios %ld\n",
+                       PTR_ERR(ctx->reset_gpio));
+               return PTR_ERR(ctx->reset_gpio);
+       }
+       ret = gpiod_direction_output(ctx->reset_gpio, 1);
+       if (ret < 0) {
+               dev_err(dev, "cannot configure reset-gpios %d\n", ret);
+               return ret;
+       }
+
+       spi->bits_per_word = 9;
+       ret = spi_setup(spi);
+       if (ret < 0) {
+               dev_err(dev, "spi setup failed.\n");
+               return ret;
+       }
+
+       drm_panel_init(&ctx->panel);
+       ctx->panel.dev = dev;
+       ctx->panel.funcs = &ld9040_drm_funcs;
+
+       return drm_panel_add(&ctx->panel);
+}
+
+static int ld9040_remove(struct spi_device *spi)
+{
+       struct ld9040 *ctx = spi_get_drvdata(spi);
+
+       ld9040_power_off(ctx);
+       drm_panel_remove(&ctx->panel);
+
+       return 0;
+}
+
+static struct of_device_id ld9040_of_match[] = {
+       { .compatible = "samsung,ld9040" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ld9040_of_match);
+
+static struct spi_driver ld9040_driver = {
+       .probe          = ld9040_probe,
+       .remove         = ld9040_remove,
+       .driver = {
+               .name   = "ld9040",
+               .owner  = THIS_MODULE,
+               .of_match_table = ld9040_of_match,
+       },
+};
+module_spi_driver(ld9040_driver);
+
+MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
+MODULE_DESCRIPTION("ld9040 LCD Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/panel/panel-s6e8aa0.c b/drivers/gpu/drm/panel/panel-s6e8aa0.c
new file mode 100644 (file)
index 0000000..35941d2
--- /dev/null
@@ -0,0 +1,1069 @@
+/*
+ * MIPI-DSI based s6e8aa0 AMOLED LCD 5.3 inch panel driver.
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd
+ *
+ * Inki Dae, <inki.dae@samsung.com>
+ * Donghwa Lee, <dh09.lee@samsung.com>
+ * Joongmock Shin <jmock.shin@samsung.com>
+ * Eunchul Kim <chulspro.kim@samsung.com>
+ * Tomasz Figa <t.figa@samsung.com>
+ * Andrzej Hajda <a.hajda@samsung.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 <drm/drmP.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+#define LDI_MTP_LENGTH                 24
+#define GAMMA_LEVEL_NUM                        25
+#define GAMMA_TABLE_LEN                        26
+
+#define PANELCTL_SS_MASK               (1 << 5)
+#define PANELCTL_SS_1_800              (0 << 5)
+#define PANELCTL_SS_800_1              (1 << 5)
+#define PANELCTL_GTCON_MASK            (7 << 2)
+#define PANELCTL_GTCON_110             (6 << 2)
+#define PANELCTL_GTCON_111             (7 << 2)
+
+#define PANELCTL_CLK1_CON_MASK         (7 << 3)
+#define PANELCTL_CLK1_000              (0 << 3)
+#define PANELCTL_CLK1_001              (1 << 3)
+#define PANELCTL_CLK2_CON_MASK         (7 << 0)
+#define PANELCTL_CLK2_000              (0 << 0)
+#define PANELCTL_CLK2_001              (1 << 0)
+
+#define PANELCTL_INT1_CON_MASK         (7 << 3)
+#define PANELCTL_INT1_000              (0 << 3)
+#define PANELCTL_INT1_001              (1 << 3)
+#define PANELCTL_INT2_CON_MASK         (7 << 0)
+#define PANELCTL_INT2_000              (0 << 0)
+#define PANELCTL_INT2_001              (1 << 0)
+
+#define PANELCTL_BICTL_CON_MASK                (7 << 3)
+#define PANELCTL_BICTL_000             (0 << 3)
+#define PANELCTL_BICTL_001             (1 << 3)
+#define PANELCTL_BICTLB_CON_MASK       (7 << 0)
+#define PANELCTL_BICTLB_000            (0 << 0)
+#define PANELCTL_BICTLB_001            (1 << 0)
+
+#define PANELCTL_EM_CLK1_CON_MASK      (7 << 3)
+#define PANELCTL_EM_CLK1_110           (6 << 3)
+#define PANELCTL_EM_CLK1_111           (7 << 3)
+#define PANELCTL_EM_CLK1B_CON_MASK     (7 << 0)
+#define PANELCTL_EM_CLK1B_110          (6 << 0)
+#define PANELCTL_EM_CLK1B_111          (7 << 0)
+
+#define PANELCTL_EM_CLK2_CON_MASK      (7 << 3)
+#define PANELCTL_EM_CLK2_110           (6 << 3)
+#define PANELCTL_EM_CLK2_111           (7 << 3)
+#define PANELCTL_EM_CLK2B_CON_MASK     (7 << 0)
+#define PANELCTL_EM_CLK2B_110          (6 << 0)
+#define PANELCTL_EM_CLK2B_111          (7 << 0)
+
+#define PANELCTL_EM_INT1_CON_MASK      (7 << 3)
+#define PANELCTL_EM_INT1_000           (0 << 3)
+#define PANELCTL_EM_INT1_001           (1 << 3)
+#define PANELCTL_EM_INT2_CON_MASK      (7 << 0)
+#define PANELCTL_EM_INT2_000           (0 << 0)
+#define PANELCTL_EM_INT2_001           (1 << 0)
+
+#define AID_DISABLE                    (0x4)
+#define AID_1                          (0x5)
+#define AID_2                          (0x6)
+#define AID_3                          (0x7)
+
+typedef u8 s6e8aa0_gamma_table[GAMMA_TABLE_LEN];
+
+struct s6e8aa0_variant {
+       u8 version;
+       const s6e8aa0_gamma_table *gamma_tables;
+};
+
+struct s6e8aa0 {
+       struct device *dev;
+       struct drm_panel panel;
+
+       struct regulator_bulk_data supplies[2];
+       struct gpio_desc *reset_gpio;
+       u32 power_on_delay;
+       u32 reset_delay;
+       u32 init_delay;
+       bool flip_horizontal;
+       bool flip_vertical;
+       struct videomode vm;
+       u32 width_mm;
+       u32 height_mm;
+
+       u8 version;
+       u8 id;
+       const struct s6e8aa0_variant *variant;
+       int brightness;
+
+       /* This field is tested by functions directly accessing DSI bus before
+        * transfer, transfer is skipped if it is set. In case of transfer
+        * failure or unexpected response the field is set to error value.
+        * Such construct allows to eliminate many checks in higher level
+        * functions.
+        */
+       int error;
+};
+
+#define panel_to_s6e8aa0(p) container_of(p, struct s6e8aa0, panel)
+
+static int s6e8aa0_clear_error(struct s6e8aa0 *ctx)
+{
+       int ret = ctx->error;
+
+       ctx->error = 0;
+       return ret;
+}
+
+static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       int ret;
+
+       if (ctx->error < 0)
+               return;
+
+       ret = mipi_dsi_dcs_write(dsi, dsi->channel, data, len);
+       if (ret < 0) {
+               dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len,
+                       data);
+               ctx->error = ret;
+       }
+}
+
+static int s6e8aa0_dcs_read(struct s6e8aa0 *ctx, u8 cmd, void *data, size_t len)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       int ret;
+
+       if (ctx->error < 0)
+               return ctx->error;
+
+       ret = mipi_dsi_dcs_read(dsi, dsi->channel, cmd, data, len);
+       if (ret < 0) {
+               dev_err(ctx->dev, "error %d reading dcs seq(%#x)\n", ret, cmd);
+               ctx->error = ret;
+       }
+
+       return ret;
+}
+
+#define s6e8aa0_dcs_write_seq(ctx, seq...) \
+({\
+       const u8 d[] = { seq };\
+       BUILD_BUG_ON_MSG(ARRAY_SIZE(d) > 64, "DCS sequence too big for stack");\
+       s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\
+})
+
+#define s6e8aa0_dcs_write_seq_static(ctx, seq...) \
+({\
+       static const u8 d[] = { seq };\
+       s6e8aa0_dcs_write(ctx, d, ARRAY_SIZE(d));\
+})
+
+static void s6e8aa0_apply_level_1_key(struct s6e8aa0 *ctx)
+{
+       s6e8aa0_dcs_write_seq_static(ctx, 0xf0, 0x5a, 0x5a);
+}
+
+static void s6e8aa0_panel_cond_set_v142(struct s6e8aa0 *ctx)
+{
+       static const u8 aids[] = {
+               0x04, 0x04, 0x04, 0x04, 0x04, 0x60, 0x80, 0xA0
+       };
+       u8 aid = aids[ctx->id >> 5];
+       u8 cfg = 0x3d;
+       u8 clk_con = 0xc8;
+       u8 int_con = 0x08;
+       u8 bictl_con = 0x48;
+       u8 em_clk1_con = 0xff;
+       u8 em_clk2_con = 0xff;
+       u8 em_int_con = 0xc8;
+
+       if (ctx->flip_vertical) {
+               /* GTCON */
+               cfg &= ~(PANELCTL_GTCON_MASK);
+               cfg |= (PANELCTL_GTCON_110);
+       }
+
+       if (ctx->flip_horizontal) {
+               /* SS */
+               cfg &= ~(PANELCTL_SS_MASK);
+               cfg |= (PANELCTL_SS_1_800);
+       }
+
+       if (ctx->flip_horizontal || ctx->flip_vertical) {
+               /* CLK1,2_CON */
+               clk_con &= ~(PANELCTL_CLK1_CON_MASK |
+                       PANELCTL_CLK2_CON_MASK);
+               clk_con |= (PANELCTL_CLK1_000 | PANELCTL_CLK2_001);
+
+               /* INT1,2_CON */
+               int_con &= ~(PANELCTL_INT1_CON_MASK |
+                       PANELCTL_INT2_CON_MASK);
+               int_con |= (PANELCTL_INT1_000 | PANELCTL_INT2_001);
+
+               /* BICTL,B_CON */
+               bictl_con &= ~(PANELCTL_BICTL_CON_MASK |
+                       PANELCTL_BICTLB_CON_MASK);
+               bictl_con |= (PANELCTL_BICTL_000 |
+                       PANELCTL_BICTLB_001);
+
+               /* EM_CLK1,1B_CON */
+               em_clk1_con &= ~(PANELCTL_EM_CLK1_CON_MASK |
+                       PANELCTL_EM_CLK1B_CON_MASK);
+               em_clk1_con |= (PANELCTL_EM_CLK1_110 |
+                       PANELCTL_EM_CLK1B_110);
+
+               /* EM_CLK2,2B_CON */
+               em_clk2_con &= ~(PANELCTL_EM_CLK2_CON_MASK |
+                       PANELCTL_EM_CLK2B_CON_MASK);
+               em_clk2_con |= (PANELCTL_EM_CLK2_110 |
+                       PANELCTL_EM_CLK2B_110);
+
+               /* EM_INT1,2_CON */
+               em_int_con &= ~(PANELCTL_EM_INT1_CON_MASK |
+                       PANELCTL_EM_INT2_CON_MASK);
+               em_int_con |= (PANELCTL_EM_INT1_000 |
+                       PANELCTL_EM_INT2_001);
+       }
+
+       s6e8aa0_dcs_write_seq(ctx,
+               0xf8, cfg, 0x35, 0x00, 0x00, 0x00, 0x93, 0x00,
+               0x3c, 0x78, 0x08, 0x27, 0x7d, 0x3f, 0x00, 0x00,
+               0x00, 0x20, aid, 0x08, 0x6e, 0x00, 0x00, 0x00,
+               0x02, 0x07, 0x07, 0x23, 0x23, 0xc0, clk_con, int_con,
+               bictl_con, 0xc1, 0x00, 0xc1, em_clk1_con, em_clk2_con,
+               em_int_con);
+}
+
+static void s6e8aa0_panel_cond_set(struct s6e8aa0 *ctx)
+{
+       if (ctx->version < 142)
+               s6e8aa0_dcs_write_seq_static(ctx,
+                       0xf8, 0x19, 0x35, 0x00, 0x00, 0x00, 0x94, 0x00,
+                       0x3c, 0x78, 0x10, 0x27, 0x08, 0x6e, 0x00, 0x00,
+                       0x00, 0x00, 0x04, 0x08, 0x6e, 0x00, 0x00, 0x00,
+                       0x00, 0x07, 0x07, 0x23, 0x6e, 0xc0, 0xc1, 0x01,
+                       0x81, 0xc1, 0x00, 0xc3, 0xf6, 0xf6, 0xc1
+               );
+       else
+               s6e8aa0_panel_cond_set_v142(ctx);
+}
+
+static void s6e8aa0_display_condition_set(struct s6e8aa0 *ctx)
+{
+       s6e8aa0_dcs_write_seq_static(ctx, 0xf2, 0x80, 0x03, 0x0d);
+}
+
+static void s6e8aa0_etc_source_control(struct s6e8aa0 *ctx)
+{
+       s6e8aa0_dcs_write_seq_static(ctx, 0xf6, 0x00, 0x02, 0x00);
+}
+
+static void s6e8aa0_etc_pentile_control(struct s6e8aa0 *ctx)
+{
+       static const u8 pent32[] = {
+               0xb6, 0x0c, 0x02, 0x03, 0x32, 0xc0, 0x44, 0x44, 0xc0, 0x00
+       };
+
+       static const u8 pent142[] = {
+               0xb6, 0x0c, 0x02, 0x03, 0x32, 0xff, 0x44, 0x44, 0xc0, 0x00
+       };
+
+       if (ctx->version < 142)
+               s6e8aa0_dcs_write(ctx, pent32, ARRAY_SIZE(pent32));
+       else
+               s6e8aa0_dcs_write(ctx, pent142, ARRAY_SIZE(pent142));
+}
+
+static void s6e8aa0_etc_power_control(struct s6e8aa0 *ctx)
+{
+       static const u8 pwr142[] = {
+               0xf4, 0xcf, 0x0a, 0x12, 0x10, 0x1e, 0x33, 0x02
+       };
+
+       static const u8 pwr32[] = {
+               0xf4, 0xcf, 0x0a, 0x15, 0x10, 0x19, 0x33, 0x02
+       };
+
+       if (ctx->version < 142)
+               s6e8aa0_dcs_write(ctx, pwr32, ARRAY_SIZE(pwr32));
+       else
+               s6e8aa0_dcs_write(ctx, pwr142, ARRAY_SIZE(pwr142));
+}
+
+static void s6e8aa0_etc_elvss_control(struct s6e8aa0 *ctx)
+{
+       u8 id = ctx->id ? 0 : 0x95;
+
+       s6e8aa0_dcs_write_seq(ctx, 0xb1, 0x04, id);
+}
+
+static void s6e8aa0_elvss_nvm_set_v142(struct s6e8aa0 *ctx)
+{
+       u8 br;
+
+       switch (ctx->brightness) {
+       case 0 ... 6: /* 30cd ~ 100cd */
+               br = 0xdf;
+               break;
+       case 7 ... 11: /* 120cd ~ 150cd */
+               br = 0xdd;
+               break;
+       case 12 ... 15: /* 180cd ~ 210cd */
+       default:
+               br = 0xd9;
+               break;
+       case 16 ... 24: /* 240cd ~ 300cd */
+               br = 0xd0;
+               break;
+       }
+
+       s6e8aa0_dcs_write_seq(ctx, 0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e,
+               0xc4, 0x0f, 0x40, 0x41, br, 0x00, 0x60, 0x19);
+}
+
+static void s6e8aa0_elvss_nvm_set(struct s6e8aa0 *ctx)
+{
+       if (ctx->version < 142)
+               s6e8aa0_dcs_write_seq_static(ctx,
+                       0xd9, 0x14, 0x40, 0x0c, 0xcb, 0xce, 0x6e, 0xc4, 0x07,
+                       0x40, 0x41, 0xc1, 0x00, 0x60, 0x19);
+       else
+               s6e8aa0_elvss_nvm_set_v142(ctx);
+};
+
+static void s6e8aa0_apply_level_2_key(struct s6e8aa0 *ctx)
+{
+       s6e8aa0_dcs_write_seq_static(ctx, 0xfc, 0x5a, 0x5a);
+}
+
+static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v142[GAMMA_LEVEL_NUM] = {
+       {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0x62, 0x55, 0x55,
+               0xaf, 0xb1, 0xb1, 0xbd, 0xce, 0xb7, 0x9a, 0xb1,
+               0x90, 0xb2, 0xc4, 0xae, 0x00, 0x60, 0x00, 0x40,
+               0x00, 0x70,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0x74, 0x68, 0x69,
+               0xb8, 0xc1, 0xb7, 0xbd, 0xcd, 0xb8, 0x93, 0xab,
+               0x88, 0xb4, 0xc4, 0xb1, 0x00, 0x6b, 0x00, 0x4d,
+               0x00, 0x7d,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0x95, 0x8a, 0x89,
+               0xb4, 0xc6, 0xb2, 0xc5, 0xd2, 0xbf, 0x90, 0xa8,
+               0x85, 0xb5, 0xc4, 0xb3, 0x00, 0x7b, 0x00, 0x5d,
+               0x00, 0x8f,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9f, 0x98, 0x92,
+               0xb3, 0xc4, 0xb0, 0xbc, 0xcc, 0xb4, 0x91, 0xa6,
+               0x87, 0xb5, 0xc5, 0xb4, 0x00, 0x87, 0x00, 0x6a,
+               0x00, 0x9e,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0x99, 0x93, 0x8b,
+               0xb2, 0xc2, 0xb0, 0xbd, 0xce, 0xb4, 0x90, 0xa6,
+               0x87, 0xb3, 0xc3, 0xb2, 0x00, 0x8d, 0x00, 0x70,
+               0x00, 0xa4,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xa5, 0x99,
+               0xb2, 0xc2, 0xb0, 0xbb, 0xcd, 0xb1, 0x93, 0xa7,
+               0x8a, 0xb2, 0xc1, 0xb0, 0x00, 0x92, 0x00, 0x75,
+               0x00, 0xaa,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xa0, 0x93,
+               0xb6, 0xc4, 0xb4, 0xb5, 0xc8, 0xaa, 0x94, 0xa9,
+               0x8c, 0xb2, 0xc0, 0xb0, 0x00, 0x97, 0x00, 0x7a,
+               0x00, 0xaf,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xa7, 0x96,
+               0xb3, 0xc2, 0xb0, 0xba, 0xcb, 0xb0, 0x94, 0xa8,
+               0x8c, 0xb0, 0xbf, 0xaf, 0x00, 0x9f, 0x00, 0x83,
+               0x00, 0xb9,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9d, 0xa2, 0x90,
+               0xb6, 0xc5, 0xb3, 0xb8, 0xc9, 0xae, 0x94, 0xa8,
+               0x8d, 0xaf, 0xbd, 0xad, 0x00, 0xa4, 0x00, 0x88,
+               0x00, 0xbf,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xac, 0x97,
+               0xb4, 0xc4, 0xb1, 0xbb, 0xcb, 0xb2, 0x93, 0xa7,
+               0x8d, 0xae, 0xbc, 0xad, 0x00, 0xa7, 0x00, 0x8c,
+               0x00, 0xc3,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa2, 0xa9, 0x93,
+               0xb6, 0xc5, 0xb2, 0xba, 0xc9, 0xb0, 0x93, 0xa7,
+               0x8d, 0xae, 0xbb, 0xac, 0x00, 0xab, 0x00, 0x90,
+               0x00, 0xc8,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0x9e, 0xa6, 0x8f,
+               0xb7, 0xc6, 0xb3, 0xb8, 0xc8, 0xb0, 0x93, 0xa6,
+               0x8c, 0xae, 0xbb, 0xad, 0x00, 0xae, 0x00, 0x93,
+               0x00, 0xcc,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb4, 0x9c,
+               0xb3, 0xc3, 0xaf, 0xb7, 0xc7, 0xaf, 0x93, 0xa6,
+               0x8c, 0xaf, 0xbc, 0xad, 0x00, 0xb1, 0x00, 0x97,
+               0x00, 0xcf,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa6, 0xb1, 0x98,
+               0xb1, 0xc2, 0xab, 0xba, 0xc9, 0xb2, 0x93, 0xa6,
+               0x8d, 0xae, 0xba, 0xab, 0x00, 0xb5, 0x00, 0x9b,
+               0x00, 0xd4,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xae, 0x94,
+               0xb2, 0xc3, 0xac, 0xbb, 0xca, 0xb4, 0x91, 0xa4,
+               0x8a, 0xae, 0xba, 0xac, 0x00, 0xb8, 0x00, 0x9e,
+               0x00, 0xd8,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xab, 0xb7, 0x9c,
+               0xae, 0xc0, 0xa9, 0xba, 0xc9, 0xb3, 0x92, 0xa5,
+               0x8b, 0xad, 0xb9, 0xab, 0x00, 0xbb, 0x00, 0xa1,
+               0x00, 0xdc,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb4, 0x97,
+               0xb0, 0xc1, 0xaa, 0xb9, 0xc8, 0xb2, 0x92, 0xa5,
+               0x8c, 0xae, 0xb9, 0xab, 0x00, 0xbe, 0x00, 0xa4,
+               0x00, 0xdf,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94,
+               0xb0, 0xc2, 0xab, 0xbb, 0xc9, 0xb3, 0x91, 0xa4,
+               0x8b, 0xad, 0xb8, 0xaa, 0x00, 0xc1, 0x00, 0xa8,
+               0x00, 0xe2,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa3, 0xb0, 0x94,
+               0xae, 0xbf, 0xa8, 0xb9, 0xc8, 0xb3, 0x92, 0xa4,
+               0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xc4, 0x00, 0xab,
+               0x00, 0xe6,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb6, 0x98,
+               0xaf, 0xc0, 0xa8, 0xb8, 0xc7, 0xb2, 0x93, 0xa5,
+               0x8d, 0xad, 0xb7, 0xa9, 0x00, 0xc7, 0x00, 0xae,
+               0x00, 0xe9,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95,
+               0xaf, 0xc1, 0xa9, 0xb9, 0xc8, 0xb3, 0x92, 0xa4,
+               0x8b, 0xad, 0xb7, 0xaa, 0x00, 0xc9, 0x00, 0xb0,
+               0x00, 0xec,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb3, 0x95,
+               0xac, 0xbe, 0xa6, 0xbb, 0xc9, 0xb4, 0x90, 0xa3,
+               0x8a, 0xad, 0xb7, 0xa9, 0x00, 0xcc, 0x00, 0xb4,
+               0x00, 0xf0,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa0, 0xb0, 0x91,
+               0xae, 0xc0, 0xa6, 0xba, 0xc8, 0xb4, 0x91, 0xa4,
+               0x8b, 0xad, 0xb7, 0xa9, 0x00, 0xcf, 0x00, 0xb7,
+               0x00, 0xf3,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa7, 0xb8, 0x98,
+               0xab, 0xbd, 0xa4, 0xbb, 0xc9, 0xb5, 0x91, 0xa3,
+               0x8b, 0xac, 0xb6, 0xa8, 0x00, 0xd1, 0x00, 0xb9,
+               0x00, 0xf6,
+       }, {
+               0xfa, 0x01, 0x71, 0x31, 0x7b, 0xa4, 0xb5, 0x95,
+               0xa9, 0xbc, 0xa1, 0xbb, 0xc9, 0xb5, 0x91, 0xa3,
+               0x8a, 0xad, 0xb6, 0xa8, 0x00, 0xd6, 0x00, 0xbf,
+               0x00, 0xfc,
+       },
+};
+
+static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v96[GAMMA_LEVEL_NUM] = {
+       {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
+               0xdf, 0x1f, 0xd7, 0xdc, 0xb7, 0xe1, 0xc0, 0xaf,
+               0xc4, 0xd2, 0xd0, 0xcf, 0x00, 0x4d, 0x00, 0x40,
+               0x00, 0x5f,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
+               0xd5, 0x35, 0xcf, 0xdc, 0xc1, 0xe1, 0xbf, 0xb3,
+               0xc1, 0xd2, 0xd1, 0xce, 0x00, 0x53, 0x00, 0x46,
+               0x00, 0x67,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
+               0xd2, 0x64, 0xcf, 0xdb, 0xc6, 0xe1, 0xbd, 0xb3,
+               0xbd, 0xd2, 0xd2, 0xce, 0x00, 0x59, 0x00, 0x4b,
+               0x00, 0x6e,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
+               0xd0, 0x7c, 0xcf, 0xdb, 0xc9, 0xe0, 0xbc, 0xb4,
+               0xbb, 0xcf, 0xd1, 0xcc, 0x00, 0x5f, 0x00, 0x50,
+               0x00, 0x75,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
+               0xd0, 0x8e, 0xd1, 0xdb, 0xcc, 0xdf, 0xbb, 0xb6,
+               0xb9, 0xd0, 0xd1, 0xcd, 0x00, 0x63, 0x00, 0x54,
+               0x00, 0x7a,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
+               0xd1, 0x9e, 0xd5, 0xda, 0xcd, 0xdd, 0xbb, 0xb7,
+               0xb9, 0xce, 0xce, 0xc9, 0x00, 0x68, 0x00, 0x59,
+               0x00, 0x81,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x00, 0xff,
+               0xd0, 0xa5, 0xd6, 0xda, 0xcf, 0xdd, 0xbb, 0xb7,
+               0xb8, 0xcc, 0xcd, 0xc7, 0x00, 0x6c, 0x00, 0x5c,
+               0x00, 0x86,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xfe,
+               0xd0, 0xae, 0xd7, 0xd9, 0xd0, 0xdb, 0xb9, 0xb6,
+               0xb5, 0xca, 0xcc, 0xc5, 0x00, 0x74, 0x00, 0x63,
+               0x00, 0x90,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf9,
+               0xcf, 0xb0, 0xd6, 0xd9, 0xd1, 0xdb, 0xb9, 0xb6,
+               0xb4, 0xca, 0xcb, 0xc5, 0x00, 0x77, 0x00, 0x66,
+               0x00, 0x94,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xff, 0x1f, 0xf7,
+               0xcf, 0xb3, 0xd7, 0xd8, 0xd1, 0xd9, 0xb7, 0xb6,
+               0xb3, 0xc9, 0xca, 0xc3, 0x00, 0x7b, 0x00, 0x69,
+               0x00, 0x99,
+
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfd, 0x2f, 0xf7,
+               0xdf, 0xb5, 0xd6, 0xd8, 0xd1, 0xd8, 0xb6, 0xb5,
+               0xb2, 0xca, 0xcb, 0xc4, 0x00, 0x7e, 0x00, 0x6c,
+               0x00, 0x9d,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xfa, 0x2f, 0xf5,
+               0xce, 0xb6, 0xd5, 0xd7, 0xd2, 0xd8, 0xb6, 0xb4,
+               0xb0, 0xc7, 0xc9, 0xc1, 0x00, 0x84, 0x00, 0x71,
+               0x00, 0xa5,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf7, 0x2f, 0xf2,
+               0xce, 0xb9, 0xd5, 0xd8, 0xd2, 0xd8, 0xb4, 0xb4,
+               0xaf, 0xc7, 0xc9, 0xc1, 0x00, 0x87, 0x00, 0x73,
+               0x00, 0xa8,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf5, 0x2f, 0xf0,
+               0xdf, 0xba, 0xd5, 0xd7, 0xd2, 0xd7, 0xb4, 0xb4,
+               0xaf, 0xc5, 0xc7, 0xbf, 0x00, 0x8a, 0x00, 0x76,
+               0x00, 0xac,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xf2, 0x2f, 0xed,
+               0xcE, 0xbb, 0xd4, 0xd6, 0xd2, 0xd6, 0xb5, 0xb4,
+               0xaF, 0xc5, 0xc7, 0xbf, 0x00, 0x8c, 0x00, 0x78,
+               0x00, 0xaf,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x2f, 0xeb,
+               0xcd, 0xbb, 0xd2, 0xd7, 0xd3, 0xd6, 0xb3, 0xb4,
+               0xae, 0xc5, 0xc6, 0xbe, 0x00, 0x91, 0x00, 0x7d,
+               0x00, 0xb6,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xee, 0x2f, 0xea,
+               0xce, 0xbd, 0xd4, 0xd6, 0xd2, 0xd5, 0xb2, 0xb3,
+               0xad, 0xc3, 0xc4, 0xbb, 0x00, 0x94, 0x00, 0x7f,
+               0x00, 0xba,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xec, 0x2f, 0xe8,
+               0xce, 0xbe, 0xd3, 0xd6, 0xd3, 0xd5, 0xb2, 0xb2,
+               0xac, 0xc3, 0xc5, 0xbc, 0x00, 0x96, 0x00, 0x81,
+               0x00, 0xbd,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xeb, 0x2f, 0xe7,
+               0xce, 0xbf, 0xd3, 0xd6, 0xd2, 0xd5, 0xb1, 0xb2,
+               0xab, 0xc2, 0xc4, 0xbb, 0x00, 0x99, 0x00, 0x83,
+               0x00, 0xc0,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xef, 0x5f, 0xe9,
+               0xca, 0xbf, 0xd3, 0xd5, 0xd2, 0xd4, 0xb2, 0xb2,
+               0xab, 0xc1, 0xc4, 0xba, 0x00, 0x9b, 0x00, 0x85,
+               0x00, 0xc3,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xea, 0x5f, 0xe8,
+               0xee, 0xbf, 0xd2, 0xd5, 0xd2, 0xd4, 0xb1, 0xb2,
+               0xab, 0xc1, 0xc2, 0xb9, 0x00, 0x9D, 0x00, 0x87,
+               0x00, 0xc6,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe9, 0x5f, 0xe7,
+               0xcd, 0xbf, 0xd2, 0xd6, 0xd2, 0xd4, 0xb1, 0xb2,
+               0xab, 0xbe, 0xc0, 0xb7, 0x00, 0xa1, 0x00, 0x8a,
+               0x00, 0xca,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x61, 0xe6,
+               0xcd, 0xbf, 0xd1, 0xd6, 0xd3, 0xd4, 0xaf, 0xb0,
+               0xa9, 0xbe, 0xc1, 0xb7, 0x00, 0xa3, 0x00, 0x8b,
+               0x00, 0xce,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe8, 0x62, 0xe5,
+               0xcc, 0xc0, 0xd0, 0xd6, 0xd2, 0xd4, 0xaf, 0xb1,
+               0xa9, 0xbd, 0xc0, 0xb6, 0x00, 0xa5, 0x00, 0x8d,
+               0x00, 0xd0,
+       }, {
+               0xfa, 0x01, 0x1f, 0x1f, 0x1f, 0xe7, 0x7f, 0xe3,
+               0xcc, 0xc1, 0xd0, 0xd5, 0xd3, 0xd3, 0xae, 0xaf,
+               0xa8, 0xbe, 0xc0, 0xb7, 0x00, 0xa8, 0x00, 0x90,
+               0x00, 0xd3,
+       }
+};
+
+static const s6e8aa0_gamma_table s6e8aa0_gamma_tables_v32[GAMMA_LEVEL_NUM] = {
+       {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0x72, 0x5e, 0x6b,
+               0xa1, 0xa7, 0x9a, 0xb4, 0xcb, 0xb8, 0x92, 0xac,
+               0x97, 0xb4, 0xc3, 0xb5, 0x00, 0x4e, 0x00, 0x37,
+               0x00, 0x58,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0x85, 0x71, 0x7d,
+               0xa6, 0xb6, 0xa1, 0xb5, 0xca, 0xba, 0x93, 0xac,
+               0x98, 0xb2, 0xc0, 0xaf, 0x00, 0x59, 0x00, 0x43,
+               0x00, 0x64,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xa4, 0x94, 0x9e,
+               0xa0, 0xbb, 0x9c, 0xc3, 0xd2, 0xc6, 0x93, 0xaa,
+               0x95, 0xb7, 0xc2, 0xb4, 0x00, 0x65, 0x00, 0x50,
+               0x00, 0x74,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa1, 0xa6,
+               0xa0, 0xb9, 0x9b, 0xc3, 0xd1, 0xc8, 0x90, 0xa6,
+               0x90, 0xbb, 0xc3, 0xb7, 0x00, 0x6f, 0x00, 0x5b,
+               0x00, 0x80,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xa6, 0x9d, 0x9f,
+               0x9f, 0xb8, 0x9a, 0xc7, 0xd5, 0xcc, 0x90, 0xa5,
+               0x8f, 0xb8, 0xc1, 0xb6, 0x00, 0x74, 0x00, 0x60,
+               0x00, 0x85,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xb3, 0xae, 0xae,
+               0x9e, 0xb7, 0x9a, 0xc8, 0xd6, 0xce, 0x91, 0xa6,
+               0x90, 0xb6, 0xc0, 0xb3, 0x00, 0x78, 0x00, 0x65,
+               0x00, 0x8a,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xa9, 0xa8,
+               0xa3, 0xb9, 0x9e, 0xc4, 0xd3, 0xcb, 0x94, 0xa6,
+               0x90, 0xb6, 0xbf, 0xb3, 0x00, 0x7c, 0x00, 0x69,
+               0x00, 0x8e,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xaf, 0xaf, 0xa9,
+               0xa5, 0xbc, 0xa2, 0xc7, 0xd5, 0xcd, 0x93, 0xa5,
+               0x8f, 0xb4, 0xbd, 0xb1, 0x00, 0x83, 0x00, 0x70,
+               0x00, 0x96,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xab, 0xa3,
+               0xaa, 0xbf, 0xa7, 0xc5, 0xd3, 0xcb, 0x93, 0xa5,
+               0x8f, 0xb2, 0xbb, 0xb0, 0x00, 0x86, 0x00, 0x74,
+               0x00, 0x9b,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xb5, 0xab,
+               0xab, 0xc0, 0xa9, 0xc7, 0xd4, 0xcc, 0x94, 0xa4,
+               0x8f, 0xb1, 0xbb, 0xaf, 0x00, 0x8a, 0x00, 0x77,
+               0x00, 0x9e,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb2, 0xa7,
+               0xae, 0xc2, 0xab, 0xc5, 0xd3, 0xca, 0x93, 0xa4,
+               0x8f, 0xb1, 0xba, 0xae, 0x00, 0x8d, 0x00, 0x7b,
+               0x00, 0xa2,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xaf, 0xa3,
+               0xb0, 0xc3, 0xae, 0xc4, 0xd1, 0xc8, 0x93, 0xa4,
+               0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x8f, 0x00, 0x7d,
+               0x00, 0xa5,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbd, 0xaf,
+               0xae, 0xc1, 0xab, 0xc2, 0xd0, 0xc6, 0x94, 0xa4,
+               0x8f, 0xb1, 0xba, 0xaf, 0x00, 0x92, 0x00, 0x80,
+               0x00, 0xa8,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xb9, 0xac,
+               0xad, 0xc1, 0xab, 0xc4, 0xd1, 0xc7, 0x95, 0xa4,
+               0x90, 0xb0, 0xb9, 0xad, 0x00, 0x95, 0x00, 0x84,
+               0x00, 0xac,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb6, 0xa7,
+               0xaf, 0xc2, 0xae, 0xc5, 0xd1, 0xc7, 0x93, 0xa3,
+               0x8e, 0xb0, 0xb9, 0xad, 0x00, 0x98, 0x00, 0x86,
+               0x00, 0xaf,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xb4, 0xbf, 0xaf,
+               0xad, 0xc1, 0xab, 0xc3, 0xd0, 0xc6, 0x94, 0xa3,
+               0x8f, 0xaf, 0xb8, 0xac, 0x00, 0x9a, 0x00, 0x89,
+               0x00, 0xb2,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xbc, 0xac,
+               0xaf, 0xc2, 0xad, 0xc2, 0xcf, 0xc4, 0x94, 0xa3,
+               0x90, 0xaf, 0xb8, 0xad, 0x00, 0x9c, 0x00, 0x8b,
+               0x00, 0xb5,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7,
+               0xb1, 0xc4, 0xaf, 0xc3, 0xcf, 0xc5, 0x94, 0xa3,
+               0x8f, 0xae, 0xb7, 0xac, 0x00, 0x9f, 0x00, 0x8e,
+               0x00, 0xb8,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xb9, 0xa7,
+               0xaf, 0xc2, 0xad, 0xc1, 0xce, 0xc3, 0x95, 0xa3,
+               0x90, 0xad, 0xb6, 0xab, 0x00, 0xa2, 0x00, 0x91,
+               0x00, 0xbb,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xb1, 0xbe, 0xac,
+               0xb1, 0xc4, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa4,
+               0x91, 0xad, 0xb6, 0xab, 0x00, 0xa4, 0x00, 0x93,
+               0x00, 0xbd,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8,
+               0xb3, 0xc5, 0xb2, 0xc1, 0xcd, 0xc2, 0x95, 0xa3,
+               0x90, 0xad, 0xb6, 0xab, 0x00, 0xa6, 0x00, 0x95,
+               0x00, 0xc0,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbb, 0xa8,
+               0xb0, 0xc3, 0xaf, 0xc2, 0xce, 0xc2, 0x94, 0xa2,
+               0x90, 0xac, 0xb6, 0xab, 0x00, 0xa8, 0x00, 0x98,
+               0x00, 0xc3,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xa9, 0xb8, 0xa5,
+               0xb3, 0xc5, 0xb2, 0xc1, 0xcc, 0xc0, 0x95, 0xa2,
+               0x90, 0xad, 0xb6, 0xab, 0x00, 0xaa, 0x00, 0x9a,
+               0x00, 0xc5,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xb0, 0xc0, 0xac,
+               0xb0, 0xc3, 0xaf, 0xc1, 0xcd, 0xc1, 0x95, 0xa2,
+               0x90, 0xac, 0xb5, 0xa9, 0x00, 0xac, 0x00, 0x9c,
+               0x00, 0xc8,
+       }, {
+               0xfa, 0x01, 0x43, 0x14, 0x45, 0xad, 0xbd, 0xa8,
+               0xaf, 0xc2, 0xaf, 0xc1, 0xcc, 0xc0, 0x95, 0xa2,
+               0x90, 0xac, 0xb5, 0xaa, 0x00, 0xb1, 0x00, 0xa1,
+               0x00, 0xcc,
+       },
+};
+
+static const struct s6e8aa0_variant s6e8aa0_variants[] = {
+       {
+               .version = 32,
+               .gamma_tables = s6e8aa0_gamma_tables_v32,
+       }, {
+               .version = 96,
+               .gamma_tables = s6e8aa0_gamma_tables_v96,
+       }, {
+               .version = 142,
+               .gamma_tables = s6e8aa0_gamma_tables_v142,
+       }, {
+               .version = 210,
+               .gamma_tables = s6e8aa0_gamma_tables_v142,
+       }
+};
+
+static void s6e8aa0_brightness_set(struct s6e8aa0 *ctx)
+{
+       const u8 *gamma;
+
+       if (ctx->error)
+               return;
+
+       gamma = ctx->variant->gamma_tables[ctx->brightness];
+
+       if (ctx->version >= 142)
+               s6e8aa0_elvss_nvm_set(ctx);
+
+       s6e8aa0_dcs_write(ctx, gamma, GAMMA_TABLE_LEN);
+
+       /* update gamma table. */
+       s6e8aa0_dcs_write_seq_static(ctx, 0xf7, 0x03);
+}
+
+static void s6e8aa0_panel_init(struct s6e8aa0 *ctx)
+{
+       s6e8aa0_apply_level_1_key(ctx);
+       s6e8aa0_apply_level_2_key(ctx);
+       msleep(20);
+
+       s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
+       msleep(40);
+
+       s6e8aa0_panel_cond_set(ctx);
+       s6e8aa0_display_condition_set(ctx);
+       s6e8aa0_brightness_set(ctx);
+       s6e8aa0_etc_source_control(ctx);
+       s6e8aa0_etc_pentile_control(ctx);
+       s6e8aa0_elvss_nvm_set(ctx);
+       s6e8aa0_etc_power_control(ctx);
+       s6e8aa0_etc_elvss_control(ctx);
+       msleep(ctx->init_delay);
+}
+
+static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx,
+                                                  int size)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
+       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+       u8 buf[] = {size, 0};
+       struct mipi_dsi_msg msg = {
+               .channel = dsi->channel,
+               .type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
+               .tx_len = sizeof(buf),
+               .tx_buf = buf
+       };
+       int ret;
+
+       if (ctx->error < 0)
+               return;
+
+       if (!ops || !ops->transfer)
+               ret = -EIO;
+       else
+               ret = ops->transfer(dsi->host, &msg);
+
+       if (ret < 0) {
+               dev_err(ctx->dev,
+                       "error %d setting maximum return packet size to %d\n",
+                       ret, size);
+               ctx->error = ret;
+       }
+}
+
+static void s6e8aa0_read_mtp_id(struct s6e8aa0 *ctx)
+{
+       u8 id[3];
+       int ret, i;
+
+       ret = s6e8aa0_dcs_read(ctx, 0xd1, id, ARRAY_SIZE(id));
+       if (ret < ARRAY_SIZE(id) || id[0] == 0x00) {
+               dev_err(ctx->dev, "read id failed\n");
+               ctx->error = -EIO;
+               return;
+       }
+
+       dev_info(ctx->dev, "ID: 0x%2x, 0x%2x, 0x%2x\n", id[0], id[1], id[2]);
+
+       for (i = 0; i < ARRAY_SIZE(s6e8aa0_variants); ++i) {
+               if (id[1] == s6e8aa0_variants[i].version)
+                       break;
+       }
+       if (i >= ARRAY_SIZE(s6e8aa0_variants)) {
+               dev_err(ctx->dev, "unsupported display version %d\n", id[1]);
+               ctx->error = -EINVAL;
+       }
+
+       ctx->variant = &s6e8aa0_variants[i];
+       ctx->version = id[1];
+       ctx->id = id[2];
+}
+
+static void s6e8aa0_set_sequence(struct s6e8aa0 *ctx)
+{
+       s6e8aa0_set_maximum_return_packet_size(ctx, 3);
+       s6e8aa0_read_mtp_id(ctx);
+       s6e8aa0_panel_init(ctx);
+       s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
+}
+
+static int s6e8aa0_power_on(struct s6e8aa0 *ctx)
+{
+       int ret;
+
+       ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+       if (ret < 0)
+               return ret;
+
+       msleep(ctx->power_on_delay);
+
+       gpiod_set_value(ctx->reset_gpio, 0);
+       usleep_range(10000, 11000);
+       gpiod_set_value(ctx->reset_gpio, 1);
+
+       msleep(ctx->reset_delay);
+
+       return 0;
+}
+
+static int s6e8aa0_power_off(struct s6e8aa0 *ctx)
+{
+       return regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
+}
+
+static int s6e8aa0_disable(struct drm_panel *panel)
+{
+       struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
+
+       s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
+       s6e8aa0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
+       msleep(40);
+
+       s6e8aa0_clear_error(ctx);
+
+       return s6e8aa0_power_off(ctx);
+}
+
+static int s6e8aa0_enable(struct drm_panel *panel)
+{
+       struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
+       int ret;
+
+       ret = s6e8aa0_power_on(ctx);
+       if (ret < 0)
+               return ret;
+
+       s6e8aa0_set_sequence(ctx);
+       ret = ctx->error;
+
+       if (ret < 0)
+               s6e8aa0_disable(panel);
+
+       return ret;
+}
+
+static int s6e8aa0_get_modes(struct drm_panel *panel)
+{
+       struct drm_connector *connector = panel->connector;
+       struct s6e8aa0 *ctx = panel_to_s6e8aa0(panel);
+       struct drm_display_mode *mode;
+
+       mode = drm_mode_create(connector->dev);
+       if (!mode) {
+               DRM_ERROR("failed to create a new display mode\n");
+               return 0;
+       }
+
+       drm_display_mode_from_videomode(&ctx->vm, mode);
+       mode->width_mm = ctx->width_mm;
+       mode->height_mm = ctx->height_mm;
+       connector->display_info.width_mm = mode->width_mm;
+       connector->display_info.height_mm = mode->height_mm;
+
+       mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
+       drm_mode_probed_add(connector, mode);
+
+       return 1;
+}
+
+static const struct drm_panel_funcs s6e8aa0_drm_funcs = {
+       .disable = s6e8aa0_disable,
+       .enable = s6e8aa0_enable,
+       .get_modes = s6e8aa0_get_modes,
+};
+
+static int s6e8aa0_parse_dt(struct s6e8aa0 *ctx)
+{
+       struct device *dev = ctx->dev;
+       struct device_node *np = dev->of_node;
+       int ret;
+
+       ret = of_get_videomode(np, &ctx->vm, 0);
+       if (ret < 0)
+               return ret;
+
+       of_property_read_u32(np, "power-on-delay", &ctx->power_on_delay);
+       of_property_read_u32(np, "reset-delay", &ctx->reset_delay);
+       of_property_read_u32(np, "init-delay", &ctx->init_delay);
+       of_property_read_u32(np, "panel-width-mm", &ctx->width_mm);
+       of_property_read_u32(np, "panel-height-mm", &ctx->height_mm);
+
+       ctx->flip_horizontal = of_property_read_bool(np, "flip-horizontal");
+       ctx->flip_vertical = of_property_read_bool(np, "flip-vertical");
+
+       return 0;
+}
+
+static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
+{
+       struct device *dev = &dsi->dev;
+       struct s6e8aa0 *ctx;
+       int ret;
+
+       ctx = devm_kzalloc(dev, sizeof(struct s6e8aa0), GFP_KERNEL);
+       if (!ctx)
+               return -ENOMEM;
+
+       mipi_dsi_set_drvdata(dsi, ctx);
+
+       ctx->dev = dev;
+
+       dsi->lanes = 4;
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST
+               | MIPI_DSI_MODE_VIDEO_HFP | MIPI_DSI_MODE_VIDEO_HBP
+               | MIPI_DSI_MODE_VIDEO_HSA | MIPI_DSI_MODE_EOT_PACKET
+               | MIPI_DSI_MODE_VSYNC_FLUSH | MIPI_DSI_MODE_VIDEO_AUTO_VERT;
+
+       ret = s6e8aa0_parse_dt(ctx);
+       if (ret < 0)
+               return ret;
+
+       ctx->supplies[0].supply = "vdd3";
+       ctx->supplies[1].supply = "vci";
+       ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
+                                     ctx->supplies);
+       if (ret < 0) {
+               dev_err(dev, "failed to get regulators: %d\n", ret);
+               return ret;
+       }
+
+       ctx->reset_gpio = devm_gpiod_get(dev, "reset");
+       if (IS_ERR(ctx->reset_gpio)) {
+               dev_err(dev, "cannot get reset-gpios %ld\n",
+                       PTR_ERR(ctx->reset_gpio));
+               return PTR_ERR(ctx->reset_gpio);
+       }
+       ret = gpiod_direction_output(ctx->reset_gpio, 1);
+       if (ret < 0) {
+               dev_err(dev, "cannot configure reset-gpios %d\n", ret);
+               return ret;
+       }
+
+       ctx->brightness = GAMMA_LEVEL_NUM - 1;
+
+       drm_panel_init(&ctx->panel);
+       ctx->panel.dev = dev;
+       ctx->panel.funcs = &s6e8aa0_drm_funcs;
+
+       ret = drm_panel_add(&ctx->panel);
+       if (ret < 0)
+               return ret;
+
+       ret = mipi_dsi_attach(dsi);
+       if (ret < 0)
+               drm_panel_remove(&ctx->panel);
+
+       return ret;
+}
+
+static int s6e8aa0_remove(struct mipi_dsi_device *dsi)
+{
+       struct s6e8aa0 *ctx = mipi_dsi_get_drvdata(dsi);
+
+       mipi_dsi_detach(dsi);
+       drm_panel_remove(&ctx->panel);
+
+       return 0;
+}
+
+static struct of_device_id s6e8aa0_of_match[] = {
+       { .compatible = "samsung,s6e8aa0" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, s6e8aa0_of_match);
+
+static struct mipi_dsi_driver s6e8aa0_driver = {
+       .probe = s6e8aa0_probe,
+       .remove = s6e8aa0_remove,
+       .driver = {
+               .name = "panel_s6e8aa0",
+               .owner = THIS_MODULE,
+               .of_match_table = s6e8aa0_of_match,
+       },
+};
+module_mipi_dsi_driver(s6e8aa0_driver);
+
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
+MODULE_AUTHOR("Joongmock Shin <jmock.shin@samsung.com>");
+MODULE_AUTHOR("Eunchul Kim <chulspro.kim@samsung.com>");
+MODULE_AUTHOR("Tomasz Figa <t.figa@samsung.com>");
+MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
+MODULE_DESCRIPTION("MIPI-DSI based s6e8aa0 AMOLED LCD Panel Driver");
+MODULE_LICENSE("GPL v2");
index 59d52ca..309f29e 100644 (file)
@@ -22,9 +22,8 @@
  */
 
 #include <linux/backlight.h>
-#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/module.h>
-#include <linux/of_gpio.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
@@ -44,9 +43,6 @@ struct panel_desc {
        } size;
 };
 
-/* TODO: convert to gpiod_*() API once it's been merged */
-#define GPIO_ACTIVE_LOW        (1 << 0)
-
 struct panel_simple {
        struct drm_panel base;
        bool enabled;
@@ -57,8 +53,7 @@ struct panel_simple {
        struct regulator *supply;
        struct i2c_adapter *ddc;
 
-       unsigned long enable_gpio_flags;
-       int enable_gpio;
+       struct gpio_desc *enable_gpio;
 };
 
 static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
@@ -110,12 +105,8 @@ static int panel_simple_disable(struct drm_panel *panel)
                backlight_update_status(p->backlight);
        }
 
-       if (gpio_is_valid(p->enable_gpio)) {
-               if (p->enable_gpio_flags & GPIO_ACTIVE_LOW)
-                       gpio_set_value(p->enable_gpio, 1);
-               else
-                       gpio_set_value(p->enable_gpio, 0);
-       }
+       if (p->enable_gpio)
+               gpiod_set_value_cansleep(p->enable_gpio, 0);
 
        regulator_disable(p->supply);
        p->enabled = false;
@@ -137,12 +128,8 @@ static int panel_simple_enable(struct drm_panel *panel)
                return err;
        }
 
-       if (gpio_is_valid(p->enable_gpio)) {
-               if (p->enable_gpio_flags & GPIO_ACTIVE_LOW)
-                       gpio_set_value(p->enable_gpio, 0);
-               else
-                       gpio_set_value(p->enable_gpio, 1);
-       }
+       if (p->enable_gpio)
+               gpiod_set_value_cansleep(p->enable_gpio, 1);
 
        if (p->backlight) {
                p->backlight->props.power = FB_BLANK_UNBLANK;
@@ -185,7 +172,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
 {
        struct device_node *backlight, *ddc;
        struct panel_simple *panel;
-       enum of_gpio_flags flags;
        int err;
 
        panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
@@ -199,29 +185,20 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
        if (IS_ERR(panel->supply))
                return PTR_ERR(panel->supply);
 
-       panel->enable_gpio = of_get_named_gpio_flags(dev->of_node,
-                                                    "enable-gpios", 0,
-                                                    &flags);
-       if (gpio_is_valid(panel->enable_gpio)) {
-               unsigned int value;
-
-               if (flags & OF_GPIO_ACTIVE_LOW)
-                       panel->enable_gpio_flags |= GPIO_ACTIVE_LOW;
-
-               err = gpio_request(panel->enable_gpio, "enable");
-               if (err < 0) {
-                       dev_err(dev, "failed to request GPIO#%u: %d\n",
-                               panel->enable_gpio, err);
+       panel->enable_gpio = devm_gpiod_get(dev, "enable");
+       if (IS_ERR(panel->enable_gpio)) {
+               err = PTR_ERR(panel->enable_gpio);
+               if (err != -ENOENT) {
+                       dev_err(dev, "failed to request GPIO: %d\n", err);
                        return err;
                }
 
-               value = (panel->enable_gpio_flags & GPIO_ACTIVE_LOW) != 0;
-
-               err = gpio_direction_output(panel->enable_gpio, value);
+               panel->enable_gpio = NULL;
+       } else {
+               err = gpiod_direction_output(panel->enable_gpio, 0);
                if (err < 0) {
-                       dev_err(dev, "failed to setup GPIO%u: %d\n",
-                               panel->enable_gpio, err);
-                       goto free_gpio;
+                       dev_err(dev, "failed to setup GPIO: %d\n", err);
+                       return err;
                }
        }
 
@@ -230,10 +207,8 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
                panel->backlight = of_find_backlight_by_node(backlight);
                of_node_put(backlight);
 
-               if (!panel->backlight) {
-                       err = -EPROBE_DEFER;
-                       goto free_gpio;
-               }
+               if (!panel->backlight)
+                       return -EPROBE_DEFER;
        }
 
        ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
@@ -265,9 +240,6 @@ free_ddc:
 free_backlight:
        if (panel->backlight)
                put_device(&panel->backlight->dev);
-free_gpio:
-       if (gpio_is_valid(panel->enable_gpio))
-               gpio_free(panel->enable_gpio);
 
        return err;
 }
@@ -287,11 +259,6 @@ static int panel_simple_remove(struct device *dev)
        if (panel->backlight)
                put_device(&panel->backlight->dev);
 
-       if (gpio_is_valid(panel->enable_gpio))
-               gpio_free(panel->enable_gpio);
-
-       regulator_disable(panel->supply);
-
        return 0;
 }
 
@@ -361,6 +328,28 @@ static const struct panel_desc chunghwa_claa101wb01 = {
        },
 };
 
+static const struct drm_display_mode lg_lp129qe_mode = {
+       .clock = 285250,
+       .hdisplay = 2560,
+       .hsync_start = 2560 + 48,
+       .hsync_end = 2560 + 48 + 32,
+       .htotal = 2560 + 48 + 32 + 80,
+       .vdisplay = 1700,
+       .vsync_start = 1700 + 3,
+       .vsync_end = 1700 + 3 + 10,
+       .vtotal = 1700 + 3 + 10 + 36,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc lg_lp129qe = {
+       .modes = &lg_lp129qe_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 272,
+               .height = 181,
+       },
+};
+
 static const struct drm_display_mode samsung_ltn101nt05_mode = {
        .clock = 54030,
        .hdisplay = 1024,
@@ -393,6 +382,9 @@ static const struct of_device_id platform_of_match[] = {
        }, {
                .compatible = "chunghwa,claa101wb01",
                .data = &chunghwa_claa101wb01
+       }, {
+               .compatible = "lg,lp129qe",
+               .data = &lg_lp129qe,
        }, {
                .compatible = "samsung,ltn101nt05",
                .data = &samsung_ltn101nt05,
@@ -433,10 +425,65 @@ static struct platform_driver panel_simple_platform_driver = {
 struct panel_desc_dsi {
        struct panel_desc desc;
 
+       unsigned long flags;
        enum mipi_dsi_pixel_format format;
        unsigned int lanes;
 };
 
+static const struct drm_display_mode lg_ld070wx3_sl01_mode = {
+       .clock = 71000,
+       .hdisplay = 800,
+       .hsync_start = 800 + 32,
+       .hsync_end = 800 + 32 + 1,
+       .htotal = 800 + 32 + 1 + 57,
+       .vdisplay = 1280,
+       .vsync_start = 1280 + 28,
+       .vsync_end = 1280 + 28 + 1,
+       .vtotal = 1280 + 28 + 1 + 14,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc_dsi lg_ld070wx3_sl01 = {
+       .desc = {
+               .modes = &lg_ld070wx3_sl01_mode,
+               .num_modes = 1,
+               .size = {
+                       .width = 94,
+                       .height = 151,
+               },
+       },
+       .flags = MIPI_DSI_MODE_VIDEO,
+       .format = MIPI_DSI_FMT_RGB888,
+       .lanes = 4,
+};
+
+static const struct drm_display_mode lg_lh500wx1_sd03_mode = {
+       .clock = 67000,
+       .hdisplay = 720,
+       .hsync_start = 720 + 12,
+       .hsync_end = 720 + 12 + 4,
+       .htotal = 720 + 12 + 4 + 112,
+       .vdisplay = 1280,
+       .vsync_start = 1280 + 8,
+       .vsync_end = 1280 + 8 + 4,
+       .vtotal = 1280 + 8 + 4 + 12,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc_dsi lg_lh500wx1_sd03 = {
+       .desc = {
+               .modes = &lg_lh500wx1_sd03_mode,
+               .num_modes = 1,
+               .size = {
+                       .width = 62,
+                       .height = 110,
+               },
+       },
+       .flags = MIPI_DSI_MODE_VIDEO,
+       .format = MIPI_DSI_FMT_RGB888,
+       .lanes = 4,
+};
+
 static const struct drm_display_mode panasonic_vvx10f004b00_mode = {
        .clock = 157200,
        .hdisplay = 1920,
@@ -459,12 +506,19 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
                        .height = 136,
                },
        },
+       .flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_SYNC_PULSE,
        .format = MIPI_DSI_FMT_RGB888,
        .lanes = 4,
 };
 
 static const struct of_device_id dsi_of_match[] = {
        {
+               .compatible = "lg,ld070wx3-sl01",
+               .data = &lg_ld070wx3_sl01
+       }, {
+               .compatible = "lg,lh500wx1-sd03",
+               .data = &lg_lh500wx1_sd03
+       }, {
                .compatible = "panasonic,vvx10f004b00",
                .data = &panasonic_vvx10f004b00
        }, {
@@ -489,6 +543,7 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
        if (err < 0)
                return err;
 
+       dsi->mode_flags = desc->flags;
        dsi->format = desc->format;
        dsi->lanes = desc->lanes;
 
index 798bde2..41bdd17 100644 (file)
@@ -527,7 +527,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
        bool recreate_primary = false;
        int ret;
        int surf_id;
-       if (!crtc->fb) {
+       if (!crtc->primary->fb) {
                DRM_DEBUG_KMS("No FB bound\n");
                return 0;
        }
@@ -536,7 +536,7 @@ static int qxl_crtc_mode_set(struct drm_crtc *crtc,
                qfb = to_qxl_framebuffer(old_fb);
                old_bo = gem_to_qxl_bo(qfb->obj);
        }
-       qfb = to_qxl_framebuffer(crtc->fb);
+       qfb = to_qxl_framebuffer(crtc->primary->fb);
        bo = gem_to_qxl_bo(qfb->obj);
        if (!m)
                /* and do we care? */
@@ -609,14 +609,14 @@ static void qxl_crtc_disable(struct drm_crtc *crtc)
        struct qxl_crtc *qcrtc = to_qxl_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct qxl_device *qdev = dev->dev_private;
-       if (crtc->fb) {
-               struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->fb);
+       if (crtc->primary->fb) {
+               struct qxl_framebuffer *qfb = to_qxl_framebuffer(crtc->primary->fb);
                struct qxl_bo *bo = gem_to_qxl_bo(qfb->obj);
                int ret;
                ret = qxl_bo_reserve(bo, false);
                qxl_bo_unpin(bo);
                qxl_bo_unreserve(bo);
-               crtc->fb = NULL;
+               crtc->primary->fb = NULL;
        }
 
        qxl_monitors_config_set(qdev, qcrtc->index, 0, 0, 0, 0, 0);
index 8691c76..b95f144 100644 (file)
@@ -82,8 +82,6 @@ int qxl_bo_create(struct qxl_device *qdev,
        enum ttm_bo_type type;
        int r;
 
-       if (unlikely(qdev->mman.bdev.dev_mapping == NULL))
-               qdev->mman.bdev.dev_mapping = qdev->ddev->dev_mapping;
        if (kernel)
                type = ttm_bo_type_kernel;
        else
index 821ab7b..14e776f 100644 (file)
@@ -349,7 +349,7 @@ void qxl_release_fence_buffer_objects(struct qxl_release *release)
                qxl_fence_add_release_locked(&qbo->fence, release->id);
 
                ttm_bo_add_to_lru(bo);
-               ww_mutex_unlock(&bo->resv->lock);
+               __ttm_bo_unreserve(bo);
                entry->reserved = false;
        }
        spin_unlock(&bdev->fence_lock);
index c7e7e65..d52c275 100644 (file)
@@ -433,6 +433,7 @@ static int qxl_sync_obj_flush(void *sync_obj)
 
 static void qxl_sync_obj_unref(void **sync_obj)
 {
+       *sync_obj = NULL;
 }
 
 static void *qxl_sync_obj_ref(void *sync_obj)
@@ -493,7 +494,9 @@ int qxl_ttm_init(struct qxl_device *qdev)
        /* No others user of address space so set it to 0 */
        r = ttm_bo_device_init(&qdev->mman.bdev,
                               qdev->mman.bo_global_ref.ref.object,
-                              &qxl_bo_driver, DRM_FILE_PAGE_OFFSET, 0);
+                              &qxl_bo_driver,
+                              qdev->ddev->anon_inode->i_mapping,
+                              DRM_FILE_PAGE_OFFSET, 0);
        if (r) {
                DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
                return r;
@@ -518,8 +521,6 @@ int qxl_ttm_init(struct qxl_device *qdev)
                 ((unsigned)num_io_pages * PAGE_SIZE) / (1024 * 1024));
        DRM_INFO("qxl: %uM of Surface memory size\n",
                 (unsigned)qdev->surfaceram_size / (1024 * 1024));
-       if (unlikely(qdev->mman.bdev.dev_mapping == NULL))
-               qdev->mman.bdev.dev_mapping = qdev->ddev->dev_mapping;
        r = qxl_ttm_debugfs_init(qdev);
        if (r) {
                DRM_ERROR("Failed to init debugfs\n");
index 306364a..0943353 100644 (file)
@@ -80,7 +80,7 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
        r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
        rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
        trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
-       ci_dpm.o dce6_afmt.o
+       ci_dpm.o dce6_afmt.o radeon_vm.o
 
 # add async DMA block
 radeon-y += \
@@ -99,6 +99,12 @@ radeon-y += \
        uvd_v3_1.o \
        uvd_v4_2.o
 
+# add VCE block
+radeon-y += \
+       radeon_vce.o \
+       vce_v1_0.o \
+       vce_v2_0.o \
+
 radeon-$(CONFIG_COMPAT) += radeon_ioc32.o
 radeon-$(CONFIG_VGA_SWITCHEROO) += radeon_atpx_handler.o
 radeon-$(CONFIG_ACPI) += radeon_acpi.o
index daa4dd3..fb187c7 100644 (file)
@@ -1106,7 +1106,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
        int r;
 
        /* no fb bound */
-       if (!atomic && !crtc->fb) {
+       if (!atomic && !crtc->primary->fb) {
                DRM_DEBUG_KMS("No FB bound\n");
                return 0;
        }
@@ -1116,8 +1116,8 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
                target_fb = fb;
        }
        else {
-               radeon_fb = to_radeon_framebuffer(crtc->fb);
-               target_fb = crtc->fb;
+               radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
+               target_fb = crtc->primary->fb;
        }
 
        /* If atomic, assume fb object is pinned & idle & fenced and
@@ -1316,7 +1316,7 @@ static int dce4_crtc_do_set_base(struct drm_crtc *crtc,
        /* set pageflip to happen anywhere in vblank interval */
        WREG32(EVERGREEN_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
 
-       if (!atomic && fb && fb != crtc->fb) {
+       if (!atomic && fb && fb != crtc->primary->fb) {
                radeon_fb = to_radeon_framebuffer(fb);
                rbo = gem_to_radeon_bo(radeon_fb->obj);
                r = radeon_bo_reserve(rbo, false);
@@ -1350,7 +1350,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        int r;
 
        /* no fb bound */
-       if (!atomic && !crtc->fb) {
+       if (!atomic && !crtc->primary->fb) {
                DRM_DEBUG_KMS("No FB bound\n");
                return 0;
        }
@@ -1360,8 +1360,8 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
                target_fb = fb;
        }
        else {
-               radeon_fb = to_radeon_framebuffer(crtc->fb);
-               target_fb = crtc->fb;
+               radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
+               target_fb = crtc->primary->fb;
        }
 
        obj = radeon_fb->obj;
@@ -1485,7 +1485,7 @@ static int avivo_crtc_do_set_base(struct drm_crtc *crtc,
        /* set pageflip to happen anywhere in vblank interval */
        WREG32(AVIVO_D1MODE_MASTER_UPDATE_MODE + radeon_crtc->crtc_offset, 0);
 
-       if (!atomic && fb && fb != crtc->fb) {
+       if (!atomic && fb && fb != crtc->primary->fb) {
                radeon_fb = to_radeon_framebuffer(fb);
                rbo = gem_to_radeon_bo(radeon_fb->obj);
                r = radeon_bo_reserve(rbo, false);
@@ -1972,12 +1972,12 @@ static void atombios_crtc_disable(struct drm_crtc *crtc)
        int i;
 
        atombios_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-       if (crtc->fb) {
+       if (crtc->primary->fb) {
                int r;
                struct radeon_framebuffer *radeon_fb;
                struct radeon_bo *rbo;
 
-               radeon_fb = to_radeon_framebuffer(crtc->fb);
+               radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
                rbo = gem_to_radeon_bo(radeon_fb->obj);
                r = radeon_bo_reserve(rbo, false);
                if (unlikely(r))
index 4ad7643..8b0ab17 100644 (file)
@@ -142,101 +142,69 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
        return recv_bytes;
 }
 
-static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
-                                     u16 address, u8 *send, u8 send_bytes, u8 delay)
-{
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
-       int ret;
-       u8 msg[20];
-       int msg_bytes = send_bytes + 4;
-       u8 ack;
-       unsigned retry;
-
-       if (send_bytes > 16)
-               return -1;
+#define HEADER_SIZE 4
 
-       msg[0] = address;
-       msg[1] = address >> 8;
-       msg[2] = DP_AUX_NATIVE_WRITE << 4;
-       msg[3] = (msg_bytes << 4) | (send_bytes - 1);
-       memcpy(&msg[4], send, send_bytes);
-
-       for (retry = 0; retry < 7; retry++) {
-               ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
-                                           msg, msg_bytes, NULL, 0, delay, &ack);
-               if (ret == -EBUSY)
-                       continue;
-               else if (ret < 0)
-                       return ret;
-               ack >>= 4;
-               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
-                       return send_bytes;
-               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
-                       usleep_range(400, 500);
-               else
-                       return -EIO;
-       }
-
-       return -EIO;
-}
-
-static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
-                                    u16 address, u8 *recv, int recv_bytes, u8 delay)
+static ssize_t
+radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
 {
-       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
-       u8 msg[4];
-       int msg_bytes = 4;
-       u8 ack;
+       struct radeon_i2c_chan *chan =
+               container_of(aux, struct radeon_i2c_chan, aux);
        int ret;
-       unsigned retry;
-
-       msg[0] = address;
-       msg[1] = address >> 8;
-       msg[2] = DP_AUX_NATIVE_READ << 4;
-       msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
-
-       for (retry = 0; retry < 7; retry++) {
-               ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
-                                           msg, msg_bytes, recv, recv_bytes, delay, &ack);
-               if (ret == -EBUSY)
-                       continue;
-               else if (ret < 0)
-                       return ret;
-               ack >>= 4;
-               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
-                       return ret;
-               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
-                       usleep_range(400, 500);
-               else if (ret == 0)
-                       return -EPROTO;
-               else
-                       return -EIO;
+       u8 tx_buf[20];
+       size_t tx_size;
+       u8 ack, delay = 0;
+
+       if (WARN_ON(msg->size > 16))
+               return -E2BIG;
+
+       tx_buf[0] = msg->address & 0xff;
+       tx_buf[1] = msg->address >> 8;
+       tx_buf[2] = msg->request << 4;
+       tx_buf[3] = msg->size - 1;
+
+       switch (msg->request & ~DP_AUX_I2C_MOT) {
+       case DP_AUX_NATIVE_WRITE:
+       case DP_AUX_I2C_WRITE:
+               tx_size = HEADER_SIZE + msg->size;
+               tx_buf[3] |= tx_size << 4;
+               memcpy(tx_buf + HEADER_SIZE, msg->buffer, msg->size);
+               ret = radeon_process_aux_ch(chan,
+                                           tx_buf, tx_size, NULL, 0, delay, &ack);
+               if (ret >= 0)
+                       /* Return payload size. */
+                       ret = msg->size;
+               break;
+       case DP_AUX_NATIVE_READ:
+       case DP_AUX_I2C_READ:
+               tx_size = HEADER_SIZE;
+               tx_buf[3] |= tx_size << 4;
+               ret = radeon_process_aux_ch(chan,
+                                           tx_buf, tx_size, msg->buffer, msg->size, delay, &ack);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
        }
 
-       return -EIO;
-}
+       if (ret > 0)
+               msg->reply = ack >> 4;
 
-static void radeon_write_dpcd_reg(struct radeon_connector *radeon_connector,
-                                u16 reg, u8 val)
-{
-       radeon_dp_aux_native_write(radeon_connector, reg, &val, 1, 0);
+       return ret;
 }
 
-static u8 radeon_read_dpcd_reg(struct radeon_connector *radeon_connector,
-                              u16 reg)
+void radeon_dp_aux_init(struct radeon_connector *radeon_connector)
 {
-       u8 val = 0;
-
-       radeon_dp_aux_native_read(radeon_connector, reg, &val, 1, 0);
+       struct radeon_connector_atom_dig *dig_connector = radeon_connector->con_priv;
 
-       return val;
+       dig_connector->dp_i2c_bus->aux.dev = radeon_connector->base.kdev;
+       dig_connector->dp_i2c_bus->aux.transfer = radeon_dp_aux_transfer;
 }
 
 int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                         u8 write_byte, u8 *read_byte)
 {
        struct i2c_algo_dp_aux_data *algo_data = adapter->algo_data;
-       struct radeon_i2c_chan *auxch = (struct radeon_i2c_chan *)adapter;
+       struct radeon_i2c_chan *auxch = i2c_get_adapdata(adapter);
        u16 address = algo_data->address;
        u8 msg[5];
        u8 reply[2];
@@ -246,34 +214,30 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
        int ret;
        u8 ack;
 
-       /* Set up the command byte */
-       if (mode & MODE_I2C_READ)
-               msg[2] = DP_AUX_I2C_READ << 4;
-       else
-               msg[2] = DP_AUX_I2C_WRITE << 4;
-
-       if (!(mode & MODE_I2C_STOP))
-               msg[2] |= DP_AUX_I2C_MOT << 4;
-
+       /* Set up the address */
        msg[0] = address;
        msg[1] = address >> 8;
 
-       switch (mode) {
-       case MODE_I2C_WRITE:
+       /* Set up the command byte */
+       if (mode & MODE_I2C_READ) {
+               msg[2] = DP_AUX_I2C_READ << 4;
+               msg_bytes = 4;
+               msg[3] = msg_bytes << 4;
+       } else {
+               msg[2] = DP_AUX_I2C_WRITE << 4;
                msg_bytes = 5;
                msg[3] = msg_bytes << 4;
                msg[4] = write_byte;
-               break;
-       case MODE_I2C_READ:
-               msg_bytes = 4;
-               msg[3] = msg_bytes << 4;
-               break;
-       default:
-               msg_bytes = 4;
-               msg[3] = 3 << 4;
-               break;
        }
 
+       /* special handling for start/stop */
+       if (mode & (MODE_I2C_START | MODE_I2C_STOP))
+               msg[3] = 3 << 4;
+
+       /* Set MOT bit for all but stop */
+       if ((mode & MODE_I2C_STOP) == 0)
+               msg[2] |= DP_AUX_I2C_MOT << 4;
+
        for (retry = 0; retry < 7; retry++) {
                ret = radeon_process_aux_ch(auxch,
                                            msg, msg_bytes, reply, reply_bytes, 0, &ack);
@@ -472,11 +436,11 @@ static void radeon_dp_probe_oui(struct radeon_connector *radeon_connector)
        if (!(dig_connector->dpcd[DP_DOWN_STREAM_PORT_COUNT] & DP_OUI_SUPPORT))
                return;
 
-       if (radeon_dp_aux_native_read(radeon_connector, DP_SINK_OUI, buf, 3, 0))
+       if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_SINK_OUI, buf, 3))
                DRM_DEBUG_KMS("Sink OUI: %02hx%02hx%02hx\n",
                              buf[0], buf[1], buf[2]);
 
-       if (radeon_dp_aux_native_read(radeon_connector, DP_BRANCH_OUI, buf, 3, 0))
+       if (drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_BRANCH_OUI, buf, 3))
                DRM_DEBUG_KMS("Branch OUI: %02hx%02hx%02hx\n",
                              buf[0], buf[1], buf[2]);
 }
@@ -487,8 +451,8 @@ bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector)
        u8 msg[DP_DPCD_SIZE];
        int ret, i;
 
-       ret = radeon_dp_aux_native_read(radeon_connector, DP_DPCD_REV, msg,
-                                       DP_DPCD_SIZE, 0);
+       ret = drm_dp_dpcd_read(&dig_connector->dp_i2c_bus->aux, DP_DPCD_REV, msg,
+                              DP_DPCD_SIZE);
        if (ret > 0) {
                memcpy(dig_connector->dpcd, msg, DP_DPCD_SIZE);
                DRM_DEBUG_KMS("DPCD: ");
@@ -510,6 +474,7 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector_atom_dig *dig_connector;
        int panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
        u16 dp_bridge = radeon_connector_encoder_get_dp_bridge_encoder_id(connector);
        u8 tmp;
@@ -517,9 +482,15 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
        if (!ASIC_IS_DCE4(rdev))
                return panel_mode;
 
+       if (!radeon_connector->con_priv)
+               return panel_mode;
+
+       dig_connector = radeon_connector->con_priv;
+
        if (dp_bridge != ENCODER_OBJECT_ID_NONE) {
                /* DP bridge chips */
-               tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP);
+               drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux,
+                                 DP_EDP_CONFIGURATION_CAP, &tmp);
                if (tmp & 1)
                        panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
                else if ((dp_bridge == ENCODER_OBJECT_ID_NUTMEG) ||
@@ -529,7 +500,8 @@ int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
                        panel_mode = DP_PANEL_MODE_EXTERNAL_DP_MODE;
        } else if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
                /* eDP */
-               tmp = radeon_read_dpcd_reg(radeon_connector, DP_EDP_CONFIGURATION_CAP);
+               drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux,
+                                 DP_EDP_CONFIGURATION_CAP, &tmp);
                if (tmp & 1)
                        panel_mode = DP_PANEL_MODE_INTERNAL_DP2_MODE;
        }
@@ -577,37 +549,42 @@ int radeon_dp_mode_valid_helper(struct drm_connector *connector,
        return MODE_OK;
 }
 
-static bool radeon_dp_get_link_status(struct radeon_connector *radeon_connector,
-                                     u8 link_status[DP_LINK_STATUS_SIZE])
-{
-       int ret;
-       ret = radeon_dp_aux_native_read(radeon_connector, DP_LANE0_1_STATUS,
-                                       link_status, DP_LINK_STATUS_SIZE, 100);
-       if (ret <= 0) {
-               return false;
-       }
-
-       DRM_DEBUG_KMS("link status %6ph\n", link_status);
-       return true;
-}
-
 bool radeon_dp_needs_link_train(struct radeon_connector *radeon_connector)
 {
        u8 link_status[DP_LINK_STATUS_SIZE];
        struct radeon_connector_atom_dig *dig = radeon_connector->con_priv;
 
-       if (!radeon_dp_get_link_status(radeon_connector, link_status))
+       if (drm_dp_dpcd_read_link_status(&dig->dp_i2c_bus->aux, link_status) <= 0)
                return false;
        if (drm_dp_channel_eq_ok(link_status, dig->dp_lane_count))
                return false;
        return true;
 }
 
+void radeon_dp_set_rx_power_state(struct drm_connector *connector,
+                                 u8 power_state)
+{
+       struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+       struct radeon_connector_atom_dig *dig_connector;
+
+       if (!radeon_connector->con_priv)
+               return;
+
+       dig_connector = radeon_connector->con_priv;
+
+       /* power up/down the sink */
+       if (dig_connector->dpcd[0] >= 0x11) {
+               drm_dp_dpcd_writeb(&dig_connector->dp_i2c_bus->aux,
+                                  DP_SET_POWER, power_state);
+               usleep_range(1000, 2000);
+       }
+}
+
+
 struct radeon_dp_link_train_info {
        struct radeon_device *rdev;
        struct drm_encoder *encoder;
        struct drm_connector *connector;
-       struct radeon_connector *radeon_connector;
        int enc_id;
        int dp_clock;
        int dp_lane_count;
@@ -617,6 +594,7 @@ struct radeon_dp_link_train_info {
        u8 link_status[DP_LINK_STATUS_SIZE];
        u8 tries;
        bool use_dpencoder;
+       struct drm_dp_aux *aux;
 };
 
 static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
@@ -627,8 +605,8 @@ static void radeon_dp_update_vs_emph(struct radeon_dp_link_train_info *dp_info)
                                       0, dp_info->train_set[0]); /* sets all lanes at once */
 
        /* set the vs/emph on the sink */
-       radeon_dp_aux_native_write(dp_info->radeon_connector, DP_TRAINING_LANE0_SET,
-                                  dp_info->train_set, dp_info->dp_lane_count, 0);
+       drm_dp_dpcd_write(dp_info->aux, DP_TRAINING_LANE0_SET,
+                         dp_info->train_set, dp_info->dp_lane_count);
 }
 
 static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
@@ -663,7 +641,7 @@ static void radeon_dp_set_tp(struct radeon_dp_link_train_info *dp_info, int tp)
        }
 
        /* enable training pattern on the sink */
-       radeon_write_dpcd_reg(dp_info->radeon_connector, DP_TRAINING_PATTERN_SET, tp);
+       drm_dp_dpcd_writeb(dp_info->aux, DP_TRAINING_PATTERN_SET, tp);
 }
 
 static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
@@ -673,34 +651,30 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
        u8 tmp;
 
        /* power up the sink */
-       if (dp_info->dpcd[0] >= 0x11) {
-               radeon_write_dpcd_reg(dp_info->radeon_connector,
-                                     DP_SET_POWER, DP_SET_POWER_D0);
-               usleep_range(1000, 2000);
-       }
+       radeon_dp_set_rx_power_state(dp_info->connector, DP_SET_POWER_D0);
 
        /* possibly enable downspread on the sink */
        if (dp_info->dpcd[3] & 0x1)
-               radeon_write_dpcd_reg(dp_info->radeon_connector,
-                                     DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
+               drm_dp_dpcd_writeb(dp_info->aux,
+                                  DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
        else
-               radeon_write_dpcd_reg(dp_info->radeon_connector,
-                                     DP_DOWNSPREAD_CTRL, 0);
+               drm_dp_dpcd_writeb(dp_info->aux,
+                                  DP_DOWNSPREAD_CTRL, 0);
 
        if ((dp_info->connector->connector_type == DRM_MODE_CONNECTOR_eDP) &&
            (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) {
-               radeon_write_dpcd_reg(dp_info->radeon_connector, DP_EDP_CONFIGURATION_SET, 1);
+               drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1);
        }
 
        /* set the lane count on the sink */
        tmp = dp_info->dp_lane_count;
        if (drm_dp_enhanced_frame_cap(dp_info->dpcd))
                tmp |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
-       radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LANE_COUNT_SET, tmp);
+       drm_dp_dpcd_writeb(dp_info->aux, DP_LANE_COUNT_SET, tmp);
 
        /* set the link rate on the sink */
        tmp = drm_dp_link_rate_to_bw_code(dp_info->dp_clock);
-       radeon_write_dpcd_reg(dp_info->radeon_connector, DP_LINK_BW_SET, tmp);
+       drm_dp_dpcd_writeb(dp_info->aux, DP_LINK_BW_SET, tmp);
 
        /* start training on the source */
        if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
@@ -711,9 +685,9 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
                                          dp_info->dp_clock, dp_info->enc_id, 0);
 
        /* disable the training pattern on the sink */
-       radeon_write_dpcd_reg(dp_info->radeon_connector,
-                             DP_TRAINING_PATTERN_SET,
-                             DP_TRAINING_PATTERN_DISABLE);
+       drm_dp_dpcd_writeb(dp_info->aux,
+                          DP_TRAINING_PATTERN_SET,
+                          DP_TRAINING_PATTERN_DISABLE);
 
        return 0;
 }
@@ -723,9 +697,9 @@ static int radeon_dp_link_train_finish(struct radeon_dp_link_train_info *dp_info
        udelay(400);
 
        /* disable the training pattern on the sink */
-       radeon_write_dpcd_reg(dp_info->radeon_connector,
-                             DP_TRAINING_PATTERN_SET,
-                             DP_TRAINING_PATTERN_DISABLE);
+       drm_dp_dpcd_writeb(dp_info->aux,
+                          DP_TRAINING_PATTERN_SET,
+                          DP_TRAINING_PATTERN_DISABLE);
 
        /* disable the training pattern on the source */
        if (ASIC_IS_DCE4(dp_info->rdev) || !dp_info->use_dpencoder)
@@ -757,7 +731,8 @@ static int radeon_dp_link_train_cr(struct radeon_dp_link_train_info *dp_info)
        while (1) {
                drm_dp_link_train_clock_recovery_delay(dp_info->dpcd);
 
-               if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) {
+               if (drm_dp_dpcd_read_link_status(dp_info->aux,
+                                                dp_info->link_status) <= 0) {
                        DRM_ERROR("displayport link status failed\n");
                        break;
                }
@@ -819,7 +794,8 @@ static int radeon_dp_link_train_ce(struct radeon_dp_link_train_info *dp_info)
        while (1) {
                drm_dp_link_train_channel_eq_delay(dp_info->dpcd);
 
-               if (!radeon_dp_get_link_status(dp_info->radeon_connector, dp_info->link_status)) {
+               if (drm_dp_dpcd_read_link_status(dp_info->aux,
+                                                dp_info->link_status) <= 0) {
                        DRM_ERROR("displayport link status failed\n");
                        break;
                }
@@ -902,7 +878,7 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
        else
                dp_info.enc_id |= ATOM_DP_CONFIG_LINK_A;
 
-       tmp = radeon_read_dpcd_reg(radeon_connector, DP_MAX_LANE_COUNT);
+       drm_dp_dpcd_readb(&dig_connector->dp_i2c_bus->aux, DP_MAX_LANE_COUNT, &tmp);
        if (ASIC_IS_DCE5(rdev) && (tmp & DP_TPS3_SUPPORTED))
                dp_info.tp3_supported = true;
        else
@@ -912,9 +888,9 @@ void radeon_dp_link_train(struct drm_encoder *encoder,
        dp_info.rdev = rdev;
        dp_info.encoder = encoder;
        dp_info.connector = connector;
-       dp_info.radeon_connector = radeon_connector;
        dp_info.dp_lane_count = dig_connector->dp_lane_count;
        dp_info.dp_clock = dig_connector->dp_clock;
+       dp_info.aux = &dig_connector->dp_i2c_bus->aux;
 
        if (radeon_dp_link_train_init(&dp_info))
                goto done;
index 607dc14..e6eb509 100644 (file)
@@ -1633,10 +1633,16 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
        struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
        struct radeon_connector *radeon_connector = NULL;
        struct radeon_connector_atom_dig *radeon_dig_connector = NULL;
+       bool travis_quirk = false;
 
        if (connector) {
                radeon_connector = to_radeon_connector(connector);
                radeon_dig_connector = radeon_connector->con_priv;
+               if ((radeon_connector_encoder_get_dp_bridge_encoder_id(connector) ==
+                    ENCODER_OBJECT_ID_TRAVIS) &&
+                   (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT)) &&
+                   !ASIC_IS_DCE5(rdev))
+                       travis_quirk = true;
        }
 
        switch (mode) {
@@ -1657,17 +1663,13 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
                                        atombios_external_encoder_setup(encoder, ext_encoder,
                                                                        EXTERNAL_ENCODER_ACTION_V3_ENCODER_SETUP);
                        }
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                } else if (ASIC_IS_DCE4(rdev)) {
                        /* setup and enable the encoder */
                        atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_SETUP, 0);
-                       /* enable the transmitter */
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                } else {
                        /* setup and enable the encoder and transmitter */
                        atombios_dig_encoder_setup(encoder, ATOM_ENABLE, 0);
                        atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_SETUP, 0, 0);
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
                }
                if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
                        if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
@@ -1675,68 +1677,56 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
                                                             ATOM_TRANSMITTER_ACTION_POWER_ON);
                                radeon_dig_connector->edp_on = true;
                        }
+               }
+               /* enable the transmitter */
+               atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_ENABLE, 0, 0);
+               if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
+                       /* DP_SET_POWER_D0 is set in radeon_dp_link_train */
                        radeon_dp_link_train(encoder, connector);
                        if (ASIC_IS_DCE4(rdev))
                                atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_ON, 0);
                }
                if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
+                       atombios_dig_transmitter_setup(encoder,
+                                                      ATOM_TRANSMITTER_ACTION_LCD_BLON, 0, 0);
+               if (ext_encoder)
+                       atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
                break;
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
        case DRM_MODE_DPMS_OFF:
+               if (ASIC_IS_DCE4(rdev)) {
+                       if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector)
+                               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
+               }
+               if (ext_encoder)
+                       atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE);
+               if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
+                       atombios_dig_transmitter_setup(encoder,
+                                                      ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
+
+               if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) &&
+                   connector && !travis_quirk)
+                       radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3);
                if (ASIC_IS_DCE4(rdev)) {
                        /* disable the transmitter */
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
+                       atombios_dig_transmitter_setup(encoder,
+                                                      ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
                } else {
                        /* disable the encoder and transmitter */
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
+                       atombios_dig_transmitter_setup(encoder,
+                                                      ATOM_TRANSMITTER_ACTION_DISABLE, 0, 0);
                        atombios_dig_encoder_setup(encoder, ATOM_DISABLE, 0);
                }
                if (ENCODER_MODE_IS_DP(atombios_get_encoder_mode(encoder)) && connector) {
-                       if (ASIC_IS_DCE4(rdev))
-                               atombios_dig_encoder_setup(encoder, ATOM_ENCODER_CMD_DP_VIDEO_OFF, 0);
+                       if (travis_quirk)
+                               radeon_dp_set_rx_power_state(connector, DP_SET_POWER_D3);
                        if (connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
                                atombios_set_edp_panel_power(connector,
                                                             ATOM_TRANSMITTER_ACTION_POWER_OFF);
                                radeon_dig_connector->edp_on = false;
                        }
                }
-               if (radeon_encoder->devices & (ATOM_DEVICE_LCD_SUPPORT))
-                       atombios_dig_transmitter_setup(encoder, ATOM_TRANSMITTER_ACTION_LCD_BLOFF, 0, 0);
-               break;
-       }
-}
-
-static void
-radeon_atom_encoder_dpms_ext(struct drm_encoder *encoder,
-                            struct drm_encoder *ext_encoder,
-                            int mode)
-{
-       struct drm_device *dev = encoder->dev;
-       struct radeon_device *rdev = dev->dev_private;
-
-       switch (mode) {
-       case DRM_MODE_DPMS_ON:
-       default:
-               if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) {
-                       atombios_external_encoder_setup(encoder, ext_encoder,
-                                                       EXTERNAL_ENCODER_ACTION_V3_ENABLE_OUTPUT);
-                       atombios_external_encoder_setup(encoder, ext_encoder,
-                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING_OFF);
-               } else
-                       atombios_external_encoder_setup(encoder, ext_encoder, ATOM_ENABLE);
-               break;
-       case DRM_MODE_DPMS_STANDBY:
-       case DRM_MODE_DPMS_SUSPEND:
-       case DRM_MODE_DPMS_OFF:
-               if (ASIC_IS_DCE41(rdev) || ASIC_IS_DCE61(rdev)) {
-                       atombios_external_encoder_setup(encoder, ext_encoder,
-                                                       EXTERNAL_ENCODER_ACTION_V3_ENCODER_BLANKING);
-                       atombios_external_encoder_setup(encoder, ext_encoder,
-                                                       EXTERNAL_ENCODER_ACTION_V3_DISABLE_OUTPUT);
-               } else
-                       atombios_external_encoder_setup(encoder, ext_encoder, ATOM_DISABLE);
                break;
        }
 }
@@ -1747,7 +1737,6 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
        struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
-       struct drm_encoder *ext_encoder = radeon_get_external_encoder(encoder);
 
        DRM_DEBUG_KMS("encoder dpms %d to mode %d, devices %08x, active_devices %08x\n",
                  radeon_encoder->encoder_id, mode, radeon_encoder->devices,
@@ -1807,9 +1796,6 @@ radeon_atom_encoder_dpms(struct drm_encoder *encoder, int mode)
                return;
        }
 
-       if (ext_encoder)
-               radeon_atom_encoder_dpms_ext(encoder, ext_encoder, mode);
-
        radeon_atombios_encoder_dpms_scratch_regs(encoder, (mode == DRM_MODE_DPMS_ON) ? true : false);
 
 }
index ea103cc..f81d7ca 100644 (file)
@@ -2601,6 +2601,10 @@ int btc_dpm_init(struct radeon_device *rdev)
        pi->min_vddc_in_table = 0;
        pi->max_vddc_in_table = 0;
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = rv7xx_parse_power_table(rdev);
        if (ret)
                return ret;
index 8d49104..cad89a9 100644 (file)
@@ -172,6 +172,8 @@ extern void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,
 extern void cik_enter_rlc_safe_mode(struct radeon_device *rdev);
 extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev);
 extern int ci_mc_load_microcode(struct radeon_device *rdev);
+extern void cik_update_cg(struct radeon_device *rdev,
+                         u32 block, bool enable);
 
 static int ci_get_std_voltage_value_sidd(struct radeon_device *rdev,
                                         struct atom_voltage_table_entry *voltage_table,
@@ -746,6 +748,14 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,
        u32 max_sclk_vddc, max_mclk_vddci, max_mclk_vddc;
        int i;
 
+       if (rps->vce_active) {
+               rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
+               rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
+       } else {
+               rps->evclk = 0;
+               rps->ecclk = 0;
+       }
+
        if ((rdev->pm.dpm.new_active_crtc_count > 1) ||
            ci_dpm_vblank_too_short(rdev))
                disable_mclk_switching = true;
@@ -804,6 +814,13 @@ static void ci_apply_state_adjust_rules(struct radeon_device *rdev,
                sclk = ps->performance_levels[0].sclk;
        }
 
+       if (rps->vce_active) {
+               if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
+                       sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
+               if (mclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk)
+                       mclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].mclk;
+       }
+
        ps->performance_levels[0].sclk = sclk;
        ps->performance_levels[0].mclk = mclk;
 
@@ -3468,7 +3485,6 @@ static int ci_enable_uvd_dpm(struct radeon_device *rdev, bool enable)
                0 : -EINVAL;
 }
 
-#if 0
 static int ci_enable_vce_dpm(struct radeon_device *rdev, bool enable)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
@@ -3501,6 +3517,7 @@ static int ci_enable_vce_dpm(struct radeon_device *rdev, bool enable)
                0 : -EINVAL;
 }
 
+#if 0
 static int ci_enable_samu_dpm(struct radeon_device *rdev, bool enable)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
@@ -3587,7 +3604,6 @@ static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate)
        return ci_enable_uvd_dpm(rdev, !gate);
 }
 
-#if 0
 static u8 ci_get_vce_boot_level(struct radeon_device *rdev)
 {
        u8 i;
@@ -3608,15 +3624,15 @@ static int ci_update_vce_dpm(struct radeon_device *rdev,
                             struct radeon_ps *radeon_current_state)
 {
        struct ci_power_info *pi = ci_get_pi(rdev);
-       bool new_vce_clock_non_zero = (radeon_new_state->evclk != 0);
-       bool old_vce_clock_non_zero = (radeon_current_state->evclk != 0);
        int ret = 0;
        u32 tmp;
 
-       if (new_vce_clock_non_zero != old_vce_clock_non_zero) {
-               if (new_vce_clock_non_zero) {
-                       pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(rdev);
+       if (radeon_current_state->evclk != radeon_new_state->evclk) {
+               if (radeon_new_state->evclk) {
+                       /* turn the clocks on when encoding */
+                       cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false);
 
+                       pi->smc_state_table.VceBootLevel = ci_get_vce_boot_level(rdev);
                        tmp = RREG32_SMC(DPM_TABLE_475);
                        tmp &= ~VceBootLevel_MASK;
                        tmp |= VceBootLevel(pi->smc_state_table.VceBootLevel);
@@ -3624,12 +3640,16 @@ static int ci_update_vce_dpm(struct radeon_device *rdev,
 
                        ret = ci_enable_vce_dpm(rdev, true);
                } else {
+                       /* turn the clocks off when not encoding */
+                       cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true);
+
                        ret = ci_enable_vce_dpm(rdev, false);
                }
        }
        return ret;
 }
 
+#if 0
 static int ci_update_samu_dpm(struct radeon_device *rdev, bool gate)
 {
        return ci_enable_samu_dpm(rdev, gate);
@@ -4752,13 +4772,13 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)
                DRM_ERROR("ci_generate_dpm_level_enable_mask failed\n");
                return ret;
        }
-#if 0
+
        ret = ci_update_vce_dpm(rdev, new_ps, old_ps);
        if (ret) {
                DRM_ERROR("ci_update_vce_dpm failed\n");
                return ret;
        }
-#endif
+
        ret = ci_update_sclk_t(rdev);
        if (ret) {
                DRM_ERROR("ci_update_sclk_t failed\n");
@@ -4959,9 +4979,6 @@ static int ci_parse_power_table(struct radeon_device *rdev)
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
        power_state_offset = (u8 *)state_array->states;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
        for (i = 0; i < state_array->ucNumEntries; i++) {
                u8 *idx;
                power_state = (union pplib_power_state *)power_state_offset;
@@ -4998,6 +5015,21 @@ static int ci_parse_power_table(struct radeon_device *rdev)
                power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
        }
        rdev->pm.dpm.num_ps = state_array->ucNumEntries;
+
+       /* fill in the vce power states */
+       for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
+               u32 sclk, mclk;
+               clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
+               clock_info = (union pplib_clock_info *)
+                       &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+               sclk = le16_to_cpu(clock_info->ci.usEngineClockLow);
+               sclk |= clock_info->ci.ucEngineClockHigh << 16;
+               mclk = le16_to_cpu(clock_info->ci.usMemoryClockLow);
+               mclk |= clock_info->ci.ucMemoryClockHigh << 16;
+               rdev->pm.dpm.vce_states[i].sclk = sclk;
+               rdev->pm.dpm.vce_states[i].mclk = mclk;
+       }
+
        return 0;
 }
 
@@ -5077,17 +5109,25 @@ int ci_dpm_init(struct radeon_device *rdev)
                ci_dpm_fini(rdev);
                return ret;
        }
-       ret = ci_parse_power_table(rdev);
+
+       ret = r600_get_platform_caps(rdev);
        if (ret) {
                ci_dpm_fini(rdev);
                return ret;
        }
+
        ret = r600_parse_extended_power_table(rdev);
        if (ret) {
                ci_dpm_fini(rdev);
                return ret;
        }
 
+       ret = ci_parse_power_table(rdev);
+       if (ret) {
+               ci_dpm_fini(rdev);
+               return ret;
+       }
+
         pi->dll_default_on = false;
         pi->sram_end = SMC_RAM_END;
 
@@ -5120,6 +5160,7 @@ int ci_dpm_init(struct radeon_device *rdev)
        pi->caps_sclk_throttle_low_notification = false;
 
        pi->caps_uvd_dpm = true;
+       pi->caps_vce_dpm = true;
 
         ci_get_leakage_voltages(rdev);
         ci_patch_dependency_tables_with_leakage(rdev);
index bbb1784..745143c 100644 (file)
@@ -75,6 +75,7 @@ extern void si_init_uvd_internal_cg(struct radeon_device *rdev);
 extern int cik_sdma_resume(struct radeon_device *rdev);
 extern void cik_sdma_enable(struct radeon_device *rdev, bool enable);
 extern void cik_sdma_fini(struct radeon_device *rdev);
+extern void vce_v2_0_enable_mgcg(struct radeon_device *rdev, bool enable);
 static void cik_rlc_stop(struct radeon_device *rdev);
 static void cik_pcie_gen3_enable(struct radeon_device *rdev);
 static void cik_program_aspm(struct radeon_device *rdev);
@@ -1095,7 +1096,7 @@ static const u32 spectre_golden_registers[] =
        0x8a14, 0xf000003f, 0x00000007,
        0x8b24, 0xffffffff, 0x00ffffff,
        0x28350, 0x3f3f3fff, 0x00000082,
-       0x28355, 0x0000003f, 0x00000000,
+       0x28354, 0x0000003f, 0x00000000,
        0x3e78, 0x00000001, 0x00000002,
        0x913c, 0xffff03df, 0x00000004,
        0xc768, 0x00000008, 0x00000008,
@@ -2028,6 +2029,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 5:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
                                break;
                        case 6:
@@ -2048,6 +2050,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 9:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
                                break;
                        case 10:
@@ -2070,6 +2073,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 13:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
                                break;
                        case 14:
@@ -2092,6 +2096,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 27:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P16_32x32_16x16) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
                                break;
                        case 28:
@@ -2246,6 +2251,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 5:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
                                break;
                        case 6:
@@ -2266,6 +2272,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 9:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
                                break;
                        case 10:
@@ -2288,6 +2295,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 13:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
                                break;
                        case 14:
@@ -2310,6 +2318,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 27:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P8_32x32_16x16) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
                                break;
                        case 28:
@@ -2466,6 +2475,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                        break;
                                case 5:
                                        gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                        PIPE_CONFIG(ADDR_SURF_P4_16x16) |
                                                         MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
                                        break;
                                case 6:
@@ -2486,6 +2496,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                        break;
                                case 9:
                                        gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                        PIPE_CONFIG(ADDR_SURF_P4_16x16) |
                                                         MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
                                        break;
                                case 10:
@@ -2508,6 +2519,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                        break;
                                case 13:
                                        gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                        PIPE_CONFIG(ADDR_SURF_P4_16x16) |
                                                         MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
                                        break;
                                case 14:
@@ -2530,6 +2542,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                        break;
                                case 27:
                                        gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                        PIPE_CONFIG(ADDR_SURF_P4_16x16) |
                                                         MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
                                        break;
                                case 28:
@@ -2592,6 +2605,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                        break;
                                case 5:
                                        gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                        PIPE_CONFIG(ADDR_SURF_P4_8x16) |
                                                         MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
                                        break;
                                case 6:
@@ -2612,6 +2626,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                        break;
                                case 9:
                                        gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                        PIPE_CONFIG(ADDR_SURF_P4_8x16) |
                                                         MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
                                        break;
                                case 10:
@@ -2634,6 +2649,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                        break;
                                case 13:
                                        gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                        PIPE_CONFIG(ADDR_SURF_P4_8x16) |
                                                         MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
                                        break;
                                case 14:
@@ -2656,6 +2672,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                        break;
                                case 27:
                                        gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                        PIPE_CONFIG(ADDR_SURF_P4_8x16) |
                                                         MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
                                        break;
                                case 28:
@@ -2812,6 +2829,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 5:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P2) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_DEPTH_MICRO_TILING));
                                break;
                        case 6:
@@ -2827,11 +2845,13 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                                 TILE_SPLIT(split_equal_to_row_size));
                                break;
                        case 8:
-                               gb_tile_moden = ARRAY_MODE(ARRAY_LINEAR_ALIGNED);
+                               gb_tile_moden = ARRAY_MODE(ARRAY_LINEAR_ALIGNED) |
+                                               PIPE_CONFIG(ADDR_SURF_P2);
                                break;
                        case 9:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
-                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING));
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_DISPLAY_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P2));
                                break;
                        case 10:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_2D_TILED_THIN1) |
@@ -2853,6 +2873,7 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 13:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
+                                                PIPE_CONFIG(ADDR_SURF_P2) |
                                                 MICRO_TILE_MODE_NEW(ADDR_SURF_THIN_MICRO_TILING));
                                break;
                        case 14:
@@ -2875,7 +2896,8 @@ static void cik_tiling_mode_table_init(struct radeon_device *rdev)
                                break;
                        case 27:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_1D_TILED_THIN1) |
-                                                MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING));
+                                                MICRO_TILE_MODE_NEW(ADDR_SURF_ROTATED_MICRO_TILING) |
+                                                PIPE_CONFIG(ADDR_SURF_P2));
                                break;
                        case 28:
                                gb_tile_moden = (ARRAY_MODE(ARRAY_PRT_2D_TILED_THIN1) |
@@ -4030,8 +4052,6 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)
        WREG32(CP_RB0_BASE, rb_addr);
        WREG32(CP_RB0_BASE_HI, upper_32_bits(rb_addr));
 
-       ring->rptr = RREG32(CP_RB0_RPTR);
-
        /* start the ring */
        cik_cp_gfx_start(rdev);
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = true;
@@ -4589,8 +4609,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
                rdev->ring[idx].wptr = 0;
                mqd->queue_state.cp_hqd_pq_wptr = rdev->ring[idx].wptr;
                WREG32(CP_HQD_PQ_WPTR, mqd->queue_state.cp_hqd_pq_wptr);
-               rdev->ring[idx].rptr = RREG32(CP_HQD_PQ_RPTR);
-               mqd->queue_state.cp_hqd_pq_rptr = rdev->ring[idx].rptr;
+               mqd->queue_state.cp_hqd_pq_rptr = RREG32(CP_HQD_PQ_RPTR);
 
                /* set the vmid for the queue */
                mqd->queue_state.cp_hqd_vmid = 0;
@@ -5120,11 +5139,9 @@ bool cik_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
        if (!(reset_mask & (RADEON_RESET_GFX |
                            RADEON_RESET_COMPUTE |
                            RADEON_RESET_CP))) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force CP activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
@@ -6144,6 +6161,10 @@ void cik_update_cg(struct radeon_device *rdev,
                cik_enable_hdp_mgcg(rdev, enable);
                cik_enable_hdp_ls(rdev, enable);
        }
+
+       if (block & RADEON_CG_BLOCK_VCE) {
+               vce_v2_0_enable_mgcg(rdev, enable);
+       }
 }
 
 static void cik_init_cg(struct radeon_device *rdev)
@@ -6521,8 +6542,8 @@ void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer)
                buffer[count++] = cpu_to_le32(0x00000000);
                break;
        case CHIP_HAWAII:
-               buffer[count++] = 0x3a00161a;
-               buffer[count++] = 0x0000002e;
+               buffer[count++] = cpu_to_le32(0x3a00161a);
+               buffer[count++] = cpu_to_le32(0x0000002e);
                break;
        default:
                buffer[count++] = cpu_to_le32(0x00000000);
@@ -7493,6 +7514,20 @@ restart_ih:
                        /* reset addr and status */
                        WREG32_P(VM_CONTEXT1_CNTL2, 1, ~1);
                        break;
+               case 167: /* VCE */
+                       DRM_DEBUG("IH: VCE int: 0x%08x\n", src_data);
+                       switch (src_data) {
+                       case 0:
+                               radeon_fence_process(rdev, TN_RING_TYPE_VCE1_INDEX);
+                               break;
+                       case 1:
+                               radeon_fence_process(rdev, TN_RING_TYPE_VCE2_INDEX);
+                               break;
+                       default:
+                               DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
+                               break;
+                       }
+                       break;
                case 176: /* GFX RB CP_INT */
                case 177: /* GFX IB CP_INT */
                        radeon_fence_process(rdev, RADEON_RING_TYPE_GFX_INDEX);
@@ -7792,6 +7827,22 @@ static int cik_startup(struct radeon_device *rdev)
        if (r)
                rdev->ring[R600_RING_TYPE_UVD_INDEX].ring_size = 0;
 
+       r = radeon_vce_resume(rdev);
+       if (!r) {
+               r = vce_v2_0_resume(rdev);
+               if (!r)
+                       r = radeon_fence_driver_start_ring(rdev,
+                                                          TN_RING_TYPE_VCE1_INDEX);
+               if (!r)
+                       r = radeon_fence_driver_start_ring(rdev,
+                                                          TN_RING_TYPE_VCE2_INDEX);
+       }
+       if (r) {
+               dev_err(rdev->dev, "VCE init error (%d).\n", r);
+               rdev->ring[TN_RING_TYPE_VCE1_INDEX].ring_size = 0;
+               rdev->ring[TN_RING_TYPE_VCE2_INDEX].ring_size = 0;
+       }
+
        /* Enable IRQ */
        if (!rdev->irq.installed) {
                r = radeon_irq_kms_init(rdev);
@@ -7867,6 +7918,23 @@ static int cik_startup(struct radeon_device *rdev)
                        DRM_ERROR("radeon: failed initializing UVD (%d).\n", r);
        }
 
+       r = -ENOENT;
+
+       ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
+       if (ring->ring_size)
+               r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
+                                    VCE_CMD_NO_OP);
+
+       ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
+       if (ring->ring_size)
+               r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
+                                    VCE_CMD_NO_OP);
+
+       if (!r)
+               r = vce_v1_0_init(rdev);
+       else if (r != -ENOENT)
+               DRM_ERROR("radeon: failed initializing VCE (%d).\n", r);
+
        r = radeon_ib_pool_init(rdev);
        if (r) {
                dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
@@ -7938,6 +8006,7 @@ int cik_suspend(struct radeon_device *rdev)
        cik_sdma_enable(rdev, false);
        uvd_v1_0_fini(rdev);
        radeon_uvd_suspend(rdev);
+       radeon_vce_suspend(rdev);
        cik_fini_pg(rdev);
        cik_fini_cg(rdev);
        cik_irq_suspend(rdev);
@@ -8070,6 +8139,17 @@ int cik_init(struct radeon_device *rdev)
                r600_ring_init(rdev, ring, 4096);
        }
 
+       r = radeon_vce_init(rdev);
+       if (!r) {
+               ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
+               ring->ring_obj = NULL;
+               r600_ring_init(rdev, ring, 4096);
+
+               ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
+               ring->ring_obj = NULL;
+               r600_ring_init(rdev, ring, 4096);
+       }
+
        rdev->ih.ring_obj = NULL;
        r600_ih_ring_init(rdev, 64 * 1024);
 
@@ -8131,6 +8211,7 @@ void cik_fini(struct radeon_device *rdev)
        radeon_irq_kms_fini(rdev);
        uvd_v1_0_fini(rdev);
        radeon_uvd_fini(rdev);
+       radeon_vce_fini(rdev);
        cik_pcie_gart_fini(rdev);
        r600_vram_scratch_fini(rdev);
        radeon_gem_fini(rdev);
@@ -8869,6 +8950,41 @@ int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk)
        return r;
 }
 
+int cik_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk)
+{
+       int r, i;
+       struct atom_clock_dividers dividers;
+       u32 tmp;
+
+       r = radeon_atom_get_clock_dividers(rdev, COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK,
+                                          ecclk, false, &dividers);
+       if (r)
+               return r;
+
+       for (i = 0; i < 100; i++) {
+               if (RREG32_SMC(CG_ECLK_STATUS) & ECLK_STATUS)
+                       break;
+               mdelay(10);
+       }
+       if (i == 100)
+               return -ETIMEDOUT;
+
+       tmp = RREG32_SMC(CG_ECLK_CNTL);
+       tmp &= ~(ECLK_DIR_CNTL_EN|ECLK_DIVIDER_MASK);
+       tmp |= dividers.post_divider;
+       WREG32_SMC(CG_ECLK_CNTL, tmp);
+
+       for (i = 0; i < 100; i++) {
+               if (RREG32_SMC(CG_ECLK_STATUS) & ECLK_STATUS)
+                       break;
+               mdelay(10);
+       }
+       if (i == 100)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
 static void cik_pcie_gen3_enable(struct radeon_device *rdev)
 {
        struct pci_dev *root = rdev->pdev->bus->self;
index 94626ea..89b4afa 100644 (file)
@@ -369,8 +369,6 @@ static int cik_sdma_gfx_resume(struct radeon_device *rdev)
                ring->wptr = 0;
                WREG32(SDMA0_GFX_RB_WPTR + reg_offset, ring->wptr << 2);
 
-               ring->rptr = RREG32(SDMA0_GFX_RB_RPTR + reg_offset) >> 2;
-
                /* enable DMA RB */
                WREG32(SDMA0_GFX_RB_CNTL + reg_offset, rb_cntl | SDMA_RB_ENABLE);
 
@@ -713,11 +711,9 @@ bool cik_sdma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
                mask = RADEON_RESET_DMA1;
 
        if (!(reset_mask & mask)) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force ring activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
index 98bae9d..2138732 100644 (file)
 #define                CTF_TEMP_MASK                           0x0003fe00
 #define                CTF_TEMP_SHIFT                          9
 
+#define CG_ECLK_CNTL                                    0xC05000AC
+#       define ECLK_DIVIDER_MASK                        0x7f
+#       define ECLK_DIR_CNTL_EN                         (1 << 8)
+#define CG_ECLK_STATUS                                  0xC05000B0
+#       define ECLK_STATUS                              (1 << 0)
+
 #define        CG_SPLL_FUNC_CNTL                               0xC0500140
 #define                SPLL_RESET                              (1 << 0)
 #define                SPLL_PWRON                              (1 << 1)
 /* UVD CTX indirect */
 #define        UVD_CGC_MEM_CTRL                                0xC0
 
+/* VCE */
+
+#define VCE_VCPU_CACHE_OFFSET0         0x20024
+#define VCE_VCPU_CACHE_SIZE0           0x20028
+#define VCE_VCPU_CACHE_OFFSET1         0x2002c
+#define VCE_VCPU_CACHE_SIZE1           0x20030
+#define VCE_VCPU_CACHE_OFFSET2         0x20034
+#define VCE_VCPU_CACHE_SIZE2           0x20038
+#define VCE_RB_RPTR2                   0x20178
+#define VCE_RB_WPTR2                   0x2017c
+#define VCE_RB_RPTR                    0x2018c
+#define VCE_RB_WPTR                    0x20190
+#define VCE_CLOCK_GATING_A             0x202f8
+#      define CGC_CLK_GATE_DLY_TIMER_MASK      (0xf << 0)
+#      define CGC_CLK_GATE_DLY_TIMER(x)        ((x) << 0)
+#      define CGC_CLK_GATER_OFF_DLY_TIMER_MASK (0xff << 4)
+#      define CGC_CLK_GATER_OFF_DLY_TIMER(x)   ((x) << 4)
+#      define CGC_UENC_WAIT_AWAKE      (1 << 18)
+#define VCE_CLOCK_GATING_B             0x202fc
+#define VCE_CGTT_CLK_OVERRIDE          0x207a0
+#define VCE_UENC_CLOCK_GATING          0x207bc
+#      define CLOCK_ON_DELAY_MASK      (0xf << 0)
+#      define CLOCK_ON_DELAY(x)        ((x) << 0)
+#      define CLOCK_OFF_DELAY_MASK     (0xff << 4)
+#      define CLOCK_OFF_DELAY(x)       ((x) << 4)
+#define VCE_UENC_REG_CLOCK_GATING      0x207c0
+#define VCE_SYS_INT_EN                 0x21300
+#      define VCE_SYS_INT_TRAP_INTERRUPT_EN    (1 << 3)
+#define VCE_LMI_CTRL2                  0x21474
+#define VCE_LMI_CTRL                   0x21498
+#define VCE_LMI_VM_CTRL                        0x214a0
+#define VCE_LMI_SWAP_CNTL              0x214b4
+#define VCE_LMI_SWAP_CNTL1             0x214b8
+#define VCE_LMI_CACHE_CTRL             0x214f4
+
+#define VCE_CMD_NO_OP          0x00000000
+#define VCE_CMD_END            0x00000001
+#define VCE_CMD_IB             0x00000002
+#define VCE_CMD_FENCE          0x00000003
+#define VCE_CMD_TRAP           0x00000004
+#define VCE_CMD_IB_AUTO                0x00000005
+#define VCE_CMD_SEMAPHORE      0x00000006
+
 #endif
index cf783fc..5a9a5f4 100644 (file)
@@ -2036,6 +2036,10 @@ int cypress_dpm_init(struct radeon_device *rdev)
        pi->min_vddc_in_table = 0;
        pi->max_vddc_in_table = 0;
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = rv7xx_parse_power_table(rdev);
        if (ret)
                return ret;
index 27b0ff1..b406546 100644 (file)
@@ -2990,8 +2990,6 @@ static int evergreen_cp_resume(struct radeon_device *rdev)
        WREG32(CP_RB_BASE, ring->gpu_addr >> 8);
        WREG32(CP_DEBUG, (1 << 27) | (1 << 28));
 
-       ring->rptr = RREG32(CP_RB_RPTR);
-
        evergreen_cp_start(rdev);
        ring->ready = true;
        r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring);
@@ -3952,11 +3950,9 @@ bool evergreen_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin
        if (!(reset_mask & (RADEON_RESET_GFX |
                            RADEON_RESET_COMPUTE |
                            RADEON_RESET_CP))) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force CP activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
index c7cac07..5c8b358 100644 (file)
@@ -1165,7 +1165,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                break;
        case DB_DEPTH_CONTROL:
                track->db_depth_control = radeon_get_ib_value(p, idx);
@@ -1196,12 +1196,12 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        }
                        ib[idx] &= ~Z_ARRAY_MODE(0xf);
                        track->db_z_info &= ~Z_ARRAY_MODE(0xf);
-                       ib[idx] |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
-                       track->db_z_info |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+                       ib[idx] |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
+                       track->db_z_info |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO) {
                                unsigned bankw, bankh, mtaspect, tile_split;
 
-                               evergreen_tiling_fields(reloc->lobj.tiling_flags,
+                               evergreen_tiling_fields(reloc->tiling_flags,
                                                        &bankw, &bankh, &mtaspect,
                                                        &tile_split);
                                ib[idx] |= DB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
@@ -1237,7 +1237,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        return -EINVAL;
                }
                track->db_z_read_offset = radeon_get_ib_value(p, idx);
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->db_z_read_bo = reloc->robj;
                track->db_dirty = true;
                break;
@@ -1249,7 +1249,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        return -EINVAL;
                }
                track->db_z_write_offset = radeon_get_ib_value(p, idx);
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->db_z_write_bo = reloc->robj;
                track->db_dirty = true;
                break;
@@ -1261,7 +1261,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        return -EINVAL;
                }
                track->db_s_read_offset = radeon_get_ib_value(p, idx);
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->db_s_read_bo = reloc->robj;
                track->db_dirty = true;
                break;
@@ -1273,7 +1273,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        return -EINVAL;
                }
                track->db_s_write_offset = radeon_get_ib_value(p, idx);
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->db_s_write_bo = reloc->robj;
                track->db_dirty = true;
                break;
@@ -1297,7 +1297,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                }
                tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;
                track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->vgt_strmout_bo[tmp] = reloc->robj;
                track->streamout_dirty = true;
                break;
@@ -1317,7 +1317,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
        case CB_TARGET_MASK:
                track->cb_target_mask = radeon_get_ib_value(p, idx);
                track->cb_dirty = true;
@@ -1381,8 +1381,8 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                                "0x%04X\n", reg);
                                return -EINVAL;
                        }
-                       ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
-                       track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
+                       ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
+                       track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
                }
                track->cb_dirty = true;
                break;
@@ -1399,8 +1399,8 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                                "0x%04X\n", reg);
                                return -EINVAL;
                        }
-                       ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
-                       track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
+                       ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
+                       track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
                }
                track->cb_dirty = true;
                break;
@@ -1461,10 +1461,10 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        return -EINVAL;
                }
                if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO) {
                                unsigned bankw, bankh, mtaspect, tile_split;
 
-                               evergreen_tiling_fields(reloc->lobj.tiling_flags,
+                               evergreen_tiling_fields(reloc->tiling_flags,
                                                        &bankw, &bankh, &mtaspect,
                                                        &tile_split);
                                ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
@@ -1489,10 +1489,10 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        return -EINVAL;
                }
                if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO) {
                                unsigned bankw, bankh, mtaspect, tile_split;
 
-                               evergreen_tiling_fields(reloc->lobj.tiling_flags,
+                               evergreen_tiling_fields(reloc->tiling_flags,
                                                        &bankw, &bankh, &mtaspect,
                                                        &tile_split);
                                ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
@@ -1520,7 +1520,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->cb_color_fmask_bo[tmp] = reloc->robj;
                break;
        case CB_COLOR0_CMASK:
@@ -1537,7 +1537,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->cb_color_cmask_bo[tmp] = reloc->robj;
                break;
        case CB_COLOR0_FMASK_SLICE:
@@ -1578,7 +1578,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                }
                tmp = (reg - CB_COLOR0_BASE) / 0x3c;
                track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->cb_color_bo[tmp] = reloc->robj;
                track->cb_dirty = true;
                break;
@@ -1594,7 +1594,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                }
                tmp = ((reg - CB_COLOR8_BASE) / 0x1c) + 8;
                track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->cb_color_bo[tmp] = reloc->robj;
                track->cb_dirty = true;
                break;
@@ -1606,7 +1606,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        return -EINVAL;
                }
                track->htile_offset = radeon_get_ib_value(p, idx);
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->htile_bo = reloc->robj;
                track->db_dirty = true;
                break;
@@ -1723,7 +1723,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                break;
        case SX_MEMORY_EXPORT_BASE:
                if (p->rdev->family >= CHIP_CAYMAN) {
@@ -1737,7 +1737,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                break;
        case CAYMAN_SX_SCATTER_EXPORT_BASE:
                if (p->rdev->family < CHIP_CAYMAN) {
@@ -1751,7 +1751,7 @@ static int evergreen_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                break;
        case SX_MISC:
                track->sx_misc_kill_all_prims = (radeon_get_ib_value(p, idx) & 0x1) != 0;
@@ -1836,7 +1836,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
 
-               offset = reloc->lobj.gpu_offset +
+               offset = reloc->gpu_offset +
                         (idx_value & 0xfffffff0) +
                         ((u64)(tmp & 0xff) << 32);
 
@@ -1882,7 +1882,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
 
-               offset = reloc->lobj.gpu_offset +
+               offset = reloc->gpu_offset +
                         idx_value +
                         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
 
@@ -1909,7 +1909,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
 
-               offset = reloc->lobj.gpu_offset +
+               offset = reloc->gpu_offset +
                         idx_value +
                         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
 
@@ -1937,7 +1937,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
 
-               offset = reloc->lobj.gpu_offset +
+               offset = reloc->gpu_offset +
                         radeon_get_ib_value(p, idx+1) +
                         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
 
@@ -2027,7 +2027,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                        DRM_ERROR("bad DISPATCH_INDIRECT\n");
                        return -EINVAL;
                }
-               ib[idx+0] = idx_value + (u32)(reloc->lobj.gpu_offset & 0xffffffff);
+               ib[idx+0] = idx_value + (u32)(reloc->gpu_offset & 0xffffffff);
                r = evergreen_cs_track_check(p);
                if (r) {
                        dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
@@ -2049,7 +2049,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                return -EINVAL;
                        }
 
-                       offset = reloc->lobj.gpu_offset +
+                       offset = reloc->gpu_offset +
                                 (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
                                 ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
 
@@ -2106,7 +2106,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                tmp = radeon_get_ib_value(p, idx) +
                                        ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
 
-                               offset = reloc->lobj.gpu_offset + tmp;
+                               offset = reloc->gpu_offset + tmp;
 
                                if ((tmp + size) > radeon_bo_size(reloc->robj)) {
                                        dev_warn(p->dev, "CP DMA src buffer too small (%llu %lu)\n",
@@ -2144,7 +2144,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                tmp = radeon_get_ib_value(p, idx+2) +
                                        ((u64)(radeon_get_ib_value(p, idx+3) & 0xff) << 32);
 
-                               offset = reloc->lobj.gpu_offset + tmp;
+                               offset = reloc->gpu_offset + tmp;
 
                                if ((tmp + size) > radeon_bo_size(reloc->robj)) {
                                        dev_warn(p->dev, "CP DMA dst buffer too small (%llu %lu)\n",
@@ -2174,7 +2174,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                DRM_ERROR("bad SURFACE_SYNC\n");
                                return -EINVAL;
                        }
-                       ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                       ib[idx+2] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                }
                break;
        case PACKET3_EVENT_WRITE:
@@ -2190,7 +2190,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                DRM_ERROR("bad EVENT_WRITE\n");
                                return -EINVAL;
                        }
-                       offset = reloc->lobj.gpu_offset +
+                       offset = reloc->gpu_offset +
                                 (radeon_get_ib_value(p, idx+1) & 0xfffffff8) +
                                 ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
 
@@ -2212,7 +2212,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
 
-               offset = reloc->lobj.gpu_offset +
+               offset = reloc->gpu_offset +
                         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
                         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
 
@@ -2234,7 +2234,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
 
-               offset = reloc->lobj.gpu_offset +
+               offset = reloc->gpu_offset +
                         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
                         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
 
@@ -2302,11 +2302,11 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                }
                                if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
                                        ib[idx+1+(i*8)+1] |=
-                                               TEX_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->lobj.tiling_flags));
-                                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+                                               TEX_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
+                                       if (reloc->tiling_flags & RADEON_TILING_MACRO) {
                                                unsigned bankw, bankh, mtaspect, tile_split;
 
-                                               evergreen_tiling_fields(reloc->lobj.tiling_flags,
+                                               evergreen_tiling_fields(reloc->tiling_flags,
                                                                        &bankw, &bankh, &mtaspect,
                                                                        &tile_split);
                                                ib[idx+1+(i*8)+6] |= TEX_TILE_SPLIT(tile_split);
@@ -2318,7 +2318,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                        }
                                }
                                texture = reloc->robj;
-                               toffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                               toffset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
 
                                /* tex mip base */
                                tex_dim = ib[idx+1+(i*8)+0] & 0x7;
@@ -2337,7 +2337,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                                DRM_ERROR("bad SET_RESOURCE (tex)\n");
                                                return -EINVAL;
                                        }
-                                       moffset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                                       moffset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                                        mipmap = reloc->robj;
                                }
 
@@ -2364,7 +2364,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                        ib[idx+1+(i*8)+1] = radeon_bo_size(reloc->robj) - offset;
                                }
 
-                               offset64 = reloc->lobj.gpu_offset + offset;
+                               offset64 = reloc->gpu_offset + offset;
                                ib[idx+1+(i*8)+0] = offset64;
                                ib[idx+1+(i*8)+2] = (ib[idx+1+(i*8)+2] & 0xffffff00) |
                                                    (upper_32_bits(offset64) & 0xff);
@@ -2445,7 +2445,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                          offset + 4, radeon_bo_size(reloc->robj));
                                return -EINVAL;
                        }
-                       offset += reloc->lobj.gpu_offset;
+                       offset += reloc->gpu_offset;
                        ib[idx+1] = offset;
                        ib[idx+2] = upper_32_bits(offset) & 0xff;
                }
@@ -2464,7 +2464,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                          offset + 4, radeon_bo_size(reloc->robj));
                                return -EINVAL;
                        }
-                       offset += reloc->lobj.gpu_offset;
+                       offset += reloc->gpu_offset;
                        ib[idx+3] = offset;
                        ib[idx+4] = upper_32_bits(offset) & 0xff;
                }
@@ -2493,7 +2493,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                  offset + 8, radeon_bo_size(reloc->robj));
                        return -EINVAL;
                }
-               offset += reloc->lobj.gpu_offset;
+               offset += reloc->gpu_offset;
                ib[idx+0] = offset;
                ib[idx+1] = upper_32_bits(offset) & 0xff;
                break;
@@ -2518,7 +2518,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                          offset + 4, radeon_bo_size(reloc->robj));
                                return -EINVAL;
                        }
-                       offset += reloc->lobj.gpu_offset;
+                       offset += reloc->gpu_offset;
                        ib[idx+1] = offset;
                        ib[idx+2] = upper_32_bits(offset) & 0xff;
                } else {
@@ -2542,7 +2542,7 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
                                          offset + 4, radeon_bo_size(reloc->robj));
                                return -EINVAL;
                        }
-                       offset += reloc->lobj.gpu_offset;
+                       offset += reloc->gpu_offset;
                        ib[idx+3] = offset;
                        ib[idx+4] = upper_32_bits(offset) & 0xff;
                } else {
@@ -2717,7 +2717,7 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                dst_offset = radeon_get_ib_value(p, idx+1);
                                dst_offset <<= 8;
 
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);
                                p->idx += count + 7;
                                break;
                        /* linear */
@@ -2725,8 +2725,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                dst_offset = radeon_get_ib_value(p, idx+1);
                                dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
 
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+2] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
                                p->idx += count + 3;
                                break;
                        default:
@@ -2768,10 +2768,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
                                        return -EINVAL;
                                }
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
-                               ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+2] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+3] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
+                               ib[idx+4] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
                                p->idx += 5;
                                break;
                        /* Copy L2T/T2L */
@@ -2781,22 +2781,22 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                        /* tiled src, linear dst */
                                        src_offset = radeon_get_ib_value(p, idx+1);
                                        src_offset <<= 8;
-                                       ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
+                                       ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8);
 
                                        dst_offset = radeon_get_ib_value(p, idx + 7);
                                        dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
-                                       ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+7] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+8] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
                                } else {
                                        /* linear src, tiled dst */
                                        src_offset = radeon_get_ib_value(p, idx+7);
                                        src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
-                                       ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+7] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+8] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
 
                                        dst_offset = radeon_get_ib_value(p, idx+1);
                                        dst_offset <<= 8;
-                                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
+                                       ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);
                                }
                                if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
                                        dev_warn(p->dev, "DMA L2T, src buffer too small (%llu %lu)\n",
@@ -2827,10 +2827,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        dst_offset + count, radeon_bo_size(dst_reloc->robj));
                                        return -EINVAL;
                                }
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xffffffff);
-                               ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xffffffff);
-                               ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
-                               ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xffffffff);
+                               ib[idx+2] += (u32)(src_reloc->gpu_offset & 0xffffffff);
+                               ib[idx+3] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
+                               ib[idx+4] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
                                p->idx += 5;
                                break;
                        /* Copy L2L, partial */
@@ -2840,10 +2840,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                        DRM_ERROR("L2L Partial is cayman only !\n");
                                        return -EINVAL;
                                }
-                               ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset & 0xffffffff);
-                               ib[idx+2] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
-                               ib[idx+4] += (u32)(dst_reloc->lobj.gpu_offset & 0xffffffff);
-                               ib[idx+5] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
+                               ib[idx+1] += (u32)(src_reloc->gpu_offset & 0xffffffff);
+                               ib[idx+2] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
+                               ib[idx+4] += (u32)(dst_reloc->gpu_offset & 0xffffffff);
+                               ib[idx+5] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
 
                                p->idx += 9;
                                break;
@@ -2876,12 +2876,12 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));
                                        return -EINVAL;
                                }
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+3] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+4] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
-                               ib[idx+5] += upper_32_bits(dst2_reloc->lobj.gpu_offset) & 0xff;
-                               ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+2] += (u32)(dst2_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+3] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+4] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
+                               ib[idx+5] += upper_32_bits(dst2_reloc->gpu_offset) & 0xff;
+                               ib[idx+6] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
                                p->idx += 7;
                                break;
                        /* Copy L2T Frame to Field */
@@ -2916,10 +2916,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));
                                        return -EINVAL;
                                }
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
-                               ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8);
-                               ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);
+                               ib[idx+2] += (u32)(dst2_reloc->gpu_offset >> 8);
+                               ib[idx+8] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+9] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
                                p->idx += 10;
                                break;
                        /* Copy L2T/T2L, partial */
@@ -2932,16 +2932,16 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                /* detile bit */
                                if (radeon_get_ib_value(p, idx + 2) & (1 << 31)) {
                                        /* tiled src, linear dst */
-                                       ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
+                                       ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8);
 
-                                       ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+7] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+8] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
                                } else {
                                        /* linear src, tiled dst */
-                                       ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+7] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+8] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
 
-                                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
+                                       ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);
                                }
                                p->idx += 12;
                                break;
@@ -2978,10 +2978,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));
                                        return -EINVAL;
                                }
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
-                               ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8);
-                               ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);
+                               ib[idx+2] += (u32)(dst2_reloc->gpu_offset >> 8);
+                               ib[idx+8] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+9] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
                                p->idx += 10;
                                break;
                        /* Copy L2T/T2L (tile units) */
@@ -2992,22 +2992,22 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                        /* tiled src, linear dst */
                                        src_offset = radeon_get_ib_value(p, idx+1);
                                        src_offset <<= 8;
-                                       ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
+                                       ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8);
 
                                        dst_offset = radeon_get_ib_value(p, idx+7);
                                        dst_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
-                                       ib[idx+7] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+8] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+7] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+8] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
                                } else {
                                        /* linear src, tiled dst */
                                        src_offset = radeon_get_ib_value(p, idx+7);
                                        src_offset |= ((u64)(radeon_get_ib_value(p, idx+8) & 0xff)) << 32;
-                                       ib[idx+7] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+8] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+7] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+8] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
 
                                        dst_offset = radeon_get_ib_value(p, idx+1);
                                        dst_offset <<= 8;
-                                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
+                                       ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);
                                }
                                if ((src_offset + (count * 4)) > radeon_bo_size(src_reloc->robj)) {
                                        dev_warn(p->dev, "DMA L2T, T2L src buffer too small (%llu %lu)\n",
@@ -3028,8 +3028,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                        DRM_ERROR("L2T, T2L Partial is cayman only !\n");
                                        return -EINVAL;
                                }
-                               ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
-                               ib[idx+4] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
+                               ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8);
+                               ib[idx+4] += (u32)(dst_reloc->gpu_offset >> 8);
                                p->idx += 13;
                                break;
                        /* Copy L2T broadcast (tile units) */
@@ -3065,10 +3065,10 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                                        dst2_offset + (count * 4), radeon_bo_size(dst2_reloc->robj));
                                        return -EINVAL;
                                }
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
-                               ib[idx+2] += (u32)(dst2_reloc->lobj.gpu_offset >> 8);
-                               ib[idx+8] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+9] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);
+                               ib[idx+2] += (u32)(dst2_reloc->gpu_offset >> 8);
+                               ib[idx+8] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+9] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
                                p->idx += 10;
                                break;
                        default:
@@ -3089,8 +3089,8 @@ int evergreen_dma_cs_parse(struct radeon_cs_parser *p)
                                         dst_offset, radeon_bo_size(dst_reloc->robj));
                                return -EINVAL;
                        }
-                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                       ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) << 16) & 0x00ff0000;
+                       ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                       ib[idx+3] += (upper_32_bits(dst_reloc->gpu_offset) << 16) & 0x00ff0000;
                        p->idx += 4;
                        break;
                case DMA_PACKET_NOP:
index a37b544..287fe96 100644 (file)
@@ -174,11 +174,9 @@ bool evergreen_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *rin
        u32 reset_mask = evergreen_gpu_check_soft_reset(rdev);
 
        if (!(reset_mask & RADEON_RESET_DMA)) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force ring activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
index 351db36..16ec9d5 100644 (file)
@@ -1338,13 +1338,11 @@ static int kv_enable_uvd_dpm(struct radeon_device *rdev, bool enable)
                                        PPSMC_MSG_UVDDPM_Enable : PPSMC_MSG_UVDDPM_Disable);
 }
 
-#if 0
 static int kv_enable_vce_dpm(struct radeon_device *rdev, bool enable)
 {
        return kv_notify_message_to_smu(rdev, enable ?
                                        PPSMC_MSG_VCEDPM_Enable : PPSMC_MSG_VCEDPM_Disable);
 }
-#endif
 
 static int kv_enable_samu_dpm(struct radeon_device *rdev, bool enable)
 {
@@ -1389,7 +1387,6 @@ static int kv_update_uvd_dpm(struct radeon_device *rdev, bool gate)
        return kv_enable_uvd_dpm(rdev, !gate);
 }
 
-#if 0
 static u8 kv_get_vce_boot_level(struct radeon_device *rdev)
 {
        u8 i;
@@ -1414,6 +1411,9 @@ static int kv_update_vce_dpm(struct radeon_device *rdev,
        int ret;
 
        if (radeon_new_state->evclk > 0 && radeon_current_state->evclk == 0) {
+               kv_dpm_powergate_vce(rdev, false);
+               /* turn the clocks on when encoding */
+               cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, false);
                if (pi->caps_stable_p_state)
                        pi->vce_boot_level = table->count - 1;
                else
@@ -1436,11 +1436,13 @@ static int kv_update_vce_dpm(struct radeon_device *rdev,
                kv_enable_vce_dpm(rdev, true);
        } else if (radeon_new_state->evclk == 0 && radeon_current_state->evclk > 0) {
                kv_enable_vce_dpm(rdev, false);
+               /* turn the clocks off when not encoding */
+               cik_update_cg(rdev, RADEON_CG_BLOCK_VCE, true);
+               kv_dpm_powergate_vce(rdev, true);
        }
 
        return 0;
 }
-#endif
 
 static int kv_update_samu_dpm(struct radeon_device *rdev, bool gate)
 {
@@ -1575,11 +1577,16 @@ static void kv_dpm_powergate_vce(struct radeon_device *rdev, bool gate)
        pi->vce_power_gated = gate;
 
        if (gate) {
-               if (pi->caps_vce_pg)
+               if (pi->caps_vce_pg) {
+                       /* XXX do we need a vce_v1_0_stop() ?  */
                        kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerOFF);
+               }
        } else {
-               if (pi->caps_vce_pg)
+               if (pi->caps_vce_pg) {
                        kv_notify_message_to_smu(rdev, PPSMC_MSG_VCEPowerON);
+                       vce_v2_0_resume(rdev);
+                       vce_v1_0_start(rdev);
+               }
        }
 }
 
@@ -1768,7 +1775,7 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)
 {
        struct kv_power_info *pi = kv_get_pi(rdev);
        struct radeon_ps *new_ps = &pi->requested_rps;
-       /*struct radeon_ps *old_ps = &pi->current_rps;*/
+       struct radeon_ps *old_ps = &pi->current_rps;
        int ret;
 
        if (pi->bapm_enable) {
@@ -1798,13 +1805,12 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)
                        kv_set_enabled_levels(rdev);
                        kv_force_lowest_valid(rdev);
                        kv_unforce_levels(rdev);
-#if 0
+
                        ret = kv_update_vce_dpm(rdev, new_ps, old_ps);
                        if (ret) {
                                DRM_ERROR("kv_update_vce_dpm failed\n");
                                return ret;
                        }
-#endif
                        kv_update_sclk_t(rdev);
                }
        } else {
@@ -1823,13 +1829,11 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)
                        kv_program_nbps_index_settings(rdev, new_ps);
                        kv_freeze_sclk_dpm(rdev, false);
                        kv_set_enabled_levels(rdev);
-#if 0
                        ret = kv_update_vce_dpm(rdev, new_ps, old_ps);
                        if (ret) {
                                DRM_ERROR("kv_update_vce_dpm failed\n");
                                return ret;
                        }
-#endif
                        kv_update_acp_boot_level(rdev);
                        kv_update_sclk_t(rdev);
                        kv_enable_nb_dpm(rdev);
@@ -2037,6 +2041,14 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev,
        struct radeon_clock_and_voltage_limits *max_limits =
                &rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
 
+       if (new_rps->vce_active) {
+               new_rps->evclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].evclk;
+               new_rps->ecclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].ecclk;
+       } else {
+               new_rps->evclk = 0;
+               new_rps->ecclk = 0;
+       }
+
        mclk = max_limits->mclk;
        sclk = min_sclk;
 
@@ -2056,6 +2068,11 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev,
                sclk = stable_p_state_sclk;
        }
 
+       if (new_rps->vce_active) {
+               if (sclk < rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk)
+                       sclk = rdev->pm.dpm.vce_states[rdev->pm.dpm.vce_level].sclk;
+       }
+
        ps->need_dfs_bypass = true;
 
        for (i = 0; i < ps->num_levels; i++) {
@@ -2092,7 +2109,8 @@ static void kv_apply_state_adjust_rules(struct radeon_device *rdev,
                }
        }
 
-       pi->video_start = new_rps->dclk || new_rps->vclk;
+       pi->video_start = new_rps->dclk || new_rps->vclk ||
+               new_rps->evclk || new_rps->ecclk;
 
        if ((new_rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
            ATOM_PPLIB_CLASSIFICATION_UI_BATTERY)
@@ -2538,9 +2556,6 @@ static int kv_parse_power_table(struct radeon_device *rdev)
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
        power_state_offset = (u8 *)state_array->states;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
        for (i = 0; i < state_array->ucNumEntries; i++) {
                u8 *idx;
                power_state = (union pplib_power_state *)power_state_offset;
@@ -2577,6 +2592,19 @@ static int kv_parse_power_table(struct radeon_device *rdev)
                power_state_offset += 2 + power_state->v2.ucNumDPMLevels;
        }
        rdev->pm.dpm.num_ps = state_array->ucNumEntries;
+
+       /* fill in the vce power states */
+       for (i = 0; i < RADEON_MAX_VCE_LEVELS; i++) {
+               u32 sclk;
+               clock_array_index = rdev->pm.dpm.vce_states[i].clk_idx;
+               clock_info = (union pplib_clock_info *)
+                       &clock_info_array->clockInfo[clock_array_index * clock_info_array->ucEntrySize];
+               sclk = le16_to_cpu(clock_info->sumo.usEngineClockLow);
+               sclk |= clock_info->sumo.ucEngineClockHigh << 16;
+               rdev->pm.dpm.vce_states[i].sclk = sclk;
+               rdev->pm.dpm.vce_states[i].mclk = 0;
+       }
+
        return 0;
 }
 
@@ -2590,6 +2618,10 @@ int kv_dpm_init(struct radeon_device *rdev)
                return -ENOMEM;
        rdev->pm.dpm.priv = pi;
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = r600_parse_extended_power_table(rdev);
        if (ret)
                return ret;
@@ -2623,7 +2655,7 @@ int kv_dpm_init(struct radeon_device *rdev)
        pi->caps_fps = false; /* true? */
        pi->caps_uvd_pg = true;
        pi->caps_uvd_dpm = true;
-       pi->caps_vce_pg = false;
+       pi->caps_vce_pg = false; /* XXX true */
        pi->caps_samu_pg = false;
        pi->caps_acp_pg = false;
        pi->caps_stable_p_state = false;
index bf6300c..d246e04 100644 (file)
@@ -1642,8 +1642,8 @@ static int cayman_cp_resume(struct radeon_device *rdev)
                ring = &rdev->ring[ridx[i]];
                WREG32_P(cp_rb_cntl[i], RB_RPTR_WR_ENA, ~RB_RPTR_WR_ENA);
 
-               ring->rptr = ring->wptr = 0;
-               WREG32(cp_rb_rptr[i], ring->rptr);
+               ring->wptr = 0;
+               WREG32(cp_rb_rptr[i], 0);
                WREG32(cp_rb_wptr[i], ring->wptr);
 
                mdelay(1);
@@ -1917,11 +1917,9 @@ bool cayman_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
        if (!(reset_mask & (RADEON_RESET_GFX |
                            RADEON_RESET_COMPUTE |
                            RADEON_RESET_CP))) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force CP activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
index 7cf96b1..6378e02 100644 (file)
@@ -248,8 +248,6 @@ int cayman_dma_resume(struct radeon_device *rdev)
                ring->wptr = 0;
                WREG32(DMA_RB_WPTR + reg_offset, ring->wptr << 2);
 
-               ring->rptr = RREG32(DMA_RB_RPTR + reg_offset) >> 2;
-
                WREG32(DMA_RB_CNTL + reg_offset, rb_cntl | DMA_RB_ENABLE);
 
                ring->ready = true;
@@ -302,11 +300,9 @@ bool cayman_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
                mask = RADEON_RESET_DMA1;
 
        if (!(reset_mask & mask)) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force ring activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
index ca81427..004c931 100644 (file)
@@ -4025,9 +4025,6 @@ static int ni_parse_power_table(struct radeon_device *rdev)
                                  power_info->pplib.ucNumStates, GFP_KERNEL);
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
 
        for (i = 0; i < power_info->pplib.ucNumStates; i++) {
                power_state = (union pplib_power_state *)
@@ -4089,6 +4086,10 @@ int ni_dpm_init(struct radeon_device *rdev)
        pi->min_vddc_in_table = 0;
        pi->max_vddc_in_table = 0;
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = ni_parse_power_table(rdev);
        if (ret)
                return ret;
index 3cc78bb..b6c3264 100644 (file)
@@ -1193,7 +1193,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
 
        WREG32(RADEON_CP_RB_CNTL, tmp);
        udelay(10);
-       ring->rptr = RREG32(RADEON_CP_RB_RPTR);
        /* Set cp mode to bus mastering & enable cp*/
        WREG32(RADEON_CP_CSQ_MODE,
               REG_SET(RADEON_INDIRECT2_START, indirect2_start) |
@@ -1275,12 +1274,12 @@ int r100_reloc_pitch_offset(struct radeon_cs_parser *p,
 
        value = radeon_get_ib_value(p, idx);
        tmp = value & 0x003fffff;
-       tmp += (((u32)reloc->lobj.gpu_offset) >> 10);
+       tmp += (((u32)reloc->gpu_offset) >> 10);
 
        if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
-               if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+               if (reloc->tiling_flags & RADEON_TILING_MACRO)
                        tile_flags |= RADEON_DST_TILE_MACRO;
-               if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+               if (reloc->tiling_flags & RADEON_TILING_MICRO) {
                        if (reg == RADEON_SRC_PITCH_OFFSET) {
                                DRM_ERROR("Cannot src blit from microtiled surface\n");
                                radeon_cs_dump_packet(p, pkt);
@@ -1326,7 +1325,7 @@ int r100_packet3_load_vbpntr(struct radeon_cs_parser *p,
                        return r;
                }
                idx_value = radeon_get_ib_value(p, idx);
-               ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->lobj.gpu_offset);
+               ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset);
 
                track->arrays[i + 0].esize = idx_value >> 8;
                track->arrays[i + 0].robj = reloc->robj;
@@ -1338,7 +1337,7 @@ int r100_packet3_load_vbpntr(struct radeon_cs_parser *p,
                        radeon_cs_dump_packet(p, pkt);
                        return r;
                }
-               ib[idx+2] = radeon_get_ib_value(p, idx + 2) + ((u32)reloc->lobj.gpu_offset);
+               ib[idx+2] = radeon_get_ib_value(p, idx + 2) + ((u32)reloc->gpu_offset);
                track->arrays[i + 1].robj = reloc->robj;
                track->arrays[i + 1].esize = idx_value >> 24;
                track->arrays[i + 1].esize &= 0x7F;
@@ -1352,7 +1351,7 @@ int r100_packet3_load_vbpntr(struct radeon_cs_parser *p,
                        return r;
                }
                idx_value = radeon_get_ib_value(p, idx);
-               ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->lobj.gpu_offset);
+               ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset);
                track->arrays[i + 0].robj = reloc->robj;
                track->arrays[i + 0].esize = idx_value >> 8;
                track->arrays[i + 0].esize &= 0x7F;
@@ -1595,7 +1594,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                track->zb.robj = reloc->robj;
                track->zb.offset = idx_value;
                track->zb_dirty = true;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case RADEON_RB3D_COLOROFFSET:
                r = radeon_cs_packet_next_reloc(p, &reloc, 0);
@@ -1608,7 +1607,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                track->cb[0].robj = reloc->robj;
                track->cb[0].offset = idx_value;
                track->cb_dirty = true;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case RADEON_PP_TXOFFSET_0:
        case RADEON_PP_TXOFFSET_1:
@@ -1622,16 +1621,16 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        return r;
                }
                if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO)
                                tile_flags |= RADEON_TXO_MACRO_TILE;
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MICRO)
                                tile_flags |= RADEON_TXO_MICRO_TILE_X2;
 
                        tmp = idx_value & ~(0x7 << 2);
                        tmp |= tile_flags;
-                       ib[idx] = tmp + ((u32)reloc->lobj.gpu_offset);
+                       ib[idx] = tmp + ((u32)reloc->gpu_offset);
                } else
-                       ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+                       ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                track->textures[i].robj = reloc->robj;
                track->tex_dirty = true;
                break;
@@ -1649,7 +1648,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        return r;
                }
                track->textures[0].cube_info[i].offset = idx_value;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                track->textures[0].cube_info[i].robj = reloc->robj;
                track->tex_dirty = true;
                break;
@@ -1667,7 +1666,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        return r;
                }
                track->textures[1].cube_info[i].offset = idx_value;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                track->textures[1].cube_info[i].robj = reloc->robj;
                track->tex_dirty = true;
                break;
@@ -1685,7 +1684,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        return r;
                }
                track->textures[2].cube_info[i].offset = idx_value;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                track->textures[2].cube_info[i].robj = reloc->robj;
                track->tex_dirty = true;
                break;
@@ -1703,9 +1702,9 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        return r;
                }
                if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO)
                                tile_flags |= RADEON_COLOR_TILE_ENABLE;
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MICRO)
                                tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
 
                        tmp = idx_value & ~(0x7 << 16);
@@ -1773,7 +1772,7 @@ static int r100_packet0_check(struct radeon_cs_parser *p,
                        radeon_cs_dump_packet(p, pkt);
                        return r;
                }
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case RADEON_PP_CNTL:
                {
@@ -1933,7 +1932,7 @@ static int r100_packet3_check(struct radeon_cs_parser *p,
                        radeon_cs_dump_packet(p, pkt);
                        return r;
                }
-               ib[idx+1] = radeon_get_ib_value(p, idx+1) + ((u32)reloc->lobj.gpu_offset);
+               ib[idx+1] = radeon_get_ib_value(p, idx+1) + ((u32)reloc->gpu_offset);
                r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj);
                if (r) {
                        return r;
@@ -1947,7 +1946,7 @@ static int r100_packet3_check(struct radeon_cs_parser *p,
                        radeon_cs_dump_packet(p, pkt);
                        return r;
                }
-               ib[idx] = radeon_get_ib_value(p, idx) + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = radeon_get_ib_value(p, idx) + ((u32)reloc->gpu_offset);
                track->num_arrays = 1;
                track->vtx_size = r100_get_vtx_size(radeon_get_ib_value(p, idx + 2));
 
@@ -2523,11 +2522,9 @@ bool r100_gpu_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
 
        rbbm_status = RREG32(R_000E40_RBBM_STATUS);
        if (!G_000E40_GUI_ACTIVE(rbbm_status)) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force CP activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
@@ -3223,12 +3220,12 @@ void r100_bandwidth_update(struct radeon_device *rdev)
 
        if (rdev->mode_info.crtcs[0]->base.enabled) {
                mode1 = &rdev->mode_info.crtcs[0]->base.mode;
-               pixel_bytes1 = rdev->mode_info.crtcs[0]->base.fb->bits_per_pixel / 8;
+               pixel_bytes1 = rdev->mode_info.crtcs[0]->base.primary->fb->bits_per_pixel / 8;
        }
        if (!(rdev->flags & RADEON_SINGLE_CRTC)) {
                if (rdev->mode_info.crtcs[1]->base.enabled) {
                        mode2 = &rdev->mode_info.crtcs[1]->base.mode;
-                       pixel_bytes2 = rdev->mode_info.crtcs[1]->base.fb->bits_per_pixel / 8;
+                       pixel_bytes2 = rdev->mode_info.crtcs[1]->base.primary->fb->bits_per_pixel / 8;
                }
        }
 
index b3807ed..58f0473 100644 (file)
@@ -185,7 +185,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                track->zb.robj = reloc->robj;
                track->zb.offset = idx_value;
                track->zb_dirty = true;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case RADEON_RB3D_COLOROFFSET:
                r = radeon_cs_packet_next_reloc(p, &reloc, 0);
@@ -198,7 +198,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                track->cb[0].robj = reloc->robj;
                track->cb[0].offset = idx_value;
                track->cb_dirty = true;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case R200_PP_TXOFFSET_0:
        case R200_PP_TXOFFSET_1:
@@ -215,16 +215,16 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                        return r;
                }
                if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO)
                                tile_flags |= R200_TXO_MACRO_TILE;
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MICRO)
                                tile_flags |= R200_TXO_MICRO_TILE;
 
                        tmp = idx_value & ~(0x7 << 2);
                        tmp |= tile_flags;
-                       ib[idx] = tmp + ((u32)reloc->lobj.gpu_offset);
+                       ib[idx] = tmp + ((u32)reloc->gpu_offset);
                } else
-                       ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+                       ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                track->textures[i].robj = reloc->robj;
                track->tex_dirty = true;
                break;
@@ -268,7 +268,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                        return r;
                }
                track->textures[i].cube_info[face - 1].offset = idx_value;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                track->textures[i].cube_info[face - 1].robj = reloc->robj;
                track->tex_dirty = true;
                break;
@@ -287,9 +287,9 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                }
 
                if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO)
                                tile_flags |= RADEON_COLOR_TILE_ENABLE;
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MICRO)
                                tile_flags |= RADEON_COLOR_MICROTILE_ENABLE;
 
                        tmp = idx_value & ~(0x7 << 16);
@@ -362,7 +362,7 @@ int r200_packet0_check(struct radeon_cs_parser *p,
                        radeon_cs_dump_packet(p, pkt);
                        return r;
                }
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case RADEON_PP_CNTL:
                {
index 0b658b3..206caf9 100644 (file)
@@ -640,7 +640,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                track->cb[i].robj = reloc->robj;
                track->cb[i].offset = idx_value;
                track->cb_dirty = true;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case R300_ZB_DEPTHOFFSET:
                r = radeon_cs_packet_next_reloc(p, &reloc, 0);
@@ -653,7 +653,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                track->zb.robj = reloc->robj;
                track->zb.offset = idx_value;
                track->zb_dirty = true;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case R300_TX_OFFSET_0:
        case R300_TX_OFFSET_0+4:
@@ -682,16 +682,16 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
 
                if (p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS) {
                        ib[idx] = (idx_value & 31) | /* keep the 1st 5 bits */
-                                 ((idx_value & ~31) + (u32)reloc->lobj.gpu_offset);
+                                 ((idx_value & ~31) + (u32)reloc->gpu_offset);
                } else {
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO)
                                tile_flags |= R300_TXO_MACRO_TILE;
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MICRO)
                                tile_flags |= R300_TXO_MICRO_TILE;
-                       else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
+                       else if (reloc->tiling_flags & RADEON_TILING_MICRO_SQUARE)
                                tile_flags |= R300_TXO_MICRO_TILE_SQUARE;
 
-                       tmp = idx_value + ((u32)reloc->lobj.gpu_offset);
+                       tmp = idx_value + ((u32)reloc->gpu_offset);
                        tmp |= tile_flags;
                        ib[idx] = tmp;
                }
@@ -753,11 +753,11 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                return r;
                        }
 
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO)
                                tile_flags |= R300_COLOR_TILE_ENABLE;
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MICRO)
                                tile_flags |= R300_COLOR_MICROTILE_ENABLE;
-                       else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
+                       else if (reloc->tiling_flags & RADEON_TILING_MICRO_SQUARE)
                                tile_flags |= R300_COLOR_MICROTILE_SQUARE_ENABLE;
 
                        tmp = idx_value & ~(0x7 << 16);
@@ -838,11 +838,11 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                                return r;
                        }
 
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO)
                                tile_flags |= R300_DEPTHMACROTILE_ENABLE;
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                       if (reloc->tiling_flags & RADEON_TILING_MICRO)
                                tile_flags |= R300_DEPTHMICROTILE_TILED;
-                       else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO_SQUARE)
+                       else if (reloc->tiling_flags & RADEON_TILING_MICRO_SQUARE)
                                tile_flags |= R300_DEPTHMICROTILE_TILED_SQUARE;
 
                        tmp = idx_value & ~(0x7 << 16);
@@ -1052,7 +1052,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                        radeon_cs_dump_packet(p, pkt);
                        return r;
                }
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case 0x4e0c:
                /* RB3D_COLOR_CHANNEL_MASK */
@@ -1097,7 +1097,7 @@ static int r300_packet0_check(struct radeon_cs_parser *p,
                track->aa.robj = reloc->robj;
                track->aa.offset = idx_value;
                track->aa_dirty = true;
-               ib[idx] = idx_value + ((u32)reloc->lobj.gpu_offset);
+               ib[idx] = idx_value + ((u32)reloc->gpu_offset);
                break;
        case R300_RB3D_AARESOLVE_PITCH:
                track->aa.pitch = idx_value & 0x3FFE;
@@ -1162,7 +1162,7 @@ static int r300_packet3_check(struct radeon_cs_parser *p,
                        radeon_cs_dump_packet(p, pkt);
                        return r;
                }
-               ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->lobj.gpu_offset);
+               ib[idx+1] = radeon_get_ib_value(p, idx + 1) + ((u32)reloc->gpu_offset);
                r = r100_cs_track_check_pkt3_indx_buffer(p, pkt, reloc->robj);
                if (r) {
                        return r;
index 647ef40..6e887d0 100644 (file)
@@ -1748,11 +1748,9 @@ bool r600_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
        if (!(reset_mask & (RADEON_RESET_GFX |
                            RADEON_RESET_COMPUTE |
                            RADEON_RESET_CP))) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force CP activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
@@ -2604,8 +2602,6 @@ int r600_cp_resume(struct radeon_device *rdev)
        WREG32(CP_RB_BASE, ring->gpu_addr >> 8);
        WREG32(CP_DEBUG, (1 << 27) | (1 << 28));
 
-       ring->rptr = RREG32(CP_RB_RPTR);
-
        r600_cp_start(rdev);
        ring->ready = true;
        r = radeon_ring_test(rdev, RADEON_RING_TYPE_GFX_INDEX, ring);
index 2812c7d..12511bb 100644 (file)
@@ -1022,7 +1022,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                break;
        case SQ_CONFIG:
                track->sq_config = radeon_get_ib_value(p, idx);
@@ -1043,7 +1043,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        track->db_depth_info = radeon_get_ib_value(p, idx);
                        ib[idx] &= C_028010_ARRAY_MODE;
                        track->db_depth_info &= C_028010_ARRAY_MODE;
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO) {
                                ib[idx] |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1);
                                track->db_depth_info |= S_028010_ARRAY_MODE(V_028010_ARRAY_2D_TILED_THIN1);
                        } else {
@@ -1084,9 +1084,9 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                }
                tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;
                track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->vgt_strmout_bo[tmp] = reloc->robj;
-               track->vgt_strmout_bo_mc[tmp] = reloc->lobj.gpu_offset;
+               track->vgt_strmout_bo_mc[tmp] = reloc->gpu_offset;
                track->streamout_dirty = true;
                break;
        case VGT_STRMOUT_BUFFER_SIZE_0:
@@ -1105,7 +1105,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                break;
        case R_028238_CB_TARGET_MASK:
                track->cb_target_mask = radeon_get_ib_value(p, idx);
@@ -1142,10 +1142,10 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        }
                        tmp = (reg - R_0280A0_CB_COLOR0_INFO) / 4;
                        track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
-                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO) {
+                       if (reloc->tiling_flags & RADEON_TILING_MACRO) {
                                ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1);
                                track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_2D_TILED_THIN1);
-                       } else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO) {
+                       } else if (reloc->tiling_flags & RADEON_TILING_MICRO) {
                                ib[idx] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1);
                                track->cb_color_info[tmp] |= S_0280A0_ARRAY_MODE(V_0280A0_ARRAY_1D_TILED_THIN1);
                        }
@@ -1214,7 +1214,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        }
                        track->cb_color_frag_bo[tmp] = reloc->robj;
                        track->cb_color_frag_offset[tmp] = (u64)ib[idx] << 8;
-                       ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                       ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                }
                if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {
                        track->cb_dirty = true;
@@ -1245,7 +1245,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        }
                        track->cb_color_tile_bo[tmp] = reloc->robj;
                        track->cb_color_tile_offset[tmp] = (u64)ib[idx] << 8;
-                       ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                       ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                }
                if (G_0280A0_TILE_MODE(track->cb_color_info[tmp])) {
                        track->cb_dirty = true;
@@ -1281,10 +1281,10 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                }
                tmp = (reg - CB_COLOR0_BASE) / 4;
                track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->cb_color_base_last[tmp] = ib[idx];
                track->cb_color_bo[tmp] = reloc->robj;
-               track->cb_color_bo_mc[tmp] = reloc->lobj.gpu_offset;
+               track->cb_color_bo_mc[tmp] = reloc->gpu_offset;
                track->cb_dirty = true;
                break;
        case DB_DEPTH_BASE:
@@ -1295,9 +1295,9 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        return -EINVAL;
                }
                track->db_offset = radeon_get_ib_value(p, idx) << 8;
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->db_bo = reloc->robj;
-               track->db_bo_mc = reloc->lobj.gpu_offset;
+               track->db_bo_mc = reloc->gpu_offset;
                track->db_dirty = true;
                break;
        case DB_HTILE_DATA_BASE:
@@ -1308,7 +1308,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                        return -EINVAL;
                }
                track->htile_offset = radeon_get_ib_value(p, idx) << 8;
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                track->htile_bo = reloc->robj;
                track->db_dirty = true;
                break;
@@ -1377,7 +1377,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                break;
        case SX_MEMORY_EXPORT_BASE:
                r = radeon_cs_packet_next_reloc(p, &reloc, r600_nomm);
@@ -1386,7 +1386,7 @@ static int r600_cs_check_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
                                        "0x%04X\n", reg);
                        return -EINVAL;
                }
-               ib[idx] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+               ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                break;
        case SX_MISC:
                track->sx_misc_kill_all_prims = (radeon_get_ib_value(p, idx) & 0x1) != 0;
@@ -1672,7 +1672,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
 
-               offset = reloc->lobj.gpu_offset +
+               offset = reloc->gpu_offset +
                         (idx_value & 0xfffffff0) +
                         ((u64)(tmp & 0xff) << 32);
 
@@ -1713,7 +1713,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
 
-               offset = reloc->lobj.gpu_offset +
+               offset = reloc->gpu_offset +
                         idx_value +
                         ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
 
@@ -1765,7 +1765,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                return -EINVAL;
                        }
 
-                       offset = reloc->lobj.gpu_offset +
+                       offset = reloc->gpu_offset +
                                 (radeon_get_ib_value(p, idx+1) & 0xfffffff0) +
                                 ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
 
@@ -1805,7 +1805,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                        tmp = radeon_get_ib_value(p, idx) +
                                ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);
 
-                       offset = reloc->lobj.gpu_offset + tmp;
+                       offset = reloc->gpu_offset + tmp;
 
                        if ((tmp + size) > radeon_bo_size(reloc->robj)) {
                                dev_warn(p->dev, "CP DMA src buffer too small (%llu %lu)\n",
@@ -1835,7 +1835,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                        tmp = radeon_get_ib_value(p, idx+2) +
                                ((u64)(radeon_get_ib_value(p, idx+3) & 0xff) << 32);
 
-                       offset = reloc->lobj.gpu_offset + tmp;
+                       offset = reloc->gpu_offset + tmp;
 
                        if ((tmp + size) > radeon_bo_size(reloc->robj)) {
                                dev_warn(p->dev, "CP DMA dst buffer too small (%llu %lu)\n",
@@ -1861,7 +1861,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                DRM_ERROR("bad SURFACE_SYNC\n");
                                return -EINVAL;
                        }
-                       ib[idx+2] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                       ib[idx+2] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                }
                break;
        case PACKET3_EVENT_WRITE:
@@ -1877,7 +1877,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                DRM_ERROR("bad EVENT_WRITE\n");
                                return -EINVAL;
                        }
-                       offset = reloc->lobj.gpu_offset +
+                       offset = reloc->gpu_offset +
                                 (radeon_get_ib_value(p, idx+1) & 0xfffffff8) +
                                 ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
 
@@ -1899,7 +1899,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                        return -EINVAL;
                }
 
-               offset = reloc->lobj.gpu_offset +
+               offset = reloc->gpu_offset +
                         (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
                         ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);
 
@@ -1964,11 +1964,11 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                        DRM_ERROR("bad SET_RESOURCE\n");
                                        return -EINVAL;
                                }
-                               base_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                               base_offset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                                if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
-                                       if (reloc->lobj.tiling_flags & RADEON_TILING_MACRO)
+                                       if (reloc->tiling_flags & RADEON_TILING_MACRO)
                                                ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_2D_TILED_THIN1);
-                                       else if (reloc->lobj.tiling_flags & RADEON_TILING_MICRO)
+                                       else if (reloc->tiling_flags & RADEON_TILING_MICRO)
                                                ib[idx+1+(i*7)+0] |= S_038000_TILE_MODE(V_038000_ARRAY_1D_TILED_THIN1);
                                }
                                texture = reloc->robj;
@@ -1978,13 +1978,13 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                        DRM_ERROR("bad SET_RESOURCE\n");
                                        return -EINVAL;
                                }
-                               mip_offset = (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                               mip_offset = (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                                mipmap = reloc->robj;
                                r = r600_check_texture_resource(p,  idx+(i*7)+1,
                                                                texture, mipmap,
                                                                base_offset + radeon_get_ib_value(p, idx+1+(i*7)+2),
                                                                mip_offset + radeon_get_ib_value(p, idx+1+(i*7)+3),
-                                                               reloc->lobj.tiling_flags);
+                                                               reloc->tiling_flags);
                                if (r)
                                        return r;
                                ib[idx+1+(i*7)+2] += base_offset;
@@ -2008,7 +2008,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                        ib[idx+1+(i*7)+1] = radeon_bo_size(reloc->robj) - offset;
                                }
 
-                               offset64 = reloc->lobj.gpu_offset + offset;
+                               offset64 = reloc->gpu_offset + offset;
                                ib[idx+1+(i*8)+0] = offset64;
                                ib[idx+1+(i*8)+2] = (ib[idx+1+(i*8)+2] & 0xffffff00) |
                                                    (upper_32_bits(offset64) & 0xff);
@@ -2118,7 +2118,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                          offset + 4, radeon_bo_size(reloc->robj));
                                return -EINVAL;
                        }
-                       ib[idx+1] += (u32)((reloc->lobj.gpu_offset >> 8) & 0xffffffff);
+                       ib[idx+1] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
                }
                break;
        case PACKET3_SURFACE_BASE_UPDATE:
@@ -2151,7 +2151,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                          offset + 4, radeon_bo_size(reloc->robj));
                                return -EINVAL;
                        }
-                       offset += reloc->lobj.gpu_offset;
+                       offset += reloc->gpu_offset;
                        ib[idx+1] = offset;
                        ib[idx+2] = upper_32_bits(offset) & 0xff;
                }
@@ -2170,7 +2170,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                          offset + 4, radeon_bo_size(reloc->robj));
                                return -EINVAL;
                        }
-                       offset += reloc->lobj.gpu_offset;
+                       offset += reloc->gpu_offset;
                        ib[idx+3] = offset;
                        ib[idx+4] = upper_32_bits(offset) & 0xff;
                }
@@ -2199,7 +2199,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                  offset + 8, radeon_bo_size(reloc->robj));
                        return -EINVAL;
                }
-               offset += reloc->lobj.gpu_offset;
+               offset += reloc->gpu_offset;
                ib[idx+0] = offset;
                ib[idx+1] = upper_32_bits(offset) & 0xff;
                break;
@@ -2224,7 +2224,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                          offset + 4, radeon_bo_size(reloc->robj));
                                return -EINVAL;
                        }
-                       offset += reloc->lobj.gpu_offset;
+                       offset += reloc->gpu_offset;
                        ib[idx+1] = offset;
                        ib[idx+2] = upper_32_bits(offset) & 0xff;
                } else {
@@ -2248,7 +2248,7 @@ static int r600_packet3_check(struct radeon_cs_parser *p,
                                          offset + 4, radeon_bo_size(reloc->robj));
                                return -EINVAL;
                        }
-                       offset += reloc->lobj.gpu_offset;
+                       offset += reloc->gpu_offset;
                        ib[idx+3] = offset;
                        ib[idx+4] = upper_32_bits(offset) & 0xff;
                } else {
@@ -2505,14 +2505,14 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
                                dst_offset = radeon_get_ib_value(p, idx+1);
                                dst_offset <<= 8;
 
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);
                                p->idx += count + 5;
                        } else {
                                dst_offset = radeon_get_ib_value(p, idx+1);
                                dst_offset |= ((u64)(radeon_get_ib_value(p, idx+2) & 0xff)) << 32;
 
-                               ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                               ib[idx+2] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
+                               ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                               ib[idx+2] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
                                p->idx += count + 3;
                        }
                        if ((dst_offset + (count * 4)) > radeon_bo_size(dst_reloc->robj)) {
@@ -2539,22 +2539,22 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
                                        /* tiled src, linear dst */
                                        src_offset = radeon_get_ib_value(p, idx+1);
                                        src_offset <<= 8;
-                                       ib[idx+1] += (u32)(src_reloc->lobj.gpu_offset >> 8);
+                                       ib[idx+1] += (u32)(src_reloc->gpu_offset >> 8);
 
                                        dst_offset = radeon_get_ib_value(p, idx+5);
                                        dst_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
-                                       ib[idx+5] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+6] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+5] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+6] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
                                } else {
                                        /* linear src, tiled dst */
                                        src_offset = radeon_get_ib_value(p, idx+5);
                                        src_offset |= ((u64)(radeon_get_ib_value(p, idx+6) & 0xff)) << 32;
-                                       ib[idx+5] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+6] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+5] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+6] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
 
                                        dst_offset = radeon_get_ib_value(p, idx+1);
                                        dst_offset <<= 8;
-                                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset >> 8);
+                                       ib[idx+1] += (u32)(dst_reloc->gpu_offset >> 8);
                                }
                                p->idx += 7;
                        } else {
@@ -2564,10 +2564,10 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
                                        dst_offset = radeon_get_ib_value(p, idx+1);
                                        dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff)) << 32;
 
-                                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+3] += upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff;
-                                       ib[idx+4] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
+                                       ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+2] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+3] += upper_32_bits(dst_reloc->gpu_offset) & 0xff;
+                                       ib[idx+4] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
                                        p->idx += 5;
                                } else {
                                        src_offset = radeon_get_ib_value(p, idx+2);
@@ -2575,10 +2575,10 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
                                        dst_offset = radeon_get_ib_value(p, idx+1);
                                        dst_offset |= ((u64)(radeon_get_ib_value(p, idx+3) & 0xff0000)) << 16;
 
-                                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+2] += (u32)(src_reloc->lobj.gpu_offset & 0xfffffffc);
-                                       ib[idx+3] += upper_32_bits(src_reloc->lobj.gpu_offset) & 0xff;
-                                       ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) & 0xff) << 16;
+                                       ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+2] += (u32)(src_reloc->gpu_offset & 0xfffffffc);
+                                       ib[idx+3] += upper_32_bits(src_reloc->gpu_offset) & 0xff;
+                                       ib[idx+3] += (upper_32_bits(dst_reloc->gpu_offset) & 0xff) << 16;
                                        p->idx += 4;
                                }
                        }
@@ -2610,8 +2610,8 @@ int r600_dma_cs_parse(struct radeon_cs_parser *p)
                                         dst_offset + (count * 4), radeon_bo_size(dst_reloc->robj));
                                return -EINVAL;
                        }
-                       ib[idx+1] += (u32)(dst_reloc->lobj.gpu_offset & 0xfffffffc);
-                       ib[idx+3] += (upper_32_bits(dst_reloc->lobj.gpu_offset) << 16) & 0x00ff0000;
+                       ib[idx+1] += (u32)(dst_reloc->gpu_offset & 0xfffffffc);
+                       ib[idx+3] += (upper_32_bits(dst_reloc->gpu_offset) << 16) & 0x00ff0000;
                        p->idx += 4;
                        break;
                case DMA_PACKET_NOP:
index b2d4c91..53fcb28 100644 (file)
@@ -176,8 +176,6 @@ int r600_dma_resume(struct radeon_device *rdev)
        ring->wptr = 0;
        WREG32(DMA_RB_WPTR, ring->wptr << 2);
 
-       ring->rptr = RREG32(DMA_RB_RPTR) >> 2;
-
        WREG32(DMA_RB_CNTL, rb_cntl | DMA_RB_ENABLE);
 
        ring->ready = true;
@@ -221,11 +219,9 @@ bool r600_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
        u32 reset_mask = r600_gpu_check_soft_reset(rdev);
 
        if (!(reset_mask & RADEON_RESET_DMA)) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force ring activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
index e4cc9b3..cbf7e32 100644 (file)
@@ -834,6 +834,26 @@ static int r600_parse_clk_voltage_dep_table(struct radeon_clock_voltage_dependen
        return 0;
 }
 
+int r600_get_platform_caps(struct radeon_device *rdev)
+{
+       struct radeon_mode_info *mode_info = &rdev->mode_info;
+       union power_info *power_info;
+       int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
+        u16 data_offset;
+       u8 frev, crev;
+
+       if (!atom_parse_data_header(mode_info->atom_context, index, NULL,
+                                  &frev, &crev, &data_offset))
+               return -EINVAL;
+       power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
+
+       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
+       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
+       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
+
+       return 0;
+}
+
 /* sizeof(ATOM_PPLIB_EXTENDEDHEADER) */
 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
@@ -1043,7 +1063,15 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
                                (mode_info->atom_context->bios + data_offset +
                                 le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
                                 1 + array->ucNumEntries * sizeof(VCEClockInfo));
+                       ATOM_PPLIB_VCE_State_Table *states =
+                               (ATOM_PPLIB_VCE_State_Table *)
+                               (mode_info->atom_context->bios + data_offset +
+                                le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
+                                1 + (array->ucNumEntries * sizeof (VCEClockInfo)) +
+                                1 + (limits->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record)));
                        ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *entry;
+                       ATOM_PPLIB_VCE_State_Record *state_entry;
+                       VCEClockInfo *vce_clk;
                        u32 size = limits->numEntries *
                                sizeof(struct radeon_vce_clock_voltage_dependency_entry);
                        rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries =
@@ -1055,8 +1083,9 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
                        rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count =
                                limits->numEntries;
                        entry = &limits->entries[0];
+                       state_entry = &states->entries[0];
                        for (i = 0; i < limits->numEntries; i++) {
-                               VCEClockInfo *vce_clk = (VCEClockInfo *)
+                               vce_clk = (VCEClockInfo *)
                                        ((u8 *)&array->entries[0] +
                                         (entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
                                rdev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].evclk =
@@ -1068,6 +1097,23 @@ int r600_parse_extended_power_table(struct radeon_device *rdev)
                                entry = (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *)
                                        ((u8 *)entry + sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record));
                        }
+                       for (i = 0; i < states->numEntries; i++) {
+                               if (i >= RADEON_MAX_VCE_LEVELS)
+                                       break;
+                               vce_clk = (VCEClockInfo *)
+                                       ((u8 *)&array->entries[0] +
+                                        (state_entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
+                               rdev->pm.dpm.vce_states[i].evclk =
+                                       le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16);
+                               rdev->pm.dpm.vce_states[i].ecclk =
+                                       le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16);
+                               rdev->pm.dpm.vce_states[i].clk_idx =
+                                       state_entry->ucClockInfoIndex & 0x3f;
+                               rdev->pm.dpm.vce_states[i].pstate =
+                                       (state_entry->ucClockInfoIndex & 0xc0) >> 6;
+                               state_entry = (ATOM_PPLIB_VCE_State_Record *)
+                                       ((u8 *)state_entry + sizeof(ATOM_PPLIB_VCE_State_Record));
+                       }
                }
                if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) &&
                        ext_hdr->usUVDTableOffset) {
index 07eab2b..46b9d2a 100644 (file)
@@ -215,6 +215,8 @@ void r600_stop_dpm(struct radeon_device *rdev);
 
 bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor);
 
+int r600_get_platform_caps(struct radeon_device *rdev);
+
 int r600_parse_extended_power_table(struct radeon_device *rdev);
 void r600_free_extended_power_table(struct radeon_device *rdev);
 
index e887d02..f21db7a 100644 (file)
@@ -113,19 +113,16 @@ extern int radeon_hard_reset;
 #define RADEONFB_CONN_LIMIT                    4
 #define RADEON_BIOS_NUM_SCRATCH                        8
 
-/* max number of rings */
-#define RADEON_NUM_RINGS                       6
-
 /* fence seq are set to this number when signaled */
 #define RADEON_FENCE_SIGNALED_SEQ              0LL
 
 /* internal ring indices */
 /* r1xx+ has gfx CP ring */
-#define RADEON_RING_TYPE_GFX_INDEX     0
+#define RADEON_RING_TYPE_GFX_INDEX             0
 
 /* cayman has 2 compute CP rings */
-#define CAYMAN_RING_TYPE_CP1_INDEX     1
-#define CAYMAN_RING_TYPE_CP2_INDEX     2
+#define CAYMAN_RING_TYPE_CP1_INDEX             1
+#define CAYMAN_RING_TYPE_CP2_INDEX             2
 
 /* R600+ has an async dma ring */
 #define R600_RING_TYPE_DMA_INDEX               3
@@ -133,7 +130,17 @@ extern int radeon_hard_reset;
 #define CAYMAN_RING_TYPE_DMA1_INDEX            4
 
 /* R600+ */
-#define R600_RING_TYPE_UVD_INDEX       5
+#define R600_RING_TYPE_UVD_INDEX               5
+
+/* TN+ */
+#define TN_RING_TYPE_VCE1_INDEX                        6
+#define TN_RING_TYPE_VCE2_INDEX                        7
+
+/* max number of rings */
+#define RADEON_NUM_RINGS                       8
+
+/* number of hw syncs before falling back on blocking */
+#define RADEON_NUM_SYNCS                       4
 
 /* number of hw syncs before falling back on blocking */
 #define RADEON_NUM_SYNCS                       4
@@ -356,9 +363,8 @@ int radeon_fence_emit(struct radeon_device *rdev, struct radeon_fence **fence, i
 void radeon_fence_process(struct radeon_device *rdev, int ring);
 bool radeon_fence_signaled(struct radeon_fence *fence);
 int radeon_fence_wait(struct radeon_fence *fence, bool interruptible);
-int radeon_fence_wait_locked(struct radeon_fence *fence);
-int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring);
-int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring);
+int radeon_fence_wait_next(struct radeon_device *rdev, int ring);
+int radeon_fence_wait_empty(struct radeon_device *rdev, int ring);
 int radeon_fence_wait_any(struct radeon_device *rdev,
                          struct radeon_fence **fences,
                          bool intr);
@@ -450,6 +456,7 @@ struct radeon_bo {
        /* Protected by gem.mutex */
        struct list_head                list;
        /* Protected by tbo.reserved */
+       u32                             initial_domain;
        u32                             placements[3];
        struct ttm_placement            placement;
        struct ttm_buffer_object        tbo;
@@ -472,16 +479,6 @@ struct radeon_bo {
 };
 #define gem_to_radeon_bo(gobj) container_of((gobj), struct radeon_bo, gem_base)
 
-struct radeon_bo_list {
-       struct ttm_validate_buffer tv;
-       struct radeon_bo        *bo;
-       uint64_t                gpu_offset;
-       bool                    written;
-       unsigned                domain;
-       unsigned                alt_domain;
-       u32                     tiling_flags;
-};
-
 int radeon_gem_debugfs_init(struct radeon_device *rdev);
 
 /* sub-allocation manager, it has to be protected by another lock.
@@ -789,7 +786,6 @@ struct radeon_ib {
 struct radeon_ring {
        struct radeon_bo        *ring_obj;
        volatile uint32_t       *ring;
-       unsigned                rptr;
        unsigned                rptr_offs;
        unsigned                rptr_save_reg;
        u64                     next_rptr_gpu_addr;
@@ -799,8 +795,8 @@ struct radeon_ring {
        unsigned                ring_size;
        unsigned                ring_free_dw;
        int                     count_dw;
-       unsigned long           last_activity;
-       unsigned                last_rptr;
+       atomic_t                last_rptr;
+       atomic64_t              last_activity;
        uint64_t                gpu_addr;
        uint32_t                align_mask;
        uint32_t                ptr_mask;
@@ -852,17 +848,22 @@ struct radeon_mec {
 #define R600_PTE_READABLE      (1 << 5)
 #define R600_PTE_WRITEABLE     (1 << 6)
 
+struct radeon_vm_pt {
+       struct radeon_bo                *bo;
+       uint64_t                        addr;
+};
+
 struct radeon_vm {
-       struct list_head                list;
        struct list_head                va;
        unsigned                        id;
 
        /* contains the page directory */
-       struct radeon_sa_bo             *page_directory;
+       struct radeon_bo                *page_directory;
        uint64_t                        pd_gpu_addr;
+       unsigned                        max_pde_used;
 
        /* array of page tables, one for each page directory entry */
-       struct radeon_sa_bo             **page_tables;
+       struct radeon_vm_pt             *page_tables;
 
        struct mutex                    mutex;
        /* last fence for cs using this vm */
@@ -874,10 +875,7 @@ struct radeon_vm {
 };
 
 struct radeon_vm_manager {
-       struct mutex                    lock;
-       struct list_head                lru_vm;
        struct radeon_fence             *active[RADEON_NUM_VM];
-       struct radeon_sa_manager        sa_manager;
        uint32_t                        max_pfn;
        /* number of VMIDs */
        unsigned                        nvm;
@@ -953,8 +951,8 @@ void radeon_ring_unlock_commit(struct radeon_device *rdev, struct radeon_ring *c
 void radeon_ring_undo(struct radeon_ring *ring);
 void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *cp);
 int radeon_ring_test(struct radeon_device *rdev, struct radeon_ring *cp);
-void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring);
-void radeon_ring_lockup_update(struct radeon_ring *ring);
+void radeon_ring_lockup_update(struct radeon_device *rdev,
+                              struct radeon_ring *ring);
 bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring);
 unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring,
                            uint32_t **data);
@@ -980,9 +978,12 @@ void cayman_dma_fini(struct radeon_device *rdev);
 struct radeon_cs_reloc {
        struct drm_gem_object           *gobj;
        struct radeon_bo                *robj;
-       struct radeon_bo_list           lobj;
+       struct ttm_validate_buffer      tv;
+       uint64_t                        gpu_offset;
+       unsigned                        domain;
+       unsigned                        alt_domain;
+       uint32_t                        tiling_flags;
        uint32_t                        handle;
-       uint32_t                        flags;
 };
 
 struct radeon_cs_chunk {
@@ -1006,6 +1007,7 @@ struct radeon_cs_parser {
        unsigned                nrelocs;
        struct radeon_cs_reloc  *relocs;
        struct radeon_cs_reloc  **relocs_ptr;
+       struct radeon_cs_reloc  *vm_bos;
        struct list_head        validated;
        unsigned                dma_reloc_idx;
        /* indices of various chunks */
@@ -1255,6 +1257,17 @@ enum radeon_dpm_event_src {
        RADEON_DPM_EVENT_SRC_DIGIAL_OR_EXTERNAL = 4
 };
 
+#define RADEON_MAX_VCE_LEVELS 6
+
+enum radeon_vce_level {
+       RADEON_VCE_LEVEL_AC_ALL = 0,     /* AC, All cases */
+       RADEON_VCE_LEVEL_DC_EE = 1,      /* DC, entropy encoding */
+       RADEON_VCE_LEVEL_DC_LL_LOW = 2,  /* DC, low latency queue, res <= 720 */
+       RADEON_VCE_LEVEL_DC_LL_HIGH = 3, /* DC, low latency queue, 1080 >= res > 720 */
+       RADEON_VCE_LEVEL_DC_GP_LOW = 4,  /* DC, general purpose queue, res <= 720 */
+       RADEON_VCE_LEVEL_DC_GP_HIGH = 5, /* DC, general purpose queue, 1080 >= res > 720 */
+};
+
 struct radeon_ps {
        u32 caps; /* vbios flags */
        u32 class; /* vbios flags */
@@ -1265,6 +1278,8 @@ struct radeon_ps {
        /* VCE clocks */
        u32 evclk;
        u32 ecclk;
+       bool vce_active;
+       enum radeon_vce_level vce_level;
        /* asic priv */
        void *ps_priv;
 };
@@ -1439,6 +1454,17 @@ enum radeon_dpm_forced_level {
        RADEON_DPM_FORCED_LEVEL_HIGH = 2,
 };
 
+struct radeon_vce_state {
+       /* vce clocks */
+       u32 evclk;
+       u32 ecclk;
+       /* gpu clocks */
+       u32 sclk;
+       u32 mclk;
+       u8 clk_idx;
+       u8 pstate;
+};
+
 struct radeon_dpm {
        struct radeon_ps        *ps;
        /* number of valid power states */
@@ -1451,6 +1477,9 @@ struct radeon_dpm {
        struct radeon_ps        *boot_ps;
        /* default uvd power state */
        struct radeon_ps        *uvd_ps;
+       /* vce requirements */
+       struct radeon_vce_state vce_states[RADEON_MAX_VCE_LEVELS];
+       enum radeon_vce_level vce_level;
        enum radeon_pm_state_type state;
        enum radeon_pm_state_type user_state;
        u32                     platform_caps;
@@ -1476,6 +1505,7 @@ struct radeon_dpm {
        /* special states active */
        bool                    thermal_active;
        bool                    uvd_active;
+       bool                    vce_active;
        /* thermal handling */
        struct radeon_dpm_thermal thermal;
        /* forced levels */
@@ -1486,6 +1516,7 @@ struct radeon_dpm {
 };
 
 void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable);
+void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable);
 
 struct radeon_pm {
        struct mutex            mutex;
@@ -1591,6 +1622,45 @@ int radeon_uvd_calc_upll_dividers(struct radeon_device *rdev,
 int radeon_uvd_send_upll_ctlreq(struct radeon_device *rdev,
                                 unsigned cg_upll_func_cntl);
 
+/*
+ * VCE
+ */
+#define RADEON_MAX_VCE_HANDLES 16
+#define RADEON_VCE_STACK_SIZE  (1024*1024)
+#define RADEON_VCE_HEAP_SIZE   (4*1024*1024)
+
+struct radeon_vce {
+       struct radeon_bo        *vcpu_bo;
+       uint64_t                gpu_addr;
+       unsigned                fw_version;
+       unsigned                fb_version;
+       atomic_t                handles[RADEON_MAX_VCE_HANDLES];
+       struct drm_file         *filp[RADEON_MAX_VCE_HANDLES];
+       struct delayed_work     idle_work;
+};
+
+int radeon_vce_init(struct radeon_device *rdev);
+void radeon_vce_fini(struct radeon_device *rdev);
+int radeon_vce_suspend(struct radeon_device *rdev);
+int radeon_vce_resume(struct radeon_device *rdev);
+int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring,
+                             uint32_t handle, struct radeon_fence **fence);
+int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring,
+                              uint32_t handle, struct radeon_fence **fence);
+void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp);
+void radeon_vce_note_usage(struct radeon_device *rdev);
+int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi);
+int radeon_vce_cs_parse(struct radeon_cs_parser *p);
+bool radeon_vce_semaphore_emit(struct radeon_device *rdev,
+                              struct radeon_ring *ring,
+                              struct radeon_semaphore *semaphore,
+                              bool emit_wait);
+void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib);
+void radeon_vce_fence_emit(struct radeon_device *rdev,
+                          struct radeon_fence *fence);
+int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring);
+int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring);
+
 struct r600_audio_pin {
        int                     channels;
        int                     rate;
@@ -1780,6 +1850,7 @@ struct radeon_asic {
                void (*set_pcie_lanes)(struct radeon_device *rdev, int lanes);
                void (*set_clock_gating)(struct radeon_device *rdev, int enable);
                int (*set_uvd_clocks)(struct radeon_device *rdev, u32 vclk, u32 dclk);
+               int (*set_vce_clocks)(struct radeon_device *rdev, u32 evclk, u32 ecclk);
                int (*get_temperature)(struct radeon_device *rdev);
        } pm;
        /* dynamic power management */
@@ -2041,6 +2112,8 @@ int radeon_gem_wait_idle_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *filp);
 int radeon_gem_va_ioctl(struct drm_device *dev, void *data,
                          struct drm_file *filp);
+int radeon_gem_op_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *filp);
 int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp);
 int radeon_gem_set_tiling_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *filp);
@@ -2186,6 +2259,7 @@ struct radeon_device {
        struct radeon_gem               gem;
        struct radeon_pm                pm;
        struct radeon_uvd               uvd;
+       struct radeon_vce               vce;
        uint32_t                        bios_scratch[RADEON_BIOS_NUM_SCRATCH];
        struct radeon_wb                wb;
        struct radeon_dummy_page        dummy_page;
@@ -2205,6 +2279,7 @@ struct radeon_device {
        const struct firmware *sdma_fw; /* CIK SDMA firmware */
        const struct firmware *smc_fw;  /* SMC firmware */
        const struct firmware *uvd_fw;  /* UVD firmware */
+       const struct firmware *vce_fw;  /* VCE firmware */
        struct r600_vram_scratch vram_scratch;
        int msi_enabled; /* msi enabled */
        struct r600_ih ih; /* r6/700 interrupt ring */
@@ -2229,6 +2304,10 @@ struct radeon_device {
        /* virtual memory */
        struct radeon_vm_manager        vm_manager;
        struct mutex                    gpu_clock_mutex;
+       /* memory stats */
+       atomic64_t                      vram_usage;
+       atomic64_t                      gtt_usage;
+       atomic64_t                      num_bytes_moved;
        /* ACPI interface */
        struct radeon_atif              atif;
        struct radeon_atcs              atcs;
@@ -2639,6 +2718,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_set_pcie_lanes(rdev, l) (rdev)->asic->pm.set_pcie_lanes((rdev), (l))
 #define radeon_set_clock_gating(rdev, e) (rdev)->asic->pm.set_clock_gating((rdev), (e))
 #define radeon_set_uvd_clocks(rdev, v, d) (rdev)->asic->pm.set_uvd_clocks((rdev), (v), (d))
+#define radeon_set_vce_clocks(rdev, ev, ec) (rdev)->asic->pm.set_vce_clocks((rdev), (ev), (ec))
 #define radeon_get_temperature(rdev) (rdev)->asic->pm.get_temperature((rdev))
 #define radeon_set_surface_reg(rdev, r, f, p, o, s) ((rdev)->asic->surface.set_reg((rdev), (r), (f), (p), (o), (s)))
 #define radeon_clear_surface_reg(rdev, r) ((rdev)->asic->surface.clear_reg((rdev), (r)))
@@ -2715,16 +2795,22 @@ extern void radeon_program_register_sequence(struct radeon_device *rdev,
  */
 int radeon_vm_manager_init(struct radeon_device *rdev);
 void radeon_vm_manager_fini(struct radeon_device *rdev);
-void radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm);
+int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm);
 void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm);
-int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm);
-void radeon_vm_add_to_lru(struct radeon_device *rdev, struct radeon_vm *vm);
+struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev,
+                                         struct radeon_vm *vm,
+                                          struct list_head *head);
 struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
                                       struct radeon_vm *vm, int ring);
+void radeon_vm_flush(struct radeon_device *rdev,
+                     struct radeon_vm *vm,
+                     int ring);
 void radeon_vm_fence(struct radeon_device *rdev,
                     struct radeon_vm *vm,
                     struct radeon_fence *fence);
 uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr);
+int radeon_vm_update_page_directory(struct radeon_device *rdev,
+                                   struct radeon_vm *vm);
 int radeon_vm_bo_update(struct radeon_device *rdev,
                        struct radeon_vm *vm,
                        struct radeon_bo *bo,
index dda02bf..b8a24a7 100644 (file)
@@ -1987,6 +1987,19 @@ static struct radeon_asic_ring ci_dma_ring = {
        .set_wptr = &cik_sdma_set_wptr,
 };
 
+static struct radeon_asic_ring ci_vce_ring = {
+       .ib_execute = &radeon_vce_ib_execute,
+       .emit_fence = &radeon_vce_fence_emit,
+       .emit_semaphore = &radeon_vce_semaphore_emit,
+       .cs_parse = &radeon_vce_cs_parse,
+       .ring_test = &radeon_vce_ring_test,
+       .ib_test = &radeon_vce_ib_test,
+       .is_lockup = &radeon_ring_test_lockup,
+       .get_rptr = &vce_v1_0_get_rptr,
+       .get_wptr = &vce_v1_0_get_wptr,
+       .set_wptr = &vce_v1_0_set_wptr,
+};
+
 static struct radeon_asic ci_asic = {
        .init = &cik_init,
        .fini = &cik_fini,
@@ -2015,6 +2028,8 @@ static struct radeon_asic ci_asic = {
                [R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring,
                [CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring,
                [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring,
+               [TN_RING_TYPE_VCE1_INDEX] = &ci_vce_ring,
+               [TN_RING_TYPE_VCE2_INDEX] = &ci_vce_ring,
        },
        .irq = {
                .set = &cik_irq_set,
@@ -2061,6 +2076,7 @@ static struct radeon_asic ci_asic = {
                .set_pcie_lanes = NULL,
                .set_clock_gating = NULL,
                .set_uvd_clocks = &cik_set_uvd_clocks,
+               .set_vce_clocks = &cik_set_vce_clocks,
                .get_temperature = &ci_get_temp,
        },
        .dpm = {
@@ -2117,6 +2133,8 @@ static struct radeon_asic kv_asic = {
                [R600_RING_TYPE_DMA_INDEX] = &ci_dma_ring,
                [CAYMAN_RING_TYPE_DMA1_INDEX] = &ci_dma_ring,
                [R600_RING_TYPE_UVD_INDEX] = &cayman_uvd_ring,
+               [TN_RING_TYPE_VCE1_INDEX] = &ci_vce_ring,
+               [TN_RING_TYPE_VCE2_INDEX] = &ci_vce_ring,
        },
        .irq = {
                .set = &cik_irq_set,
@@ -2163,6 +2181,7 @@ static struct radeon_asic kv_asic = {
                .set_pcie_lanes = NULL,
                .set_clock_gating = NULL,
                .set_uvd_clocks = &cik_set_uvd_clocks,
+               .set_vce_clocks = &cik_set_vce_clocks,
                .get_temperature = &kv_get_temp,
        },
        .dpm = {
index ae637cf..3d55a3a 100644 (file)
@@ -717,6 +717,7 @@ u32 cik_get_xclk(struct radeon_device *rdev);
 uint32_t cik_pciep_rreg(struct radeon_device *rdev, uint32_t reg);
 void cik_pciep_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v);
 int cik_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
+int cik_set_vce_clocks(struct radeon_device *rdev, u32 evclk, u32 ecclk);
 void cik_sdma_fence_ring_emit(struct radeon_device *rdev,
                              struct radeon_fence *fence);
 bool cik_sdma_semaphore_ring_emit(struct radeon_device *rdev,
@@ -863,4 +864,17 @@ bool uvd_v3_1_semaphore_emit(struct radeon_device *rdev,
 /* uvd v4.2 */
 int uvd_v4_2_resume(struct radeon_device *rdev);
 
+/* vce v1.0 */
+uint32_t vce_v1_0_get_rptr(struct radeon_device *rdev,
+                          struct radeon_ring *ring);
+uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev,
+                          struct radeon_ring *ring);
+void vce_v1_0_set_wptr(struct radeon_device *rdev,
+                      struct radeon_ring *ring);
+int vce_v1_0_init(struct radeon_device *rdev);
+int vce_v1_0_start(struct radeon_device *rdev);
+
+/* vce v2.0 */
+int vce_v2_0_resume(struct radeon_device *rdev);
+
 #endif
index 82d4f86..c566b48 100644 (file)
@@ -89,7 +89,7 @@ static void radeon_property_change_mode(struct drm_encoder *encoder)
 
        if (crtc && crtc->enabled) {
                drm_crtc_helper_set_mode(crtc, &crtc->mode,
-                                        crtc->x, crtc->y, crtc->fb);
+                                        crtc->x, crtc->y, crtc->primary->fb);
        }
 }
 
@@ -1595,6 +1595,7 @@ radeon_add_atom_connector(struct drm_device *dev,
        uint32_t subpixel_order = SubPixelNone;
        bool shared_ddc = false;
        bool is_dp_bridge = false;
+       bool has_aux = false;
 
        if (connector_type == DRM_MODE_CONNECTOR_Unknown)
                return;
@@ -1672,7 +1673,9 @@ radeon_add_atom_connector(struct drm_device *dev,
                                radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
                        else
                                radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "DP-auxch");
-                       if (!radeon_dig_connector->dp_i2c_bus)
+                       if (radeon_dig_connector->dp_i2c_bus)
+                               has_aux = true;
+                       else
                                DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
                        radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                        if (!radeon_connector->ddc_bus)
@@ -1895,7 +1898,9 @@ radeon_add_atom_connector(struct drm_device *dev,
                                if (!radeon_dig_connector->dp_i2c_bus)
                                        DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
                                radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
-                               if (!radeon_connector->ddc_bus)
+                               if (radeon_connector->ddc_bus)
+                                       has_aux = true;
+                               else
                                        DRM_ERROR("DP: Failed to assign ddc bus! Check dmesg for i2c errors.\n");
                        }
                        subpixel_order = SubPixelHorizontalRGB;
@@ -1939,7 +1944,9 @@ radeon_add_atom_connector(struct drm_device *dev,
                        if (i2c_bus->valid) {
                                /* add DP i2c bus */
                                radeon_dig_connector->dp_i2c_bus = radeon_i2c_create_dp(dev, i2c_bus, "eDP-auxch");
-                               if (!radeon_dig_connector->dp_i2c_bus)
+                               if (radeon_dig_connector->dp_i2c_bus)
+                                       has_aux = true;
+                               else
                                        DRM_ERROR("DP: Failed to assign dp ddc bus! Check dmesg for i2c errors.\n");
                                radeon_connector->ddc_bus = radeon_i2c_lookup(rdev, i2c_bus);
                                if (!radeon_connector->ddc_bus)
@@ -2000,6 +2007,10 @@ radeon_add_atom_connector(struct drm_device *dev,
 
        connector->display_info.subpixel_order = subpixel_order;
        drm_sysfs_connector_add(connector);
+
+       if (has_aux)
+               radeon_dp_aux_init(radeon_connector);
+
        return;
 
 failed:
index dfb5a1d..2b6e0eb 100644 (file)
  * Authors:
  *    Jerome Glisse <glisse@freedesktop.org>
  */
+#include <linux/list_sort.h>
 #include <drm/drmP.h>
 #include <drm/radeon_drm.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 #include "radeon_trace.h"
 
+#define RADEON_CS_MAX_PRIORITY         32u
+#define RADEON_CS_NUM_BUCKETS          (RADEON_CS_MAX_PRIORITY + 1)
+
+/* This is based on the bucket sort with O(n) time complexity.
+ * An item with priority "i" is added to bucket[i]. The lists are then
+ * concatenated in descending order.
+ */
+struct radeon_cs_buckets {
+       struct list_head bucket[RADEON_CS_NUM_BUCKETS];
+};
+
+static void radeon_cs_buckets_init(struct radeon_cs_buckets *b)
+{
+       unsigned i;
+
+       for (i = 0; i < RADEON_CS_NUM_BUCKETS; i++)
+               INIT_LIST_HEAD(&b->bucket[i]);
+}
+
+static void radeon_cs_buckets_add(struct radeon_cs_buckets *b,
+                                 struct list_head *item, unsigned priority)
+{
+       /* Since buffers which appear sooner in the relocation list are
+        * likely to be used more often than buffers which appear later
+        * in the list, the sort mustn't change the ordering of buffers
+        * with the same priority, i.e. it must be stable.
+        */
+       list_add_tail(item, &b->bucket[min(priority, RADEON_CS_MAX_PRIORITY)]);
+}
+
+static void radeon_cs_buckets_get_list(struct radeon_cs_buckets *b,
+                                      struct list_head *out_list)
+{
+       unsigned i;
+
+       /* Connect the sorted buckets in the output list. */
+       for (i = 0; i < RADEON_CS_NUM_BUCKETS; i++) {
+               list_splice(&b->bucket[i], out_list);
+       }
+}
+
 static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
 {
        struct drm_device *ddev = p->rdev->ddev;
        struct radeon_cs_chunk *chunk;
+       struct radeon_cs_buckets buckets;
        unsigned i, j;
        bool duplicate;
 
@@ -52,8 +95,12 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
        if (p->relocs == NULL) {
                return -ENOMEM;
        }
+
+       radeon_cs_buckets_init(&buckets);
+
        for (i = 0; i < p->nrelocs; i++) {
                struct drm_radeon_cs_reloc *r;
+               unsigned priority;
 
                duplicate = false;
                r = (struct drm_radeon_cs_reloc *)&chunk->kdata[i*4];
@@ -78,8 +125,14 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                }
                p->relocs_ptr[i] = &p->relocs[i];
                p->relocs[i].robj = gem_to_radeon_bo(p->relocs[i].gobj);
-               p->relocs[i].lobj.bo = p->relocs[i].robj;
-               p->relocs[i].lobj.written = !!r->write_domain;
+
+               /* The userspace buffer priorities are from 0 to 15. A higher
+                * number means the buffer is more important.
+                * Also, the buffers used for write have a higher priority than
+                * the buffers used for read only, which doubles the range
+                * to 0 to 31. 32 is reserved for the kernel driver.
+                */
+               priority = (r->flags & 0xf) * 2 + !!r->write_domain;
 
                /* the first reloc of an UVD job is the msg and that must be in
                   VRAM, also but everything into VRAM on AGP cards to avoid
@@ -87,29 +140,38 @@ static int radeon_cs_parser_relocs(struct radeon_cs_parser *p)
                if (p->ring == R600_RING_TYPE_UVD_INDEX &&
                    (i == 0 || drm_pci_device_is_agp(p->rdev->ddev))) {
                        /* TODO: is this still needed for NI+ ? */
-                       p->relocs[i].lobj.domain =
+                       p->relocs[i].domain =
                                RADEON_GEM_DOMAIN_VRAM;
 
-                       p->relocs[i].lobj.alt_domain =
+                       p->relocs[i].alt_domain =
                                RADEON_GEM_DOMAIN_VRAM;
 
+                       /* prioritize this over any other relocation */
+                       priority = RADEON_CS_MAX_PRIORITY;
                } else {
                        uint32_t domain = r->write_domain ?
                                r->write_domain : r->read_domains;
 
-                       p->relocs[i].lobj.domain = domain;
+                       p->relocs[i].domain = domain;
                        if (domain == RADEON_GEM_DOMAIN_VRAM)
                                domain |= RADEON_GEM_DOMAIN_GTT;
-                       p->relocs[i].lobj.alt_domain = domain;
+                       p->relocs[i].alt_domain = domain;
                }
 
-               p->relocs[i].lobj.tv.bo = &p->relocs[i].robj->tbo;
+               p->relocs[i].tv.bo = &p->relocs[i].robj->tbo;
                p->relocs[i].handle = r->handle;
 
-               radeon_bo_list_add_object(&p->relocs[i].lobj,
-                                         &p->validated);
+               radeon_cs_buckets_add(&buckets, &p->relocs[i].tv.head,
+                                     priority);
        }
-       return radeon_bo_list_validate(&p->ticket, &p->validated, p->ring);
+
+       radeon_cs_buckets_get_list(&buckets, &p->validated);
+
+       if (p->cs_flags & RADEON_CS_USE_VM)
+               p->vm_bos = radeon_vm_get_bos(p->rdev, p->ib.vm,
+                                             &p->validated);
+
+       return radeon_bo_list_validate(p->rdev, &p->ticket, &p->validated, p->ring);
 }
 
 static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority)
@@ -147,6 +209,10 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
        case RADEON_CS_RING_UVD:
                p->ring = R600_RING_TYPE_UVD_INDEX;
                break;
+       case RADEON_CS_RING_VCE:
+               /* TODO: only use the low priority ring for now */
+               p->ring = TN_RING_TYPE_VCE1_INDEX;
+               break;
        }
        return 0;
 }
@@ -286,6 +352,16 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
        return 0;
 }
 
+static int cmp_size_smaller_first(void *priv, struct list_head *a,
+                                 struct list_head *b)
+{
+       struct radeon_cs_reloc *la = list_entry(a, struct radeon_cs_reloc, tv.head);
+       struct radeon_cs_reloc *lb = list_entry(b, struct radeon_cs_reloc, tv.head);
+
+       /* Sort A before B if A is smaller. */
+       return (int)la->robj->tbo.num_pages - (int)lb->robj->tbo.num_pages;
+}
+
 /**
  * cs_parser_fini() - clean parser states
  * @parser:    parser structure holding parsing context.
@@ -299,6 +375,18 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo
        unsigned i;
 
        if (!error) {
+               /* Sort the buffer list from the smallest to largest buffer,
+                * which affects the order of buffers in the LRU list.
+                * This assures that the smallest buffers are added first
+                * to the LRU list, so they are likely to be later evicted
+                * first, instead of large buffers whose eviction is more
+                * expensive.
+                *
+                * This slightly lowers the number of bytes moved by TTM
+                * per frame under memory pressure.
+                */
+               list_sort(NULL, &parser->validated, cmp_size_smaller_first);
+
                ttm_eu_fence_buffer_objects(&parser->ticket,
                                            &parser->validated,
                                            parser->ib.fence);
@@ -316,6 +404,7 @@ static void radeon_cs_parser_fini(struct radeon_cs_parser *parser, int error, bo
        kfree(parser->track);
        kfree(parser->relocs);
        kfree(parser->relocs_ptr);
+       kfree(parser->vm_bos);
        for (i = 0; i < parser->nchunks; i++)
                drm_free_large(parser->chunks[i].kdata);
        kfree(parser->chunks);
@@ -343,6 +432,9 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
 
        if (parser->ring == R600_RING_TYPE_UVD_INDEX)
                radeon_uvd_note_usage(rdev);
+       else if ((parser->ring == TN_RING_TYPE_VCE1_INDEX) ||
+                (parser->ring == TN_RING_TYPE_VCE2_INDEX))
+               radeon_vce_note_usage(rdev);
 
        radeon_cs_sync_rings(parser);
        r = radeon_ib_schedule(rdev, &parser->ib, NULL);
@@ -352,24 +444,32 @@ static int radeon_cs_ib_chunk(struct radeon_device *rdev,
        return r;
 }
 
-static int radeon_bo_vm_update_pte(struct radeon_cs_parser *parser,
+static int radeon_bo_vm_update_pte(struct radeon_cs_parser *p,
                                   struct radeon_vm *vm)
 {
-       struct radeon_device *rdev = parser->rdev;
-       struct radeon_bo_list *lobj;
-       struct radeon_bo *bo;
-       int r;
+       struct radeon_device *rdev = p->rdev;
+       int i, r;
 
-       r = radeon_vm_bo_update(rdev, vm, rdev->ring_tmp_bo.bo, &rdev->ring_tmp_bo.bo->tbo.mem);
-       if (r) {
+       r = radeon_vm_update_page_directory(rdev, vm);
+       if (r)
                return r;
-       }
-       list_for_each_entry(lobj, &parser->validated, tv.head) {
-               bo = lobj->bo;
-               r = radeon_vm_bo_update(parser->rdev, vm, bo, &bo->tbo.mem);
-               if (r) {
+
+       r = radeon_vm_bo_update(rdev, vm, rdev->ring_tmp_bo.bo,
+                               &rdev->ring_tmp_bo.bo->tbo.mem);
+       if (r)
+               return r;
+
+       for (i = 0; i < p->nrelocs; i++) {
+               struct radeon_bo *bo;
+
+               /* ignore duplicates */
+               if (p->relocs_ptr[i] != &p->relocs[i])
+                       continue;
+
+               bo = p->relocs[i].robj;
+               r = radeon_vm_bo_update(rdev, vm, bo, &bo->tbo.mem);
+               if (r)
                        return r;
-               }
        }
        return 0;
 }
@@ -401,20 +501,13 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
        if (parser->ring == R600_RING_TYPE_UVD_INDEX)
                radeon_uvd_note_usage(rdev);
 
-       mutex_lock(&rdev->vm_manager.lock);
        mutex_lock(&vm->mutex);
-       r = radeon_vm_alloc_pt(rdev, vm);
-       if (r) {
-               goto out;
-       }
        r = radeon_bo_vm_update_pte(parser, vm);
        if (r) {
                goto out;
        }
        radeon_cs_sync_rings(parser);
        radeon_semaphore_sync_to(parser->ib.semaphore, vm->fence);
-       radeon_semaphore_sync_to(parser->ib.semaphore,
-                                radeon_vm_grab_id(rdev, vm, parser->ring));
 
        if ((rdev->family >= CHIP_TAHITI) &&
            (parser->chunk_const_ib_idx != -1)) {
@@ -423,14 +516,8 @@ static int radeon_cs_ib_vm_chunk(struct radeon_device *rdev,
                r = radeon_ib_schedule(rdev, &parser->ib, NULL);
        }
 
-       if (!r) {
-               radeon_vm_fence(rdev, vm, parser->ib.fence);
-       }
-
 out:
-       radeon_vm_add_to_lru(rdev, vm);
        mutex_unlock(&vm->mutex);
-       mutex_unlock(&rdev->vm_manager.lock);
        return r;
 }
 
@@ -698,9 +785,9 @@ int radeon_cs_packet_next_reloc(struct radeon_cs_parser *p,
        /* FIXME: we assume reloc size is 4 dwords */
        if (nomm) {
                *cs_reloc = p->relocs;
-               (*cs_reloc)->lobj.gpu_offset =
+               (*cs_reloc)->gpu_offset =
                        (u64)relocs_chunk->kdata[idx + 3] << 32;
-               (*cs_reloc)->lobj.gpu_offset |= relocs_chunk->kdata[idx + 0];
+               (*cs_reloc)->gpu_offset |= relocs_chunk->kdata[idx + 0];
        } else
                *cs_reloc = p->relocs_ptr[(idx / 4)];
        return 0;
index 044bc98..835516d 100644 (file)
@@ -1191,14 +1191,12 @@ int radeon_device_init(struct radeon_device *rdev,
        r = radeon_gem_init(rdev);
        if (r)
                return r;
-       /* initialize vm here */
-       mutex_init(&rdev->vm_manager.lock);
+
        /* Adjust VM size here.
         * Currently set to 4GB ((1 << 20) 4k pages).
         * Max GPUVM size for cayman and SI is 40 bits.
         */
        rdev->vm_manager.max_pfn = 1 << 20;
-       INIT_LIST_HEAD(&rdev->vm_manager.lru_vm);
 
        /* Set asic functions */
        r = radeon_asic_init(rdev);
@@ -1426,7 +1424,7 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
 
        /* unpin the front buffers */
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
-               struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->fb);
+               struct radeon_framebuffer *rfb = to_radeon_framebuffer(crtc->primary->fb);
                struct radeon_bo *robj;
 
                if (rfb == NULL || rfb->obj == NULL) {
@@ -1445,10 +1443,9 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
        /* evict vram memory */
        radeon_bo_evict_vram(rdev);
 
-       mutex_lock(&rdev->ring_lock);
        /* wait for gpu to finish processing current batch */
        for (i = 0; i < RADEON_NUM_RINGS; i++) {
-               r = radeon_fence_wait_empty_locked(rdev, i);
+               r = radeon_fence_wait_empty(rdev, i);
                if (r) {
                        /* delay GPU reset to resume */
                        force_completion = true;
@@ -1457,7 +1454,6 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
        if (force_completion) {
                radeon_fence_driver_force_completion(rdev);
        }
-       mutex_unlock(&rdev->ring_lock);
 
        radeon_save_bios_scratch_regs(rdev);
 
@@ -1555,10 +1551,12 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        /* reset hpd state */
        radeon_hpd_init(rdev);
        /* blat the mode back in */
-       drm_helper_resume_force_mode(dev);
-       /* turn on display hw */
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
-               drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+       if (fbcon) {
+               drm_helper_resume_force_mode(dev);
+               /* turn on display hw */
+               list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+                       drm_helper_connector_dpms(connector, DRM_MODE_DPMS_ON);
+               }
        }
 
        drm_kms_helper_poll_enable(dev);
index fbd8b93..386cfa4 100644 (file)
@@ -34,6 +34,8 @@
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
 
+#include <linux/gcd.h>
+
 static void avivo_crtc_load_lut(struct drm_crtc *crtc)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@@ -369,7 +371,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
        work->event = event;
        work->rdev = rdev;
        work->crtc_id = radeon_crtc->crtc_id;
-       old_radeon_fb = to_radeon_framebuffer(crtc->fb);
+       old_radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
        new_radeon_fb = to_radeon_framebuffer(fb);
        /* schedule unpin of the old buffer */
        obj = old_radeon_fb->obj;
@@ -460,7 +462,7 @@ static int radeon_crtc_page_flip(struct drm_crtc *crtc,
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
        /* update crtc fb */
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
 
        r = drm_vblank_get(dev, radeon_crtc->crtc_id);
        if (r) {
@@ -792,6 +794,7 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
        if (radeon_connector->edid) {
                drm_mode_connector_update_edid_property(&radeon_connector->base, radeon_connector->edid);
                ret = drm_add_edid_modes(&radeon_connector->base, radeon_connector->edid);
+               drm_edid_to_eld(&radeon_connector->base, radeon_connector->edid);
                return ret;
        }
        drm_mode_connector_update_edid_property(&radeon_connector->base, NULL);
@@ -799,66 +802,57 @@ int radeon_ddc_get_modes(struct radeon_connector *radeon_connector)
 }
 
 /* avivo */
-static void avivo_get_fb_div(struct radeon_pll *pll,
-                            u32 target_clock,
-                            u32 post_div,
-                            u32 ref_div,
-                            u32 *fb_div,
-                            u32 *frac_fb_div)
-{
-       u32 tmp = post_div * ref_div;
 
-       tmp *= target_clock;
-       *fb_div = tmp / pll->reference_freq;
-       *frac_fb_div = tmp % pll->reference_freq;
-
-        if (*fb_div > pll->max_feedback_div)
-               *fb_div = pll->max_feedback_div;
-        else if (*fb_div < pll->min_feedback_div)
-                *fb_div = pll->min_feedback_div;
-}
-
-static u32 avivo_get_post_div(struct radeon_pll *pll,
-                             u32 target_clock)
+/**
+ * avivo_reduce_ratio - fractional number reduction
+ *
+ * @nom: nominator
+ * @den: denominator
+ * @nom_min: minimum value for nominator
+ * @den_min: minimum value for denominator
+ *
+ * Find the greatest common divisor and apply it on both nominator and
+ * denominator, but make nominator and denominator are at least as large
+ * as their minimum values.
+ */
+static void avivo_reduce_ratio(unsigned *nom, unsigned *den,
+                              unsigned nom_min, unsigned den_min)
 {
-       u32 vco, post_div, tmp;
-
-       if (pll->flags & RADEON_PLL_USE_POST_DIV)
-               return pll->post_div;
-
-       if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
-               if (pll->flags & RADEON_PLL_IS_LCD)
-                       vco = pll->lcd_pll_out_min;
-               else
-                       vco = pll->pll_out_min;
-       } else {
-               if (pll->flags & RADEON_PLL_IS_LCD)
-                       vco = pll->lcd_pll_out_max;
-               else
-                       vco = pll->pll_out_max;
+       unsigned tmp;
+
+       /* reduce the numbers to a simpler ratio */
+       tmp = gcd(*nom, *den);
+       *nom /= tmp;
+       *den /= tmp;
+
+       /* make sure nominator is large enough */
+        if (*nom < nom_min) {
+               tmp = (nom_min + *nom - 1) / *nom;
+               *nom *= tmp;
+               *den *= tmp;
        }
 
-       post_div = vco / target_clock;
-       tmp = vco % target_clock;
-
-       if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP) {
-               if (tmp)
-                       post_div++;
-       } else {
-               if (!tmp)
-                       post_div--;
+       /* make sure the denominator is large enough */
+       if (*den < den_min) {
+               tmp = (den_min + *den - 1) / *den;
+               *nom *= tmp;
+               *den *= tmp;
        }
-
-       if (post_div > pll->max_post_div)
-               post_div = pll->max_post_div;
-       else if (post_div < pll->min_post_div)
-               post_div = pll->min_post_div;
-
-       return post_div;
 }
 
-#define MAX_TOLERANCE 10
-
+/**
+ * radeon_compute_pll_avivo - compute PLL paramaters
+ *
+ * @pll: information about the PLL
+ * @dot_clock_p: resulting pixel clock
+ * fb_div_p: resulting feedback divider
+ * frac_fb_div_p: fractional part of the feedback divider
+ * ref_div_p: resulting reference divider
+ * post_div_p: resulting reference divider
+ *
+ * Try to calculate the PLL parameters to generate the given frequency:
+ * dot_clock = (ref_freq * feedback_div) / (ref_div * post_div)
+ */
 void radeon_compute_pll_avivo(struct radeon_pll *pll,
                              u32 freq,
                              u32 *dot_clock_p,
@@ -867,53 +861,123 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
                              u32 *ref_div_p,
                              u32 *post_div_p)
 {
-       u32 target_clock = freq / 10;
-       u32 post_div = avivo_get_post_div(pll, target_clock);
-       u32 ref_div = pll->min_ref_div;
-       u32 fb_div = 0, frac_fb_div = 0, tmp;
+       unsigned fb_div_min, fb_div_max, fb_div;
+       unsigned post_div_min, post_div_max, post_div;
+       unsigned ref_div_min, ref_div_max, ref_div;
+       unsigned post_div_best, diff_best;
+       unsigned nom, den, tmp;
 
-       if (pll->flags & RADEON_PLL_USE_REF_DIV)
-               ref_div = pll->reference_div;
+       /* determine allowed feedback divider range */
+       fb_div_min = pll->min_feedback_div;
+       fb_div_max = pll->max_feedback_div;
 
        if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
-               avivo_get_fb_div(pll, target_clock, post_div, ref_div, &fb_div, &frac_fb_div);
-               frac_fb_div = (100 * frac_fb_div) / pll->reference_freq;
-               if (frac_fb_div >= 5) {
-                       frac_fb_div -= 5;
-                       frac_fb_div = frac_fb_div / 10;
-                       frac_fb_div++;
+               fb_div_min *= 10;
+               fb_div_max *= 10;
+       }
+
+       /* determine allowed ref divider range */
+       if (pll->flags & RADEON_PLL_USE_REF_DIV)
+               ref_div_min = pll->reference_div;
+       else
+               ref_div_min = pll->min_ref_div;
+       ref_div_max = pll->max_ref_div;
+
+       /* determine allowed post divider range */
+       if (pll->flags & RADEON_PLL_USE_POST_DIV) {
+               post_div_min = pll->post_div;
+               post_div_max = pll->post_div;
+       } else {
+               unsigned target_clock = freq / 10;
+               unsigned vco_min, vco_max;
+
+               if (pll->flags & RADEON_PLL_IS_LCD) {
+                       vco_min = pll->lcd_pll_out_min;
+                       vco_max = pll->lcd_pll_out_max;
+               } else {
+                       vco_min = pll->pll_out_min;
+                       vco_max = pll->pll_out_max;
                }
-               if (frac_fb_div >= 10) {
-                       fb_div++;
-                       frac_fb_div = 0;
+
+               post_div_min = vco_min / target_clock;
+               if ((target_clock * post_div_min) < vco_min)
+                       ++post_div_min;
+               if (post_div_min < pll->min_post_div)
+                       post_div_min = pll->min_post_div;
+
+               post_div_max = vco_max / target_clock;
+               if ((target_clock * post_div_max) > vco_max)
+                       --post_div_max;
+               if (post_div_max > pll->max_post_div)
+                       post_div_max = pll->max_post_div;
+       }
+
+       /* represent the searched ratio as fractional number */
+       nom = pll->flags & RADEON_PLL_USE_FRAC_FB_DIV ? freq : freq / 10;
+       den = pll->reference_freq;
+
+       /* reduce the numbers to a simpler ratio */
+       avivo_reduce_ratio(&nom, &den, fb_div_min, post_div_min);
+
+       /* now search for a post divider */
+       if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP)
+               post_div_best = post_div_min;
+       else
+               post_div_best = post_div_max;
+       diff_best = ~0;
+
+       for (post_div = post_div_min; post_div <= post_div_max; ++post_div) {
+               unsigned diff = abs(den - den / post_div * post_div);
+               if (diff < diff_best || (diff == diff_best &&
+                   !(pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP))) {
+
+                       post_div_best = post_div;
+                       diff_best = diff;
                }
+       }
+       post_div = post_div_best;
+
+       /* get matching reference and feedback divider */
+       ref_div = max(den / post_div, 1u);
+       fb_div = nom;
+
+       /* we're almost done, but reference and feedback
+          divider might be to large now */
+
+       tmp = ref_div;
+
+        if (fb_div > fb_div_max) {
+               ref_div = ref_div * fb_div_max / fb_div;
+               fb_div = fb_div_max;
+       }
+
+       if (ref_div > ref_div_max) {
+               ref_div = ref_div_max;
+               fb_div = nom * ref_div_max / tmp;
+       }
+
+       /* reduce the numbers to a simpler ratio once more */
+       /* this also makes sure that the reference divider is large enough */
+       avivo_reduce_ratio(&fb_div, &ref_div, fb_div_min, ref_div_min);
+
+       /* and finally save the result */
+       if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV) {
+               *fb_div_p = fb_div / 10;
+               *frac_fb_div_p = fb_div % 10;
        } else {
-               while (ref_div <= pll->max_ref_div) {
-                       avivo_get_fb_div(pll, target_clock, post_div, ref_div,
-                                        &fb_div, &frac_fb_div);
-                       if (frac_fb_div >= (pll->reference_freq / 2))
-                               fb_div++;
-                       frac_fb_div = 0;
-                       tmp = (pll->reference_freq * fb_div) / (post_div * ref_div);
-                       tmp = (tmp * 10000) / target_clock;
-
-                       if (tmp > (10000 + MAX_TOLERANCE))
-                               ref_div++;
-                       else if (tmp >= (10000 - MAX_TOLERANCE))
-                               break;
-                       else
-                               ref_div++;
-               }
+               *fb_div_p = fb_div;
+               *frac_fb_div_p = 0;
        }
 
-       *dot_clock_p = ((pll->reference_freq * fb_div * 10) + (pll->reference_freq * frac_fb_div)) /
-               (ref_div * post_div * 10);
-       *fb_div_p = fb_div;
-       *frac_fb_div_p = frac_fb_div;
+       *dot_clock_p = ((pll->reference_freq * *fb_div_p * 10) +
+                       (pll->reference_freq * *frac_fb_div_p)) /
+                      (ref_div * post_div * 10);
        *ref_div_p = ref_div;
        *post_div_p = post_div;
-       DRM_DEBUG_KMS("%d, pll dividers - fb: %d.%d ref: %d, post %d\n",
-                     *dot_clock_p, fb_div, frac_fb_div, ref_div, post_div);
+
+       DRM_DEBUG_KMS("%d - %d, pll dividers - fb: %d.%d ref: %d, post %d\n",
+                     freq, *dot_clock_p, *fb_div_p, *frac_fb_div_p,
+                     ref_div, post_div);
 }
 
 /* pre-avivo */
index f633c27..d0eba48 100644 (file)
  *   2.35.0 - Add CIK macrotile mode array query
  *   2.36.0 - Fix CIK DCE tiling setup
  *   2.37.0 - allow GS ring setup on r6xx/r7xx
+ *   2.38.0 - RADEON_GEM_OP (GET_INITIAL_DOMAIN, SET_INITIAL_DOMAIN),
+ *            CIK: 1D and linear tiling modes contain valid PIPE_CONFIG
  */
 #define KMS_DRIVER_MAJOR       2
-#define KMS_DRIVER_MINOR       37
+#define KMS_DRIVER_MINOR       38
 #define KMS_DRIVER_PATCHLEVEL  0
 int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
 int radeon_driver_unload_kms(struct drm_device *dev);
index c37cb79..a77b1c1 100644 (file)
@@ -288,7 +288,6 @@ static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq)
  * @rdev: radeon device pointer
  * @target_seq: sequence number(s) we want to wait for
  * @intr: use interruptable sleep
- * @lock_ring: whether the ring should be locked or not
  *
  * Wait for the requested sequence number(s) to be written by any ring
  * (all asics).  Sequnce number array is indexed by ring id.
@@ -299,7 +298,7 @@ static bool radeon_fence_any_seq_signaled(struct radeon_device *rdev, u64 *seq)
  * -EDEADLK is returned when a GPU lockup has been detected.
  */
 static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
-                                bool intr, bool lock_ring)
+                                bool intr)
 {
        uint64_t last_seq[RADEON_NUM_RINGS];
        bool signaled;
@@ -358,9 +357,6 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
                        if (i != RADEON_NUM_RINGS)
                                continue;
 
-                       if (lock_ring)
-                               mutex_lock(&rdev->ring_lock);
-
                        for (i = 0; i < RADEON_NUM_RINGS; ++i) {
                                if (!target_seq[i])
                                        continue;
@@ -378,14 +374,9 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
 
                                /* remember that we need an reset */
                                rdev->needs_reset = true;
-                               if (lock_ring)
-                                       mutex_unlock(&rdev->ring_lock);
                                wake_up_all(&rdev->fence_queue);
                                return -EDEADLK;
                        }
-
-                       if (lock_ring)
-                               mutex_unlock(&rdev->ring_lock);
                }
        }
        return 0;
@@ -416,7 +407,7 @@ int radeon_fence_wait(struct radeon_fence *fence, bool intr)
        if (seq[fence->ring] == RADEON_FENCE_SIGNALED_SEQ)
                return 0;
 
-       r = radeon_fence_wait_seq(fence->rdev, seq, intr, true);
+       r = radeon_fence_wait_seq(fence->rdev, seq, intr);
        if (r)
                return r;
 
@@ -464,7 +455,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev,
        if (num_rings == 0)
                return -ENOENT;
 
-       r = radeon_fence_wait_seq(rdev, seq, intr, true);
+       r = radeon_fence_wait_seq(rdev, seq, intr);
        if (r) {
                return r;
        }
@@ -472,37 +463,7 @@ int radeon_fence_wait_any(struct radeon_device *rdev,
 }
 
 /**
- * radeon_fence_wait_locked - wait for a fence to signal
- *
- * @fence: radeon fence object
- *
- * Wait for the requested fence to signal (all asics).
- * Returns 0 if the fence has passed, error for all other cases.
- */
-int radeon_fence_wait_locked(struct radeon_fence *fence)
-{
-       uint64_t seq[RADEON_NUM_RINGS] = {};
-       int r;
-
-       if (fence == NULL) {
-               WARN(1, "Querying an invalid fence : %p !\n", fence);
-               return -EINVAL;
-       }
-
-       seq[fence->ring] = fence->seq;
-       if (seq[fence->ring] == RADEON_FENCE_SIGNALED_SEQ)
-               return 0;
-
-       r = radeon_fence_wait_seq(fence->rdev, seq, false, false);
-       if (r)
-               return r;
-
-       fence->seq = RADEON_FENCE_SIGNALED_SEQ;
-       return 0;
-}
-
-/**
- * radeon_fence_wait_next_locked - wait for the next fence to signal
+ * radeon_fence_wait_next - wait for the next fence to signal
  *
  * @rdev: radeon device pointer
  * @ring: ring index the fence is associated with
@@ -511,7 +472,7 @@ int radeon_fence_wait_locked(struct radeon_fence *fence)
  * Returns 0 if the next fence has passed, error for all other cases.
  * Caller must hold ring lock.
  */
-int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring)
+int radeon_fence_wait_next(struct radeon_device *rdev, int ring)
 {
        uint64_t seq[RADEON_NUM_RINGS] = {};
 
@@ -521,11 +482,11 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring)
                   already the last emited fence */
                return -ENOENT;
        }
-       return radeon_fence_wait_seq(rdev, seq, false, false);
+       return radeon_fence_wait_seq(rdev, seq, false);
 }
 
 /**
- * radeon_fence_wait_empty_locked - wait for all fences to signal
+ * radeon_fence_wait_empty - wait for all fences to signal
  *
  * @rdev: radeon device pointer
  * @ring: ring index the fence is associated with
@@ -534,7 +495,7 @@ int radeon_fence_wait_next_locked(struct radeon_device *rdev, int ring)
  * Returns 0 if the fences have passed, error for all other cases.
  * Caller must hold ring lock.
  */
-int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring)
+int radeon_fence_wait_empty(struct radeon_device *rdev, int ring)
 {
        uint64_t seq[RADEON_NUM_RINGS] = {};
        int r;
@@ -543,7 +504,7 @@ int radeon_fence_wait_empty_locked(struct radeon_device *rdev, int ring)
        if (!seq[ring])
                return 0;
 
-       r = radeon_fence_wait_seq(rdev, seq, false, false);
+       r = radeon_fence_wait_seq(rdev, seq, false);
        if (r) {
                if (r == -EDEADLK)
                        return -EDEADLK;
@@ -794,7 +755,7 @@ void radeon_fence_driver_fini(struct radeon_device *rdev)
        for (ring = 0; ring < RADEON_NUM_RINGS; ring++) {
                if (!rdev->fence_drv[ring].initialized)
                        continue;
-               r = radeon_fence_wait_empty_locked(rdev, ring);
+               r = radeon_fence_wait_empty(rdev, ring);
                if (r) {
                        /* no need to trigger GPU reset as we are unloading */
                        radeon_fence_driver_force_completion(rdev);
index a8f9b46..2e72365 100644 (file)
@@ -28,8 +28,6 @@
 #include <drm/drmP.h>
 #include <drm/radeon_drm.h>
 #include "radeon.h"
-#include "radeon_reg.h"
-#include "radeon_trace.h"
 
 /*
  * GART
@@ -394,959 +392,3 @@ void radeon_gart_fini(struct radeon_device *rdev)
 
        radeon_dummy_page_fini(rdev);
 }
-
-/*
- * GPUVM
- * GPUVM is similar to the legacy gart on older asics, however
- * rather than there being a single global gart table
- * for the entire GPU, there are multiple VM page tables active
- * at any given time.  The VM page tables can contain a mix
- * vram pages and system memory pages and system memory pages
- * can be mapped as snooped (cached system pages) or unsnooped
- * (uncached system pages).
- * Each VM has an ID associated with it and there is a page table
- * associated with each VMID.  When execting a command buffer,
- * the kernel tells the the ring what VMID to use for that command
- * buffer.  VMIDs are allocated dynamically as commands are submitted.
- * The userspace drivers maintain their own address space and the kernel
- * sets up their pages tables accordingly when they submit their
- * command buffers and a VMID is assigned.
- * Cayman/Trinity support up to 8 active VMs at any given time;
- * SI supports 16.
- */
-
-/*
- * vm helpers
- *
- * TODO bind a default page at vm initialization for default address
- */
-
-/**
- * radeon_vm_num_pde - return the number of page directory entries
- *
- * @rdev: radeon_device pointer
- *
- * Calculate the number of page directory entries (cayman+).
- */
-static unsigned radeon_vm_num_pdes(struct radeon_device *rdev)
-{
-       return rdev->vm_manager.max_pfn >> RADEON_VM_BLOCK_SIZE;
-}
-
-/**
- * radeon_vm_directory_size - returns the size of the page directory in bytes
- *
- * @rdev: radeon_device pointer
- *
- * Calculate the size of the page directory in bytes (cayman+).
- */
-static unsigned radeon_vm_directory_size(struct radeon_device *rdev)
-{
-       return RADEON_GPU_PAGE_ALIGN(radeon_vm_num_pdes(rdev) * 8);
-}
-
-/**
- * radeon_vm_manager_init - init the vm manager
- *
- * @rdev: radeon_device pointer
- *
- * Init the vm manager (cayman+).
- * Returns 0 for success, error for failure.
- */
-int radeon_vm_manager_init(struct radeon_device *rdev)
-{
-       struct radeon_vm *vm;
-       struct radeon_bo_va *bo_va;
-       int r;
-       unsigned size;
-
-       if (!rdev->vm_manager.enabled) {
-               /* allocate enough for 2 full VM pts */
-               size = radeon_vm_directory_size(rdev);
-               size += rdev->vm_manager.max_pfn * 8;
-               size *= 2;
-               r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager,
-                                             RADEON_GPU_PAGE_ALIGN(size),
-                                             RADEON_VM_PTB_ALIGN_SIZE,
-                                             RADEON_GEM_DOMAIN_VRAM);
-               if (r) {
-                       dev_err(rdev->dev, "failed to allocate vm bo (%dKB)\n",
-                               (rdev->vm_manager.max_pfn * 8) >> 10);
-                       return r;
-               }
-
-               r = radeon_asic_vm_init(rdev);
-               if (r)
-                       return r;
-
-               rdev->vm_manager.enabled = true;
-
-               r = radeon_sa_bo_manager_start(rdev, &rdev->vm_manager.sa_manager);
-               if (r)
-                       return r;
-       }
-
-       /* restore page table */
-       list_for_each_entry(vm, &rdev->vm_manager.lru_vm, list) {
-               if (vm->page_directory == NULL)
-                       continue;
-
-               list_for_each_entry(bo_va, &vm->va, vm_list) {
-                       bo_va->valid = false;
-               }
-       }
-       return 0;
-}
-
-/**
- * radeon_vm_free_pt - free the page table for a specific vm
- *
- * @rdev: radeon_device pointer
- * @vm: vm to unbind
- *
- * Free the page table of a specific vm (cayman+).
- *
- * Global and local mutex must be lock!
- */
-static void radeon_vm_free_pt(struct radeon_device *rdev,
-                                   struct radeon_vm *vm)
-{
-       struct radeon_bo_va *bo_va;
-       int i;
-
-       if (!vm->page_directory)
-               return;
-
-       list_del_init(&vm->list);
-       radeon_sa_bo_free(rdev, &vm->page_directory, vm->fence);
-
-       list_for_each_entry(bo_va, &vm->va, vm_list) {
-               bo_va->valid = false;
-       }
-
-       if (vm->page_tables == NULL)
-               return;
-
-       for (i = 0; i < radeon_vm_num_pdes(rdev); i++)
-               radeon_sa_bo_free(rdev, &vm->page_tables[i], vm->fence);
-
-       kfree(vm->page_tables);
-}
-
-/**
- * radeon_vm_manager_fini - tear down the vm manager
- *
- * @rdev: radeon_device pointer
- *
- * Tear down the VM manager (cayman+).
- */
-void radeon_vm_manager_fini(struct radeon_device *rdev)
-{
-       struct radeon_vm *vm, *tmp;
-       int i;
-
-       if (!rdev->vm_manager.enabled)
-               return;
-
-       mutex_lock(&rdev->vm_manager.lock);
-       /* free all allocated page tables */
-       list_for_each_entry_safe(vm, tmp, &rdev->vm_manager.lru_vm, list) {
-               mutex_lock(&vm->mutex);
-               radeon_vm_free_pt(rdev, vm);
-               mutex_unlock(&vm->mutex);
-       }
-       for (i = 0; i < RADEON_NUM_VM; ++i) {
-               radeon_fence_unref(&rdev->vm_manager.active[i]);
-       }
-       radeon_asic_vm_fini(rdev);
-       mutex_unlock(&rdev->vm_manager.lock);
-
-       radeon_sa_bo_manager_suspend(rdev, &rdev->vm_manager.sa_manager);
-       radeon_sa_bo_manager_fini(rdev, &rdev->vm_manager.sa_manager);
-       rdev->vm_manager.enabled = false;
-}
-
-/**
- * radeon_vm_evict - evict page table to make room for new one
- *
- * @rdev: radeon_device pointer
- * @vm: VM we want to allocate something for
- *
- * Evict a VM from the lru, making sure that it isn't @vm. (cayman+).
- * Returns 0 for success, -ENOMEM for failure.
- *
- * Global and local mutex must be locked!
- */
-static int radeon_vm_evict(struct radeon_device *rdev, struct radeon_vm *vm)
-{
-       struct radeon_vm *vm_evict;
-
-       if (list_empty(&rdev->vm_manager.lru_vm))
-               return -ENOMEM;
-
-       vm_evict = list_first_entry(&rdev->vm_manager.lru_vm,
-                                   struct radeon_vm, list);
-       if (vm_evict == vm)
-               return -ENOMEM;
-
-       mutex_lock(&vm_evict->mutex);
-       radeon_vm_free_pt(rdev, vm_evict);
-       mutex_unlock(&vm_evict->mutex);
-       return 0;
-}
-
-/**
- * radeon_vm_alloc_pt - allocates a page table for a VM
- *
- * @rdev: radeon_device pointer
- * @vm: vm to bind
- *
- * Allocate a page table for the requested vm (cayman+).
- * Returns 0 for success, error for failure.
- *
- * Global and local mutex must be locked!
- */
-int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm)
-{
-       unsigned pd_size, pd_entries, pts_size;
-       struct radeon_ib ib;
-       int r;
-
-       if (vm == NULL) {
-               return -EINVAL;
-       }
-
-       if (vm->page_directory != NULL) {
-               return 0;
-       }
-
-       pd_size = radeon_vm_directory_size(rdev);
-       pd_entries = radeon_vm_num_pdes(rdev);
-
-retry:
-       r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
-                            &vm->page_directory, pd_size,
-                            RADEON_VM_PTB_ALIGN_SIZE, false);
-       if (r == -ENOMEM) {
-               r = radeon_vm_evict(rdev, vm);
-               if (r)
-                       return r;
-               goto retry;
-
-       } else if (r) {
-               return r;
-       }
-
-       vm->pd_gpu_addr = radeon_sa_bo_gpu_addr(vm->page_directory);
-
-       /* Initially clear the page directory */
-       r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib,
-                         NULL, pd_entries * 2 + 64);
-       if (r) {
-               radeon_sa_bo_free(rdev, &vm->page_directory, vm->fence);
-               return r;
-       }
-
-       ib.length_dw = 0;
-
-       radeon_asic_vm_set_page(rdev, &ib, vm->pd_gpu_addr,
-                               0, pd_entries, 0, 0);
-
-       radeon_semaphore_sync_to(ib.semaphore, vm->fence);
-       r = radeon_ib_schedule(rdev, &ib, NULL);
-       if (r) {
-               radeon_ib_free(rdev, &ib);
-               radeon_sa_bo_free(rdev, &vm->page_directory, vm->fence);
-               return r;
-       }
-       radeon_fence_unref(&vm->fence);
-       vm->fence = radeon_fence_ref(ib.fence);
-       radeon_ib_free(rdev, &ib);
-       radeon_fence_unref(&vm->last_flush);
-
-       /* allocate page table array */
-       pts_size = radeon_vm_num_pdes(rdev) * sizeof(struct radeon_sa_bo *);
-       vm->page_tables = kzalloc(pts_size, GFP_KERNEL);
-
-       if (vm->page_tables == NULL) {
-               DRM_ERROR("Cannot allocate memory for page table array\n");
-               radeon_sa_bo_free(rdev, &vm->page_directory, vm->fence);
-               return -ENOMEM;
-       }
-
-       return 0;
-}
-
-/**
- * radeon_vm_add_to_lru - add VMs page table to LRU list
- *
- * @rdev: radeon_device pointer
- * @vm: vm to add to LRU
- *
- * Add the allocated page table to the LRU list (cayman+).
- *
- * Global mutex must be locked!
- */
-void radeon_vm_add_to_lru(struct radeon_device *rdev, struct radeon_vm *vm)
-{
-       list_del_init(&vm->list);
-       list_add_tail(&vm->list, &rdev->vm_manager.lru_vm);
-}
-
-/**
- * radeon_vm_grab_id - allocate the next free VMID
- *
- * @rdev: radeon_device pointer
- * @vm: vm to allocate id for
- * @ring: ring we want to submit job to
- *
- * Allocate an id for the vm (cayman+).
- * Returns the fence we need to sync to (if any).
- *
- * Global and local mutex must be locked!
- */
-struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
-                                      struct radeon_vm *vm, int ring)
-{
-       struct radeon_fence *best[RADEON_NUM_RINGS] = {};
-       unsigned choices[2] = {};
-       unsigned i;
-
-       /* check if the id is still valid */
-       if (vm->last_id_use && vm->last_id_use == rdev->vm_manager.active[vm->id])
-               return NULL;
-
-       /* we definately need to flush */
-       radeon_fence_unref(&vm->last_flush);
-
-       /* skip over VMID 0, since it is the system VM */
-       for (i = 1; i < rdev->vm_manager.nvm; ++i) {
-               struct radeon_fence *fence = rdev->vm_manager.active[i];
-
-               if (fence == NULL) {
-                       /* found a free one */
-                       vm->id = i;
-                       trace_radeon_vm_grab_id(vm->id, ring);
-                       return NULL;
-               }
-
-               if (radeon_fence_is_earlier(fence, best[fence->ring])) {
-                       best[fence->ring] = fence;
-                       choices[fence->ring == ring ? 0 : 1] = i;
-               }
-       }
-
-       for (i = 0; i < 2; ++i) {
-               if (choices[i]) {
-                       vm->id = choices[i];
-                       trace_radeon_vm_grab_id(vm->id, ring);
-                       return rdev->vm_manager.active[choices[i]];
-               }
-       }
-
-       /* should never happen */
-       BUG();
-       return NULL;
-}
-
-/**
- * radeon_vm_fence - remember fence for vm
- *
- * @rdev: radeon_device pointer
- * @vm: vm we want to fence
- * @fence: fence to remember
- *
- * Fence the vm (cayman+).
- * Set the fence used to protect page table and id.
- *
- * Global and local mutex must be locked!
- */
-void radeon_vm_fence(struct radeon_device *rdev,
-                    struct radeon_vm *vm,
-                    struct radeon_fence *fence)
-{
-       radeon_fence_unref(&rdev->vm_manager.active[vm->id]);
-       rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence);
-
-       radeon_fence_unref(&vm->fence);
-       vm->fence = radeon_fence_ref(fence);
-
-       radeon_fence_unref(&vm->last_id_use);
-       vm->last_id_use = radeon_fence_ref(fence);
-}
-
-/**
- * radeon_vm_bo_find - find the bo_va for a specific vm & bo
- *
- * @vm: requested vm
- * @bo: requested buffer object
- *
- * Find @bo inside the requested vm (cayman+).
- * Search inside the @bos vm list for the requested vm
- * Returns the found bo_va or NULL if none is found
- *
- * Object has to be reserved!
- */
-struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm,
-                                      struct radeon_bo *bo)
-{
-       struct radeon_bo_va *bo_va;
-
-       list_for_each_entry(bo_va, &bo->va, bo_list) {
-               if (bo_va->vm == vm) {
-                       return bo_va;
-               }
-       }
-       return NULL;
-}
-
-/**
- * radeon_vm_bo_add - add a bo to a specific vm
- *
- * @rdev: radeon_device pointer
- * @vm: requested vm
- * @bo: radeon buffer object
- *
- * Add @bo into the requested vm (cayman+).
- * Add @bo to the list of bos associated with the vm
- * Returns newly added bo_va or NULL for failure
- *
- * Object has to be reserved!
- */
-struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev,
-                                     struct radeon_vm *vm,
-                                     struct radeon_bo *bo)
-{
-       struct radeon_bo_va *bo_va;
-
-       bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL);
-       if (bo_va == NULL) {
-               return NULL;
-       }
-       bo_va->vm = vm;
-       bo_va->bo = bo;
-       bo_va->soffset = 0;
-       bo_va->eoffset = 0;
-       bo_va->flags = 0;
-       bo_va->valid = false;
-       bo_va->ref_count = 1;
-       INIT_LIST_HEAD(&bo_va->bo_list);
-       INIT_LIST_HEAD(&bo_va->vm_list);
-
-       mutex_lock(&vm->mutex);
-       list_add(&bo_va->vm_list, &vm->va);
-       list_add_tail(&bo_va->bo_list, &bo->va);
-       mutex_unlock(&vm->mutex);
-
-       return bo_va;
-}
-
-/**
- * radeon_vm_bo_set_addr - set bos virtual address inside a vm
- *
- * @rdev: radeon_device pointer
- * @bo_va: bo_va to store the address
- * @soffset: requested offset of the buffer in the VM address space
- * @flags: attributes of pages (read/write/valid/etc.)
- *
- * Set offset of @bo_va (cayman+).
- * Validate and set the offset requested within the vm address space.
- * Returns 0 for success, error for failure.
- *
- * Object has to be reserved!
- */
-int radeon_vm_bo_set_addr(struct radeon_device *rdev,
-                         struct radeon_bo_va *bo_va,
-                         uint64_t soffset,
-                         uint32_t flags)
-{
-       uint64_t size = radeon_bo_size(bo_va->bo);
-       uint64_t eoffset, last_offset = 0;
-       struct radeon_vm *vm = bo_va->vm;
-       struct radeon_bo_va *tmp;
-       struct list_head *head;
-       unsigned last_pfn;
-
-       if (soffset) {
-               /* make sure object fit at this offset */
-               eoffset = soffset + size;
-               if (soffset >= eoffset) {
-                       return -EINVAL;
-               }
-
-               last_pfn = eoffset / RADEON_GPU_PAGE_SIZE;
-               if (last_pfn > rdev->vm_manager.max_pfn) {
-                       dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n",
-                               last_pfn, rdev->vm_manager.max_pfn);
-                       return -EINVAL;
-               }
-
-       } else {
-               eoffset = last_pfn = 0;
-       }
-
-       mutex_lock(&vm->mutex);
-       head = &vm->va;
-       last_offset = 0;
-       list_for_each_entry(tmp, &vm->va, vm_list) {
-               if (bo_va == tmp) {
-                       /* skip over currently modified bo */
-                       continue;
-               }
-
-               if (soffset >= last_offset && eoffset <= tmp->soffset) {
-                       /* bo can be added before this one */
-                       break;
-               }
-               if (eoffset > tmp->soffset && soffset < tmp->eoffset) {
-                       /* bo and tmp overlap, invalid offset */
-                       dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n",
-                               bo_va->bo, (unsigned)bo_va->soffset, tmp->bo,
-                               (unsigned)tmp->soffset, (unsigned)tmp->eoffset);
-                       mutex_unlock(&vm->mutex);
-                       return -EINVAL;
-               }
-               last_offset = tmp->eoffset;
-               head = &tmp->vm_list;
-       }
-
-       bo_va->soffset = soffset;
-       bo_va->eoffset = eoffset;
-       bo_va->flags = flags;
-       bo_va->valid = false;
-       list_move(&bo_va->vm_list, head);
-
-       mutex_unlock(&vm->mutex);
-       return 0;
-}
-
-/**
- * radeon_vm_map_gart - get the physical address of a gart page
- *
- * @rdev: radeon_device pointer
- * @addr: the unmapped addr
- *
- * Look up the physical address of the page that the pte resolves
- * to (cayman+).
- * Returns the physical address of the page.
- */
-uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr)
-{
-       uint64_t result;
-
-       /* page table offset */
-       result = rdev->gart.pages_addr[addr >> PAGE_SHIFT];
-
-       /* in case cpu page size != gpu page size*/
-       result |= addr & (~PAGE_MASK);
-
-       return result;
-}
-
-/**
- * radeon_vm_page_flags - translate page flags to what the hw uses
- *
- * @flags: flags comming from userspace
- *
- * Translate the flags the userspace ABI uses to hw flags.
- */
-static uint32_t radeon_vm_page_flags(uint32_t flags)
-{
-        uint32_t hw_flags = 0;
-        hw_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_PTE_VALID : 0;
-        hw_flags |= (flags & RADEON_VM_PAGE_READABLE) ? R600_PTE_READABLE : 0;
-        hw_flags |= (flags & RADEON_VM_PAGE_WRITEABLE) ? R600_PTE_WRITEABLE : 0;
-        if (flags & RADEON_VM_PAGE_SYSTEM) {
-                hw_flags |= R600_PTE_SYSTEM;
-                hw_flags |= (flags & RADEON_VM_PAGE_SNOOPED) ? R600_PTE_SNOOPED : 0;
-        }
-        return hw_flags;
-}
-
-/**
- * radeon_vm_update_pdes - make sure that page directory is valid
- *
- * @rdev: radeon_device pointer
- * @vm: requested vm
- * @start: start of GPU address range
- * @end: end of GPU address range
- *
- * Allocates new page tables if necessary
- * and updates the page directory (cayman+).
- * Returns 0 for success, error for failure.
- *
- * Global and local mutex must be locked!
- */
-static int radeon_vm_update_pdes(struct radeon_device *rdev,
-                                struct radeon_vm *vm,
-                                struct radeon_ib *ib,
-                                uint64_t start, uint64_t end)
-{
-       static const uint32_t incr = RADEON_VM_PTE_COUNT * 8;
-
-       uint64_t last_pde = ~0, last_pt = ~0;
-       unsigned count = 0;
-       uint64_t pt_idx;
-       int r;
-
-       start = (start / RADEON_GPU_PAGE_SIZE) >> RADEON_VM_BLOCK_SIZE;
-       end = (end / RADEON_GPU_PAGE_SIZE) >> RADEON_VM_BLOCK_SIZE;
-
-       /* walk over the address space and update the page directory */
-       for (pt_idx = start; pt_idx <= end; ++pt_idx) {
-               uint64_t pde, pt;
-
-               if (vm->page_tables[pt_idx])
-                       continue;
-
-retry:
-               r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
-                                    &vm->page_tables[pt_idx],
-                                    RADEON_VM_PTE_COUNT * 8,
-                                    RADEON_GPU_PAGE_SIZE, false);
-
-               if (r == -ENOMEM) {
-                       r = radeon_vm_evict(rdev, vm);
-                       if (r)
-                               return r;
-                       goto retry;
-               } else if (r) {
-                       return r;
-               }
-
-               pde = vm->pd_gpu_addr + pt_idx * 8;
-
-               pt = radeon_sa_bo_gpu_addr(vm->page_tables[pt_idx]);
-
-               if (((last_pde + 8 * count) != pde) ||
-                   ((last_pt + incr * count) != pt)) {
-
-                       if (count) {
-                               radeon_asic_vm_set_page(rdev, ib, last_pde,
-                                                       last_pt, count, incr,
-                                                       R600_PTE_VALID);
-
-                               count *= RADEON_VM_PTE_COUNT;
-                               radeon_asic_vm_set_page(rdev, ib, last_pt, 0,
-                                                       count, 0, 0);
-                       }
-
-                       count = 1;
-                       last_pde = pde;
-                       last_pt = pt;
-               } else {
-                       ++count;
-               }
-       }
-
-       if (count) {
-               radeon_asic_vm_set_page(rdev, ib, last_pde, last_pt, count,
-                                       incr, R600_PTE_VALID);
-
-               count *= RADEON_VM_PTE_COUNT;
-               radeon_asic_vm_set_page(rdev, ib, last_pt, 0,
-                                       count, 0, 0);
-       }
-
-       return 0;
-}
-
-/**
- * radeon_vm_update_ptes - make sure that page tables are valid
- *
- * @rdev: radeon_device pointer
- * @vm: requested vm
- * @start: start of GPU address range
- * @end: end of GPU address range
- * @dst: destination address to map to
- * @flags: mapping flags
- *
- * Update the page tables in the range @start - @end (cayman+).
- *
- * Global and local mutex must be locked!
- */
-static void radeon_vm_update_ptes(struct radeon_device *rdev,
-                                 struct radeon_vm *vm,
-                                 struct radeon_ib *ib,
-                                 uint64_t start, uint64_t end,
-                                 uint64_t dst, uint32_t flags)
-{
-       static const uint64_t mask = RADEON_VM_PTE_COUNT - 1;
-
-       uint64_t last_pte = ~0, last_dst = ~0;
-       unsigned count = 0;
-       uint64_t addr;
-
-       start = start / RADEON_GPU_PAGE_SIZE;
-       end = end / RADEON_GPU_PAGE_SIZE;
-
-       /* walk over the address space and update the page tables */
-       for (addr = start; addr < end; ) {
-               uint64_t pt_idx = addr >> RADEON_VM_BLOCK_SIZE;
-               unsigned nptes;
-               uint64_t pte;
-
-               if ((addr & ~mask) == (end & ~mask))
-                       nptes = end - addr;
-               else
-                       nptes = RADEON_VM_PTE_COUNT - (addr & mask);
-
-               pte = radeon_sa_bo_gpu_addr(vm->page_tables[pt_idx]);
-               pte += (addr & mask) * 8;
-
-               if ((last_pte + 8 * count) != pte) {
-
-                       if (count) {
-                               radeon_asic_vm_set_page(rdev, ib, last_pte,
-                                                       last_dst, count,
-                                                       RADEON_GPU_PAGE_SIZE,
-                                                       flags);
-                       }
-
-                       count = nptes;
-                       last_pte = pte;
-                       last_dst = dst;
-               } else {
-                       count += nptes;
-               }
-
-               addr += nptes;
-               dst += nptes * RADEON_GPU_PAGE_SIZE;
-       }
-
-       if (count) {
-               radeon_asic_vm_set_page(rdev, ib, last_pte,
-                                       last_dst, count,
-                                       RADEON_GPU_PAGE_SIZE, flags);
-       }
-}
-
-/**
- * radeon_vm_bo_update - map a bo into the vm page table
- *
- * @rdev: radeon_device pointer
- * @vm: requested vm
- * @bo: radeon buffer object
- * @mem: ttm mem
- *
- * Fill in the page table entries for @bo (cayman+).
- * Returns 0 for success, -EINVAL for failure.
- *
- * Object have to be reserved & global and local mutex must be locked!
- */
-int radeon_vm_bo_update(struct radeon_device *rdev,
-                       struct radeon_vm *vm,
-                       struct radeon_bo *bo,
-                       struct ttm_mem_reg *mem)
-{
-       struct radeon_ib ib;
-       struct radeon_bo_va *bo_va;
-       unsigned nptes, npdes, ndw;
-       uint64_t addr;
-       int r;
-
-       /* nothing to do if vm isn't bound */
-       if (vm->page_directory == NULL)
-               return 0;
-
-       bo_va = radeon_vm_bo_find(vm, bo);
-       if (bo_va == NULL) {
-               dev_err(rdev->dev, "bo %p not in vm %p\n", bo, vm);
-               return -EINVAL;
-       }
-
-       if (!bo_va->soffset) {
-               dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n",
-                       bo, vm);
-               return -EINVAL;
-       }
-
-       if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL))
-               return 0;
-
-       bo_va->flags &= ~RADEON_VM_PAGE_VALID;
-       bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM;
-       if (mem) {
-               addr = mem->start << PAGE_SHIFT;
-               if (mem->mem_type != TTM_PL_SYSTEM) {
-                       bo_va->flags |= RADEON_VM_PAGE_VALID;
-                       bo_va->valid = true;
-               }
-               if (mem->mem_type == TTM_PL_TT) {
-                       bo_va->flags |= RADEON_VM_PAGE_SYSTEM;
-               } else {
-                       addr += rdev->vm_manager.vram_base_offset;
-               }
-       } else {
-               addr = 0;
-               bo_va->valid = false;
-       }
-
-       trace_radeon_vm_bo_update(bo_va);
-
-       nptes = radeon_bo_ngpu_pages(bo);
-
-       /* assume two extra pdes in case the mapping overlaps the borders */
-       npdes = (nptes >> RADEON_VM_BLOCK_SIZE) + 2;
-
-       /* padding, etc. */
-       ndw = 64;
-
-       if (RADEON_VM_BLOCK_SIZE > 11)
-               /* reserve space for one header for every 2k dwords */
-               ndw += (nptes >> 11) * 4;
-       else
-               /* reserve space for one header for
-                   every (1 << BLOCK_SIZE) entries */
-               ndw += (nptes >> RADEON_VM_BLOCK_SIZE) * 4;
-
-       /* reserve space for pte addresses */
-       ndw += nptes * 2;
-
-       /* reserve space for one header for every 2k dwords */
-       ndw += (npdes >> 11) * 4;
-
-       /* reserve space for pde addresses */
-       ndw += npdes * 2;
-
-       /* reserve space for clearing new page tables */
-       ndw += npdes * 2 * RADEON_VM_PTE_COUNT;
-
-       /* update too big for an IB */
-       if (ndw > 0xfffff)
-               return -ENOMEM;
-
-       r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, ndw * 4);
-       if (r)
-               return r;
-       ib.length_dw = 0;
-
-       r = radeon_vm_update_pdes(rdev, vm, &ib, bo_va->soffset, bo_va->eoffset);
-       if (r) {
-               radeon_ib_free(rdev, &ib);
-               return r;
-       }
-
-       radeon_vm_update_ptes(rdev, vm, &ib, bo_va->soffset, bo_va->eoffset,
-                             addr, radeon_vm_page_flags(bo_va->flags));
-
-       radeon_semaphore_sync_to(ib.semaphore, vm->fence);
-       r = radeon_ib_schedule(rdev, &ib, NULL);
-       if (r) {
-               radeon_ib_free(rdev, &ib);
-               return r;
-       }
-       radeon_fence_unref(&vm->fence);
-       vm->fence = radeon_fence_ref(ib.fence);
-       radeon_ib_free(rdev, &ib);
-       radeon_fence_unref(&vm->last_flush);
-
-       return 0;
-}
-
-/**
- * radeon_vm_bo_rmv - remove a bo to a specific vm
- *
- * @rdev: radeon_device pointer
- * @bo_va: requested bo_va
- *
- * Remove @bo_va->bo from the requested vm (cayman+).
- * Remove @bo_va->bo from the list of bos associated with the bo_va->vm and
- * remove the ptes for @bo_va in the page table.
- * Returns 0 for success.
- *
- * Object have to be reserved!
- */
-int radeon_vm_bo_rmv(struct radeon_device *rdev,
-                    struct radeon_bo_va *bo_va)
-{
-       int r = 0;
-
-       mutex_lock(&rdev->vm_manager.lock);
-       mutex_lock(&bo_va->vm->mutex);
-       if (bo_va->soffset) {
-               r = radeon_vm_bo_update(rdev, bo_va->vm, bo_va->bo, NULL);
-       }
-       mutex_unlock(&rdev->vm_manager.lock);
-       list_del(&bo_va->vm_list);
-       mutex_unlock(&bo_va->vm->mutex);
-       list_del(&bo_va->bo_list);
-
-       kfree(bo_va);
-       return r;
-}
-
-/**
- * radeon_vm_bo_invalidate - mark the bo as invalid
- *
- * @rdev: radeon_device pointer
- * @vm: requested vm
- * @bo: radeon buffer object
- *
- * Mark @bo as invalid (cayman+).
- */
-void radeon_vm_bo_invalidate(struct radeon_device *rdev,
-                            struct radeon_bo *bo)
-{
-       struct radeon_bo_va *bo_va;
-
-       list_for_each_entry(bo_va, &bo->va, bo_list) {
-               bo_va->valid = false;
-       }
-}
-
-/**
- * radeon_vm_init - initialize a vm instance
- *
- * @rdev: radeon_device pointer
- * @vm: requested vm
- *
- * Init @vm fields (cayman+).
- */
-void radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
-{
-       vm->id = 0;
-       vm->fence = NULL;
-       vm->last_flush = NULL;
-       vm->last_id_use = NULL;
-       mutex_init(&vm->mutex);
-       INIT_LIST_HEAD(&vm->list);
-       INIT_LIST_HEAD(&vm->va);
-}
-
-/**
- * radeon_vm_fini - tear down a vm instance
- *
- * @rdev: radeon_device pointer
- * @vm: requested vm
- *
- * Tear down @vm (cayman+).
- * Unbind the VM and remove all bos from the vm bo list
- */
-void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
-{
-       struct radeon_bo_va *bo_va, *tmp;
-       int r;
-
-       mutex_lock(&rdev->vm_manager.lock);
-       mutex_lock(&vm->mutex);
-       radeon_vm_free_pt(rdev, vm);
-       mutex_unlock(&rdev->vm_manager.lock);
-
-       if (!list_empty(&vm->va)) {
-               dev_err(rdev->dev, "still active bo inside vm\n");
-       }
-       list_for_each_entry_safe(bo_va, tmp, &vm->va, vm_list) {
-               list_del_init(&bo_va->vm_list);
-               r = radeon_bo_reserve(bo_va->bo, false);
-               if (!r) {
-                       list_del_init(&bo_va->bo_list);
-                       radeon_bo_unreserve(bo_va->bo);
-                       kfree(bo_va);
-               }
-       }
-       radeon_fence_unref(&vm->fence);
-       radeon_fence_unref(&vm->last_flush);
-       radeon_fence_unref(&vm->last_id_use);
-       mutex_unlock(&vm->mutex);
-}
index b96c819..d09650c 100644 (file)
@@ -344,18 +344,7 @@ int radeon_gem_busy_ioctl(struct drm_device *dev, void *data,
        }
        robj = gem_to_radeon_bo(gobj);
        r = radeon_bo_wait(robj, &cur_placement, true);
-       switch (cur_placement) {
-       case TTM_PL_VRAM:
-               args->domain = RADEON_GEM_DOMAIN_VRAM;
-               break;
-       case TTM_PL_TT:
-               args->domain = RADEON_GEM_DOMAIN_GTT;
-               break;
-       case TTM_PL_SYSTEM:
-               args->domain = RADEON_GEM_DOMAIN_CPU;
-       default:
-               break;
-       }
+       args->domain = radeon_mem_type_to_domain(cur_placement);
        drm_gem_object_unreference_unlocked(gobj);
        r = radeon_gem_handle_lockup(rdev, r);
        return r;
@@ -533,6 +522,42 @@ out:
        return r;
 }
 
+int radeon_gem_op_ioctl(struct drm_device *dev, void *data,
+                       struct drm_file *filp)
+{
+       struct drm_radeon_gem_op *args = data;
+       struct drm_gem_object *gobj;
+       struct radeon_bo *robj;
+       int r;
+
+       gobj = drm_gem_object_lookup(dev, filp, args->handle);
+       if (gobj == NULL) {
+               return -ENOENT;
+       }
+       robj = gem_to_radeon_bo(gobj);
+       r = radeon_bo_reserve(robj, false);
+       if (unlikely(r))
+               goto out;
+
+       switch (args->op) {
+       case RADEON_GEM_OP_GET_INITIAL_DOMAIN:
+               args->value = robj->initial_domain;
+               break;
+       case RADEON_GEM_OP_SET_INITIAL_DOMAIN:
+               robj->initial_domain = args->value & (RADEON_GEM_DOMAIN_VRAM |
+                                                     RADEON_GEM_DOMAIN_GTT |
+                                                     RADEON_GEM_DOMAIN_CPU);
+               break;
+       default:
+               r = -EINVAL;
+       }
+
+       radeon_bo_unreserve(robj);
+out:
+       drm_gem_object_unreference_unlocked(gobj);
+       return r;
+}
+
 int radeon_mode_dumb_create(struct drm_file *file_priv,
                            struct drm_device *dev,
                            struct drm_mode_create_dumb *args)
index 66ed3ea..3e49342 100644 (file)
@@ -441,6 +441,9 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                case RADEON_CS_RING_UVD:
                        *value = rdev->ring[R600_RING_TYPE_UVD_INDEX].ready;
                        break;
+               case RADEON_CS_RING_VCE:
+                       *value = rdev->ring[TN_RING_TYPE_VCE1_INDEX].ready;
+                       break;
                default:
                        return -EINVAL;
                }
@@ -485,6 +488,27 @@ static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file
                else
                        *value = rdev->pm.default_sclk * 10;
                break;
+       case RADEON_INFO_VCE_FW_VERSION:
+               *value = rdev->vce.fw_version;
+               break;
+       case RADEON_INFO_VCE_FB_VERSION:
+               *value = rdev->vce.fb_version;
+               break;
+       case RADEON_INFO_NUM_BYTES_MOVED:
+               value = (uint32_t*)&value64;
+               value_size = sizeof(uint64_t);
+               value64 = atomic64_read(&rdev->num_bytes_moved);
+               break;
+       case RADEON_INFO_VRAM_USAGE:
+               value = (uint32_t*)&value64;
+               value_size = sizeof(uint64_t);
+               value64 = atomic64_read(&rdev->vram_usage);
+               break;
+       case RADEON_INFO_GTT_USAGE:
+               value = (uint32_t*)&value64;
+               value_size = sizeof(uint64_t);
+               value64 = atomic64_read(&rdev->gtt_usage);
+               break;
        default:
                DRM_DEBUG_KMS("Invalid request %d\n", info->request);
                return -EINVAL;
@@ -543,7 +567,9 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
                        return -ENOMEM;
                }
 
-               radeon_vm_init(rdev, &fpriv->vm);
+               r = radeon_vm_init(rdev, &fpriv->vm);
+               if (r)
+                       return r;
 
                r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
                if (r)
@@ -624,6 +650,7 @@ void radeon_driver_preclose_kms(struct drm_device *dev,
        if (rdev->cmask_filp == file_priv)
                rdev->cmask_filp = NULL;
        radeon_uvd_free_handles(rdev, file_priv);
+       radeon_vce_free_handles(rdev, file_priv);
 }
 
 /*
@@ -818,5 +845,6 @@ const struct drm_ioctl_desc radeon_ioctls_kms[] = {
        DRM_IOCTL_DEF_DRV(RADEON_GEM_GET_TILING, radeon_gem_get_tiling_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(RADEON_GEM_BUSY, radeon_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(RADEON_GEM_VA, radeon_gem_va_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(RADEON_GEM_OP, radeon_gem_op_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
 };
 int radeon_max_kms_ioctl = DRM_ARRAY_SIZE(radeon_ioctls_kms);
index 0b158f9..cafb1cc 100644 (file)
@@ -385,7 +385,7 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
 
        DRM_DEBUG_KMS("\n");
        /* no fb bound */
-       if (!atomic && !crtc->fb) {
+       if (!atomic && !crtc->primary->fb) {
                DRM_DEBUG_KMS("No FB bound\n");
                return 0;
        }
@@ -395,8 +395,8 @@ int radeon_crtc_do_set_base(struct drm_crtc *crtc,
                target_fb = fb;
        }
        else {
-               radeon_fb = to_radeon_framebuffer(crtc->fb);
-               target_fb = crtc->fb;
+               radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
+               target_fb = crtc->primary->fb;
        }
 
        switch (target_fb->bits_per_pixel) {
@@ -444,7 +444,7 @@ retry:
                 * We don't shutdown the display controller because new buffer
                 * will end up in same spot.
                 */
-               if (!atomic && fb && fb != crtc->fb) {
+               if (!atomic && fb && fb != crtc->primary->fb) {
                        struct radeon_bo *old_rbo;
                        unsigned long nsize, osize;
 
@@ -555,7 +555,7 @@ retry:
        WREG32(RADEON_CRTC_OFFSET + radeon_crtc->crtc_offset, crtc_offset);
        WREG32(RADEON_CRTC_PITCH + radeon_crtc->crtc_offset, crtc_pitch);
 
-       if (!atomic && fb && fb != crtc->fb) {
+       if (!atomic && fb && fb != crtc->primary->fb) {
                radeon_fb = to_radeon_framebuffer(fb);
                rbo = gem_to_radeon_bo(radeon_fb->obj);
                r = radeon_bo_reserve(rbo, false);
@@ -599,7 +599,7 @@ static bool radeon_set_crtc_timing(struct drm_crtc *crtc, struct drm_display_mod
                }
        }
 
-       switch (crtc->fb->bits_per_pixel) {
+       switch (crtc->primary->fb->bits_per_pixel) {
        case 8:
                format = 2;
                break;
@@ -1087,12 +1087,12 @@ static void radeon_crtc_commit(struct drm_crtc *crtc)
 static void radeon_crtc_disable(struct drm_crtc *crtc)
 {
        radeon_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
-       if (crtc->fb) {
+       if (crtc->primary->fb) {
                int r;
                struct radeon_framebuffer *radeon_fb;
                struct radeon_bo *rbo;
 
-               radeon_fb = to_radeon_framebuffer(crtc->fb);
+               radeon_fb = to_radeon_framebuffer(crtc->primary->fb);
                rbo = gem_to_radeon_bo(radeon_fb->obj);
                r = radeon_bo_reserve(rbo, false);
                if (unlikely(r))
index 402dbe3..832d9fa 100644 (file)
@@ -192,6 +192,7 @@ struct radeon_i2c_chan {
                struct i2c_algo_dp_aux_data dp;
        } algo;
        struct radeon_i2c_bus_rec rec;
+       struct drm_dp_aux aux;
 };
 
 /* mostly for macs, but really any system without connector tables */
@@ -690,6 +691,9 @@ extern u8 radeon_dp_getsinktype(struct radeon_connector *radeon_connector);
 extern bool radeon_dp_getdpcd(struct radeon_connector *radeon_connector);
 extern int radeon_dp_get_panel_mode(struct drm_encoder *encoder,
                                    struct drm_connector *connector);
+extern void radeon_dp_set_rx_power_state(struct drm_connector *connector,
+                                        u8 power_state);
+extern void radeon_dp_aux_init(struct radeon_connector *radeon_connector);
 extern void atombios_dig_encoder_setup(struct drm_encoder *encoder, int action, int panel_mode);
 extern void radeon_atom_encoder_init(struct radeon_device *rdev);
 extern void radeon_atom_disp_eng_pll_init(struct radeon_device *rdev);
index 08595cf..19bec0d 100644 (file)
@@ -56,11 +56,36 @@ static void radeon_bo_clear_va(struct radeon_bo *bo)
        }
 }
 
+static void radeon_update_memory_usage(struct radeon_bo *bo,
+                                      unsigned mem_type, int sign)
+{
+       struct radeon_device *rdev = bo->rdev;
+       u64 size = (u64)bo->tbo.num_pages << PAGE_SHIFT;
+
+       switch (mem_type) {
+       case TTM_PL_TT:
+               if (sign > 0)
+                       atomic64_add(size, &rdev->gtt_usage);
+               else
+                       atomic64_sub(size, &rdev->gtt_usage);
+               break;
+       case TTM_PL_VRAM:
+               if (sign > 0)
+                       atomic64_add(size, &rdev->vram_usage);
+               else
+                       atomic64_sub(size, &rdev->vram_usage);
+               break;
+       }
+}
+
 static void radeon_ttm_bo_destroy(struct ttm_buffer_object *tbo)
 {
        struct radeon_bo *bo;
 
        bo = container_of(tbo, struct radeon_bo, tbo);
+
+       radeon_update_memory_usage(bo, bo->tbo.mem.mem_type, -1);
+
        mutex_lock(&bo->rdev->gem.mutex);
        list_del_init(&bo->list);
        mutex_unlock(&bo->rdev->gem.mutex);
@@ -79,7 +104,7 @@ bool radeon_ttm_bo_is_radeon_bo(struct ttm_buffer_object *bo)
 
 void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
 {
-       u32 c = 0;
+       u32 c = 0, i;
 
        rbo->placement.fpfn = 0;
        rbo->placement.lpfn = 0;
@@ -106,6 +131,17 @@ void radeon_ttm_placement_from_domain(struct radeon_bo *rbo, u32 domain)
                rbo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
        rbo->placement.num_placement = c;
        rbo->placement.num_busy_placement = c;
+
+       /*
+        * Use two-ended allocation depending on the buffer size to
+        * improve fragmentation quality.
+        * 512kb was measured as the most optimal number.
+        */
+       if (rbo->tbo.mem.size > 512 * 1024) {
+               for (i = 0; i < c; i++) {
+                       rbo->placements[i] |= TTM_PL_FLAG_TOPDOWN;
+               }
+       }
 }
 
 int radeon_bo_create(struct radeon_device *rdev,
@@ -120,7 +156,6 @@ int radeon_bo_create(struct radeon_device *rdev,
 
        size = ALIGN(size, PAGE_SIZE);
 
-       rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;
        if (kernel) {
                type = ttm_bo_type_kernel;
        } else if (sg) {
@@ -145,6 +180,9 @@ int radeon_bo_create(struct radeon_device *rdev,
        bo->surface_reg = -1;
        INIT_LIST_HEAD(&bo->list);
        INIT_LIST_HEAD(&bo->va);
+       bo->initial_domain = domain & (RADEON_GEM_DOMAIN_VRAM |
+                                      RADEON_GEM_DOMAIN_GTT |
+                                      RADEON_GEM_DOMAIN_CPU);
        radeon_ttm_placement_from_domain(bo, domain);
        /* Kernel allocation are uninterruptible */
        down_read(&rdev->pm.mclk_lock);
@@ -338,39 +376,105 @@ void radeon_bo_fini(struct radeon_device *rdev)
        arch_phys_wc_del(rdev->mc.vram_mtrr);
 }
 
-void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
-                               struct list_head *head)
+/* Returns how many bytes TTM can move per IB.
+ */
+static u64 radeon_bo_get_threshold_for_moves(struct radeon_device *rdev)
 {
-       if (lobj->written) {
-               list_add(&lobj->tv.head, head);
-       } else {
-               list_add_tail(&lobj->tv.head, head);
-       }
+       u64 real_vram_size = rdev->mc.real_vram_size;
+       u64 vram_usage = atomic64_read(&rdev->vram_usage);
+
+       /* This function is based on the current VRAM usage.
+        *
+        * - If all of VRAM is free, allow relocating the number of bytes that
+        *   is equal to 1/4 of the size of VRAM for this IB.
+
+        * - If more than one half of VRAM is occupied, only allow relocating
+        *   1 MB of data for this IB.
+        *
+        * - From 0 to one half of used VRAM, the threshold decreases
+        *   linearly.
+        *         __________________
+        * 1/4 of -|\               |
+        * VRAM    | \              |
+        *         |  \             |
+        *         |   \            |
+        *         |    \           |
+        *         |     \          |
+        *         |      \         |
+        *         |       \________|1 MB
+        *         |----------------|
+        *    VRAM 0 %             100 %
+        *         used            used
+        *
+        * Note: It's a threshold, not a limit. The threshold must be crossed
+        * for buffer relocations to stop, so any buffer of an arbitrary size
+        * can be moved as long as the threshold isn't crossed before
+        * the relocation takes place. We don't want to disable buffer
+        * relocations completely.
+        *
+        * The idea is that buffers should be placed in VRAM at creation time
+        * and TTM should only do a minimum number of relocations during
+        * command submission. In practice, you need to submit at least
+        * a dozen IBs to move all buffers to VRAM if they are in GTT.
+        *
+        * Also, things can get pretty crazy under memory pressure and actual
+        * VRAM usage can change a lot, so playing safe even at 50% does
+        * consistently increase performance.
+        */
+
+       u64 half_vram = real_vram_size >> 1;
+       u64 half_free_vram = vram_usage >= half_vram ? 0 : half_vram - vram_usage;
+       u64 bytes_moved_threshold = half_free_vram >> 1;
+       return max(bytes_moved_threshold, 1024*1024ull);
 }
 
-int radeon_bo_list_validate(struct ww_acquire_ctx *ticket,
+int radeon_bo_list_validate(struct radeon_device *rdev,
+                           struct ww_acquire_ctx *ticket,
                            struct list_head *head, int ring)
 {
-       struct radeon_bo_list *lobj;
+       struct radeon_cs_reloc *lobj;
        struct radeon_bo *bo;
-       u32 domain;
        int r;
+       u64 bytes_moved = 0, initial_bytes_moved;
+       u64 bytes_moved_threshold = radeon_bo_get_threshold_for_moves(rdev);
 
        r = ttm_eu_reserve_buffers(ticket, head);
        if (unlikely(r != 0)) {
                return r;
        }
+
        list_for_each_entry(lobj, head, tv.head) {
-               bo = lobj->bo;
+               bo = lobj->robj;
                if (!bo->pin_count) {
-                       domain = lobj->domain;
-                       
+                       u32 domain = lobj->domain;
+                       u32 current_domain =
+                               radeon_mem_type_to_domain(bo->tbo.mem.mem_type);
+
+                       /* Check if this buffer will be moved and don't move it
+                        * if we have moved too many buffers for this IB already.
+                        *
+                        * Note that this allows moving at least one buffer of
+                        * any size, because it doesn't take the current "bo"
+                        * into account. We don't want to disallow buffer moves
+                        * completely.
+                        */
+                       if (current_domain != RADEON_GEM_DOMAIN_CPU &&
+                           (domain & current_domain) == 0 && /* will be moved */
+                           bytes_moved > bytes_moved_threshold) {
+                               /* don't move it */
+                               domain = current_domain;
+                       }
+
                retry:
                        radeon_ttm_placement_from_domain(bo, domain);
                        if (ring == R600_RING_TYPE_UVD_INDEX)
                                radeon_uvd_force_into_uvd_segment(bo);
-                       r = ttm_bo_validate(&bo->tbo, &bo->placement,
-                                               true, false);
+
+                       initial_bytes_moved = atomic64_read(&rdev->num_bytes_moved);
+                       r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+                       bytes_moved += atomic64_read(&rdev->num_bytes_moved) -
+                                      initial_bytes_moved;
+
                        if (unlikely(r)) {
                                if (r != -ERESTARTSYS && domain != lobj->alt_domain) {
                                        domain = lobj->alt_domain;
@@ -564,14 +668,23 @@ int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
 }
 
 void radeon_bo_move_notify(struct ttm_buffer_object *bo,
-                          struct ttm_mem_reg *mem)
+                          struct ttm_mem_reg *new_mem)
 {
        struct radeon_bo *rbo;
+
        if (!radeon_ttm_bo_is_radeon_bo(bo))
                return;
+
        rbo = container_of(bo, struct radeon_bo, tbo);
        radeon_bo_check_tiling(rbo, 0, 1);
        radeon_vm_bo_invalidate(rbo->rdev, rbo);
+
+       /* update statistics */
+       if (!new_mem)
+               return;
+
+       radeon_update_memory_usage(rbo, bo->mem.mem_type, -1);
+       radeon_update_memory_usage(rbo, new_mem->mem_type, 1);
 }
 
 int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo)
index 209b111..9e7b25a 100644 (file)
@@ -138,9 +138,8 @@ extern int radeon_bo_evict_vram(struct radeon_device *rdev);
 extern void radeon_bo_force_delete(struct radeon_device *rdev);
 extern int radeon_bo_init(struct radeon_device *rdev);
 extern void radeon_bo_fini(struct radeon_device *rdev);
-extern void radeon_bo_list_add_object(struct radeon_bo_list *lobj,
-                               struct list_head *head);
-extern int radeon_bo_list_validate(struct ww_acquire_ctx *ticket,
+extern int radeon_bo_list_validate(struct radeon_device *rdev,
+                                  struct ww_acquire_ctx *ticket,
                                   struct list_head *head, int ring);
 extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
                                struct vm_area_struct *vma);
@@ -151,7 +150,7 @@ extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo,
 extern int radeon_bo_check_tiling(struct radeon_bo *bo, bool has_moved,
                                bool force_drop);
 extern void radeon_bo_move_notify(struct ttm_buffer_object *bo,
-                                       struct ttm_mem_reg *mem);
+                                 struct ttm_mem_reg *new_mem);
 extern int radeon_bo_fault_reserve_notify(struct ttm_buffer_object *bo);
 extern int radeon_bo_get_surface_reg(struct radeon_bo *bo);
 
@@ -181,7 +180,7 @@ extern int radeon_sa_bo_manager_suspend(struct radeon_device *rdev,
 extern int radeon_sa_bo_new(struct radeon_device *rdev,
                            struct radeon_sa_manager *sa_manager,
                            struct radeon_sa_bo **sa_bo,
-                           unsigned size, unsigned align, bool block);
+                           unsigned size, unsigned align);
 extern void radeon_sa_bo_free(struct radeon_device *rdev,
                              struct radeon_sa_bo **sa_bo,
                              struct radeon_fence *fence);
index 8e8153e..ee738a5 100644 (file)
@@ -260,7 +260,7 @@ static void radeon_pm_set_clocks(struct radeon_device *rdev)
                if (!ring->ready) {
                        continue;
                }
-               r = radeon_fence_wait_empty_locked(rdev, i);
+               r = radeon_fence_wait_empty(rdev, i);
                if (r) {
                        /* needs a GPU reset dont reset here */
                        mutex_unlock(&rdev->ring_lock);
@@ -826,6 +826,9 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
 
        /* no need to reprogram if nothing changed unless we are on BTC+ */
        if (rdev->pm.dpm.current_ps == rdev->pm.dpm.requested_ps) {
+               /* vce just modifies an existing state so force a change */
+               if (ps->vce_active != rdev->pm.dpm.vce_active)
+                       goto force;
                if ((rdev->family < CHIP_BARTS) || (rdev->flags & RADEON_IS_IGP)) {
                        /* for pre-BTC and APUs if the num crtcs changed but state is the same,
                         * all we need to do is update the display configuration.
@@ -862,16 +865,21 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
                }
        }
 
+force:
        if (radeon_dpm == 1) {
                printk("switching from power state:\n");
                radeon_dpm_print_power_state(rdev, rdev->pm.dpm.current_ps);
                printk("switching to power state:\n");
                radeon_dpm_print_power_state(rdev, rdev->pm.dpm.requested_ps);
        }
+
        mutex_lock(&rdev->ddev->struct_mutex);
        down_write(&rdev->pm.mclk_lock);
        mutex_lock(&rdev->ring_lock);
 
+       /* update whether vce is active */
+       ps->vce_active = rdev->pm.dpm.vce_active;
+
        ret = radeon_dpm_pre_set_power_state(rdev);
        if (ret)
                goto done;
@@ -888,7 +896,7 @@ static void radeon_dpm_change_power_state_locked(struct radeon_device *rdev)
        for (i = 0; i < RADEON_NUM_RINGS; i++) {
                struct radeon_ring *ring = &rdev->ring[i];
                if (ring->ready)
-                       radeon_fence_wait_empty_locked(rdev, i);
+                       radeon_fence_wait_empty(rdev, i);
        }
 
        /* program the new power state */
@@ -935,8 +943,6 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
                if (enable) {
                        mutex_lock(&rdev->pm.mutex);
                        rdev->pm.dpm.uvd_active = true;
-                       /* disable this for now */
-#if 0
                        if ((rdev->pm.dpm.sd == 1) && (rdev->pm.dpm.hd == 0))
                                dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_SD;
                        else if ((rdev->pm.dpm.sd == 2) && (rdev->pm.dpm.hd == 0))
@@ -946,7 +952,6 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
                        else if ((rdev->pm.dpm.sd == 0) && (rdev->pm.dpm.hd == 2))
                                dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD2;
                        else
-#endif
                                dpm_state = POWER_STATE_TYPE_INTERNAL_UVD;
                        rdev->pm.dpm.state = dpm_state;
                        mutex_unlock(&rdev->pm.mutex);
@@ -960,6 +965,23 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
        }
 }
 
+void radeon_dpm_enable_vce(struct radeon_device *rdev, bool enable)
+{
+       if (enable) {
+               mutex_lock(&rdev->pm.mutex);
+               rdev->pm.dpm.vce_active = true;
+               /* XXX select vce level based on ring/task */
+               rdev->pm.dpm.vce_level = RADEON_VCE_LEVEL_AC_ALL;
+               mutex_unlock(&rdev->pm.mutex);
+       } else {
+               mutex_lock(&rdev->pm.mutex);
+               rdev->pm.dpm.vce_active = false;
+               mutex_unlock(&rdev->pm.mutex);
+       }
+
+       radeon_pm_compute_clocks(rdev);
+}
+
 static void radeon_pm_suspend_old(struct radeon_device *rdev)
 {
        mutex_lock(&rdev->pm.mutex);
index 15e44a7..f8050f5 100644 (file)
@@ -63,7 +63,7 @@ int radeon_ib_get(struct radeon_device *rdev, int ring,
 {
        int r;
 
-       r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &ib->sa_bo, size, 256, true);
+       r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &ib->sa_bo, size, 256);
        if (r) {
                dev_err(rdev->dev, "failed to get a new IB (%d)\n", r);
                return r;
@@ -145,6 +145,13 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
                return r;
        }
 
+       /* grab a vm id if necessary */
+       if (ib->vm) {
+               struct radeon_fence *vm_id_fence;
+               vm_id_fence = radeon_vm_grab_id(rdev, ib->vm, ib->ring);
+               radeon_semaphore_sync_to(ib->semaphore, vm_id_fence);
+       }
+
        /* sync with other rings */
        r = radeon_semaphore_sync_rings(rdev, ib->semaphore, ib->ring);
        if (r) {
@@ -153,11 +160,9 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
                return r;
        }
 
-       /* if we can't remember our last VM flush then flush now! */
-       /* XXX figure out why we have to flush for every IB */
-       if (ib->vm /*&& !ib->vm->last_flush*/) {
-               radeon_ring_vm_flush(rdev, ib->ring, ib->vm);
-       }
+       if (ib->vm)
+               radeon_vm_flush(rdev, ib->vm, ib->ring);
+
        if (const_ib) {
                radeon_ring_ib_execute(rdev, const_ib->ring, const_ib);
                radeon_semaphore_free(rdev, &const_ib->semaphore, NULL);
@@ -172,10 +177,10 @@ int radeon_ib_schedule(struct radeon_device *rdev, struct radeon_ib *ib,
        if (const_ib) {
                const_ib->fence = radeon_fence_ref(ib->fence);
        }
-       /* we just flushed the VM, remember that */
-       if (ib->vm && !ib->vm->last_flush) {
-               ib->vm->last_flush = radeon_fence_ref(ib->fence);
-       }
+
+       if (ib->vm)
+               radeon_vm_fence(rdev, ib->vm, ib->fence);
+
        radeon_ring_unlock_commit(rdev, ring);
        return 0;
 }
@@ -257,6 +262,7 @@ int radeon_ib_ring_tests(struct radeon_device *rdev)
                r = radeon_ib_test(rdev, i, ring);
                if (r) {
                        ring->ready = false;
+                       rdev->needs_reset = false;
 
                        if (i == RADEON_RING_TYPE_GFX_INDEX) {
                                /* oh, oh, that's really bad */
@@ -342,13 +348,17 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
  */
 void radeon_ring_free_size(struct radeon_device *rdev, struct radeon_ring *ring)
 {
-       ring->rptr = radeon_ring_get_rptr(rdev, ring);
+       uint32_t rptr = radeon_ring_get_rptr(rdev, ring);
+
        /* This works because ring_size is a power of 2 */
-       ring->ring_free_dw = (ring->rptr + (ring->ring_size / 4));
+       ring->ring_free_dw = rptr + (ring->ring_size / 4);
        ring->ring_free_dw -= ring->wptr;
        ring->ring_free_dw &= ring->ptr_mask;
        if (!ring->ring_free_dw) {
+               /* this is an empty ring */
                ring->ring_free_dw = ring->ring_size / 4;
+               /*  update lockup info to avoid false positive */
+               radeon_ring_lockup_update(rdev, ring);
        }
 }
 
@@ -372,19 +382,13 @@ int radeon_ring_alloc(struct radeon_device *rdev, struct radeon_ring *ring, unsi
        /* Align requested size with padding so unlock_commit can
         * pad safely */
        radeon_ring_free_size(rdev, ring);
-       if (ring->ring_free_dw == (ring->ring_size / 4)) {
-               /* This is an empty ring update lockup info to avoid
-                * false positive.
-                */
-               radeon_ring_lockup_update(ring);
-       }
        ndw = (ndw + ring->align_mask) & ~ring->align_mask;
        while (ndw > (ring->ring_free_dw - 1)) {
                radeon_ring_free_size(rdev, ring);
                if (ndw < ring->ring_free_dw) {
                        break;
                }
-               r = radeon_fence_wait_next_locked(rdev, ring->idx);
+               r = radeon_fence_wait_next(rdev, ring->idx);
                if (r)
                        return r;
        }
@@ -477,29 +481,6 @@ void radeon_ring_unlock_undo(struct radeon_device *rdev, struct radeon_ring *rin
        mutex_unlock(&rdev->ring_lock);
 }
 
-/**
- * radeon_ring_force_activity - add some nop packets to the ring
- *
- * @rdev: radeon_device pointer
- * @ring: radeon_ring structure holding ring information
- *
- * Add some nop packets to the ring to force activity (all asics).
- * Used for lockup detection to see if the rptr is advancing.
- */
-void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *ring)
-{
-       int r;
-
-       radeon_ring_free_size(rdev, ring);
-       if (ring->rptr == ring->wptr) {
-               r = radeon_ring_alloc(rdev, ring, 1);
-               if (!r) {
-                       radeon_ring_write(ring, ring->nop);
-                       radeon_ring_commit(rdev, ring);
-               }
-       }
-}
-
 /**
  * radeon_ring_lockup_update - update lockup variables
  *
@@ -507,10 +488,11 @@ void radeon_ring_force_activity(struct radeon_device *rdev, struct radeon_ring *
  *
  * Update the last rptr value and timestamp (all asics).
  */
-void radeon_ring_lockup_update(struct radeon_ring *ring)
+void radeon_ring_lockup_update(struct radeon_device *rdev,
+                              struct radeon_ring *ring)
 {
-       ring->last_rptr = ring->rptr;
-       ring->last_activity = jiffies;
+       atomic_set(&ring->last_rptr, radeon_ring_get_rptr(rdev, ring));
+       atomic64_set(&ring->last_activity, jiffies_64);
 }
 
 /**
@@ -518,40 +500,23 @@ void radeon_ring_lockup_update(struct radeon_ring *ring)
  * @rdev:       radeon device structure
  * @ring:       radeon_ring structure holding ring information
  *
- * We don't need to initialize the lockup tracking information as we will either
- * have CP rptr to a different value of jiffies wrap around which will force
- * initialization of the lockup tracking informations.
- *
- * A possible false positivie is if we get call after while and last_cp_rptr ==
- * the current CP rptr, even if it's unlikely it might happen. To avoid this
- * if the elapsed time since last call is bigger than 2 second than we return
- * false and update the tracking information. Due to this the caller must call
- * radeon_ring_test_lockup several time in less than 2sec for lockup to be reported
- * the fencing code should be cautious about that.
- *
- * Caller should write to the ring to force CP to do something so we don't get
- * false positive when CP is just gived nothing to do.
- *
- **/
+ */
 bool radeon_ring_test_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
 {
-       unsigned long cjiffies, elapsed;
+       uint32_t rptr = radeon_ring_get_rptr(rdev, ring);
+       uint64_t last = atomic64_read(&ring->last_activity);
+       uint64_t elapsed;
 
-       cjiffies = jiffies;
-       if (!time_after(cjiffies, ring->last_activity)) {
-               /* likely a wrap around */
-               radeon_ring_lockup_update(ring);
+       if (rptr != atomic_read(&ring->last_rptr)) {
+               /* ring is still working, no lockup */
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       ring->rptr = radeon_ring_get_rptr(rdev, ring);
-       if (ring->rptr != ring->last_rptr) {
-               /* CP is still working no lockup */
-               radeon_ring_lockup_update(ring);
-               return false;
-       }
-       elapsed = jiffies_to_msecs(cjiffies - ring->last_activity);
+
+       elapsed = jiffies_to_msecs(jiffies_64 - last);
        if (radeon_lockup_timeout && elapsed >= radeon_lockup_timeout) {
-               dev_err(rdev->dev, "GPU lockup CP stall for more than %lumsec\n", elapsed);
+               dev_err(rdev->dev, "ring %d stalled for more than %llumsec\n",
+                       ring->idx, elapsed);
                return true;
        }
        /* give a chance to the GPU ... */
@@ -709,7 +674,7 @@ int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsig
        if (radeon_debugfs_ring_init(rdev, ring)) {
                DRM_ERROR("Failed to register debugfs file for rings !\n");
        }
-       radeon_ring_lockup_update(ring);
+       radeon_ring_lockup_update(rdev, ring);
        return 0;
 }
 
@@ -780,8 +745,6 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
 
        seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n",
                   ring->wptr, ring->wptr);
-       seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n",
-                  ring->rptr, ring->rptr);
        seq_printf(m, "last semaphore signal addr : 0x%016llx\n",
                   ring->last_semaphore_signal_addr);
        seq_printf(m, "last semaphore wait addr   : 0x%016llx\n",
@@ -814,6 +777,8 @@ static int cayman_cp2_index = CAYMAN_RING_TYPE_CP2_INDEX;
 static int radeon_dma1_index = R600_RING_TYPE_DMA_INDEX;
 static int radeon_dma2_index = CAYMAN_RING_TYPE_DMA1_INDEX;
 static int r600_uvd_index = R600_RING_TYPE_UVD_INDEX;
+static int si_vce1_index = TN_RING_TYPE_VCE1_INDEX;
+static int si_vce2_index = TN_RING_TYPE_VCE2_INDEX;
 
 static struct drm_info_list radeon_debugfs_ring_info_list[] = {
        {"radeon_ring_gfx", radeon_debugfs_ring_info, 0, &radeon_gfx_index},
@@ -822,6 +787,8 @@ static struct drm_info_list radeon_debugfs_ring_info_list[] = {
        {"radeon_ring_dma1", radeon_debugfs_ring_info, 0, &radeon_dma1_index},
        {"radeon_ring_dma2", radeon_debugfs_ring_info, 0, &radeon_dma2_index},
        {"radeon_ring_uvd", radeon_debugfs_ring_info, 0, &r600_uvd_index},
+       {"radeon_ring_vce1", radeon_debugfs_ring_info, 0, &si_vce1_index},
+       {"radeon_ring_vce2", radeon_debugfs_ring_info, 0, &si_vce2_index},
 };
 
 static int radeon_debugfs_sa_info(struct seq_file *m, void *data)
index c062580..adcf3e2 100644 (file)
@@ -312,7 +312,7 @@ static bool radeon_sa_bo_next_hole(struct radeon_sa_manager *sa_manager,
 int radeon_sa_bo_new(struct radeon_device *rdev,
                     struct radeon_sa_manager *sa_manager,
                     struct radeon_sa_bo **sa_bo,
-                    unsigned size, unsigned align, bool block)
+                    unsigned size, unsigned align)
 {
        struct radeon_fence *fences[RADEON_NUM_RINGS];
        unsigned tries[RADEON_NUM_RINGS];
@@ -353,14 +353,11 @@ int radeon_sa_bo_new(struct radeon_device *rdev,
                r = radeon_fence_wait_any(rdev, fences, false);
                spin_lock(&sa_manager->wq.lock);
                /* if we have nothing to wait for block */
-               if (r == -ENOENT && block) {
+               if (r == -ENOENT) {
                        r = wait_event_interruptible_locked(
                                sa_manager->wq, 
                                radeon_sa_event(sa_manager, size, align)
                        );
-
-               } else if (r == -ENOENT) {
-                       r = -ENOMEM;
                }
 
        } while (!r);
index 9006b32..dbd6bcd 100644 (file)
@@ -42,7 +42,7 @@ int radeon_semaphore_create(struct radeon_device *rdev,
                return -ENOMEM;
        }
        r = radeon_sa_bo_new(rdev, &rdev->ring_tmp_bo, &(*semaphore)->sa_bo,
-                            8 * RADEON_NUM_SYNCS, 8, true);
+                            8 * RADEON_NUM_SYNCS, 8);
        if (r) {
                kfree(*semaphore);
                *semaphore = NULL;
@@ -147,7 +147,9 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
 
                if (++count > RADEON_NUM_SYNCS) {
                        /* not enough room, wait manually */
-                       radeon_fence_wait_locked(fence);
+                       r = radeon_fence_wait(fence, false);
+                       if (r)
+                               return r;
                        continue;
                }
 
@@ -161,7 +163,9 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
                if (!radeon_semaphore_emit_signal(rdev, i, semaphore)) {
                        /* signaling wasn't successful wait manually */
                        radeon_ring_undo(&rdev->ring[i]);
-                       radeon_fence_wait_locked(fence);
+                       r = radeon_fence_wait(fence, false);
+                       if (r)
+                               return r;
                        continue;
                }
 
@@ -169,7 +173,9 @@ int radeon_semaphore_sync_rings(struct radeon_device *rdev,
                if (!radeon_semaphore_emit_wait(rdev, ring, semaphore)) {
                        /* waiting wasn't successful wait manually */
                        radeon_ring_undo(&rdev->ring[i]);
-                       radeon_fence_wait_locked(fence);
+                       r = radeon_fence_wait(fence, false);
+                       if (r)
+                               return r;
                        continue;
                }
 
index 12e8099..3a13e0d 100644 (file)
@@ -257,20 +257,36 @@ static int radeon_test_create_and_emit_fence(struct radeon_device *rdev,
                                             struct radeon_ring *ring,
                                             struct radeon_fence **fence)
 {
+       uint32_t handle = ring->idx ^ 0xdeafbeef;
        int r;
 
        if (ring->idx == R600_RING_TYPE_UVD_INDEX) {
-               r = radeon_uvd_get_create_msg(rdev, ring->idx, 1, NULL);
+               r = radeon_uvd_get_create_msg(rdev, ring->idx, handle, NULL);
                if (r) {
                        DRM_ERROR("Failed to get dummy create msg\n");
                        return r;
                }
 
-               r = radeon_uvd_get_destroy_msg(rdev, ring->idx, 1, fence);
+               r = radeon_uvd_get_destroy_msg(rdev, ring->idx, handle, fence);
                if (r) {
                        DRM_ERROR("Failed to get dummy destroy msg\n");
                        return r;
                }
+
+       } else if (ring->idx == TN_RING_TYPE_VCE1_INDEX ||
+                  ring->idx == TN_RING_TYPE_VCE2_INDEX) {
+               r = radeon_vce_get_create_msg(rdev, ring->idx, handle, NULL);
+               if (r) {
+                       DRM_ERROR("Failed to get dummy create msg\n");
+                       return r;
+               }
+
+               r = radeon_vce_get_destroy_msg(rdev, ring->idx, handle, fence);
+               if (r) {
+                       DRM_ERROR("Failed to get dummy destroy msg\n");
+                       return r;
+               }
+
        } else {
                r = radeon_ring_lock(rdev, ring, 64);
                if (r) {
@@ -486,6 +502,16 @@ out_cleanup:
                printk(KERN_WARNING "Error while testing ring sync (%d).\n", r);
 }
 
+static bool radeon_test_sync_possible(struct radeon_ring *ringA,
+                                     struct radeon_ring *ringB)
+{
+       if (ringA->idx == TN_RING_TYPE_VCE2_INDEX &&
+           ringB->idx == TN_RING_TYPE_VCE1_INDEX)
+               return false;
+
+       return true;
+}
+
 void radeon_test_syncing(struct radeon_device *rdev)
 {
        int i, j, k;
@@ -500,6 +526,9 @@ void radeon_test_syncing(struct radeon_device *rdev)
                        if (!ringB->ready)
                                continue;
 
+                       if (!radeon_test_sync_possible(ringA, ringB))
+                               continue;
+
                        DRM_INFO("Testing syncing between rings %d and %d...\n", i, j);
                        radeon_test_ring_sync(rdev, ringA, ringB);
 
@@ -511,6 +540,12 @@ void radeon_test_syncing(struct radeon_device *rdev)
                                if (!ringC->ready)
                                        continue;
 
+                               if (!radeon_test_sync_possible(ringA, ringC))
+                                       continue;
+
+                               if (!radeon_test_sync_possible(ringB, ringC))
+                                       continue;
+
                                DRM_INFO("Testing syncing between rings %d, %d and %d...\n", i, j, k);
                                radeon_test_ring_sync2(rdev, ringA, ringB, ringC);
 
index 040a2a1..c8a8a51 100644 (file)
@@ -406,8 +406,14 @@ static int radeon_bo_move(struct ttm_buffer_object *bo,
        if (r) {
 memcpy:
                r = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
+               if (r) {
+                       return r;
+               }
        }
-       return r;
+
+       /* update statistics */
+       atomic64_add((u64)bo->num_pages << PAGE_SHIFT, &rdev->num_bytes_moved);
+       return 0;
 }
 
 static int radeon_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
@@ -701,7 +707,9 @@ int radeon_ttm_init(struct radeon_device *rdev)
        /* No others user of address space so set it to 0 */
        r = ttm_bo_device_init(&rdev->mman.bdev,
                               rdev->mman.bo_global_ref.ref.object,
-                              &radeon_bo_driver, DRM_FILE_PAGE_OFFSET,
+                              &radeon_bo_driver,
+                              rdev->ddev->anon_inode->i_mapping,
+                              DRM_FILE_PAGE_OFFSET,
                               rdev->need_dma32);
        if (r) {
                DRM_ERROR("failed initializing buffer object driver(%d).\n", r);
@@ -742,7 +750,6 @@ int radeon_ttm_init(struct radeon_device *rdev)
        }
        DRM_INFO("radeon: %uM of GTT memory ready.\n",
                 (unsigned)(rdev->mc.gtt_size / (1024 * 1024)));
-       rdev->mman.bdev.dev_mapping = rdev->ddev->dev_mapping;
 
        r = radeon_ttm_debugfs_init(rdev);
        if (r) {
index 3e6804b..5748bda 100644 (file)
@@ -455,7 +455,7 @@ static int radeon_uvd_cs_reloc(struct radeon_cs_parser *p,
        }
 
        reloc = p->relocs_ptr[(idx / 4)];
-       start = reloc->lobj.gpu_offset;
+       start = reloc->gpu_offset;
        end = start + radeon_bo_size(reloc->robj);
        start += offset;
 
@@ -807,8 +807,7 @@ void radeon_uvd_note_usage(struct radeon_device *rdev)
                    (rdev->pm.dpm.hd != hd)) {
                        rdev->pm.dpm.sd = sd;
                        rdev->pm.dpm.hd = hd;
-                       /* disable this for now */
-                       /*streams_changed = true;*/
+                       streams_changed = true;
                }
        }
 
diff --git a/drivers/gpu/drm/radeon/radeon_vce.c b/drivers/gpu/drm/radeon/radeon_vce.c
new file mode 100644 (file)
index 0000000..76e9904
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Christian König <christian.koenig@amd.com>
+ */
+
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <drm/drmP.h>
+#include <drm/drm.h>
+
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "sid.h"
+
+/* 1 second timeout */
+#define VCE_IDLE_TIMEOUT_MS    1000
+
+/* Firmware Names */
+#define FIRMWARE_BONAIRE       "radeon/BONAIRE_vce.bin"
+
+MODULE_FIRMWARE(FIRMWARE_BONAIRE);
+
+static void radeon_vce_idle_work_handler(struct work_struct *work);
+
+/**
+ * radeon_vce_init - allocate memory, load vce firmware
+ *
+ * @rdev: radeon_device pointer
+ *
+ * First step to get VCE online, allocate memory and load the firmware
+ */
+int radeon_vce_init(struct radeon_device *rdev)
+{
+       static const char *fw_version = "[ATI LIB=VCEFW,";
+       static const char *fb_version = "[ATI LIB=VCEFWSTATS,";
+       unsigned long size;
+       const char *fw_name, *c;
+       uint8_t start, mid, end;
+       int i, r;
+
+       INIT_DELAYED_WORK(&rdev->vce.idle_work, radeon_vce_idle_work_handler);
+
+       switch (rdev->family) {
+       case CHIP_BONAIRE:
+       case CHIP_KAVERI:
+       case CHIP_KABINI:
+               fw_name = FIRMWARE_BONAIRE;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       r = request_firmware(&rdev->vce_fw, fw_name, rdev->dev);
+       if (r) {
+               dev_err(rdev->dev, "radeon_vce: Can't load firmware \"%s\"\n",
+                       fw_name);
+               return r;
+       }
+
+       /* search for firmware version */
+
+       size = rdev->vce_fw->size - strlen(fw_version) - 9;
+       c = rdev->vce_fw->data;
+       for (;size > 0; --size, ++c)
+               if (strncmp(c, fw_version, strlen(fw_version)) == 0)
+                       break;
+
+       if (size == 0)
+               return -EINVAL;
+
+       c += strlen(fw_version);
+       if (sscanf(c, "%2hhd.%2hhd.%2hhd]", &start, &mid, &end) != 3)
+               return -EINVAL;
+
+       /* search for feedback version */
+
+       size = rdev->vce_fw->size - strlen(fb_version) - 3;
+       c = rdev->vce_fw->data;
+       for (;size > 0; --size, ++c)
+               if (strncmp(c, fb_version, strlen(fb_version)) == 0)
+                       break;
+
+       if (size == 0)
+               return -EINVAL;
+
+       c += strlen(fb_version);
+       if (sscanf(c, "%2u]", &rdev->vce.fb_version) != 1)
+               return -EINVAL;
+
+       DRM_INFO("Found VCE firmware/feedback version %hhd.%hhd.%hhd / %d!\n",
+                start, mid, end, rdev->vce.fb_version);
+
+       rdev->vce.fw_version = (start << 24) | (mid << 16) | (end << 8);
+
+       /* we can only work with this fw version for now */
+       if (rdev->vce.fw_version != ((40 << 24) | (2 << 16) | (2 << 8)))
+               return -EINVAL;
+
+       /* allocate firmware, stack and heap BO */
+
+       size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size) +
+              RADEON_VCE_STACK_SIZE + RADEON_VCE_HEAP_SIZE;
+       r = radeon_bo_create(rdev, size, PAGE_SIZE, true,
+                            RADEON_GEM_DOMAIN_VRAM, NULL, &rdev->vce.vcpu_bo);
+       if (r) {
+               dev_err(rdev->dev, "(%d) failed to allocate VCE bo\n", r);
+               return r;
+       }
+
+       r = radeon_bo_reserve(rdev->vce.vcpu_bo, false);
+       if (r) {
+               radeon_bo_unref(&rdev->vce.vcpu_bo);
+               dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r);
+               return r;
+       }
+
+       r = radeon_bo_pin(rdev->vce.vcpu_bo, RADEON_GEM_DOMAIN_VRAM,
+                         &rdev->vce.gpu_addr);
+       radeon_bo_unreserve(rdev->vce.vcpu_bo);
+       if (r) {
+               radeon_bo_unref(&rdev->vce.vcpu_bo);
+               dev_err(rdev->dev, "(%d) VCE bo pin failed\n", r);
+               return r;
+       }
+
+       for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
+               atomic_set(&rdev->vce.handles[i], 0);
+               rdev->vce.filp[i] = NULL;
+        }
+
+       return 0;
+}
+
+/**
+ * radeon_vce_fini - free memory
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Last step on VCE teardown, free firmware memory
+ */
+void radeon_vce_fini(struct radeon_device *rdev)
+{
+       if (rdev->vce.vcpu_bo == NULL)
+               return;
+
+       radeon_bo_unref(&rdev->vce.vcpu_bo);
+
+       release_firmware(rdev->vce_fw);
+}
+
+/**
+ * radeon_vce_suspend - unpin VCE fw memory
+ *
+ * @rdev: radeon_device pointer
+ *
+ */
+int radeon_vce_suspend(struct radeon_device *rdev)
+{
+       int i;
+
+       if (rdev->vce.vcpu_bo == NULL)
+               return 0;
+
+       for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i)
+               if (atomic_read(&rdev->vce.handles[i]))
+                       break;
+
+       if (i == RADEON_MAX_VCE_HANDLES)
+               return 0;
+
+       /* TODO: suspending running encoding sessions isn't supported */
+       return -EINVAL;
+}
+
+/**
+ * radeon_vce_resume - pin VCE fw memory
+ *
+ * @rdev: radeon_device pointer
+ *
+ */
+int radeon_vce_resume(struct radeon_device *rdev)
+{
+       void *cpu_addr;
+       int r;
+
+       if (rdev->vce.vcpu_bo == NULL)
+               return -EINVAL;
+
+       r = radeon_bo_reserve(rdev->vce.vcpu_bo, false);
+       if (r) {
+               dev_err(rdev->dev, "(%d) failed to reserve VCE bo\n", r);
+               return r;
+       }
+
+       r = radeon_bo_kmap(rdev->vce.vcpu_bo, &cpu_addr);
+       if (r) {
+               radeon_bo_unreserve(rdev->vce.vcpu_bo);
+               dev_err(rdev->dev, "(%d) VCE map failed\n", r);
+               return r;
+       }
+
+       memcpy(cpu_addr, rdev->vce_fw->data, rdev->vce_fw->size);
+
+       radeon_bo_kunmap(rdev->vce.vcpu_bo);
+
+       radeon_bo_unreserve(rdev->vce.vcpu_bo);
+
+       return 0;
+}
+
+/**
+ * radeon_vce_idle_work_handler - power off VCE
+ *
+ * @work: pointer to work structure
+ *
+ * power of VCE when it's not used any more
+ */
+static void radeon_vce_idle_work_handler(struct work_struct *work)
+{
+       struct radeon_device *rdev =
+               container_of(work, struct radeon_device, vce.idle_work.work);
+
+       if ((radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE1_INDEX) == 0) &&
+           (radeon_fence_count_emitted(rdev, TN_RING_TYPE_VCE2_INDEX) == 0)) {
+               if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+                       radeon_dpm_enable_vce(rdev, false);
+               } else {
+                       radeon_set_vce_clocks(rdev, 0, 0);
+               }
+       } else {
+               schedule_delayed_work(&rdev->vce.idle_work,
+                                     msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
+       }
+}
+
+/**
+ * radeon_vce_note_usage - power up VCE
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Make sure VCE is powerd up when we want to use it
+ */
+void radeon_vce_note_usage(struct radeon_device *rdev)
+{
+       bool streams_changed = false;
+       bool set_clocks = !cancel_delayed_work_sync(&rdev->vce.idle_work);
+       set_clocks &= schedule_delayed_work(&rdev->vce.idle_work,
+                                           msecs_to_jiffies(VCE_IDLE_TIMEOUT_MS));
+
+       if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+               /* XXX figure out if the streams changed */
+               streams_changed = false;
+       }
+
+       if (set_clocks || streams_changed) {
+               if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+                       radeon_dpm_enable_vce(rdev, true);
+               } else {
+                       radeon_set_vce_clocks(rdev, 53300, 40000);
+               }
+       }
+}
+
+/**
+ * radeon_vce_free_handles - free still open VCE handles
+ *
+ * @rdev: radeon_device pointer
+ * @filp: drm file pointer
+ *
+ * Close all VCE handles still open by this file pointer
+ */
+void radeon_vce_free_handles(struct radeon_device *rdev, struct drm_file *filp)
+{
+       int i, r;
+       for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
+               uint32_t handle = atomic_read(&rdev->vce.handles[i]);
+               if (!handle || rdev->vce.filp[i] != filp)
+                       continue;
+
+               radeon_vce_note_usage(rdev);
+
+               r = radeon_vce_get_destroy_msg(rdev, TN_RING_TYPE_VCE1_INDEX,
+                                              handle, NULL);
+               if (r)
+                       DRM_ERROR("Error destroying VCE handle (%d)!\n", r);
+
+               rdev->vce.filp[i] = NULL;
+               atomic_set(&rdev->vce.handles[i], 0);
+       }
+}
+
+/**
+ * radeon_vce_get_create_msg - generate a VCE create msg
+ *
+ * @rdev: radeon_device pointer
+ * @ring: ring we should submit the msg to
+ * @handle: VCE session handle to use
+ * @fence: optional fence to return
+ *
+ * Open up a stream for HW test
+ */
+int radeon_vce_get_create_msg(struct radeon_device *rdev, int ring,
+                             uint32_t handle, struct radeon_fence **fence)
+{
+       const unsigned ib_size_dw = 1024;
+       struct radeon_ib ib;
+       uint64_t dummy;
+       int i, r;
+
+       r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4);
+       if (r) {
+               DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+               return r;
+       }
+
+       dummy = ib.gpu_addr + 1024;
+
+       /* stitch together an VCE create msg */
+       ib.length_dw = 0;
+       ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
+       ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
+       ib.ptr[ib.length_dw++] = handle;
+
+       ib.ptr[ib.length_dw++] = 0x00000030; /* len */
+       ib.ptr[ib.length_dw++] = 0x01000001; /* create cmd */
+       ib.ptr[ib.length_dw++] = 0x00000000;
+       ib.ptr[ib.length_dw++] = 0x00000042;
+       ib.ptr[ib.length_dw++] = 0x0000000a;
+       ib.ptr[ib.length_dw++] = 0x00000001;
+       ib.ptr[ib.length_dw++] = 0x00000080;
+       ib.ptr[ib.length_dw++] = 0x00000060;
+       ib.ptr[ib.length_dw++] = 0x00000100;
+       ib.ptr[ib.length_dw++] = 0x00000100;
+       ib.ptr[ib.length_dw++] = 0x0000000c;
+       ib.ptr[ib.length_dw++] = 0x00000000;
+
+       ib.ptr[ib.length_dw++] = 0x00000014; /* len */
+       ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
+       ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
+       ib.ptr[ib.length_dw++] = dummy;
+       ib.ptr[ib.length_dw++] = 0x00000001;
+
+       for (i = ib.length_dw; i < ib_size_dw; ++i)
+               ib.ptr[i] = 0x0;
+
+       r = radeon_ib_schedule(rdev, &ib, NULL);
+       if (r) {
+               DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
+       }
+
+       if (fence)
+               *fence = radeon_fence_ref(ib.fence);
+
+       radeon_ib_free(rdev, &ib);
+
+       return r;
+}
+
+/**
+ * radeon_vce_get_destroy_msg - generate a VCE destroy msg
+ *
+ * @rdev: radeon_device pointer
+ * @ring: ring we should submit the msg to
+ * @handle: VCE session handle to use
+ * @fence: optional fence to return
+ *
+ * Close up a stream for HW test or if userspace failed to do so
+ */
+int radeon_vce_get_destroy_msg(struct radeon_device *rdev, int ring,
+                              uint32_t handle, struct radeon_fence **fence)
+{
+       const unsigned ib_size_dw = 1024;
+       struct radeon_ib ib;
+       uint64_t dummy;
+       int i, r;
+
+       r = radeon_ib_get(rdev, ring, &ib, NULL, ib_size_dw * 4);
+       if (r) {
+               DRM_ERROR("radeon: failed to get ib (%d).\n", r);
+               return r;
+       }
+
+       dummy = ib.gpu_addr + 1024;
+
+       /* stitch together an VCE destroy msg */
+       ib.length_dw = 0;
+       ib.ptr[ib.length_dw++] = 0x0000000c; /* len */
+       ib.ptr[ib.length_dw++] = 0x00000001; /* session cmd */
+       ib.ptr[ib.length_dw++] = handle;
+
+       ib.ptr[ib.length_dw++] = 0x00000014; /* len */
+       ib.ptr[ib.length_dw++] = 0x05000005; /* feedback buffer */
+       ib.ptr[ib.length_dw++] = upper_32_bits(dummy);
+       ib.ptr[ib.length_dw++] = dummy;
+       ib.ptr[ib.length_dw++] = 0x00000001;
+
+       ib.ptr[ib.length_dw++] = 0x00000008; /* len */
+       ib.ptr[ib.length_dw++] = 0x02000001; /* destroy cmd */
+
+       for (i = ib.length_dw; i < ib_size_dw; ++i)
+               ib.ptr[i] = 0x0;
+
+       r = radeon_ib_schedule(rdev, &ib, NULL);
+       if (r) {
+               DRM_ERROR("radeon: failed to schedule ib (%d).\n", r);
+       }
+
+       if (fence)
+               *fence = radeon_fence_ref(ib.fence);
+
+       radeon_ib_free(rdev, &ib);
+
+       return r;
+}
+
+/**
+ * radeon_vce_cs_reloc - command submission relocation
+ *
+ * @p: parser context
+ * @lo: address of lower dword
+ * @hi: address of higher dword
+ *
+ * Patch relocation inside command stream with real buffer address
+ */
+int radeon_vce_cs_reloc(struct radeon_cs_parser *p, int lo, int hi)
+{
+       struct radeon_cs_chunk *relocs_chunk;
+       uint64_t offset;
+       unsigned idx;
+
+       relocs_chunk = &p->chunks[p->chunk_relocs_idx];
+       offset = radeon_get_ib_value(p, lo);
+       idx = radeon_get_ib_value(p, hi);
+
+       if (idx >= relocs_chunk->length_dw) {
+               DRM_ERROR("Relocs at %d after relocations chunk end %d !\n",
+                         idx, relocs_chunk->length_dw);
+               return -EINVAL;
+       }
+
+       offset += p->relocs_ptr[(idx / 4)]->gpu_offset;
+
+        p->ib.ptr[lo] = offset & 0xFFFFFFFF;
+        p->ib.ptr[hi] = offset >> 32;
+
+       return 0;
+}
+
+/**
+ * radeon_vce_cs_parse - parse and validate the command stream
+ *
+ * @p: parser context
+ *
+ */
+int radeon_vce_cs_parse(struct radeon_cs_parser *p)
+{
+       uint32_t handle = 0;
+       bool destroy = false;
+       int i, r;
+
+       while (p->idx < p->chunks[p->chunk_ib_idx].length_dw) {
+               uint32_t len = radeon_get_ib_value(p, p->idx);
+               uint32_t cmd = radeon_get_ib_value(p, p->idx + 1);
+
+               if ((len < 8) || (len & 3)) {
+                       DRM_ERROR("invalid VCE command length (%d)!\n", len);
+                       return -EINVAL;
+               }
+
+               switch (cmd) {
+               case 0x00000001: // session
+                       handle = radeon_get_ib_value(p, p->idx + 2);
+                       break;
+
+               case 0x00000002: // task info
+               case 0x01000001: // create
+               case 0x04000001: // config extension
+               case 0x04000002: // pic control
+               case 0x04000005: // rate control
+               case 0x04000007: // motion estimation
+               case 0x04000008: // rdo
+                       break;
+
+               case 0x03000001: // encode
+                       r = radeon_vce_cs_reloc(p, p->idx + 10, p->idx + 9);
+                       if (r)
+                               return r;
+
+                       r = radeon_vce_cs_reloc(p, p->idx + 12, p->idx + 11);
+                       if (r)
+                               return r;
+                       break;
+
+               case 0x02000001: // destroy
+                       destroy = true;
+                       break;
+
+               case 0x05000001: // context buffer
+               case 0x05000004: // video bitstream buffer
+               case 0x05000005: // feedback buffer
+                       r = radeon_vce_cs_reloc(p, p->idx + 3, p->idx + 2);
+                       if (r)
+                               return r;
+                       break;
+
+               default:
+                       DRM_ERROR("invalid VCE command (0x%x)!\n", cmd);
+                       return -EINVAL;
+               }
+
+               p->idx += len / 4;
+       }
+
+       if (destroy) {
+               /* IB contains a destroy msg, free the handle */
+               for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i)
+                       atomic_cmpxchg(&p->rdev->vce.handles[i], handle, 0);
+
+               return 0;
+        }
+
+       /* create or encode, validate the handle */
+       for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
+               if (atomic_read(&p->rdev->vce.handles[i]) == handle)
+                       return 0;
+       }
+
+       /* handle not found try to alloc a new one */
+       for (i = 0; i < RADEON_MAX_VCE_HANDLES; ++i) {
+               if (!atomic_cmpxchg(&p->rdev->vce.handles[i], 0, handle)) {
+                       p->rdev->vce.filp[i] = p->filp;
+                       return 0;
+               }
+       }
+
+       DRM_ERROR("No more free VCE handles!\n");
+       return -EINVAL;
+}
+
+/**
+ * radeon_vce_semaphore_emit - emit a semaphore command
+ *
+ * @rdev: radeon_device pointer
+ * @ring: engine to use
+ * @semaphore: address of semaphore
+ * @emit_wait: true=emit wait, false=emit signal
+ *
+ */
+bool radeon_vce_semaphore_emit(struct radeon_device *rdev,
+                              struct radeon_ring *ring,
+                              struct radeon_semaphore *semaphore,
+                              bool emit_wait)
+{
+       uint64_t addr = semaphore->gpu_addr;
+
+       radeon_ring_write(ring, VCE_CMD_SEMAPHORE);
+       radeon_ring_write(ring, (addr >> 3) & 0x000FFFFF);
+       radeon_ring_write(ring, (addr >> 23) & 0x000FFFFF);
+       radeon_ring_write(ring, 0x01003000 | (emit_wait ? 1 : 0));
+       if (!emit_wait)
+               radeon_ring_write(ring, VCE_CMD_END);
+
+       return true;
+}
+
+/**
+ * radeon_vce_ib_execute - execute indirect buffer
+ *
+ * @rdev: radeon_device pointer
+ * @ib: the IB to execute
+ *
+ */
+void radeon_vce_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
+{
+       struct radeon_ring *ring = &rdev->ring[ib->ring];
+       radeon_ring_write(ring, VCE_CMD_IB);
+       radeon_ring_write(ring, ib->gpu_addr);
+       radeon_ring_write(ring, upper_32_bits(ib->gpu_addr));
+       radeon_ring_write(ring, ib->length_dw);
+}
+
+/**
+ * radeon_vce_fence_emit - add a fence command to the ring
+ *
+ * @rdev: radeon_device pointer
+ * @fence: the fence
+ *
+ */
+void radeon_vce_fence_emit(struct radeon_device *rdev,
+                          struct radeon_fence *fence)
+{
+       struct radeon_ring *ring = &rdev->ring[fence->ring];
+       uint32_t addr = rdev->fence_drv[fence->ring].gpu_addr;
+
+       radeon_ring_write(ring, VCE_CMD_FENCE);
+       radeon_ring_write(ring, addr);
+       radeon_ring_write(ring, upper_32_bits(addr));
+       radeon_ring_write(ring, fence->seq);
+       radeon_ring_write(ring, VCE_CMD_TRAP);
+       radeon_ring_write(ring, VCE_CMD_END);
+}
+
+/**
+ * radeon_vce_ring_test - test if VCE ring is working
+ *
+ * @rdev: radeon_device pointer
+ * @ring: the engine to test on
+ *
+ */
+int radeon_vce_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+       uint32_t rptr = vce_v1_0_get_rptr(rdev, ring);
+       unsigned i;
+       int r;
+
+       r = radeon_ring_lock(rdev, ring, 16);
+       if (r) {
+               DRM_ERROR("radeon: vce failed to lock ring %d (%d).\n",
+                         ring->idx, r);
+               return r;
+       }
+       radeon_ring_write(ring, VCE_CMD_END);
+       radeon_ring_unlock_commit(rdev, ring);
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               if (vce_v1_0_get_rptr(rdev, ring) != rptr)
+                       break;
+               DRM_UDELAY(1);
+       }
+
+       if (i < rdev->usec_timeout) {
+               DRM_INFO("ring test on %d succeeded in %d usecs\n",
+                        ring->idx, i);
+       } else {
+               DRM_ERROR("radeon: ring %d test failed\n",
+                         ring->idx);
+               r = -ETIMEDOUT;
+       }
+
+       return r;
+}
+
+/**
+ * radeon_vce_ib_test - test if VCE IBs are working
+ *
+ * @rdev: radeon_device pointer
+ * @ring: the engine to test on
+ *
+ */
+int radeon_vce_ib_test(struct radeon_device *rdev, struct radeon_ring *ring)
+{
+       struct radeon_fence *fence = NULL;
+       int r;
+
+       r = radeon_vce_get_create_msg(rdev, ring->idx, 1, NULL);
+       if (r) {
+               DRM_ERROR("radeon: failed to get create msg (%d).\n", r);
+               goto error;
+       }
+
+       r = radeon_vce_get_destroy_msg(rdev, ring->idx, 1, &fence);
+       if (r) {
+               DRM_ERROR("radeon: failed to get destroy ib (%d).\n", r);
+               goto error;
+       }
+
+       r = radeon_fence_wait(fence, false);
+       if (r) {
+               DRM_ERROR("radeon: fence wait failed (%d).\n", r);
+       } else {
+               DRM_INFO("ib test on ring %d succeeded\n", ring->idx);
+       }
+error:
+       radeon_fence_unref(&fence);
+       return r;
+}
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
new file mode 100644 (file)
index 0000000..2aae6ce
--- /dev/null
@@ -0,0 +1,966 @@
+/*
+ * Copyright 2008 Advanced Micro Devices, Inc.
+ * Copyright 2008 Red Hat Inc.
+ * Copyright 2009 Jerome Glisse.
+ *
+ * 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.
+ *
+ * Authors: Dave Airlie
+ *          Alex Deucher
+ *          Jerome Glisse
+ */
+#include <drm/drmP.h>
+#include <drm/radeon_drm.h>
+#include "radeon.h"
+#include "radeon_trace.h"
+
+/*
+ * GPUVM
+ * GPUVM is similar to the legacy gart on older asics, however
+ * rather than there being a single global gart table
+ * for the entire GPU, there are multiple VM page tables active
+ * at any given time.  The VM page tables can contain a mix
+ * vram pages and system memory pages and system memory pages
+ * can be mapped as snooped (cached system pages) or unsnooped
+ * (uncached system pages).
+ * Each VM has an ID associated with it and there is a page table
+ * associated with each VMID.  When execting a command buffer,
+ * the kernel tells the the ring what VMID to use for that command
+ * buffer.  VMIDs are allocated dynamically as commands are submitted.
+ * The userspace drivers maintain their own address space and the kernel
+ * sets up their pages tables accordingly when they submit their
+ * command buffers and a VMID is assigned.
+ * Cayman/Trinity support up to 8 active VMs at any given time;
+ * SI supports 16.
+ */
+
+/**
+ * radeon_vm_num_pde - return the number of page directory entries
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Calculate the number of page directory entries (cayman+).
+ */
+static unsigned radeon_vm_num_pdes(struct radeon_device *rdev)
+{
+       return rdev->vm_manager.max_pfn >> RADEON_VM_BLOCK_SIZE;
+}
+
+/**
+ * radeon_vm_directory_size - returns the size of the page directory in bytes
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Calculate the size of the page directory in bytes (cayman+).
+ */
+static unsigned radeon_vm_directory_size(struct radeon_device *rdev)
+{
+       return RADEON_GPU_PAGE_ALIGN(radeon_vm_num_pdes(rdev) * 8);
+}
+
+/**
+ * radeon_vm_manager_init - init the vm manager
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Init the vm manager (cayman+).
+ * Returns 0 for success, error for failure.
+ */
+int radeon_vm_manager_init(struct radeon_device *rdev)
+{
+       int r;
+
+       if (!rdev->vm_manager.enabled) {
+               r = radeon_asic_vm_init(rdev);
+               if (r)
+                       return r;
+
+               rdev->vm_manager.enabled = true;
+       }
+       return 0;
+}
+
+/**
+ * radeon_vm_manager_fini - tear down the vm manager
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down the VM manager (cayman+).
+ */
+void radeon_vm_manager_fini(struct radeon_device *rdev)
+{
+       int i;
+
+       if (!rdev->vm_manager.enabled)
+               return;
+
+       for (i = 0; i < RADEON_NUM_VM; ++i)
+               radeon_fence_unref(&rdev->vm_manager.active[i]);
+       radeon_asic_vm_fini(rdev);
+       rdev->vm_manager.enabled = false;
+}
+
+/**
+ * radeon_vm_get_bos - add the vm BOs to a validation list
+ *
+ * @vm: vm providing the BOs
+ * @head: head of validation list
+ *
+ * Add the page directory to the list of BOs to
+ * validate for command submission (cayman+).
+ */
+struct radeon_cs_reloc *radeon_vm_get_bos(struct radeon_device *rdev,
+                                         struct radeon_vm *vm,
+                                         struct list_head *head)
+{
+       struct radeon_cs_reloc *list;
+       unsigned i, idx, size;
+
+       size = (radeon_vm_num_pdes(rdev) + 1) * sizeof(struct radeon_cs_reloc);
+       list = kmalloc(size, GFP_KERNEL);
+       if (!list)
+               return NULL;
+
+       /* add the vm page table to the list */
+       list[0].gobj = NULL;
+       list[0].robj = vm->page_directory;
+       list[0].domain = RADEON_GEM_DOMAIN_VRAM;
+       list[0].alt_domain = RADEON_GEM_DOMAIN_VRAM;
+       list[0].tv.bo = &vm->page_directory->tbo;
+       list[0].tiling_flags = 0;
+       list[0].handle = 0;
+       list_add(&list[0].tv.head, head);
+
+       for (i = 0, idx = 1; i <= vm->max_pde_used; i++) {
+               if (!vm->page_tables[i].bo)
+                       continue;
+
+               list[idx].gobj = NULL;
+               list[idx].robj = vm->page_tables[i].bo;
+               list[idx].domain = RADEON_GEM_DOMAIN_VRAM;
+               list[idx].alt_domain = RADEON_GEM_DOMAIN_VRAM;
+               list[idx].tv.bo = &list[idx].robj->tbo;
+               list[idx].tiling_flags = 0;
+               list[idx].handle = 0;
+               list_add(&list[idx++].tv.head, head);
+       }
+
+       return list;
+}
+
+/**
+ * radeon_vm_grab_id - allocate the next free VMID
+ *
+ * @rdev: radeon_device pointer
+ * @vm: vm to allocate id for
+ * @ring: ring we want to submit job to
+ *
+ * Allocate an id for the vm (cayman+).
+ * Returns the fence we need to sync to (if any).
+ *
+ * Global and local mutex must be locked!
+ */
+struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
+                                      struct radeon_vm *vm, int ring)
+{
+       struct radeon_fence *best[RADEON_NUM_RINGS] = {};
+       unsigned choices[2] = {};
+       unsigned i;
+
+       /* check if the id is still valid */
+       if (vm->last_id_use && vm->last_id_use == rdev->vm_manager.active[vm->id])
+               return NULL;
+
+       /* we definately need to flush */
+       radeon_fence_unref(&vm->last_flush);
+
+       /* skip over VMID 0, since it is the system VM */
+       for (i = 1; i < rdev->vm_manager.nvm; ++i) {
+               struct radeon_fence *fence = rdev->vm_manager.active[i];
+
+               if (fence == NULL) {
+                       /* found a free one */
+                       vm->id = i;
+                       trace_radeon_vm_grab_id(vm->id, ring);
+                       return NULL;
+               }
+
+               if (radeon_fence_is_earlier(fence, best[fence->ring])) {
+                       best[fence->ring] = fence;
+                       choices[fence->ring == ring ? 0 : 1] = i;
+               }
+       }
+
+       for (i = 0; i < 2; ++i) {
+               if (choices[i]) {
+                       vm->id = choices[i];
+                       trace_radeon_vm_grab_id(vm->id, ring);
+                       return rdev->vm_manager.active[choices[i]];
+               }
+       }
+
+       /* should never happen */
+       BUG();
+       return NULL;
+}
+
+/**
+ * radeon_vm_flush - hardware flush the vm
+ *
+ * @rdev: radeon_device pointer
+ * @vm: vm we want to flush
+ * @ring: ring to use for flush
+ *
+ * Flush the vm (cayman+).
+ *
+ * Global and local mutex must be locked!
+ */
+void radeon_vm_flush(struct radeon_device *rdev,
+                    struct radeon_vm *vm,
+                    int ring)
+{
+       uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory);
+
+       /* if we can't remember our last VM flush then flush now! */
+       /* XXX figure out why we have to flush all the time */
+       if (!vm->last_flush || true || pd_addr != vm->pd_gpu_addr) {
+               vm->pd_gpu_addr = pd_addr;
+               radeon_ring_vm_flush(rdev, ring, vm);
+       }
+}
+
+/**
+ * radeon_vm_fence - remember fence for vm
+ *
+ * @rdev: radeon_device pointer
+ * @vm: vm we want to fence
+ * @fence: fence to remember
+ *
+ * Fence the vm (cayman+).
+ * Set the fence used to protect page table and id.
+ *
+ * Global and local mutex must be locked!
+ */
+void radeon_vm_fence(struct radeon_device *rdev,
+                    struct radeon_vm *vm,
+                    struct radeon_fence *fence)
+{
+       radeon_fence_unref(&vm->fence);
+       vm->fence = radeon_fence_ref(fence);
+
+       radeon_fence_unref(&rdev->vm_manager.active[vm->id]);
+       rdev->vm_manager.active[vm->id] = radeon_fence_ref(fence);
+
+       radeon_fence_unref(&vm->last_id_use);
+       vm->last_id_use = radeon_fence_ref(fence);
+
+        /* we just flushed the VM, remember that */
+        if (!vm->last_flush)
+                vm->last_flush = radeon_fence_ref(fence);
+}
+
+/**
+ * radeon_vm_bo_find - find the bo_va for a specific vm & bo
+ *
+ * @vm: requested vm
+ * @bo: requested buffer object
+ *
+ * Find @bo inside the requested vm (cayman+).
+ * Search inside the @bos vm list for the requested vm
+ * Returns the found bo_va or NULL if none is found
+ *
+ * Object has to be reserved!
+ */
+struct radeon_bo_va *radeon_vm_bo_find(struct radeon_vm *vm,
+                                      struct radeon_bo *bo)
+{
+       struct radeon_bo_va *bo_va;
+
+       list_for_each_entry(bo_va, &bo->va, bo_list) {
+               if (bo_va->vm == vm) {
+                       return bo_va;
+               }
+       }
+       return NULL;
+}
+
+/**
+ * radeon_vm_bo_add - add a bo to a specific vm
+ *
+ * @rdev: radeon_device pointer
+ * @vm: requested vm
+ * @bo: radeon buffer object
+ *
+ * Add @bo into the requested vm (cayman+).
+ * Add @bo to the list of bos associated with the vm
+ * Returns newly added bo_va or NULL for failure
+ *
+ * Object has to be reserved!
+ */
+struct radeon_bo_va *radeon_vm_bo_add(struct radeon_device *rdev,
+                                     struct radeon_vm *vm,
+                                     struct radeon_bo *bo)
+{
+       struct radeon_bo_va *bo_va;
+
+       bo_va = kzalloc(sizeof(struct radeon_bo_va), GFP_KERNEL);
+       if (bo_va == NULL) {
+               return NULL;
+       }
+       bo_va->vm = vm;
+       bo_va->bo = bo;
+       bo_va->soffset = 0;
+       bo_va->eoffset = 0;
+       bo_va->flags = 0;
+       bo_va->valid = false;
+       bo_va->ref_count = 1;
+       INIT_LIST_HEAD(&bo_va->bo_list);
+       INIT_LIST_HEAD(&bo_va->vm_list);
+
+       mutex_lock(&vm->mutex);
+       list_add(&bo_va->vm_list, &vm->va);
+       list_add_tail(&bo_va->bo_list, &bo->va);
+       mutex_unlock(&vm->mutex);
+
+       return bo_va;
+}
+
+/**
+ * radeon_vm_clear_bo - initially clear the page dir/table
+ *
+ * @rdev: radeon_device pointer
+ * @bo: bo to clear
+ */
+static int radeon_vm_clear_bo(struct radeon_device *rdev,
+                             struct radeon_bo *bo)
+{
+        struct ttm_validate_buffer tv;
+        struct ww_acquire_ctx ticket;
+        struct list_head head;
+       struct radeon_ib ib;
+       unsigned entries;
+       uint64_t addr;
+       int r;
+
+        memset(&tv, 0, sizeof(tv));
+        tv.bo = &bo->tbo;
+
+        INIT_LIST_HEAD(&head);
+        list_add(&tv.head, &head);
+
+        r = ttm_eu_reserve_buffers(&ticket, &head);
+        if (r)
+               return r;
+
+        r = ttm_bo_validate(&bo->tbo, &bo->placement, true, false);
+        if (r)
+                goto error;
+
+       addr = radeon_bo_gpu_offset(bo);
+       entries = radeon_bo_size(bo) / 8;
+
+       r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib,
+                         NULL, entries * 2 + 64);
+       if (r)
+                goto error;
+
+       ib.length_dw = 0;
+
+       radeon_asic_vm_set_page(rdev, &ib, addr, 0, entries, 0, 0);
+
+       r = radeon_ib_schedule(rdev, &ib, NULL);
+       if (r)
+                goto error;
+
+       ttm_eu_fence_buffer_objects(&ticket, &head, ib.fence);
+       radeon_ib_free(rdev, &ib);
+
+       return 0;
+
+error:
+       ttm_eu_backoff_reservation(&ticket, &head);
+       return r;
+}
+
+/**
+ * radeon_vm_bo_set_addr - set bos virtual address inside a vm
+ *
+ * @rdev: radeon_device pointer
+ * @bo_va: bo_va to store the address
+ * @soffset: requested offset of the buffer in the VM address space
+ * @flags: attributes of pages (read/write/valid/etc.)
+ *
+ * Set offset of @bo_va (cayman+).
+ * Validate and set the offset requested within the vm address space.
+ * Returns 0 for success, error for failure.
+ *
+ * Object has to be reserved!
+ */
+int radeon_vm_bo_set_addr(struct radeon_device *rdev,
+                         struct radeon_bo_va *bo_va,
+                         uint64_t soffset,
+                         uint32_t flags)
+{
+       uint64_t size = radeon_bo_size(bo_va->bo);
+       uint64_t eoffset, last_offset = 0;
+       struct radeon_vm *vm = bo_va->vm;
+       struct radeon_bo_va *tmp;
+       struct list_head *head;
+       unsigned last_pfn, pt_idx;
+       int r;
+
+       if (soffset) {
+               /* make sure object fit at this offset */
+               eoffset = soffset + size;
+               if (soffset >= eoffset) {
+                       return -EINVAL;
+               }
+
+               last_pfn = eoffset / RADEON_GPU_PAGE_SIZE;
+               if (last_pfn > rdev->vm_manager.max_pfn) {
+                       dev_err(rdev->dev, "va above limit (0x%08X > 0x%08X)\n",
+                               last_pfn, rdev->vm_manager.max_pfn);
+                       return -EINVAL;
+               }
+
+       } else {
+               eoffset = last_pfn = 0;
+       }
+
+       mutex_lock(&vm->mutex);
+       head = &vm->va;
+       last_offset = 0;
+       list_for_each_entry(tmp, &vm->va, vm_list) {
+               if (bo_va == tmp) {
+                       /* skip over currently modified bo */
+                       continue;
+               }
+
+               if (soffset >= last_offset && eoffset <= tmp->soffset) {
+                       /* bo can be added before this one */
+                       break;
+               }
+               if (eoffset > tmp->soffset && soffset < tmp->eoffset) {
+                       /* bo and tmp overlap, invalid offset */
+                       dev_err(rdev->dev, "bo %p va 0x%08X conflict with (bo %p 0x%08X 0x%08X)\n",
+                               bo_va->bo, (unsigned)bo_va->soffset, tmp->bo,
+                               (unsigned)tmp->soffset, (unsigned)tmp->eoffset);
+                       mutex_unlock(&vm->mutex);
+                       return -EINVAL;
+               }
+               last_offset = tmp->eoffset;
+               head = &tmp->vm_list;
+       }
+
+       bo_va->soffset = soffset;
+       bo_va->eoffset = eoffset;
+       bo_va->flags = flags;
+       bo_va->valid = false;
+       list_move(&bo_va->vm_list, head);
+
+       soffset = (soffset / RADEON_GPU_PAGE_SIZE) >> RADEON_VM_BLOCK_SIZE;
+       eoffset = (eoffset / RADEON_GPU_PAGE_SIZE) >> RADEON_VM_BLOCK_SIZE;
+
+       if (eoffset > vm->max_pde_used)
+               vm->max_pde_used = eoffset;
+
+       radeon_bo_unreserve(bo_va->bo);
+
+       /* walk over the address space and allocate the page tables */
+       for (pt_idx = soffset; pt_idx <= eoffset; ++pt_idx) {
+               struct radeon_bo *pt;
+
+               if (vm->page_tables[pt_idx].bo)
+                       continue;
+
+               /* drop mutex to allocate and clear page table */
+               mutex_unlock(&vm->mutex);
+
+               r = radeon_bo_create(rdev, RADEON_VM_PTE_COUNT * 8,
+                                    RADEON_GPU_PAGE_SIZE, false, 
+                                    RADEON_GEM_DOMAIN_VRAM, NULL, &pt);
+               if (r)
+                       return r;
+
+               r = radeon_vm_clear_bo(rdev, pt);
+               if (r) {
+                       radeon_bo_unref(&pt);
+                       radeon_bo_reserve(bo_va->bo, false);
+                       return r;
+               }
+
+               /* aquire mutex again */
+               mutex_lock(&vm->mutex);
+               if (vm->page_tables[pt_idx].bo) {
+                       /* someone else allocated the pt in the meantime */
+                       mutex_unlock(&vm->mutex);
+                       radeon_bo_unref(&pt);
+                       mutex_lock(&vm->mutex);
+                       continue;
+               }
+
+               vm->page_tables[pt_idx].addr = 0;
+               vm->page_tables[pt_idx].bo = pt;
+       }
+
+       mutex_unlock(&vm->mutex);
+       return radeon_bo_reserve(bo_va->bo, false);
+}
+
+/**
+ * radeon_vm_map_gart - get the physical address of a gart page
+ *
+ * @rdev: radeon_device pointer
+ * @addr: the unmapped addr
+ *
+ * Look up the physical address of the page that the pte resolves
+ * to (cayman+).
+ * Returns the physical address of the page.
+ */
+uint64_t radeon_vm_map_gart(struct radeon_device *rdev, uint64_t addr)
+{
+       uint64_t result;
+
+       /* page table offset */
+       result = rdev->gart.pages_addr[addr >> PAGE_SHIFT];
+
+       /* in case cpu page size != gpu page size*/
+       result |= addr & (~PAGE_MASK);
+
+       return result;
+}
+
+/**
+ * radeon_vm_page_flags - translate page flags to what the hw uses
+ *
+ * @flags: flags comming from userspace
+ *
+ * Translate the flags the userspace ABI uses to hw flags.
+ */
+static uint32_t radeon_vm_page_flags(uint32_t flags)
+{
+        uint32_t hw_flags = 0;
+        hw_flags |= (flags & RADEON_VM_PAGE_VALID) ? R600_PTE_VALID : 0;
+        hw_flags |= (flags & RADEON_VM_PAGE_READABLE) ? R600_PTE_READABLE : 0;
+        hw_flags |= (flags & RADEON_VM_PAGE_WRITEABLE) ? R600_PTE_WRITEABLE : 0;
+        if (flags & RADEON_VM_PAGE_SYSTEM) {
+                hw_flags |= R600_PTE_SYSTEM;
+                hw_flags |= (flags & RADEON_VM_PAGE_SNOOPED) ? R600_PTE_SNOOPED : 0;
+        }
+        return hw_flags;
+}
+
+/**
+ * radeon_vm_update_pdes - make sure that page directory is valid
+ *
+ * @rdev: radeon_device pointer
+ * @vm: requested vm
+ * @start: start of GPU address range
+ * @end: end of GPU address range
+ *
+ * Allocates new page tables if necessary
+ * and updates the page directory (cayman+).
+ * Returns 0 for success, error for failure.
+ *
+ * Global and local mutex must be locked!
+ */
+int radeon_vm_update_page_directory(struct radeon_device *rdev,
+                                   struct radeon_vm *vm)
+{
+       static const uint32_t incr = RADEON_VM_PTE_COUNT * 8;
+
+       uint64_t pd_addr = radeon_bo_gpu_offset(vm->page_directory);
+       uint64_t last_pde = ~0, last_pt = ~0;
+       unsigned count = 0, pt_idx, ndw;
+       struct radeon_ib ib;
+       int r;
+
+       /* padding, etc. */
+       ndw = 64;
+
+       /* assume the worst case */
+       ndw += vm->max_pde_used * 12;
+
+       /* update too big for an IB */
+       if (ndw > 0xfffff)
+               return -ENOMEM;
+
+       r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, ndw * 4);
+       if (r)
+               return r;
+       ib.length_dw = 0;
+
+       /* walk over the address space and update the page directory */
+       for (pt_idx = 0; pt_idx <= vm->max_pde_used; ++pt_idx) {
+               struct radeon_bo *bo = vm->page_tables[pt_idx].bo;
+               uint64_t pde, pt;
+
+               if (bo == NULL)
+                       continue;
+
+               pt = radeon_bo_gpu_offset(bo);
+               if (vm->page_tables[pt_idx].addr == pt)
+                       continue;
+               vm->page_tables[pt_idx].addr = pt;
+
+               pde = pd_addr + pt_idx * 8;
+               if (((last_pde + 8 * count) != pde) ||
+                   ((last_pt + incr * count) != pt)) {
+
+                       if (count) {
+                               radeon_asic_vm_set_page(rdev, &ib, last_pde,
+                                                       last_pt, count, incr,
+                                                       R600_PTE_VALID);
+                       }
+
+                       count = 1;
+                       last_pde = pde;
+                       last_pt = pt;
+               } else {
+                       ++count;
+               }
+       }
+
+       if (count)
+               radeon_asic_vm_set_page(rdev, &ib, last_pde, last_pt, count,
+                                       incr, R600_PTE_VALID);
+
+       if (ib.length_dw != 0) {
+               radeon_semaphore_sync_to(ib.semaphore, vm->last_id_use);
+               r = radeon_ib_schedule(rdev, &ib, NULL);
+               if (r) {
+                       radeon_ib_free(rdev, &ib);
+                       return r;
+               }
+               radeon_fence_unref(&vm->fence);
+               vm->fence = radeon_fence_ref(ib.fence);
+               radeon_fence_unref(&vm->last_flush);
+       }
+       radeon_ib_free(rdev, &ib);
+
+       return 0;
+}
+
+/**
+ * radeon_vm_update_ptes - make sure that page tables are valid
+ *
+ * @rdev: radeon_device pointer
+ * @vm: requested vm
+ * @start: start of GPU address range
+ * @end: end of GPU address range
+ * @dst: destination address to map to
+ * @flags: mapping flags
+ *
+ * Update the page tables in the range @start - @end (cayman+).
+ *
+ * Global and local mutex must be locked!
+ */
+static void radeon_vm_update_ptes(struct radeon_device *rdev,
+                                 struct radeon_vm *vm,
+                                 struct radeon_ib *ib,
+                                 uint64_t start, uint64_t end,
+                                 uint64_t dst, uint32_t flags)
+{
+       static const uint64_t mask = RADEON_VM_PTE_COUNT - 1;
+
+       uint64_t last_pte = ~0, last_dst = ~0;
+       unsigned count = 0;
+       uint64_t addr;
+
+       start = start / RADEON_GPU_PAGE_SIZE;
+       end = end / RADEON_GPU_PAGE_SIZE;
+
+       /* walk over the address space and update the page tables */
+       for (addr = start; addr < end; ) {
+               uint64_t pt_idx = addr >> RADEON_VM_BLOCK_SIZE;
+               unsigned nptes;
+               uint64_t pte;
+
+               if ((addr & ~mask) == (end & ~mask))
+                       nptes = end - addr;
+               else
+                       nptes = RADEON_VM_PTE_COUNT - (addr & mask);
+
+               pte = radeon_bo_gpu_offset(vm->page_tables[pt_idx].bo);
+               pte += (addr & mask) * 8;
+
+               if ((last_pte + 8 * count) != pte) {
+
+                       if (count) {
+                               radeon_asic_vm_set_page(rdev, ib, last_pte,
+                                                       last_dst, count,
+                                                       RADEON_GPU_PAGE_SIZE,
+                                                       flags);
+                       }
+
+                       count = nptes;
+                       last_pte = pte;
+                       last_dst = dst;
+               } else {
+                       count += nptes;
+               }
+
+               addr += nptes;
+               dst += nptes * RADEON_GPU_PAGE_SIZE;
+       }
+
+       if (count) {
+               radeon_asic_vm_set_page(rdev, ib, last_pte,
+                                       last_dst, count,
+                                       RADEON_GPU_PAGE_SIZE, flags);
+       }
+}
+
+/**
+ * radeon_vm_bo_update - map a bo into the vm page table
+ *
+ * @rdev: radeon_device pointer
+ * @vm: requested vm
+ * @bo: radeon buffer object
+ * @mem: ttm mem
+ *
+ * Fill in the page table entries for @bo (cayman+).
+ * Returns 0 for success, -EINVAL for failure.
+ *
+ * Object have to be reserved and mutex must be locked!
+ */
+int radeon_vm_bo_update(struct radeon_device *rdev,
+                       struct radeon_vm *vm,
+                       struct radeon_bo *bo,
+                       struct ttm_mem_reg *mem)
+{
+       struct radeon_ib ib;
+       struct radeon_bo_va *bo_va;
+       unsigned nptes, ndw;
+       uint64_t addr;
+       int r;
+
+       bo_va = radeon_vm_bo_find(vm, bo);
+       if (bo_va == NULL) {
+               dev_err(rdev->dev, "bo %p not in vm %p\n", bo, vm);
+               return -EINVAL;
+       }
+
+       if (!bo_va->soffset) {
+               dev_err(rdev->dev, "bo %p don't has a mapping in vm %p\n",
+                       bo, vm);
+               return -EINVAL;
+       }
+
+       if ((bo_va->valid && mem) || (!bo_va->valid && mem == NULL))
+               return 0;
+
+       bo_va->flags &= ~RADEON_VM_PAGE_VALID;
+       bo_va->flags &= ~RADEON_VM_PAGE_SYSTEM;
+       if (mem) {
+               addr = mem->start << PAGE_SHIFT;
+               if (mem->mem_type != TTM_PL_SYSTEM) {
+                       bo_va->flags |= RADEON_VM_PAGE_VALID;
+                       bo_va->valid = true;
+               }
+               if (mem->mem_type == TTM_PL_TT) {
+                       bo_va->flags |= RADEON_VM_PAGE_SYSTEM;
+               } else {
+                       addr += rdev->vm_manager.vram_base_offset;
+               }
+       } else {
+               addr = 0;
+               bo_va->valid = false;
+       }
+
+       trace_radeon_vm_bo_update(bo_va);
+
+       nptes = radeon_bo_ngpu_pages(bo);
+
+       /* padding, etc. */
+       ndw = 64;
+
+       if (RADEON_VM_BLOCK_SIZE > 11)
+               /* reserve space for one header for every 2k dwords */
+               ndw += (nptes >> 11) * 4;
+       else
+               /* reserve space for one header for
+                   every (1 << BLOCK_SIZE) entries */
+               ndw += (nptes >> RADEON_VM_BLOCK_SIZE) * 4;
+
+       /* reserve space for pte addresses */
+       ndw += nptes * 2;
+
+       /* update too big for an IB */
+       if (ndw > 0xfffff)
+               return -ENOMEM;
+
+       r = radeon_ib_get(rdev, R600_RING_TYPE_DMA_INDEX, &ib, NULL, ndw * 4);
+       if (r)
+               return r;
+       ib.length_dw = 0;
+
+       radeon_vm_update_ptes(rdev, vm, &ib, bo_va->soffset, bo_va->eoffset,
+                             addr, radeon_vm_page_flags(bo_va->flags));
+
+       radeon_semaphore_sync_to(ib.semaphore, vm->fence);
+       r = radeon_ib_schedule(rdev, &ib, NULL);
+       if (r) {
+               radeon_ib_free(rdev, &ib);
+               return r;
+       }
+       radeon_fence_unref(&vm->fence);
+       vm->fence = radeon_fence_ref(ib.fence);
+       radeon_ib_free(rdev, &ib);
+       radeon_fence_unref(&vm->last_flush);
+
+       return 0;
+}
+
+/**
+ * radeon_vm_bo_rmv - remove a bo to a specific vm
+ *
+ * @rdev: radeon_device pointer
+ * @bo_va: requested bo_va
+ *
+ * Remove @bo_va->bo from the requested vm (cayman+).
+ * Remove @bo_va->bo from the list of bos associated with the bo_va->vm and
+ * remove the ptes for @bo_va in the page table.
+ * Returns 0 for success.
+ *
+ * Object have to be reserved!
+ */
+int radeon_vm_bo_rmv(struct radeon_device *rdev,
+                    struct radeon_bo_va *bo_va)
+{
+       int r = 0;
+
+       mutex_lock(&bo_va->vm->mutex);
+       if (bo_va->soffset)
+               r = radeon_vm_bo_update(rdev, bo_va->vm, bo_va->bo, NULL);
+
+       list_del(&bo_va->vm_list);
+       mutex_unlock(&bo_va->vm->mutex);
+       list_del(&bo_va->bo_list);
+
+       kfree(bo_va);
+       return r;
+}
+
+/**
+ * radeon_vm_bo_invalidate - mark the bo as invalid
+ *
+ * @rdev: radeon_device pointer
+ * @vm: requested vm
+ * @bo: radeon buffer object
+ *
+ * Mark @bo as invalid (cayman+).
+ */
+void radeon_vm_bo_invalidate(struct radeon_device *rdev,
+                            struct radeon_bo *bo)
+{
+       struct radeon_bo_va *bo_va;
+
+       list_for_each_entry(bo_va, &bo->va, bo_list) {
+               bo_va->valid = false;
+       }
+}
+
+/**
+ * radeon_vm_init - initialize a vm instance
+ *
+ * @rdev: radeon_device pointer
+ * @vm: requested vm
+ *
+ * Init @vm fields (cayman+).
+ */
+int radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
+{
+       unsigned pd_size, pd_entries, pts_size;
+       int r;
+
+       vm->id = 0;
+       vm->fence = NULL;
+       vm->last_flush = NULL;
+       vm->last_id_use = NULL;
+       mutex_init(&vm->mutex);
+       INIT_LIST_HEAD(&vm->va);
+
+       pd_size = radeon_vm_directory_size(rdev);
+       pd_entries = radeon_vm_num_pdes(rdev);
+
+       /* allocate page table array */
+       pts_size = pd_entries * sizeof(struct radeon_vm_pt);
+       vm->page_tables = kzalloc(pts_size, GFP_KERNEL);
+       if (vm->page_tables == NULL) {
+               DRM_ERROR("Cannot allocate memory for page table array\n");
+               return -ENOMEM;
+       }
+
+       r = radeon_bo_create(rdev, pd_size, RADEON_VM_PTB_ALIGN_SIZE, false,
+                            RADEON_GEM_DOMAIN_VRAM, NULL,
+                            &vm->page_directory);
+       if (r)
+               return r;
+
+       r = radeon_vm_clear_bo(rdev, vm->page_directory);
+       if (r) {
+               radeon_bo_unref(&vm->page_directory);
+               vm->page_directory = NULL;
+               return r;
+       }
+
+       return 0;
+}
+
+/**
+ * radeon_vm_fini - tear down a vm instance
+ *
+ * @rdev: radeon_device pointer
+ * @vm: requested vm
+ *
+ * Tear down @vm (cayman+).
+ * Unbind the VM and remove all bos from the vm bo list
+ */
+void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
+{
+       struct radeon_bo_va *bo_va, *tmp;
+       int i, r;
+
+       if (!list_empty(&vm->va)) {
+               dev_err(rdev->dev, "still active bo inside vm\n");
+       }
+       list_for_each_entry_safe(bo_va, tmp, &vm->va, vm_list) {
+               list_del_init(&bo_va->vm_list);
+               r = radeon_bo_reserve(bo_va->bo, false);
+               if (!r) {
+                       list_del_init(&bo_va->bo_list);
+                       radeon_bo_unreserve(bo_va->bo);
+                       kfree(bo_va);
+               }
+       }
+
+
+       for (i = 0; i < radeon_vm_num_pdes(rdev); i++)
+               radeon_bo_unref(&vm->page_tables[i].bo);
+       kfree(vm->page_tables);
+
+       radeon_bo_unref(&vm->page_directory);
+
+       radeon_fence_unref(&vm->fence);
+       radeon_fence_unref(&vm->last_flush);
+       radeon_fence_unref(&vm->last_id_use);
+
+       mutex_destroy(&vm->mutex);
+}
index 8512085..02f7710 100644 (file)
@@ -807,9 +807,6 @@ static int rs780_parse_power_table(struct radeon_device *rdev)
                                  power_info->pplib.ucNumStates, GFP_KERNEL);
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
 
        for (i = 0; i < power_info->pplib.ucNumStates; i++) {
                power_state = (union pplib_power_state *)
@@ -859,6 +856,10 @@ int rs780_dpm_init(struct radeon_device *rdev)
                return -ENOMEM;
        rdev->pm.dpm.priv = pi;
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = rs780_parse_power_table(rdev);
        if (ret)
                return ret;
index bebf31c..e7045b0 100644 (file)
@@ -1891,9 +1891,6 @@ static int rv6xx_parse_power_table(struct radeon_device *rdev)
                                  power_info->pplib.ucNumStates, GFP_KERNEL);
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
 
        for (i = 0; i < power_info->pplib.ucNumStates; i++) {
                power_state = (union pplib_power_state *)
@@ -1943,6 +1940,10 @@ int rv6xx_dpm_init(struct radeon_device *rdev)
                return -ENOMEM;
        rdev->pm.dpm.priv = pi;
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = rv6xx_parse_power_table(rdev);
        if (ret)
                return ret;
index b5f63f5..da041a4 100644 (file)
@@ -2281,9 +2281,6 @@ int rv7xx_parse_power_table(struct radeon_device *rdev)
                                  power_info->pplib.ucNumStates, GFP_KERNEL);
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
 
        for (i = 0; i < power_info->pplib.ucNumStates; i++) {
                power_state = (union pplib_power_state *)
@@ -2361,6 +2358,10 @@ int rv770_dpm_init(struct radeon_device *rdev)
        pi->min_vddc_in_table = 0;
        pi->max_vddc_in_table = 0;
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = rv7xx_parse_power_table(rdev);
        if (ret)
                return ret;
index 9a124d0..d589475 100644 (file)
@@ -3434,8 +3434,6 @@ static int si_cp_resume(struct radeon_device *rdev)
 
        WREG32(CP_RB0_BASE, ring->gpu_addr >> 8);
 
-       ring->rptr = RREG32(CP_RB0_RPTR);
-
        /* ring1  - compute only */
        /* Set ring buffer size */
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
@@ -3460,8 +3458,6 @@ static int si_cp_resume(struct radeon_device *rdev)
 
        WREG32(CP_RB1_BASE, ring->gpu_addr >> 8);
 
-       ring->rptr = RREG32(CP_RB1_RPTR);
-
        /* ring2 - compute only */
        /* Set ring buffer size */
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
@@ -3486,8 +3482,6 @@ static int si_cp_resume(struct radeon_device *rdev)
 
        WREG32(CP_RB2_BASE, ring->gpu_addr >> 8);
 
-       ring->rptr = RREG32(CP_RB2_RPTR);
-
        /* start the rings */
        si_cp_start(rdev);
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = true;
@@ -3872,11 +3866,9 @@ bool si_gfx_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
        if (!(reset_mask & (RADEON_RESET_GFX |
                            RADEON_RESET_COMPUTE |
                            RADEON_RESET_CP))) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force CP activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
index 59be2cf..cf0fdad 100644 (file)
@@ -49,11 +49,9 @@ bool si_dma_is_lockup(struct radeon_device *rdev, struct radeon_ring *ring)
                mask = RADEON_RESET_DMA1;
 
        if (!(reset_mask & mask)) {
-               radeon_ring_lockup_update(ring);
+               radeon_ring_lockup_update(rdev, ring);
                return false;
        }
-       /* force ring activities */
-       radeon_ring_force_activity(rdev, ring);
        return radeon_ring_test_lockup(rdev, ring);
 }
 
index 0a2f5b4..9a3567b 100644 (file)
@@ -6271,9 +6271,6 @@ static int si_parse_power_table(struct radeon_device *rdev)
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
        power_state_offset = (u8 *)state_array->states;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
        for (i = 0; i < state_array->ucNumEntries; i++) {
                u8 *idx;
                power_state = (union pplib_power_state *)power_state_offset;
@@ -6350,6 +6347,10 @@ int si_dpm_init(struct radeon_device *rdev)
        pi->min_vddc_in_table = 0;
        pi->max_vddc_in_table = 0;
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = si_parse_power_table(rdev);
        if (ret)
                return ret;
index 9239a6d..683532f 100644 (file)
 #define        DMA_PACKET_CONSTANT_FILL                          0xd
 #define        DMA_PACKET_NOP                                    0xf
 
+#define VCE_STATUS                                     0x20004
+#define VCE_VCPU_CNTL                                  0x20014
+#define                VCE_CLK_EN                              (1 << 0)
+#define VCE_VCPU_CACHE_OFFSET0                         0x20024
+#define VCE_VCPU_CACHE_SIZE0                           0x20028
+#define VCE_VCPU_CACHE_OFFSET1                         0x2002c
+#define VCE_VCPU_CACHE_SIZE1                           0x20030
+#define VCE_VCPU_CACHE_OFFSET2                         0x20034
+#define VCE_VCPU_CACHE_SIZE2                           0x20038
+#define VCE_SOFT_RESET                                 0x20120
+#define        VCE_ECPU_SOFT_RESET                     (1 << 0)
+#define        VCE_FME_SOFT_RESET                      (1 << 2)
+#define VCE_RB_BASE_LO2                                        0x2016c
+#define VCE_RB_BASE_HI2                                        0x20170
+#define VCE_RB_SIZE2                                   0x20174
+#define VCE_RB_RPTR2                                   0x20178
+#define VCE_RB_WPTR2                                   0x2017c
+#define VCE_RB_BASE_LO                                 0x20180
+#define VCE_RB_BASE_HI                                 0x20184
+#define VCE_RB_SIZE                                    0x20188
+#define VCE_RB_RPTR                                    0x2018c
+#define VCE_RB_WPTR                                    0x20190
+#define VCE_CLOCK_GATING_A                             0x202f8
+#define VCE_CLOCK_GATING_B                             0x202fc
+#define VCE_UENC_CLOCK_GATING                          0x205bc
+#define VCE_UENC_REG_CLOCK_GATING                      0x205c0
+#define VCE_FW_REG_STATUS                              0x20e10
+#      define VCE_FW_REG_STATUS_BUSY                   (1 << 0)
+#      define VCE_FW_REG_STATUS_PASS                   (1 << 3)
+#      define VCE_FW_REG_STATUS_DONE                   (1 << 11)
+#define VCE_LMI_FW_START_KEYSEL                                0x20e18
+#define VCE_LMI_FW_PERIODIC_CTRL                       0x20e20
+#define VCE_LMI_CTRL2                                  0x20e74
+#define VCE_LMI_CTRL                                   0x20e98
+#define VCE_LMI_VM_CTRL                                        0x20ea0
+#define VCE_LMI_SWAP_CNTL                              0x20eb4
+#define VCE_LMI_SWAP_CNTL1                             0x20eb8
+#define VCE_LMI_CACHE_CTRL                             0x20ef4
+
+#define VCE_CMD_NO_OP                                  0x00000000
+#define VCE_CMD_END                                    0x00000001
+#define VCE_CMD_IB                                     0x00000002
+#define VCE_CMD_FENCE                                  0x00000003
+#define VCE_CMD_TRAP                                   0x00000004
+#define VCE_CMD_IB_AUTO                                        0x00000005
+#define VCE_CMD_SEMAPHORE                              0x00000006
+
 #endif
index 8b47b3c..3f0e8d7 100644 (file)
@@ -1484,9 +1484,6 @@ static int sumo_parse_power_table(struct radeon_device *rdev)
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
        power_state_offset = (u8 *)state_array->states;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
        for (i = 0; i < state_array->ucNumEntries; i++) {
                u8 *idx;
                power_state = (union pplib_power_state *)power_state_offset;
@@ -1772,6 +1769,10 @@ int sumo_dpm_init(struct radeon_device *rdev)
 
        sumo_construct_boot_and_acpi_state(rdev);
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = sumo_parse_power_table(rdev);
        if (ret)
                return ret;
index 2da0e17..2a2822c 100644 (file)
@@ -1694,9 +1694,6 @@ static int trinity_parse_power_table(struct radeon_device *rdev)
        if (!rdev->pm.dpm.ps)
                return -ENOMEM;
        power_state_offset = (u8 *)state_array->states;
-       rdev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
-       rdev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
-       rdev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
        for (i = 0; i < state_array->ucNumEntries; i++) {
                u8 *idx;
                power_state = (union pplib_power_state *)power_state_offset;
@@ -1895,6 +1892,10 @@ int trinity_dpm_init(struct radeon_device *rdev)
 
        trinity_construct_boot_state(rdev);
 
+       ret = r600_get_platform_caps(rdev);
+       if (ret)
+               return ret;
+
        ret = trinity_parse_power_table(rdev);
        if (ret)
                return ret;
index d4a68af..0a243f0 100644 (file)
@@ -262,7 +262,7 @@ int uvd_v1_0_start(struct radeon_device *rdev)
        /* Initialize the ring buffer's read and write pointers */
        WREG32(UVD_RBC_RB_RPTR, 0x0);
 
-       ring->wptr = ring->rptr = RREG32(UVD_RBC_RB_RPTR);
+       ring->wptr = RREG32(UVD_RBC_RB_RPTR);
        WREG32(UVD_RBC_RB_WPTR, ring->wptr);
 
        /* set the ring address */
diff --git a/drivers/gpu/drm/radeon/vce_v1_0.c b/drivers/gpu/drm/radeon/vce_v1_0.c
new file mode 100644 (file)
index 0000000..b44d9c8
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Christian König <christian.koenig@amd.com>
+ */
+
+#include <linux/firmware.h>
+#include <drm/drmP.h>
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "sid.h"
+
+/**
+ * vce_v1_0_get_rptr - get read pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ *
+ * Returns the current hardware read pointer
+ */
+uint32_t vce_v1_0_get_rptr(struct radeon_device *rdev,
+                          struct radeon_ring *ring)
+{
+       if (ring->idx == TN_RING_TYPE_VCE1_INDEX)
+               return RREG32(VCE_RB_RPTR);
+       else
+               return RREG32(VCE_RB_RPTR2);
+}
+
+/**
+ * vce_v1_0_get_wptr - get write pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ *
+ * Returns the current hardware write pointer
+ */
+uint32_t vce_v1_0_get_wptr(struct radeon_device *rdev,
+                          struct radeon_ring *ring)
+{
+       if (ring->idx == TN_RING_TYPE_VCE1_INDEX)
+               return RREG32(VCE_RB_WPTR);
+       else
+               return RREG32(VCE_RB_WPTR2);
+}
+
+/**
+ * vce_v1_0_set_wptr - set write pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon_ring pointer
+ *
+ * Commits the write pointer to the hardware
+ */
+void vce_v1_0_set_wptr(struct radeon_device *rdev,
+                      struct radeon_ring *ring)
+{
+       if (ring->idx == TN_RING_TYPE_VCE1_INDEX)
+               WREG32(VCE_RB_WPTR, ring->wptr);
+       else
+               WREG32(VCE_RB_WPTR2, ring->wptr);
+}
+
+/**
+ * vce_v1_0_start - start VCE block
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Setup and start the VCE block
+ */
+int vce_v1_0_start(struct radeon_device *rdev)
+{
+       struct radeon_ring *ring;
+       int i, j, r;
+
+       /* set BUSY flag */
+       WREG32_P(VCE_STATUS, 1, ~1);
+
+       ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
+       WREG32(VCE_RB_RPTR, ring->wptr);
+       WREG32(VCE_RB_WPTR, ring->wptr);
+       WREG32(VCE_RB_BASE_LO, ring->gpu_addr);
+       WREG32(VCE_RB_BASE_HI, upper_32_bits(ring->gpu_addr));
+       WREG32(VCE_RB_SIZE, ring->ring_size / 4);
+
+       ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
+       WREG32(VCE_RB_RPTR2, ring->wptr);
+       WREG32(VCE_RB_WPTR2, ring->wptr);
+       WREG32(VCE_RB_BASE_LO2, ring->gpu_addr);
+       WREG32(VCE_RB_BASE_HI2, upper_32_bits(ring->gpu_addr));
+       WREG32(VCE_RB_SIZE2, ring->ring_size / 4);
+
+       WREG32_P(VCE_VCPU_CNTL, VCE_CLK_EN, ~VCE_CLK_EN);
+
+       WREG32_P(VCE_SOFT_RESET,
+                VCE_ECPU_SOFT_RESET |
+                VCE_FME_SOFT_RESET, ~(
+                VCE_ECPU_SOFT_RESET |
+                VCE_FME_SOFT_RESET));
+
+       mdelay(100);
+
+       WREG32_P(VCE_SOFT_RESET, 0, ~(
+                VCE_ECPU_SOFT_RESET |
+                VCE_FME_SOFT_RESET));
+
+       for (i = 0; i < 10; ++i) {
+               uint32_t status;
+               for (j = 0; j < 100; ++j) {
+                       status = RREG32(VCE_STATUS);
+                       if (status & 2)
+                               break;
+                       mdelay(10);
+               }
+               r = 0;
+               if (status & 2)
+                       break;
+
+               DRM_ERROR("VCE not responding, trying to reset the ECPU!!!\n");
+               WREG32_P(VCE_SOFT_RESET, VCE_ECPU_SOFT_RESET, ~VCE_ECPU_SOFT_RESET);
+               mdelay(10);
+               WREG32_P(VCE_SOFT_RESET, 0, ~VCE_ECPU_SOFT_RESET);
+               mdelay(10);
+               r = -1;
+       }
+
+       /* clear BUSY flag */
+       WREG32_P(VCE_STATUS, 0, ~1);
+
+       if (r) {
+               DRM_ERROR("VCE not responding, giving up!!!\n");
+               return r;
+       }
+
+       return 0;
+}
+
+int vce_v1_0_init(struct radeon_device *rdev)
+{
+       struct radeon_ring *ring;
+       int r;
+
+       r = vce_v1_0_start(rdev);
+       if (r)
+               return r;
+
+       ring = &rdev->ring[TN_RING_TYPE_VCE1_INDEX];
+       ring->ready = true;
+       r = radeon_ring_test(rdev, TN_RING_TYPE_VCE1_INDEX, ring);
+       if (r) {
+               ring->ready = false;
+               return r;
+       }
+
+       ring = &rdev->ring[TN_RING_TYPE_VCE2_INDEX];
+       ring->ready = true;
+       r = radeon_ring_test(rdev, TN_RING_TYPE_VCE2_INDEX, ring);
+       if (r) {
+               ring->ready = false;
+               return r;
+       }
+
+       DRM_INFO("VCE initialized successfully.\n");
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/radeon/vce_v2_0.c b/drivers/gpu/drm/radeon/vce_v2_0.c
new file mode 100644 (file)
index 0000000..1ac7bb8
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2013 Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * 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, sub license, 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 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 NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS 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.
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * Authors: Christian König <christian.koenig@amd.com>
+ */
+
+#include <linux/firmware.h>
+#include <drm/drmP.h>
+#include "radeon.h"
+#include "radeon_asic.h"
+#include "cikd.h"
+
+static void vce_v2_0_set_sw_cg(struct radeon_device *rdev, bool gated)
+{
+       u32 tmp;
+
+       if (gated) {
+               tmp = RREG32(VCE_CLOCK_GATING_B);
+               tmp |= 0xe70000;
+               WREG32(VCE_CLOCK_GATING_B, tmp);
+
+               tmp = RREG32(VCE_UENC_CLOCK_GATING);
+               tmp |= 0xff000000;
+               WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+               tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
+               tmp &= ~0x3fc;
+               WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
+
+               WREG32(VCE_CGTT_CLK_OVERRIDE, 0);
+    } else {
+               tmp = RREG32(VCE_CLOCK_GATING_B);
+               tmp |= 0xe7;
+               tmp &= ~0xe70000;
+               WREG32(VCE_CLOCK_GATING_B, tmp);
+
+               tmp = RREG32(VCE_UENC_CLOCK_GATING);
+               tmp |= 0x1fe000;
+               tmp &= ~0xff000000;
+               WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+               tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
+               tmp |= 0x3fc;
+               WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
+       }
+}
+
+static void vce_v2_0_set_dyn_cg(struct radeon_device *rdev, bool gated)
+{
+       u32 orig, tmp;
+
+       tmp = RREG32(VCE_CLOCK_GATING_B);
+       tmp &= ~0x00060006;
+       if (gated) {
+               tmp |= 0xe10000;
+       } else {
+               tmp |= 0xe1;
+               tmp &= ~0xe10000;
+       }
+       WREG32(VCE_CLOCK_GATING_B, tmp);
+
+       orig = tmp = RREG32(VCE_UENC_CLOCK_GATING);
+       tmp &= ~0x1fe000;
+       tmp &= ~0xff000000;
+       if (tmp != orig)
+               WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+       orig = tmp = RREG32(VCE_UENC_REG_CLOCK_GATING);
+       tmp &= ~0x3fc;
+       if (tmp != orig)
+               WREG32(VCE_UENC_REG_CLOCK_GATING, tmp);
+
+       if (gated)
+               WREG32(VCE_CGTT_CLK_OVERRIDE, 0);
+}
+
+static void vce_v2_0_disable_cg(struct radeon_device *rdev)
+{
+       WREG32(VCE_CGTT_CLK_OVERRIDE, 7);
+}
+
+void vce_v2_0_enable_mgcg(struct radeon_device *rdev, bool enable)
+{
+       bool sw_cg = false;
+
+       if (enable && (rdev->cg_flags & RADEON_CG_SUPPORT_VCE_MGCG)) {
+               if (sw_cg)
+                       vce_v2_0_set_sw_cg(rdev, true);
+               else
+                       vce_v2_0_set_dyn_cg(rdev, true);
+       } else {
+               vce_v2_0_disable_cg(rdev);
+
+               if (sw_cg)
+                       vce_v2_0_set_sw_cg(rdev, false);
+               else
+                       vce_v2_0_set_dyn_cg(rdev, false);
+       }
+}
+
+static void vce_v2_0_init_cg(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       tmp = RREG32(VCE_CLOCK_GATING_A);
+       tmp &= ~(CGC_CLK_GATE_DLY_TIMER_MASK | CGC_CLK_GATER_OFF_DLY_TIMER_MASK);
+       tmp |= (CGC_CLK_GATE_DLY_TIMER(0) | CGC_CLK_GATER_OFF_DLY_TIMER(4));
+       tmp |= CGC_UENC_WAIT_AWAKE;
+       WREG32(VCE_CLOCK_GATING_A, tmp);
+
+       tmp = RREG32(VCE_UENC_CLOCK_GATING);
+       tmp &= ~(CLOCK_ON_DELAY_MASK | CLOCK_OFF_DELAY_MASK);
+       tmp |= (CLOCK_ON_DELAY(0) | CLOCK_OFF_DELAY(4));
+       WREG32(VCE_UENC_CLOCK_GATING, tmp);
+
+       tmp = RREG32(VCE_CLOCK_GATING_B);
+       tmp |= 0x10;
+       tmp &= ~0x100000;
+       WREG32(VCE_CLOCK_GATING_B, tmp);
+}
+
+int vce_v2_0_resume(struct radeon_device *rdev)
+{
+       uint64_t addr = rdev->vce.gpu_addr;
+       uint32_t size;
+
+       WREG32_P(VCE_CLOCK_GATING_A, 0, ~(1 << 16));
+       WREG32_P(VCE_UENC_CLOCK_GATING, 0x1FF000, ~0xFF9FF000);
+       WREG32_P(VCE_UENC_REG_CLOCK_GATING, 0x3F, ~0x3F);
+       WREG32(VCE_CLOCK_GATING_B, 0xf7);
+
+       WREG32(VCE_LMI_CTRL, 0x00398000);
+       WREG32_P(VCE_LMI_CACHE_CTRL, 0x0, ~0x1);
+       WREG32(VCE_LMI_SWAP_CNTL, 0);
+       WREG32(VCE_LMI_SWAP_CNTL1, 0);
+       WREG32(VCE_LMI_VM_CTRL, 0);
+
+       size = RADEON_GPU_PAGE_ALIGN(rdev->vce_fw->size);
+       WREG32(VCE_VCPU_CACHE_OFFSET0, addr & 0x7fffffff);
+       WREG32(VCE_VCPU_CACHE_SIZE0, size);
+
+       addr += size;
+       size = RADEON_VCE_STACK_SIZE;
+       WREG32(VCE_VCPU_CACHE_OFFSET1, addr & 0x7fffffff);
+       WREG32(VCE_VCPU_CACHE_SIZE1, size);
+
+       addr += size;
+       size = RADEON_VCE_HEAP_SIZE;
+       WREG32(VCE_VCPU_CACHE_OFFSET2, addr & 0x7fffffff);
+       WREG32(VCE_VCPU_CACHE_SIZE2, size);
+
+       WREG32_P(VCE_LMI_CTRL2, 0x0, ~0x100);
+
+       WREG32_P(VCE_SYS_INT_EN, VCE_SYS_INT_TRAP_INTERRUPT_EN,
+                ~VCE_SYS_INT_TRAP_INTERRUPT_EN);
+
+       vce_v2_0_init_cg(rdev);
+
+       return 0;
+}
index fbf4be3..299267d 100644 (file)
@@ -299,7 +299,7 @@ static void rcar_du_crtc_update_base(struct rcar_du_crtc *rcrtc)
 {
        struct drm_crtc *crtc = &rcrtc->crtc;
 
-       rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
+       rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb);
        rcar_du_plane_update_base(rcrtc->plane);
 }
 
@@ -358,10 +358,10 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
        const struct rcar_du_format_info *format;
        int ret;
 
-       format = rcar_du_format_info(crtc->fb->pixel_format);
+       format = rcar_du_format_info(crtc->primary->fb->pixel_format);
        if (format == NULL) {
                dev_dbg(rcdu->dev, "mode_set: unsupported format %08x\n",
-                       crtc->fb->pixel_format);
+                       crtc->primary->fb->pixel_format);
                ret = -EINVAL;
                goto error;
        }
@@ -377,7 +377,7 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
        rcrtc->plane->width = mode->hdisplay;
        rcrtc->plane->height = mode->vdisplay;
 
-       rcar_du_plane_compute_base(rcrtc->plane, crtc->fb);
+       rcar_du_plane_compute_base(rcrtc->plane, crtc->primary->fb);
 
        rcrtc->outputs = 0;
 
@@ -510,7 +510,7 @@ static int rcar_du_crtc_page_flip(struct drm_crtc *crtc,
        }
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
        rcar_du_crtc_update_base(rcrtc);
 
        if (event) {
index fbeabd9..a87edfa 100644 (file)
@@ -248,7 +248,10 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
                        continue;
                }
 
-               rcar_du_encoder_init(rcdu, pdata->type, pdata->output, pdata);
+               ret = rcar_du_encoder_init(rcdu, pdata->type, pdata->output,
+                                          pdata);
+               if (ret < 0)
+                       return ret;
        }
 
        /* Set the possible CRTCs and possible clones. There's always at least
index 0428076..e9e5e6d 100644 (file)
@@ -173,7 +173,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
        if (scrtc->started)
                return;
 
-       format = shmob_drm_format_info(crtc->fb->pixel_format);
+       format = shmob_drm_format_info(crtc->primary->fb->pixel_format);
        if (WARN_ON(format == NULL))
                return;
 
@@ -247,7 +247,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
        lcdc_write(sdev, LDDDSR, value);
 
        /* Setup planes. */
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
+       drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
                if (plane->crtc == crtc)
                        shmob_drm_plane_setup(plane);
        }
@@ -303,7 +303,7 @@ static void shmob_drm_crtc_compute_base(struct shmob_drm_crtc *scrtc,
                                        int x, int y)
 {
        struct drm_crtc *crtc = &scrtc->crtc;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_framebuffer *fb = crtc->primary->fb;
        struct shmob_drm_device *sdev = crtc->dev->dev_private;
        struct drm_gem_cma_object *gem;
        unsigned int bpp;
@@ -382,15 +382,15 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
        const struct shmob_drm_format_info *format;
        void *cache;
 
-       format = shmob_drm_format_info(crtc->fb->pixel_format);
+       format = shmob_drm_format_info(crtc->primary->fb->pixel_format);
        if (format == NULL) {
                dev_dbg(sdev->dev, "mode_set: unsupported format %08x\n",
-                       crtc->fb->pixel_format);
+                       crtc->primary->fb->pixel_format);
                return -EINVAL;
        }
 
        scrtc->format = format;
-       scrtc->line_size = crtc->fb->pitches[0];
+       scrtc->line_size = crtc->primary->fb->pitches[0];
 
        if (sdev->meram) {
                /* Enable MERAM cache if configured. We need to de-init
@@ -402,7 +402,7 @@ static int shmob_drm_crtc_mode_set(struct drm_crtc *crtc,
                }
 
                cache = sh_mobile_meram_cache_alloc(sdev->meram, mdata,
-                                                   crtc->fb->pitches[0],
+                                                   crtc->primary->fb->pitches[0],
                                                    adjusted_mode->vdisplay,
                                                    format->meram,
                                                    &scrtc->line_size);
@@ -489,7 +489,7 @@ static int shmob_drm_crtc_page_flip(struct drm_crtc *crtc,
        }
        spin_unlock_irqrestore(&dev->event_lock, flags);
 
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
        shmob_drm_crtc_update_base(scrtc);
 
        if (event) {
index 8d220af..d43f21b 100644 (file)
@@ -11,6 +11,8 @@ tegra-drm-y := \
        hdmi.o \
        mipi-phy.o \
        dsi.o \
+       sor.o \
+       dpaux.o \
        gr2d.o \
        gr3d.o
 
index e38e596..71cef5c 100644 (file)
@@ -63,7 +63,7 @@ int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device)
        return 0;
 
 err_free:
-       drm_dev_free(drm);
+       drm_dev_unref(drm);
        return ret;
 }
 
index 9336006..36c717a 100644 (file)
@@ -235,14 +235,14 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
        if (!dc->event)
                return;
 
-       bo = tegra_fb_get_plane(crtc->fb, 0);
+       bo = tegra_fb_get_plane(crtc->primary->fb, 0);
 
        /* check if new start address has been latched */
        tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
        base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
        tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
 
-       if (base == bo->paddr + crtc->fb->offsets[0]) {
+       if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
                spin_lock_irqsave(&drm->event_lock, flags);
                drm_send_vblank_event(drm, dc->pipe, dc->event);
                drm_vblank_put(drm, dc->pipe);
@@ -284,7 +284,7 @@ static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        }
 
        tegra_dc_set_base(dc, 0, 0, fb);
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
 
        return 0;
 }
@@ -645,7 +645,7 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
                               struct drm_display_mode *adjusted,
                               int x, int y, struct drm_framebuffer *old_fb)
 {
-       struct tegra_bo *bo = tegra_fb_get_plane(crtc->fb, 0);
+       struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0);
        struct tegra_dc *dc = to_tegra_dc(crtc);
        struct tegra_dc_window window;
        unsigned long div, value;
@@ -682,9 +682,9 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
        window.dst.y = 0;
        window.dst.w = mode->hdisplay;
        window.dst.h = mode->vdisplay;
-       window.format = tegra_dc_format(crtc->fb->pixel_format);
-       window.bits_per_pixel = crtc->fb->bits_per_pixel;
-       window.stride[0] = crtc->fb->pitches[0];
+       window.format = tegra_dc_format(crtc->primary->fb->pixel_format);
+       window.bits_per_pixel = crtc->primary->fb->bits_per_pixel;
+       window.stride[0] = crtc->primary->fb->pitches[0];
        window.base[0] = bo->paddr;
 
        err = tegra_dc_setup_window(dc, 0, &window);
@@ -699,7 +699,7 @@ static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
 {
        struct tegra_dc *dc = to_tegra_dc(crtc);
 
-       return tegra_dc_set_base(dc, x, y, crtc->fb);
+       return tegra_dc_set_base(dc, x, y, crtc->primary->fb);
 }
 
 static void tegra_crtc_prepare(struct drm_crtc *crtc)
index 3c2c0ea..c941014 100644 (file)
 #define DC_DISP_DISP_WIN_OPTIONS               0x402
 #define HDMI_ENABLE (1 << 30)
 #define DSI_ENABLE  (1 << 29)
+#define SOR_ENABLE  (1 << 25)
 
 #define DC_DISP_DISP_MEM_HIGH_PRIORITY         0x403
 #define CURSOR_THRESHOLD(x)   (((x) & 0x03) << 24)
diff --git a/drivers/gpu/drm/tegra/dpaux.c b/drivers/gpu/drm/tegra/dpaux.c
new file mode 100644 (file)
index 0000000..d536ed3
--- /dev/null
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_panel.h>
+
+#include "dpaux.h"
+#include "drm.h"
+
+static DEFINE_MUTEX(dpaux_lock);
+static LIST_HEAD(dpaux_list);
+
+struct tegra_dpaux {
+       struct drm_dp_aux aux;
+       struct device *dev;
+
+       void __iomem *regs;
+       int irq;
+
+       struct tegra_output *output;
+
+       struct reset_control *rst;
+       struct clk *clk_parent;
+       struct clk *clk;
+
+       struct regulator *vdd;
+
+       struct completion complete;
+       struct list_head list;
+};
+
+static inline struct tegra_dpaux *to_dpaux(struct drm_dp_aux *aux)
+{
+       return container_of(aux, struct tegra_dpaux, aux);
+}
+
+static inline unsigned long tegra_dpaux_readl(struct tegra_dpaux *dpaux,
+                                             unsigned long offset)
+{
+       return readl(dpaux->regs + (offset << 2));
+}
+
+static inline void tegra_dpaux_writel(struct tegra_dpaux *dpaux,
+                                     unsigned long value,
+                                     unsigned long offset)
+{
+       writel(value, dpaux->regs + (offset << 2));
+}
+
+static void tegra_dpaux_write_fifo(struct tegra_dpaux *dpaux, const u8 *buffer,
+                                  size_t size)
+{
+       unsigned long offset = DPAUX_DP_AUXDATA_WRITE(0);
+       size_t i, j;
+
+       for (i = 0; i < size; i += 4) {
+               size_t num = min_t(size_t, size - i, 4);
+               unsigned long value = 0;
+
+               for (j = 0; j < num; j++)
+                       value |= buffer[i + j] << (j * 8);
+
+               tegra_dpaux_writel(dpaux, value, offset++);
+       }
+}
+
+static void tegra_dpaux_read_fifo(struct tegra_dpaux *dpaux, u8 *buffer,
+                                 size_t size)
+{
+       unsigned long offset = DPAUX_DP_AUXDATA_READ(0);
+       size_t i, j;
+
+       for (i = 0; i < size; i += 4) {
+               size_t num = min_t(size_t, size - i, 4);
+               unsigned long value;
+
+               value = tegra_dpaux_readl(dpaux, offset++);
+
+               for (j = 0; j < num; j++)
+                       buffer[i + j] = value >> (j * 8);
+       }
+}
+
+static ssize_t tegra_dpaux_transfer(struct drm_dp_aux *aux,
+                                   struct drm_dp_aux_msg *msg)
+{
+       unsigned long value = DPAUX_DP_AUXCTL_TRANSACTREQ;
+       unsigned long timeout = msecs_to_jiffies(250);
+       struct tegra_dpaux *dpaux = to_dpaux(aux);
+       unsigned long status;
+       ssize_t ret = 0;
+
+       if (msg->size < 1 || msg->size > 16)
+               return -EINVAL;
+
+       tegra_dpaux_writel(dpaux, msg->address, DPAUX_DP_AUXADDR);
+
+       switch (msg->request & ~DP_AUX_I2C_MOT) {
+       case DP_AUX_I2C_WRITE:
+               if (msg->request & DP_AUX_I2C_MOT)
+                       value = DPAUX_DP_AUXCTL_CMD_MOT_WR;
+               else
+                       value = DPAUX_DP_AUXCTL_CMD_I2C_WR;
+
+               break;
+
+       case DP_AUX_I2C_READ:
+               if (msg->request & DP_AUX_I2C_MOT)
+                       value = DPAUX_DP_AUXCTL_CMD_MOT_RD;
+               else
+                       value = DPAUX_DP_AUXCTL_CMD_I2C_RD;
+
+               break;
+
+       case DP_AUX_I2C_STATUS:
+               if (msg->request & DP_AUX_I2C_MOT)
+                       value = DPAUX_DP_AUXCTL_CMD_MOT_RQ;
+               else
+                       value = DPAUX_DP_AUXCTL_CMD_I2C_RQ;
+
+               break;
+
+       case DP_AUX_NATIVE_WRITE:
+               value = DPAUX_DP_AUXCTL_CMD_AUX_WR;
+               break;
+
+       case DP_AUX_NATIVE_READ:
+               value = DPAUX_DP_AUXCTL_CMD_AUX_RD;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       value |= DPAUX_DP_AUXCTL_CMDLEN(msg->size - 1);
+       tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL);
+
+       if ((msg->request & DP_AUX_I2C_READ) == 0) {
+               tegra_dpaux_write_fifo(dpaux, msg->buffer, msg->size);
+               ret = msg->size;
+       }
+
+       /* start transaction */
+       value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXCTL);
+       value |= DPAUX_DP_AUXCTL_TRANSACTREQ;
+       tegra_dpaux_writel(dpaux, value, DPAUX_DP_AUXCTL);
+
+       status = wait_for_completion_timeout(&dpaux->complete, timeout);
+       if (!status)
+               return -ETIMEDOUT;
+
+       /* read status and clear errors */
+       value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT);
+       tegra_dpaux_writel(dpaux, 0xf00, DPAUX_DP_AUXSTAT);
+
+       if (value & DPAUX_DP_AUXSTAT_TIMEOUT_ERROR)
+               return -ETIMEDOUT;
+
+       if ((value & DPAUX_DP_AUXSTAT_RX_ERROR) ||
+           (value & DPAUX_DP_AUXSTAT_SINKSTAT_ERROR) ||
+           (value & DPAUX_DP_AUXSTAT_NO_STOP_ERROR))
+               return -EIO;
+
+       switch ((value & DPAUX_DP_AUXSTAT_REPLY_TYPE_MASK) >> 16) {
+       case 0x00:
+               msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+               break;
+
+       case 0x01:
+               msg->reply = DP_AUX_NATIVE_REPLY_NACK;
+               break;
+
+       case 0x02:
+               msg->reply = DP_AUX_NATIVE_REPLY_DEFER;
+               break;
+
+       case 0x04:
+               msg->reply = DP_AUX_I2C_REPLY_NACK;
+               break;
+
+       case 0x08:
+               msg->reply = DP_AUX_I2C_REPLY_DEFER;
+               break;
+       }
+
+       if (msg->reply == DP_AUX_NATIVE_REPLY_ACK) {
+               if (msg->request & DP_AUX_I2C_READ) {
+                       size_t count = value & DPAUX_DP_AUXSTAT_REPLY_MASK;
+
+                       if (WARN_ON(count != msg->size))
+                               count = min_t(size_t, count, msg->size);
+
+                       tegra_dpaux_read_fifo(dpaux, msg->buffer, count);
+                       ret = count;
+               }
+       }
+
+       return ret;
+}
+
+static irqreturn_t tegra_dpaux_irq(int irq, void *data)
+{
+       struct tegra_dpaux *dpaux = data;
+       irqreturn_t ret = IRQ_HANDLED;
+       unsigned long value;
+
+       /* clear interrupts */
+       value = tegra_dpaux_readl(dpaux, DPAUX_INTR_AUX);
+       tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX);
+
+       if (value & DPAUX_INTR_PLUG_EVENT) {
+               if (dpaux->output) {
+                       drm_helper_hpd_irq_event(dpaux->output->connector.dev);
+               }
+       }
+
+       if (value & DPAUX_INTR_UNPLUG_EVENT) {
+               if (dpaux->output)
+                       drm_helper_hpd_irq_event(dpaux->output->connector.dev);
+       }
+
+       if (value & DPAUX_INTR_IRQ_EVENT) {
+               /* TODO: handle this */
+       }
+
+       if (value & DPAUX_INTR_AUX_DONE)
+               complete(&dpaux->complete);
+
+       return ret;
+}
+
+static int tegra_dpaux_probe(struct platform_device *pdev)
+{
+       struct tegra_dpaux *dpaux;
+       struct resource *regs;
+       unsigned long value;
+       int err;
+
+       dpaux = devm_kzalloc(&pdev->dev, sizeof(*dpaux), GFP_KERNEL);
+       if (!dpaux)
+               return -ENOMEM;
+
+       init_completion(&dpaux->complete);
+       INIT_LIST_HEAD(&dpaux->list);
+       dpaux->dev = &pdev->dev;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dpaux->regs = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(dpaux->regs))
+               return PTR_ERR(dpaux->regs);
+
+       dpaux->irq = platform_get_irq(pdev, 0);
+       if (dpaux->irq < 0) {
+               dev_err(&pdev->dev, "failed to get IRQ\n");
+               return -ENXIO;
+       }
+
+       dpaux->rst = devm_reset_control_get(&pdev->dev, "dpaux");
+       if (IS_ERR(dpaux->rst))
+               return PTR_ERR(dpaux->rst);
+
+       dpaux->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(dpaux->clk))
+               return PTR_ERR(dpaux->clk);
+
+       err = clk_prepare_enable(dpaux->clk);
+       if (err < 0)
+               return err;
+
+       reset_control_deassert(dpaux->rst);
+
+       dpaux->clk_parent = devm_clk_get(&pdev->dev, "parent");
+       if (IS_ERR(dpaux->clk_parent))
+               return PTR_ERR(dpaux->clk_parent);
+
+       err = clk_prepare_enable(dpaux->clk_parent);
+       if (err < 0)
+               return err;
+
+       err = clk_set_rate(dpaux->clk_parent, 270000000);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to set clock to 270 MHz: %d\n",
+                       err);
+               return err;
+       }
+
+       dpaux->vdd = devm_regulator_get(&pdev->dev, "vdd");
+       if (IS_ERR(dpaux->vdd))
+               return PTR_ERR(dpaux->vdd);
+
+       err = devm_request_irq(dpaux->dev, dpaux->irq, tegra_dpaux_irq, 0,
+                              dev_name(dpaux->dev), dpaux);
+       if (err < 0) {
+               dev_err(dpaux->dev, "failed to request IRQ#%u: %d\n",
+                       dpaux->irq, err);
+               return err;
+       }
+
+       dpaux->aux.transfer = tegra_dpaux_transfer;
+       dpaux->aux.dev = &pdev->dev;
+
+       err = drm_dp_aux_register_i2c_bus(&dpaux->aux);
+       if (err < 0)
+               return err;
+
+       /* enable and clear all interrupts */
+       value = DPAUX_INTR_AUX_DONE | DPAUX_INTR_IRQ_EVENT |
+               DPAUX_INTR_UNPLUG_EVENT | DPAUX_INTR_PLUG_EVENT;
+       tegra_dpaux_writel(dpaux, value, DPAUX_INTR_EN_AUX);
+       tegra_dpaux_writel(dpaux, value, DPAUX_INTR_AUX);
+
+       mutex_lock(&dpaux_lock);
+       list_add_tail(&dpaux->list, &dpaux_list);
+       mutex_unlock(&dpaux_lock);
+
+       platform_set_drvdata(pdev, dpaux);
+
+       return 0;
+}
+
+static int tegra_dpaux_remove(struct platform_device *pdev)
+{
+       struct tegra_dpaux *dpaux = platform_get_drvdata(pdev);
+
+       drm_dp_aux_unregister_i2c_bus(&dpaux->aux);
+
+       mutex_lock(&dpaux_lock);
+       list_del(&dpaux->list);
+       mutex_unlock(&dpaux_lock);
+
+       clk_disable_unprepare(dpaux->clk_parent);
+       reset_control_assert(dpaux->rst);
+       clk_disable_unprepare(dpaux->clk);
+
+       return 0;
+}
+
+static const struct of_device_id tegra_dpaux_of_match[] = {
+       { .compatible = "nvidia,tegra124-dpaux", },
+       { },
+};
+
+struct platform_driver tegra_dpaux_driver = {
+       .driver = {
+               .name = "tegra-dpaux",
+               .of_match_table = tegra_dpaux_of_match,
+       },
+       .probe = tegra_dpaux_probe,
+       .remove = tegra_dpaux_remove,
+};
+
+struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np)
+{
+       struct tegra_dpaux *dpaux;
+
+       mutex_lock(&dpaux_lock);
+
+       list_for_each_entry(dpaux, &dpaux_list, list)
+               if (np == dpaux->dev->of_node) {
+                       mutex_unlock(&dpaux_lock);
+                       return dpaux;
+               }
+
+       mutex_unlock(&dpaux_lock);
+
+       return NULL;
+}
+
+int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output)
+{
+       unsigned long timeout;
+       int err;
+
+       dpaux->output = output;
+
+       err = regulator_enable(dpaux->vdd);
+       if (err < 0)
+               return err;
+
+       timeout = jiffies + msecs_to_jiffies(250);
+
+       while (time_before(jiffies, timeout)) {
+               enum drm_connector_status status;
+
+               status = tegra_dpaux_detect(dpaux);
+               if (status == connector_status_connected)
+                       return 0;
+
+               usleep_range(1000, 2000);
+       }
+
+       return -ETIMEDOUT;
+}
+
+int tegra_dpaux_detach(struct tegra_dpaux *dpaux)
+{
+       unsigned long timeout;
+       int err;
+
+       err = regulator_disable(dpaux->vdd);
+       if (err < 0)
+               return err;
+
+       timeout = jiffies + msecs_to_jiffies(250);
+
+       while (time_before(jiffies, timeout)) {
+               enum drm_connector_status status;
+
+               status = tegra_dpaux_detect(dpaux);
+               if (status == connector_status_disconnected) {
+                       dpaux->output = NULL;
+                       return 0;
+               }
+
+               usleep_range(1000, 2000);
+       }
+
+       return -ETIMEDOUT;
+}
+
+enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux)
+{
+       unsigned long value;
+
+       value = tegra_dpaux_readl(dpaux, DPAUX_DP_AUXSTAT);
+
+       if (value & DPAUX_DP_AUXSTAT_HPD_STATUS)
+               return connector_status_connected;
+
+       return connector_status_disconnected;
+}
+
+int tegra_dpaux_enable(struct tegra_dpaux *dpaux)
+{
+       unsigned long value;
+
+       value = DPAUX_HYBRID_PADCTL_AUX_CMH(2) |
+               DPAUX_HYBRID_PADCTL_AUX_DRVZ(4) |
+               DPAUX_HYBRID_PADCTL_AUX_DRVI(0x18) |
+               DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV |
+               DPAUX_HYBRID_PADCTL_MODE_AUX;
+       tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_PADCTL);
+
+       value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
+       value &= ~DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
+       tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
+
+       return 0;
+}
+
+int tegra_dpaux_disable(struct tegra_dpaux *dpaux)
+{
+       unsigned long value;
+
+       value = tegra_dpaux_readl(dpaux, DPAUX_HYBRID_SPARE);
+       value |= DPAUX_HYBRID_SPARE_PAD_POWER_DOWN;
+       tegra_dpaux_writel(dpaux, value, DPAUX_HYBRID_SPARE);
+
+       return 0;
+}
+
+int tegra_dpaux_prepare(struct tegra_dpaux *dpaux, u8 encoding)
+{
+       int err;
+
+       err = drm_dp_dpcd_writeb(&dpaux->aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
+                                encoding);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
+                     u8 pattern)
+{
+       u8 tp = pattern & DP_TRAINING_PATTERN_MASK;
+       u8 status[DP_LINK_STATUS_SIZE], values[4];
+       unsigned int i;
+       int err;
+
+       err = drm_dp_dpcd_writeb(&dpaux->aux, DP_TRAINING_PATTERN_SET, pattern);
+       if (err < 0)
+               return err;
+
+       if (tp == DP_TRAINING_PATTERN_DISABLE)
+               return 0;
+
+       for (i = 0; i < link->num_lanes; i++)
+               values[i] = DP_TRAIN_MAX_PRE_EMPHASIS_REACHED |
+                           DP_TRAIN_PRE_EMPHASIS_0 |
+                           DP_TRAIN_MAX_SWING_REACHED |
+                           DP_TRAIN_VOLTAGE_SWING_400;
+
+       err = drm_dp_dpcd_write(&dpaux->aux, DP_TRAINING_LANE0_SET, values,
+                               link->num_lanes);
+       if (err < 0)
+               return err;
+
+       usleep_range(500, 1000);
+
+       err = drm_dp_dpcd_read_link_status(&dpaux->aux, status);
+       if (err < 0)
+               return err;
+
+       switch (tp) {
+       case DP_TRAINING_PATTERN_1:
+               if (!drm_dp_clock_recovery_ok(status, link->num_lanes))
+                       return -EAGAIN;
+
+               break;
+
+       case DP_TRAINING_PATTERN_2:
+               if (!drm_dp_channel_eq_ok(status, link->num_lanes))
+                       return -EAGAIN;
+
+               break;
+
+       default:
+               dev_err(dpaux->dev, "unsupported training pattern %u\n", tp);
+               return -EINVAL;
+       }
+
+       err = drm_dp_dpcd_writeb(&dpaux->aux, DP_EDP_CONFIGURATION_SET, 0);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/tegra/dpaux.h b/drivers/gpu/drm/tegra/dpaux.h
new file mode 100644 (file)
index 0000000..4f5bf10
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * 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 DRM_TEGRA_DPAUX_H
+#define DRM_TEGRA_DPAUX_H
+
+#define DPAUX_CTXSW 0x00
+
+#define DPAUX_INTR_EN_AUX 0x01
+#define DPAUX_INTR_AUX 0x05
+#define DPAUX_INTR_AUX_DONE (1 << 3)
+#define DPAUX_INTR_IRQ_EVENT (1 << 2)
+#define DPAUX_INTR_UNPLUG_EVENT (1 << 1)
+#define DPAUX_INTR_PLUG_EVENT (1 << 0)
+
+#define DPAUX_DP_AUXDATA_WRITE(x) (0x09 + ((x) << 2))
+#define DPAUX_DP_AUXDATA_READ(x) (0x19 + ((x) << 2))
+#define DPAUX_DP_AUXADDR 0x29
+
+#define DPAUX_DP_AUXCTL 0x2d
+#define DPAUX_DP_AUXCTL_TRANSACTREQ (1 << 16)
+#define DPAUX_DP_AUXCTL_CMD_AUX_RD (9 << 12)
+#define DPAUX_DP_AUXCTL_CMD_AUX_WR (8 << 12)
+#define DPAUX_DP_AUXCTL_CMD_MOT_RQ (6 << 12)
+#define DPAUX_DP_AUXCTL_CMD_MOT_RD (5 << 12)
+#define DPAUX_DP_AUXCTL_CMD_MOT_WR (4 << 12)
+#define DPAUX_DP_AUXCTL_CMD_I2C_RQ (2 << 12)
+#define DPAUX_DP_AUXCTL_CMD_I2C_RD (1 << 12)
+#define DPAUX_DP_AUXCTL_CMD_I2C_WR (0 << 12)
+#define DPAUX_DP_AUXCTL_CMDLEN(x) ((x) & 0xff)
+
+#define DPAUX_DP_AUXSTAT 0x31
+#define DPAUX_DP_AUXSTAT_HPD_STATUS (1 << 28)
+#define DPAUX_DP_AUXSTAT_REPLY_TYPE_MASK (0xf0000)
+#define DPAUX_DP_AUXSTAT_NO_STOP_ERROR (1 << 11)
+#define DPAUX_DP_AUXSTAT_SINKSTAT_ERROR (1 << 10)
+#define DPAUX_DP_AUXSTAT_RX_ERROR (1 << 9)
+#define DPAUX_DP_AUXSTAT_TIMEOUT_ERROR (1 << 8)
+#define DPAUX_DP_AUXSTAT_REPLY_MASK (0xff)
+
+#define DPAUX_DP_AUX_SINKSTAT_LO 0x35
+#define DPAUX_DP_AUX_SINKSTAT_HI 0x39
+
+#define DPAUX_HPD_CONFIG 0x3d
+#define DPAUX_HPD_CONFIG_UNPLUG_MIN_TIME(x) (((x) & 0xffff) << 16)
+#define DPAUX_HPD_CONFIG_PLUG_MIN_TIME(x) ((x) & 0xffff)
+
+#define DPAUX_HPD_IRQ_CONFIG 0x41
+#define DPAUX_HPD_IRQ_CONFIG_MIN_LOW_TIME(x) ((x) & 0xffff)
+
+#define DPAUX_DP_AUX_CONFIG 0x45
+
+#define DPAUX_HYBRID_PADCTL 0x49
+#define DPAUX_HYBRID_PADCTL_AUX_CMH(x) (((x) & 0x3) << 12)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVZ(x) (((x) & 0x7) << 8)
+#define DPAUX_HYBRID_PADCTL_AUX_DRVI(x) (((x) & 0x3f) << 2)
+#define DPAUX_HYBRID_PADCTL_AUX_INPUT_RCV (1 << 1)
+#define DPAUX_HYBRID_PADCTL_MODE_I2C (1 << 0)
+#define DPAUX_HYBRID_PADCTL_MODE_AUX (0 << 0)
+
+#define DPAUX_HYBRID_SPARE 0x4d
+#define DPAUX_HYBRID_SPARE_PAD_POWER_DOWN (1 << 0)
+
+#define DPAUX_SCRATCH_REG0 0x51
+#define DPAUX_SCRATCH_REG1 0x55
+#define DPAUX_SCRATCH_REG2 0x59
+
+#endif
index c715947..6f5b6e2 100644 (file)
@@ -665,6 +665,7 @@ static const struct of_device_id host1x_drm_subdevs[] = {
        { .compatible = "nvidia,tegra114-hdmi", },
        { .compatible = "nvidia,tegra114-gr3d", },
        { .compatible = "nvidia,tegra124-dc", },
+       { .compatible = "nvidia,tegra124-sor", },
        { /* sentinel */ }
 };
 
@@ -691,14 +692,22 @@ static int __init host1x_drm_init(void)
        if (err < 0)
                goto unregister_dc;
 
-       err = platform_driver_register(&tegra_hdmi_driver);
+       err = platform_driver_register(&tegra_sor_driver);
        if (err < 0)
                goto unregister_dsi;
 
-       err = platform_driver_register(&tegra_gr2d_driver);
+       err = platform_driver_register(&tegra_hdmi_driver);
+       if (err < 0)
+               goto unregister_sor;
+
+       err = platform_driver_register(&tegra_dpaux_driver);
        if (err < 0)
                goto unregister_hdmi;
 
+       err = platform_driver_register(&tegra_gr2d_driver);
+       if (err < 0)
+               goto unregister_dpaux;
+
        err = platform_driver_register(&tegra_gr3d_driver);
        if (err < 0)
                goto unregister_gr2d;
@@ -707,8 +716,12 @@ static int __init host1x_drm_init(void)
 
 unregister_gr2d:
        platform_driver_unregister(&tegra_gr2d_driver);
+unregister_dpaux:
+       platform_driver_unregister(&tegra_dpaux_driver);
 unregister_hdmi:
        platform_driver_unregister(&tegra_hdmi_driver);
+unregister_sor:
+       platform_driver_unregister(&tegra_sor_driver);
 unregister_dsi:
        platform_driver_unregister(&tegra_dsi_driver);
 unregister_dc:
@@ -723,7 +736,9 @@ static void __exit host1x_drm_exit(void)
 {
        platform_driver_unregister(&tegra_gr3d_driver);
        platform_driver_unregister(&tegra_gr2d_driver);
+       platform_driver_unregister(&tegra_dpaux_driver);
        platform_driver_unregister(&tegra_hdmi_driver);
+       platform_driver_unregister(&tegra_sor_driver);
        platform_driver_unregister(&tegra_dsi_driver);
        platform_driver_unregister(&tegra_dc_driver);
        host1x_driver_unregister(&host1x_drm_driver);
index bf1cac7..126332c 100644 (file)
@@ -179,12 +179,14 @@ struct tegra_output_ops {
        int (*check_mode)(struct tegra_output *output,
                          struct drm_display_mode *mode,
                          enum drm_mode_status *status);
+       enum drm_connector_status (*detect)(struct tegra_output *output);
 };
 
 enum tegra_output_type {
        TEGRA_OUTPUT_RGB,
        TEGRA_OUTPUT_HDMI,
        TEGRA_OUTPUT_DSI,
+       TEGRA_OUTPUT_EDP,
 };
 
 struct tegra_output {
@@ -265,6 +267,22 @@ extern int tegra_output_remove(struct tegra_output *output);
 extern int tegra_output_init(struct drm_device *drm, struct tegra_output *output);
 extern int tegra_output_exit(struct tegra_output *output);
 
+/* from dpaux.c */
+
+struct tegra_dpaux;
+struct drm_dp_link;
+struct drm_dp_aux;
+
+struct tegra_dpaux *tegra_dpaux_find_by_of_node(struct device_node *np);
+enum drm_connector_status tegra_dpaux_detect(struct tegra_dpaux *dpaux);
+int tegra_dpaux_attach(struct tegra_dpaux *dpaux, struct tegra_output *output);
+int tegra_dpaux_detach(struct tegra_dpaux *dpaux);
+int tegra_dpaux_enable(struct tegra_dpaux *dpaux);
+int tegra_dpaux_disable(struct tegra_dpaux *dpaux);
+int tegra_dpaux_prepare(struct tegra_dpaux *dpaux, u8 encoding);
+int tegra_dpaux_train(struct tegra_dpaux *dpaux, struct drm_dp_link *link,
+                     u8 pattern);
+
 /* from fb.c */
 struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
                                    unsigned int index);
@@ -278,7 +296,9 @@ extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
 
 extern struct platform_driver tegra_dc_driver;
 extern struct platform_driver tegra_dsi_driver;
+extern struct platform_driver tegra_sor_driver;
 extern struct platform_driver tegra_hdmi_driver;
+extern struct platform_driver tegra_dpaux_driver;
 extern struct platform_driver tegra_gr2d_driver;
 extern struct platform_driver tegra_gr3d_driver;
 
index d452faa..0e599f0 100644 (file)
@@ -1,23 +1,9 @@
 /*
  * Copyright (C) 2013 NVIDIA Corporation
  *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  The copyright holders make no representations
- * about the suitability of this software for any purpose.  It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
+ * 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/clk.h>
index 00e79c1..1db5cc2 100644 (file)
@@ -1,23 +1,9 @@
 /*
  * Copyright (C) 2013 NVIDIA Corporation
  *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  The copyright holders make no representations
- * about the suitability of this software for any purpose.  It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
+ * 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 DRM_TEGRA_DSI_H
index ef853e5..bcf9895 100644 (file)
@@ -8,14 +8,9 @@
  *
  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
  *
- * 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.
+ * 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/dma-buf.h>
@@ -394,6 +389,18 @@ static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma)
        return -EINVAL;
 }
 
+static void *tegra_gem_prime_vmap(struct dma_buf *buf)
+{
+       struct drm_gem_object *gem = buf->priv;
+       struct tegra_bo *bo = to_tegra_bo(gem);
+
+       return bo->vaddr;
+}
+
+static void tegra_gem_prime_vunmap(struct dma_buf *buf, void *vaddr)
+{
+}
+
 static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = {
        .map_dma_buf = tegra_gem_prime_map_dma_buf,
        .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf,
@@ -403,6 +410,8 @@ static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = {
        .kmap = tegra_gem_prime_kmap,
        .kunmap = tegra_gem_prime_kunmap,
        .mmap = tegra_gem_prime_mmap,
+       .vmap = tegra_gem_prime_vmap,
+       .vunmap = tegra_gem_prime_vunmap,
 };
 
 struct dma_buf *tegra_gem_prime_export(struct drm_device *drm,
index ffd4f79..2f3fe96 100644 (file)
@@ -3,17 +3,9 @@
  *
  * Copyright (c) 2012-2013, NVIDIA Corporation.
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * 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 __HOST1X_GEM_H
index 7ec4259..2c7ca74 100644 (file)
@@ -1,17 +1,9 @@
 /*
  * Copyright (c) 2012-2013, NVIDIA Corporation.
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * 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/clk.h>
index e2c4aed..486d19d 100644 (file)
@@ -1,23 +1,9 @@
 /*
  * Copyright (C) 2013 NVIDIA Corporation
  *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  The copyright holders make no representations
- * about the suitability of this software for any purpose.  It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
+ * 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/errno.h>
index d359169..012ea8a 100644 (file)
@@ -1,23 +1,9 @@
 /*
  * Copyright (C) 2013 NVIDIA Corporation
  *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that copyright
- * notice and this permission notice appear in supporting documentation, and
- * that the name of the copyright holders not be used in advertising or
- * publicity pertaining to distribution of the software without specific,
- * written prior permission.  The copyright holders make no representations
- * about the suitability of this software for any purpose.  It is provided "as
- * is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
- * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
- * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
- * OF THIS SOFTWARE.
+ * 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 DRM_TEGRA_MIPI_PHY_H
index 57cecbd..a3e4f1e 100644 (file)
@@ -77,6 +77,9 @@ tegra_connector_detect(struct drm_connector *connector, bool force)
        struct tegra_output *output = connector_to_output(connector);
        enum drm_connector_status status = connector_status_unknown;
 
+       if (output->ops->detect)
+               return output->ops->detect(output);
+
        if (gpio_is_valid(output->hpd_gpio)) {
                if (gpio_get_value(output->hpd_gpio) == 0)
                        status = connector_status_disconnected;
@@ -292,6 +295,11 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
                encoder = DRM_MODE_ENCODER_DSI;
                break;
 
+       case TEGRA_OUTPUT_EDP:
+               connector = DRM_MODE_CONNECTOR_eDP;
+               encoder = DRM_MODE_ENCODER_TMDS;
+               break;
+
        default:
                connector = DRM_MODE_CONNECTOR_Unknown;
                encoder = DRM_MODE_ENCODER_NONE;
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
new file mode 100644 (file)
index 0000000..49ef572
--- /dev/null
@@ -0,0 +1,1092 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * 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/clk.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/tegra-powergate.h>
+
+#include <drm/drm_dp_helper.h>
+
+#include "dc.h"
+#include "drm.h"
+#include "sor.h"
+
+struct tegra_sor {
+       struct host1x_client client;
+       struct tegra_output output;
+       struct device *dev;
+
+       void __iomem *regs;
+
+       struct reset_control *rst;
+       struct clk *clk_parent;
+       struct clk *clk_safe;
+       struct clk *clk_dp;
+       struct clk *clk;
+
+       struct tegra_dpaux *dpaux;
+
+       bool enabled;
+};
+
+static inline struct tegra_sor *
+host1x_client_to_sor(struct host1x_client *client)
+{
+       return container_of(client, struct tegra_sor, client);
+}
+
+static inline struct tegra_sor *to_sor(struct tegra_output *output)
+{
+       return container_of(output, struct tegra_sor, output);
+}
+
+static inline unsigned long tegra_sor_readl(struct tegra_sor *sor,
+                                           unsigned long offset)
+{
+       return readl(sor->regs + (offset << 2));
+}
+
+static inline void tegra_sor_writel(struct tegra_sor *sor, unsigned long value,
+                                   unsigned long offset)
+{
+       writel(value, sor->regs + (offset << 2));
+}
+
+static int tegra_sor_dp_train_fast(struct tegra_sor *sor,
+                                  struct drm_dp_link *link)
+{
+       unsigned long value;
+       unsigned int i;
+       u8 pattern;
+       int err;
+
+       /* setup lane parameters */
+       value = SOR_LANE_DRIVE_CURRENT_LANE3(0x40) |
+               SOR_LANE_DRIVE_CURRENT_LANE2(0x40) |
+               SOR_LANE_DRIVE_CURRENT_LANE1(0x40) |
+               SOR_LANE_DRIVE_CURRENT_LANE0(0x40);
+       tegra_sor_writel(sor, value, SOR_LANE_DRIVE_CURRENT_0);
+
+       value = SOR_LANE_PREEMPHASIS_LANE3(0x0f) |
+               SOR_LANE_PREEMPHASIS_LANE2(0x0f) |
+               SOR_LANE_PREEMPHASIS_LANE1(0x0f) |
+               SOR_LANE_PREEMPHASIS_LANE0(0x0f);
+       tegra_sor_writel(sor, value, SOR_LANE_PREEMPHASIS_0);
+
+       value = SOR_LANE_POST_CURSOR_LANE3(0x00) |
+               SOR_LANE_POST_CURSOR_LANE2(0x00) |
+               SOR_LANE_POST_CURSOR_LANE1(0x00) |
+               SOR_LANE_POST_CURSOR_LANE0(0x00);
+       tegra_sor_writel(sor, value, SOR_LANE_POST_CURSOR_0);
+
+       /* disable LVDS mode */
+       tegra_sor_writel(sor, 0, SOR_LVDS);
+
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value |= SOR_DP_PADCTL_TX_PU_ENABLE;
+       value &= ~SOR_DP_PADCTL_TX_PU_MASK;
+       value |= SOR_DP_PADCTL_TX_PU(2); /* XXX: don't hardcode? */
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value |= SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 |
+                SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0;
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+
+       usleep_range(10, 100);
+
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value &= ~(SOR_DP_PADCTL_CM_TXD_3 | SOR_DP_PADCTL_CM_TXD_2 |
+                  SOR_DP_PADCTL_CM_TXD_1 | SOR_DP_PADCTL_CM_TXD_0);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+
+       err = tegra_dpaux_prepare(sor->dpaux, DP_SET_ANSI_8B10B);
+       if (err < 0)
+               return err;
+
+       for (i = 0, value = 0; i < link->num_lanes; i++) {
+               unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
+                                    SOR_DP_TPG_SCRAMBLER_NONE |
+                                    SOR_DP_TPG_PATTERN_TRAIN1;
+               value = (value << 8) | lane;
+       }
+
+       tegra_sor_writel(sor, value, SOR_DP_TPG);
+
+       pattern = DP_TRAINING_PATTERN_1;
+
+       err = tegra_dpaux_train(sor->dpaux, link, pattern);
+       if (err < 0)
+               return err;
+
+       value = tegra_sor_readl(sor, SOR_DP_SPARE_0);
+       value |= SOR_DP_SPARE_SEQ_ENABLE;
+       value &= ~SOR_DP_SPARE_PANEL_INTERNAL;
+       value |= SOR_DP_SPARE_MACRO_SOR_CLK;
+       tegra_sor_writel(sor, value, SOR_DP_SPARE_0);
+
+       for (i = 0, value = 0; i < link->num_lanes; i++) {
+               unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
+                                    SOR_DP_TPG_SCRAMBLER_NONE |
+                                    SOR_DP_TPG_PATTERN_TRAIN2;
+               value = (value << 8) | lane;
+       }
+
+       tegra_sor_writel(sor, value, SOR_DP_TPG);
+
+       pattern = DP_LINK_SCRAMBLING_DISABLE | DP_TRAINING_PATTERN_2;
+
+       err = tegra_dpaux_train(sor->dpaux, link, pattern);
+       if (err < 0)
+               return err;
+
+       for (i = 0, value = 0; i < link->num_lanes; i++) {
+               unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
+                                    SOR_DP_TPG_SCRAMBLER_GALIOS |
+                                    SOR_DP_TPG_PATTERN_NONE;
+               value = (value << 8) | lane;
+       }
+
+       tegra_sor_writel(sor, value, SOR_DP_TPG);
+
+       pattern = DP_TRAINING_PATTERN_DISABLE;
+
+       err = tegra_dpaux_train(sor->dpaux, link, pattern);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static void tegra_sor_super_update(struct tegra_sor *sor)
+{
+       tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0);
+       tegra_sor_writel(sor, 1, SOR_SUPER_STATE_0);
+       tegra_sor_writel(sor, 0, SOR_SUPER_STATE_0);
+}
+
+static void tegra_sor_update(struct tegra_sor *sor)
+{
+       tegra_sor_writel(sor, 0, SOR_STATE_0);
+       tegra_sor_writel(sor, 1, SOR_STATE_0);
+       tegra_sor_writel(sor, 0, SOR_STATE_0);
+}
+
+static int tegra_sor_setup_pwm(struct tegra_sor *sor, unsigned long timeout)
+{
+       unsigned long value;
+
+       value = tegra_sor_readl(sor, SOR_PWM_DIV);
+       value &= ~SOR_PWM_DIV_MASK;
+       value |= 0x400; /* period */
+       tegra_sor_writel(sor, value, SOR_PWM_DIV);
+
+       value = tegra_sor_readl(sor, SOR_PWM_CTL);
+       value &= ~SOR_PWM_CTL_DUTY_CYCLE_MASK;
+       value |= 0x400; /* duty cycle */
+       value &= ~SOR_PWM_CTL_CLK_SEL; /* clock source: PCLK */
+       value |= SOR_PWM_CTL_TRIGGER;
+       tegra_sor_writel(sor, value, SOR_PWM_CTL);
+
+       timeout = jiffies + msecs_to_jiffies(timeout);
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_sor_readl(sor, SOR_PWM_CTL);
+               if ((value & SOR_PWM_CTL_TRIGGER) == 0)
+                       return 0;
+
+               usleep_range(25, 100);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int tegra_sor_attach(struct tegra_sor *sor)
+{
+       unsigned long value, timeout;
+
+       /* wake up in normal mode */
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value |= SOR_SUPER_STATE_HEAD_MODE_AWAKE;
+       value |= SOR_SUPER_STATE_MODE_NORMAL;
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_super_update(sor);
+
+       /* attach */
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value |= SOR_SUPER_STATE_ATTACHED;
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_super_update(sor);
+
+       timeout = jiffies + msecs_to_jiffies(250);
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_sor_readl(sor, SOR_TEST);
+               if ((value & SOR_TEST_ATTACHED) != 0)
+                       return 0;
+
+               usleep_range(25, 100);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int tegra_sor_wakeup(struct tegra_sor *sor)
+{
+       struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc);
+       unsigned long value, timeout;
+
+       /* enable display controller outputs */
+       value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+       value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+                PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
+       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+
+       tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+       timeout = jiffies + msecs_to_jiffies(250);
+
+       /* wait for head to wake up */
+       while (time_before(jiffies, timeout)) {
+               value = tegra_sor_readl(sor, SOR_TEST);
+               value &= SOR_TEST_HEAD_MODE_MASK;
+
+               if (value == SOR_TEST_HEAD_MODE_AWAKE)
+                       return 0;
+
+               usleep_range(25, 100);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int tegra_sor_power_up(struct tegra_sor *sor, unsigned long timeout)
+{
+       unsigned long value;
+
+       value = tegra_sor_readl(sor, SOR_PWR);
+       value |= SOR_PWR_TRIGGER | SOR_PWR_NORMAL_STATE_PU;
+       tegra_sor_writel(sor, value, SOR_PWR);
+
+       timeout = jiffies + msecs_to_jiffies(timeout);
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_sor_readl(sor, SOR_PWR);
+               if ((value & SOR_PWR_TRIGGER) == 0)
+                       return 0;
+
+               usleep_range(25, 100);
+       }
+
+       return -ETIMEDOUT;
+}
+
+static int tegra_output_sor_enable(struct tegra_output *output)
+{
+       struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
+       struct drm_display_mode *mode = &dc->base.mode;
+       unsigned int vbe, vse, hbe, hse, vbs, hbs, i;
+       struct tegra_sor *sor = to_sor(output);
+       unsigned long value;
+       int err;
+
+       if (sor->enabled)
+               return 0;
+
+       err = clk_prepare_enable(sor->clk);
+       if (err < 0)
+               return err;
+
+       reset_control_deassert(sor->rst);
+
+       if (sor->dpaux) {
+               err = tegra_dpaux_enable(sor->dpaux);
+               if (err < 0)
+                       dev_err(sor->dev, "failed to enable DP: %d\n", err);
+       }
+
+       err = clk_set_parent(sor->clk, sor->clk_safe);
+       if (err < 0)
+               dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
+
+       value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
+       value &= ~SOR_CLK_CNTRL_DP_CLK_SEL_MASK;
+       value |= SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK;
+       tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
+
+       value = tegra_sor_readl(sor, SOR_PLL_2);
+       value &= ~SOR_PLL_2_BANDGAP_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL_2);
+       usleep_range(20, 100);
+
+       value = tegra_sor_readl(sor, SOR_PLL_3);
+       value |= SOR_PLL_3_PLL_VDD_MODE_V3_3;
+       tegra_sor_writel(sor, value, SOR_PLL_3);
+
+       value = SOR_PLL_0_ICHPMP(0xf) | SOR_PLL_0_VCOCAP_RST |
+               SOR_PLL_0_PLLREG_LEVEL_V45 | SOR_PLL_0_RESISTOR_EXT;
+       tegra_sor_writel(sor, value, SOR_PLL_0);
+
+       value = tegra_sor_readl(sor, SOR_PLL_2);
+       value |= SOR_PLL_2_SEQ_PLLCAPPD;
+       value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
+       value |= SOR_PLL_2_LVDS_ENABLE;
+       tegra_sor_writel(sor, value, SOR_PLL_2);
+
+       value = SOR_PLL_1_TERM_COMPOUT | SOR_PLL_1_TMDS_TERM;
+       tegra_sor_writel(sor, value, SOR_PLL_1);
+
+       while (true) {
+               value = tegra_sor_readl(sor, SOR_PLL_2);
+               if ((value & SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE) == 0)
+                       break;
+
+               usleep_range(250, 1000);
+       }
+
+       value = tegra_sor_readl(sor, SOR_PLL_2);
+       value &= ~SOR_PLL_2_POWERDOWN_OVERRIDE;
+       value &= ~SOR_PLL_2_PORT_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL_2);
+
+       /*
+        * power up
+        */
+
+       /* set safe link bandwidth (1.62 Gbps) */
+       value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
+       value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
+       value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62;
+       tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
+
+       /* step 1 */
+       value = tegra_sor_readl(sor, SOR_PLL_2);
+       value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE | SOR_PLL_2_PORT_POWERDOWN |
+                SOR_PLL_2_BANDGAP_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL_2);
+
+       value = tegra_sor_readl(sor, SOR_PLL_0);
+       value |= SOR_PLL_0_VCOPD | SOR_PLL_0_POWER_OFF;
+       tegra_sor_writel(sor, value, SOR_PLL_0);
+
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value &= ~SOR_DP_PADCTL_PAD_CAL_PD;
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+
+       /* step 2 */
+       err = tegra_io_rail_power_on(TEGRA_IO_RAIL_LVDS);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to power on I/O rail: %d\n", err);
+               return err;
+       }
+
+       usleep_range(5, 100);
+
+       /* step 3 */
+       value = tegra_sor_readl(sor, SOR_PLL_2);
+       value &= ~SOR_PLL_2_BANDGAP_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL_2);
+
+       usleep_range(20, 100);
+
+       /* step 4 */
+       value = tegra_sor_readl(sor, SOR_PLL_0);
+       value &= ~SOR_PLL_0_POWER_OFF;
+       value &= ~SOR_PLL_0_VCOPD;
+       tegra_sor_writel(sor, value, SOR_PLL_0);
+
+       value = tegra_sor_readl(sor, SOR_PLL_2);
+       value &= ~SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
+       tegra_sor_writel(sor, value, SOR_PLL_2);
+
+       usleep_range(200, 1000);
+
+       /* step 5 */
+       value = tegra_sor_readl(sor, SOR_PLL_2);
+       value &= ~SOR_PLL_2_PORT_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL_2);
+
+       /* switch to DP clock */
+       err = clk_set_parent(sor->clk, sor->clk_dp);
+       if (err < 0)
+               dev_err(sor->dev, "failed to set DP parent clock: %d\n", err);
+
+       /* power dplanes (XXX parameterize based on link?) */
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value |= SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
+                SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2;
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+
+       value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0);
+       value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
+       value |= SOR_DP_LINKCTL_LANE_COUNT(4);
+       tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
+
+       /* start lane sequencer */
+       value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN |
+               SOR_LANE_SEQ_CTL_POWER_STATE_UP;
+       tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
+
+       while (true) {
+               value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
+               if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
+                       break;
+
+               usleep_range(250, 1000);
+       }
+
+       /* set link bandwidth (2.7 GHz, XXX: parameterize based on link?) */
+       value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
+       value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
+       value |= SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70;
+       tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
+
+       /* set linkctl */
+       value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0);
+       value |= SOR_DP_LINKCTL_ENABLE;
+
+       value &= ~SOR_DP_LINKCTL_TU_SIZE_MASK;
+       value |= SOR_DP_LINKCTL_TU_SIZE(59); /* XXX: don't hardcode? */
+
+       value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
+       tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
+
+       for (i = 0, value = 0; i < 4; i++) {
+               unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
+                                    SOR_DP_TPG_SCRAMBLER_GALIOS |
+                                    SOR_DP_TPG_PATTERN_NONE;
+               value = (value << 8) | lane;
+       }
+
+       tegra_sor_writel(sor, value, SOR_DP_TPG);
+
+       value = tegra_sor_readl(sor, SOR_DP_CONFIG_0);
+       value &= ~SOR_DP_CONFIG_WATERMARK_MASK;
+       value |= SOR_DP_CONFIG_WATERMARK(14); /* XXX: don't hardcode? */
+
+       value &= ~SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK;
+       value |= SOR_DP_CONFIG_ACTIVE_SYM_COUNT(47); /* XXX: don't hardcode? */
+
+       value &= ~SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK;
+       value |= SOR_DP_CONFIG_ACTIVE_SYM_FRAC(9); /* XXX: don't hardcode? */
+
+       value &= ~SOR_DP_CONFIG_ACTIVE_SYM_POLARITY; /* XXX: don't hardcode? */
+
+       value |= SOR_DP_CONFIG_ACTIVE_SYM_ENABLE;
+       value |= SOR_DP_CONFIG_DISPARITY_NEGATIVE; /* XXX: don't hardcode? */
+       tegra_sor_writel(sor, value, SOR_DP_CONFIG_0);
+
+       value = tegra_sor_readl(sor, SOR_DP_AUDIO_HBLANK_SYMBOLS);
+       value &= ~SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK;
+       value |= 137; /* XXX: don't hardcode? */
+       tegra_sor_writel(sor, value, SOR_DP_AUDIO_HBLANK_SYMBOLS);
+
+       value = tegra_sor_readl(sor, SOR_DP_AUDIO_VBLANK_SYMBOLS);
+       value &= ~SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK;
+       value |= 2368; /* XXX: don't hardcode? */
+       tegra_sor_writel(sor, value, SOR_DP_AUDIO_VBLANK_SYMBOLS);
+
+       /* enable pad calibration logic */
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value |= SOR_DP_PADCTL_PAD_CAL_PD;
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+
+       if (sor->dpaux) {
+               /* FIXME: properly convert to struct drm_dp_aux */
+               struct drm_dp_aux *aux = (struct drm_dp_aux *)sor->dpaux;
+               struct drm_dp_link link;
+               u8 rate, lanes;
+
+               err = drm_dp_link_probe(aux, &link);
+               if (err < 0) {
+                       dev_err(sor->dev, "failed to probe eDP link: %d\n",
+                               err);
+                       return err;
+               }
+
+               err = drm_dp_link_power_up(aux, &link);
+               if (err < 0) {
+                       dev_err(sor->dev, "failed to power up eDP link: %d\n",
+                               err);
+                       return err;
+               }
+
+               err = drm_dp_link_configure(aux, &link);
+               if (err < 0) {
+                       dev_err(sor->dev, "failed to configure eDP link: %d\n",
+                               err);
+                       return err;
+               }
+
+               rate = drm_dp_link_rate_to_bw_code(link.rate);
+               lanes = link.num_lanes;
+
+               value = tegra_sor_readl(sor, SOR_CLK_CNTRL);
+               value &= ~SOR_CLK_CNTRL_DP_LINK_SPEED_MASK;
+               value |= SOR_CLK_CNTRL_DP_LINK_SPEED(rate);
+               tegra_sor_writel(sor, value, SOR_CLK_CNTRL);
+
+               value = tegra_sor_readl(sor, SOR_DP_LINKCTL_0);
+               value &= ~SOR_DP_LINKCTL_LANE_COUNT_MASK;
+               value |= SOR_DP_LINKCTL_LANE_COUNT(lanes);
+
+               if (link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
+                       value |= SOR_DP_LINKCTL_ENHANCED_FRAME;
+
+               tegra_sor_writel(sor, value, SOR_DP_LINKCTL_0);
+
+               /* disable training pattern generator */
+
+               for (i = 0; i < link.num_lanes; i++) {
+                       unsigned long lane = SOR_DP_TPG_CHANNEL_CODING |
+                                            SOR_DP_TPG_SCRAMBLER_GALIOS |
+                                            SOR_DP_TPG_PATTERN_NONE;
+                       value = (value << 8) | lane;
+               }
+
+               tegra_sor_writel(sor, value, SOR_DP_TPG);
+
+               err = tegra_sor_dp_train_fast(sor, &link);
+               if (err < 0) {
+                       dev_err(sor->dev, "DP fast link training failed: %d\n",
+                               err);
+                       return err;
+               }
+
+               dev_dbg(sor->dev, "fast link training succeeded\n");
+       }
+
+       err = tegra_sor_power_up(sor, 250);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to power up SOR: %d\n", err);
+               return err;
+       }
+
+       /* start display controller in continuous mode */
+       value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
+       value |= WRITE_MUX;
+       tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS);
+
+       tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS);
+       tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);
+
+       value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
+       value &= ~WRITE_MUX;
+       tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS);
+
+       /*
+        * configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete
+        * raster, associate with display controller)
+        */
+       value = SOR_STATE_ASY_PIXELDEPTH_BPP_24_444 |
+               SOR_STATE_ASY_VSYNCPOL |
+               SOR_STATE_ASY_HSYNCPOL |
+               SOR_STATE_ASY_PROTOCOL_DP_A |
+               SOR_STATE_ASY_CRC_MODE_COMPLETE |
+               SOR_STATE_ASY_OWNER(dc->pipe + 1);
+       tegra_sor_writel(sor, value, SOR_STATE_1);
+
+       /*
+        * TODO: The video timing programming below doesn't seem to match the
+        * register definitions.
+        */
+
+       value = ((mode->vtotal & 0x7fff) << 16) | (mode->htotal & 0x7fff);
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE_1(0));
+
+       vse = mode->vsync_end - mode->vsync_start - 1;
+       hse = mode->hsync_end - mode->hsync_start - 1;
+
+       value = ((vse & 0x7fff) << 16) | (hse & 0x7fff);
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE_2(0));
+
+       vbe = vse + (mode->vsync_start - mode->vdisplay);
+       hbe = hse + (mode->hsync_start - mode->hdisplay);
+
+       value = ((vbe & 0x7fff) << 16) | (hbe & 0x7fff);
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE_3(0));
+
+       vbs = vbe + mode->vdisplay;
+       hbs = hbe + mode->hdisplay;
+
+       value = ((vbs & 0x7fff) << 16) | (hbs & 0x7fff);
+       tegra_sor_writel(sor, value, SOR_HEAD_STATE_4(0));
+
+       /* XXX interlaced mode */
+       tegra_sor_writel(sor, 0x00000001, SOR_HEAD_STATE_5(0));
+
+       /* CSTM (LVDS, link A/B, upper) */
+       value = SOR_CSTM_LVDS | SOR_CSTM_LINK_ACT_B | SOR_CSTM_LINK_ACT_B |
+               SOR_CSTM_UPPER;
+       tegra_sor_writel(sor, value, SOR_CSTM);
+
+       /* PWM setup */
+       err = tegra_sor_setup_pwm(sor, 250);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to setup PWM: %d\n", err);
+               return err;
+       }
+
+       value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+       value |= SOR_ENABLE;
+       tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+       tegra_sor_update(sor);
+
+       err = tegra_sor_attach(sor);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to attach SOR: %d\n", err);
+               return err;
+       }
+
+       err = tegra_sor_wakeup(sor);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to enable DC: %d\n", err);
+               return err;
+       }
+
+       sor->enabled = true;
+
+       return 0;
+}
+
+static int tegra_sor_detach(struct tegra_sor *sor)
+{
+       unsigned long value, timeout;
+
+       /* switch to safe mode */
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value &= ~SOR_SUPER_STATE_MODE_NORMAL;
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_super_update(sor);
+
+       timeout = jiffies + msecs_to_jiffies(250);
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_sor_readl(sor, SOR_PWR);
+               if (value & SOR_PWR_MODE_SAFE)
+                       break;
+       }
+
+       if ((value & SOR_PWR_MODE_SAFE) == 0)
+               return -ETIMEDOUT;
+
+       /* go to sleep */
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK;
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_super_update(sor);
+
+       /* detach */
+       value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+       value &= ~SOR_SUPER_STATE_ATTACHED;
+       tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+       tegra_sor_super_update(sor);
+
+       timeout = jiffies + msecs_to_jiffies(250);
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_sor_readl(sor, SOR_TEST);
+               if ((value & SOR_TEST_ATTACHED) == 0)
+                       break;
+
+               usleep_range(25, 100);
+       }
+
+       if ((value & SOR_TEST_ATTACHED) != 0)
+               return -ETIMEDOUT;
+
+       return 0;
+}
+
+static int tegra_sor_power_down(struct tegra_sor *sor)
+{
+       unsigned long value, timeout;
+       int err;
+
+       value = tegra_sor_readl(sor, SOR_PWR);
+       value &= ~SOR_PWR_NORMAL_STATE_PU;
+       value |= SOR_PWR_TRIGGER;
+       tegra_sor_writel(sor, value, SOR_PWR);
+
+       timeout = jiffies + msecs_to_jiffies(250);
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_sor_readl(sor, SOR_PWR);
+               if ((value & SOR_PWR_TRIGGER) == 0)
+                       return 0;
+
+               usleep_range(25, 100);
+       }
+
+       if ((value & SOR_PWR_TRIGGER) != 0)
+               return -ETIMEDOUT;
+
+       err = clk_set_parent(sor->clk, sor->clk_safe);
+       if (err < 0)
+               dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
+
+       value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+       value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
+                  SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2);
+       tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+
+       /* stop lane sequencer */
+       value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_DOWN |
+               SOR_LANE_SEQ_CTL_POWER_STATE_DOWN;
+       tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
+
+       timeout = jiffies + msecs_to_jiffies(250);
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
+               if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
+                       break;
+
+               usleep_range(25, 100);
+       }
+
+       if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0)
+               return -ETIMEDOUT;
+
+       value = tegra_sor_readl(sor, SOR_PLL_2);
+       value |= SOR_PLL_2_PORT_POWERDOWN;
+       tegra_sor_writel(sor, value, SOR_PLL_2);
+
+       usleep_range(20, 100);
+
+       value = tegra_sor_readl(sor, SOR_PLL_0);
+       value |= SOR_PLL_0_POWER_OFF;
+       value |= SOR_PLL_0_VCOPD;
+       tegra_sor_writel(sor, value, SOR_PLL_0);
+
+       value = tegra_sor_readl(sor, SOR_PLL_2);
+       value |= SOR_PLL_2_SEQ_PLLCAPPD;
+       value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
+       tegra_sor_writel(sor, value, SOR_PLL_2);
+
+       usleep_range(20, 100);
+
+       return 0;
+}
+
+static int tegra_output_sor_disable(struct tegra_output *output)
+{
+       struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
+       struct tegra_sor *sor = to_sor(output);
+       unsigned long value;
+       int err;
+
+       if (!sor->enabled)
+               return 0;
+
+       err = tegra_sor_detach(sor);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to detach SOR: %d\n", err);
+               return err;
+       }
+
+       tegra_sor_writel(sor, 0, SOR_STATE_1);
+       tegra_sor_update(sor);
+
+       /*
+        * The following accesses registers of the display controller, so make
+        * sure it's only executed when the output is attached to one.
+        */
+       if (dc) {
+               /*
+                * XXX: We can't do this here because it causes the SOR to go
+                * into an erroneous state and the output will look scrambled
+                * the next time it is enabled. Presumably this is because we
+                * should be doing this only on the next VBLANK. A possible
+                * solution would be to queue a "power-off" event to trigger
+                * this code to be run during the next VBLANK.
+                */
+               /*
+               value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+               value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+                          PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
+               tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+               */
+
+               value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+               value &= ~DISP_CTRL_MODE_MASK;
+               tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+               value &= ~SOR_ENABLE;
+               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+               tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+               tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+       }
+
+       err = tegra_sor_power_down(sor);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to power down SOR: %d\n", err);
+               return err;
+       }
+
+       if (sor->dpaux) {
+               err = tegra_dpaux_disable(sor->dpaux);
+               if (err < 0) {
+                       dev_err(sor->dev, "failed to disable DP: %d\n", err);
+                       return err;
+               }
+       }
+
+       err = tegra_io_rail_power_off(TEGRA_IO_RAIL_LVDS);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to power off I/O rail: %d\n", err);
+               return err;
+       }
+
+       reset_control_assert(sor->rst);
+       clk_disable_unprepare(sor->clk);
+
+       sor->enabled = false;
+
+       return 0;
+}
+
+static int tegra_output_sor_setup_clock(struct tegra_output *output,
+                                       struct clk *clk, unsigned long pclk)
+{
+       struct tegra_sor *sor = to_sor(output);
+       int err;
+
+       /* round to next MHz */
+       pclk = DIV_ROUND_UP(pclk / 2, 1000000) * 1000000;
+
+       err = clk_set_parent(clk, sor->clk_parent);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to set parent clock: %d\n", err);
+               return err;
+       }
+
+       err = clk_set_rate(sor->clk_parent, pclk);
+       if (err < 0) {
+               dev_err(sor->dev, "failed to set base clock rate to %lu Hz\n",
+                       pclk * 2);
+               return err;
+       }
+
+       return 0;
+}
+
+static int tegra_output_sor_check_mode(struct tegra_output *output,
+                                      struct drm_display_mode *mode,
+                                      enum drm_mode_status *status)
+{
+       /*
+        * FIXME: For now, always assume that the mode is okay.
+        */
+
+       *status = MODE_OK;
+
+       return 0;
+}
+
+static enum drm_connector_status
+tegra_output_sor_detect(struct tegra_output *output)
+{
+       struct tegra_sor *sor = to_sor(output);
+
+       if (sor->dpaux)
+               return tegra_dpaux_detect(sor->dpaux);
+
+       return connector_status_unknown;
+}
+
+static const struct tegra_output_ops sor_ops = {
+       .enable = tegra_output_sor_enable,
+       .disable = tegra_output_sor_disable,
+       .setup_clock = tegra_output_sor_setup_clock,
+       .check_mode = tegra_output_sor_check_mode,
+       .detect = tegra_output_sor_detect,
+};
+
+static int tegra_sor_init(struct host1x_client *client)
+{
+       struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+       struct tegra_sor *sor = host1x_client_to_sor(client);
+       int err;
+
+       if (!sor->dpaux)
+               return -ENODEV;
+
+       sor->output.type = TEGRA_OUTPUT_EDP;
+
+       sor->output.dev = sor->dev;
+       sor->output.ops = &sor_ops;
+
+       err = tegra_output_init(tegra->drm, &sor->output);
+       if (err < 0) {
+               dev_err(sor->dev, "output setup failed: %d\n", err);
+               return err;
+       }
+
+       if (sor->dpaux) {
+               err = tegra_dpaux_attach(sor->dpaux, &sor->output);
+               if (err < 0) {
+                       dev_err(sor->dev, "failed to attach DP: %d\n", err);
+                       return err;
+               }
+       }
+
+       return 0;
+}
+
+static int tegra_sor_exit(struct host1x_client *client)
+{
+       struct tegra_sor *sor = host1x_client_to_sor(client);
+       int err;
+
+       err = tegra_output_disable(&sor->output);
+       if (err < 0) {
+               dev_err(sor->dev, "output failed to disable: %d\n", err);
+               return err;
+       }
+
+       if (sor->dpaux) {
+               err = tegra_dpaux_detach(sor->dpaux);
+               if (err < 0) {
+                       dev_err(sor->dev, "failed to detach DP: %d\n", err);
+                       return err;
+               }
+       }
+
+       err = tegra_output_exit(&sor->output);
+       if (err < 0) {
+               dev_err(sor->dev, "output cleanup failed: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static const struct host1x_client_ops sor_client_ops = {
+       .init = tegra_sor_init,
+       .exit = tegra_sor_exit,
+};
+
+static int tegra_sor_probe(struct platform_device *pdev)
+{
+       struct device_node *np;
+       struct tegra_sor *sor;
+       struct resource *regs;
+       int err;
+
+       sor = devm_kzalloc(&pdev->dev, sizeof(*sor), GFP_KERNEL);
+       if (!sor)
+               return -ENOMEM;
+
+       sor->output.dev = sor->dev = &pdev->dev;
+
+       np = of_parse_phandle(pdev->dev.of_node, "nvidia,dpaux", 0);
+       if (np) {
+               sor->dpaux = tegra_dpaux_find_by_of_node(np);
+               of_node_put(np);
+
+               if (!sor->dpaux)
+                       return -EPROBE_DEFER;
+       }
+
+       err = tegra_output_probe(&sor->output);
+       if (err < 0)
+               return err;
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       sor->regs = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(sor->regs))
+               return PTR_ERR(sor->regs);
+
+       sor->rst = devm_reset_control_get(&pdev->dev, "sor");
+       if (IS_ERR(sor->rst))
+               return PTR_ERR(sor->rst);
+
+       sor->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(sor->clk))
+               return PTR_ERR(sor->clk);
+
+       sor->clk_parent = devm_clk_get(&pdev->dev, "parent");
+       if (IS_ERR(sor->clk_parent))
+               return PTR_ERR(sor->clk_parent);
+
+       err = clk_prepare_enable(sor->clk_parent);
+       if (err < 0)
+               return err;
+
+       sor->clk_safe = devm_clk_get(&pdev->dev, "safe");
+       if (IS_ERR(sor->clk_safe))
+               return PTR_ERR(sor->clk_safe);
+
+       err = clk_prepare_enable(sor->clk_safe);
+       if (err < 0)
+               return err;
+
+       sor->clk_dp = devm_clk_get(&pdev->dev, "dp");
+       if (IS_ERR(sor->clk_dp))
+               return PTR_ERR(sor->clk_dp);
+
+       err = clk_prepare_enable(sor->clk_dp);
+       if (err < 0)
+               return err;
+
+       INIT_LIST_HEAD(&sor->client.list);
+       sor->client.ops = &sor_client_ops;
+       sor->client.dev = &pdev->dev;
+
+       err = host1x_client_register(&sor->client);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to register host1x client: %d\n",
+                       err);
+               return err;
+       }
+
+       platform_set_drvdata(pdev, sor);
+
+       return 0;
+}
+
+static int tegra_sor_remove(struct platform_device *pdev)
+{
+       struct tegra_sor *sor = platform_get_drvdata(pdev);
+       int err;
+
+       err = host1x_client_unregister(&sor->client);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
+                       err);
+               return err;
+       }
+
+       clk_disable_unprepare(sor->clk_parent);
+       clk_disable_unprepare(sor->clk_safe);
+       clk_disable_unprepare(sor->clk_dp);
+       clk_disable_unprepare(sor->clk);
+
+       return 0;
+}
+
+static const struct of_device_id tegra_sor_of_match[] = {
+       { .compatible = "nvidia,tegra124-sor", },
+       { },
+};
+
+struct platform_driver tegra_sor_driver = {
+       .driver = {
+               .name = "tegra-sor",
+               .of_match_table = tegra_sor_of_match,
+       },
+       .probe = tegra_sor_probe,
+       .remove = tegra_sor_remove,
+};
diff --git a/drivers/gpu/drm/tegra/sor.h b/drivers/gpu/drm/tegra/sor.h
new file mode 100644 (file)
index 0000000..f4156d5
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * 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 DRM_TEGRA_SOR_H
+#define DRM_TEGRA_SOR_H
+
+#define SOR_CTXSW 0x00
+
+#define SOR_SUPER_STATE_0 0x01
+
+#define SOR_SUPER_STATE_1 0x02
+#define  SOR_SUPER_STATE_ATTACHED              (1 << 3)
+#define  SOR_SUPER_STATE_MODE_NORMAL           (1 << 2)
+#define  SOR_SUPER_STATE_HEAD_MODE_MASK                (3 << 0)
+#define  SOR_SUPER_STATE_HEAD_MODE_AWAKE       (2 << 0)
+#define  SOR_SUPER_STATE_HEAD_MODE_SNOOZE      (1 << 0)
+#define  SOR_SUPER_STATE_HEAD_MODE_SLEEP       (0 << 0)
+
+#define SOR_STATE_0 0x03
+
+#define SOR_STATE_1 0x04
+#define  SOR_STATE_ASY_PIXELDEPTH_MASK         (0xf << 17)
+#define  SOR_STATE_ASY_PIXELDEPTH_BPP_18_444   (0x2 << 17)
+#define  SOR_STATE_ASY_PIXELDEPTH_BPP_24_444   (0x5 << 17)
+#define  SOR_STATE_ASY_VSYNCPOL                        (1 << 13)
+#define  SOR_STATE_ASY_HSYNCPOL                        (1 << 12)
+#define  SOR_STATE_ASY_PROTOCOL_MASK           (0xf << 8)
+#define  SOR_STATE_ASY_PROTOCOL_CUSTOM         (0xf << 8)
+#define  SOR_STATE_ASY_PROTOCOL_DP_A           (0x8 << 8)
+#define  SOR_STATE_ASY_PROTOCOL_DP_B           (0x9 << 8)
+#define  SOR_STATE_ASY_PROTOCOL_LVDS           (0x0 << 8)
+#define  SOR_STATE_ASY_CRC_MODE_MASK           (0x3 << 6)
+#define  SOR_STATE_ASY_CRC_MODE_NON_ACTIVE     (0x2 << 6)
+#define  SOR_STATE_ASY_CRC_MODE_COMPLETE       (0x1 << 6)
+#define  SOR_STATE_ASY_CRC_MODE_ACTIVE         (0x0 << 6)
+#define  SOR_STATE_ASY_OWNER(x)                        (((x) & 0xf) << 0)
+
+#define SOR_HEAD_STATE_0(x) (0x05 + (x))
+#define SOR_HEAD_STATE_1(x) (0x07 + (x))
+#define SOR_HEAD_STATE_2(x) (0x09 + (x))
+#define SOR_HEAD_STATE_3(x) (0x0b + (x))
+#define SOR_HEAD_STATE_4(x) (0x0d + (x))
+#define SOR_HEAD_STATE_5(x) (0x0f + (x))
+#define SOR_CRC_CNTRL 0x11
+#define SOR_DP_DEBUG_MVID 0x12
+
+#define SOR_CLK_CNTRL 0x13
+#define  SOR_CLK_CNTRL_DP_LINK_SPEED_MASK      (0x1f << 2)
+#define  SOR_CLK_CNTRL_DP_LINK_SPEED(x)                (((x) & 0x1f) << 2)
+#define  SOR_CLK_CNTRL_DP_LINK_SPEED_G1_62     (0x06 << 2)
+#define  SOR_CLK_CNTRL_DP_LINK_SPEED_G2_70     (0x0a << 2)
+#define  SOR_CLK_CNTRL_DP_LINK_SPEED_G5_40     (0x14 << 2)
+#define  SOR_CLK_CNTRL_DP_CLK_SEL_MASK         (3 << 0)
+#define  SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_PCLK  (0 << 0)
+#define  SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_PCLK    (1 << 0)
+#define  SOR_CLK_CNTRL_DP_CLK_SEL_SINGLE_DPCLK (2 << 0)
+#define  SOR_CLK_CNTRL_DP_CLK_SEL_DIFF_DPCLK   (3 << 0)
+
+#define SOR_CAP 0x14
+
+#define SOR_PWR 0x15
+#define  SOR_PWR_TRIGGER                       (1 << 31)
+#define  SOR_PWR_MODE_SAFE                     (1 << 28)
+#define  SOR_PWR_NORMAL_STATE_PU               (1 << 0)
+
+#define SOR_TEST 0x16
+#define  SOR_TEST_ATTACHED                     (1 << 10)
+#define  SOR_TEST_HEAD_MODE_MASK               (3 << 8)
+#define  SOR_TEST_HEAD_MODE_AWAKE              (2 << 8)
+
+#define SOR_PLL_0 0x17
+#define  SOR_PLL_0_ICHPMP_MASK                 (0xf << 24)
+#define  SOR_PLL_0_ICHPMP(x)                   (((x) & 0xf) << 24)
+#define  SOR_PLL_0_VCOCAP_MASK                 (0xf << 8)
+#define  SOR_PLL_0_VCOCAP(x)                   (((x) & 0xf) << 8)
+#define  SOR_PLL_0_VCOCAP_RST                  SOR_PLL_0_VCOCAP(3)
+#define  SOR_PLL_0_PLLREG_MASK                 (0x3 << 6)
+#define  SOR_PLL_0_PLLREG_LEVEL(x)             (((x) & 0x3) << 6)
+#define  SOR_PLL_0_PLLREG_LEVEL_V25            SOR_PLL_0_PLLREG_LEVEL(0)
+#define  SOR_PLL_0_PLLREG_LEVEL_V15            SOR_PLL_0_PLLREG_LEVEL(1)
+#define  SOR_PLL_0_PLLREG_LEVEL_V35            SOR_PLL_0_PLLREG_LEVEL(2)
+#define  SOR_PLL_0_PLLREG_LEVEL_V45            SOR_PLL_0_PLLREG_LEVEL(3)
+#define  SOR_PLL_0_PULLDOWN                    (1 << 5)
+#define  SOR_PLL_0_RESISTOR_EXT                        (1 << 4)
+#define  SOR_PLL_0_VCOPD                       (1 << 2)
+#define  SOR_PLL_0_POWER_OFF                   (1 << 0)
+
+#define SOR_PLL_1 0x18
+/* XXX: read-only bit? */
+#define  SOR_PLL_1_TERM_COMPOUT                        (1 << 15)
+#define  SOR_PLL_1_TMDS_TERM                   (1 << 8)
+
+#define SOR_PLL_2 0x19
+#define  SOR_PLL_2_LVDS_ENABLE                 (1 << 25)
+#define  SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE                (1 << 24)
+#define  SOR_PLL_2_PORT_POWERDOWN              (1 << 23)
+#define  SOR_PLL_2_BANDGAP_POWERDOWN           (1 << 22)
+#define  SOR_PLL_2_POWERDOWN_OVERRIDE          (1 << 18)
+#define  SOR_PLL_2_SEQ_PLLCAPPD                        (1 << 17)
+
+#define SOR_PLL_3 0x1a
+#define  SOR_PLL_3_PLL_VDD_MODE_V1_8 (0 << 13)
+#define  SOR_PLL_3_PLL_VDD_MODE_V3_3 (1 << 13)
+
+#define SOR_CSTM 0x1b
+#define  SOR_CSTM_LVDS                         (1 << 16)
+#define  SOR_CSTM_LINK_ACT_B                   (1 << 15)
+#define  SOR_CSTM_LINK_ACT_A                   (1 << 14)
+#define  SOR_CSTM_UPPER                                (1 << 11)
+
+#define SOR_LVDS 0x1c
+#define SOR_CRC_A 0x1d
+#define SOR_CRC_B 0x1e
+#define SOR_BLANK 0x1f
+#define SOR_SEQ_CTL 0x20
+
+#define SOR_LANE_SEQ_CTL 0x21
+#define  SOR_LANE_SEQ_CTL_TRIGGER              (1 << 31)
+#define  SOR_LANE_SEQ_CTL_SEQUENCE_UP          (0 << 20)
+#define  SOR_LANE_SEQ_CTL_SEQUENCE_DOWN                (1 << 20)
+#define  SOR_LANE_SEQ_CTL_POWER_STATE_UP       (0 << 16)
+#define  SOR_LANE_SEQ_CTL_POWER_STATE_DOWN     (1 << 16)
+
+#define SOR_SEQ_INST(x) (0x22 + (x))
+
+#define SOR_PWM_DIV 0x32
+#define  SOR_PWM_DIV_MASK                      0xffffff
+
+#define SOR_PWM_CTL 0x33
+#define  SOR_PWM_CTL_TRIGGER                   (1 << 31)
+#define  SOR_PWM_CTL_CLK_SEL                   (1 << 30)
+#define  SOR_PWM_CTL_DUTY_CYCLE_MASK           0xffffff
+
+#define SOR_VCRC_A_0 0x34
+#define SOR_VCRC_A_1 0x35
+#define SOR_VCRC_B_0 0x36
+#define SOR_VCRC_B_1 0x37
+#define SOR_CCRC_A_0 0x38
+#define SOR_CCRC_A_1 0x39
+#define SOR_CCRC_B_0 0x3a
+#define SOR_CCRC_B_1 0x3b
+#define SOR_EDATA_A_0 0x3c
+#define SOR_EDATA_A_1 0x3d
+#define SOR_EDATA_B_0 0x3e
+#define SOR_EDATA_B_1 0x3f
+#define SOR_COUNT_A_0 0x40
+#define SOR_COUNT_A_1 0x41
+#define SOR_COUNT_B_0 0x42
+#define SOR_COUNT_B_1 0x43
+#define SOR_DEBUG_A_0 0x44
+#define SOR_DEBUG_A_1 0x45
+#define SOR_DEBUG_B_0 0x46
+#define SOR_DEBUG_B_1 0x47
+#define SOR_TRIG 0x48
+#define SOR_MSCHECK 0x49
+#define SOR_XBAR_CTRL 0x4a
+#define SOR_XBAR_POL 0x4b
+
+#define SOR_DP_LINKCTL_0 0x4c
+#define  SOR_DP_LINKCTL_LANE_COUNT_MASK                (0x1f << 16)
+#define  SOR_DP_LINKCTL_LANE_COUNT(x)          (((1 << (x)) - 1) << 16)
+#define  SOR_DP_LINKCTL_ENHANCED_FRAME         (1 << 14)
+#define  SOR_DP_LINKCTL_TU_SIZE_MASK           (0x7f << 2)
+#define  SOR_DP_LINKCTL_TU_SIZE(x)             (((x) & 0x7f) << 2)
+#define  SOR_DP_LINKCTL_ENABLE                 (1 << 0)
+
+#define SOR_DP_LINKCTL_1 0x4d
+
+#define SOR_LANE_DRIVE_CURRENT_0 0x4e
+#define SOR_LANE_DRIVE_CURRENT_1 0x4f
+#define SOR_LANE4_DRIVE_CURRENT_0 0x50
+#define SOR_LANE4_DRIVE_CURRENT_1 0x51
+#define  SOR_LANE_DRIVE_CURRENT_LANE3(x) (((x) & 0xff) << 24)
+#define  SOR_LANE_DRIVE_CURRENT_LANE2(x) (((x) & 0xff) << 16)
+#define  SOR_LANE_DRIVE_CURRENT_LANE1(x) (((x) & 0xff) << 8)
+#define  SOR_LANE_DRIVE_CURRENT_LANE0(x) (((x) & 0xff) << 0)
+
+#define SOR_LANE_PREEMPHASIS_0 0x52
+#define SOR_LANE_PREEMPHASIS_1 0x53
+#define SOR_LANE4_PREEMPHASIS_0 0x54
+#define SOR_LANE4_PREEMPHASIS_1 0x55
+#define  SOR_LANE_PREEMPHASIS_LANE3(x) (((x) & 0xff) << 24)
+#define  SOR_LANE_PREEMPHASIS_LANE2(x) (((x) & 0xff) << 16)
+#define  SOR_LANE_PREEMPHASIS_LANE1(x) (((x) & 0xff) << 8)
+#define  SOR_LANE_PREEMPHASIS_LANE0(x) (((x) & 0xff) << 0)
+
+#define SOR_LANE_POST_CURSOR_0 0x56
+#define SOR_LANE_POST_CURSOR_1 0x57
+#define  SOR_LANE_POST_CURSOR_LANE3(x) (((x) & 0xff) << 24)
+#define  SOR_LANE_POST_CURSOR_LANE2(x) (((x) & 0xff) << 16)
+#define  SOR_LANE_POST_CURSOR_LANE1(x) (((x) & 0xff) << 8)
+#define  SOR_LANE_POST_CURSOR_LANE0(x) (((x) & 0xff) << 0)
+
+#define SOR_DP_CONFIG_0 0x58
+#define SOR_DP_CONFIG_DISPARITY_NEGATIVE       (1 << 31)
+#define SOR_DP_CONFIG_ACTIVE_SYM_ENABLE                (1 << 26)
+#define SOR_DP_CONFIG_ACTIVE_SYM_POLARITY      (1 << 24)
+#define SOR_DP_CONFIG_ACTIVE_SYM_FRAC_MASK     (0xf << 16)
+#define SOR_DP_CONFIG_ACTIVE_SYM_FRAC(x)       (((x) & 0xf) << 16)
+#define SOR_DP_CONFIG_ACTIVE_SYM_COUNT_MASK    (0x7f << 8)
+#define SOR_DP_CONFIG_ACTIVE_SYM_COUNT(x)      (((x) & 0x7f) << 8)
+#define SOR_DP_CONFIG_WATERMARK_MASK   (0x3f << 0)
+#define SOR_DP_CONFIG_WATERMARK(x)     (((x) & 0x3f) << 0)
+
+#define SOR_DP_CONFIG_1 0x59
+#define SOR_DP_MN_0 0x5a
+#define SOR_DP_MN_1 0x5b
+
+#define SOR_DP_PADCTL_0 0x5c
+#define  SOR_DP_PADCTL_PAD_CAL_PD      (1 << 23)
+#define  SOR_DP_PADCTL_TX_PU_ENABLE    (1 << 22)
+#define  SOR_DP_PADCTL_TX_PU_MASK      (0xff << 8)
+#define  SOR_DP_PADCTL_TX_PU(x)                (((x) & 0xff) << 8)
+#define  SOR_DP_PADCTL_CM_TXD_3                (1 << 7)
+#define  SOR_DP_PADCTL_CM_TXD_2                (1 << 6)
+#define  SOR_DP_PADCTL_CM_TXD_1                (1 << 5)
+#define  SOR_DP_PADCTL_CM_TXD_0                (1 << 4)
+#define  SOR_DP_PADCTL_PD_TXD_3                (1 << 3)
+#define  SOR_DP_PADCTL_PD_TXD_0                (1 << 2)
+#define  SOR_DP_PADCTL_PD_TXD_1                (1 << 1)
+#define  SOR_DP_PADCTL_PD_TXD_2                (1 << 0)
+
+#define SOR_DP_PADCTL_1 0x5d
+
+#define SOR_DP_DEBUG_0 0x5e
+#define SOR_DP_DEBUG_1 0x5f
+
+#define SOR_DP_SPARE_0 0x60
+#define  SOR_DP_SPARE_MACRO_SOR_CLK    (1 << 2)
+#define  SOR_DP_SPARE_PANEL_INTERNAL   (1 << 1)
+#define  SOR_DP_SPARE_SEQ_ENABLE       (1 << 0)
+
+#define SOR_DP_SPARE_1 0x61
+#define SOR_DP_AUDIO_CTRL 0x62
+
+#define SOR_DP_AUDIO_HBLANK_SYMBOLS 0x63
+#define SOR_DP_AUDIO_HBLANK_SYMBOLS_MASK (0x01ffff << 0)
+
+#define SOR_DP_AUDIO_VBLANK_SYMBOLS 0x64
+#define SOR_DP_AUDIO_VBLANK_SYMBOLS_MASK (0x1fffff << 0)
+
+#define SOR_DP_GENERIC_INFOFRAME_HEADER 0x65
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_0 0x66
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_1 0x67
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_2 0x68
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_3 0x69
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_4 0x6a
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_5 0x6b
+#define SOR_DP_GENERIC_INFOFRAME_SUBPACK_6 0x6c
+
+#define SOR_DP_TPG 0x6d
+#define  SOR_DP_TPG_CHANNEL_CODING     (1 << 6)
+#define  SOR_DP_TPG_SCRAMBLER_MASK     (3 << 4)
+#define  SOR_DP_TPG_SCRAMBLER_FIBONACCI        (2 << 4)
+#define  SOR_DP_TPG_SCRAMBLER_GALIOS   (1 << 4)
+#define  SOR_DP_TPG_SCRAMBLER_NONE     (0 << 4)
+#define  SOR_DP_TPG_PATTERN_MASK       (0xf << 0)
+#define  SOR_DP_TPG_PATTERN_HBR2       (0x8 << 0)
+#define  SOR_DP_TPG_PATTERN_CSTM       (0x7 << 0)
+#define  SOR_DP_TPG_PATTERN_PRBS7      (0x6 << 0)
+#define  SOR_DP_TPG_PATTERN_SBLERRRATE (0x5 << 0)
+#define  SOR_DP_TPG_PATTERN_D102       (0x4 << 0)
+#define  SOR_DP_TPG_PATTERN_TRAIN3     (0x3 << 0)
+#define  SOR_DP_TPG_PATTERN_TRAIN2     (0x2 << 0)
+#define  SOR_DP_TPG_PATTERN_TRAIN1     (0x1 << 0)
+#define  SOR_DP_TPG_PATTERN_NONE       (0x0 << 0)
+
+#define SOR_DP_TPG_CONFIG 0x6e
+#define SOR_DP_LQ_CSTM_0 0x6f
+#define SOR_DP_LQ_CSTM_1 0x70
+#define SOR_DP_LQ_CSTM_2 0x71
+
+#endif
index d36efc1..d642d4a 100644 (file)
@@ -74,7 +74,7 @@ static void set_scanout(struct drm_crtc *crtc, int n)
                drm_flip_work_queue(&tilcdc_crtc->unref_work, tilcdc_crtc->scanout[n]);
                drm_flip_work_commit(&tilcdc_crtc->unref_work, priv->wq);
        }
-       tilcdc_crtc->scanout[n] = crtc->fb;
+       tilcdc_crtc->scanout[n] = crtc->primary->fb;
        drm_framebuffer_reference(tilcdc_crtc->scanout[n]);
        tilcdc_crtc->dirty &= ~stat[n];
        pm_runtime_put_sync(dev->dev);
@@ -84,7 +84,7 @@ static void update_scanout(struct drm_crtc *crtc)
 {
        struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
        struct drm_device *dev = crtc->dev;
-       struct drm_framebuffer *fb = crtc->fb;
+       struct drm_framebuffer *fb = crtc->primary->fb;
        struct drm_gem_cma_object *gem;
        unsigned int depth, bpp;
 
@@ -159,7 +159,7 @@ static int tilcdc_crtc_page_flip(struct drm_crtc *crtc,
                return -EBUSY;
        }
 
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
        tilcdc_crtc->event = event;
        update_scanout(crtc);
 
@@ -339,7 +339,7 @@ static int tilcdc_crtc_mode_set(struct drm_crtc *crtc,
        if (priv->rev == 2) {
                unsigned int depth, bpp;
 
-               drm_fb_get_bpp_depth(crtc->fb->pixel_format, &depth, &bpp);
+               drm_fb_get_bpp_depth(crtc->primary->fb->pixel_format, &depth, &bpp);
                switch (bpp) {
                case 16:
                        break;
index 214b799..4ab9f71 100644 (file)
@@ -412,7 +412,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
        int ret;
 
        spin_lock(&glob->lru_lock);
-       ret = ttm_bo_reserve_nolru(bo, false, true, false, 0);
+       ret = __ttm_bo_reserve(bo, false, true, false, 0);
 
        spin_lock(&bdev->fence_lock);
        (void) ttm_bo_wait(bo, false, false, true);
@@ -443,7 +443,7 @@ static void ttm_bo_cleanup_refs_or_queue(struct ttm_buffer_object *bo)
                        ttm_bo_add_to_lru(bo);
                }
 
-               ww_mutex_unlock(&bo->resv->lock);
+               __ttm_bo_unreserve(bo);
        }
 
        kref_get(&bo->list_kref);
@@ -494,7 +494,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
                sync_obj = driver->sync_obj_ref(bo->sync_obj);
                spin_unlock(&bdev->fence_lock);
 
-               ww_mutex_unlock(&bo->resv->lock);
+               __ttm_bo_unreserve(bo);
                spin_unlock(&glob->lru_lock);
 
                ret = driver->sync_obj_wait(sync_obj, false, interruptible);
@@ -514,7 +514,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
                        return ret;
 
                spin_lock(&glob->lru_lock);
-               ret = ttm_bo_reserve_nolru(bo, false, true, false, 0);
+               ret = __ttm_bo_reserve(bo, false, true, false, 0);
 
                /*
                 * We raced, and lost, someone else holds the reservation now,
@@ -532,7 +532,7 @@ static int ttm_bo_cleanup_refs_and_unlock(struct ttm_buffer_object *bo,
                spin_unlock(&bdev->fence_lock);
 
        if (ret || unlikely(list_empty(&bo->ddestroy))) {
-               ww_mutex_unlock(&bo->resv->lock);
+               __ttm_bo_unreserve(bo);
                spin_unlock(&glob->lru_lock);
                return ret;
        }
@@ -577,11 +577,11 @@ static int ttm_bo_delayed_delete(struct ttm_bo_device *bdev, bool remove_all)
                        kref_get(&nentry->list_kref);
                }
 
-               ret = ttm_bo_reserve_nolru(entry, false, true, false, 0);
+               ret = __ttm_bo_reserve(entry, false, true, false, 0);
                if (remove_all && ret) {
                        spin_unlock(&glob->lru_lock);
-                       ret = ttm_bo_reserve_nolru(entry, false, false,
-                                                  false, 0);
+                       ret = __ttm_bo_reserve(entry, false, false,
+                                              false, 0);
                        spin_lock(&glob->lru_lock);
                }
 
@@ -726,7 +726,7 @@ static int ttm_mem_evict_first(struct ttm_bo_device *bdev,
 
        spin_lock(&glob->lru_lock);
        list_for_each_entry(bo, &man->lru, lru) {
-               ret = ttm_bo_reserve_nolru(bo, false, true, false, 0);
+               ret = __ttm_bo_reserve(bo, false, true, false, 0);
                if (!ret)
                        break;
        }
@@ -1451,6 +1451,7 @@ EXPORT_SYMBOL(ttm_bo_device_release);
 int ttm_bo_device_init(struct ttm_bo_device *bdev,
                       struct ttm_bo_global *glob,
                       struct ttm_bo_driver *driver,
+                      struct address_space *mapping,
                       uint64_t file_page_offset,
                       bool need_dma32)
 {
@@ -1472,7 +1473,7 @@ int ttm_bo_device_init(struct ttm_bo_device *bdev,
                                    0x10000000);
        INIT_DELAYED_WORK(&bdev->wq, ttm_bo_delayed_workqueue);
        INIT_LIST_HEAD(&bdev->ddestroy);
-       bdev->dev_mapping = NULL;
+       bdev->dev_mapping = mapping;
        bdev->glob = glob;
        bdev->need_dma32 = need_dma32;
        bdev->val_seq = 0;
@@ -1629,7 +1630,7 @@ static int ttm_bo_swapout(struct ttm_mem_shrink *shrink)
 
        spin_lock(&glob->lru_lock);
        list_for_each_entry(bo, &glob->swap_lru, swap) {
-               ret = ttm_bo_reserve_nolru(bo, false, true, false, 0);
+               ret = __ttm_bo_reserve(bo, false, true, false, 0);
                if (!ret)
                        break;
        }
@@ -1696,7 +1697,7 @@ out:
         * already swapped buffer.
         */
 
-       ww_mutex_unlock(&bo->resv->lock);
+       __ttm_bo_unreserve(bo);
        kref_put(&bo->list_kref, ttm_bo_release_list);
        return ret;
 }
@@ -1730,10 +1731,10 @@ int ttm_bo_wait_unreserved(struct ttm_buffer_object *bo)
                return -ERESTARTSYS;
        if (!ww_mutex_is_locked(&bo->resv->lock))
                goto out_unlock;
-       ret = ttm_bo_reserve_nolru(bo, true, false, false, NULL);
+       ret = __ttm_bo_reserve(bo, true, false, false, NULL);
        if (unlikely(ret != 0))
                goto out_unlock;
-       ww_mutex_unlock(&bo->resv->lock);
+       __ttm_bo_unreserve(bo);
 
 out_unlock:
        mutex_unlock(&bo->wu_mutex);
index c58eba3..bd850c9 100644 (file)
@@ -55,6 +55,7 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
        struct ttm_range_manager *rman = (struct ttm_range_manager *) man->priv;
        struct drm_mm *mm = &rman->mm;
        struct drm_mm_node *node = NULL;
+       enum drm_mm_allocator_flags aflags = DRM_MM_CREATE_DEFAULT;
        unsigned long lpfn;
        int ret;
 
@@ -66,11 +67,15 @@ static int ttm_bo_man_get_node(struct ttm_mem_type_manager *man,
        if (!node)
                return -ENOMEM;
 
+       if (bo->mem.placement & TTM_PL_FLAG_TOPDOWN)
+               aflags = DRM_MM_CREATE_TOP;
+
        spin_lock(&rman->lock);
-       ret = drm_mm_insert_node_in_range(mm, node, mem->num_pages,
-                                         mem->page_alignment,
+       ret = drm_mm_insert_node_in_range_generic(mm, node, mem->num_pages,
+                                         mem->page_alignment, 0,
                                          placement->fpfn, lpfn,
-                                         DRM_MM_SEARCH_BEST);
+                                         DRM_MM_SEARCH_BEST,
+                                         aflags);
        spin_unlock(&rman->lock);
 
        if (unlikely(ret)) {
index 479e941..e8dac87 100644 (file)
@@ -46,7 +46,7 @@ static void ttm_eu_backoff_reservation_locked(struct list_head *list)
                        ttm_bo_add_to_lru(bo);
                        entry->removed = false;
                }
-               ww_mutex_unlock(&bo->resv->lock);
+               __ttm_bo_unreserve(bo);
        }
 }
 
@@ -140,8 +140,8 @@ retry:
                if (entry->reserved)
                        continue;
 
-               ret = ttm_bo_reserve_nolru(bo, true, (ticket == NULL), true,
-                                          ticket);
+               ret = __ttm_bo_reserve(bo, true, (ticket == NULL), true,
+                                      ticket);
 
                if (ret == -EDEADLK) {
                        /* uh oh, we lost out, drop every reservation and try
@@ -224,7 +224,7 @@ void ttm_eu_fence_buffer_objects(struct ww_acquire_ctx *ticket,
                entry->old_sync_obj = bo->sync_obj;
                bo->sync_obj = driver->sync_obj_ref(sync_obj);
                ttm_bo_add_to_lru(bo);
-               ww_mutex_unlock(&bo->resv->lock);
+               __ttm_bo_unreserve(bo);
                entry->reserved = false;
        }
        spin_unlock(&bdev->fence_lock);
index 53b51c4..d2a0533 100644 (file)
@@ -270,6 +270,52 @@ ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key)
 }
 EXPORT_SYMBOL(ttm_base_object_lookup_for_ref);
 
+/**
+ * ttm_ref_object_exists - Check whether a caller has a valid ref object
+ * (has opened) a base object.
+ *
+ * @tfile: Pointer to a struct ttm_object_file identifying the caller.
+ * @base: Pointer to a struct base object.
+ *
+ * Checks wether the caller identified by @tfile has put a valid USAGE
+ * reference object on the base object identified by @base.
+ */
+bool ttm_ref_object_exists(struct ttm_object_file *tfile,
+                          struct ttm_base_object *base)
+{
+       struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
+       struct drm_hash_item *hash;
+       struct ttm_ref_object *ref;
+
+       rcu_read_lock();
+       if (unlikely(drm_ht_find_item_rcu(ht, base->hash.key, &hash) != 0))
+               goto out_false;
+
+       /*
+        * Verify that the ref object is really pointing to our base object.
+        * Our base object could actually be dead, and the ref object pointing
+        * to another base object with the same handle.
+        */
+       ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
+       if (unlikely(base != ref->obj))
+               goto out_false;
+
+       /*
+        * Verify that the ref->obj pointer was actually valid!
+        */
+       rmb();
+       if (unlikely(atomic_read(&ref->kref.refcount) == 0))
+               goto out_false;
+
+       rcu_read_unlock();
+       return true;
+
+ out_false:
+       rcu_read_unlock();
+       return false;
+}
+EXPORT_SYMBOL(ttm_ref_object_exists);
+
 int ttm_ref_object_add(struct ttm_object_file *tfile,
                       struct ttm_base_object *base,
                       enum ttm_ref_type ref_type, bool *existed)
index dbadd49..3771763 100644 (file)
@@ -421,7 +421,7 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
                                  clips[i].x2 - clips[i].x1,
                                  clips[i].y2 - clips[i].y1);
                if (ret)
-                       goto unlock;
+                       break;
        }
 
        if (ufb->obj->base.import_attach) {
index 0394811..c041cd7 100644 (file)
@@ -60,7 +60,7 @@ int udl_dumb_create(struct drm_file *file,
                    struct drm_device *dev,
                    struct drm_mode_create_dumb *args)
 {
-       args->pitch = args->width * ((args->bpp + 1) / 8);
+       args->pitch = args->width * DIV_ROUND_UP(args->bpp, 8);
        args->size = args->pitch * args->height;
        return udl_gem_create(file, dev,
                              args->size, &args->handle);
index 2ae1eb7..cddc4fc 100644 (file)
@@ -310,7 +310,7 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
 
 {
        struct drm_device *dev = crtc->dev;
-       struct udl_framebuffer *ufb = to_udl_fb(crtc->fb);
+       struct udl_framebuffer *ufb = to_udl_fb(crtc->primary->fb);
        struct udl_device *udl = dev->dev_private;
        char *buf;
        char *wrptr;
index 1e80152..8bb26dc 100644 (file)
@@ -117,10 +117,10 @@ static void vmw_hw_context_destroy(struct vmw_resource *res)
                (void) vmw_context_binding_state_kill
                        (&container_of(res, struct vmw_user_context, res)->cbs);
                (void) vmw_gb_context_destroy(res);
+               mutex_unlock(&dev_priv->binding_mutex);
                if (dev_priv->pinned_bo != NULL &&
                    !dev_priv->query_cid_valid)
                        __vmw_execbuf_release_pinned_bo(dev_priv, NULL);
-               mutex_unlock(&dev_priv->binding_mutex);
                mutex_unlock(&dev_priv->cmdbuf_mutex);
                return;
        }
@@ -462,7 +462,6 @@ int vmw_context_define_ioctl(struct drm_device *dev, void *data,
        struct vmw_resource *tmp;
        struct drm_vmw_context_arg *arg = (struct drm_vmw_context_arg *)data;
        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        int ret;
 
 
@@ -474,7 +473,7 @@ int vmw_context_define_ioctl(struct drm_device *dev, void *data,
        if (unlikely(vmw_user_context_size == 0))
                vmw_user_context_size = ttm_round_pot(sizeof(*ctx)) + 128;
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
 
@@ -521,7 +520,7 @@ int vmw_context_define_ioctl(struct drm_device *dev, void *data,
 out_err:
        vmw_resource_unreference(&res);
 out_unlock:
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
        return ret;
 
 }
index a758402..70ddce8 100644 (file)
@@ -52,11 +52,10 @@ int vmw_dmabuf_to_placement(struct vmw_private *dev_priv,
                            struct ttm_placement *placement,
                            bool interruptible)
 {
-       struct vmw_master *vmaster = dev_priv->active_master;
        struct ttm_buffer_object *bo = &buf->base;
        int ret;
 
-       ret = ttm_write_lock(&vmaster->lock, interruptible);
+       ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
        if (unlikely(ret != 0))
                return ret;
 
@@ -71,7 +70,7 @@ int vmw_dmabuf_to_placement(struct vmw_private *dev_priv,
        ttm_bo_unreserve(bo);
 
 err:
-       ttm_write_unlock(&vmaster->lock);
+       ttm_write_unlock(&dev_priv->reservation_sem);
        return ret;
 }
 
@@ -95,12 +94,11 @@ int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv,
                              struct vmw_dma_buffer *buf,
                              bool pin, bool interruptible)
 {
-       struct vmw_master *vmaster = dev_priv->active_master;
        struct ttm_buffer_object *bo = &buf->base;
        struct ttm_placement *placement;
        int ret;
 
-       ret = ttm_write_lock(&vmaster->lock, interruptible);
+       ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
        if (unlikely(ret != 0))
                return ret;
 
@@ -143,7 +141,7 @@ int vmw_dmabuf_to_vram_or_gmr(struct vmw_private *dev_priv,
 err_unreserve:
        ttm_bo_unreserve(bo);
 err:
-       ttm_write_unlock(&vmaster->lock);
+       ttm_write_unlock(&dev_priv->reservation_sem);
        return ret;
 }
 
@@ -198,7 +196,6 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv,
                                struct vmw_dma_buffer *buf,
                                bool pin, bool interruptible)
 {
-       struct vmw_master *vmaster = dev_priv->active_master;
        struct ttm_buffer_object *bo = &buf->base;
        struct ttm_placement placement;
        int ret = 0;
@@ -209,7 +206,7 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv,
                placement = vmw_vram_placement;
        placement.lpfn = bo->num_pages;
 
-       ret = ttm_write_lock(&vmaster->lock, interruptible);
+       ret = ttm_write_lock(&dev_priv->reservation_sem, interruptible);
        if (unlikely(ret != 0))
                return ret;
 
@@ -232,7 +229,7 @@ int vmw_dmabuf_to_start_of_vram(struct vmw_private *dev_priv,
 
        ttm_bo_unreserve(bo);
 err_unlock:
-       ttm_write_unlock(&vmaster->lock);
+       ttm_write_unlock(&dev_priv->reservation_sem);
 
        return ret;
 }
index 0083cbf..4a223bb 100644 (file)
 
 static const struct drm_ioctl_desc vmw_ioctls[] = {
        VMW_IOCTL_DEF(VMW_GET_PARAM, vmw_getparam_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_ALLOC_DMABUF, vmw_dmabuf_alloc_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_UNREF_DMABUF, vmw_dmabuf_unref_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_CURSOR_BYPASS,
                      vmw_kms_cursor_bypass_ioctl,
                      DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
@@ -159,29 +159,28 @@ static const struct drm_ioctl_desc vmw_ioctls[] = {
                      DRM_MASTER | DRM_CONTROL_ALLOW | DRM_UNLOCKED),
 
        VMW_IOCTL_DEF(VMW_CREATE_CONTEXT, vmw_context_define_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_UNREF_CONTEXT, vmw_context_destroy_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_CREATE_SURFACE, vmw_surface_define_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_UNREF_SURFACE, vmw_surface_destroy_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_REF_SURFACE, vmw_surface_reference_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_EXECBUF, vmw_execbuf_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_FENCE_WAIT, vmw_fence_obj_wait_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_FENCE_SIGNALED,
                      vmw_fence_obj_signaled_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_FENCE_UNREF, vmw_fence_obj_unref_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
-       VMW_IOCTL_DEF(VMW_FENCE_EVENT,
-                     vmw_fence_event_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_UNLOCKED | DRM_RENDER_ALLOW),
+       VMW_IOCTL_DEF(VMW_FENCE_EVENT, vmw_fence_event_ioctl,
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_GET_3D_CAP, vmw_get_cap_3d_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
 
        /* these allow direct access to the framebuffers mark as master only */
        VMW_IOCTL_DEF(VMW_PRESENT, vmw_present_ioctl,
@@ -194,19 +193,19 @@ static const struct drm_ioctl_desc vmw_ioctls[] = {
                      DRM_MASTER | DRM_UNLOCKED),
        VMW_IOCTL_DEF(VMW_CREATE_SHADER,
                      vmw_shader_define_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_UNREF_SHADER,
                      vmw_shader_destroy_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE,
                      vmw_gb_surface_define_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_GB_SURFACE_REF,
                      vmw_gb_surface_reference_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_AUTH | DRM_UNLOCKED | DRM_RENDER_ALLOW),
        VMW_IOCTL_DEF(VMW_SYNCCPU,
                      vmw_user_dmabuf_synccpu_ioctl,
-                     DRM_AUTH | DRM_UNLOCKED),
+                     DRM_UNLOCKED | DRM_RENDER_ALLOW),
 };
 
 static struct pci_device_id vmw_pci_id_list[] = {
@@ -606,6 +605,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        mutex_init(&dev_priv->release_mutex);
        mutex_init(&dev_priv->binding_mutex);
        rwlock_init(&dev_priv->resource_lock);
+       ttm_lock_init(&dev_priv->reservation_sem);
 
        for (i = vmw_res_context; i < vmw_res_max; ++i) {
                idr_init(&dev_priv->res_idr[i]);
@@ -722,7 +722,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 
        ret = ttm_bo_device_init(&dev_priv->bdev,
                                 dev_priv->bo_global_ref.ref.object,
-                                &vmw_bo_driver, VMWGFX_FILE_PAGE_OFFSET,
+                                &vmw_bo_driver,
+                                dev->anon_inode->i_mapping,
+                                VMWGFX_FILE_PAGE_OFFSET,
                                 false);
        if (unlikely(ret != 0)) {
                DRM_ERROR("Failed initializing TTM buffer object driver.\n");
@@ -969,7 +971,6 @@ static int vmw_driver_open(struct drm_device *dev, struct drm_file *file_priv)
                goto out_no_shman;
 
        file_priv->driver_priv = vmw_fp;
-       dev_priv->bdev.dev_mapping = dev->dev_mapping;
 
        return 0;
 
@@ -980,12 +981,70 @@ out_no_tfile:
        return ret;
 }
 
-static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
-                              unsigned long arg)
+static struct vmw_master *vmw_master_check(struct drm_device *dev,
+                                          struct drm_file *file_priv,
+                                          unsigned int flags)
+{
+       int ret;
+       struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv);
+       struct vmw_master *vmaster;
+
+       if (file_priv->minor->type != DRM_MINOR_LEGACY ||
+           !(flags & DRM_AUTH))
+               return NULL;
+
+       ret = mutex_lock_interruptible(&dev->master_mutex);
+       if (unlikely(ret != 0))
+               return ERR_PTR(-ERESTARTSYS);
+
+       if (file_priv->is_master) {
+               mutex_unlock(&dev->master_mutex);
+               return NULL;
+       }
+
+       /*
+        * Check if we were previously master, but now dropped.
+        */
+       if (vmw_fp->locked_master) {
+               mutex_unlock(&dev->master_mutex);
+               DRM_ERROR("Dropped master trying to access ioctl that "
+                         "requires authentication.\n");
+               return ERR_PTR(-EACCES);
+       }
+       mutex_unlock(&dev->master_mutex);
+
+       /*
+        * Taking the drm_global_mutex after the TTM lock might deadlock
+        */
+       if (!(flags & DRM_UNLOCKED)) {
+               DRM_ERROR("Refusing locked ioctl access.\n");
+               return ERR_PTR(-EDEADLK);
+       }
+
+       /*
+        * Take the TTM lock. Possibly sleep waiting for the authenticating
+        * master to become master again, or for a SIGTERM if the
+        * authenticating master exits.
+        */
+       vmaster = vmw_master(file_priv->master);
+       ret = ttm_read_lock(&vmaster->lock, true);
+       if (unlikely(ret != 0))
+               vmaster = ERR_PTR(ret);
+
+       return vmaster;
+}
+
+static long vmw_generic_ioctl(struct file *filp, unsigned int cmd,
+                             unsigned long arg,
+                             long (*ioctl_func)(struct file *, unsigned int,
+                                                unsigned long))
 {
        struct drm_file *file_priv = filp->private_data;
        struct drm_device *dev = file_priv->minor->dev;
        unsigned int nr = DRM_IOCTL_NR(cmd);
+       struct vmw_master *vmaster;
+       unsigned int flags;
+       long ret;
 
        /*
         * Do extra checking on driver private ioctls.
@@ -994,18 +1053,44 @@ static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
        if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END)
            && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) {
                const struct drm_ioctl_desc *ioctl =
-                   &vmw_ioctls[nr - DRM_COMMAND_BASE];
+                       &vmw_ioctls[nr - DRM_COMMAND_BASE];
 
                if (unlikely(ioctl->cmd_drv != cmd)) {
                        DRM_ERROR("Invalid command format, ioctl %d\n",
                                  nr - DRM_COMMAND_BASE);
                        return -EINVAL;
                }
+               flags = ioctl->flags;
+       } else if (!drm_ioctl_flags(nr, &flags))
+               return -EINVAL;
+
+       vmaster = vmw_master_check(dev, file_priv, flags);
+       if (unlikely(IS_ERR(vmaster))) {
+               DRM_INFO("IOCTL ERROR %d\n", nr);
+               return PTR_ERR(vmaster);
        }
 
-       return drm_ioctl(filp, cmd, arg);
+       ret = ioctl_func(filp, cmd, arg);
+       if (vmaster)
+               ttm_read_unlock(&vmaster->lock);
+
+       return ret;
+}
+
+static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd,
+                              unsigned long arg)
+{
+       return vmw_generic_ioctl(filp, cmd, arg, &drm_ioctl);
 }
 
+#ifdef CONFIG_COMPAT
+static long vmw_compat_ioctl(struct file *filp, unsigned int cmd,
+                            unsigned long arg)
+{
+       return vmw_generic_ioctl(filp, cmd, arg, &drm_compat_ioctl);
+}
+#endif
+
 static void vmw_lastclose(struct drm_device *dev)
 {
        struct drm_crtc *crtc;
@@ -1174,12 +1259,11 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
 {
        struct vmw_private *dev_priv =
                container_of(nb, struct vmw_private, pm_nb);
-       struct vmw_master *vmaster = dev_priv->active_master;
 
        switch (val) {
        case PM_HIBERNATION_PREPARE:
        case PM_SUSPEND_PREPARE:
-               ttm_suspend_lock(&vmaster->lock);
+               ttm_suspend_lock(&dev_priv->reservation_sem);
 
                /**
                 * This empties VRAM and unbinds all GMR bindings.
@@ -1193,7 +1277,7 @@ static int vmwgfx_pm_notifier(struct notifier_block *nb, unsigned long val,
        case PM_POST_HIBERNATION:
        case PM_POST_SUSPEND:
        case PM_POST_RESTORE:
-               ttm_suspend_unlock(&vmaster->lock);
+               ttm_suspend_unlock(&dev_priv->reservation_sem);
 
                break;
        case PM_RESTORE_PREPARE:
@@ -1314,14 +1398,14 @@ static const struct file_operations vmwgfx_driver_fops = {
        .poll = vmw_fops_poll,
        .read = vmw_fops_read,
 #if defined(CONFIG_COMPAT)
-       .compat_ioctl = drm_compat_ioctl,
+       .compat_ioctl = vmw_compat_ioctl,
 #endif
        .llseek = noop_llseek,
 };
 
 static struct drm_driver driver = {
        .driver_features = DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED |
-       DRIVER_MODESET | DRIVER_PRIME,
+       DRIVER_MODESET | DRIVER_PRIME | DRIVER_RENDER,
        .load = vmw_driver_load,
        .unload = vmw_driver_unload,
        .lastclose = vmw_lastclose,
index 0783155..6b252a8 100644 (file)
@@ -40,9 +40,9 @@
 #include <drm/ttm/ttm_module.h>
 #include "vmwgfx_fence.h"
 
-#define VMWGFX_DRIVER_DATE "20140228"
+#define VMWGFX_DRIVER_DATE "20140325"
 #define VMWGFX_DRIVER_MAJOR 2
-#define VMWGFX_DRIVER_MINOR 5
+#define VMWGFX_DRIVER_MINOR 6
 #define VMWGFX_DRIVER_PATCHLEVEL 0
 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000
 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
@@ -486,6 +486,11 @@ struct vmw_private {
        struct mutex release_mutex;
        uint32_t num_3d_resources;
 
+       /*
+        * Replace this with an rwsem as soon as we have down_xx_interruptible()
+        */
+       struct ttm_lock reservation_sem;
+
        /*
         * Query processing. These members
         * are protected by the cmdbuf mutex.
index efb575a..931490b 100644 (file)
@@ -2712,7 +2712,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
 {
        struct vmw_private *dev_priv = vmw_priv(dev);
        struct drm_vmw_execbuf_arg *arg = (struct drm_vmw_execbuf_arg *)data;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        int ret;
 
        /*
@@ -2729,7 +2728,7 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
 
@@ -2745,6 +2744,6 @@ int vmw_execbuf_ioctl(struct drm_device *dev, void *data,
        vmw_kms_cursor_post_execbuf(dev_priv);
 
 out_unlock:
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
        return ret;
 }
index ed5ce2a..a89ad93 100644 (file)
@@ -147,7 +147,7 @@ static int vmw_fb_check_var(struct fb_var_screeninfo *var,
        }
 
        if (!vmw_kms_validate_mode_vram(vmw_priv,
-                                       info->fix.line_length,
+                                       var->xres * var->bits_per_pixel/8,
                                        var->yoffset + var->yres)) {
                DRM_ERROR("Requested geom can not fit in framebuffer\n");
                return -EINVAL;
@@ -162,6 +162,8 @@ static int vmw_fb_set_par(struct fb_info *info)
        struct vmw_private *vmw_priv = par->vmw_priv;
        int ret;
 
+       info->fix.line_length = info->var.xres * info->var.bits_per_pixel/8;
+
        ret = vmw_kms_write_svga(vmw_priv, info->var.xres, info->var.yres,
                                 info->fix.line_length,
                                 par->bpp, par->depth);
@@ -177,6 +179,7 @@ static int vmw_fb_set_par(struct fb_info *info)
                vmw_write(vmw_priv, SVGA_REG_DISPLAY_POSITION_Y, info->var.yoffset);
                vmw_write(vmw_priv, SVGA_REG_DISPLAY_WIDTH, info->var.xres);
                vmw_write(vmw_priv, SVGA_REG_DISPLAY_HEIGHT, info->var.yres);
+               vmw_write(vmw_priv, SVGA_REG_BYTES_PER_LINE, info->fix.line_length);
                vmw_write(vmw_priv, SVGA_REG_DISPLAY_ID, SVGA_ID_INVALID);
        }
 
@@ -377,14 +380,13 @@ static int vmw_fb_create_bo(struct vmw_private *vmw_priv,
 
        ne_placement.lpfn = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 
-       /* interuptable? */
-       ret = ttm_write_lock(&vmw_priv->fbdev_master.lock, false);
-       if (unlikely(ret != 0))
-               return ret;
+       (void) ttm_write_lock(&vmw_priv->reservation_sem, false);
 
        vmw_bo = kmalloc(sizeof(*vmw_bo), GFP_KERNEL);
-       if (!vmw_bo)
+       if (!vmw_bo) {
+               ret = -ENOMEM;
                goto err_unlock;
+       }
 
        ret = vmw_dmabuf_init(vmw_priv, vmw_bo, size,
                              &ne_placement,
index 47b7094..37881ec 100644 (file)
@@ -226,7 +226,6 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
        struct drm_vmw_present_arg *arg =
                (struct drm_vmw_present_arg *)data;
        struct vmw_surface *surface;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct drm_vmw_rect __user *clips_ptr;
        struct drm_vmw_rect *clips = NULL;
        struct drm_framebuffer *fb;
@@ -271,7 +270,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
        }
        vfb = vmw_framebuffer_to_vfb(fb);
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                goto out_no_ttm_lock;
 
@@ -291,7 +290,7 @@ int vmw_present_ioctl(struct drm_device *dev, void *data,
        vmw_surface_unreference(&surface);
 
 out_no_surface:
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
 out_no_ttm_lock:
        drm_framebuffer_unreference(fb);
 out_no_fb:
@@ -311,7 +310,6 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
        struct drm_vmw_fence_rep __user *user_fence_rep =
                (struct drm_vmw_fence_rep __user *)
                (unsigned long)arg->fence_rep;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct drm_vmw_rect __user *clips_ptr;
        struct drm_vmw_rect *clips = NULL;
        struct drm_framebuffer *fb;
@@ -361,7 +359,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
                goto out_no_ttm_lock;
        }
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                goto out_no_ttm_lock;
 
@@ -369,7 +367,7 @@ int vmw_present_readback_ioctl(struct drm_device *dev, void *data,
                               vfb, user_fence_rep,
                               clips, num_clips);
 
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
 out_no_ttm_lock:
        drm_framebuffer_unreference(fb);
 out_no_fb:
index 8a65041..a2dde5a 100644 (file)
@@ -468,7 +468,7 @@ static int do_surface_dirty_sou(struct vmw_private *dev_priv,
        num_units = 0;
        list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list,
                            head) {
-               if (crtc->fb != &framebuffer->base)
+               if (crtc->primary->fb != &framebuffer->base)
                        continue;
                units[num_units++] = vmw_crtc_to_du(crtc);
        }
@@ -596,7 +596,6 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                                  unsigned num_clips)
 {
        struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct vmw_framebuffer_surface *vfbs =
                vmw_framebuffer_to_vfbs(framebuffer);
        struct drm_clip_rect norect;
@@ -611,7 +610,7 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
 
        drm_modeset_lock_all(dev_priv->dev);
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0)) {
                drm_modeset_unlock_all(dev_priv->dev);
                return ret;
@@ -632,7 +631,7 @@ static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                                   flags, color,
                                   clips, num_clips, inc, NULL);
 
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
 
        drm_modeset_unlock_all(dev_priv->dev);
 
@@ -883,7 +882,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
 
        num_units = 0;
        list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
-               if (crtc->fb != &framebuffer->base)
+               if (crtc->primary->fb != &framebuffer->base)
                        continue;
                units[num_units++] = vmw_crtc_to_du(crtc);
        }
@@ -954,7 +953,6 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
                                 unsigned num_clips)
 {
        struct vmw_private *dev_priv = vmw_priv(framebuffer->dev);
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct vmw_framebuffer_dmabuf *vfbd =
                vmw_framebuffer_to_vfbd(framebuffer);
        struct drm_clip_rect norect;
@@ -962,7 +960,7 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
 
        drm_modeset_lock_all(dev_priv->dev);
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0)) {
                drm_modeset_unlock_all(dev_priv->dev);
                return ret;
@@ -989,7 +987,7 @@ static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
                                          clips, num_clips, increment, NULL);
        }
 
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
 
        drm_modeset_unlock_all(dev_priv->dev);
 
@@ -1245,7 +1243,7 @@ int vmw_kms_present(struct vmw_private *dev_priv,
 
        num_units = 0;
        list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
-               if (crtc->fb != &vfb->base)
+               if (crtc->primary->fb != &vfb->base)
                        continue;
                units[num_units++] = vmw_crtc_to_du(crtc);
        }
@@ -1382,7 +1380,7 @@ int vmw_kms_readback(struct vmw_private *dev_priv,
 
        num_units = 0;
        list_for_each_entry(crtc, &dev_priv->dev->mode_config.crtc_list, head) {
-               if (crtc->fb != &vfb->base)
+               if (crtc->primary->fb != &vfb->base)
                        continue;
                units[num_units++] = vmw_crtc_to_du(crtc);
        }
@@ -1725,7 +1723,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
                     uint32_t page_flip_flags)
 {
        struct vmw_private *dev_priv = vmw_priv(crtc->dev);
-       struct drm_framebuffer *old_fb = crtc->fb;
+       struct drm_framebuffer *old_fb = crtc->primary->fb;
        struct vmw_framebuffer *vfb = vmw_framebuffer_to_vfb(fb);
        struct drm_file *file_priv ;
        struct vmw_fence_obj *fence = NULL;
@@ -1743,7 +1741,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
        if (!vmw_kms_screen_object_flippable(dev_priv, crtc))
                return -EINVAL;
 
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
 
        /* do a full screen dirty update */
        clips.x1 = clips.y1 = 0;
@@ -1783,7 +1781,7 @@ int vmw_du_page_flip(struct drm_crtc *crtc,
        return ret;
 
 out_no_fence:
-       crtc->fb = old_fb;
+       crtc->primary->fb = old_fb;
        return ret;
 }
 
@@ -2022,7 +2020,6 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
        struct vmw_private *dev_priv = vmw_priv(dev);
        struct drm_vmw_update_layout_arg *arg =
                (struct drm_vmw_update_layout_arg *)data;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        void __user *user_rects;
        struct drm_vmw_rect *rects;
        unsigned rects_size;
@@ -2030,7 +2027,7 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
        int i;
        struct drm_mode_config *mode_config = &dev->mode_config;
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
 
@@ -2072,6 +2069,6 @@ int vmw_kms_update_layout_ioctl(struct drm_device *dev, void *data,
 out_free:
        kfree(rects);
 out_unlock:
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
        return ret;
 }
index a055a26..b2b9bd2 100644 (file)
@@ -93,7 +93,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
 
                if (crtc == NULL)
                        return 0;
-               fb = entry->base.crtc.fb;
+               fb = entry->base.crtc.primary->fb;
 
                return vmw_kms_write_svga(dev_priv, w, h, fb->pitches[0],
                                          fb->bits_per_pixel, fb->depth);
@@ -101,7 +101,7 @@ static int vmw_ldu_commit_list(struct vmw_private *dev_priv)
 
        if (!list_empty(&lds->active)) {
                entry = list_entry(lds->active.next, typeof(*entry), active);
-               fb = entry->base.crtc.fb;
+               fb = entry->base.crtc.primary->fb;
 
                vmw_kms_write_svga(dev_priv, fb->width, fb->height, fb->pitches[0],
                                   fb->bits_per_pixel, fb->depth);
@@ -259,7 +259,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
 
                connector->encoder = NULL;
                encoder->crtc = NULL;
-               crtc->fb = NULL;
+               crtc->primary->fb = NULL;
                crtc->enabled = false;
 
                vmw_ldu_del_active(dev_priv, ldu);
@@ -280,7 +280,7 @@ static int vmw_ldu_crtc_set_config(struct drm_mode_set *set)
 
        vmw_fb_off(dev_priv);
 
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
        encoder->crtc = crtc;
        connector->encoder = encoder;
        crtc->x = set->x;
index 9757b57..01d68f0 100644 (file)
@@ -538,8 +538,13 @@ int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo,
                return -EPERM;
 
        vmw_user_bo = vmw_user_dma_buffer(bo);
-       return (vmw_user_bo->prime.base.tfile == tfile ||
-               vmw_user_bo->prime.base.shareable) ? 0 : -EPERM;
+
+       /* Check that the caller has opened the object. */
+       if (likely(ttm_ref_object_exists(tfile, &vmw_user_bo->prime.base)))
+               return 0;
+
+       DRM_ERROR("Could not grant buffer access.\n");
+       return -EPERM;
 }
 
 /**
@@ -676,10 +681,9 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
        struct drm_vmw_dmabuf_rep *rep = &arg->rep;
        struct vmw_dma_buffer *dma_buf;
        uint32_t handle;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        int ret;
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
 
@@ -696,7 +700,7 @@ int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
        vmw_dmabuf_unreference(&dma_buf);
 
 out_no_dmabuf:
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
 
        return ret;
 }
@@ -873,7 +877,6 @@ int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
        struct vmw_resource *tmp;
        struct drm_vmw_stream_arg *arg = (struct drm_vmw_stream_arg *)data;
        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        int ret;
 
        /*
@@ -884,7 +887,7 @@ int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
        if (unlikely(vmw_user_stream_size == 0))
                vmw_user_stream_size = ttm_round_pot(sizeof(*stream)) + 128;
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
 
@@ -932,7 +935,7 @@ int vmw_stream_claim_ioctl(struct drm_device *dev, void *data,
 out_err:
        vmw_resource_unreference(&res);
 out_unlock:
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
        return ret;
 }
 
@@ -985,14 +988,13 @@ int vmw_dumb_create(struct drm_file *file_priv,
                    struct drm_mode_create_dumb *args)
 {
        struct vmw_private *dev_priv = vmw_priv(dev);
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct vmw_dma_buffer *dma_buf;
        int ret;
 
        args->pitch = args->width * ((args->bpp + 7) / 8);
        args->size = args->pitch * args->height;
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
 
@@ -1004,7 +1006,7 @@ int vmw_dumb_create(struct drm_file *file_priv,
 
        vmw_dmabuf_unreference(&dma_buf);
 out_no_dmabuf:
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
        return ret;
 }
 
index 22406c8..a95d3a0 100644 (file)
@@ -307,7 +307,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
 
                connector->encoder = NULL;
                encoder->crtc = NULL;
-               crtc->fb = NULL;
+               crtc->primary->fb = NULL;
                crtc->x = 0;
                crtc->y = 0;
                crtc->enabled = false;
@@ -368,7 +368,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
 
                connector->encoder = NULL;
                encoder->crtc = NULL;
-               crtc->fb = NULL;
+               crtc->primary->fb = NULL;
                crtc->x = 0;
                crtc->y = 0;
                crtc->enabled = false;
@@ -381,7 +381,7 @@ static int vmw_sou_crtc_set_config(struct drm_mode_set *set)
        connector->encoder = encoder;
        encoder->crtc = crtc;
        crtc->mode = *mode;
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
        crtc->x = set->x;
        crtc->y = set->y;
        crtc->enabled = true;
@@ -572,5 +572,5 @@ void vmw_kms_screen_object_update_implicit_fb(struct vmw_private *dev_priv,
        BUG_ON(!sou->base.is_implicit);
 
        dev_priv->sou_priv->implicit_fb =
-               vmw_framebuffer_to_vfb(sou->base.crtc.fb);
+               vmw_framebuffer_to_vfb(sou->base.crtc.primary->fb);
 }
index ee38565..c1559ee 100644 (file)
@@ -449,7 +449,6 @@ int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
        struct drm_vmw_shader_create_arg *arg =
                (struct drm_vmw_shader_create_arg *)data;
        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        struct vmw_dma_buffer *buffer = NULL;
        SVGA3dShaderType shader_type;
        int ret;
@@ -487,14 +486,14 @@ int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
                goto out_bad_arg;
        }
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                goto out_bad_arg;
 
        ret = vmw_shader_alloc(dev_priv, buffer, arg->size, arg->offset,
                               shader_type, tfile, &arg->shader_handle);
 
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
 out_bad_arg:
        vmw_dmabuf_unreference(&buffer);
        return ret;
index e7af580..4ecdbf3 100644 (file)
  * @base:           The TTM base object handling user-space visibility.
  * @srf:            The surface metadata.
  * @size:           TTM accounting size for the surface.
+ * @master:         master of the creating client. Used for security check.
  */
 struct vmw_user_surface {
        struct ttm_prime_object prime;
        struct vmw_surface srf;
        uint32_t size;
+       struct drm_master *master;
 };
 
 /**
@@ -624,6 +626,8 @@ static void vmw_user_surface_free(struct vmw_resource *res)
        struct vmw_private *dev_priv = srf->res.dev_priv;
        uint32_t size = user_srf->size;
 
+       if (user_srf->master)
+               drm_master_put(&user_srf->master);
        kfree(srf->offsets);
        kfree(srf->sizes);
        kfree(srf->snooper.image);
@@ -697,7 +701,6 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
        struct vmw_surface_offset *cur_offset;
        uint32_t num_sizes;
        uint32_t size;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        const struct svga3d_surface_desc *desc;
 
        if (unlikely(vmw_user_surface_size == 0))
@@ -723,7 +726,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
 
@@ -820,6 +823,8 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
 
        user_srf->prime.base.shareable = false;
        user_srf->prime.base.tfile = NULL;
+       if (drm_is_primary_client(file_priv))
+               user_srf->master = drm_master_get(file_priv->master);
 
        /**
         * From this point, the generic resource management functions
@@ -862,7 +867,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
        rep->sid = user_srf->prime.base.hash.key;
        vmw_resource_unreference(&res);
 
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
        return 0;
 out_no_copy:
        kfree(srf->offsets);
@@ -873,7 +878,81 @@ out_no_sizes:
 out_no_user_srf:
        ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
 out_unlock:
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
+       return ret;
+}
+
+
+static int
+vmw_surface_handle_reference(struct vmw_private *dev_priv,
+                            struct drm_file *file_priv,
+                            uint32_t u_handle,
+                            enum drm_vmw_handle_type handle_type,
+                            struct ttm_base_object **base_p)
+{
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct vmw_user_surface *user_srf;
+       uint32_t handle;
+       struct ttm_base_object *base;
+       int ret;
+
+       if (handle_type == DRM_VMW_HANDLE_PRIME) {
+               ret = ttm_prime_fd_to_handle(tfile, u_handle, &handle);
+               if (unlikely(ret != 0))
+                       return ret;
+       } else {
+               if (unlikely(drm_is_render_client(file_priv))) {
+                       DRM_ERROR("Render client refused legacy "
+                                 "surface reference.\n");
+                       return -EACCES;
+               }
+               handle = u_handle;
+       }
+
+       ret = -EINVAL;
+       base = ttm_base_object_lookup_for_ref(dev_priv->tdev, handle);
+       if (unlikely(base == NULL)) {
+               DRM_ERROR("Could not find surface to reference.\n");
+               goto out_no_lookup;
+       }
+
+       if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE)) {
+               DRM_ERROR("Referenced object is not a surface.\n");
+               goto out_bad_resource;
+       }
+
+       if (handle_type != DRM_VMW_HANDLE_PRIME) {
+               user_srf = container_of(base, struct vmw_user_surface,
+                                       prime.base);
+
+               /*
+                * Make sure the surface creator has the same
+                * authenticating master.
+                */
+               if (drm_is_primary_client(file_priv) &&
+                   user_srf->master != file_priv->master) {
+                       DRM_ERROR("Trying to reference surface outside of"
+                                 " master domain.\n");
+                       ret = -EACCES;
+                       goto out_bad_resource;
+               }
+
+               ret = ttm_ref_object_add(tfile, base, TTM_REF_USAGE, NULL);
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("Could not add a reference to a surface.\n");
+                       goto out_bad_resource;
+               }
+       }
+
+       *base_p = base;
+       return 0;
+
+out_bad_resource:
+       ttm_base_object_unref(&base);
+out_no_lookup:
+       if (handle_type == DRM_VMW_HANDLE_PRIME)
+               (void) ttm_ref_object_base_unref(tfile, handle, TTM_REF_USAGE);
+
        return ret;
 }
 
@@ -898,27 +977,16 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
        struct vmw_user_surface *user_srf;
        struct drm_vmw_size __user *user_sizes;
        struct ttm_base_object *base;
-       int ret = -EINVAL;
-
-       base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid);
-       if (unlikely(base == NULL)) {
-               DRM_ERROR("Could not find surface to reference.\n");
-               return -EINVAL;
-       }
+       int ret;
 
-       if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE))
-               goto out_bad_resource;
+       ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid,
+                                          req->handle_type, &base);
+       if (unlikely(ret != 0))
+               return ret;
 
        user_srf = container_of(base, struct vmw_user_surface, prime.base);
        srf = &user_srf->srf;
 
-       ret = ttm_ref_object_add(tfile, &user_srf->prime.base,
-                                TTM_REF_USAGE, NULL);
-       if (unlikely(ret != 0)) {
-               DRM_ERROR("Could not add a reference to a surface.\n");
-               goto out_no_reference;
-       }
-
        rep->flags = srf->flags;
        rep->format = srf->format;
        memcpy(rep->mip_levels, srf->mip_levels, sizeof(srf->mip_levels));
@@ -931,10 +999,10 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
        if (unlikely(ret != 0)) {
                DRM_ERROR("copy_to_user failed %p %u\n",
                          user_sizes, srf->num_sizes);
+               ttm_ref_object_base_unref(tfile, base->hash.key, TTM_REF_USAGE);
                ret = -EFAULT;
        }
-out_bad_resource:
-out_no_reference:
+
        ttm_base_object_unref(&base);
 
        return ret;
@@ -1173,7 +1241,6 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
        struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
        int ret;
        uint32_t size;
-       struct vmw_master *vmaster = vmw_master(file_priv->master);
        const struct svga3d_surface_desc *desc;
        uint32_t backup_handle;
 
@@ -1189,7 +1256,7 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       ret = ttm_read_lock(&vmaster->lock, true);
+       ret = ttm_read_lock(&dev_priv->reservation_sem, true);
        if (unlikely(ret != 0))
                return ret;
 
@@ -1228,6 +1295,8 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
 
        user_srf->prime.base.shareable = false;
        user_srf->prime.base.tfile = NULL;
+       if (drm_is_primary_client(file_priv))
+               user_srf->master = drm_master_get(file_priv->master);
 
        /**
         * From this point, the generic resource management functions
@@ -1283,12 +1352,12 @@ int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
 
        vmw_resource_unreference(&res);
 
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
        return 0;
 out_no_user_srf:
        ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
 out_unlock:
-       ttm_read_unlock(&vmaster->lock);
+       ttm_read_unlock(&dev_priv->reservation_sem);
        return ret;
 }
 
@@ -1315,14 +1384,10 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
        uint32_t backup_handle;
        int ret = -EINVAL;
 
-       base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid);
-       if (unlikely(base == NULL)) {
-               DRM_ERROR("Could not find surface to reference.\n");
-               return -EINVAL;
-       }
-
-       if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE))
-               goto out_bad_resource;
+       ret = vmw_surface_handle_reference(dev_priv, file_priv, req->sid,
+                                          req->handle_type, &base);
+       if (unlikely(ret != 0))
+               return ret;
 
        user_srf = container_of(base, struct vmw_user_surface, prime.base);
        srf = &user_srf->srf;
@@ -1331,13 +1396,6 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
                goto out_bad_resource;
        }
 
-       ret = ttm_ref_object_add(tfile, &user_srf->prime.base,
-                                TTM_REF_USAGE, NULL);
-       if (unlikely(ret != 0)) {
-               DRM_ERROR("Could not add a reference to a GB surface.\n");
-               goto out_bad_resource;
-       }
-
        mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */
        ret = vmw_user_dmabuf_reference(tfile, srf->res.backup,
                                        &backup_handle);
@@ -1346,8 +1404,7 @@ int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
        if (unlikely(ret != 0)) {
                DRM_ERROR("Could not add a reference to a GB surface "
                          "backup buffer.\n");
-               (void) ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
-                                                req->sid,
+               (void) ttm_ref_object_base_unref(tfile, base->hash.key,
                                                 TTM_REF_USAGE);
                goto out_bad_resource;
        }
index bfb09d8..b10550e 100644 (file)
@@ -102,6 +102,7 @@ u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs)
 {
        return (u32)atomic_add_return(incrs, &sp->max_val);
 }
+EXPORT_SYMBOL(host1x_syncpt_incr_max);
 
  /*
  * Write cached syncpoint and waitbase values to hardware.
index b13172c..bc196f4 100644 (file)
@@ -554,14 +554,6 @@ config SENSORS_IBMPEX
          This driver can also be built as a module.  If so, the module
          will be called ibmpex.
 
-config SENSORS_IBMPOWERNV
-       tristate "IBM PowerNv Platform temperature/power/fan sensor"
-       depends on PPC_POWERNV
-       default y
-       help
-         If you say yes here you get support for the temperature/fan/power
-         sensors on your platform.
-
 config SENSORS_IIO_HWMON
        tristate "Hwmon driver that uses channels specified via iio maps"
        depends on IIO
index 199c401..c48f987 100644 (file)
@@ -71,7 +71,6 @@ obj-$(CONFIG_SENSORS_ULTRA45) += ultra45_env.o
 obj-$(CONFIG_SENSORS_I5K_AMB)  += i5k_amb.o
 obj-$(CONFIG_SENSORS_IBMAEM)   += ibmaem.o
 obj-$(CONFIG_SENSORS_IBMPEX)   += ibmpex.o
-obj-$(CONFIG_SENSORS_IBMPOWERNV)+= ibmpowernv.o
 obj-$(CONFIG_SENSORS_IIO_HWMON) += iio_hwmon.o
 obj-$(CONFIG_SENSORS_INA209)   += ina209.o
 obj-$(CONFIG_SENSORS_INA2XX)   += ina2xx.o
index f31bc4c..6d02e3b 100644 (file)
@@ -810,20 +810,20 @@ static int __init coretemp_init(void)
        if (err)
                goto exit;
 
-       get_online_cpus();
+       cpu_notifier_register_begin();
        for_each_online_cpu(i)
                get_core_online(i);
 
 #ifndef CONFIG_HOTPLUG_CPU
        if (list_empty(&pdev_list)) {
-               put_online_cpus();
+               cpu_notifier_register_done();
                err = -ENODEV;
                goto exit_driver_unreg;
        }
 #endif
 
-       register_hotcpu_notifier(&coretemp_cpu_notifier);
-       put_online_cpus();
+       __register_hotcpu_notifier(&coretemp_cpu_notifier);
+       cpu_notifier_register_done();
        return 0;
 
 #ifndef CONFIG_HOTPLUG_CPU
@@ -838,8 +838,8 @@ static void __exit coretemp_exit(void)
 {
        struct pdev_entry *p, *n;
 
-       get_online_cpus();
-       unregister_hotcpu_notifier(&coretemp_cpu_notifier);
+       cpu_notifier_register_begin();
+       __unregister_hotcpu_notifier(&coretemp_cpu_notifier);
        mutex_lock(&pdev_list_mutex);
        list_for_each_entry_safe(p, n, &pdev_list, list) {
                platform_device_unregister(p->pdev);
@@ -847,7 +847,7 @@ static void __exit coretemp_exit(void)
                kfree(p);
        }
        mutex_unlock(&pdev_list_mutex);
-       put_online_cpus();
+       cpu_notifier_register_done();
        platform_driver_unregister(&coretemp_driver);
 }
 
diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
deleted file mode 100644 (file)
index b7b1297..0000000
+++ /dev/null
@@ -1,529 +0,0 @@
-/*
- * hwmon driver for temperature/power/fan on IBM PowerNV platform
- * Copyright (C) 2013 IBM
- *
- * 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/init.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-
-#include <linux/jiffies.h>
-#include <linux/platform_device.h>
-#include <asm/opal.h>
-#include <linux/err.h>
-
-MODULE_DESCRIPTION("IBM PowerNV Platform power/temp/fan sensor hwmon module");
-MODULE_LICENSE("GPL");
-
-#define MAX_ATTR_LENGTH                32
-
-/* Device tree sensor name prefixes. The device tree has the names in the
- * format "cooling-fan#2-faulted" where the "cooling-fan" is the sensor type,
- * 2 is the sensor count, and "faulted" is the sensor data attribute type.
- */
-#define DT_FAULT_ATTR_SUFFIX           "faulted"
-#define DT_DATA_ATTR_SUFFIX            "data"
-#define DT_THRESHOLD_ATTR_SUFFIX       "thrs"
-
-enum sensors {
-       FAN,
-       TEMPERATURE,
-       POWERSUPPLY,
-       POWER,
-       MAX_SENSOR_TYPE,
-};
-
-enum attributes {
-       INPUT,
-       MINIMUM,
-       MAXIMUM,
-       FAULT,
-       MAX_ATTR_TYPES
-};
-
-static struct sensor_name {
-       char *name;
-       char *compaible;
-} sensor_names[] = {
-               {"fan-sensor", "ibm,opal-sensor-cooling-fan"},
-               {"amb-temp-sensor", "ibm,opal-sensor-amb-temp"},
-               {"power-sensor", "ibm,opal-sensor-power-supply"},
-               {"power", "ibm,opal-sensor-power"}
-};
-
-static const char * const attribute_type_table[] = {
-       "input",
-       "min",
-       "max",
-       "fault",
-       NULL
-};
-
-struct pdev_entry {
-       struct list_head list;
-       struct platform_device *pdev;
-       enum sensors type;
-};
-
-static LIST_HEAD(pdev_list);
-
-/* The sensors are categorised on type.
- *
- * The sensors of same type are categorised under a common platform device.
- * So, The pdev is shared by all sensors of same type.
- * Ex : temp1_input, temp1_max, temp2_input,temp2_max all share same platform
- * device.
- *
- * "sensor_data" is the Platform device specific data.
- * There is one hwmon_device instance for all the sensors of same type.
- * This also holds the list of all sensors with same type but different
- * attribute and index.
- */
-struct sensor_specific_data {
-       u32 sensor_id; /* The hex value as in the device tree */
-       u32 sensor_index; /* The sensor instance index */
-       struct sensor_device_attribute sd_attr;
-       enum attributes attr_type;
-       char attr_name[64];
-};
-
-struct sensor_data {
-       struct device *hwmon_dev;
-       struct list_head sensor_list;
-       struct device_attribute name_attr;
-};
-
-struct  sensor_entry {
-       struct list_head list;
-       struct sensor_specific_data *sensor_data;
-};
-
-static struct platform_device *powernv_sensor_get_pdev(enum sensors type)
-{
-       struct pdev_entry *p;
-       list_for_each_entry(p, &pdev_list, list)
-               if (p->type == type)
-                       return p->pdev;
-
-       return NULL;
-}
-
-static struct sensor_specific_data *powernv_sensor_get_sensor_data(
-                                       struct sensor_data *pdata,
-                                       int index, enum attributes attr_type)
-{
-       struct sensor_entry *p;
-       list_for_each_entry(p, &pdata->sensor_list, list)
-               if ((p->sensor_data->sensor_index == index) &&
-                   (attr_type == p->sensor_data->attr_type))
-                       return p->sensor_data;
-
-       return NULL;
-}
-
-static ssize_t show_name(struct device *dev,
-                               struct device_attribute *devattr, char *buf)
-{
-       struct platform_device *pdev = to_platform_device(dev);
-
-       return sprintf(buf, "%s\n", pdev->name);
-}
-
-/* Note: Data from the sensors for each sensor type needs to be converted to
- * the dimension appropriate.
- */
-static ssize_t show_sensor(struct device *dev,
-                               struct device_attribute *devattr, char *buf)
-{
-       struct sensor_device_attribute *sd_attr = to_sensor_dev_attr(devattr);
-       struct platform_device *pdev = to_platform_device(dev);
-       struct sensor_data *pdata = platform_get_drvdata(pdev);
-       struct sensor_specific_data *tdata = NULL;
-       enum sensors sensor_type = pdev->id;
-       u32 x = -1;
-       int ret;
-
-       if (sd_attr && sd_attr->dev_attr.attr.name) {
-               char *pos = strchr(sd_attr->dev_attr.attr.name, '_');
-               int i;
-
-               for (i = 0; i < MAX_ATTR_TYPES; i++) {
-                       if (strcmp(pos+1, attribute_type_table[i]) == 0) {
-                               tdata = powernv_sensor_get_sensor_data(pdata,
-                                               sd_attr->index, i);
-                               break;
-                       }
-               }
-       }
-
-       if (tdata) {
-               ret = opal_get_sensor_data(tdata->sensor_id, &x);
-               if (ret)
-                       x = -1;
-       }
-
-       if (sensor_type == TEMPERATURE && x > 0) {
-               /* Temperature comes in Degrees and convert it to
-                * milli-degrees.
-                */
-               x = x*1000;
-       } else if (sensor_type == POWER && x > 0) {
-               /* Power value comes in watts, convert to micro-watts */
-               x = x * 1000000;
-       }
-
-       return sprintf(buf, "%d\n", x);
-}
-
-static u32 get_sensor_index_from_name(const char *name)
-{
-       char *hash_position = strchr(name, '#');
-       u32 index = 0, copy_length;
-       char newbuf[8];
-
-       if (hash_position) {
-               copy_length = strchr(hash_position, '-') - hash_position - 1;
-               if (copy_length < sizeof(newbuf)) {
-                       strncpy(newbuf, hash_position + 1, copy_length);
-                       sscanf(newbuf, "%d", &index);
-               }
-       }
-
-       return index;
-}
-
-static inline void get_sensor_suffix_from_name(const char *name, char *suffix)
-{
-       char *dash_position = strrchr(name, '-');
-       if (dash_position)
-               strncpy(suffix, dash_position+1, MAX_ATTR_LENGTH);
-       else
-               strcpy(suffix,"");
-}
-
-static int get_sensor_attr_properties(const char *sensor_name,
-               enum sensors sensor_type, enum attributes *attr_type,
-               u32 *sensor_index)
-{
-       char suffix[MAX_ATTR_LENGTH];
-
-       *attr_type = MAX_ATTR_TYPES;
-       *sensor_index = get_sensor_index_from_name(sensor_name);
-       if (*sensor_index == 0)
-               return -EINVAL;
-
-       get_sensor_suffix_from_name(sensor_name, suffix);
-       if (strcmp(suffix, "") == 0)
-               return -EINVAL;
-
-       if (strcmp(suffix, DT_FAULT_ATTR_SUFFIX) == 0)
-               *attr_type = FAULT;
-       else if (strcmp(suffix, DT_DATA_ATTR_SUFFIX) == 0)
-               *attr_type = INPUT;
-       else if ((sensor_type == TEMPERATURE) &&
-                       (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
-               *attr_type = MAXIMUM;
-       else if ((sensor_type == FAN) &&
-                       (strcmp(suffix, DT_THRESHOLD_ATTR_SUFFIX) == 0))
-               *attr_type = MINIMUM;
-       else
-               return -ENOENT;
-
-       if (((sensor_type == FAN) && ((*attr_type == INPUT) ||
-                                   (*attr_type == MINIMUM)))
-           || ((sensor_type == TEMPERATURE) && ((*attr_type == INPUT) ||
-                                                (*attr_type == MAXIMUM)))
-           || ((sensor_type == POWER) && ((*attr_type == INPUT))))
-               return 0;
-
-       return -ENOENT;
-}
-
-static int create_sensor_attr(struct sensor_specific_data *tdata,
-               struct device *dev, enum sensors sensor_type,
-               enum attributes attr_type)
-{
-       int err = 0;
-       char temp_file_prefix[50];
-       static const char *const file_name_format = "%s%d_%s";
-
-       tdata->attr_type = attr_type;
-
-       if (sensor_type == FAN)
-               strcpy(temp_file_prefix, "fan");
-       else if (sensor_type == TEMPERATURE)
-               strcpy(temp_file_prefix, "temp");
-       else if (sensor_type == POWERSUPPLY)
-               strcpy(temp_file_prefix, "powersupply");
-       else if (sensor_type == POWER)
-               strcpy(temp_file_prefix, "power");
-
-       snprintf(tdata->attr_name, sizeof(tdata->attr_name), file_name_format,
-                temp_file_prefix, tdata->sensor_index,
-                attribute_type_table[tdata->attr_type]);
-
-       sysfs_attr_init(&tdata->sd_attr.dev_attr.attr);
-       tdata->sd_attr.dev_attr.attr.name = tdata->attr_name;
-       tdata->sd_attr.dev_attr.attr.mode = S_IRUGO;
-       tdata->sd_attr.dev_attr.show = show_sensor;
-
-       tdata->sd_attr.index = tdata->sensor_index;
-       err = device_create_file(dev, &tdata->sd_attr.dev_attr);
-
-       return err;
-}
-
-static int create_name_attr(struct sensor_data *pdata,
-                               struct device *dev)
-{
-       sysfs_attr_init(&pdata->name_attr.attr);
-       pdata->name_attr.attr.name = "name";
-       pdata->name_attr.attr.mode = S_IRUGO;
-       pdata->name_attr.show = show_name;
-       return device_create_file(dev, &pdata->name_attr);
-}
-
-static int create_platform_device(enum sensors sensor_type,
-                                       struct platform_device **pdev)
-{
-       struct pdev_entry *pdev_entry = NULL;
-       int err;
-
-       *pdev = platform_device_alloc(sensor_names[sensor_type].name,
-                       sensor_type);
-       if (!*pdev) {
-               pr_err("Device allocation failed\n");
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       pdev_entry = kzalloc(sizeof(struct pdev_entry), GFP_KERNEL);
-       if (!pdev_entry) {
-               pr_err("Device allocation failed\n");
-               err = -ENOMEM;
-               goto exit_device_put;
-       }
-
-       err = platform_device_add(*pdev);
-       if (err) {
-               pr_err("Device addition failed (%d)\n", err);
-               goto exit_device_free;
-       }
-
-       pdev_entry->pdev = *pdev;
-       pdev_entry->type = (*pdev)->id;
-
-       list_add_tail(&pdev_entry->list, &pdev_list);
-
-       return 0;
-exit_device_free:
-       kfree(pdev_entry);
-exit_device_put:
-       platform_device_put(*pdev);
-exit:
-       return err;
-}
-
-static int create_sensor_data(struct platform_device *pdev)
-{
-       struct sensor_data *pdata = NULL;
-       int err = 0;
-
-       pdata = kzalloc(sizeof(struct sensor_data), GFP_KERNEL);
-       if (!pdata) {
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       err = create_name_attr(pdata, &pdev->dev);
-       if (err)
-               goto exit_free;
-
-       pdata->hwmon_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(pdata->hwmon_dev)) {
-               err = PTR_ERR(pdata->hwmon_dev);
-               dev_err(&pdev->dev, "Class registration failed (%d)\n",
-                       err);
-               goto exit_name;
-       }
-
-       INIT_LIST_HEAD(&pdata->sensor_list);
-       platform_set_drvdata(pdev, pdata);
-
-       return 0;
-
-exit_name:
-       device_remove_file(&pdev->dev, &pdata->name_attr);
-exit_free:
-       kfree(pdata);
-exit:
-       return err;
-}
-
-static void delete_sensor_attr(struct sensor_data *pdata)
-{
-       struct sensor_entry *s, *l;
-
-       list_for_each_entry_safe(s, l, &pdata->sensor_list, list) {
-               struct sensor_specific_data *tdata = s->sensor_data;
-                       kfree(tdata);
-                       list_del(&s->list);
-                       kfree(s);
-               }
-}
-
-static int powernv_sensor_init(u32 sensor_id, const struct device_node *np,
-               enum sensors sensor_type, enum attributes attr_type,
-               u32 sensor_index)
-{
-       struct platform_device *pdev = powernv_sensor_get_pdev(sensor_type);
-       struct sensor_specific_data *tdata;
-       struct sensor_entry *sensor_entry;
-       struct sensor_data *pdata;
-       int err = 0;
-
-       if (!pdev) {
-               err = create_platform_device(sensor_type, &pdev);
-               if (err)
-                       goto exit;
-
-               err = create_sensor_data(pdev);
-               if (err)
-                       goto exit;
-       }
-
-       pdata = platform_get_drvdata(pdev);
-       if (!pdata) {
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       tdata = kzalloc(sizeof(struct sensor_specific_data), GFP_KERNEL);
-       if (!tdata) {
-               err = -ENOMEM;
-               goto exit;
-       }
-
-       tdata->sensor_id = sensor_id;
-       tdata->sensor_index = sensor_index;
-
-       err = create_sensor_attr(tdata, &pdev->dev, sensor_type, attr_type);
-       if (err)
-               goto exit_free;
-
-       sensor_entry = kzalloc(sizeof(struct sensor_entry), GFP_KERNEL);
-       if (!sensor_entry) {
-               err = -ENOMEM;
-               goto exit_attr;
-       }
-
-       sensor_entry->sensor_data = tdata;
-
-       list_add_tail(&sensor_entry->list, &pdata->sensor_list);
-
-       return 0;
-exit_attr:
-       device_remove_file(&pdev->dev, &tdata->sd_attr.dev_attr);
-exit_free:
-       kfree(tdata);
-exit:
-       return err;
-}
-
-static void delete_unregister_sensors(void)
-{
-       struct pdev_entry *p, *n;
-
-       list_for_each_entry_safe(p, n, &pdev_list, list) {
-               struct sensor_data *pdata = platform_get_drvdata(p->pdev);
-                       if (pdata) {
-                               delete_sensor_attr(pdata);
-
-                               hwmon_device_unregister(pdata->hwmon_dev);
-                               kfree(pdata);
-                       }
-               platform_device_unregister(p->pdev);
-               list_del(&p->list);
-               kfree(p);
-       }
-}
-
-static int __init powernv_hwmon_init(void)
-{
-       struct device_node *opal, *np = NULL;
-       enum attributes attr_type;
-       enum sensors type;
-       const u32 *sensor_id;
-       u32 sensor_index;
-       int err;
-
-       opal = of_find_node_by_path("/ibm,opal/sensors");
-       if (!opal) {
-               pr_err("%s: Opal 'sensors' node not found\n", __func__);
-               return -ENXIO;
-       }
-
-       for_each_child_of_node(opal, np) {
-               if (np->name == NULL)
-                       continue;
-
-               for (type = 0; type < MAX_SENSOR_TYPE; type++)
-                       if (of_device_is_compatible(np,
-                                       sensor_names[type].compaible))
-                               break;
-
-               if (type == MAX_SENSOR_TYPE)
-                       continue;
-
-               if (get_sensor_attr_properties(np->name, type, &attr_type,
-                               &sensor_index))
-                       continue;
-
-               sensor_id = of_get_property(np, "sensor-id", NULL);
-               if (!sensor_id) {
-                       pr_info("%s: %s doesn't have sensor-id\n", __func__,
-                                       np->name);
-                       continue;
-               }
-
-               err = powernv_sensor_init(*sensor_id, np, type, attr_type,
-                               sensor_index);
-               if (err) {
-                       of_node_put(opal);
-                       goto exit;
-               }
-       }
-       of_node_put(opal);
-
-       return 0;
-exit:
-       delete_unregister_sensors();
-       return err;
-
-}
-
-static void powernv_hwmon_exit(void)
-{
-       delete_unregister_sensors();
-}
-
-module_init(powernv_hwmon_init);
-module_exit(powernv_hwmon_exit);
index 38944e9..8df43c5 100644 (file)
@@ -319,7 +319,7 @@ static int __init via_cputemp_init(void)
        if (err)
                goto exit;
 
-       get_online_cpus();
+       cpu_notifier_register_begin();
        for_each_online_cpu(i) {
                struct cpuinfo_x86 *c = &cpu_data(i);
 
@@ -339,14 +339,14 @@ static int __init via_cputemp_init(void)
 
 #ifndef CONFIG_HOTPLUG_CPU
        if (list_empty(&pdev_list)) {
-               put_online_cpus();
+               cpu_notifier_register_done();
                err = -ENODEV;
                goto exit_driver_unreg;
        }
 #endif
 
-       register_hotcpu_notifier(&via_cputemp_cpu_notifier);
-       put_online_cpus();
+       __register_hotcpu_notifier(&via_cputemp_cpu_notifier);
+       cpu_notifier_register_done();
        return 0;
 
 #ifndef CONFIG_HOTPLUG_CPU
@@ -361,8 +361,8 @@ static void __exit via_cputemp_exit(void)
 {
        struct pdev_entry *p, *n;
 
-       get_online_cpus();
-       unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
+       cpu_notifier_register_begin();
+       __unregister_hotcpu_notifier(&via_cputemp_cpu_notifier);
        mutex_lock(&pdev_list_mutex);
        list_for_each_entry_safe(p, n, &pdev_list, list) {
                platform_device_unregister(p->pdev);
@@ -370,7 +370,7 @@ static void __exit via_cputemp_exit(void)
                kfree(p);
        }
        mutex_unlock(&pdev_list_mutex);
-       put_online_cpus();
+       cpu_notifier_register_done();
        platform_driver_unregister(&via_cputemp_driver);
 }
 
index de17c55..c94db1c 100644 (file)
@@ -110,6 +110,7 @@ config I2C_I801
            Wellsburg (PCH)
            Coleto Creek (PCH)
            Wildcat Point-LP (PCH)
+           BayTrail (SOC)
 
          This driver can also be built as a module.  If so, the module
          will be called i2c-i801.
@@ -375,6 +376,13 @@ config I2C_BLACKFIN_TWI_CLK_KHZ
        help
          The unit of the TWI clock is kHz.
 
+config I2C_CADENCE
+       tristate "Cadence I2C Controller"
+       depends on ARCH_ZYNQ
+       help
+         Say yes here to select Cadence I2C Host Controller. This controller is
+         e.g. used by Xilinx Zynq.
+
 config I2C_CBUS_GPIO
        tristate "CBUS I2C driver"
        depends on GPIOLIB
@@ -432,6 +440,13 @@ config I2C_DESIGNWARE_PCI
          This driver can also be built as a module.  If so, the module
          will be called i2c-designware-pci.
 
+config I2C_EFM32
+       tristate "EFM32 I2C controller"
+       depends on ARCH_EFM32 || COMPILE_TEST
+       help
+         This driver supports the i2c block found in Energy Micro's EFM32
+         SoCs.
+
 config I2C_EG20T
        tristate "Intel EG20T PCH/LAPIS Semicon IOH(ML7213/ML7223/ML7831) I2C"
        depends on PCI
@@ -527,7 +542,7 @@ config I2C_MPC
 
 config I2C_MV64XXX
        tristate "Marvell mv64xxx I2C Controller"
-       depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI)
+       depends on MV64X60 || PLAT_ORION || ARCH_SUNXI
        help
          If you say yes to this option, support will be included for the
          built-in I2C interface on the Marvell 64xxx line of host bridges.
@@ -648,6 +663,16 @@ config I2C_PXA_SLAVE
          is necessary for systems where the PXA may be a target on the
          I2C bus.
 
+config I2C_QUP
+       tristate "Qualcomm QUP based I2C controller"
+       depends on ARCH_QCOM
+       help
+         If you say yes to this option, support will be included for the
+         built-in I2C interface on the Qualcomm SoCs.
+
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-qup.
+
 config I2C_RIIC
        tristate "Renesas RIIC adapter"
        depends on ARCH_SHMOBILE || COMPILE_TEST
@@ -936,7 +961,7 @@ config I2C_ACORN
 
 config I2C_ELEKTOR
        tristate "Elektor ISA card"
-       depends on ISA && HAS_IOPORT && BROKEN_ON_SMP
+       depends on ISA && HAS_IOPORT_MAP && BROKEN_ON_SMP
        select I2C_ALGOPCF
        help
          This supports the PCF8584 ISA bus I2C adapter.  Say Y if you own
index a08931f..18d18ff 100644 (file)
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91)                += i2c-at91.o
 obj-$(CONFIG_I2C_AU1550)       += i2c-au1550.o
 obj-$(CONFIG_I2C_BCM2835)      += i2c-bcm2835.o
 obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
+obj-$(CONFIG_I2C_CADENCE)      += i2c-cadence.o
 obj-$(CONFIG_I2C_CBUS_GPIO)    += i2c-cbus-gpio.o
 obj-$(CONFIG_I2C_CPM)          += i2c-cpm.o
 obj-$(CONFIG_I2C_DAVINCI)      += i2c-davinci.o
@@ -41,6 +42,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
 i2c-designware-platform-objs := i2c-designware-platdrv.o
 obj-$(CONFIG_I2C_DESIGNWARE_PCI)       += i2c-designware-pci.o
 i2c-designware-pci-objs := i2c-designware-pcidrv.o
+obj-$(CONFIG_I2C_EFM32)                += i2c-efm32.o
 obj-$(CONFIG_I2C_EG20T)                += i2c-eg20t.o
 obj-$(CONFIG_I2C_EXYNOS5)      += i2c-exynos5.o
 obj-$(CONFIG_I2C_GPIO)         += i2c-gpio.o
@@ -63,6 +65,7 @@ obj-$(CONFIG_I2C_PNX)         += i2c-pnx.o
 obj-$(CONFIG_I2C_PUV3)         += i2c-puv3.o
 obj-$(CONFIG_I2C_PXA)          += i2c-pxa.o
 obj-$(CONFIG_I2C_PXA_PCI)      += i2c-pxa-pci.o
+obj-$(CONFIG_I2C_QUP)          += i2c-qup.o
 obj-$(CONFIG_I2C_RIIC)         += i2c-riic.o
 obj-$(CONFIG_I2C_S3C2410)      += i2c-s3c2410.o
 obj-$(CONFIG_I2C_S6000)                += i2c-s6000.o
index 7d60d3a..451e305 100644 (file)
@@ -494,7 +494,7 @@ static struct i2c_adapter ali1535_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(ali1535_ids) = {
+static const struct pci_device_id ali1535_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
        { },
 };
index 4611e47..98a1c97 100644 (file)
@@ -416,7 +416,7 @@ static void ali1563_remove(struct pci_dev *dev)
        ali1563_shutdown(dev);
 }
 
-static DEFINE_PCI_DEVICE_TABLE(ali1563_id_table) = {
+static const struct pci_device_id ali1563_id_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1563) },
        {},
 };
index 4823206..2fa21ce 100644 (file)
@@ -476,7 +476,7 @@ static struct i2c_adapter ali15x3_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(ali15x3_ids) = {
+static const struct pci_device_id ali15x3_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
        { 0, }
 };
index 819d3c1..a16f728 100644 (file)
@@ -307,7 +307,7 @@ static const char* chipname[] = {
        "nVidia nForce", "AMD8111",
 };
 
-static DEFINE_PCI_DEVICE_TABLE(amd756_ids) = {
+static const struct pci_device_id amd756_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_740B),
          .driver_data = AMD756 },
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7413),
index f3d4d79..95a80a8 100644 (file)
@@ -414,7 +414,7 @@ static const struct i2c_algorithm smbus_algorithm = {
 };
 
 
-static DEFINE_PCI_DEVICE_TABLE(amd8111_ids) = {
+static const struct pci_device_id amd8111_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS2) },
        { 0, }
 };
index 843d012..e95f9ba 100644 (file)
@@ -32,7 +32,7 @@
 #include <linux/slab.h>
 #include <linux/platform_data/dma-atmel.h>
 
-#define TWI_CLK_HZ             100000                  /* max 400 Kbits/s */
+#define DEFAULT_TWI_CLK_HZ             100000          /* max 400 Kbits/s */
 #define AT91_I2C_TIMEOUT       msecs_to_jiffies(100)   /* transfer timeout */
 #define AT91_I2C_DMA_THRESHOLD 8                       /* enable DMA if transfer size is bigger than this threshold */
 
@@ -711,6 +711,7 @@ static int at91_twi_probe(struct platform_device *pdev)
        struct resource *mem;
        int rc;
        u32 phy_addr;
+       u32 bus_clk_rate;
 
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
        if (!dev)
@@ -756,13 +757,18 @@ static int at91_twi_probe(struct platform_device *pdev)
                        dev->use_dma = true;
        }
 
-       at91_calc_twi_clock(dev, TWI_CLK_HZ);
+       rc = of_property_read_u32(dev->dev->of_node, "clock-frequency",
+                       &bus_clk_rate);
+       if (rc)
+               bus_clk_rate = DEFAULT_TWI_CLK_HZ;
+
+       at91_calc_twi_clock(dev, bus_clk_rate);
        at91_init_twi_bus(dev);
 
        snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91");
        i2c_set_adapdata(&dev->adapter, dev);
        dev->adapter.owner = THIS_MODULE;
-       dev->adapter.class = I2C_CLASS_HWMON;
+       dev->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
        dev->adapter.algo = &at91_twi_algorithm;
        dev->adapter.dev.parent = dev->dev;
        dev->adapter.nr = pdev->id;
index 77df97b..c607195 100644 (file)
@@ -219,7 +219,7 @@ static const struct i2c_algorithm bcm2835_i2c_algo = {
 static int bcm2835_i2c_probe(struct platform_device *pdev)
 {
        struct bcm2835_i2c_dev *i2c_dev;
-       struct resource *mem, *requested, *irq;
+       struct resource *mem, *irq;
        u32 bus_clk_rate, divider;
        int ret;
        struct i2c_adapter *adap;
@@ -234,25 +234,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
        init_completion(&i2c_dev->completion);
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "No mem resource\n");
-               return -ENODEV;
-       }
-
-       requested = devm_request_mem_region(&pdev->dev, mem->start,
-                                           resource_size(mem),
-                                           dev_name(&pdev->dev));
-       if (!requested) {
-               dev_err(&pdev->dev, "Could not claim register region\n");
-               return -EBUSY;
-       }
-
-       i2c_dev->regs = devm_ioremap(&pdev->dev, mem->start,
-                                    resource_size(mem));
-       if (!i2c_dev->regs) {
-               dev_err(&pdev->dev, "Could not map registers\n");
-               return -ENOMEM;
-       }
+       i2c_dev->regs = devm_ioremap_resource(&pdev->dev, mem);
+       if (IS_ERR(i2c_dev->regs))
+               return PTR_ERR(i2c_dev->regs);
 
        i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(i2c_dev->clk)) {
@@ -295,7 +279,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev)
        adap = &i2c_dev->adapter;
        i2c_set_adapdata(adap, i2c_dev);
        adap->owner = THIS_MODULE;
-       adap->class = I2C_CLASS_HWMON;
+       adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
        strlcpy(adap->name, "bcm2835 I2C adapter", sizeof(adap->name));
        adap->algo = &bcm2835_i2c_algo;
        adap->dev.parent = &pdev->dev;
index 3b9bd9a..e6d5162 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
+#include <linux/i2c/bfin_twi.h>
 
-#include <asm/blackfin.h>
-#include <asm/portmux.h>
 #include <asm/irq.h>
+#include <asm/portmux.h>
 #include <asm/bfin_twi.h>
 
 /* SMBus mode*/
@@ -65,7 +65,6 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface,
                /* Transmit next data */
                while (iface->writeNum > 0 &&
                        (read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) {
-                       SSYNC();
                        write_XMT_DATA8(iface, *(iface->transPtr++));
                        iface->writeNum--;
                }
@@ -248,7 +247,6 @@ static irqreturn_t bfin_twi_interrupt_entry(int irq, void *dev_id)
                /* Clear interrupt status */
                write_INT_STAT(iface, twi_int_status);
                bfin_twi_handle_interrupt(iface, twi_int_status);
-               SSYNC();
        }
        spin_unlock_irqrestore(&iface->lock, flags);
        return IRQ_HANDLED;
@@ -294,9 +292,7 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
         *  discarded before start a new operation.
         */
        write_FIFO_CTL(iface, 0x3);
-       SSYNC();
        write_FIFO_CTL(iface, 0);
-       SSYNC();
 
        if (pmsg->flags & I2C_M_RD)
                iface->read_write = I2C_SMBUS_READ;
@@ -306,7 +302,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
                if (iface->writeNum > 0) {
                        write_XMT_DATA8(iface, *(iface->transPtr++));
                        iface->writeNum--;
-                       SSYNC();
                }
        }
 
@@ -315,7 +310,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
 
        /* Interrupt mask . Enable XMT, RCV interrupt */
        write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
-       SSYNC();
 
        if (pmsg->len <= 255)
                write_MASTER_CTL(iface, pmsg->len << 6);
@@ -329,7 +323,6 @@ static int bfin_twi_do_master_xfer(struct i2c_adapter *adap,
                (iface->msg_num > 1 ? RSTART : 0) |
                ((iface->read_write == I2C_SMBUS_READ) ? MDIR : 0) |
                ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
-       SSYNC();
 
        while (!iface->result) {
                if (!wait_for_completion_timeout(&iface->complete,
@@ -453,7 +446,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
         * start a new operation.
         */
        write_FIFO_CTL(iface, 0x3);
-       SSYNC();
        write_FIFO_CTL(iface, 0);
 
        /* clear int stat */
@@ -461,7 +453,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
 
        /* Set Transmit device address */
        write_MASTER_ADDR(iface, addr);
-       SSYNC();
 
        switch (iface->cur_mode) {
        case TWI_I2C_MODE_STANDARDSUB:
@@ -469,7 +460,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
                write_INT_MASK(iface, MCOMP | MERR |
                        ((iface->read_write == I2C_SMBUS_READ) ?
                        RCVSERV : XMTSERV));
-               SSYNC();
 
                if (iface->writeNum + 1 <= 255)
                        write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
@@ -484,7 +474,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
        case TWI_I2C_MODE_COMBINED:
                write_XMT_DATA8(iface, iface->command);
                write_INT_MASK(iface, MCOMP | MERR | RCVSERV | XMTSERV);
-               SSYNC();
 
                if (iface->writeNum > 0)
                        write_MASTER_CTL(iface, (iface->writeNum + 1) << 6);
@@ -531,7 +520,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
                write_INT_MASK(iface, MCOMP | MERR |
                        ((iface->read_write == I2C_SMBUS_READ) ?
                        RCVSERV : XMTSERV));
-               SSYNC();
 
                /* Master enable */
                write_MASTER_CTL(iface, read_MASTER_CTL(iface) | MEN |
@@ -539,7 +527,6 @@ int bfin_twi_do_smbus_xfer(struct i2c_adapter *adap, u16 addr,
                        ((CONFIG_I2C_BLACKFIN_TWI_CLK_KHZ > 100) ? FAST : 0));
                break;
        }
-       SSYNC();
 
        while (!iface->result) {
                if (!wait_for_completion_timeout(&iface->complete,
@@ -669,7 +656,7 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
        strlcpy(p_adap->name, pdev->name, sizeof(p_adap->name));
        p_adap->algo = &bfin_twi_algorithm;
        p_adap->algo_data = iface;
-       p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       p_adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
        p_adap->dev.parent = &pdev->dev;
        p_adap->timeout = 5 * HZ;
        p_adap->retries = 3;
@@ -704,7 +691,6 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev)
 
        /* Enable TWI */
        write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA);
-       SSYNC();
 
        rc = i2c_add_numbered_adapter(p_adap);
        if (rc < 0) {
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
new file mode 100644 (file)
index 0000000..63f3f03
--- /dev/null
@@ -0,0 +1,905 @@
+/*
+ * I2C bus driver for the Cadence I2C controller.
+ *
+ * Copyright (C) 2009 - 2014 Xilinx, Inc.
+ *
+ * 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/clk.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+/* Register offsets for the I2C device. */
+#define CDNS_I2C_CR_OFFSET             0x00 /* Control Register, RW */
+#define CDNS_I2C_SR_OFFSET             0x04 /* Status Register, RO */
+#define CDNS_I2C_ADDR_OFFSET           0x08 /* I2C Address Register, RW */
+#define CDNS_I2C_DATA_OFFSET           0x0C /* I2C Data Register, RW */
+#define CDNS_I2C_ISR_OFFSET            0x10 /* IRQ Status Register, RW */
+#define CDNS_I2C_XFER_SIZE_OFFSET      0x14 /* Transfer Size Register, RW */
+#define CDNS_I2C_TIME_OUT_OFFSET       0x1C /* Time Out Register, RW */
+#define CDNS_I2C_IER_OFFSET            0x24 /* IRQ Enable Register, WO */
+#define CDNS_I2C_IDR_OFFSET            0x28 /* IRQ Disable Register, WO */
+
+/* Control Register Bit mask definitions */
+#define CDNS_I2C_CR_HOLD               BIT(4) /* Hold Bus bit */
+#define CDNS_I2C_CR_ACK_EN             BIT(3)
+#define CDNS_I2C_CR_NEA                        BIT(2)
+#define CDNS_I2C_CR_MS                 BIT(1)
+/* Read or Write Master transfer 0 = Transmitter, 1 = Receiver */
+#define CDNS_I2C_CR_RW                 BIT(0)
+/* 1 = Auto init FIFO to zeroes */
+#define CDNS_I2C_CR_CLR_FIFO           BIT(6)
+#define CDNS_I2C_CR_DIVA_SHIFT         14
+#define CDNS_I2C_CR_DIVA_MASK          (3 << CDNS_I2C_CR_DIVA_SHIFT)
+#define CDNS_I2C_CR_DIVB_SHIFT         8
+#define CDNS_I2C_CR_DIVB_MASK          (0x3f << CDNS_I2C_CR_DIVB_SHIFT)
+
+/* Status Register Bit mask definitions */
+#define CDNS_I2C_SR_BA         BIT(8)
+#define CDNS_I2C_SR_RXDV       BIT(5)
+
+/*
+ * I2C Address Register Bit mask definitions
+ * Normal addressing mode uses [6:0] bits. Extended addressing mode uses [9:0]
+ * bits. A write access to this register always initiates a transfer if the I2C
+ * is in master mode.
+ */
+#define CDNS_I2C_ADDR_MASK     0x000003FF /* I2C Address Mask */
+
+/*
+ * I2C Interrupt Registers Bit mask definitions
+ * All the four interrupt registers (Status/Mask/Enable/Disable) have the same
+ * bit definitions.
+ */
+#define CDNS_I2C_IXR_ARB_LOST          BIT(9)
+#define CDNS_I2C_IXR_RX_UNF            BIT(7)
+#define CDNS_I2C_IXR_TX_OVF            BIT(6)
+#define CDNS_I2C_IXR_RX_OVF            BIT(5)
+#define CDNS_I2C_IXR_SLV_RDY           BIT(4)
+#define CDNS_I2C_IXR_TO                        BIT(3)
+#define CDNS_I2C_IXR_NACK              BIT(2)
+#define CDNS_I2C_IXR_DATA              BIT(1)
+#define CDNS_I2C_IXR_COMP              BIT(0)
+
+#define CDNS_I2C_IXR_ALL_INTR_MASK     (CDNS_I2C_IXR_ARB_LOST | \
+                                        CDNS_I2C_IXR_RX_UNF | \
+                                        CDNS_I2C_IXR_TX_OVF | \
+                                        CDNS_I2C_IXR_RX_OVF | \
+                                        CDNS_I2C_IXR_SLV_RDY | \
+                                        CDNS_I2C_IXR_TO | \
+                                        CDNS_I2C_IXR_NACK | \
+                                        CDNS_I2C_IXR_DATA | \
+                                        CDNS_I2C_IXR_COMP)
+
+#define CDNS_I2C_IXR_ERR_INTR_MASK     (CDNS_I2C_IXR_ARB_LOST | \
+                                        CDNS_I2C_IXR_RX_UNF | \
+                                        CDNS_I2C_IXR_TX_OVF | \
+                                        CDNS_I2C_IXR_RX_OVF | \
+                                        CDNS_I2C_IXR_NACK)
+
+#define CDNS_I2C_ENABLED_INTR_MASK     (CDNS_I2C_IXR_ARB_LOST | \
+                                        CDNS_I2C_IXR_RX_UNF | \
+                                        CDNS_I2C_IXR_TX_OVF | \
+                                        CDNS_I2C_IXR_RX_OVF | \
+                                        CDNS_I2C_IXR_NACK | \
+                                        CDNS_I2C_IXR_DATA | \
+                                        CDNS_I2C_IXR_COMP)
+
+#define CDNS_I2C_TIMEOUT               msecs_to_jiffies(1000)
+
+#define CDNS_I2C_FIFO_DEPTH            16
+/* FIFO depth at which the DATA interrupt occurs */
+#define CDNS_I2C_DATA_INTR_DEPTH       (CDNS_I2C_FIFO_DEPTH - 2)
+#define CDNS_I2C_MAX_TRANSFER_SIZE     255
+/* Transfer size in multiples of data interrupt depth */
+#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3)
+
+#define DRIVER_NAME            "cdns-i2c"
+
+#define CDNS_I2C_SPEED_MAX     400000
+#define CDNS_I2C_SPEED_DEFAULT 100000
+
+#define CDNS_I2C_DIVA_MAX      4
+#define CDNS_I2C_DIVB_MAX      64
+
+#define cdns_i2c_readreg(offset)       readl_relaxed(id->membase + offset)
+#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
+
+/**
+ * struct cdns_i2c - I2C device private data structure
+ * @membase:           Base address of the I2C device
+ * @adap:              I2C adapter instance
+ * @p_msg:             Message pointer
+ * @err_status:                Error status in Interrupt Status Register
+ * @xfer_done:         Transfer complete status
+ * @p_send_buf:                Pointer to transmit buffer
+ * @p_recv_buf:                Pointer to receive buffer
+ * @suspended:         Flag holding the device's PM status
+ * @send_count:                Number of bytes still expected to send
+ * @recv_count:                Number of bytes still expected to receive
+ * @irq:               IRQ number
+ * @input_clk:         Input clock to I2C controller
+ * @i2c_clk:           Maximum I2C clock speed
+ * @bus_hold_flag:     Flag used in repeated start for clearing HOLD bit
+ * @clk:               Pointer to struct clk
+ * @clk_rate_change_nb:        Notifier block for clock rate changes
+ */
+struct cdns_i2c {
+       void __iomem *membase;
+       struct i2c_adapter adap;
+       struct i2c_msg *p_msg;
+       int err_status;
+       struct completion xfer_done;
+       unsigned char *p_send_buf;
+       unsigned char *p_recv_buf;
+       u8 suspended;
+       unsigned int send_count;
+       unsigned int recv_count;
+       int irq;
+       unsigned long input_clk;
+       unsigned int i2c_clk;
+       unsigned int bus_hold_flag;
+       struct clk *clk;
+       struct notifier_block clk_rate_change_nb;
+};
+
+#define to_cdns_i2c(_nb)       container_of(_nb, struct cdns_i2c, \
+                                            clk_rate_change_nb)
+
+/**
+ * cdns_i2c_clear_bus_hold() - Clear bus hold bit
+ * @id:        Pointer to driver data struct
+ *
+ * Helper to clear the controller's bus hold bit.
+ */
+static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
+{
+       u32 reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+       if (reg & CDNS_I2C_CR_HOLD)
+               cdns_i2c_writereg(reg & ~CDNS_I2C_CR_HOLD, CDNS_I2C_CR_OFFSET);
+}
+
+/**
+ * cdns_i2c_isr - Interrupt handler for the I2C device
+ * @irq:       irq number for the I2C device
+ * @ptr:       void pointer to cdns_i2c structure
+ *
+ * This function handles the data interrupt, transfer complete interrupt and
+ * the error interrupts of the I2C device.
+ *
+ * Return: IRQ_HANDLED always
+ */
+static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
+{
+       unsigned int isr_status, avail_bytes;
+       unsigned int bytes_to_recv, bytes_to_send;
+       struct cdns_i2c *id = ptr;
+       /* Signal completion only after everything is updated */
+       int done_flag = 0;
+       irqreturn_t status = IRQ_NONE;
+
+       isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+
+       /* Handling nack and arbitration lost interrupt */
+       if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
+               done_flag = 1;
+               status = IRQ_HANDLED;
+       }
+
+       /* Handling Data interrupt */
+       if ((isr_status & CDNS_I2C_IXR_DATA) &&
+                       (id->recv_count >= CDNS_I2C_DATA_INTR_DEPTH)) {
+               /* Always read data interrupt threshold bytes */
+               bytes_to_recv = CDNS_I2C_DATA_INTR_DEPTH;
+               id->recv_count -= CDNS_I2C_DATA_INTR_DEPTH;
+               avail_bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+
+               /*
+                * if the tranfer size register value is zero, then
+                * check for the remaining bytes and update the
+                * transfer size register.
+                */
+               if (!avail_bytes) {
+                       if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
+                               cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+                                               CDNS_I2C_XFER_SIZE_OFFSET);
+                       else
+                               cdns_i2c_writereg(id->recv_count,
+                                               CDNS_I2C_XFER_SIZE_OFFSET);
+               }
+
+               /* Process the data received */
+               while (bytes_to_recv--)
+                       *(id->p_recv_buf)++ =
+                               cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
+
+               if (!id->bus_hold_flag &&
+                               (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
+                       cdns_i2c_clear_bus_hold(id);
+
+               status = IRQ_HANDLED;
+       }
+
+       /* Handling Transfer Complete interrupt */
+       if (isr_status & CDNS_I2C_IXR_COMP) {
+               if (!id->p_recv_buf) {
+                       /*
+                        * If the device is sending data If there is further
+                        * data to be sent. Calculate the available space
+                        * in FIFO and fill the FIFO with that many bytes.
+                        */
+                       if (id->send_count) {
+                               avail_bytes = CDNS_I2C_FIFO_DEPTH -
+                                   cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+                               if (id->send_count > avail_bytes)
+                                       bytes_to_send = avail_bytes;
+                               else
+                                       bytes_to_send = id->send_count;
+
+                               while (bytes_to_send--) {
+                                       cdns_i2c_writereg(
+                                               (*(id->p_send_buf)++),
+                                                CDNS_I2C_DATA_OFFSET);
+                                       id->send_count--;
+                               }
+                       } else {
+                               /*
+                                * Signal the completion of transaction and
+                                * clear the hold bus bit if there are no
+                                * further messages to be processed.
+                                */
+                               done_flag = 1;
+                       }
+                       if (!id->send_count && !id->bus_hold_flag)
+                               cdns_i2c_clear_bus_hold(id);
+               } else {
+                       if (!id->bus_hold_flag)
+                               cdns_i2c_clear_bus_hold(id);
+                       /*
+                        * If the device is receiving data, then signal
+                        * the completion of transaction and read the data
+                        * present in the FIFO. Signal the completion of
+                        * transaction.
+                        */
+                       while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
+                                       CDNS_I2C_SR_RXDV) {
+                               *(id->p_recv_buf)++ =
+                                       cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
+                               id->recv_count--;
+                       }
+                       done_flag = 1;
+               }
+
+               status = IRQ_HANDLED;
+       }
+
+       /* Update the status for errors */
+       id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK;
+       if (id->err_status)
+               status = IRQ_HANDLED;
+
+       cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
+
+       if (done_flag)
+               complete(&id->xfer_done);
+
+       return status;
+}
+
+/**
+ * cdns_i2c_mrecv - Prepare and start a master receive operation
+ * @id:                pointer to the i2c device structure
+ */
+static void cdns_i2c_mrecv(struct cdns_i2c *id)
+{
+       unsigned int ctrl_reg;
+       unsigned int isr_status;
+
+       id->p_recv_buf = id->p_msg->buf;
+       id->recv_count = id->p_msg->len;
+
+       /* Put the controller in master receive mode and clear the FIFO */
+       ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+       ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO;
+
+       if (id->p_msg->flags & I2C_M_RECV_LEN)
+               id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
+
+       /*
+        * Check for the message size against FIFO depth and set the
+        * 'hold bus' bit if it is greater than FIFO depth.
+        */
+       if (id->recv_count > CDNS_I2C_FIFO_DEPTH)
+               ctrl_reg |= CDNS_I2C_CR_HOLD;
+
+       cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+
+       /* Clear the interrupts in interrupt status register */
+       isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+       cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
+
+       /*
+        * The no. of bytes to receive is checked against the limit of
+        * max transfer size. Set transfer size register with no of bytes
+        * receive if it is less than transfer size and transfer size if
+        * it is more. Enable the interrupts.
+        */
+       if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
+               cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+                                 CDNS_I2C_XFER_SIZE_OFFSET);
+       else
+               cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
+       /* Clear the bus hold flag if bytes to receive is less than FIFO size */
+       if (!id->bus_hold_flag &&
+               ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
+               (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
+                       cdns_i2c_clear_bus_hold(id);
+       /* Set the slave address in address register - triggers operation */
+       cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
+                                               CDNS_I2C_ADDR_OFFSET);
+       cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+}
+
+/**
+ * cdns_i2c_msend - Prepare and start a master send operation
+ * @id:                pointer to the i2c device
+ */
+static void cdns_i2c_msend(struct cdns_i2c *id)
+{
+       unsigned int avail_bytes;
+       unsigned int bytes_to_send;
+       unsigned int ctrl_reg;
+       unsigned int isr_status;
+
+       id->p_recv_buf = NULL;
+       id->p_send_buf = id->p_msg->buf;
+       id->send_count = id->p_msg->len;
+
+       /* Set the controller in Master transmit mode and clear the FIFO. */
+       ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+       ctrl_reg &= ~CDNS_I2C_CR_RW;
+       ctrl_reg |= CDNS_I2C_CR_CLR_FIFO;
+
+       /*
+        * Check for the message size against FIFO depth and set the
+        * 'hold bus' bit if it is greater than FIFO depth.
+        */
+       if (id->send_count > CDNS_I2C_FIFO_DEPTH)
+               ctrl_reg |= CDNS_I2C_CR_HOLD;
+       cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+
+       /* Clear the interrupts in interrupt status register. */
+       isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+       cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
+
+       /*
+        * Calculate the space available in FIFO. Check the message length
+        * against the space available, and fill the FIFO accordingly.
+        * Enable the interrupts.
+        */
+       avail_bytes = CDNS_I2C_FIFO_DEPTH -
+                               cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+
+       if (id->send_count > avail_bytes)
+               bytes_to_send = avail_bytes;
+       else
+               bytes_to_send = id->send_count;
+
+       while (bytes_to_send--) {
+               cdns_i2c_writereg((*(id->p_send_buf)++), CDNS_I2C_DATA_OFFSET);
+               id->send_count--;
+       }
+
+       /*
+        * Clear the bus hold flag if there is no more data
+        * and if it is the last message.
+        */
+       if (!id->bus_hold_flag && !id->send_count)
+               cdns_i2c_clear_bus_hold(id);
+       /* Set the slave address in address register - triggers operation. */
+       cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK,
+                                               CDNS_I2C_ADDR_OFFSET);
+
+       cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET);
+}
+
+/**
+ * cdns_i2c_master_reset - Reset the interface
+ * @adap:      pointer to the i2c adapter driver instance
+ *
+ * This function cleanup the fifos, clear the hold bit and status
+ * and disable the interrupts.
+ */
+static void cdns_i2c_master_reset(struct i2c_adapter *adap)
+{
+       struct cdns_i2c *id = adap->algo_data;
+       u32 regval;
+
+       /* Disable the interrupts */
+       cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK, CDNS_I2C_IDR_OFFSET);
+       /* Clear the hold bit and fifos */
+       regval = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+       regval &= ~CDNS_I2C_CR_HOLD;
+       regval |= CDNS_I2C_CR_CLR_FIFO;
+       cdns_i2c_writereg(regval, CDNS_I2C_CR_OFFSET);
+       /* Update the transfercount register to zero */
+       cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET);
+       /* Clear the interupt status register */
+       regval = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+       cdns_i2c_writereg(regval, CDNS_I2C_ISR_OFFSET);
+       /* Clear the status register */
+       regval = cdns_i2c_readreg(CDNS_I2C_SR_OFFSET);
+       cdns_i2c_writereg(regval, CDNS_I2C_SR_OFFSET);
+}
+
+static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
+               struct i2c_adapter *adap)
+{
+       int ret;
+       u32 reg;
+
+       id->p_msg = msg;
+       id->err_status = 0;
+       reinit_completion(&id->xfer_done);
+
+       /* Check for the TEN Bit mode on each msg */
+       reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+       if (msg->flags & I2C_M_TEN) {
+               if (reg & CDNS_I2C_CR_NEA)
+                       cdns_i2c_writereg(reg & ~CDNS_I2C_CR_NEA,
+                                       CDNS_I2C_CR_OFFSET);
+       } else {
+               if (!(reg & CDNS_I2C_CR_NEA))
+                       cdns_i2c_writereg(reg | CDNS_I2C_CR_NEA,
+                                       CDNS_I2C_CR_OFFSET);
+       }
+
+       /* Check for the R/W flag on each msg */
+       if (msg->flags & I2C_M_RD)
+               cdns_i2c_mrecv(id);
+       else
+               cdns_i2c_msend(id);
+
+       /* Wait for the signal of completion */
+       ret = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
+       if (!ret) {
+               cdns_i2c_master_reset(adap);
+               dev_err(id->adap.dev.parent,
+                               "timeout waiting on completion\n");
+               return -ETIMEDOUT;
+       }
+
+       cdns_i2c_writereg(CDNS_I2C_IXR_ALL_INTR_MASK,
+                         CDNS_I2C_IDR_OFFSET);
+
+       /* If it is bus arbitration error, try again */
+       if (id->err_status & CDNS_I2C_IXR_ARB_LOST)
+               return -EAGAIN;
+
+       return 0;
+}
+
+/**
+ * cdns_i2c_master_xfer - The main i2c transfer function
+ * @adap:      pointer to the i2c adapter driver instance
+ * @msgs:      pointer to the i2c message structure
+ * @num:       the number of messages to transfer
+ *
+ * Initiates the send/recv activity based on the transfer message received.
+ *
+ * Return: number of msgs processed on success, negative error otherwise
+ */
+static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+                               int num)
+{
+       int ret, count;
+       u32 reg;
+       struct cdns_i2c *id = adap->algo_data;
+
+       /* Check if the bus is free */
+       if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA)
+               return -EAGAIN;
+
+       /*
+        * Set the flag to one when multiple messages are to be
+        * processed with a repeated start.
+        */
+       if (num > 1) {
+               id->bus_hold_flag = 1;
+               reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+               reg |= CDNS_I2C_CR_HOLD;
+               cdns_i2c_writereg(reg, CDNS_I2C_CR_OFFSET);
+       } else {
+               id->bus_hold_flag = 0;
+       }
+
+       /* Process the msg one by one */
+       for (count = 0; count < num; count++, msgs++) {
+               if (count == (num - 1))
+                       id->bus_hold_flag = 0;
+
+               ret = cdns_i2c_process_msg(id, msgs, adap);
+               if (ret)
+                       return ret;
+
+               /* Report the other error interrupts to application */
+               if (id->err_status) {
+                       cdns_i2c_master_reset(adap);
+
+                       if (id->err_status & CDNS_I2C_IXR_NACK)
+                               return -ENXIO;
+
+                       return -EIO;
+               }
+       }
+
+       return num;
+}
+
+/**
+ * cdns_i2c_func - Returns the supported features of the I2C driver
+ * @adap:      pointer to the i2c adapter structure
+ *
+ * Return: 32 bit value, each bit corresponding to a feature
+ */
+static u32 cdns_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR |
+               (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) |
+               I2C_FUNC_SMBUS_BLOCK_DATA;
+}
+
+static const struct i2c_algorithm cdns_i2c_algo = {
+       .master_xfer    = cdns_i2c_master_xfer,
+       .functionality  = cdns_i2c_func,
+};
+
+/**
+ * cdns_i2c_calc_divs - Calculate clock dividers
+ * @f:         I2C clock frequency
+ * @input_clk: Input clock frequency
+ * @a:         First divider (return value)
+ * @b:         Second divider (return value)
+ *
+ * f is used as input and output variable. As input it is used as target I2C
+ * frequency. On function exit f holds the actually resulting I2C frequency.
+ *
+ * Return: 0 on success, negative errno otherwise.
+ */
+static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
+               unsigned int *a, unsigned int *b)
+{
+       unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
+       unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
+       unsigned int last_error, current_error;
+
+       /* calculate (divisor_a+1) x (divisor_b+1) */
+       temp = input_clk / (22 * fscl);
+
+       /*
+        * If the calculated value is negative or 0, the fscl input is out of
+        * range. Return error.
+        */
+       if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
+               return -EINVAL;
+
+       last_error = -1;
+       for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
+               div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
+
+               if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
+                       continue;
+               div_b--;
+
+               actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
+
+               if (actual_fscl > fscl)
+                       continue;
+
+               current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
+                                                       (fscl - actual_fscl));
+
+               if (last_error > current_error) {
+                       calc_div_a = div_a;
+                       calc_div_b = div_b;
+                       best_fscl = actual_fscl;
+                       last_error = current_error;
+               }
+       }
+
+       *a = calc_div_a;
+       *b = calc_div_b;
+       *f = best_fscl;
+
+       return 0;
+}
+
+/**
+ * cdns_i2c_setclk - This function sets the serial clock rate for the I2C device
+ * @clk_in:    I2C clock input frequency in Hz
+ * @id:                Pointer to the I2C device structure
+ *
+ * The device must be idle rather than busy transferring data before setting
+ * these device options.
+ * The data rate is set by values in the control register.
+ * The formula for determining the correct register values is
+ *     Fscl = Fpclk/(22 x (divisor_a+1) x (divisor_b+1))
+ * See the hardware data sheet for a full explanation of setting the serial
+ * clock rate. The clock can not be faster than the input clock divide by 22.
+ * The two most common clock rates are 100KHz and 400KHz.
+ *
+ * Return: 0 on success, negative error otherwise
+ */
+static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id)
+{
+       unsigned int div_a, div_b;
+       unsigned int ctrl_reg;
+       int ret = 0;
+       unsigned long fscl = id->i2c_clk;
+
+       ret = cdns_i2c_calc_divs(&fscl, clk_in, &div_a, &div_b);
+       if (ret)
+               return ret;
+
+       ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
+       ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK);
+       ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) |
+                       (div_b << CDNS_I2C_CR_DIVB_SHIFT));
+       cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET);
+
+       return 0;
+}
+
+/**
+ * cdns_i2c_clk_notifier_cb - Clock rate change callback
+ * @nb:                Pointer to notifier block
+ * @event:     Notification reason
+ * @data:      Pointer to notification data object
+ *
+ * This function is called when the cdns_i2c input clock frequency changes.
+ * The callback checks whether a valid bus frequency can be generated after the
+ * change. If so, the change is acknowledged, otherwise the change is aborted.
+ * New dividers are written to the HW in the pre- or post change notification
+ * depending on the scaling direction.
+ *
+ * Return:     NOTIFY_STOP if the rate change should be aborted, NOTIFY_OK
+ *             to acknowedge the change, NOTIFY_DONE if the notification is
+ *             considered irrelevant.
+ */
+static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
+               event, void *data)
+{
+       struct clk_notifier_data *ndata = data;
+       struct cdns_i2c *id = to_cdns_i2c(nb);
+
+       if (id->suspended)
+               return NOTIFY_OK;
+
+       switch (event) {
+       case PRE_RATE_CHANGE:
+       {
+               unsigned long input_clk = ndata->new_rate;
+               unsigned long fscl = id->i2c_clk;
+               unsigned int div_a, div_b;
+               int ret;
+
+               ret = cdns_i2c_calc_divs(&fscl, input_clk, &div_a, &div_b);
+               if (ret) {
+                       dev_warn(id->adap.dev.parent,
+                                       "clock rate change rejected\n");
+                       return NOTIFY_STOP;
+               }
+
+               /* scale up */
+               if (ndata->new_rate > ndata->old_rate)
+                       cdns_i2c_setclk(ndata->new_rate, id);
+
+               return NOTIFY_OK;
+       }
+       case POST_RATE_CHANGE:
+               id->input_clk = ndata->new_rate;
+               /* scale down */
+               if (ndata->new_rate < ndata->old_rate)
+                       cdns_i2c_setclk(ndata->new_rate, id);
+               return NOTIFY_OK;
+       case ABORT_RATE_CHANGE:
+               /* scale up */
+               if (ndata->new_rate > ndata->old_rate)
+                       cdns_i2c_setclk(ndata->old_rate, id);
+               return NOTIFY_OK;
+       default:
+               return NOTIFY_DONE;
+       }
+}
+
+/**
+ * cdns_i2c_suspend - Suspend method for the driver
+ * @_dev:      Address of the platform_device structure
+ *
+ * Put the driver into low power mode.
+ *
+ * Return: 0 always
+ */
+static int __maybe_unused cdns_i2c_suspend(struct device *_dev)
+{
+       struct platform_device *pdev = container_of(_dev,
+                       struct platform_device, dev);
+       struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
+
+       clk_disable(xi2c->clk);
+       xi2c->suspended = 1;
+
+       return 0;
+}
+
+/**
+ * cdns_i2c_resume - Resume from suspend
+ * @_dev:      Address of the platform_device structure
+ *
+ * Resume operation after suspend.
+ *
+ * Return: 0 on success and error value on error
+ */
+static int __maybe_unused cdns_i2c_resume(struct device *_dev)
+{
+       struct platform_device *pdev = container_of(_dev,
+                       struct platform_device, dev);
+       struct cdns_i2c *xi2c = platform_get_drvdata(pdev);
+       int ret;
+
+       ret = clk_enable(xi2c->clk);
+       if (ret) {
+               dev_err(_dev, "Cannot enable clock.\n");
+               return ret;
+       }
+
+       xi2c->suspended = 0;
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(cdns_i2c_dev_pm_ops, cdns_i2c_suspend,
+                        cdns_i2c_resume);
+
+/**
+ * cdns_i2c_probe - Platform registration call
+ * @pdev:      Handle to the platform device structure
+ *
+ * This function does all the memory allocation and registration for the i2c
+ * device. User can modify the address mode to 10 bit address mode using the
+ * ioctl call with option I2C_TENBIT.
+ *
+ * Return: 0 on success, negative error otherwise
+ */
+static int cdns_i2c_probe(struct platform_device *pdev)
+{
+       struct resource *r_mem;
+       struct cdns_i2c *id;
+       int ret;
+
+       id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL);
+       if (!id)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, id);
+
+       r_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       id->membase = devm_ioremap_resource(&pdev->dev, r_mem);
+       if (IS_ERR(id->membase))
+               return PTR_ERR(id->membase);
+
+       id->irq = platform_get_irq(pdev, 0);
+
+       id->adap.dev.of_node = pdev->dev.of_node;
+       id->adap.algo = &cdns_i2c_algo;
+       id->adap.timeout = CDNS_I2C_TIMEOUT;
+       id->adap.retries = 3;           /* Default retry value. */
+       id->adap.algo_data = id;
+       id->adap.dev.parent = &pdev->dev;
+       init_completion(&id->xfer_done);
+       snprintf(id->adap.name, sizeof(id->adap.name),
+                "Cadence I2C at %08lx", (unsigned long)r_mem->start);
+
+       id->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(id->clk)) {
+               dev_err(&pdev->dev, "input clock not found.\n");
+               return PTR_ERR(id->clk);
+       }
+       ret = clk_prepare_enable(id->clk);
+       if (ret) {
+               dev_err(&pdev->dev, "Unable to enable clock.\n");
+               return ret;
+       }
+       id->clk_rate_change_nb.notifier_call = cdns_i2c_clk_notifier_cb;
+       if (clk_notifier_register(id->clk, &id->clk_rate_change_nb))
+               dev_warn(&pdev->dev, "Unable to register clock notifier.\n");
+       id->input_clk = clk_get_rate(id->clk);
+
+       ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+                       &id->i2c_clk);
+       if (ret || (id->i2c_clk > CDNS_I2C_SPEED_MAX))
+               id->i2c_clk = CDNS_I2C_SPEED_DEFAULT;
+
+       cdns_i2c_writereg(CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS,
+                         CDNS_I2C_CR_OFFSET);
+
+       ret = cdns_i2c_setclk(id->input_clk, id);
+       if (ret) {
+               dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk);
+               ret = -EINVAL;
+               goto err_clk_dis;
+       }
+
+       ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0,
+                                DRIVER_NAME, id);
+       if (ret) {
+               dev_err(&pdev->dev, "cannot get irq %d\n", id->irq);
+               goto err_clk_dis;
+       }
+
+       ret = i2c_add_adapter(&id->adap);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "reg adap failed: %d\n", ret);
+               goto err_clk_dis;
+       }
+
+       dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
+                id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
+
+       return 0;
+
+err_clk_dis:
+       clk_disable_unprepare(id->clk);
+       return ret;
+}
+
+/**
+ * cdns_i2c_remove - Unregister the device after releasing the resources
+ * @pdev:      Handle to the platform device structure
+ *
+ * This function frees all the resources allocated to the device.
+ *
+ * Return: 0 always
+ */
+static int cdns_i2c_remove(struct platform_device *pdev)
+{
+       struct cdns_i2c *id = platform_get_drvdata(pdev);
+
+       i2c_del_adapter(&id->adap);
+       clk_notifier_unregister(id->clk, &id->clk_rate_change_nb);
+       clk_disable_unprepare(id->clk);
+
+       return 0;
+}
+
+static const struct of_device_id cdns_i2c_of_match[] = {
+       { .compatible = "cdns,i2c-r1p10", },
+       { /* end of table */ }
+};
+MODULE_DEVICE_TABLE(of, cdns_i2c_of_match);
+
+static struct platform_driver cdns_i2c_drv = {
+       .driver = {
+               .name  = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = cdns_i2c_of_match,
+               .pm = &cdns_i2c_dev_pm_ops,
+       },
+       .probe  = cdns_i2c_probe,
+       .remove = cdns_i2c_remove,
+};
+
+module_platform_driver(cdns_i2c_drv);
+
+MODULE_AUTHOR("Xilinx Inc.");
+MODULE_DESCRIPTION("Cadence I2C bus driver");
+MODULE_LICENSE("GPL");
index af0b583..389bc68 100644 (file)
@@ -712,7 +712,7 @@ static int davinci_i2c_probe(struct platform_device *pdev)
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
-       adap->class = I2C_CLASS_HWMON;
+       adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
        strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name));
        adap->algo = &i2c_davinci_algo;
        adap->dev.parent = &pdev->dev;
index 14c4b30..22e92c3 100644 (file)
@@ -218,7 +218,7 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
                 *
                 * If your hardware is free from tHD;STA issue, try this one.
                 */
-               return (ic_clk * tSYMBOL + 5000) / 10000 - 8 + offset;
+               return (ic_clk * tSYMBOL + 500000) / 1000000 - 8 + offset;
        else
                /*
                 * Conditional expression:
@@ -234,7 +234,8 @@ i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset)
                 * The reason why we need to take into account "tf" here,
                 * is the same as described in i2c_dw_scl_lcnt().
                 */
-               return (ic_clk * (tSYMBOL + tf) + 5000) / 10000 - 3 + offset;
+               return (ic_clk * (tSYMBOL + tf) + 500000) / 1000000
+                       - 3 + offset;
 }
 
 static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
@@ -250,7 +251,7 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset)
         * account the fall time of SCL signal (tf).  Default tf value
         * should be 0.3 us, for safety.
         */
-       return ((ic_clk * (tLOW + tf) + 5000) / 10000) - 1 + offset;
+       return ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 1 + offset;
 }
 
 static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable)
@@ -287,6 +288,7 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
        u32 input_clock_khz;
        u32 hcnt, lcnt;
        u32 reg;
+       u32 sda_falling_time, scl_falling_time;
 
        input_clock_khz = dev->get_clk_rate_khz(dev);
 
@@ -308,15 +310,18 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 
        /* set standard and fast speed deviders for high/low periods */
 
+       sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
+       scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
+
        /* Standard-mode */
        hcnt = i2c_dw_scl_hcnt(input_clock_khz,
-                               40,     /* tHD;STA = tHIGH = 4.0 us */
-                               3,      /* tf = 0.3 us */
+                               4000,   /* tHD;STA = tHIGH = 4.0 us */
+                               sda_falling_time,
                                0,      /* 0: DW default, 1: Ideal */
                                0);     /* No offset */
        lcnt = i2c_dw_scl_lcnt(input_clock_khz,
-                               47,     /* tLOW = 4.7 us */
-                               3,      /* tf = 0.3 us */
+                               4700,   /* tLOW = 4.7 us */
+                               scl_falling_time,
                                0);     /* No offset */
 
        /* Allow platforms to specify the ideal HCNT and LCNT values */
@@ -330,13 +335,13 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
 
        /* Fast-mode */
        hcnt = i2c_dw_scl_hcnt(input_clock_khz,
-                               6,      /* tHD;STA = tHIGH = 0.6 us */
-                               3,      /* tf = 0.3 us */
+                               600,    /* tHD;STA = tHIGH = 0.6 us */
+                               sda_falling_time,
                                0,      /* 0: DW default, 1: Ideal */
                                0);     /* No offset */
        lcnt = i2c_dw_scl_lcnt(input_clock_khz,
-                               13,     /* tLOW = 1.3 us */
-                               3,      /* tf = 0.3 us */
+                               1300,   /* tLOW = 1.3 us */
+                               scl_falling_time,
                                0);     /* No offset */
 
        if (dev->fs_hcnt && dev->fs_lcnt) {
index e8a7565..d66b6cb 100644 (file)
@@ -99,6 +99,8 @@ struct dw_i2c_dev {
        unsigned int            rx_fifo_depth;
        int                     rx_outstanding;
        u32                     sda_hold_time;
+       u32                     sda_falling_time;
+       u32                     scl_falling_time;
        u16                     ss_hcnt;
        u16                     ss_lcnt;
        u16                     fs_hcnt;
index f6ed06c..85056c2 100644 (file)
@@ -54,6 +54,16 @@ enum dw_pci_ctl_id_t {
        medfield_3,
        medfield_4,
        medfield_5,
+
+       baytrail,
+};
+
+struct dw_scl_sda_cfg {
+       u32 ss_hcnt;
+       u32 fs_hcnt;
+       u32 ss_lcnt;
+       u32 fs_lcnt;
+       u32 sda_hold;
 };
 
 struct dw_pci_controller {
@@ -62,12 +72,29 @@ struct dw_pci_controller {
        u32 tx_fifo_depth;
        u32 rx_fifo_depth;
        u32 clk_khz;
+       u32 functionality;
+       struct dw_scl_sda_cfg *scl_sda_cfg;
 };
 
 #define INTEL_MID_STD_CFG  (DW_IC_CON_MASTER |                 \
                                DW_IC_CON_SLAVE_DISABLE |       \
                                DW_IC_CON_RESTART_EN)
 
+#define DW_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C |                       \
+                                       I2C_FUNC_SMBUS_BYTE |           \
+                                       I2C_FUNC_SMBUS_BYTE_DATA |      \
+                                       I2C_FUNC_SMBUS_WORD_DATA |      \
+                                       I2C_FUNC_SMBUS_I2C_BLOCK)
+
+/* BayTrail HCNT/LCNT/SDA hold time */
+static struct dw_scl_sda_cfg byt_config = {
+       .ss_hcnt = 0x200,
+       .fs_hcnt = 0x55,
+       .ss_lcnt = 0x200,
+       .fs_lcnt = 0x99,
+       .sda_hold = 0x6,
+};
+
 static struct  dw_pci_controller  dw_pci_controllers[] = {
        [moorestown_0] = {
                .bus_num     = 0,
@@ -132,75 +159,40 @@ static struct  dw_pci_controller  dw_pci_controllers[] = {
                .rx_fifo_depth = 32,
                .clk_khz      = 25000,
        },
+       [baytrail] = {
+               .bus_num = -1,
+               .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
+               .tx_fifo_depth = 32,
+               .rx_fifo_depth = 32,
+               .clk_khz = 100000,
+               .functionality = I2C_FUNC_10BIT_ADDR,
+               .scl_sda_cfg = &byt_config,
+       },
 };
 static struct i2c_algorithm i2c_dw_algo = {
        .master_xfer    = i2c_dw_xfer,
        .functionality  = i2c_dw_func,
 };
 
+#ifdef CONFIG_PM
 static int i2c_dw_pci_suspend(struct device *dev)
 {
        struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
-       struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
-       int err;
-
-
-       i2c_dw_disable(i2c);
-
-       err = pci_save_state(pdev);
-       if (err) {
-               dev_err(&pdev->dev, "pci_save_state failed\n");
-               return err;
-       }
-
-       err = pci_set_power_state(pdev, PCI_D3hot);
-       if (err) {
-               dev_err(&pdev->dev, "pci_set_power_state failed\n");
-               return err;
-       }
 
+       i2c_dw_disable(pci_get_drvdata(pdev));
        return 0;
 }
 
 static int i2c_dw_pci_resume(struct device *dev)
 {
        struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
-       struct dw_i2c_dev *i2c = pci_get_drvdata(pdev);
-       int err;
-       u32 enabled;
-
-       enabled = i2c_dw_is_enabled(i2c);
-       if (enabled)
-               return 0;
-
-       err = pci_set_power_state(pdev, PCI_D0);
-       if (err) {
-               dev_err(&pdev->dev, "pci_set_power_state() failed\n");
-               return err;
-       }
-
-       pci_restore_state(pdev);
-
-       i2c_dw_init(i2c);
-       return 0;
-}
 
-static int i2c_dw_pci_runtime_idle(struct device *dev)
-{
-       int err = pm_schedule_suspend(dev, 500);
-       dev_dbg(dev, "runtime_idle called\n");
-
-       if (err != 0)
-               return 0;
-       return -EBUSY;
+       return i2c_dw_init(pci_get_drvdata(pdev));
 }
+#endif
 
-static const struct dev_pm_ops i2c_dw_pm_ops = {
-       .resume         = i2c_dw_pci_resume,
-       .suspend        = i2c_dw_pci_suspend,
-       SET_RUNTIME_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume,
-                          i2c_dw_pci_runtime_idle)
-};
+static UNIVERSAL_DEV_PM_OPS(i2c_dw_pm_ops, i2c_dw_pci_suspend,
+                           i2c_dw_pci_resume, NULL);
 
 static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev)
 {
@@ -214,6 +206,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
        struct i2c_adapter *adap;
        int r;
        struct  dw_pci_controller *controller;
+       struct dw_scl_sda_cfg *cfg;
 
        if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) {
                dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__,
@@ -247,13 +240,18 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
        dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz;
        dev->base = pcim_iomap_table(pdev)[0];
        dev->dev = &pdev->dev;
-       dev->functionality =
-               I2C_FUNC_I2C |
-               I2C_FUNC_SMBUS_BYTE |
-               I2C_FUNC_SMBUS_BYTE_DATA |
-               I2C_FUNC_SMBUS_WORD_DATA |
-               I2C_FUNC_SMBUS_I2C_BLOCK;
+       dev->functionality = controller->functionality |
+                               DW_DEFAULT_FUNCTIONALITY;
+
        dev->master_cfg =  controller->bus_cfg;
+       if (controller->scl_sda_cfg) {
+               cfg = controller->scl_sda_cfg;
+               dev->ss_hcnt = cfg->ss_hcnt;
+               dev->fs_hcnt = cfg->fs_hcnt;
+               dev->ss_lcnt = cfg->ss_lcnt;
+               dev->fs_lcnt = cfg->fs_lcnt;
+               dev->sda_hold_time = cfg->sda_hold;
+       }
 
        pci_set_drvdata(pdev, dev);
 
@@ -270,8 +268,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
        adap->algo = &i2c_dw_algo;
        adap->dev.parent = &pdev->dev;
        adap->nr = controller->bus_num;
-       snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci-%d",
-               adap->nr);
+
+       snprintf(adap->name, sizeof(adap->name), "i2c-designware-pci");
 
        r = devm_request_irq(&pdev->dev, pdev->irq, i2c_dw_isr, IRQF_SHARED,
                        adap->name, dev);
@@ -290,6 +288,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
 
        pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
        pm_runtime_use_autosuspend(&pdev->dev);
+       pm_runtime_put_autosuspend(&pdev->dev);
        pm_runtime_allow(&pdev->dev);
 
        return 0;
@@ -309,7 +308,7 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
 /* work with hotplug and coldplug */
 MODULE_ALIAS("i2c_designware-pci");
 
-static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
+static const struct pci_device_id i2_designware_pci_ids[] = {
        /* Moorestown */
        { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
        { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
@@ -321,6 +320,14 @@ static DEFINE_PCI_DEVICE_TABLE(i2_designware_pci_ids) = {
        { PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
        { PCI_VDEVICE(INTEL, 0x082D), medfield_1 },
        { PCI_VDEVICE(INTEL, 0x082E), medfield_2 },
+       /* Baytrail */
+       { PCI_VDEVICE(INTEL, 0x0F41), baytrail },
+       { PCI_VDEVICE(INTEL, 0x0F42), baytrail },
+       { PCI_VDEVICE(INTEL, 0x0F43), baytrail },
+       { PCI_VDEVICE(INTEL, 0x0F44), baytrail },
+       { PCI_VDEVICE(INTEL, 0x0F45), baytrail },
+       { PCI_VDEVICE(INTEL, 0x0F46), baytrail },
+       { PCI_VDEVICE(INTEL, 0x0F47), baytrail },
        { 0,}
 };
 MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids);
index d0bdac0..9c78026 100644 (file)
@@ -159,6 +159,13 @@ static int dw_i2c_probe(struct platform_device *pdev)
                                        "i2c-sda-hold-time-ns", &ht);
                dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000,
                                             1000000);
+
+               of_property_read_u32(pdev->dev.of_node,
+                                    "i2c-sda-falling-time-ns",
+                                    &dev->sda_falling_time);
+               of_property_read_u32(pdev->dev.of_node,
+                                    "i2c-scl-falling-time-ns",
+                                    &dev->scl_falling_time);
        }
 
        dev->functionality =
@@ -195,7 +202,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
-       adap->class = I2C_CLASS_HWMON;
+       adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
        strlcpy(adap->name, "Synopsys DesignWare I2C adapter",
                        sizeof(adap->name));
        adap->algo = &i2c_dw_algo;
diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c
new file mode 100644 (file)
index 0000000..777ed40
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2014 Uwe Kleine-Koenig for Pengutronix
+ *
+ * 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/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+
+#define DRIVER_NAME "efm32-i2c"
+
+#define MASK_VAL(mask, val)            ((val << __ffs(mask)) & mask)
+
+#define REG_CTRL               0x00
+#define REG_CTRL_EN                    0x00001
+#define REG_CTRL_SLAVE                 0x00002
+#define REG_CTRL_AUTOACK               0x00004
+#define REG_CTRL_AUTOSE                        0x00008
+#define REG_CTRL_AUTOSN                        0x00010
+#define REG_CTRL_ARBDIS                        0x00020
+#define REG_CTRL_GCAMEN                        0x00040
+#define REG_CTRL_CLHR__MASK            0x00300
+#define REG_CTRL_BITO__MASK            0x03000
+#define REG_CTRL_BITO_OFF              0x00000
+#define REG_CTRL_BITO_40PCC            0x01000
+#define REG_CTRL_BITO_80PCC            0x02000
+#define REG_CTRL_BITO_160PCC           0x03000
+#define REG_CTRL_GIBITO                        0x08000
+#define REG_CTRL_CLTO__MASK            0x70000
+#define REG_CTRL_CLTO_OFF              0x00000
+
+#define REG_CMD                        0x04
+#define REG_CMD_START                  0x00001
+#define REG_CMD_STOP                   0x00002
+#define REG_CMD_ACK                    0x00004
+#define REG_CMD_NACK                   0x00008
+#define REG_CMD_CONT                   0x00010
+#define REG_CMD_ABORT                  0x00020
+#define REG_CMD_CLEARTX                        0x00040
+#define REG_CMD_CLEARPC                        0x00080
+
+#define REG_STATE              0x08
+#define REG_STATE_BUSY                 0x00001
+#define REG_STATE_MASTER               0x00002
+#define REG_STATE_TRANSMITTER          0x00004
+#define REG_STATE_NACKED               0x00008
+#define REG_STATE_BUSHOLD              0x00010
+#define REG_STATE_STATE__MASK          0x000e0
+#define REG_STATE_STATE_IDLE           0x00000
+#define REG_STATE_STATE_WAIT           0x00020
+#define REG_STATE_STATE_START          0x00040
+#define REG_STATE_STATE_ADDR           0x00060
+#define REG_STATE_STATE_ADDRACK                0x00080
+#define REG_STATE_STATE_DATA           0x000a0
+#define REG_STATE_STATE_DATAACK                0x000c0
+
+#define REG_STATUS             0x0c
+#define REG_STATUS_PSTART              0x00001
+#define REG_STATUS_PSTOP               0x00002
+#define REG_STATUS_PACK                        0x00004
+#define REG_STATUS_PNACK               0x00008
+#define REG_STATUS_PCONT               0x00010
+#define REG_STATUS_PABORT              0x00020
+#define REG_STATUS_TXC                 0x00040
+#define REG_STATUS_TXBL                        0x00080
+#define REG_STATUS_RXDATAV             0x00100
+
+#define REG_CLKDIV             0x10
+#define REG_CLKDIV_DIV__MASK           0x001ff
+#define REG_CLKDIV_DIV(div)            MASK_VAL(REG_CLKDIV_DIV__MASK, (div))
+
+#define REG_SADDR              0x14
+#define REG_SADDRMASK          0x18
+#define REG_RXDATA             0x1c
+#define REG_RXDATAP            0x20
+#define REG_TXDATA             0x24
+#define REG_IF                 0x28
+#define REG_IF_START                   0x00001
+#define REG_IF_RSTART                  0x00002
+#define REG_IF_ADDR                    0x00004
+#define REG_IF_TXC                     0x00008
+#define REG_IF_TXBL                    0x00010
+#define REG_IF_RXDATAV                 0x00020
+#define REG_IF_ACK                     0x00040
+#define REG_IF_NACK                    0x00080
+#define REG_IF_MSTOP                   0x00100
+#define REG_IF_ARBLOST                 0x00200
+#define REG_IF_BUSERR                  0x00400
+#define REG_IF_BUSHOLD                 0x00800
+#define REG_IF_TXOF                    0x01000
+#define REG_IF_RXUF                    0x02000
+#define REG_IF_BITO                    0x04000
+#define REG_IF_CLTO                    0x08000
+#define REG_IF_SSTOP                   0x10000
+
+#define REG_IFS                        0x2c
+#define REG_IFC                        0x30
+#define REG_IFC__MASK                  0x1ffcf
+
+#define REG_IEN                        0x34
+
+#define REG_ROUTE              0x38
+#define REG_ROUTE_SDAPEN               0x00001
+#define REG_ROUTE_SCLPEN               0x00002
+#define REG_ROUTE_LOCATION__MASK       0x00700
+#define REG_ROUTE_LOCATION(n)          MASK_VAL(REG_ROUTE_LOCATION__MASK, (n))
+
+struct efm32_i2c_ddata {
+       struct i2c_adapter adapter;
+
+       struct clk *clk;
+       void __iomem *base;
+       unsigned int irq;
+       u8 location;
+       unsigned long frequency;
+
+       /* transfer data */
+       struct completion done;
+       struct i2c_msg *msgs;
+       size_t num_msgs;
+       size_t current_word, current_msg;
+       int retval;
+};
+
+static u32 efm32_i2c_read32(struct efm32_i2c_ddata *ddata, unsigned offset)
+{
+       return readl(ddata->base + offset);
+}
+
+static void efm32_i2c_write32(struct efm32_i2c_ddata *ddata,
+               unsigned offset, u32 value)
+{
+       writel(value, ddata->base + offset);
+}
+
+static void efm32_i2c_send_next_msg(struct efm32_i2c_ddata *ddata)
+{
+       struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+
+       efm32_i2c_write32(ddata, REG_CMD, REG_CMD_START);
+       efm32_i2c_write32(ddata, REG_TXDATA, cur_msg->addr << 1 |
+                       (cur_msg->flags & I2C_M_RD ? 1 : 0));
+}
+
+static void efm32_i2c_send_next_byte(struct efm32_i2c_ddata *ddata)
+{
+       struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+
+       if (ddata->current_word >= cur_msg->len) {
+               /* cur_msg completely transferred */
+               ddata->current_word = 0;
+               ddata->current_msg += 1;
+
+               if (ddata->current_msg >= ddata->num_msgs) {
+                       efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+                       complete(&ddata->done);
+               } else {
+                       efm32_i2c_send_next_msg(ddata);
+               }
+       } else {
+               efm32_i2c_write32(ddata, REG_TXDATA,
+                               cur_msg->buf[ddata->current_word++]);
+       }
+}
+
+static void efm32_i2c_recv_next_byte(struct efm32_i2c_ddata *ddata)
+{
+       struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+
+       cur_msg->buf[ddata->current_word] = efm32_i2c_read32(ddata, REG_RXDATA);
+       ddata->current_word += 1;
+       if (ddata->current_word >= cur_msg->len) {
+               /* cur_msg completely transferred */
+               ddata->current_word = 0;
+               ddata->current_msg += 1;
+
+               efm32_i2c_write32(ddata, REG_CMD, REG_CMD_NACK);
+
+               if (ddata->current_msg >= ddata->num_msgs) {
+                       efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+                       complete(&ddata->done);
+               } else {
+                       efm32_i2c_send_next_msg(ddata);
+               }
+       } else {
+               efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ACK);
+       }
+}
+
+static irqreturn_t efm32_i2c_irq(int irq, void *dev_id)
+{
+       struct efm32_i2c_ddata *ddata = dev_id;
+       struct i2c_msg *cur_msg = &ddata->msgs[ddata->current_msg];
+       u32 irqflag = efm32_i2c_read32(ddata, REG_IF);
+       u32 state = efm32_i2c_read32(ddata, REG_STATE);
+
+       efm32_i2c_write32(ddata, REG_IFC, irqflag & REG_IFC__MASK);
+
+       switch (state & REG_STATE_STATE__MASK) {
+       case REG_STATE_STATE_IDLE:
+               /* arbitration lost? */
+               ddata->retval = -EAGAIN;
+               complete(&ddata->done);
+               break;
+       case REG_STATE_STATE_WAIT:
+               /*
+                * huh, this shouldn't happen.
+                * Reset hardware state and get out
+                */
+               ddata->retval = -EIO;
+               efm32_i2c_write32(ddata, REG_CMD,
+                               REG_CMD_STOP | REG_CMD_ABORT |
+                               REG_CMD_CLEARTX | REG_CMD_CLEARPC);
+               complete(&ddata->done);
+               break;
+       case REG_STATE_STATE_START:
+               /* "caller" is expected to send an address */
+               break;
+       case REG_STATE_STATE_ADDR:
+               /* wait for Ack or NAck of slave */
+               break;
+       case REG_STATE_STATE_ADDRACK:
+               if (state & REG_STATE_NACKED) {
+                       efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+                       ddata->retval = -ENXIO;
+                       complete(&ddata->done);
+               } else if (cur_msg->flags & I2C_M_RD) {
+                       /* wait for slave to send first data byte */
+               } else {
+                       efm32_i2c_send_next_byte(ddata);
+               }
+               break;
+       case REG_STATE_STATE_DATA:
+               if (cur_msg->flags & I2C_M_RD) {
+                       efm32_i2c_recv_next_byte(ddata);
+               } else {
+                       /* wait for Ack or Nack of slave */
+               }
+               break;
+       case REG_STATE_STATE_DATAACK:
+               if (state & REG_STATE_NACKED) {
+                       efm32_i2c_write32(ddata, REG_CMD, REG_CMD_STOP);
+                       complete(&ddata->done);
+               } else {
+                       efm32_i2c_send_next_byte(ddata);
+               }
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int efm32_i2c_master_xfer(struct i2c_adapter *adap,
+               struct i2c_msg *msgs, int num)
+{
+       struct efm32_i2c_ddata *ddata = i2c_get_adapdata(adap);
+       int ret;
+
+       if (ddata->msgs)
+               return -EBUSY;
+
+       ddata->msgs = msgs;
+       ddata->num_msgs = num;
+       ddata->current_word = 0;
+       ddata->current_msg = 0;
+       ddata->retval = -EIO;
+
+       reinit_completion(&ddata->done);
+
+       dev_dbg(&ddata->adapter.dev, "state: %08x, status: %08x\n",
+                       efm32_i2c_read32(ddata, REG_STATE),
+                       efm32_i2c_read32(ddata, REG_STATUS));
+
+       efm32_i2c_send_next_msg(ddata);
+
+       wait_for_completion(&ddata->done);
+
+       if (ddata->current_msg >= ddata->num_msgs)
+               ret = ddata->num_msgs;
+       else
+               ret = ddata->retval;
+
+       return ret;
+}
+
+static u32 efm32_i2c_functionality(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm efm32_i2c_algo = {
+       .master_xfer = efm32_i2c_master_xfer,
+       .functionality = efm32_i2c_functionality,
+};
+
+static u32 efm32_i2c_get_configured_location(struct efm32_i2c_ddata *ddata)
+{
+       u32 reg = efm32_i2c_read32(ddata, REG_ROUTE);
+
+       return (reg & REG_ROUTE_LOCATION__MASK) >>
+               __ffs(REG_ROUTE_LOCATION__MASK);
+}
+
+static int efm32_i2c_probe(struct platform_device *pdev)
+{
+       struct efm32_i2c_ddata *ddata;
+       struct resource *res;
+       unsigned long rate;
+       struct device_node *np = pdev->dev.of_node;
+       u32 location, frequency;
+       int ret;
+       u32 clkdiv;
+
+       if (!np)
+               return -EINVAL;
+
+       ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+       if (!ddata) {
+               dev_dbg(&pdev->dev, "failed to allocate private data\n");
+               return -ENOMEM;
+       }
+       platform_set_drvdata(pdev, ddata);
+
+       init_completion(&ddata->done);
+       strlcpy(ddata->adapter.name, pdev->name, sizeof(ddata->adapter.name));
+       ddata->adapter.owner = THIS_MODULE;
+       ddata->adapter.algo = &efm32_i2c_algo;
+       ddata->adapter.dev.parent = &pdev->dev;
+       ddata->adapter.dev.of_node = pdev->dev.of_node;
+       i2c_set_adapdata(&ddata->adapter, ddata);
+
+       ddata->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(ddata->clk)) {
+               ret = PTR_ERR(ddata->clk);
+               dev_err(&pdev->dev, "failed to get clock: %d\n", ret);
+               return ret;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "failed to determine base address\n");
+               return -ENODEV;
+       }
+
+       if (resource_size(res) < 0x42) {
+               dev_err(&pdev->dev, "memory resource too small\n");
+               return -EINVAL;
+       }
+
+       ddata->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(ddata->base))
+               return PTR_ERR(ddata->base);
+
+       ret = platform_get_irq(pdev, 0);
+       if (ret <= 0) {
+               dev_err(&pdev->dev, "failed to get irq (%d)\n", ret);
+               if (!ret)
+                       ret = -EINVAL;
+               return ret;
+       }
+
+       ddata->irq = ret;
+
+       ret = clk_prepare_enable(ddata->clk);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to enable clock (%d)\n", ret);
+               return ret;
+       }
+
+       ret = of_property_read_u32(np, "efm32,location", &location);
+       if (!ret) {
+               dev_dbg(&pdev->dev, "using location %u\n", location);
+       } else {
+               /* default to location configured in hardware */
+               location = efm32_i2c_get_configured_location(ddata);
+
+               dev_info(&pdev->dev, "fall back to location %u\n", location);
+       }
+
+       ddata->location = location;
+
+       ret = of_property_read_u32(np, "clock-frequency", &frequency);
+       if (!ret) {
+               dev_dbg(&pdev->dev, "using frequency %u\n", frequency);
+       } else {
+               frequency = 100000;
+               dev_info(&pdev->dev, "defaulting to 100 kHz\n");
+       }
+       ddata->frequency = frequency;
+
+       rate = clk_get_rate(ddata->clk);
+       if (!rate) {
+               dev_err(&pdev->dev, "there is no input clock available\n");
+               ret = -EINVAL;
+               goto err_disable_clk;
+       }
+       clkdiv = DIV_ROUND_UP(rate, 8 * ddata->frequency) - 1;
+       if (clkdiv >= 0x200) {
+               dev_err(&pdev->dev,
+                               "input clock too fast (%lu) to divide down to bus freq (%lu)",
+                               rate, ddata->frequency);
+               ret = -EINVAL;
+               goto err_disable_clk;
+       }
+
+       dev_dbg(&pdev->dev, "input clock = %lu, bus freq = %lu, clkdiv = %lu\n",
+                       rate, ddata->frequency, (unsigned long)clkdiv);
+       efm32_i2c_write32(ddata, REG_CLKDIV, REG_CLKDIV_DIV(clkdiv));
+
+       efm32_i2c_write32(ddata, REG_ROUTE, REG_ROUTE_SDAPEN |
+                       REG_ROUTE_SCLPEN |
+                       REG_ROUTE_LOCATION(ddata->location));
+
+       efm32_i2c_write32(ddata, REG_CTRL, REG_CTRL_EN |
+                       REG_CTRL_BITO_160PCC | 0 * REG_CTRL_GIBITO);
+
+       efm32_i2c_write32(ddata, REG_IFC, REG_IFC__MASK);
+       efm32_i2c_write32(ddata, REG_IEN, REG_IF_TXC | REG_IF_ACK | REG_IF_NACK
+                       | REG_IF_ARBLOST | REG_IF_BUSERR | REG_IF_RXDATAV);
+
+       /* to make bus idle */
+       efm32_i2c_write32(ddata, REG_CMD, REG_CMD_ABORT);
+
+       ret = request_irq(ddata->irq, efm32_i2c_irq, 0, DRIVER_NAME, ddata);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request irq (%d)\n", ret);
+               return ret;
+       }
+
+       ret = i2c_add_adapter(&ddata->adapter);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to add i2c adapter (%d)\n", ret);
+               free_irq(ddata->irq, ddata);
+
+err_disable_clk:
+               clk_disable_unprepare(ddata->clk);
+       }
+       return ret;
+}
+
+static int efm32_i2c_remove(struct platform_device *pdev)
+{
+       struct efm32_i2c_ddata *ddata = platform_get_drvdata(pdev);
+
+       i2c_del_adapter(&ddata->adapter);
+       free_irq(ddata->irq, ddata);
+       clk_disable_unprepare(ddata->clk);
+
+       return 0;
+}
+
+static const struct of_device_id efm32_i2c_dt_ids[] = {
+       {
+               .compatible = "energymicro,efm32-i2c",
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, efm32_i2c_dt_ids);
+
+static struct platform_driver efm32_i2c_driver = {
+       .probe = efm32_i2c_probe,
+       .remove = efm32_i2c_remove,
+
+       .driver = {
+               .name = DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = efm32_i2c_dt_ids,
+       },
+};
+module_platform_driver(efm32_i2c_driver);
+
+MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
+MODULE_DESCRIPTION("EFM32 i2c driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
index e08e458..ff775ac 100644 (file)
@@ -186,7 +186,7 @@ static DEFINE_MUTEX(pch_mutex);
 #define PCI_DEVICE_ID_ML7223_I2C       0x8010
 #define PCI_DEVICE_ID_ML7831_I2C       0x8817
 
-static DEFINE_PCI_DEVICE_TABLE(pch_pcidev_id) = {
+static const struct pci_device_id pch_pcidev_id[] = {
        { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PCH_I2C),   1, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_I2C), 2, },
        { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7223_I2C), 1, },
index 9fd711c..00af0a0 100644 (file)
@@ -566,7 +566,7 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c,
 static int exynos5_i2c_xfer(struct i2c_adapter *adap,
                        struct i2c_msg *msgs, int num)
 {
-       struct exynos5_i2c *i2c = (struct exynos5_i2c *)adap->algo_data;
+       struct exynos5_i2c *i2c = adap->algo_data;
        int i = 0, ret = 0, stop = 0;
 
        if (i2c->suspended) {
@@ -715,6 +715,7 @@ static int exynos5_i2c_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int exynos5_i2c_suspend_noirq(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -745,6 +746,7 @@ static int exynos5_i2c_resume_noirq(struct device *dev)
 
        return 0;
 }
+#endif
 
 static SIMPLE_DEV_PM_OPS(exynos5_i2c_dev_pm_ops, exynos5_i2c_suspend_noirq,
                         exynos5_i2c_resume_noirq);
index d9f7e18..02d2d4a 100644 (file)
@@ -94,6 +94,9 @@ static int of_i2c_gpio_get_pins(struct device_node *np,
        *sda_pin = of_get_gpio(np, 0);
        *scl_pin = of_get_gpio(np, 1);
 
+       if (*sda_pin == -EPROBE_DEFER || *scl_pin == -EPROBE_DEFER)
+               return -EPROBE_DEFER;
+
        if (!gpio_is_valid(*sda_pin) || !gpio_is_valid(*scl_pin)) {
                pr_err("%s: invalid GPIO pins, sda=%d/scl=%d\n",
                       np->full_name, *sda_pin, *scl_pin);
index e248257..14d2b76 100644 (file)
@@ -104,7 +104,7 @@ static struct i2c_adapter hydra_adap = {
        .algo_data      = &hydra_bit_data,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(hydra_ids) = {
+static const struct pci_device_id hydra_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_HYDRA) },
        { 0, }
 };
index 349c2d3..6777cd6 100644 (file)
@@ -60,6 +60,7 @@
   Wellsburg (PCH) MS    0x8d7f     32     hard     yes     yes     yes
   Coleto Creek (PCH)    0x23b0     32     hard     yes     yes     yes
   Wildcat Point-LP (PCH)   0x9ca2     32     hard     yes     yes     yes
+  BayTrail (SOC)        0x0f12     32     hard     yes     yes     yes
 
   Features supported by this driver:
   Software PEC                     no
                                 STATUS_ERROR_FLAGS)
 
 /* Older devices have their ID defined in <linux/pci_ids.h> */
+#define PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS     0x0f12
 #define PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS  0x1c22
 #define PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS     0x1d22
 /* Patsburg also has three 'Integrated Device Function' SMBus controllers */
@@ -789,7 +791,7 @@ static const struct i2c_algorithm smbus_algorithm = {
        .functionality  = i801_func,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
+static const struct pci_device_id i801_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) },
@@ -822,6 +824,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
        { 0, }
 };
 
index 8ce4f51..9844925 100644 (file)
@@ -182,7 +182,7 @@ struct ismt_priv {
 /**
  * ismt_ids - PCI device IDs supported by this driver
  */
-static DEFINE_PCI_DEVICE_TABLE(ismt_ids) = {
+static const struct pci_device_id ismt_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT0) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_S1200_SMT1) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMT) },
index d52d849..540ea69 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/interrupt.h>
 #include <linux/mv643xx_i2c.h>
 #include <linux/platform_device.h>
+#include <linux/reset.h>
 #include <linux/io.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -97,7 +98,6 @@ enum {
 enum {
        MV64XXX_I2C_ACTION_INVALID,
        MV64XXX_I2C_ACTION_CONTINUE,
-       MV64XXX_I2C_ACTION_SEND_START,
        MV64XXX_I2C_ACTION_SEND_RESTART,
        MV64XXX_I2C_ACTION_OFFLOAD_RESTART,
        MV64XXX_I2C_ACTION_SEND_ADDR_1,
@@ -148,6 +148,8 @@ struct mv64xxx_i2c_data {
        bool                    offload_enabled;
 /* 5us delay in order to avoid repeated start timing violation */
        bool                    errata_delay;
+       struct reset_control    *rstc;
+       bool                    irq_clear_inverted;
 };
 
 static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = {
@@ -176,11 +178,6 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data,
 {
        u32     dir = 0;
 
-       drv_data->msg = msg;
-       drv_data->byte_posn = 0;
-       drv_data->bytes_left = msg->len;
-       drv_data->aborting = 0;
-       drv_data->rc = 0;
        drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK |
                MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN;
 
@@ -206,11 +203,6 @@ static int mv64xxx_i2c_offload_msg(struct mv64xxx_i2c_data *drv_data)
        if (!drv_data->offload_enabled)
                return -EOPNOTSUPP;
 
-       drv_data->msg = msg;
-       drv_data->byte_posn = 0;
-       drv_data->bytes_left = msg->len;
-       drv_data->aborting = 0;
-       drv_data->rc = 0;
        /* Only regular transactions can be offloaded */
        if ((msg->flags & ~(I2C_M_TEN | I2C_M_RD)) != 0)
                return -EINVAL;
@@ -419,6 +411,23 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status)
        }
 }
 
+static void mv64xxx_i2c_send_start(struct mv64xxx_i2c_data *drv_data)
+{
+       drv_data->msg = drv_data->msgs;
+       drv_data->byte_posn = 0;
+       drv_data->bytes_left = drv_data->msg->len;
+       drv_data->aborting = 0;
+       drv_data->rc = 0;
+
+       /* Can we offload this msg ? */
+       if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
+               /* No, switch to standard path */
+               mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
+               writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
+                       drv_data->reg_base + drv_data->reg_offsets.control);
+       }
+}
+
 static void
 mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
 {
@@ -435,14 +444,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
 
                drv_data->msgs++;
                drv_data->num_msgs--;
-               if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
-                       drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START;
-                       writel(drv_data->cntl_bits,
-                       drv_data->reg_base + drv_data->reg_offsets.control);
+               mv64xxx_i2c_send_start(drv_data);
 
-                       /* Setup for the next message */
-                       mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
-               }
                if (drv_data->errata_delay)
                        udelay(5);
 
@@ -459,16 +462,6 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data)
                        drv_data->reg_base + drv_data->reg_offsets.control);
                break;
 
-       case MV64XXX_I2C_ACTION_SEND_START:
-               /* Can we offload this msg ? */
-               if (mv64xxx_i2c_offload_msg(drv_data) < 0) {
-                       /* No, switch to standard path */
-                       mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs);
-                       writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START,
-                               drv_data->reg_base + drv_data->reg_offsets.control);
-               }
-               break;
-
        case MV64XXX_I2C_ACTION_SEND_ADDR_1:
                writel(drv_data->addr1,
                        drv_data->reg_base + drv_data->reg_offsets.data);
@@ -566,6 +559,11 @@ mv64xxx_i2c_intr(int irq, void *dev_id)
                status = readl(drv_data->reg_base + drv_data->reg_offsets.status);
                mv64xxx_i2c_fsm(drv_data, status);
                mv64xxx_i2c_do_action(drv_data);
+
+               if (drv_data->irq_clear_inverted)
+                       writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_IFLG,
+                              drv_data->reg_base + drv_data->reg_offsets.control);
+
                rc = IRQ_HANDLED;
        }
        spin_unlock_irqrestore(&drv_data->lock, flags);
@@ -626,12 +624,11 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg,
 
        spin_lock_irqsave(&drv_data->lock, flags);
 
-       drv_data->action = MV64XXX_I2C_ACTION_SEND_START;
        drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND;
 
        drv_data->send_stop = is_last;
        drv_data->block = 1;
-       mv64xxx_i2c_do_action(drv_data);
+       mv64xxx_i2c_send_start(drv_data);
        spin_unlock_irqrestore(&drv_data->lock, flags);
 
        mv64xxx_i2c_wait_for_completion(drv_data);
@@ -685,6 +682,7 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = {
  */
 static const struct of_device_id mv64xxx_i2c_of_match_table[] = {
        { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i},
+       { .compatible = "allwinner,sun6i-a31-i2c", .data = &mv64xxx_i2c_regs_sun4i},
        { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
        { .compatible = "marvell,mv78230-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
        { .compatible = "marvell,mv78230-a0-i2c", .data = &mv64xxx_i2c_regs_mv64xxx},
@@ -759,6 +757,16 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
        }
        drv_data->irq = irq_of_parse_and_map(np, 0);
 
+       drv_data->rstc = devm_reset_control_get_optional(dev, NULL);
+       if (IS_ERR(drv_data->rstc)) {
+               if (PTR_ERR(drv_data->rstc) == -EPROBE_DEFER) {
+                       rc = -EPROBE_DEFER;
+                       goto out;
+               }
+       } else {
+               reset_control_deassert(drv_data->rstc);
+       }
+
        /* Its not yet defined how timeouts will be specified in device tree.
         * So hard code the value to 1 second.
         */
@@ -783,6 +791,10 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data,
                drv_data->offload_enabled = false;
                drv_data->errata_delay = true;
        }
+
+       if (of_device_is_compatible(np, "allwinner,sun6i-a31-i2c"))
+               drv_data->irq_clear_inverted = true;
+
 out:
        return rc;
 #endif
@@ -845,13 +857,13 @@ mv64xxx_i2c_probe(struct platform_device *pd)
        }
        if (drv_data->irq < 0) {
                rc = -ENXIO;
-               goto exit_clk;
+               goto exit_reset;
        }
 
        drv_data->adapter.dev.parent = &pd->dev;
        drv_data->adapter.algo = &mv64xxx_i2c_algo;
        drv_data->adapter.owner = THIS_MODULE;
-       drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       drv_data->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
        drv_data->adapter.nr = pd->id;
        drv_data->adapter.dev.of_node = pd->dev.of_node;
        platform_set_drvdata(pd, drv_data);
@@ -865,7 +877,7 @@ mv64xxx_i2c_probe(struct platform_device *pd)
                dev_err(&drv_data->adapter.dev,
                        "mv64xxx: Can't register intr handler irq%d: %d\n",
                        drv_data->irq, rc);
-               goto exit_clk;
+               goto exit_reset;
        } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) {
                dev_err(&drv_data->adapter.dev,
                        "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc);
@@ -876,6 +888,9 @@ mv64xxx_i2c_probe(struct platform_device *pd)
 
 exit_free_irq:
        free_irq(drv_data->irq, drv_data);
+exit_reset:
+       if (!IS_ERR_OR_NULL(drv_data->rstc))
+               reset_control_assert(drv_data->rstc);
 exit_clk:
 #if defined(CONFIG_HAVE_CLK)
        /* Not all platforms have a clk */
@@ -894,6 +909,8 @@ mv64xxx_i2c_remove(struct platform_device *dev)
 
        i2c_del_adapter(&drv_data->adapter);
        free_irq(drv_data->irq, drv_data);
+       if (!IS_ERR_OR_NULL(drv_data->rstc))
+               reset_control_assert(drv_data->rstc);
 #if defined(CONFIG_HAVE_CLK)
        /* Not all platforms have a clk */
        if (!IS_ERR(drv_data->clk)) {
index 0cde4e6..7170fc8 100644 (file)
@@ -806,7 +806,6 @@ static int mxs_i2c_probe(struct platform_device *pdev)
        struct mxs_i2c_dev *i2c;
        struct i2c_adapter *adap;
        struct resource *res;
-       resource_size_t res_size;
        int err, irq;
 
        i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL);
@@ -819,18 +818,13 @@ static int mxs_i2c_probe(struct platform_device *pdev)
        }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       irq = platform_get_irq(pdev, 0);
-
-       if (!res || irq < 0)
-               return -ENOENT;
+       i2c->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(i2c->regs))
+               return PTR_ERR(i2c->regs);
 
-       res_size = resource_size(res);
-       if (!devm_request_mem_region(dev, res->start, res_size, res->name))
-               return -EBUSY;
-
-       i2c->regs = devm_ioremap_nocache(dev, res->start, res_size);
-       if (!i2c->regs)
-               return -EBUSY;
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
 
        err = devm_request_irq(dev, irq, mxs_i2c_isr, 0, dev_name(dev), i2c);
        if (err)
index 0038c45..ee3a76c 100644 (file)
@@ -306,7 +306,7 @@ static struct i2c_algorithm smbus_algorithm = {
 };
 
 
-static DEFINE_PCI_DEVICE_TABLE(nforce2_ids) = {
+static const struct pci_device_id nforce2_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SMBUS) },
        { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3_SMBUS) },
index 4443613..28cbe1b 100644 (file)
@@ -110,22 +110,6 @@ enum i2c_freq_mode {
        I2C_FREQ_MODE_FAST_PLUS,        /* up to 1 Mb/s */
 };
 
-/**
- * struct nmk_i2c_controller - client specific controller configuration
- * @clk_freq:  clock frequency for the operation mode
- * @tft:       Tx FIFO Threshold in bytes
- * @rft:       Rx FIFO Threshold in bytes
- * @timeout    Slave response timeout(ms)
- * @sm:                speed mode
- */
-struct nmk_i2c_controller {
-       u32             clk_freq;
-       unsigned char   tft;
-       unsigned char   rft;
-       int timeout;
-       enum i2c_freq_mode      sm;
-};
-
 /**
  * struct i2c_vendor_data - per-vendor variations
  * @has_mtdws: variant has the MTDWS bit
@@ -174,12 +158,15 @@ struct i2c_nmk_client {
  * @irq: interrupt line for the controller.
  * @virtbase: virtual io memory area.
  * @clk: hardware i2c block clock.
- * @cfg: machine provided controller configuration.
  * @cli: holder of client specific data.
+ * @clk_freq: clock frequency for the operation mode
+ * @tft: Tx FIFO Threshold in bytes
+ * @rft: Rx FIFO Threshold in bytes
+ * @timeout Slave response timeout (ms)
+ * @sm: speed mode
  * @stop: stop condition.
  * @xfer_complete: acknowledge completion for a I2C message.
  * @result: controller propogated result.
- * @busy: Busy doing transfer.
  */
 struct nmk_i2c_dev {
        struct i2c_vendor_data          *vendor;
@@ -188,12 +175,15 @@ struct nmk_i2c_dev {
        int                             irq;
        void __iomem                    *virtbase;
        struct clk                      *clk;
-       struct nmk_i2c_controller       cfg;
        struct i2c_nmk_client           cli;
+       u32                             clk_freq;
+       unsigned char                   tft;
+       unsigned char                   rft;
+       int                             timeout;
+       enum i2c_freq_mode              sm;
        int                             stop;
        struct completion               xfer_complete;
        int                             result;
-       bool                            busy;
 };
 
 /* controller's abort causes */
@@ -386,7 +376,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
         * slsu = cycles / (1000000000 / f) + 1
         */
        ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk);
-       switch (dev->cfg.sm) {
+       switch (dev->sm) {
        case I2C_FREQ_MODE_FAST:
        case I2C_FREQ_MODE_FAST_PLUS:
                slsu = DIV_ROUND_UP(100, ns); /* Fast */
@@ -409,7 +399,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
         * 2 whereas it is 3 for fast and fastplus mode of
         * operation. TODO - high speed support.
         */
-       div = (dev->cfg.clk_freq > 100000) ? 3 : 2;
+       div = (dev->clk_freq > 100000) ? 3 : 2;
 
        /*
         * generate the mask for baud rate counters. The controller
@@ -419,7 +409,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
         * so set brcr1 to 0.
         */
        brcr1 = 0 << 16;
-       brcr2 = (i2c_clk/(dev->cfg.clk_freq * div)) & 0xffff;
+       brcr2 = (i2c_clk/(dev->clk_freq * div)) & 0xffff;
 
        /* set the baud rate counter register */
        writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR);
@@ -430,7 +420,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
         * TODO - support for fast mode plus (up to 1Mb/s)
         * and high speed (up to 3.4 Mb/s)
         */
-       if (dev->cfg.sm > I2C_FREQ_MODE_FAST) {
+       if (dev->sm > I2C_FREQ_MODE_FAST) {
                dev_err(&dev->adev->dev,
                        "do not support this mode defaulting to std. mode\n");
                brcr2 = i2c_clk/(100000 * 2) & 0xffff;
@@ -438,11 +428,11 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
                writel(I2C_FREQ_MODE_STANDARD << 4,
                                dev->virtbase + I2C_CR);
        }
-       writel(dev->cfg.sm << 4, dev->virtbase + I2C_CR);
+       writel(dev->sm << 4, dev->virtbase + I2C_CR);
 
        /* set the Tx and Rx FIFO threshold */
-       writel(dev->cfg.tft, dev->virtbase + I2C_TFTR);
-       writel(dev->cfg.rft, dev->virtbase + I2C_RFTR);
+       writel(dev->tft, dev->virtbase + I2C_TFTR);
+       writel(dev->rft, dev->virtbase + I2C_RFTR);
 }
 
 /**
@@ -674,28 +664,13 @@ static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags)
 static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
                struct i2c_msg msgs[], int num_msgs)
 {
-       int status;
+       int status = 0;
        int i;
        struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap);
        int j;
 
-       dev->busy = true;
-
        pm_runtime_get_sync(&dev->adev->dev);
 
-       status = clk_prepare_enable(dev->clk);
-       if (status) {
-               dev_err(&dev->adev->dev, "can't prepare_enable clock\n");
-               goto out_clk;
-       }
-
-       /* Optionaly enable pins to be muxed in and configured */
-       pinctrl_pm_select_default_state(&dev->adev->dev);
-
-       status = init_hw(dev);
-       if (status)
-               goto out;
-
        /* Attempt three times to send the message queue */
        for (j = 0; j < 3; j++) {
                /* setup the i2c controller */
@@ -716,16 +691,8 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap,
                        break;
        }
 
-out:
-       clk_disable_unprepare(dev->clk);
-out_clk:
-       /* Optionally let pins go into idle state */
-       pinctrl_pm_select_idle_state(&dev->adev->dev);
-
        pm_runtime_put_sync(&dev->adev->dev);
 
-       dev->busy = false;
-
        /* return the no. messages processed */
        if (status)
                return status;
@@ -909,22 +876,15 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg)
        return IRQ_HANDLED;
 }
 
-
-#ifdef CONFIG_PM
-static int nmk_i2c_suspend(struct device *dev)
+#ifdef CONFIG_PM_SLEEP
+static int nmk_i2c_suspend_late(struct device *dev)
 {
-       struct amba_device *adev = to_amba_device(dev);
-       struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
-
-       if (nmk_i2c->busy)
-               return -EBUSY;
-
        pinctrl_pm_select_sleep_state(dev);
 
        return 0;
 }
 
-static int nmk_i2c_resume(struct device *dev)
+static int nmk_i2c_resume_early(struct device *dev)
 {
        /* First go to the default state */
        pinctrl_pm_select_default_state(dev);
@@ -933,19 +893,48 @@ static int nmk_i2c_resume(struct device *dev)
 
        return 0;
 }
-#else
-#define nmk_i2c_suspend        NULL
-#define nmk_i2c_resume NULL
 #endif
 
-/*
- * We use noirq so that we suspend late and resume before the wakeup interrupt
- * to ensure that we do the !pm_runtime_suspended() check in resume before
- * there has been a regular pm runtime resume (via pm_runtime_get_sync()).
- */
+#ifdef CONFIG_PM
+static int nmk_i2c_runtime_suspend(struct device *dev)
+{
+       struct amba_device *adev = to_amba_device(dev);
+       struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
+
+       clk_disable_unprepare(nmk_i2c->clk);
+       pinctrl_pm_select_idle_state(dev);
+       return 0;
+}
+
+static int nmk_i2c_runtime_resume(struct device *dev)
+{
+       struct amba_device *adev = to_amba_device(dev);
+       struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev);
+       int ret;
+
+       ret = clk_prepare_enable(nmk_i2c->clk);
+       if (ret) {
+               dev_err(dev, "can't prepare_enable clock\n");
+               return ret;
+       }
+
+       pinctrl_pm_select_default_state(dev);
+
+       ret = init_hw(nmk_i2c);
+       if (ret) {
+               clk_disable_unprepare(nmk_i2c->clk);
+               pinctrl_pm_select_idle_state(dev);
+       }
+
+       return ret;
+}
+#endif
+
 static const struct dev_pm_ops nmk_i2c_pm = {
-       .suspend_noirq  = nmk_i2c_suspend,
-       .resume_noirq   = nmk_i2c_resume,
+       SET_LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early)
+       SET_PM_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend,
+                       nmk_i2c_runtime_resume,
+                       NULL)
 };
 
 static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap)
@@ -958,118 +947,98 @@ static const struct i2c_algorithm nmk_i2c_algo = {
        .functionality  = nmk_i2c_functionality
 };
 
-static struct nmk_i2c_controller u8500_i2c = {
-       .tft            = 1,      /* Tx FIFO threshold */
-       .rft            = 8,      /* Rx FIFO threshold */
-       .clk_freq       = 400000, /* fast mode operation */
-       .timeout        = 200,    /* Slave response timeout(ms) */
-       .sm             = I2C_FREQ_MODE_FAST,
-};
-
 static void nmk_i2c_of_probe(struct device_node *np,
-                       struct nmk_i2c_controller *pdata)
+                            struct nmk_i2c_dev *nmk)
 {
-       of_property_read_u32(np, "clock-frequency", &pdata->clk_freq);
+       /* Default to 100 kHz if no frequency is given in the node */
+       if (of_property_read_u32(np, "clock-frequency", &nmk->clk_freq))
+               nmk->clk_freq = 100000;
 
        /* This driver only supports 'standard' and 'fast' modes of operation. */
-       if (pdata->clk_freq <= 100000)
-               pdata->sm = I2C_FREQ_MODE_STANDARD;
+       if (nmk->clk_freq <= 100000)
+               nmk->sm = I2C_FREQ_MODE_STANDARD;
        else
-               pdata->sm = I2C_FREQ_MODE_FAST;
+               nmk->sm = I2C_FREQ_MODE_FAST;
+       nmk->tft = 1; /* Tx FIFO threshold */
+       nmk->rft = 8; /* Rx FIFO threshold */
+       nmk->timeout = 200; /* Slave response timeout(ms) */
 }
 
 static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
 {
        int ret = 0;
-       struct nmk_i2c_controller *pdata = dev_get_platdata(&adev->dev);
        struct device_node *np = adev->dev.of_node;
        struct nmk_i2c_dev      *dev;
        struct i2c_adapter *adap;
        struct i2c_vendor_data *vendor = id->data;
        u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1;
 
-       if (!pdata) {
-               if (np) {
-                       pdata = devm_kzalloc(&adev->dev, sizeof(*pdata), GFP_KERNEL);
-                       if (!pdata) {
-                               ret = -ENOMEM;
-                               goto err_no_mem;
-                       }
-                       /* Provide the default configuration as a base. */
-                       memcpy(pdata, &u8500_i2c, sizeof(struct nmk_i2c_controller));
-                       nmk_i2c_of_probe(np, pdata);
-               } else
-                       /* No i2c configuration found, using the default. */
-                       pdata = &u8500_i2c;
+       dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL);
+       if (!dev) {
+               dev_err(&adev->dev, "cannot allocate memory\n");
+               ret = -ENOMEM;
+               goto err_no_mem;
        }
+       dev->vendor = vendor;
+       dev->adev = adev;
+       nmk_i2c_of_probe(np, dev);
 
-       if (pdata->tft > max_fifo_threshold) {
+       if (dev->tft > max_fifo_threshold) {
                dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n",
-                       pdata->tft, max_fifo_threshold);
-               pdata->tft = max_fifo_threshold;
+                        dev->tft, max_fifo_threshold);
+               dev->tft = max_fifo_threshold;
        }
 
-       if (pdata->rft > max_fifo_threshold) {
+       if (dev->rft > max_fifo_threshold) {
                dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n",
-                       pdata->rft, max_fifo_threshold);
-               pdata->rft = max_fifo_threshold;
+                       dev->rft, max_fifo_threshold);
+               dev->rft = max_fifo_threshold;
        }
 
-       dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL);
-       if (!dev) {
-               dev_err(&adev->dev, "cannot allocate memory\n");
-               ret = -ENOMEM;
-               goto err_no_mem;
-       }
-       dev->vendor = vendor;
-       dev->busy = false;
-       dev->adev = adev;
        amba_set_drvdata(adev, dev);
 
-       /* Select default pin state */
-       pinctrl_pm_select_default_state(&adev->dev);
-       /* If possible, let's go to idle until the first transfer */
-       pinctrl_pm_select_idle_state(&adev->dev);
-
-       dev->virtbase = ioremap(adev->res.start, resource_size(&adev->res));
-       if (!dev->virtbase) {
+       dev->virtbase = devm_ioremap(&adev->dev, adev->res.start,
+                               resource_size(&adev->res));
+       if (IS_ERR(dev->virtbase)) {
                ret = -ENOMEM;
-               goto err_no_ioremap;
+               goto err_no_mem;
        }
 
        dev->irq = adev->irq[0];
-       ret = request_irq(dev->irq, i2c_irq_handler, 0,
+       ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0,
                                DRIVER_NAME, dev);
        if (ret) {
                dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq);
-               goto err_irq;
+               goto err_no_mem;
        }
 
        pm_suspend_ignore_children(&adev->dev, true);
 
-       dev->clk = clk_get(&adev->dev, NULL);
+       dev->clk = devm_clk_get(&adev->dev, NULL);
        if (IS_ERR(dev->clk)) {
                dev_err(&adev->dev, "could not get i2c clock\n");
                ret = PTR_ERR(dev->clk);
-               goto err_no_clk;
+               goto err_no_mem;
+       }
+
+       ret = clk_prepare_enable(dev->clk);
+       if (ret) {
+               dev_err(&adev->dev, "can't prepare_enable clock\n");
+               goto err_no_mem;
        }
 
+       init_hw(dev);
+
        adap = &dev->adap;
        adap->dev.of_node = np;
        adap->dev.parent = &adev->dev;
        adap->owner     = THIS_MODULE;
-       adap->class     = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       adap->class     = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
        adap->algo      = &nmk_i2c_algo;
-       adap->timeout   = msecs_to_jiffies(pdata->timeout);
+       adap->timeout   = msecs_to_jiffies(dev->timeout);
        snprintf(adap->name, sizeof(adap->name),
                 "Nomadik I2C at %pR", &adev->res);
 
-       /* fetch the controller configuration from machine */
-       dev->cfg.clk_freq = pdata->clk_freq;
-       dev->cfg.tft    = pdata->tft;
-       dev->cfg.rft    = pdata->rft;
-       dev->cfg.sm     = pdata->sm;
-
        i2c_set_adapdata(adap, dev);
 
        dev_info(&adev->dev,
@@ -1079,21 +1048,15 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id)
        ret = i2c_add_adapter(adap);
        if (ret) {
                dev_err(&adev->dev, "failed to add adapter\n");
-               goto err_add_adap;
+               goto err_no_adap;
        }
 
        pm_runtime_put(&adev->dev);
 
        return 0;
 
- err_add_adap:
-       clk_put(dev->clk);
- err_no_clk:
-       free_irq(dev->irq, dev);
- err_irq:
-       iounmap(dev->virtbase);
- err_no_ioremap:
-       kfree(dev);
+ err_no_adap:
+       clk_disable_unprepare(dev->clk);
  err_no_mem:
 
        return ret;
@@ -1110,13 +1073,9 @@ static int nmk_i2c_remove(struct amba_device *adev)
        clear_all_interrupts(dev);
        /* disable the controller */
        i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE);
-       free_irq(dev->irq, dev);
-       iounmap(dev->virtbase);
+       clk_disable_unprepare(dev->clk);
        if (res)
                release_mem_region(res->start, resource_size(res));
-       clk_put(dev->clk);
-       pm_runtime_disable(&adev->dev);
-       kfree(dev);
 
        return 0;
 }
index 80e06fa..1f6369f 100644 (file)
@@ -246,7 +246,7 @@ static const struct i2c_algorithm ocores_algorithm = {
 static struct i2c_adapter ocores_adapter = {
        .owner          = THIS_MODULE,
        .name           = "i2c-ocores",
-       .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+       .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED,
        .algo           = &ocores_algorithm,
 };
 
index 90dcc2e..85f8eac 100644 (file)
@@ -636,7 +636,7 @@ omap_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
        int r;
 
        r = pm_runtime_get_sync(dev->dev);
-       if (IS_ERR_VALUE(r))
+       if (r < 0)
                goto out;
 
        r = omap_i2c_wait_for_bb(dev);
@@ -1155,7 +1155,7 @@ omap_i2c_probe(struct platform_device *pdev)
        pm_runtime_use_autosuspend(dev->dev);
 
        r = pm_runtime_get_sync(dev->dev);
-       if (IS_ERR_VALUE(r))
+       if (r < 0)
                goto err_free_mem;
 
        /*
@@ -1238,7 +1238,7 @@ omap_i2c_probe(struct platform_device *pdev)
        adap = &dev->adapter;
        i2c_set_adapdata(adap, dev);
        adap->owner = THIS_MODULE;
-       adap->class = I2C_CLASS_HWMON;
+       adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
        strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name));
        adap->algo = &omap_i2c_algo;
        adap->dev.parent = &pdev->dev;
@@ -1276,7 +1276,7 @@ static int omap_i2c_remove(struct platform_device *pdev)
 
        i2c_del_adapter(&dev->adapter);
        ret = pm_runtime_get_sync(&pdev->dev);
-       if (IS_ERR_VALUE(ret))
+       if (ret < 0)
                return ret;
 
        omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
index 615f632..7a9dce4 100644 (file)
@@ -401,7 +401,7 @@ static void pasemi_smb_remove(struct pci_dev *dev)
        kfree(smbus);
 }
 
-static DEFINE_PCI_DEVICE_TABLE(pasemi_smb_ids) = {
+static const struct pci_device_id pasemi_smb_ids[] = {
        { PCI_DEVICE(0x1959, 0xa003) },
        { 0, }
 };
index 39dd8ec..a6f54ba 100644 (file)
@@ -540,7 +540,7 @@ static const struct i2c_algorithm smbus_algorithm = {
        .functionality  = piix4_func,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(piix4_ids) = {
+static const struct pci_device_id piix4_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443MX_3) },
        { PCI_DEVICE(PCI_VENDOR_ID_EFAR, PCI_DEVICE_ID_EFAR_SLC90E66_3) },
index 9639be8..417464e 100644 (file)
@@ -148,7 +148,7 @@ static void ce4100_i2c_remove(struct pci_dev *dev)
        kfree(sds);
 }
 
-static DEFINE_PCI_DEVICE_TABLE(ce4100_i2c_devices) = {
+static const struct pci_device_id ce4100_i2c_devices[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)},
        { },
 };
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
new file mode 100644 (file)
index 0000000..1b4cf14
--- /dev/null
@@ -0,0 +1,768 @@
+/*
+ * Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2014, Sony Mobile Communications AB.
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only 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/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+/* QUP Registers */
+#define QUP_CONFIG             0x000
+#define QUP_STATE              0x004
+#define QUP_IO_MODE            0x008
+#define QUP_SW_RESET           0x00c
+#define QUP_OPERATIONAL                0x018
+#define QUP_ERROR_FLAGS                0x01c
+#define QUP_ERROR_FLAGS_EN     0x020
+#define QUP_HW_VERSION         0x030
+#define QUP_MX_OUTPUT_CNT      0x100
+#define QUP_OUT_FIFO_BASE      0x110
+#define QUP_MX_WRITE_CNT       0x150
+#define QUP_MX_INPUT_CNT       0x200
+#define QUP_MX_READ_CNT                0x208
+#define QUP_IN_FIFO_BASE       0x218
+#define QUP_I2C_CLK_CTL                0x400
+#define QUP_I2C_STATUS         0x404
+
+/* QUP States and reset values */
+#define QUP_RESET_STATE                0
+#define QUP_RUN_STATE          1
+#define QUP_PAUSE_STATE                3
+#define QUP_STATE_MASK         3
+
+#define QUP_STATE_VALID                BIT(2)
+#define QUP_I2C_MAST_GEN       BIT(4)
+
+#define QUP_OPERATIONAL_RESET  0x000ff0
+#define QUP_I2C_STATUS_RESET   0xfffffc
+
+/* QUP OPERATIONAL FLAGS */
+#define QUP_I2C_NACK_FLAG      BIT(3)
+#define QUP_OUT_NOT_EMPTY      BIT(4)
+#define QUP_IN_NOT_EMPTY       BIT(5)
+#define QUP_OUT_FULL           BIT(6)
+#define QUP_OUT_SVC_FLAG       BIT(8)
+#define QUP_IN_SVC_FLAG                BIT(9)
+#define QUP_MX_OUTPUT_DONE     BIT(10)
+#define QUP_MX_INPUT_DONE      BIT(11)
+
+/* I2C mini core related values */
+#define QUP_CLOCK_AUTO_GATE    BIT(13)
+#define I2C_MINI_CORE          (2 << 8)
+#define I2C_N_VAL              15
+/* Most significant word offset in FIFO port */
+#define QUP_MSW_SHIFT          (I2C_N_VAL + 1)
+
+/* Packing/Unpacking words in FIFOs, and IO modes */
+#define QUP_OUTPUT_BLK_MODE    (1 << 10)
+#define QUP_INPUT_BLK_MODE     (1 << 12)
+#define QUP_UNPACK_EN          BIT(14)
+#define QUP_PACK_EN            BIT(15)
+
+#define QUP_REPACK_EN          (QUP_UNPACK_EN | QUP_PACK_EN)
+
+#define QUP_OUTPUT_BLOCK_SIZE(x)(((x) >> 0) & 0x03)
+#define QUP_OUTPUT_FIFO_SIZE(x)        (((x) >> 2) & 0x07)
+#define QUP_INPUT_BLOCK_SIZE(x)        (((x) >> 5) & 0x03)
+#define QUP_INPUT_FIFO_SIZE(x) (((x) >> 7) & 0x07)
+
+/* QUP tags */
+#define QUP_TAG_START          (1 << 8)
+#define QUP_TAG_DATA           (2 << 8)
+#define QUP_TAG_STOP           (3 << 8)
+#define QUP_TAG_REC            (4 << 8)
+
+/* Status, Error flags */
+#define I2C_STATUS_WR_BUFFER_FULL      BIT(0)
+#define I2C_STATUS_BUS_ACTIVE          BIT(8)
+#define I2C_STATUS_ERROR_MASK          0x38000fc
+#define QUP_STATUS_ERROR_FLAGS         0x7c
+
+#define QUP_READ_LIMIT                 256
+
+struct qup_i2c_dev {
+       struct device           *dev;
+       void __iomem            *base;
+       int                     irq;
+       struct clk              *clk;
+       struct clk              *pclk;
+       struct i2c_adapter      adap;
+
+       int                     clk_ctl;
+       int                     out_fifo_sz;
+       int                     in_fifo_sz;
+       int                     out_blk_sz;
+       int                     in_blk_sz;
+
+       unsigned long           one_byte_t;
+
+       struct i2c_msg          *msg;
+       /* Current posion in user message buffer */
+       int                     pos;
+       /* I2C protocol errors */
+       u32                     bus_err;
+       /* QUP core errors */
+       u32                     qup_err;
+
+       struct completion       xfer;
+};
+
+static irqreturn_t qup_i2c_interrupt(int irq, void *dev)
+{
+       struct qup_i2c_dev *qup = dev;
+       u32 bus_err;
+       u32 qup_err;
+       u32 opflags;
+
+       bus_err = readl(qup->base + QUP_I2C_STATUS);
+       qup_err = readl(qup->base + QUP_ERROR_FLAGS);
+       opflags = readl(qup->base + QUP_OPERATIONAL);
+
+       if (!qup->msg) {
+               /* Clear Error interrupt */
+               writel(QUP_RESET_STATE, qup->base + QUP_STATE);
+               return IRQ_HANDLED;
+       }
+
+       bus_err &= I2C_STATUS_ERROR_MASK;
+       qup_err &= QUP_STATUS_ERROR_FLAGS;
+
+       if (qup_err) {
+               /* Clear Error interrupt */
+               writel(qup_err, qup->base + QUP_ERROR_FLAGS);
+               goto done;
+       }
+
+       if (bus_err) {
+               /* Clear Error interrupt */
+               writel(QUP_RESET_STATE, qup->base + QUP_STATE);
+               goto done;
+       }
+
+       if (opflags & QUP_IN_SVC_FLAG)
+               writel(QUP_IN_SVC_FLAG, qup->base + QUP_OPERATIONAL);
+
+       if (opflags & QUP_OUT_SVC_FLAG)
+               writel(QUP_OUT_SVC_FLAG, qup->base + QUP_OPERATIONAL);
+
+done:
+       qup->qup_err = qup_err;
+       qup->bus_err = bus_err;
+       complete(&qup->xfer);
+       return IRQ_HANDLED;
+}
+
+static int qup_i2c_poll_state_mask(struct qup_i2c_dev *qup,
+                                  u32 req_state, u32 req_mask)
+{
+       int retries = 1;
+       u32 state;
+
+       /*
+        * State transition takes 3 AHB clocks cycles + 3 I2C master clock
+        * cycles. So retry once after a 1uS delay.
+        */
+       do {
+               state = readl(qup->base + QUP_STATE);
+
+               if (state & QUP_STATE_VALID &&
+                   (state & req_mask) == req_state)
+                       return 0;
+
+               udelay(1);
+       } while (retries--);
+
+       return -ETIMEDOUT;
+}
+
+static int qup_i2c_poll_state(struct qup_i2c_dev *qup, u32 req_state)
+{
+       return qup_i2c_poll_state_mask(qup, req_state, QUP_STATE_MASK);
+}
+
+static int qup_i2c_poll_state_valid(struct qup_i2c_dev *qup)
+{
+       return qup_i2c_poll_state_mask(qup, 0, 0);
+}
+
+static int qup_i2c_poll_state_i2c_master(struct qup_i2c_dev *qup)
+{
+       return qup_i2c_poll_state_mask(qup, QUP_I2C_MAST_GEN, QUP_I2C_MAST_GEN);
+}
+
+static int qup_i2c_change_state(struct qup_i2c_dev *qup, u32 state)
+{
+       if (qup_i2c_poll_state_valid(qup) != 0)
+               return -EIO;
+
+       writel(state, qup->base + QUP_STATE);
+
+       if (qup_i2c_poll_state(qup, state) != 0)
+               return -EIO;
+       return 0;
+}
+
+static int qup_i2c_wait_writeready(struct qup_i2c_dev *qup)
+{
+       unsigned long timeout;
+       u32 opflags;
+       u32 status;
+
+       timeout = jiffies + HZ;
+
+       for (;;) {
+               opflags = readl(qup->base + QUP_OPERATIONAL);
+               status = readl(qup->base + QUP_I2C_STATUS);
+
+               if (!(opflags & QUP_OUT_NOT_EMPTY) &&
+                   !(status & I2C_STATUS_BUS_ACTIVE))
+                       return 0;
+
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+
+               usleep_range(qup->one_byte_t, qup->one_byte_t * 2);
+       }
+}
+
+static void qup_i2c_set_write_mode(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+       /* Number of entries to shift out, including the start */
+       int total = msg->len + 1;
+
+       if (total < qup->out_fifo_sz) {
+               /* FIFO mode */
+               writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
+               writel(total, qup->base + QUP_MX_WRITE_CNT);
+       } else {
+               /* BLOCK mode (transfer data on chunks) */
+               writel(QUP_OUTPUT_BLK_MODE | QUP_REPACK_EN,
+                      qup->base + QUP_IO_MODE);
+               writel(total, qup->base + QUP_MX_OUTPUT_CNT);
+       }
+}
+
+static void qup_i2c_issue_write(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+       u32 addr = msg->addr << 1;
+       u32 qup_tag;
+       u32 opflags;
+       int idx;
+       u32 val;
+
+       if (qup->pos == 0) {
+               val = QUP_TAG_START | addr;
+               idx = 1;
+       } else {
+               val = 0;
+               idx = 0;
+       }
+
+       while (qup->pos < msg->len) {
+               /* Check that there's space in the FIFO for our pair */
+               opflags = readl(qup->base + QUP_OPERATIONAL);
+               if (opflags & QUP_OUT_FULL)
+                       break;
+
+               if (qup->pos == msg->len - 1)
+                       qup_tag = QUP_TAG_STOP;
+               else
+                       qup_tag = QUP_TAG_DATA;
+
+               if (idx & 1)
+                       val |= (qup_tag | msg->buf[qup->pos]) << QUP_MSW_SHIFT;
+               else
+                       val = qup_tag | msg->buf[qup->pos];
+
+               /* Write out the pair and the last odd value */
+               if (idx & 1 || qup->pos == msg->len - 1)
+                       writel(val, qup->base + QUP_OUT_FIFO_BASE);
+
+               qup->pos++;
+               idx++;
+       }
+}
+
+static int qup_i2c_write_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+       unsigned long left;
+       int ret;
+
+       qup->msg = msg;
+       qup->pos = 0;
+
+       enable_irq(qup->irq);
+
+       qup_i2c_set_write_mode(qup, msg);
+
+       ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+       if (ret)
+               goto err;
+
+       writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+       do {
+               ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+               if (ret)
+                       goto err;
+
+               qup_i2c_issue_write(qup, msg);
+
+               ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+               if (ret)
+                       goto err;
+
+               left = wait_for_completion_timeout(&qup->xfer, HZ);
+               if (!left) {
+                       writel(1, qup->base + QUP_SW_RESET);
+                       ret = -ETIMEDOUT;
+                       goto err;
+               }
+
+               if (qup->bus_err || qup->qup_err) {
+                       if (qup->bus_err & QUP_I2C_NACK_FLAG)
+                               dev_err(qup->dev, "NACK from %x\n", msg->addr);
+                       ret = -EIO;
+                       goto err;
+               }
+       } while (qup->pos < msg->len);
+
+       /* Wait for the outstanding data in the fifo to drain */
+       ret = qup_i2c_wait_writeready(qup);
+
+err:
+       disable_irq(qup->irq);
+       qup->msg = NULL;
+
+       return ret;
+}
+
+static void qup_i2c_set_read_mode(struct qup_i2c_dev *qup, int len)
+{
+       if (len < qup->in_fifo_sz) {
+               /* FIFO mode */
+               writel(QUP_REPACK_EN, qup->base + QUP_IO_MODE);
+               writel(len, qup->base + QUP_MX_READ_CNT);
+       } else {
+               /* BLOCK mode (transfer data on chunks) */
+               writel(QUP_INPUT_BLK_MODE | QUP_REPACK_EN,
+                      qup->base + QUP_IO_MODE);
+               writel(len, qup->base + QUP_MX_INPUT_CNT);
+       }
+}
+
+static void qup_i2c_issue_read(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+       u32 addr, len, val;
+
+       addr = (msg->addr << 1) | 1;
+
+       /* 0 is used to specify a length 256 (QUP_READ_LIMIT) */
+       len = (msg->len == QUP_READ_LIMIT) ? 0 : msg->len;
+
+       val = ((QUP_TAG_REC | len) << QUP_MSW_SHIFT) | QUP_TAG_START | addr;
+       writel(val, qup->base + QUP_OUT_FIFO_BASE);
+}
+
+
+static void qup_i2c_read_fifo(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+       u32 opflags;
+       u32 val = 0;
+       int idx;
+
+       for (idx = 0; qup->pos < msg->len; idx++) {
+               if ((idx & 1) == 0) {
+                       /* Check that FIFO have data */
+                       opflags = readl(qup->base + QUP_OPERATIONAL);
+                       if (!(opflags & QUP_IN_NOT_EMPTY))
+                               break;
+
+                       /* Reading 2 words at time */
+                       val = readl(qup->base + QUP_IN_FIFO_BASE);
+
+                       msg->buf[qup->pos++] = val & 0xFF;
+               } else {
+                       msg->buf[qup->pos++] = val >> QUP_MSW_SHIFT;
+               }
+       }
+}
+
+static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
+{
+       unsigned long left;
+       int ret;
+
+       /*
+        * The QUP block will issue a NACK and STOP on the bus when reaching
+        * the end of the read, the length of the read is specified as one byte
+        * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
+        */
+       if (msg->len > QUP_READ_LIMIT) {
+               dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
+                       QUP_READ_LIMIT);
+               return -EINVAL;
+       }
+
+       qup->msg = msg;
+       qup->pos  = 0;
+
+       enable_irq(qup->irq);
+
+       qup_i2c_set_read_mode(qup, msg->len);
+
+       ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+       if (ret)
+               goto err;
+
+       writel(qup->clk_ctl, qup->base + QUP_I2C_CLK_CTL);
+
+       ret = qup_i2c_change_state(qup, QUP_PAUSE_STATE);
+       if (ret)
+               goto err;
+
+       qup_i2c_issue_read(qup, msg);
+
+       ret = qup_i2c_change_state(qup, QUP_RUN_STATE);
+       if (ret)
+               goto err;
+
+       do {
+               left = wait_for_completion_timeout(&qup->xfer, HZ);
+               if (!left) {
+                       writel(1, qup->base + QUP_SW_RESET);
+                       ret = -ETIMEDOUT;
+                       goto err;
+               }
+
+               if (qup->bus_err || qup->qup_err) {
+                       if (qup->bus_err & QUP_I2C_NACK_FLAG)
+                               dev_err(qup->dev, "NACK from %x\n", msg->addr);
+                       ret = -EIO;
+                       goto err;
+               }
+
+               qup_i2c_read_fifo(qup, msg);
+       } while (qup->pos < msg->len);
+
+err:
+       disable_irq(qup->irq);
+       qup->msg = NULL;
+
+       return ret;
+}
+
+static int qup_i2c_xfer(struct i2c_adapter *adap,
+                       struct i2c_msg msgs[],
+                       int num)
+{
+       struct qup_i2c_dev *qup = i2c_get_adapdata(adap);
+       int ret, idx;
+
+       ret = pm_runtime_get_sync(qup->dev);
+       if (ret)
+               goto out;
+
+       writel(1, qup->base + QUP_SW_RESET);
+       ret = qup_i2c_poll_state(qup, QUP_RESET_STATE);
+       if (ret)
+               goto out;
+
+       /* Configure QUP as I2C mini core */
+       writel(I2C_MINI_CORE | I2C_N_VAL, qup->base + QUP_CONFIG);
+
+       for (idx = 0; idx < num; idx++) {
+               if (msgs[idx].len == 0) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               if (qup_i2c_poll_state_i2c_master(qup)) {
+                       ret = -EIO;
+                       goto out;
+               }
+
+               if (msgs[idx].flags & I2C_M_RD)
+                       ret = qup_i2c_read_one(qup, &msgs[idx]);
+               else
+                       ret = qup_i2c_write_one(qup, &msgs[idx]);
+
+               if (ret)
+                       break;
+
+               ret = qup_i2c_change_state(qup, QUP_RESET_STATE);
+               if (ret)
+                       break;
+       }
+
+       if (ret == 0)
+               ret = num;
+out:
+
+       pm_runtime_mark_last_busy(qup->dev);
+       pm_runtime_put_autosuspend(qup->dev);
+
+       return ret;
+}
+
+static u32 qup_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK);
+}
+
+static const struct i2c_algorithm qup_i2c_algo = {
+       .master_xfer    = qup_i2c_xfer,
+       .functionality  = qup_i2c_func,
+};
+
+static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
+{
+       clk_prepare_enable(qup->clk);
+       clk_prepare_enable(qup->pclk);
+}
+
+static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup)
+{
+       u32 config;
+
+       qup_i2c_change_state(qup, QUP_RESET_STATE);
+       clk_disable_unprepare(qup->clk);
+       config = readl(qup->base + QUP_CONFIG);
+       config |= QUP_CLOCK_AUTO_GATE;
+       writel(config, qup->base + QUP_CONFIG);
+       clk_disable_unprepare(qup->pclk);
+}
+
+static int qup_i2c_probe(struct platform_device *pdev)
+{
+       static const int blk_sizes[] = {4, 16, 32};
+       struct device_node *node = pdev->dev.of_node;
+       struct qup_i2c_dev *qup;
+       unsigned long one_bit_t;
+       struct resource *res;
+       u32 io_mode, hw_ver, size;
+       int ret, fs_div, hs_div;
+       int src_clk_freq;
+       u32 clk_freq = 100000;
+
+       qup = devm_kzalloc(&pdev->dev, sizeof(*qup), GFP_KERNEL);
+       if (!qup)
+               return -ENOMEM;
+
+       qup->dev = &pdev->dev;
+       init_completion(&qup->xfer);
+       platform_set_drvdata(pdev, qup);
+
+       of_property_read_u32(node, "clock-frequency", &clk_freq);
+
+       /* We support frequencies up to FAST Mode (400KHz) */
+       if (!clk_freq || clk_freq > 400000) {
+               dev_err(qup->dev, "clock frequency not supported %d\n",
+                       clk_freq);
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       qup->base = devm_ioremap_resource(qup->dev, res);
+       if (IS_ERR(qup->base))
+               return PTR_ERR(qup->base);
+
+       qup->irq = platform_get_irq(pdev, 0);
+       if (qup->irq < 0) {
+               dev_err(qup->dev, "No IRQ defined\n");
+               return qup->irq;
+       }
+
+       qup->clk = devm_clk_get(qup->dev, "core");
+       if (IS_ERR(qup->clk)) {
+               dev_err(qup->dev, "Could not get core clock\n");
+               return PTR_ERR(qup->clk);
+       }
+
+       qup->pclk = devm_clk_get(qup->dev, "iface");
+       if (IS_ERR(qup->pclk)) {
+               dev_err(qup->dev, "Could not get iface clock\n");
+               return PTR_ERR(qup->pclk);
+       }
+
+       qup_i2c_enable_clocks(qup);
+
+       /*
+        * Bootloaders might leave a pending interrupt on certain QUP's,
+        * so we reset the core before registering for interrupts.
+        */
+       writel(1, qup->base + QUP_SW_RESET);
+       ret = qup_i2c_poll_state_valid(qup);
+       if (ret)
+               goto fail;
+
+       ret = devm_request_irq(qup->dev, qup->irq, qup_i2c_interrupt,
+                              IRQF_TRIGGER_HIGH, "i2c_qup", qup);
+       if (ret) {
+               dev_err(qup->dev, "Request %d IRQ failed\n", qup->irq);
+               goto fail;
+       }
+       disable_irq(qup->irq);
+
+       hw_ver = readl(qup->base + QUP_HW_VERSION);
+       dev_dbg(qup->dev, "Revision %x\n", hw_ver);
+
+       io_mode = readl(qup->base + QUP_IO_MODE);
+
+       /*
+        * The block/fifo size w.r.t. 'actual data' is 1/2 due to 'tag'
+        * associated with each byte written/received
+        */
+       size = QUP_OUTPUT_BLOCK_SIZE(io_mode);
+       if (size >= ARRAY_SIZE(blk_sizes))
+               return -EIO;
+       qup->out_blk_sz = blk_sizes[size] / 2;
+
+       size = QUP_INPUT_BLOCK_SIZE(io_mode);
+       if (size >= ARRAY_SIZE(blk_sizes))
+               return -EIO;
+       qup->in_blk_sz = blk_sizes[size] / 2;
+
+       size = QUP_OUTPUT_FIFO_SIZE(io_mode);
+       qup->out_fifo_sz = qup->out_blk_sz * (2 << size);
+
+       size = QUP_INPUT_FIFO_SIZE(io_mode);
+       qup->in_fifo_sz = qup->in_blk_sz * (2 << size);
+
+       src_clk_freq = clk_get_rate(qup->clk);
+       fs_div = ((src_clk_freq / clk_freq) / 2) - 3;
+       hs_div = 3;
+       qup->clk_ctl = (hs_div << 8) | (fs_div & 0xff);
+
+       /*
+        * Time it takes for a byte to be clocked out on the bus.
+        * Each byte takes 9 clock cycles (8 bits + 1 ack).
+        */
+       one_bit_t = (USEC_PER_SEC / clk_freq) + 1;
+       qup->one_byte_t = one_bit_t * 9;
+
+       dev_dbg(qup->dev, "IN:block:%d, fifo:%d, OUT:block:%d, fifo:%d\n",
+               qup->in_blk_sz, qup->in_fifo_sz,
+               qup->out_blk_sz, qup->out_fifo_sz);
+
+       i2c_set_adapdata(&qup->adap, qup);
+       qup->adap.algo = &qup_i2c_algo;
+       qup->adap.dev.parent = qup->dev;
+       qup->adap.dev.of_node = pdev->dev.of_node;
+       strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
+
+       ret = i2c_add_adapter(&qup->adap);
+       if (ret)
+               goto fail;
+
+       pm_runtime_set_autosuspend_delay(qup->dev, MSEC_PER_SEC);
+       pm_runtime_use_autosuspend(qup->dev);
+       pm_runtime_set_active(qup->dev);
+       pm_runtime_enable(qup->dev);
+       return 0;
+
+fail:
+       qup_i2c_disable_clocks(qup);
+       return ret;
+}
+
+static int qup_i2c_remove(struct platform_device *pdev)
+{
+       struct qup_i2c_dev *qup = platform_get_drvdata(pdev);
+
+       disable_irq(qup->irq);
+       qup_i2c_disable_clocks(qup);
+       i2c_del_adapter(&qup->adap);
+       pm_runtime_disable(qup->dev);
+       pm_runtime_set_suspended(qup->dev);
+       return 0;
+}
+
+#ifdef CONFIG_PM
+static int qup_i2c_pm_suspend_runtime(struct device *device)
+{
+       struct qup_i2c_dev *qup = dev_get_drvdata(device);
+
+       dev_dbg(device, "pm_runtime: suspending...\n");
+       qup_i2c_disable_clocks(qup);
+       return 0;
+}
+
+static int qup_i2c_pm_resume_runtime(struct device *device)
+{
+       struct qup_i2c_dev *qup = dev_get_drvdata(device);
+
+       dev_dbg(device, "pm_runtime: resuming...\n");
+       qup_i2c_enable_clocks(qup);
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int qup_i2c_suspend(struct device *device)
+{
+       qup_i2c_pm_suspend_runtime(device);
+       return 0;
+}
+
+static int qup_i2c_resume(struct device *device)
+{
+       qup_i2c_pm_resume_runtime(device);
+       pm_runtime_mark_last_busy(device);
+       pm_request_autosuspend(device);
+       return 0;
+}
+#endif
+
+static const struct dev_pm_ops qup_i2c_qup_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(
+               qup_i2c_suspend,
+               qup_i2c_resume)
+       SET_RUNTIME_PM_OPS(
+               qup_i2c_pm_suspend_runtime,
+               qup_i2c_pm_resume_runtime,
+               NULL)
+};
+
+static const struct of_device_id qup_i2c_dt_match[] = {
+       { .compatible = "qcom,i2c-qup-v1.1.1" },
+       { .compatible = "qcom,i2c-qup-v2.1.1" },
+       { .compatible = "qcom,i2c-qup-v2.2.1" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, qup_i2c_dt_match);
+
+static struct platform_driver qup_i2c_driver = {
+       .probe  = qup_i2c_probe,
+       .remove = qup_i2c_remove,
+       .driver = {
+               .name = "i2c_qup",
+               .owner = THIS_MODULE,
+               .pm = &qup_i2c_qup_pm_ops,
+               .of_match_table = qup_i2c_dt_match,
+       },
+};
+
+module_platform_driver(qup_i2c_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:i2c_qup");
index 0282d4d..d4fa8eb 100644 (file)
@@ -638,6 +638,7 @@ static const struct of_device_id rcar_i2c_dt_ids[] = {
        { .compatible = "renesas,i2c-r8a7778", .data = (void *)I2C_RCAR_GEN1 },
        { .compatible = "renesas,i2c-r8a7779", .data = (void *)I2C_RCAR_GEN1 },
        { .compatible = "renesas,i2c-r8a7790", .data = (void *)I2C_RCAR_GEN2 },
+       { .compatible = "renesas,i2c-r8a7791", .data = (void *)I2C_RCAR_GEN2 },
        {},
 };
 MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids);
@@ -691,7 +692,7 @@ static int rcar_i2c_probe(struct platform_device *pdev)
        adap                    = &priv->adap;
        adap->nr                = pdev->id;
        adap->algo              = &rcar_i2c_algo;
-       adap->class             = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       adap->class             = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
        adap->retries           = 3;
        adap->dev.parent        = dev;
        adap->dev.of_node       = dev->of_node;
index 684d21e..ae44910 100644 (file)
@@ -601,6 +601,31 @@ static irqreturn_t s3c24xx_i2c_irq(int irqno, void *dev_id)
        return IRQ_HANDLED;
 }
 
+/*
+ * Disable the bus so that we won't get any interrupts from now on, or try
+ * to drive any lines. This is the default state when we don't have
+ * anything to send/receive.
+ *
+ * If there is an event on the bus, or we have a pre-existing event at
+ * kernel boot time, we may not notice the event and the I2C controller
+ * will lock the bus with the I2C clock line low indefinitely.
+ */
+static inline void s3c24xx_i2c_disable_bus(struct s3c24xx_i2c *i2c)
+{
+       unsigned long tmp;
+
+       /* Stop driving the I2C pins */
+       tmp = readl(i2c->regs + S3C2410_IICSTAT);
+       tmp &= ~S3C2410_IICSTAT_TXRXEN;
+       writel(tmp, i2c->regs + S3C2410_IICSTAT);
+
+       /* We don't expect any interrupts now, and don't want send acks */
+       tmp = readl(i2c->regs + S3C2410_IICCON);
+       tmp &= ~(S3C2410_IICCON_IRQEN | S3C2410_IICCON_IRQPEND |
+               S3C2410_IICCON_ACKEN);
+       writel(tmp, i2c->regs + S3C2410_IICCON);
+}
+
 
 /* s3c24xx_i2c_set_master
  *
@@ -735,7 +760,11 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c,
 
        s3c24xx_i2c_wait_idle(i2c);
 
+       s3c24xx_i2c_disable_bus(i2c);
+
  out:
+       i2c->state = STATE_IDLE;
+
        return ret;
 }
 
@@ -1004,7 +1033,6 @@ static void s3c24xx_i2c_dt_gpio_free(struct s3c24xx_i2c *i2c)
 
 static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
 {
-       unsigned long iicon = S3C2410_IICCON_IRQEN | S3C2410_IICCON_ACKEN;
        struct s3c2410_platform_i2c *pdata;
        unsigned int freq;
 
@@ -1018,12 +1046,12 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
 
        dev_info(i2c->dev, "slave address 0x%02x\n", pdata->slave_addr);
 
-       writel(iicon, i2c->regs + S3C2410_IICCON);
+       writel(0, i2c->regs + S3C2410_IICCON);
+       writel(0, i2c->regs + S3C2410_IICSTAT);
 
        /* we need to work out the divisors for the clock... */
 
        if (s3c24xx_i2c_clockrate(i2c, &freq) != 0) {
-               writel(0, i2c->regs + S3C2410_IICCON);
                dev_err(i2c->dev, "cannot meet bus frequency required\n");
                return -EINVAL;
        }
@@ -1031,7 +1059,8 @@ static int s3c24xx_i2c_init(struct s3c24xx_i2c *i2c)
        /* todo - check that the i2c lines aren't being dragged anywhere */
 
        dev_info(i2c->dev, "bus frequency set to %d KHz\n", freq);
-       dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02lx\n", iicon);
+       dev_dbg(i2c->dev, "S3C2410_IICCON=0x%02x\n",
+               readl(i2c->regs + S3C2410_IICCON));
 
        return 0;
 }
@@ -1106,7 +1135,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
        i2c->adap.owner   = THIS_MODULE;
        i2c->adap.algo    = &s3c24xx_i2c_algorithm;
        i2c->adap.retries = 2;
-       i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD;
+       i2c->adap.class   = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED;
        i2c->tx_setup     = 50;
 
        init_waitqueue_head(&i2c->wait);
index 6784f7f..8e3be7e 100644 (file)
@@ -312,7 +312,7 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev)
                goto out;
        }
        adap = &siic->adapter;
-       adap->class = I2C_CLASS_HWMON;
+       adap->class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
 
        mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        siic->base = devm_ioremap_resource(&pdev->dev, mem_res);
index 79fd96a..ac9bc33 100644 (file)
@@ -369,7 +369,7 @@ static struct i2c_adapter sis5595_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(sis5595_ids) = {
+static const struct pci_device_id sis5595_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, 
        { 0, }
 };
index 19b8505..c636673 100644 (file)
@@ -510,7 +510,7 @@ static struct i2c_adapter sis630_adapter = {
        .retries        = 3
 };
 
-static DEFINE_PCI_DEVICE_TABLE(sis630_ids) = {
+static const struct pci_device_id sis630_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) },
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) },
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_964) },
index f8aa0c2..8dc2fc5 100644 (file)
@@ -244,7 +244,7 @@ static struct i2c_adapter sis96x_adapter = {
        .algo           = &smbus_algorithm,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(sis96x_ids) = {
+static const struct pci_device_id sis96x_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) },
        { 0, }
 };
index 9cf715d..8720161 100644 (file)
@@ -574,7 +574,7 @@ static irqreturn_t st_i2c_isr_thread(int irq, void *data)
                writel_relaxed(it, i2c_dev->base + SSC_IEN);
 
                st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STOPG);
-               c->result = -EIO;
+               c->result = -EAGAIN;
                break;
 
        default:
index 5b80ef3..29b1fb7 100644 (file)
@@ -911,7 +911,7 @@ static int stu300_probe(struct platform_device *pdev)
        adap = &dev->adapter;
        adap->owner = THIS_MODULE;
        /* DDC class but actually often used for more generic I2C */
-       adap->class = I2C_CLASS_DDC;
+       adap->class = I2C_CLASS_DDC | I2C_CLASS_DEPRECATED;
        strlcpy(adap->name, "ST Microelectronics DDC I2C adapter",
                sizeof(adap->name));
        adap->nr = bus_nr;
index 9704537..00f04cb 100644 (file)
@@ -794,7 +794,7 @@ static int tegra_i2c_probe(struct platform_device *pdev)
 
        i2c_set_adapdata(&i2c_dev->adapter, i2c_dev);
        i2c_dev->adapter.owner = THIS_MODULE;
-       i2c_dev->adapter.class = I2C_CLASS_HWMON;
+       i2c_dev->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED;
        strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter",
                sizeof(i2c_dev->adapter.name));
        i2c_dev->adapter.algo = &tegra_i2c_algo;
index 49d7f14..f4a1ed7 100644 (file)
@@ -88,7 +88,7 @@ static struct i2c_adapter vt586b_adapter = {
 };
 
 
-static DEFINE_PCI_DEVICE_TABLE(vt586b_ids) = {
+static const struct pci_device_id vt586b_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C586_3) },
        { 0, }
 };
index 40d36df..6841200 100644 (file)
@@ -442,7 +442,7 @@ release_region:
        return error;
 }
 
-static DEFINE_PCI_DEVICE_TABLE(vt596_ids) = {
+static const struct pci_device_id vt596_ids[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596_3),
          .driver_data = SMBBA1 },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C596B_3),
index 2810750..7731f17 100644 (file)
@@ -684,7 +684,7 @@ static const struct i2c_algorithm xiic_algorithm = {
 static struct i2c_adapter xiic_adapter = {
        .owner          = THIS_MODULE,
        .name           = DRIVER_NAME,
-       .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+       .class          = I2C_CLASS_HWMON | I2C_CLASS_SPD | I2C_CLASS_DEPRECATED,
        .algo           = &xiic_algorithm,
 };
 
index 2d1d2c5..cb66f95 100644 (file)
@@ -556,7 +556,7 @@ static struct platform_driver scx200_pci_driver = {
        .remove = scx200_remove,
 };
 
-static DEFINE_PCI_DEVICE_TABLE(scx200_isa) = {
+static const struct pci_device_id scx200_isa[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SCx200_BRIDGE) },
        { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_SC1100_BRIDGE) },
        { 0, }
index 5fb80b8..7c7f4b8 100644 (file)
 #include <linux/rwsem.h>
 #include <linux/pm_runtime.h>
 #include <linux/acpi.h>
+#include <linux/jump_label.h>
 #include <asm/uaccess.h>
 
 #include "i2c-core.h"
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/i2c.h>
 
 /* core_lock protects i2c_adapter_idr, and guarantees
    that device detection, deletion of detected devices, and attach_adapter
@@ -62,6 +65,18 @@ static DEFINE_IDR(i2c_adapter_idr);
 static struct device_type i2c_client_type;
 static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver);
 
+static struct static_key i2c_trace_msg = STATIC_KEY_INIT_FALSE;
+
+void i2c_transfer_trace_reg(void)
+{
+       static_key_slow_inc(&i2c_trace_msg);
+}
+
+void i2c_transfer_trace_unreg(void)
+{
+       static_key_slow_dec(&i2c_trace_msg);
+}
+
 /* ------------------------------------------------------------------------- */
 
 static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
@@ -1686,6 +1701,7 @@ static void __exit i2c_exit(void)
        class_compat_unregister(i2c_adapter_compat_class);
 #endif
        bus_unregister(&i2c_bus_type);
+       tracepoint_synchronize_unregister();
 }
 
 /* We must initialize early, because some subsystems register i2c drivers
@@ -1716,6 +1732,19 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
        unsigned long orig_jiffies;
        int ret, try;
 
+       /* i2c_trace_msg gets enabled when tracepoint i2c_transfer gets
+        * enabled.  This is an efficient way of keeping the for-loop from
+        * being executed when not needed.
+        */
+       if (static_key_false(&i2c_trace_msg)) {
+               int i;
+               for (i = 0; i < num; i++)
+                       if (msgs[i].flags & I2C_M_RD)
+                               trace_i2c_read(adap, &msgs[i], i);
+                       else
+                               trace_i2c_write(adap, &msgs[i], i);
+       }
+
        /* Retry automatically on arbitration loss */
        orig_jiffies = jiffies;
        for (ret = 0, try = 0; try <= adap->retries; try++) {
@@ -1726,6 +1755,14 @@ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
                        break;
        }
 
+       if (static_key_false(&i2c_trace_msg)) {
+               int i;
+               for (i = 0; i < ret; i++)
+                       if (msgs[i].flags & I2C_M_RD)
+                               trace_i2c_reply(adap, &msgs[i], i);
+               trace_i2c_result(adap, i, ret);
+       }
+
        return ret;
 }
 EXPORT_SYMBOL(__i2c_transfer);
@@ -1941,6 +1978,13 @@ static int i2c_detect_address(struct i2c_client *temp_client,
                struct i2c_client *client;
 
                /* Detection succeeded, instantiate the device */
+               if (adapter->class & I2C_CLASS_DEPRECATED)
+                       dev_warn(&adapter->dev,
+                               "This adapter will soon drop class based instantiation of devices. "
+                               "Please make sure client 0x%02x gets instantiated by other means. "
+                               "Check 'Documentation/i2c/instantiating-devices' for details.\n",
+                               info.addr);
+
                dev_dbg(&adapter->dev, "Creating %s at 0x%02x\n",
                        info.type, info.addr);
                client = i2c_new_device(adapter, &info);
@@ -2521,6 +2565,14 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
        int try;
        s32 res;
 
+       /* If enabled, the following two tracepoints are conditional on
+        * read_write and protocol.
+        */
+       trace_smbus_write(adapter, addr, flags, read_write,
+                         command, protocol, data);
+       trace_smbus_read(adapter, addr, flags, read_write,
+                        command, protocol);
+
        flags &= I2C_M_TEN | I2C_CLIENT_PEC | I2C_CLIENT_SCCB;
 
        if (adapter->algo->smbus_xfer) {
@@ -2541,15 +2593,24 @@ s32 i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags,
                i2c_unlock_adapter(adapter);
 
                if (res != -EOPNOTSUPP || !adapter->algo->master_xfer)
-                       return res;
+                       goto trace;
                /*
                 * Fall back to i2c_smbus_xfer_emulated if the adapter doesn't
                 * implement native support for the SMBus operation.
                 */
        }
 
-       return i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
-                                      command, protocol, data);
+       res = i2c_smbus_xfer_emulated(adapter, addr, flags, read_write,
+                                     command, protocol, data);
+
+trace:
+       /* If enabled, the reply tracepoint is conditional on read_write. */
+       trace_smbus_reply(adapter, addr, flags, read_write,
+                         command, protocol, data);
+       trace_smbus_result(adapter, addr, flags, read_write,
+                          command, protocol, res);
+
+       return res;
 }
 EXPORT_SYMBOL(i2c_smbus_xfer);
 
index 8e1939f..51493ed 100644 (file)
@@ -681,14 +681,19 @@ static int __init intel_idle_init(void)
        if (intel_idle_cpuidle_devices == NULL)
                return -ENOMEM;
 
+       cpu_notifier_register_begin();
+
        for_each_online_cpu(i) {
                retval = intel_idle_cpu_init(i);
                if (retval) {
+                       cpu_notifier_register_done();
                        cpuidle_unregister_driver(&intel_idle_driver);
                        return retval;
                }
        }
-       register_cpu_notifier(&cpu_hotplug_notifier);
+       __register_cpu_notifier(&cpu_hotplug_notifier);
+
+       cpu_notifier_register_done();
 
        return 0;
 }
@@ -698,10 +703,13 @@ static void __exit intel_idle_exit(void)
        intel_idle_cpuidle_devices_uninit();
        cpuidle_unregister_driver(&intel_idle_driver);
 
+       cpu_notifier_register_begin();
 
        if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
                on_each_cpu(__setup_broadcast_timer, (void *)false, 1);
-       unregister_cpu_notifier(&cpu_hotplug_notifier);
+       __unregister_cpu_notifier(&cpu_hotplug_notifier);
+
+       cpu_notifier_register_done();
 
        return;
 }
index 4bf4c16..d86196c 100644 (file)
@@ -193,6 +193,16 @@ config TI_AM335X_ADC
          Say yes here to build support for Texas Instruments ADC
          driver which is also a MFD client.
 
+config TWL4030_MADC
+       tristate "TWL4030 MADC (Monitoring A/D Converter)"
+       depends on TWL4030_CORE
+       help
+       This driver provides support for Triton TWL4030-MADC. The
+       driver supports both RT and SW conversion methods.
+
+       This driver can also be built as a module. If so, the module will be
+       called twl4030-madc.
+
 config TWL6030_GPADC
        tristate "TWL6030 GPADC (General Purpose A/D Converter) Support"
        depends on TWL4030_CORE
index bb25254..ab346d8 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
 obj-$(CONFIG_NAU7802) += nau7802.o
 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
 obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o
+obj-$(CONFIG_TWL4030_MADC) += twl4030-madc.o
 obj-$(CONFIG_TWL6030_GPADC) += twl6030-gpadc.o
 obj-$(CONFIG_VF610_ADC) += vf610_adc.o
 obj-$(CONFIG_VIPERBOARD_ADC) += viperboard_adc.o
diff --git a/drivers/iio/adc/twl4030-madc.c b/drivers/iio/adc/twl4030-madc.c
new file mode 100644 (file)
index 0000000..7de1c4c
--- /dev/null
@@ -0,0 +1,895 @@
+/*
+ *
+ * TWL4030 MADC module driver-This driver monitors the real time
+ * conversion of analog signals like battery temperature,
+ * battery type, battery level etc.
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
+ * J Keerthy <j-keerthy@ti.com>
+ *
+ * Based on twl4030-madc.c
+ * Copyright (C) 2008 Nokia Corporation
+ * Mikko Ylinen <mikko.k.ylinen@nokia.com>
+ *
+ * Amit Kucheria <amit.kucheria@canonical.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/i2c/twl.h>
+#include <linux/i2c/twl4030-madc.h>
+#include <linux/module.h>
+#include <linux/stddef.h>
+#include <linux/mutex.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
+#include <linux/types.h>
+#include <linux/gfp.h>
+#include <linux/err.h>
+
+#include <linux/iio/iio.h>
+
+/**
+ * struct twl4030_madc_data - a container for madc info
+ * @dev:               Pointer to device structure for madc
+ * @lock:              Mutex protecting this data structure
+ * @requests:          Array of request struct corresponding to SW1, SW2 and RT
+ * @use_second_irq:    IRQ selection (main or co-processor)
+ * @imr:               Interrupt mask register of MADC
+ * @isr:               Interrupt status register of MADC
+ */
+struct twl4030_madc_data {
+       struct device *dev;
+       struct mutex lock;      /* mutex protecting this data structure */
+       struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
+       bool use_second_irq;
+       u8 imr;
+       u8 isr;
+};
+
+static int twl4030_madc_read(struct iio_dev *iio_dev,
+                            const struct iio_chan_spec *chan,
+                            int *val, int *val2, long mask)
+{
+       struct twl4030_madc_data *madc = iio_priv(iio_dev);
+       struct twl4030_madc_request req;
+       int ret;
+
+       req.method = madc->use_second_irq ? TWL4030_MADC_SW2 : TWL4030_MADC_SW1;
+
+       req.channels = BIT(chan->channel);
+       req.active = false;
+       req.func_cb = NULL;
+       req.type = TWL4030_MADC_WAIT;
+       req.raw = !(mask == IIO_CHAN_INFO_PROCESSED);
+       req.do_avg = (mask == IIO_CHAN_INFO_AVERAGE_RAW);
+
+       ret = twl4030_madc_conversion(&req);
+       if (ret < 0)
+               return ret;
+
+       *val = req.rbuf[chan->channel];
+
+       return IIO_VAL_INT;
+}
+
+static const struct iio_info twl4030_madc_iio_info = {
+       .read_raw = &twl4030_madc_read,
+       .driver_module = THIS_MODULE,
+};
+
+#define TWL4030_ADC_CHANNEL(_channel, _type, _name) {  \
+       .type = _type,                                  \
+       .channel = _channel,                            \
+       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |  \
+                             BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \
+                             BIT(IIO_CHAN_INFO_PROCESSED), \
+       .datasheet_name = _name,                        \
+       .indexed = 1,                                   \
+}
+
+static const struct iio_chan_spec twl4030_madc_iio_channels[] = {
+       TWL4030_ADC_CHANNEL(0, IIO_VOLTAGE, "ADCIN0"),
+       TWL4030_ADC_CHANNEL(1, IIO_TEMP, "ADCIN1"),
+       TWL4030_ADC_CHANNEL(2, IIO_VOLTAGE, "ADCIN2"),
+       TWL4030_ADC_CHANNEL(3, IIO_VOLTAGE, "ADCIN3"),
+       TWL4030_ADC_CHANNEL(4, IIO_VOLTAGE, "ADCIN4"),
+       TWL4030_ADC_CHANNEL(5, IIO_VOLTAGE, "ADCIN5"),
+       TWL4030_ADC_CHANNEL(6, IIO_VOLTAGE, "ADCIN6"),
+       TWL4030_ADC_CHANNEL(7, IIO_VOLTAGE, "ADCIN7"),
+       TWL4030_ADC_CHANNEL(8, IIO_VOLTAGE, "ADCIN8"),
+       TWL4030_ADC_CHANNEL(9, IIO_VOLTAGE, "ADCIN9"),
+       TWL4030_ADC_CHANNEL(10, IIO_CURRENT, "ADCIN10"),
+       TWL4030_ADC_CHANNEL(11, IIO_VOLTAGE, "ADCIN11"),
+       TWL4030_ADC_CHANNEL(12, IIO_VOLTAGE, "ADCIN12"),
+       TWL4030_ADC_CHANNEL(13, IIO_VOLTAGE, "ADCIN13"),
+       TWL4030_ADC_CHANNEL(14, IIO_VOLTAGE, "ADCIN14"),
+       TWL4030_ADC_CHANNEL(15, IIO_VOLTAGE, "ADCIN15"),
+};
+
+static struct twl4030_madc_data *twl4030_madc;
+
+struct twl4030_prescale_divider_ratios {
+       s16 numerator;
+       s16 denominator;
+};
+
+static const struct twl4030_prescale_divider_ratios
+twl4030_divider_ratios[16] = {
+       {1, 1},         /* CHANNEL 0 No Prescaler */
+       {1, 1},         /* CHANNEL 1 No Prescaler */
+       {6, 10},        /* CHANNEL 2 */
+       {6, 10},        /* CHANNEL 3 */
+       {6, 10},        /* CHANNEL 4 */
+       {6, 10},        /* CHANNEL 5 */
+       {6, 10},        /* CHANNEL 6 */
+       {6, 10},        /* CHANNEL 7 */
+       {3, 14},        /* CHANNEL 8 */
+       {1, 3},         /* CHANNEL 9 */
+       {1, 1},         /* CHANNEL 10 No Prescaler */
+       {15, 100},      /* CHANNEL 11 */
+       {1, 4},         /* CHANNEL 12 */
+       {1, 1},         /* CHANNEL 13 Reserved channels */
+       {1, 1},         /* CHANNEL 14 Reseved channels */
+       {5, 11},        /* CHANNEL 15 */
+};
+
+
+/* Conversion table from -3 to 55 degrees Celcius */
+static int twl4030_therm_tbl[] = {
+       30800,  29500,  28300,  27100,
+       26000,  24900,  23900,  22900,  22000,  21100,  20300,  19400,  18700,
+       17900,  17200,  16500,  15900,  15300,  14700,  14100,  13600,  13100,
+       12600,  12100,  11600,  11200,  10800,  10400,  10000,  9630,   9280,
+       8950,   8620,   8310,   8020,   7730,   7460,   7200,   6950,   6710,
+       6470,   6250,   6040,   5830,   5640,   5450,   5260,   5090,   4920,
+       4760,   4600,   4450,   4310,   4170,   4040,   3910,   3790,   3670,
+       3550
+};
+
+/*
+ * Structure containing the registers
+ * of different conversion methods supported by MADC.
+ * Hardware or RT real time conversion request initiated by external host
+ * processor for RT Signal conversions.
+ * External host processors can also request for non RT conversions
+ * SW1 and SW2 software conversions also called asynchronous or GPC request.
+ */
+static
+const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
+       [TWL4030_MADC_RT] = {
+                            .sel = TWL4030_MADC_RTSELECT_LSB,
+                            .avg = TWL4030_MADC_RTAVERAGE_LSB,
+                            .rbase = TWL4030_MADC_RTCH0_LSB,
+                            },
+       [TWL4030_MADC_SW1] = {
+                             .sel = TWL4030_MADC_SW1SELECT_LSB,
+                             .avg = TWL4030_MADC_SW1AVERAGE_LSB,
+                             .rbase = TWL4030_MADC_GPCH0_LSB,
+                             .ctrl = TWL4030_MADC_CTRL_SW1,
+                             },
+       [TWL4030_MADC_SW2] = {
+                             .sel = TWL4030_MADC_SW2SELECT_LSB,
+                             .avg = TWL4030_MADC_SW2AVERAGE_LSB,
+                             .rbase = TWL4030_MADC_GPCH0_LSB,
+                             .ctrl = TWL4030_MADC_CTRL_SW2,
+                             },
+};
+
+/**
+ * twl4030_madc_channel_raw_read() - Function to read a particular channel value
+ * @madc:      pointer to struct twl4030_madc_data
+ * @reg:       lsb of ADC Channel
+ *
+ * Return: 0 on success, an error code otherwise.
+ */
+static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
+{
+       u16 val;
+       int ret;
+       /*
+        * For each ADC channel, we have MSB and LSB register pair. MSB address
+        * is always LSB address+1. reg parameter is the address of LSB register
+        */
+       ret = twl_i2c_read_u16(TWL4030_MODULE_MADC, &val, reg);
+       if (ret) {
+               dev_err(madc->dev, "unable to read register 0x%X\n", reg);
+               return ret;
+       }
+
+       return (int)(val >> 6);
+}
+
+/*
+ * Return battery temperature in degrees Celsius
+ * Or < 0 on failure.
+ */
+static int twl4030battery_temperature(int raw_volt)
+{
+       u8 val;
+       int temp, curr, volt, res, ret;
+
+       volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
+       /* Getting and calculating the supply current in micro amperes */
+       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
+               REG_BCICTL2);
+       if (ret < 0)
+               return ret;
+
+       curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
+       /* Getting and calculating the thermistor resistance in ohms */
+       res = volt * 1000 / curr;
+       /* calculating temperature */
+       for (temp = 58; temp >= 0; temp--) {
+               int actual = twl4030_therm_tbl[temp];
+               if ((actual - res) >= 0)
+                       break;
+       }
+
+       return temp + 1;
+}
+
+static int twl4030battery_current(int raw_volt)
+{
+       int ret;
+       u8 val;
+
+       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
+               TWL4030_BCI_BCICTL1);
+       if (ret)
+               return ret;
+       if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
+               return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
+       else /* slope of 0.88 mV/mA */
+               return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
+}
+
+/*
+ * Function to read channel values
+ * @madc - pointer to twl4030_madc_data struct
+ * @reg_base - Base address of the first channel
+ * @Channels - 16 bit bitmap. If the bit is set, channel's value is read
+ * @buf - The channel values are stored here. if read fails error
+ * @raw - Return raw values without conversion
+ * value is stored
+ * Returns the number of successfully read channels.
+ */
+static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
+                                     u8 reg_base, unsigned
+                                     long channels, int *buf,
+                                     bool raw)
+{
+       int count = 0;
+       int i;
+       u8 reg;
+
+       for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
+               reg = reg_base + (2 * i);
+               buf[i] = twl4030_madc_channel_raw_read(madc, reg);
+               if (buf[i] < 0) {
+                       dev_err(madc->dev, "Unable to read register 0x%X\n",
+                               reg);
+                       return buf[i];
+               }
+               if (raw) {
+                       count++;
+                       continue;
+               }
+               switch (i) {
+               case 10:
+                       buf[i] = twl4030battery_current(buf[i]);
+                       if (buf[i] < 0) {
+                               dev_err(madc->dev, "err reading current\n");
+                               return buf[i];
+                       } else {
+                               count++;
+                               buf[i] = buf[i] - 750;
+                       }
+                       break;
+               case 1:
+                       buf[i] = twl4030battery_temperature(buf[i]);
+                       if (buf[i] < 0) {
+                               dev_err(madc->dev, "err reading temperature\n");
+                               return buf[i];
+                       } else {
+                               buf[i] -= 3;
+                               count++;
+                       }
+                       break;
+               default:
+                       count++;
+                       /* Analog Input (V) = conv_result * step_size / R
+                        * conv_result = decimal value of 10-bit conversion
+                        *               result
+                        * step size = 1.5 / (2 ^ 10 -1)
+                        * R = Prescaler ratio for input channels.
+                        * Result given in mV hence multiplied by 1000.
+                        */
+                       buf[i] = (buf[i] * 3 * 1000 *
+                                twl4030_divider_ratios[i].denominator)
+                               / (2 * 1023 *
+                               twl4030_divider_ratios[i].numerator);
+               }
+       }
+
+       return count;
+}
+
+/*
+ * Enables irq.
+ * @madc - pointer to twl4030_madc_data struct
+ * @id - irq number to be enabled
+ * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
+ * corresponding to RT, SW1, SW2 conversion requests.
+ * If the i2c read fails it returns an error else returns 0.
+ */
+static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
+{
+       u8 val;
+       int ret;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev, "unable to read imr register 0x%X\n",
+                       madc->imr);
+               return ret;
+       }
+
+       val &= ~(1 << id);
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev,
+                       "unable to write imr register 0x%X\n", madc->imr);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Disables irq.
+ * @madc - pointer to twl4030_madc_data struct
+ * @id - irq number to be disabled
+ * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
+ * corresponding to RT, SW1, SW2 conversion requests.
+ * Returns error if i2c read/write fails.
+ */
+static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
+{
+       u8 val;
+       int ret;
+
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev, "unable to read imr register 0x%X\n",
+                       madc->imr);
+               return ret;
+       }
+       val |= (1 << id);
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev,
+                       "unable to write imr register 0x%X\n", madc->imr);
+               return ret;
+       }
+
+       return 0;
+}
+
+static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
+{
+       struct twl4030_madc_data *madc = _madc;
+       const struct twl4030_madc_conversion_method *method;
+       u8 isr_val, imr_val;
+       int i, len, ret;
+       struct twl4030_madc_request *r;
+
+       mutex_lock(&madc->lock);
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
+       if (ret) {
+               dev_err(madc->dev, "unable to read isr register 0x%X\n",
+                       madc->isr);
+               goto err_i2c;
+       }
+       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
+       if (ret) {
+               dev_err(madc->dev, "unable to read imr register 0x%X\n",
+                       madc->imr);
+               goto err_i2c;
+       }
+       isr_val &= ~imr_val;
+       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+               if (!(isr_val & (1 << i)))
+                       continue;
+               ret = twl4030_madc_disable_irq(madc, i);
+               if (ret < 0)
+                       dev_dbg(madc->dev, "Disable interrupt failed %d\n", i);
+               madc->requests[i].result_pending = 1;
+       }
+       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+               r = &madc->requests[i];
+               /* No pending results for this method, move to next one */
+               if (!r->result_pending)
+                       continue;
+               method = &twl4030_conversion_methods[r->method];
+               /* Read results */
+               len = twl4030_madc_read_channels(madc, method->rbase,
+                                                r->channels, r->rbuf, r->raw);
+               /* Return results to caller */
+               if (r->func_cb != NULL) {
+                       r->func_cb(len, r->channels, r->rbuf);
+                       r->func_cb = NULL;
+               }
+               /* Free request */
+               r->result_pending = 0;
+               r->active = 0;
+       }
+       mutex_unlock(&madc->lock);
+
+       return IRQ_HANDLED;
+
+err_i2c:
+       /*
+        * In case of error check whichever request is active
+        * and service the same.
+        */
+       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
+               r = &madc->requests[i];
+               if (r->active == 0)
+                       continue;
+               method = &twl4030_conversion_methods[r->method];
+               /* Read results */
+               len = twl4030_madc_read_channels(madc, method->rbase,
+                                                r->channels, r->rbuf, r->raw);
+               /* Return results to caller */
+               if (r->func_cb != NULL) {
+                       r->func_cb(len, r->channels, r->rbuf);
+                       r->func_cb = NULL;
+               }
+               /* Free request */
+               r->result_pending = 0;
+               r->active = 0;
+       }
+       mutex_unlock(&madc->lock);
+
+       return IRQ_HANDLED;
+}
+
+static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
+                               struct twl4030_madc_request *req)
+{
+       struct twl4030_madc_request *p;
+       int ret;
+
+       p = &madc->requests[req->method];
+       memcpy(p, req, sizeof(*req));
+       ret = twl4030_madc_enable_irq(madc, req->method);
+       if (ret < 0) {
+               dev_err(madc->dev, "enable irq failed!!\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Function which enables the madc conversion
+ * by writing to the control register.
+ * @madc - pointer to twl4030_madc_data struct
+ * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
+ * corresponding to RT SW1 or SW2 conversion methods.
+ * Returns 0 if succeeds else a negative error value
+ */
+static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
+                                        int conv_method)
+{
+       const struct twl4030_madc_conversion_method *method;
+       int ret = 0;
+
+       if (conv_method != TWL4030_MADC_SW1 && conv_method != TWL4030_MADC_SW2)
+               return -ENOTSUPP;
+
+       method = &twl4030_conversion_methods[conv_method];
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, TWL4030_MADC_SW_START,
+                              method->ctrl);
+       if (ret) {
+               dev_err(madc->dev, "unable to write ctrl register 0x%X\n",
+                       method->ctrl);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Function that waits for conversion to be ready
+ * @madc - pointer to twl4030_madc_data struct
+ * @timeout_ms - timeout value in milliseconds
+ * @status_reg - ctrl register
+ * returns 0 if succeeds else a negative error value
+ */
+static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
+                                             unsigned int timeout_ms,
+                                             u8 status_reg)
+{
+       unsigned long timeout;
+       int ret;
+
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       do {
+               u8 reg;
+
+               ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &reg, status_reg);
+               if (ret) {
+                       dev_err(madc->dev,
+                               "unable to read status register 0x%X\n",
+                               status_reg);
+                       return ret;
+               }
+               if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
+                       return 0;
+               usleep_range(500, 2000);
+       } while (!time_after(jiffies, timeout));
+       dev_err(madc->dev, "conversion timeout!\n");
+
+       return -EAGAIN;
+}
+
+/*
+ * An exported function which can be called from other kernel drivers.
+ * @req twl4030_madc_request structure
+ * req->rbuf will be filled with read values of channels based on the
+ * channel index. If a particular channel reading fails there will
+ * be a negative error value in the corresponding array element.
+ * returns 0 if succeeds else error value
+ */
+int twl4030_madc_conversion(struct twl4030_madc_request *req)
+{
+       const struct twl4030_madc_conversion_method *method;
+       int ret;
+
+       if (!req || !twl4030_madc)
+               return -EINVAL;
+
+       mutex_lock(&twl4030_madc->lock);
+       if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
+               ret = -EINVAL;
+               goto out;
+       }
+       /* Do we have a conversion request ongoing */
+       if (twl4030_madc->requests[req->method].active) {
+               ret = -EBUSY;
+               goto out;
+       }
+       method = &twl4030_conversion_methods[req->method];
+       /* Select channels to be converted */
+       ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels, method->sel);
+       if (ret) {
+               dev_err(twl4030_madc->dev,
+                       "unable to write sel register 0x%X\n", method->sel);
+               goto out;
+       }
+       /* Select averaging for all channels if do_avg is set */
+       if (req->do_avg) {
+               ret = twl_i2c_write_u16(TWL4030_MODULE_MADC, req->channels,
+                                      method->avg);
+               if (ret) {
+                       dev_err(twl4030_madc->dev,
+                               "unable to write avg register 0x%X\n",
+                               method->avg);
+                       goto out;
+               }
+       }
+       if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
+               ret = twl4030_madc_set_irq(twl4030_madc, req);
+               if (ret < 0)
+                       goto out;
+               ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
+               if (ret < 0)
+                       goto out;
+               twl4030_madc->requests[req->method].active = 1;
+               ret = 0;
+               goto out;
+       }
+       /* With RT method we should not be here anymore */
+       if (req->method == TWL4030_MADC_RT) {
+               ret = -EINVAL;
+               goto out;
+       }
+       ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
+       if (ret < 0)
+               goto out;
+       twl4030_madc->requests[req->method].active = 1;
+       /* Wait until conversion is ready (ctrl register returns EOC) */
+       ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
+       if (ret) {
+               twl4030_madc->requests[req->method].active = 0;
+               goto out;
+       }
+       ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
+                                        req->channels, req->rbuf, req->raw);
+       twl4030_madc->requests[req->method].active = 0;
+
+out:
+       mutex_unlock(&twl4030_madc->lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
+
+int twl4030_get_madc_conversion(int channel_no)
+{
+       struct twl4030_madc_request req;
+       int temp = 0;
+       int ret;
+
+       req.channels = (1 << channel_no);
+       req.method = TWL4030_MADC_SW2;
+       req.active = 0;
+       req.func_cb = NULL;
+       ret = twl4030_madc_conversion(&req);
+       if (ret < 0)
+               return ret;
+       if (req.rbuf[channel_no] > 0)
+               temp = req.rbuf[channel_no];
+
+       return temp;
+}
+EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
+
+/**
+ * twl4030_madc_set_current_generator() - setup bias current
+ *
+ * @madc:      pointer to twl4030_madc_data struct
+ * @chan:      can be one of the two values:
+ *             TWL4030_BCI_ITHEN
+ *             Enables bias current for main battery type reading
+ *             TWL4030_BCI_TYPEN
+ *             Enables bias current for main battery temperature sensing
+ * @on:                enable or disable chan.
+ *
+ * Function to enable or disable bias current for
+ * main battery type reading or temperature sensing
+ */
+static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
+                                             int chan, int on)
+{
+       int ret;
+       int regmask;
+       u8 regval;
+
+       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
+                             &regval, TWL4030_BCI_BCICTL1);
+       if (ret) {
+               dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
+                       TWL4030_BCI_BCICTL1);
+               return ret;
+       }
+
+       regmask = chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
+       if (on)
+               regval |= regmask;
+       else
+               regval &= ~regmask;
+
+       ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
+                              regval, TWL4030_BCI_BCICTL1);
+       if (ret) {
+               dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
+                       TWL4030_BCI_BCICTL1);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Function that sets MADC software power on bit to enable MADC
+ * @madc - pointer to twl4030_madc_data struct
+ * @on - Enable or disable MADC software power on bit.
+ * returns error if i2c read/write fails else 0
+ */
+static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
+{
+       u8 regval;
+       int ret;
+
+       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
+                             &regval, TWL4030_MADC_CTRL1);
+       if (ret) {
+               dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
+                       TWL4030_MADC_CTRL1);
+               return ret;
+       }
+       if (on)
+               regval |= TWL4030_MADC_MADCON;
+       else
+               regval &= ~TWL4030_MADC_MADCON;
+       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
+       if (ret) {
+               dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
+                       TWL4030_MADC_CTRL1);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * Initialize MADC and request for threaded irq
+ */
+static int twl4030_madc_probe(struct platform_device *pdev)
+{
+       struct twl4030_madc_data *madc;
+       struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
+       struct device_node *np = pdev->dev.of_node;
+       int irq, ret;
+       u8 regval;
+       struct iio_dev *iio_dev = NULL;
+
+       if (!pdata && !np) {
+               dev_err(&pdev->dev, "neither platform data nor Device Tree node available\n");
+               return -EINVAL;
+       }
+
+       iio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*madc));
+       if (!iio_dev) {
+               dev_err(&pdev->dev, "failed allocating iio device\n");
+               return -ENOMEM;
+       }
+
+       madc = iio_priv(iio_dev);
+       madc->dev = &pdev->dev;
+
+       iio_dev->name = dev_name(&pdev->dev);
+       iio_dev->dev.parent = &pdev->dev;
+       iio_dev->dev.of_node = pdev->dev.of_node;
+       iio_dev->info = &twl4030_madc_iio_info;
+       iio_dev->modes = INDIO_DIRECT_MODE;
+       iio_dev->channels = twl4030_madc_iio_channels;
+       iio_dev->num_channels = ARRAY_SIZE(twl4030_madc_iio_channels);
+
+       /*
+        * Phoenix provides 2 interrupt lines. The first one is connected to
+        * the OMAP. The other one can be connected to the other processor such
+        * as modem. Hence two separate ISR and IMR registers.
+        */
+       if (pdata)
+               madc->use_second_irq = (pdata->irq_line != 1);
+       else
+               madc->use_second_irq = of_property_read_bool(np,
+                                      "ti,system-uses-second-madc-irq");
+
+       madc->imr = madc->use_second_irq ? TWL4030_MADC_IMR2 :
+                                          TWL4030_MADC_IMR1;
+       madc->isr = madc->use_second_irq ? TWL4030_MADC_ISR2 :
+                                          TWL4030_MADC_ISR1;
+
+       ret = twl4030_madc_set_power(madc, 1);
+       if (ret < 0)
+               return ret;
+       ret = twl4030_madc_set_current_generator(madc, 0, 1);
+       if (ret < 0)
+               goto err_current_generator;
+
+       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
+                             &regval, TWL4030_BCI_BCICTL1);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
+                       TWL4030_BCI_BCICTL1);
+               goto err_i2c;
+       }
+       regval |= TWL4030_BCI_MESBAT;
+       ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
+                              regval, TWL4030_BCI_BCICTL1);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
+                       TWL4030_BCI_BCICTL1);
+               goto err_i2c;
+       }
+
+       /* Check that MADC clock is on */
+       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &regval, TWL4030_REG_GPBR1);
+       if (ret) {
+               dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
+                               TWL4030_REG_GPBR1);
+               goto err_i2c;
+       }
+
+       /* If MADC clk is not on, turn it on */
+       if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
+               dev_info(&pdev->dev, "clk disabled, enabling\n");
+               regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
+               ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
+                                      TWL4030_REG_GPBR1);
+               if (ret) {
+                       dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
+                                       TWL4030_REG_GPBR1);
+                       goto err_i2c;
+               }
+       }
+
+       platform_set_drvdata(pdev, iio_dev);
+       mutex_init(&madc->lock);
+
+       irq = platform_get_irq(pdev, 0);
+       ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+                                  twl4030_madc_threaded_irq_handler,
+                                  IRQF_TRIGGER_RISING, "twl4030_madc", madc);
+       if (ret) {
+               dev_err(&pdev->dev, "could not request irq\n");
+               goto err_i2c;
+       }
+       twl4030_madc = madc;
+
+       ret = iio_device_register(iio_dev);
+       if (ret) {
+               dev_err(&pdev->dev, "could not register iio device\n");
+               goto err_i2c;
+       }
+
+       return 0;
+
+err_i2c:
+       twl4030_madc_set_current_generator(madc, 0, 0);
+err_current_generator:
+       twl4030_madc_set_power(madc, 0);
+       return ret;
+}
+
+static int twl4030_madc_remove(struct platform_device *pdev)
+{
+       struct iio_dev *iio_dev = platform_get_drvdata(pdev);
+       struct twl4030_madc_data *madc = iio_priv(iio_dev);
+
+       iio_device_unregister(iio_dev);
+
+       twl4030_madc_set_current_generator(madc, 0, 0);
+       twl4030_madc_set_power(madc, 0);
+
+       return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id twl_madc_of_match[] = {
+       { .compatible = "ti,twl4030-madc", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, twl_madc_of_match);
+#endif
+
+static struct platform_driver twl4030_madc_driver = {
+       .probe = twl4030_madc_probe,
+       .remove = twl4030_madc_remove,
+       .driver = {
+                  .name = "twl4030_madc",
+                  .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(twl_madc_of_match),
+       },
+};
+
+module_platform_driver(twl4030_madc_driver);
+
+MODULE_DESCRIPTION("TWL4030 ADC driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("J Keerthy");
+MODULE_ALIAS("platform:twl4030_madc");
index 02125e6..5a4da94 100644 (file)
@@ -518,9 +518,9 @@ static isdnloop_stat isdnloop_cmd_table[] =
 static void
 isdnloop_fake_err(isdnloop_card *card)
 {
-       char buf[60];
+       char buf[64];
 
-       sprintf(buf, "E%s", card->omsg);
+       snprintf(buf, sizeof(buf), "E%s", card->omsg);
        isdnloop_fake(card, buf, -1);
        isdnloop_fake(card, "NAK", -1);
 }
@@ -903,6 +903,8 @@ isdnloop_parse_cmd(isdnloop_card *card)
        case 7:
                /* 0x;EAZ */
                p += 3;
+               if (strlen(p) >= sizeof(card->eazlist[0]))
+                       break;
                strcpy(card->eazlist[ch - 1], p);
                break;
        case 8:
@@ -1070,6 +1072,12 @@ isdnloop_start(isdnloop_card *card, isdnloop_sdef *sdefp)
                return -EBUSY;
        if (copy_from_user((char *) &sdef, (char *) sdefp, sizeof(sdef)))
                return -EFAULT;
+
+       for (i = 0; i < 3; i++) {
+               if (!memchr(sdef.num[i], 0, sizeof(sdef.num[i])))
+                       return -EINVAL;
+       }
+
        spin_lock_irqsave(&card->isdnloop_lock, flags);
        switch (sdef.ptype) {
        case ISDN_PTYPE_EURO:
@@ -1127,7 +1135,7 @@ isdnloop_command(isdn_ctrl *c, isdnloop_card *card)
 {
        ulong a;
        int i;
-       char cbuf[60];
+       char cbuf[80];
        isdn_ctrl cmd;
        isdnloop_cdef cdef;
 
@@ -1192,7 +1200,6 @@ isdnloop_command(isdn_ctrl *c, isdnloop_card *card)
                        break;
                if ((c->arg & 255) < ISDNLOOP_BCH) {
                        char *p;
-                       char dial[50];
                        char dcode[4];
 
                        a = c->arg;
@@ -1204,10 +1211,10 @@ isdnloop_command(isdn_ctrl *c, isdnloop_card *card)
                        } else
                                /* Normal Dial */
                                strcpy(dcode, "CAL");
-                       strcpy(dial, p);
-                       sprintf(cbuf, "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
-                               dcode, dial, c->parm.setup.si1,
-                               c->parm.setup.si2, c->parm.setup.eazmsn);
+                       snprintf(cbuf, sizeof(cbuf),
+                                "%02d;D%s_R%s,%02d,%02d,%s\n", (int) (a + 1),
+                                dcode, p, c->parm.setup.si1,
+                                c->parm.setup.si2, c->parm.setup.eazmsn);
                        i = isdnloop_writecmd(cbuf, strlen(cbuf), 0, card);
                }
                break;
index 44c358e..6de9dfb 100644 (file)
@@ -416,7 +416,7 @@ config LEDS_MC13783
        depends on MFD_MC13XXX
        help
          This option enable support for on-chip LED drivers found
-         on Freescale Semiconductor MC13783/MC13892 PMIC.
+         on Freescale Semiconductor MC13783/MC13892/MC34708 PMIC.
 
 config LEDS_NS2
        tristate "LED support for Network Space v2 GPIO LEDs"
@@ -474,7 +474,7 @@ config LEDS_LM355x
 
 config LEDS_OT200
        tristate "LED support for the Bachmann OT200"
-       depends on LEDS_CLASS && HAS_IOMEM
+       depends on LEDS_CLASS && HAS_IOMEM && (X86_32 || COMPILE_TEST)
        help
          This option enables support for the LEDs on the Bachmann OT200.
          Say Y to enable LEDs on the Bachmann OT200.
index ce8921a..71b40d3 100644 (file)
@@ -39,9 +39,11 @@ static void led_set_software_blink(struct led_classdev *led_cdev,
        led_cdev->blink_delay_on = delay_on;
        led_cdev->blink_delay_off = delay_off;
 
-       /* never on - don't blink */
-       if (!delay_on)
+       /* never on - just set to off */
+       if (!delay_on) {
+               __led_set_brightness(led_cdev, LED_OFF);
                return;
+       }
 
        /* never off - just set to brightness */
        if (!delay_off) {
index e387f41..c3734f1 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
@@ -220,9 +219,12 @@ void led_trigger_unregister(struct led_trigger *trig)
 {
        struct led_classdev *led_cdev;
 
+       if (list_empty_careful(&trig->next_trig))
+               return;
+
        /* Remove from the list of led triggers */
        down_write(&triggers_list_lock);
-       list_del(&trig->next_trig);
+       list_del_init(&trig->next_trig);
        up_write(&triggers_list_lock);
 
        /* Remove anyone actively using this trigger */
index 5f588c0..d1e1bca 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
index 7e311a1..86b5bdb 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/workqueue.h>
index 6de216a..70c74a7 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/slab.h>
index 66d0a57..d0452b0 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/jiffies.h>
 #include <linux/i2c.h>
@@ -444,7 +443,7 @@ static void led_work(struct work_struct *work)
 {
        int ret;
        struct blinkm_led *led;
-       struct blinkm_data *data ;
+       struct blinkm_data *data;
        struct blinkm_work *blm_work = work_to_blmwork(work);
 
        led = blm_work->blinkm_led;
index d93e245..f58a354 100644 (file)
@@ -19,7 +19,7 @@ MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
 MODULE_DESCRIPTION("Clevo mail LED driver");
 MODULE_LICENSE("GPL");
 
-static bool __initdata nodetect;
+static bool nodetect;
 module_param_named(nodetect, nodetect, bool, 0);
 MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection");
 
@@ -153,7 +153,7 @@ static struct led_classdev clevo_mail_led = {
        .flags                  = LED_CORE_SUSPENDRESUME,
 };
 
-static int clevo_mail_led_probe(struct platform_device *pdev)
+static int __init clevo_mail_led_probe(struct platform_device *pdev)
 {
        return led_classdev_register(&pdev->dev, &clevo_mail_led);
 }
@@ -165,7 +165,6 @@ static int clevo_mail_led_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver clevo_mail_led_driver = {
-       .probe          = clevo_mail_led_probe,
        .remove         = clevo_mail_led_remove,
        .driver         = {
                .name           = KBUILD_MODNAME,
index 8abcb66..910339d 100644 (file)
@@ -3,7 +3,6 @@
  *
  * Control the Cobalt Qube/RaQ front LED
  */
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/ioport.h>
 #include <linux/leds.h>
index 2a4b87f..35dffb1 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/workqueue.h>
index 865d4fa..01486ad 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/workqueue.h>
index b4d5a44..2b4dc73 100644 (file)
@@ -16,7 +16,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/module.h>
index 78b0e27..57ff20f 100644 (file)
@@ -11,7 +11,6 @@
  *
  */
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/leds.h>
@@ -204,6 +203,9 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
                                led.default_state = LEDS_GPIO_DEFSTATE_OFF;
                }
 
+               if (of_get_property(child, "retain-state-suspended", NULL))
+                       led.retain_state_suspended = 1;
+
                ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
                                      &pdev->dev, NULL);
                if (ret < 0) {
@@ -224,6 +226,8 @@ static const struct of_device_id of_gpio_leds_match[] = {
        { .compatible = "gpio-leds", },
        {},
 };
+
+MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
 #else /* CONFIG_OF_GPIO */
 static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
 {
index 366b605..d61a988 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <asm/hd64461.h>
index 027ede7..e2c642c 100644 (file)
@@ -12,7 +12,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/leds.h>
 #include <linux/mfd/core.h>
 #include <linux/mutex.h>
index 2ec34cf..8ca197a 100644 (file)
@@ -25,7 +25,6 @@
 #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>
index 4ade66a..cb5ed82 100644 (file)
@@ -25,7 +25,6 @@
 #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>
index bf006f4..ca85724 100644 (file)
@@ -13,7 +13,6 @@
 #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>
@@ -347,9 +346,9 @@ static void lp5562_write_program_memory(struct lp55xx_chip *chip,
 /* check the size of program count */
 static inline bool _is_pc_overflow(struct lp55xx_predef_pattern *ptn)
 {
-       return (ptn->size_r >= LP5562_PROGRAM_LENGTH ||
-               ptn->size_g >= LP5562_PROGRAM_LENGTH ||
-               ptn->size_b >= LP5562_PROGRAM_LENGTH);
+       return ptn->size_r >= LP5562_PROGRAM_LENGTH ||
+              ptn->size_g >= LP5562_PROGRAM_LENGTH ||
+              ptn->size_b >= LP5562_PROGRAM_LENGTH;
 }
 
 static int lp5562_run_predef_led_pattern(struct lp55xx_chip *chip, int mode)
index 3417e5b..059f5b1 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/workqueue.h>
index ca87a1b..f1db88e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * LEDs driver for Freescale MC13783/MC13892
+ * LEDs driver for Freescale MC13783/MC13892/MC34708
  *
  * Copyright (C) 2010 Philippe Rétornaz
  *
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
+#include <linux/of.h>
 #include <linux/workqueue.h>
 #include <linux/mfd/mc13xxx.h>
 
-#define MC13XXX_REG_LED_CONTROL(x)     (51 + (x))
-
 struct mc13xxx_led_devtype {
        int     led_min;
        int     led_max;
        int     num_regs;
+       u32     ledctrl_base;
 };
 
 struct mc13xxx_led {
        struct led_classdev     cdev;
        struct work_struct      work;
-       struct mc13xxx          *master;
        enum led_brightness     new_brightness;
        int                     id;
+       struct mc13xxx_leds     *leds;
 };
 
 struct mc13xxx_leds {
+       struct mc13xxx                  *master;
        struct mc13xxx_led_devtype      *devtype;
        int                             num_leds;
-       struct mc13xxx_led              led[0];
+       struct mc13xxx_led              *led;
 };
 
+static unsigned int mc13xxx_max_brightness(int id)
+{
+       if (id >= MC13783_LED_MD && id <= MC13783_LED_KP)
+               return 0x0f;
+       else if (id >= MC13783_LED_R1 && id <= MC13783_LED_B3)
+               return 0x1f;
+
+       return 0x3f;
+}
+
 static void mc13xxx_led_work(struct work_struct *work)
 {
        struct mc13xxx_led *led = container_of(work, struct mc13xxx_led, work);
-       int reg, mask, value, bank, off, shift;
+       struct mc13xxx_leds *leds = led->leds;
+       unsigned int reg, bank, off, shift;
 
        switch (led->id) {
        case MC13783_LED_MD:
-               reg = MC13XXX_REG_LED_CONTROL(2);
-               shift = 9;
-               mask = 0x0f;
-               value = led->new_brightness >> 4;
-               break;
        case MC13783_LED_AD:
-               reg = MC13XXX_REG_LED_CONTROL(2);
-               shift = 13;
-               mask = 0x0f;
-               value = led->new_brightness >> 4;
-               break;
        case MC13783_LED_KP:
-               reg = MC13XXX_REG_LED_CONTROL(2);
-               shift = 17;
-               mask = 0x0f;
-               value = led->new_brightness >> 4;
+               reg = 2;
+               shift = 9 + (led->id - MC13783_LED_MD) * 4;
                break;
        case MC13783_LED_R1:
        case MC13783_LED_G1:
@@ -80,44 +79,35 @@ static void mc13xxx_led_work(struct work_struct *work)
        case MC13783_LED_B3:
                off = led->id - MC13783_LED_R1;
                bank = off / 3;
-               reg = MC13XXX_REG_LED_CONTROL(3) + bank;
+               reg = 3 + bank;
                shift = (off - bank * 3) * 5 + 6;
-               value = led->new_brightness >> 3;
-               mask = 0x1f;
                break;
        case MC13892_LED_MD:
-               reg = MC13XXX_REG_LED_CONTROL(0);
-               shift = 3;
-               mask = 0x3f;
-               value = led->new_brightness >> 2;
-               break;
        case MC13892_LED_AD:
-               reg = MC13XXX_REG_LED_CONTROL(0);
-               shift = 15;
-               mask = 0x3f;
-               value = led->new_brightness >> 2;
-               break;
        case MC13892_LED_KP:
-               reg = MC13XXX_REG_LED_CONTROL(1);
-               shift = 3;
-               mask = 0x3f;
-               value = led->new_brightness >> 2;
+               reg = (led->id - MC13892_LED_MD) / 2;
+               shift = 3 + (led->id - MC13892_LED_MD) * 12;
                break;
        case MC13892_LED_R:
        case MC13892_LED_G:
        case MC13892_LED_B:
                off = led->id - MC13892_LED_R;
                bank = off / 2;
-               reg = MC13XXX_REG_LED_CONTROL(2) + bank;
+               reg = 2 + bank;
                shift = (off - bank * 2) * 12 + 3;
-               value = led->new_brightness >> 2;
-               mask = 0x3f;
+               break;
+       case MC34708_LED_R:
+       case MC34708_LED_G:
+               reg = 0;
+               shift = 3 + (led->id - MC34708_LED_R) * 12;
                break;
        default:
                BUG();
        }
 
-       mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift);
+       mc13xxx_reg_rmw(leds->master, leds->devtype->ledctrl_base + reg,
+                       mc13xxx_max_brightness(led->id) << shift,
+                       led->new_brightness << shift);
 }
 
 static void mc13xxx_led_set(struct led_classdev *led_cdev,
@@ -130,47 +120,121 @@ static void mc13xxx_led_set(struct led_classdev *led_cdev,
        schedule_work(&led->work);
 }
 
-static int __init mc13xxx_led_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF
+static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
+       struct platform_device *pdev)
 {
-       struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent);
-       struct mc13xxx_led_devtype *devtype =
-               (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data;
-       struct mc13xxx_leds *leds;
-       int i, id, num_leds, ret = -ENODATA;
-       u32 reg, init_led = 0;
+       struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
+       struct mc13xxx_leds_platform_data *pdata;
+       struct device_node *parent, *child;
+       struct device *dev = &pdev->dev;
+       int i = 0, ret = -ENODATA;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       of_node_get(dev->parent->of_node);
+
+       parent = of_find_node_by_name(dev->parent->of_node, "leds");
+       if (!parent)
+               goto out_node_put;
 
-       if (!pdata) {
-               dev_err(&pdev->dev, "Missing platform data\n");
-               return -ENODEV;
+       ret = of_property_read_u32_array(parent, "led-control",
+                                        pdata->led_control,
+                                        leds->devtype->num_regs);
+       if (ret)
+               goto out_node_put;
+
+       pdata->num_leds = of_get_child_count(parent);
+
+       pdata->led = devm_kzalloc(dev, pdata->num_leds * sizeof(*pdata->led),
+                                 GFP_KERNEL);
+       if (!pdata->led) {
+               ret = -ENOMEM;
+               goto out_node_put;
        }
 
-       num_leds = pdata->num_leds;
+       for_each_child_of_node(parent, child) {
+               const char *str;
+               u32 tmp;
 
-       if ((num_leds < 1) ||
-           (num_leds > (devtype->led_max - devtype->led_min + 1))) {
-               dev_err(&pdev->dev, "Invalid LED count %d\n", num_leds);
-               return -EINVAL;
+               if (of_property_read_u32(child, "reg", &tmp))
+                       continue;
+               pdata->led[i].id = leds->devtype->led_min + tmp;
+
+               if (!of_property_read_string(child, "label", &str))
+                       pdata->led[i].name = str;
+               if (!of_property_read_string(child, "linux,default-trigger",
+                                            &str))
+                       pdata->led[i].default_trigger = str;
+
+               i++;
        }
 
-       leds = devm_kzalloc(&pdev->dev, num_leds * sizeof(struct mc13xxx_led) +
-                           sizeof(struct mc13xxx_leds), GFP_KERNEL);
+       pdata->num_leds = i;
+       ret = i > 0 ? 0 : -ENODATA;
+
+out_node_put:
+       of_node_put(parent);
+
+       return ret ? ERR_PTR(ret) : pdata;
+}
+#else
+static inline struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
+       struct platform_device *pdev)
+{
+       return ERR_PTR(-ENOSYS);
+}
+#endif
+
+static int __init mc13xxx_led_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(dev);
+       struct mc13xxx *mcdev = dev_get_drvdata(dev->parent);
+       struct mc13xxx_led_devtype *devtype =
+               (struct mc13xxx_led_devtype *)pdev->id_entry->driver_data;
+       struct mc13xxx_leds *leds;
+       int i, id, ret = -ENODATA;
+       u32 init_led = 0;
+
+       leds = devm_kzalloc(dev, sizeof(*leds), GFP_KERNEL);
        if (!leds)
                return -ENOMEM;
 
        leds->devtype = devtype;
-       leds->num_leds = num_leds;
+       leds->master = mcdev;
        platform_set_drvdata(pdev, leds);
 
+       if (dev->parent->of_node) {
+               pdata = mc13xxx_led_probe_dt(pdev);
+               if (IS_ERR(pdata))
+                       return PTR_ERR(pdata);
+       } else if (!pdata)
+               return -ENODATA;
+
+       leds->num_leds = pdata->num_leds;
+
+       if ((leds->num_leds < 1) ||
+           (leds->num_leds > (devtype->led_max - devtype->led_min + 1))) {
+               dev_err(dev, "Invalid LED count %d\n", leds->num_leds);
+               return -EINVAL;
+       }
+
+       leds->led = devm_kzalloc(dev, leds->num_leds * sizeof(*leds->led),
+                                GFP_KERNEL);
+       if (!leds->led)
+               return -ENOMEM;
+
        for (i = 0; i < devtype->num_regs; i++) {
-               reg = pdata->led_control[i];
-               WARN_ON(reg >= (1 << 24));
-               ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg);
+               ret = mc13xxx_reg_write(mcdev, leds->devtype->ledctrl_base + i,
+                                       pdata->led_control[i]);
                if (ret)
                        return ret;
        }
 
-       for (i = 0; i < num_leds; i++) {
+       for (i = 0; i < leds->num_leds; i++) {
                const char *name, *trig;
 
                ret = -EINVAL;
@@ -180,30 +244,29 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
                trig = pdata->led[i].default_trigger;
 
                if ((id > devtype->led_max) || (id < devtype->led_min)) {
-                       dev_err(&pdev->dev, "Invalid ID %i\n", id);
+                       dev_err(dev, "Invalid ID %i\n", id);
                        break;
                }
 
                if (init_led & (1 << id)) {
-                       dev_warn(&pdev->dev,
-                                "LED %i already initialized\n", id);
+                       dev_warn(dev, "LED %i already initialized\n", id);
                        break;
                }
 
                init_led |= 1 << id;
                leds->led[i].id = id;
-               leds->led[i].master = mcdev;
+               leds->led[i].leds = leds;
                leds->led[i].cdev.name = name;
                leds->led[i].cdev.default_trigger = trig;
+               leds->led[i].cdev.flags = LED_CORE_SUSPENDRESUME;
                leds->led[i].cdev.brightness_set = mc13xxx_led_set;
-               leds->led[i].cdev.brightness = LED_OFF;
+               leds->led[i].cdev.max_brightness = mc13xxx_max_brightness(id);
 
                INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
 
-               ret = led_classdev_register(pdev->dev.parent,
-                                           &leds->led[i].cdev);
+               ret = led_classdev_register(dev->parent, &leds->led[i].cdev);
                if (ret) {
-                       dev_err(&pdev->dev, "Failed to register LED %i\n", id);
+                       dev_err(dev, "Failed to register LED %i\n", id);
                        break;
                }
        }
@@ -219,7 +282,6 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
 
 static int mc13xxx_led_remove(struct platform_device *pdev)
 {
-       struct mc13xxx *mcdev = dev_get_drvdata(pdev->dev.parent);
        struct mc13xxx_leds *leds = platform_get_drvdata(pdev);
        int i;
 
@@ -228,9 +290,6 @@ static int mc13xxx_led_remove(struct platform_device *pdev)
                cancel_work_sync(&leds->led[i].work);
        }
 
-       for (i = 0; i < leds->devtype->num_regs; i++)
-               mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0);
-
        return 0;
 }
 
@@ -238,17 +297,27 @@ static const struct mc13xxx_led_devtype mc13783_led_devtype = {
        .led_min        = MC13783_LED_MD,
        .led_max        = MC13783_LED_B3,
        .num_regs       = 6,
+       .ledctrl_base   = 51,
 };
 
 static const struct mc13xxx_led_devtype mc13892_led_devtype = {
        .led_min        = MC13892_LED_MD,
        .led_max        = MC13892_LED_B,
        .num_regs       = 4,
+       .ledctrl_base   = 51,
+};
+
+static const struct mc13xxx_led_devtype mc34708_led_devtype = {
+       .led_min        = MC34708_LED_R,
+       .led_max        = MC34708_LED_G,
+       .num_regs       = 1,
+       .ledctrl_base   = 54,
 };
 
 static const struct platform_device_id mc13xxx_led_id_table[] = {
        { "mc13783-led", (kernel_ulong_t)&mc13783_led_devtype, },
        { "mc13892-led", (kernel_ulong_t)&mc13892_led_devtype, },
+       { "mc34708-led", (kernel_ulong_t)&mc34708_led_devtype, },
        { }
 };
 MODULE_DEVICE_TABLE(platform, mc13xxx_led_id_table);
index 2f9f141..e97f443 100644 (file)
@@ -21,7 +21,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
index c7a4230..efa6258 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
index 98cae52..c9d9060 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/leds.h>
index 6050474..7d0aaed 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/of_platform.h>
 #include <linux/fb.h>
@@ -84,6 +83,15 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds)
                      (sizeof(struct led_pwm_data) * num_leds);
 }
 
+static void led_pwm_cleanup(struct led_pwm_priv *priv)
+{
+       while (priv->num_leds--) {
+               led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
+               if (priv->leds[priv->num_leds].can_sleep)
+                       cancel_work_sync(&priv->leds[priv->num_leds].work);
+       }
+}
+
 static int led_pwm_create_of(struct platform_device *pdev,
                             struct led_pwm_priv *priv)
 {
@@ -131,8 +139,7 @@ static int led_pwm_create_of(struct platform_device *pdev,
 
        return 0;
 err:
-       while (priv->num_leds--)
-               led_classdev_unregister(&priv->leds[priv->num_leds].cdev);
+       led_pwm_cleanup(priv);
 
        return ret;
 }
@@ -200,8 +207,8 @@ static int led_pwm_probe(struct platform_device *pdev)
        return 0;
 
 err:
-       while (i--)
-               led_classdev_unregister(&priv->leds[i].cdev);
+       priv->num_leds = i;
+       led_pwm_cleanup(priv);
 
        return ret;
 }
@@ -209,13 +216,8 @@ err:
 static int led_pwm_remove(struct platform_device *pdev)
 {
        struct led_pwm_priv *priv = platform_get_drvdata(pdev);
-       int i;
 
-       for (i = 0; i < priv->num_leds; i++) {
-               led_classdev_unregister(&priv->leds[i].cdev);
-               if (priv->leds[i].can_sleep)
-                       cancel_work_sync(&priv->leds[i].work);
-       }
+       led_pwm_cleanup(priv);
 
        return 0;
 }
index 98174e7..28988b7 100644 (file)
@@ -12,7 +12,6 @@
 */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/gpio.h>
index 5b8f938..2eb3ef6 100644 (file)
@@ -63,7 +63,7 @@ MODULE_LICENSE("GPL");
 /*
  * PCI ID of the Intel ICH7 LPC Device within which the GPIO block lives.
  */
-static DEFINE_PCI_DEVICE_TABLE(ich7_lpc_pci_id) = {
+static const struct pci_device_id ich7_lpc_pci_id[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_0) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_1) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_30) },
@@ -78,7 +78,7 @@ static int __init ss4200_led_dmi_callback(const struct dmi_system_id *id)
        return 1;
 }
 
-static bool __initdata nodetect;
+static bool nodetect;
 module_param_named(nodetect, nodetect, bool, 0);
 MODULE_PARM_DESC(nodetect, "Skip DMI-based hardware detection");
 
index 0a1a13f..e72c974 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/leds.h>
index 3f75fd2..4133ffe 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/leds.h>
 #include <linux/err.h>
index 118335e..1c3ee9f 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/percpu.h>
 #include <linux/syscore_ops.h>
 #include <linux/rwsem.h>
+#include <linux/cpu.h>
 #include "../leds.h"
 
 #define MAX_NAME_LEN   8
@@ -92,6 +93,26 @@ static struct syscore_ops ledtrig_cpu_syscore_ops = {
        .resume         = ledtrig_cpu_syscore_resume,
 };
 
+static int ledtrig_cpu_notify(struct notifier_block *self,
+                                          unsigned long action, void *hcpu)
+{
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_STARTING:
+               ledtrig_cpu(CPU_LED_START);
+               break;
+       case CPU_DYING:
+               ledtrig_cpu(CPU_LED_STOP);
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+
+static struct notifier_block ledtrig_cpu_nb = {
+       .notifier_call = ledtrig_cpu_notify,
+};
+
 static int __init ledtrig_cpu_init(void)
 {
        int cpu;
@@ -113,6 +134,7 @@ static int __init ledtrig_cpu_init(void)
        }
 
        register_syscore_ops(&ledtrig_cpu_syscore_ops);
+       register_cpu_notifier(&ledtrig_cpu_nb);
 
        pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n");
 
@@ -124,6 +146,8 @@ static void __exit ledtrig_cpu_exit(void)
 {
        int cpu;
 
+       unregister_cpu_notifier(&ledtrig_cpu_nb);
+
        for_each_possible_cpu(cpu) {
                struct led_trigger_cpu *trig = &per_cpu(cpu_trig, cpu);
 
index bfb39bb..e8b55c3 100644 (file)
@@ -887,7 +887,7 @@ void guest_new_pagetable(struct lg_cpu *cpu, unsigned long pgtable)
  * _PAGE_ACCESSED then we can put a read-only PTE entry in immediately, and if
  * they set _PAGE_DIRTY then we can put a writable PTE entry in immediately.
  */
-static void do_set_pte(struct lg_cpu *cpu, int idx,
+static void __guest_set_pte(struct lg_cpu *cpu, int idx,
                       unsigned long vaddr, pte_t gpte)
 {
        /* Look up the matching shadow page directory entry. */
@@ -960,13 +960,13 @@ void guest_set_pte(struct lg_cpu *cpu,
                unsigned int i;
                for (i = 0; i < ARRAY_SIZE(cpu->lg->pgdirs); i++)
                        if (cpu->lg->pgdirs[i].pgdir)
-                               do_set_pte(cpu, i, vaddr, gpte);
+                               __guest_set_pte(cpu, i, vaddr, gpte);
        } else {
                /* Is this page table one we have a shadow for? */
                int pgdir = find_pgdir(cpu->lg, gpgdir);
                if (pgdir != ARRAY_SIZE(cpu->lg->pgdirs))
                        /* If so, do the update. */
-                       do_set_pte(cpu, pgdir, vaddr, gpte);
+                       __guest_set_pte(cpu, pgdir, vaddr, gpte);
        }
 }
 
index 7dca1e6..841717a 100644 (file)
@@ -571,7 +571,7 @@ static int pm800_probe(struct i2c_client *client,
        ret = pm800_pages_init(chip);
        if (ret) {
                dev_err(&client->dev, "pm800_pages_init failed!\n");
-               goto err_page_init;
+               goto err_device_init;
        }
 
        ret = device_800_init(chip, pdata);
@@ -587,7 +587,6 @@ static int pm800_probe(struct i2c_client *client,
 
 err_device_init:
        pm800_pages_exit(chip);
-err_page_init:
 err_subchip_alloc:
        pm80x_deinit();
 out_init:
index c9b1f64..bcfc9e8 100644 (file)
@@ -1179,12 +1179,18 @@ static int pm860x_probe(struct i2c_client *client,
                chip->companion_addr = pdata->companion_addr;
                chip->companion = i2c_new_dummy(chip->client->adapter,
                                                chip->companion_addr);
+               if (!chip->companion) {
+                       dev_err(&client->dev,
+                               "Failed to allocate I2C companion device\n");
+                       return -ENODEV;
+               }
                chip->regmap_companion = regmap_init_i2c(chip->companion,
                                                        &pm860x_regmap_config);
                if (IS_ERR(chip->regmap_companion)) {
                        ret = PTR_ERR(chip->regmap_companion);
                        dev_err(&chip->companion->dev,
                                "Failed to allocate register map: %d\n", ret);
+                       i2c_unregister_device(chip->companion);
                        return ret;
                }
                i2c_set_clientdata(chip->companion, chip);
index 49bb445..3383412 100644 (file)
@@ -59,6 +59,14 @@ config MFD_AAT2870_CORE
          additional drivers must be enabled in order to use the
          functionality of the device.
 
+config MFD_BCM590XX
+       tristate "Broadcom BCM590xx PMUs"
+       select MFD_CORE
+       select REGMAP_I2C
+       depends on I2C
+       help
+         Support for the BCM590xx PMUs from Broadcom
+
 config MFD_CROS_EC
        tristate "ChromeOS Embedded Controller"
        select MFD_CORE
@@ -100,7 +108,7 @@ config PMIC_DA903X
        bool "Dialog Semiconductor DA9030/DA9034 PMIC Support"
        depends on I2C=y
        help
-         Say yes here to support for Dialog Semiconductor DA9030 (a.k.a
+         Say yes here to add support for Dialog Semiconductor DA9030 (a.k.a
          ARAVA) and DA9034 (a.k.a MICCO), these are Power Management IC
          usually found on PXA processors-based platforms. This includes
          the I2C driver and the core APIs _only_, you have to select
@@ -270,13 +278,18 @@ config MFD_KEMPLD
          device may provide functions like watchdog, GPIO, UART and I2C bus.
 
          The following modules are supported:
+               * COMe-bHL6
                * COMe-bIP#
                * COMe-bPC2 (ETXexpress-PC)
                * COMe-bSC# (ETXexpress-SC T#)
+               * COMe-cBT6
                * COMe-cCT6
                * COMe-cDC2 (microETXexpress-DC)
+               * COMe-cHL6
                * COMe-cPC2 (microETXexpress-PC)
+               * COMe-mBT10
                * COMe-mCT10
+               * COMe-mTT10 (nanoETXexpress-TT)
                * ETX-OH
 
          This driver can also be built as a module. If so, the module
@@ -322,9 +335,10 @@ config MFD_MAX14577
        depends on I2C=y
        select MFD_CORE
        select REGMAP_I2C
+       select REGMAP_IRQ
        select IRQ_DOMAIN
        help
-         Say yes here to support for Maxim Semiconductor MAX14577.
+         Say yes here to add support for Maxim Semiconductor MAX14577.
          This is a Micro-USB IC with Charger controls on chip.
          This driver provides common support for accessing the device;
          additional drivers must be enabled in order to use the functionality
@@ -337,7 +351,7 @@ config MFD_MAX77686
        select REGMAP_I2C
        select IRQ_DOMAIN
        help
-         Say yes here to support for Maxim Semiconductor MAX77686.
+         Say yes here to add support for Maxim Semiconductor MAX77686.
          This is a Power Management IC with RTC on chip.
          This driver provides common support for accessing the device;
          additional drivers must be enabled in order to use the functionality
@@ -349,7 +363,7 @@ config MFD_MAX77693
        select MFD_CORE
        select REGMAP_I2C
        help
-         Say yes here to support for Maxim Semiconductor MAX77693.
+         Say yes here to add support for Maxim Semiconductor MAX77693.
          This is a companion Power Management IC with Flash, Haptic, Charger,
          and MUIC(Micro USB Interface Controller) controls on chip.
          This driver provides common support for accessing the device;
@@ -363,7 +377,7 @@ config MFD_MAX8907
        select REGMAP_I2C
        select REGMAP_IRQ
        help
-         Say yes here to support for Maxim Semiconductor MAX8907. This is
+         Say yes here to add support for Maxim Semiconductor MAX8907. This is
          a Power Management IC. This driver provides common support for
          accessing the device; additional drivers must be enabled in order
          to use the functionality of the device.
@@ -373,7 +387,7 @@ config MFD_MAX8925
        depends on I2C=y
        select MFD_CORE
        help
-         Say yes here to support for Maxim Semiconductor MAX8925. This is
+         Say yes here to add support for Maxim Semiconductor MAX8925. This is
          a Power Management IC. This driver provides common support for
          accessing the device, additional drivers must be enabled in order
          to use the functionality of the device.
@@ -384,7 +398,7 @@ config MFD_MAX8997
        select MFD_CORE
        select IRQ_DOMAIN
        help
-         Say yes here to support for Maxim Semiconductor MAX8997/8966.
+         Say yes here to add support for Maxim Semiconductor MAX8997/8966.
          This is a Power Management IC with RTC, Flash, Fuel Gauge, Haptic,
          MUIC controls on chip.
          This driver provides common support for accessing the device;
@@ -397,7 +411,7 @@ config MFD_MAX8998
        select MFD_CORE
        select IRQ_DOMAIN
        help
-         Say yes here to support for Maxim Semiconductor MAX8998 and
+         Say yes here to add support for Maxim Semiconductor MAX8998 and
          National Semiconductor LP3974. This is a Power Management IC.
          This driver provides common support for accessing the device,
          additional drivers must be enabled in order to use the functionality
@@ -473,10 +487,11 @@ config MFD_PM8XXX
 
 config MFD_PM8921_CORE
        tristate "Qualcomm PM8921 PMIC chip"
-       depends on (ARCH_MSM || HEXAGON)
-       depends on BROKEN
+       depends on (ARM || HEXAGON)
+       select IRQ_DOMAIN
        select MFD_CORE
        select MFD_PM8XXX
+       select REGMAP
        help
          If you say yes to this option, support will be included for the
          built-in PM8921 PMIC chip.
@@ -487,16 +502,6 @@ config MFD_PM8921_CORE
          Say M here if you want to include support for PM8921 chip as a module.
          This will build a module called "pm8921-core".
 
-config MFD_PM8XXX_IRQ
-       bool "Qualcomm PM8xxx IRQ features"
-       depends on MFD_PM8XXX
-       default y if MFD_PM8XXX
-       help
-         This is the IRQ driver for Qualcomm PM 8xxx PMIC chips.
-
-         This is required to use certain other PM 8xxx features, such as GPIO
-         and MPP.
-
 config MFD_RDC321X
        tristate "RDC R-321x southbridge"
        select MFD_CORE
@@ -516,6 +521,16 @@ config MFD_RTSX_PCI
          types of memory cards, such as Memory Stick, Memory Stick Pro,
          Secure Digital and MultiMediaCard.
 
+config MFD_RTSX_USB
+       tristate "Realtek USB card reader"
+       depends on USB
+       select MFD_CORE
+       help
+         Select this option to get support for Realtek USB 2.0 card readers
+         including RTS5129, RTS5139, RTS5179 and RTS5170.
+         Realtek card reader supports access to many types of memory cards,
+         such as Memory Stick Pro, Secure Digital and MultiMediaCard.
+
 config MFD_RC5T583
        bool "Ricoh RC5T583 Power Management system device"
        depends on I2C=y
@@ -774,17 +789,6 @@ config MFD_PALMAS
          If you say yes here you get support for the Palmas
          series of PMIC chips from Texas Instruments.
 
-config MFD_TI_SSP
-       tristate "TI Sequencer Serial Port support"
-       depends on ARCH_DAVINCI_TNETV107X
-       select MFD_CORE
-       ---help---
-         Say Y here if you want support for the Sequencer Serial Port
-         in a Texas Instruments TNETV107X SoC.
-
-         To compile this driver as a module, choose M here: the
-         module will be called ti-ssp.
-
 config TPS6105X
        tristate "TI TPS61050/61052 Boost Converters"
        depends on I2C
@@ -853,6 +857,22 @@ config MFD_TPS65217
          This driver can also be built as a module.  If so, the module
          will be called tps65217.
 
+config MFD_TPS65218
+       tristate "TI TPS65218 Power Management chips"
+       depends on I2C
+       select MFD_CORE
+       select REGMAP_I2C
+       select REGMAP_IRQ
+       help
+         If you say yes here you get support for the TPS65218 series of
+         Power Management chips.
+         These include voltage regulators, gpio and other features
+         that are often used in portable devices. Only regulator
+         component is currently supported.
+
+         This driver can also be built as a module.  If so, the module
+         will be called tps65218.
+
 config MFD_TPS6586X
        bool "TI TPS6586x Power Management chips"
        depends on I2C=y
@@ -935,16 +955,6 @@ config TWL4030_CORE
          high speed USB OTG transceiver, an audio codec (on most
          versions) and many other features.
 
-config TWL4030_MADC
-       tristate "TI TWL4030 MADC"
-       depends on TWL4030_CORE
-       help
-       This driver provides support for triton TWL4030-MADC. The
-       driver supports both RT and SW conversion methods.
-
-       This driver can be built as a module. If so it will be
-       named twl4030-madc
-
 config TWL4030_POWER
        bool "TI TWL4030 power resources"
        depends on TWL4030_CORE && ARM
@@ -1193,9 +1203,6 @@ config MFD_STW481X
          in various ST Microelectronics and ST-Ericsson embedded
          Nomadik series.
 
-endmenu
-endif
-
 menu "Multimedia Capabilities Port drivers"
        depends on ARCH_SA1100
 
@@ -1226,3 +1233,6 @@ config VEXPRESS_CONFIG
        help
          Platform configuration infrastructure for the ARM Ltd.
          Versatile Express.
+
+endmenu
+endif
index 5aea5ef..2851275 100644 (file)
@@ -8,12 +8,14 @@ obj-$(CONFIG_MFD_88PM800)     += 88pm800.o 88pm80x.o
 obj-$(CONFIG_MFD_88PM805)      += 88pm805.o 88pm80x.o
 obj-$(CONFIG_MFD_SM501)                += sm501.o
 obj-$(CONFIG_MFD_ASIC3)                += asic3.o tmio_core.o
+obj-$(CONFIG_MFD_BCM590XX)     += bcm590xx.o
 obj-$(CONFIG_MFD_CROS_EC)      += cros_ec.o
 obj-$(CONFIG_MFD_CROS_EC_I2C)  += cros_ec_i2c.o
 obj-$(CONFIG_MFD_CROS_EC_SPI)  += cros_ec_spi.o
 
 rtsx_pci-objs                  := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
 obj-$(CONFIG_MFD_RTSX_PCI)     += rtsx_pci.o
+obj-$(CONFIG_MFD_RTSX_USB)     += rtsx_usb.o
 
 obj-$(CONFIG_HTC_EGPIO)                += htc-egpio.o
 obj-$(CONFIG_HTC_PASIC3)       += htc-pasic3.o
@@ -21,7 +23,6 @@ obj-$(CONFIG_HTC_I2CPLD)      += htc-i2cpld.o
 
 obj-$(CONFIG_MFD_DAVINCI_VOICECODEC)   += davinci_voicecodec.o
 obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
-obj-$(CONFIG_MFD_TI_SSP)       += ti-ssp.o
 obj-$(CONFIG_MFD_TI_AM335X_TSCADC)     += ti_am335x_tscadc.o
 
 obj-$(CONFIG_MFD_STA2X11)      += sta2x11-mfd.o
@@ -62,6 +63,7 @@ obj-$(CONFIG_TPS6105X)                += tps6105x.o
 obj-$(CONFIG_TPS65010)         += tps65010.o
 obj-$(CONFIG_TPS6507X)         += tps6507x.o
 obj-$(CONFIG_MFD_TPS65217)     += tps65217.o
+obj-$(CONFIG_MFD_TPS65218)     += tps65218.o
 obj-$(CONFIG_MFD_TPS65910)     += tps65910.o
 tps65912-objs                   := tps65912-core.o tps65912-irq.o
 obj-$(CONFIG_MFD_TPS65912)     += tps65912.o
@@ -71,7 +73,6 @@ obj-$(CONFIG_MFD_TPS80031)    += tps80031.o
 obj-$(CONFIG_MENELAUS)         += menelaus.o
 
 obj-$(CONFIG_TWL4030_CORE)     += twl-core.o twl4030-irq.o twl6030-irq.o
-obj-$(CONFIG_TWL4030_MADC)      += twl4030-madc.o
 obj-$(CONFIG_TWL4030_POWER)    += twl4030-power.o
 obj-$(CONFIG_MFD_TWL4030_AUDIO)        += twl4030-audio.o
 obj-$(CONFIG_TWL6040_CORE)     += twl6040.o
@@ -150,7 +151,6 @@ obj-$(CONFIG_MFD_SI476X_CORE)       += si476x-core.o
 obj-$(CONFIG_MFD_CS5535)       += cs5535-mfd.o
 obj-$(CONFIG_MFD_OMAP_USB_HOST)        += omap-usb-host.o omap-usb-tll.o
 obj-$(CONFIG_MFD_PM8921_CORE)  += pm8921-core.o ssbi.o
-obj-$(CONFIG_MFD_PM8XXX_IRQ)   += pm8xxx-irq.o
 obj-$(CONFIG_TPS65911_COMPARATOR)      += tps65911-comparator.o
 obj-$(CONFIG_MFD_TPS65090)     += tps65090.o
 obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
index 6250155..f495b8b 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index c71ff0a..39fa554 100644 (file)
@@ -277,6 +277,7 @@ static const struct regmap_range as3722_readable_ranges[] = {
        regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC_CONFIGURATION_REG),
        regmap_reg_range(AS3722_ASIC_ID1_REG, AS3722_ASIC_ID2_REG),
        regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG),
+       regmap_reg_range(AS3722_FUSE7_REG, AS3722_FUSE7_REG),
 };
 
 static const struct regmap_access_table as3722_readable_table = {
diff --git a/drivers/mfd/bcm590xx.c b/drivers/mfd/bcm590xx.c
new file mode 100644 (file)
index 0000000..e9a33c7
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Broadcom BCM590xx PMU
+ *
+ * Copyright 2014 Linaro Limited
+ * Author: Matt Porter <mporter@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under  the terms of the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/mfd/bcm590xx.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+static const struct mfd_cell bcm590xx_devs[] = {
+       {
+               .name = "bcm590xx-vregs",
+       },
+};
+
+static const struct regmap_config bcm590xx_regmap_config = {
+       .reg_bits       = 8,
+       .val_bits       = 8,
+       .max_register   = BCM590XX_MAX_REGISTER,
+       .cache_type     = REGCACHE_RBTREE,
+};
+
+static int bcm590xx_i2c_probe(struct i2c_client *i2c,
+                             const struct i2c_device_id *id)
+{
+       struct bcm590xx *bcm590xx;
+       int ret;
+
+       bcm590xx = devm_kzalloc(&i2c->dev, sizeof(*bcm590xx), GFP_KERNEL);
+       if (!bcm590xx)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, bcm590xx);
+       bcm590xx->dev = &i2c->dev;
+       bcm590xx->i2c_client = i2c;
+
+       bcm590xx->regmap = devm_regmap_init_i2c(i2c, &bcm590xx_regmap_config);
+       if (IS_ERR(bcm590xx->regmap)) {
+               ret = PTR_ERR(bcm590xx->regmap);
+               dev_err(&i2c->dev, "regmap initialization failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = mfd_add_devices(&i2c->dev, -1, bcm590xx_devs,
+                             ARRAY_SIZE(bcm590xx_devs), NULL, 0, NULL);
+       if (ret < 0)
+               dev_err(&i2c->dev, "failed to add sub-devices: %d\n", ret);
+
+       return ret;
+}
+
+static const struct of_device_id bcm590xx_of_match[] = {
+       { .compatible = "brcm,bcm59056" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, bcm590xx_of_match);
+
+static const struct i2c_device_id bcm590xx_i2c_id[] = {
+       { "bcm59056" },
+       { }
+};
+MODULE_DEVICE_TABLE(i2c, bcm590xx_i2c_id);
+
+static struct i2c_driver bcm590xx_i2c_driver = {
+       .driver = {
+                  .name = "bcm590xx",
+                  .owner = THIS_MODULE,
+                  .of_match_table = of_match_ptr(bcm590xx_of_match),
+       },
+       .probe = bcm590xx_i2c_probe,
+       .id_table = bcm590xx_i2c_id,
+};
+module_i2c_driver(bcm590xx_i2c_driver);
+
+MODULE_AUTHOR("Matt Porter <mporter@linaro.org>");
+MODULE_DESCRIPTION("BCM590xx multi-function driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bcm590xx");
index 17c1301..be91cb5 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/mfd/core.h>
 #include <linux/module.h>
 #include <linux/pci.h>
index 25838f1..e8af816 100644 (file)
@@ -279,6 +279,9 @@ static bool da9052_reg_volatile(struct device *dev, unsigned int reg)
        case DA9052_EVENT_B_REG:
        case DA9052_EVENT_C_REG:
        case DA9052_EVENT_D_REG:
+       case DA9052_CONTROL_B_REG:
+       case DA9052_CONTROL_D_REG:
+       case DA9052_SUPPLY_REG:
        case DA9052_FAULTLOG_REG:
        case DA9052_CHG_TIME_REG:
        case DA9052_ADC_RES_L_REG:
index c319c4e..6da8ec8 100644 (file)
@@ -75,6 +75,7 @@ static int da9052_i2c_fix(struct da9052 *da9052, unsigned char reg)
                                           DA9052_PARK_REGISTER,
                                           &val);
                break;
+       case DA9053_BC:
        default:
                /*
                 * For other chips parking of I2C register
@@ -114,6 +115,7 @@ static const struct i2c_device_id da9052_i2c_id[] = {
        {"da9053-aa", DA9053_AA},
        {"da9053-ba", DA9053_BA},
        {"da9053-bb", DA9053_BB},
+       {"da9053-bc", DA9053_BC},
        {}
 };
 
@@ -121,8 +123,9 @@ static const struct i2c_device_id da9052_i2c_id[] = {
 static const struct of_device_id dialog_dt_ids[] = {
        { .compatible = "dlg,da9052", .data = &da9052_i2c_id[0] },
        { .compatible = "dlg,da9053-aa", .data = &da9052_i2c_id[1] },
-       { .compatible = "dlg,da9053-ab", .data = &da9052_i2c_id[2] },
+       { .compatible = "dlg,da9053-ba", .data = &da9052_i2c_id[2] },
        { .compatible = "dlg,da9053-bb", .data = &da9052_i2c_id[3] },
+       { .compatible = "dlg,da9053-bc", .data = &da9052_i2c_id[4] },
        { /* sentinel */ }
 };
 #endif
index 0680bcb..17666b4 100644 (file)
@@ -71,6 +71,7 @@ static struct spi_device_id da9052_spi_id[] = {
        {"da9053-aa", DA9053_AA},
        {"da9053-ba", DA9053_BA},
        {"da9053-bb", DA9053_BB},
+       {"da9053-bc", DA9053_BC},
        {}
 };
 
index 8103e43..d4d4c16 100644 (file)
@@ -15,6 +15,8 @@
 #include <linux/device.h>
 #include <linux/i2c.h>
 #include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
 
 #include <linux/mfd/da9055/core.h>
 
@@ -66,6 +68,11 @@ static struct i2c_device_id da9055_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, da9055_i2c_id);
 
+static const struct of_device_id da9055_of_match[] = {
+       { .compatible = "dlg,da9055-pmic", },
+       { }
+};
+
 static struct i2c_driver da9055_i2c_driver = {
        .probe = da9055_i2c_probe,
        .remove = da9055_i2c_remove,
@@ -73,6 +80,7 @@ static struct i2c_driver da9055_i2c_driver = {
        .driver = {
                .name = "da9055-pmic",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(da9055_of_match),
        },
 };
 
index 26937cd..e70ae31 100644 (file)
@@ -110,7 +110,7 @@ static const struct mfd_cell da9063_devs[] = {
 int da9063_device_init(struct da9063 *da9063, unsigned int irq)
 {
        struct da9063_pdata *pdata = da9063->dev->platform_data;
-       int model, revision;
+       int model, variant_id, variant_code;
        int ret;
 
        if (pdata) {
@@ -141,23 +141,26 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
                return -ENODEV;
        }
 
-       ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &revision);
+       ret = regmap_read(da9063->regmap, DA9063_REG_CHIP_VARIANT, &variant_id);
        if (ret < 0) {
-               dev_err(da9063->dev, "Cannot read chip revision id.\n");
+               dev_err(da9063->dev, "Cannot read chip variant id.\n");
                return -EIO;
        }
-       revision >>= DA9063_CHIP_VARIANT_SHIFT;
-       if (revision != 3) {
-               dev_err(da9063->dev, "Unknown chip revision: %d\n", revision);
+
+       variant_code = variant_id >> DA9063_CHIP_VARIANT_SHIFT;
+
+       dev_info(da9063->dev,
+                "Device detected (chip-ID: 0x%02X, var-ID: 0x%02X)\n",
+                model, variant_id);
+
+       if (variant_code != PMIC_DA9063_BB) {
+               dev_err(da9063->dev, "Unknown chip variant code: 0x%02X\n",
+                               variant_code);
                return -ENODEV;
        }
 
        da9063->model = model;
-       da9063->revision = revision;
-
-       dev_info(da9063->dev,
-                "Device detected (model-ID: 0x%02X  rev-ID: 0x%02X)\n",
-                model, revision);
+       da9063->variant_code = variant_code;
 
        ret = da9063_irq_init(da9063);
        if (ret) {
index 81b7d88..433f823 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
index d3e2327..0769260 100644 (file)
@@ -322,9 +322,12 @@ static int kempld_detect_device(struct kempld_device_data *pld)
                return -ENODEV;
        }
 
-       /* Release hardware mutex if aquired */
-       if (!(index_reg & KEMPLD_MUTEX_KEY))
+       /* Release hardware mutex if acquired */
+       if (!(index_reg & KEMPLD_MUTEX_KEY)) {
                iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
+               /* PXT and COMe-cPC2 boards may require a second release */
+               iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
+       }
 
        mutex_unlock(&pld->lock);
 
@@ -437,6 +440,14 @@ static struct dmi_system_id __initdata kempld_dmi_table[] = {
                },
                .driver_data = (void *)&kempld_platform_data_generic,
                .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CHL6",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
        }, {
                .ident = "CHR2",
                .matches = {
@@ -509,6 +520,14 @@ static struct dmi_system_id __initdata kempld_dmi_table[] = {
                },
                .driver_data = (void *)&kempld_platform_data_generic,
                .callback = kempld_create_platform_device,
+       }, {
+               .ident = "CVV6",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
        }, {
                .ident = "FRI2",
                .matches = {
@@ -532,6 +551,14 @@ static struct dmi_system_id __initdata kempld_dmi_table[] = {
                },
                .driver_data = (void *)&kempld_platform_data_generic,
                .callback = kempld_create_platform_device,
+       }, {
+               .ident = "MVV1",
+               .matches = {
+                       DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
+                       DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT"),
+               },
+               .driver_data = (void *)&kempld_platform_data_generic,
+               .callback = kempld_create_platform_device,
        }, {
                .ident = "NTC1",
                .matches = {
index be93fa2..3f10ea3 100644 (file)
@@ -58,7 +58,6 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
 #define ACPIBASE_GPE_END       0x2f
 #define ACPIBASE_SMI_OFF       0x30
 #define ACPIBASE_SMI_END       0x33
+#define ACPIBASE_PMC_OFF       0x08
+#define ACPIBASE_PMC_END       0x0c
 #define ACPIBASE_TCO_OFF       0x60
 #define ACPIBASE_TCO_END       0x7f
-#define ACPICTRL               0x44
+#define ACPICTRL_PMCBASE       0x44
 
 #define ACPIBASE_GCS_OFF       0x3410
 #define ACPIBASE_GCS_END       0x3414
 #define wdt_mem_res(i) wdt_res(ICH_RES_MEM_OFF, i)
 #define wdt_res(b, i) (&wdt_ich_res[(b) + (i)])
 
-struct lpc_ich_cfg {
-       int base;
-       int ctrl;
-       int save;
-};
-
 struct lpc_ich_priv {
        int chipset;
-       struct lpc_ich_cfg acpi;
-       struct lpc_ich_cfg gpio;
+
+       int abase;              /* ACPI base */
+       int actrl_pbase;        /* ACPI control or PMC base */
+       int gbase;              /* GPIO base */
+       int gctrl;              /* GPIO control */
+
+       int abase_save;         /* Cached ACPI base value */
+       int actrl_pbase_save;           /* Cached ACPI control or PMC base value */
+       int gctrl_save;         /* Cached GPIO control value */
 };
 
 static struct resource wdt_ich_res[] = {
@@ -111,7 +113,7 @@ static struct resource wdt_ich_res[] = {
        {
                .flags = IORESOURCE_IO,
        },
-       /* GCS */
+       /* GCS or PMC */
        {
                .flags = IORESOURCE_MEM,
        },
@@ -211,6 +213,7 @@ enum lpc_chipsets {
        LPC_LPT_LP,     /* Lynx Point-LP */
        LPC_WBG,        /* Wellsburg */
        LPC_AVN,        /* Avoton SoC */
+       LPC_BAYTRAIL,   /* Bay Trail SoC */
        LPC_COLETO,     /* Coleto Creek */
        LPC_WPT_LP,     /* Wildcat Point-LP */
 };
@@ -303,6 +306,7 @@ static struct lpc_ich_info lpc_chipset_info[] = {
        [LPC_NM10] = {
                .name = "NM10",
                .iTCO_version = 2,
+               .gpio_version = ICH_V7_GPIO,
        },
        [LPC_ICH8] = {
                .name = "ICH8 or ICH8R",
@@ -499,7 +503,12 @@ static struct lpc_ich_info lpc_chipset_info[] = {
        },
        [LPC_AVN] = {
                .name = "Avoton SoC",
-               .iTCO_version = 1,
+               .iTCO_version = 3,
+               .gpio_version = AVOTON_GPIO,
+       },
+       [LPC_BAYTRAIL] = {
+               .name = "Bay Trail SoC",
+               .iTCO_version = 3,
        },
        [LPC_COLETO] = {
                .name = "Coleto Creek",
@@ -726,6 +735,7 @@ static const struct pci_device_id lpc_ich_ids[] = {
        { PCI_VDEVICE(INTEL, 0x1f39), LPC_AVN},
        { PCI_VDEVICE(INTEL, 0x1f3a), LPC_AVN},
        { PCI_VDEVICE(INTEL, 0x1f3b), LPC_AVN},
+       { PCI_VDEVICE(INTEL, 0x0f1c), LPC_BAYTRAIL},
        { PCI_VDEVICE(INTEL, 0x2390), LPC_COLETO},
        { PCI_VDEVICE(INTEL, 0x9cc1), LPC_WPT_LP},
        { PCI_VDEVICE(INTEL, 0x9cc2), LPC_WPT_LP},
@@ -742,14 +752,20 @@ static void lpc_ich_restore_config_space(struct pci_dev *dev)
 {
        struct lpc_ich_priv *priv = pci_get_drvdata(dev);
 
-       if (priv->acpi.save >= 0) {
-               pci_write_config_byte(dev, priv->acpi.ctrl, priv->acpi.save);
-               priv->acpi.save = -1;
+       if (priv->abase_save >= 0) {
+               pci_write_config_byte(dev, priv->abase, priv->abase_save);
+               priv->abase_save = -1;
+       }
+
+       if (priv->actrl_pbase_save >= 0) {
+               pci_write_config_byte(dev, priv->actrl_pbase,
+                       priv->actrl_pbase_save);
+               priv->actrl_pbase_save = -1;
        }
 
-       if (priv->gpio.save >= 0) {
-               pci_write_config_byte(dev, priv->gpio.ctrl, priv->gpio.save);
-               priv->gpio.save = -1;
+       if (priv->gctrl_save >= 0) {
+               pci_write_config_byte(dev, priv->gctrl, priv->gctrl_save);
+               priv->gctrl_save = -1;
        }
 }
 
@@ -758,9 +774,26 @@ static void lpc_ich_enable_acpi_space(struct pci_dev *dev)
        struct lpc_ich_priv *priv = pci_get_drvdata(dev);
        u8 reg_save;
 
-       pci_read_config_byte(dev, priv->acpi.ctrl, &reg_save);
-       pci_write_config_byte(dev, priv->acpi.ctrl, reg_save | 0x10);
-       priv->acpi.save = reg_save;
+       switch (lpc_chipset_info[priv->chipset].iTCO_version) {
+       case 3:
+               /*
+                * Some chipsets (eg Avoton) enable the ACPI space in the
+                * ACPI BASE register.
+                */
+               pci_read_config_byte(dev, priv->abase, &reg_save);
+               pci_write_config_byte(dev, priv->abase, reg_save | 0x2);
+               priv->abase_save = reg_save;
+               break;
+       default:
+               /*
+                * Most chipsets enable the ACPI space in the ACPI control
+                * register.
+                */
+               pci_read_config_byte(dev, priv->actrl_pbase, &reg_save);
+               pci_write_config_byte(dev, priv->actrl_pbase, reg_save | 0x80);
+               priv->actrl_pbase_save = reg_save;
+               break;
+       }
 }
 
 static void lpc_ich_enable_gpio_space(struct pci_dev *dev)
@@ -768,9 +801,20 @@ static void lpc_ich_enable_gpio_space(struct pci_dev *dev)
        struct lpc_ich_priv *priv = pci_get_drvdata(dev);
        u8 reg_save;
 
-       pci_read_config_byte(dev, priv->gpio.ctrl, &reg_save);
-       pci_write_config_byte(dev, priv->gpio.ctrl, reg_save | 0x10);
-       priv->gpio.save = reg_save;
+       pci_read_config_byte(dev, priv->gctrl, &reg_save);
+       pci_write_config_byte(dev, priv->gctrl, reg_save | 0x10);
+       priv->gctrl_save = reg_save;
+}
+
+static void lpc_ich_enable_pmc_space(struct pci_dev *dev)
+{
+       struct lpc_ich_priv *priv = pci_get_drvdata(dev);
+       u8 reg_save;
+
+       pci_read_config_byte(dev, priv->actrl_pbase, &reg_save);
+       pci_write_config_byte(dev, priv->actrl_pbase, reg_save | 0x2);
+
+       priv->actrl_pbase_save = reg_save;
 }
 
 static void lpc_ich_finalize_cell(struct pci_dev *dev, struct mfd_cell *cell)
@@ -815,7 +859,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev)
        struct resource *res;
 
        /* Setup power management base register */
-       pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
+       pci_read_config_dword(dev, priv->abase, &base_addr_cfg);
        base_addr = base_addr_cfg & 0x0000ff80;
        if (!base_addr) {
                dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
@@ -841,7 +885,7 @@ static int lpc_ich_init_gpio(struct pci_dev *dev)
 
 gpe0_done:
        /* Setup GPIO base register */
-       pci_read_config_dword(dev, priv->gpio.base, &base_addr_cfg);
+       pci_read_config_dword(dev, priv->gbase, &base_addr_cfg);
        base_addr = base_addr_cfg & 0x0000ff80;
        if (!base_addr) {
                dev_notice(&dev->dev, "I/O space for GPIO uninitialized\n");
@@ -891,7 +935,7 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
        struct resource *res;
 
        /* Setup power management base register */
-       pci_read_config_dword(dev, priv->acpi.base, &base_addr_cfg);
+       pci_read_config_dword(dev, priv->abase, &base_addr_cfg);
        base_addr = base_addr_cfg & 0x0000ff80;
        if (!base_addr) {
                dev_notice(&dev->dev, "I/O space for ACPI uninitialized\n");
@@ -910,14 +954,20 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
        lpc_ich_enable_acpi_space(dev);
 
        /*
+        * iTCO v2:
         * Get the Memory-Mapped GCS register. To get access to it
         * we have to read RCBA from PCI Config space 0xf0 and use
         * it as base. GCS = RCBA + ICH6_GCS(0x3410).
+        *
+        * iTCO v3:
+        * Get the Power Management Configuration register.  To get access
+        * to it we have to read the PMC BASE from config space and address
+        * the register at offset 0x8.
         */
        if (lpc_chipset_info[priv->chipset].iTCO_version == 1) {
                /* Don't register iomem for TCO ver 1 */
                lpc_ich_cells[LPC_WDT].num_resources--;
-       } else {
+       } else if (lpc_chipset_info[priv->chipset].iTCO_version == 2) {
                pci_read_config_dword(dev, RCBABASE, &base_addr_cfg);
                base_addr = base_addr_cfg & 0xffffc000;
                if (!(base_addr_cfg & 1)) {
@@ -926,9 +976,17 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
                        ret = -ENODEV;
                        goto wdt_done;
                }
-               res = wdt_mem_res(ICH_RES_MEM_GCS);
+               res = wdt_mem_res(ICH_RES_MEM_GCS_PMC);
                res->start = base_addr + ACPIBASE_GCS_OFF;
                res->end = base_addr + ACPIBASE_GCS_END;
+       } else if (lpc_chipset_info[priv->chipset].iTCO_version == 3) {
+               lpc_ich_enable_pmc_space(dev);
+               pci_read_config_dword(dev, ACPICTRL_PMCBASE, &base_addr_cfg);
+               base_addr = base_addr_cfg & 0xfffffe00;
+
+               res = wdt_mem_res(ICH_RES_MEM_GCS_PMC);
+               res->start = base_addr + ACPIBASE_PMC_OFF;
+               res->end = base_addr + ACPIBASE_PMC_END;
        }
 
        lpc_ich_finalize_cell(dev, &lpc_ich_cells[LPC_WDT]);
@@ -952,28 +1010,35 @@ static int lpc_ich_probe(struct pci_dev *dev,
                return -ENOMEM;
 
        priv->chipset = id->driver_data;
-       priv->acpi.save = -1;
-       priv->acpi.base = ACPIBASE;
-       priv->acpi.ctrl = ACPICTRL;
 
-       priv->gpio.save = -1;
+       priv->actrl_pbase_save = -1;
+       priv->abase_save = -1;
+
+       priv->abase = ACPIBASE;
+       priv->actrl_pbase = ACPICTRL_PMCBASE;
+
+       priv->gctrl_save = -1;
        if (priv->chipset <= LPC_ICH5) {
-               priv->gpio.base = GPIOBASE_ICH0;
-               priv->gpio.ctrl = GPIOCTRL_ICH0;
+               priv->gbase = GPIOBASE_ICH0;
+               priv->gctrl = GPIOCTRL_ICH0;
        } else {
-               priv->gpio.base = GPIOBASE_ICH6;
-               priv->gpio.ctrl = GPIOCTRL_ICH6;
+               priv->gbase = GPIOBASE_ICH6;
+               priv->gctrl = GPIOCTRL_ICH6;
        }
 
        pci_set_drvdata(dev, priv);
 
-       ret = lpc_ich_init_wdt(dev);
-       if (!ret)
-               cell_added = true;
+       if (lpc_chipset_info[priv->chipset].iTCO_version) {
+               ret = lpc_ich_init_wdt(dev);
+               if (!ret)
+                       cell_added = true;
+       }
 
-       ret = lpc_ich_init_gpio(dev);
-       if (!ret)
-               cell_added = true;
+       if (lpc_chipset_info[priv->chipset].gpio_version) {
+               ret = lpc_ich_init_gpio(dev);
+               if (!ret)
+                       cell_added = true;
+       }
 
        /*
         * We only care if at least one or none of the cells registered
index 3bb05c0..4ee7550 100644 (file)
@@ -23,7 +23,6 @@
  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/errno.h>
index 71aa14a..5f13cef 100644 (file)
@@ -18,6 +18,7 @@
  * This driver is based on max8997.c
  */
 
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/max14577-private.h>
 
 static struct mfd_cell max14577_devs[] = {
-       { .name = "max14577-muic", },
+       {
+               .name = "max14577-muic",
+               .of_compatible = "maxim,max14577-muic",
+       },
        {
                .name = "max14577-regulator",
                .of_compatible = "maxim,max14577-regulator",
index f53d582..e5fce76 100644 (file)
@@ -121,6 +121,10 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
                dev_info(max77686->dev, "device found\n");
 
        max77686->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
+       if (!max77686->rtc) {
+               dev_err(max77686->dev, "Failed to allocate I2C device for RTC\n");
+               return -ENODEV;
+       }
        i2c_set_clientdata(max77686->rtc, max77686);
 
        max77686_irq_init(max77686);
index e085998..c5535f0 100644 (file)
@@ -148,9 +148,18 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
                dev_info(max77693->dev, "device ID: 0x%x\n", reg_data);
 
        max77693->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC);
+       if (!max77693->muic) {
+               dev_err(max77693->dev, "Failed to allocate I2C device for MUIC\n");
+               return -ENODEV;
+       }
        i2c_set_clientdata(max77693->muic, max77693);
 
        max77693->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
+       if (!max77693->haptic) {
+               dev_err(max77693->dev, "Failed to allocate I2C device for Haptic\n");
+               ret = -ENODEV;
+               goto err_i2c_haptic;
+       }
        i2c_set_clientdata(max77693->haptic, max77693);
 
        /*
@@ -184,8 +193,9 @@ err_mfd:
        max77693_irq_exit(max77693);
 err_irq:
 err_regmap_muic:
-       i2c_unregister_device(max77693->muic);
        i2c_unregister_device(max77693->haptic);
+err_i2c_haptic:
+       i2c_unregister_device(max77693->muic);
        return ret;
 }
 
index 176aa26..a83eed5 100644 (file)
@@ -181,9 +181,18 @@ static int max8925_probe(struct i2c_client *client,
        mutex_init(&chip->io_lock);
 
        chip->rtc = i2c_new_dummy(chip->i2c->adapter, RTC_I2C_ADDR);
+       if (!chip->rtc) {
+               dev_err(chip->dev, "Failed to allocate I2C device for RTC\n");
+               return -ENODEV;
+       }
        i2c_set_clientdata(chip->rtc, chip);
 
        chip->adc = i2c_new_dummy(chip->i2c->adapter, ADC_I2C_ADDR);
+       if (!chip->adc) {
+               dev_err(chip->dev, "Failed to allocate I2C device for ADC\n");
+               i2c_unregister_device(chip->rtc);
+               return -ENODEV;
+       }
        i2c_set_clientdata(chip->adc, chip);
 
        device_init_wakeup(&client->dev, 1);
index 5adede0..8cf7a01 100644 (file)
@@ -208,10 +208,26 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
        mutex_init(&max8997->iolock);
 
        max8997->rtc = i2c_new_dummy(i2c->adapter, I2C_ADDR_RTC);
+       if (!max8997->rtc) {
+               dev_err(max8997->dev, "Failed to allocate I2C device for RTC\n");
+               return -ENODEV;
+       }
        i2c_set_clientdata(max8997->rtc, max8997);
+
        max8997->haptic = i2c_new_dummy(i2c->adapter, I2C_ADDR_HAPTIC);
+       if (!max8997->haptic) {
+               dev_err(max8997->dev, "Failed to allocate I2C device for Haptic\n");
+               ret = -ENODEV;
+               goto err_i2c_haptic;
+       }
        i2c_set_clientdata(max8997->haptic, max8997);
+
        max8997->muic = i2c_new_dummy(i2c->adapter, I2C_ADDR_MUIC);
+       if (!max8997->muic) {
+               dev_err(max8997->dev, "Failed to allocate I2C device for MUIC\n");
+               ret = -ENODEV;
+               goto err_i2c_muic;
+       }
        i2c_set_clientdata(max8997->muic, max8997);
 
        pm_runtime_set_active(max8997->dev);
@@ -239,7 +255,9 @@ static int max8997_i2c_probe(struct i2c_client *i2c,
 err_mfd:
        mfd_remove_devices(max8997->dev);
        i2c_unregister_device(max8997->muic);
+err_i2c_muic:
        i2c_unregister_device(max8997->haptic);
+err_i2c_haptic:
        i2c_unregister_device(max8997->rtc);
        return ret;
 }
index 5d5e186..592db06 100644 (file)
@@ -215,6 +215,10 @@ static int max8998_i2c_probe(struct i2c_client *i2c,
        mutex_init(&max8998->iolock);
 
        max8998->rtc = i2c_new_dummy(i2c->adapter, RTC_I2C_ADDR);
+       if (!max8998->rtc) {
+               dev_err(&i2c->dev, "Failed to allocate I2C device for RTC\n");
+               return -ENODEV;
+       }
        i2c_set_clientdata(max8998->rtc, max8998);
 
        max8998_irq_init(max8998);
index 38ab678..702925e 100644 (file)
@@ -140,6 +140,11 @@ static int mc13xxx_spi_probe(struct spi_device *spi)
 
        mc13xxx->irq = spi->irq;
 
+       spi->max_speed_hz = spi->max_speed_hz ? : 26000000;
+       ret = spi_setup(spi);
+       if (ret)
+               return ret;
+
        mc13xxx->regmap = devm_regmap_init(&spi->dev, &regmap_mc13xxx_bus,
                                           &spi->dev,
                                           &mc13xxx_regmap_spi_config);
index 41c31b3..29d7698 100644 (file)
@@ -12,7 +12,6 @@
  *  MCP read/write timeouts from Jordi Colomer, rehacked by rmk.
  */
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
index 90b630c..651e249 100644 (file)
@@ -665,55 +665,78 @@ static int usbhs_omap_probe(struct platform_device *pdev)
                goto err_mem;
        }
 
-       need_logic_fck = false;
+       /* Set all clocks as invalid to begin with */
+       omap->ehci_logic_fck = ERR_PTR(-ENODEV);
+       omap->init_60m_fclk = ERR_PTR(-ENODEV);
+       omap->utmi_p1_gfclk = ERR_PTR(-ENODEV);
+       omap->utmi_p2_gfclk = ERR_PTR(-ENODEV);
+       omap->xclk60mhsp1_ck = ERR_PTR(-ENODEV);
+       omap->xclk60mhsp2_ck = ERR_PTR(-ENODEV);
+
        for (i = 0; i < omap->nports; i++) {
-               if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) ||
-                       is_ehci_hsic_mode(i))
-                               need_logic_fck |= true;
+               omap->utmi_clk[i] = ERR_PTR(-ENODEV);
+               omap->hsic480m_clk[i] = ERR_PTR(-ENODEV);
+               omap->hsic60m_clk[i] = ERR_PTR(-ENODEV);
        }
 
-       omap->ehci_logic_fck = ERR_PTR(-EINVAL);
-       if (need_logic_fck) {
-               omap->ehci_logic_fck = clk_get(dev, "ehci_logic_fck");
-               if (IS_ERR(omap->ehci_logic_fck)) {
-                       ret = PTR_ERR(omap->ehci_logic_fck);
-                       dev_dbg(dev, "ehci_logic_fck failed:%d\n", ret);
+       /* for OMAP3 i.e. USBHS REV1 */
+       if (omap->usbhs_rev == OMAP_USBHS_REV1) {
+               need_logic_fck = false;
+               for (i = 0; i < omap->nports; i++) {
+                       if (is_ehci_phy_mode(pdata->port_mode[i]) ||
+                           is_ehci_tll_mode(pdata->port_mode[i]) ||
+                           is_ehci_hsic_mode(pdata->port_mode[i]))
+
+                               need_logic_fck |= true;
                }
+
+               if (need_logic_fck) {
+                       omap->ehci_logic_fck = devm_clk_get(dev,
+                                                           "usbhost_120m_fck");
+                       if (IS_ERR(omap->ehci_logic_fck)) {
+                               ret = PTR_ERR(omap->ehci_logic_fck);
+                               dev_err(dev, "usbhost_120m_fck failed:%d\n",
+                                       ret);
+                               goto err_mem;
+                       }
+               }
+               goto initialize;
        }
 
-       omap->utmi_p1_gfclk = clk_get(dev, "utmi_p1_gfclk");
+       /* for OMAP4+ i.e. USBHS REV2+ */
+       omap->utmi_p1_gfclk = devm_clk_get(dev, "utmi_p1_gfclk");
        if (IS_ERR(omap->utmi_p1_gfclk)) {
                ret = PTR_ERR(omap->utmi_p1_gfclk);
                dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret);
-               goto err_p1_gfclk;
+               goto err_mem;
        }
 
-       omap->utmi_p2_gfclk = clk_get(dev, "utmi_p2_gfclk");
+       omap->utmi_p2_gfclk = devm_clk_get(dev, "utmi_p2_gfclk");
        if (IS_ERR(omap->utmi_p2_gfclk)) {
                ret = PTR_ERR(omap->utmi_p2_gfclk);
                dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret);
-               goto err_p2_gfclk;
+               goto err_mem;
        }
 
-       omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck");
+       omap->xclk60mhsp1_ck = devm_clk_get(dev, "refclk_60m_ext_p1");
        if (IS_ERR(omap->xclk60mhsp1_ck)) {
                ret = PTR_ERR(omap->xclk60mhsp1_ck);
-               dev_err(dev, "xclk60mhsp1_ck failed error:%d\n", ret);
-               goto err_xclk60mhsp1;
+               dev_err(dev, "refclk_60m_ext_p1 failed error:%d\n", ret);
+               goto err_mem;
        }
 
-       omap->xclk60mhsp2_ck = clk_get(dev, "xclk60mhsp2_ck");
+       omap->xclk60mhsp2_ck = devm_clk_get(dev, "refclk_60m_ext_p2");
        if (IS_ERR(omap->xclk60mhsp2_ck)) {
                ret = PTR_ERR(omap->xclk60mhsp2_ck);
-               dev_err(dev, "xclk60mhsp2_ck failed error:%d\n", ret);
-               goto err_xclk60mhsp2;
+               dev_err(dev, "refclk_60m_ext_p2 failed error:%d\n", ret);
+               goto err_mem;
        }
 
-       omap->init_60m_fclk = clk_get(dev, "init_60m_fclk");
+       omap->init_60m_fclk = devm_clk_get(dev, "refclk_60m_int");
        if (IS_ERR(omap->init_60m_fclk)) {
                ret = PTR_ERR(omap->init_60m_fclk);
-               dev_err(dev, "init_60m_fclk failed error:%d\n", ret);
-               goto err_init60m;
+               dev_err(dev, "refclk_60m_int failed error:%d\n", ret);
+               goto err_mem;
        }
 
        for (i = 0; i < omap->nports; i++) {
@@ -727,55 +750,72 @@ static int usbhs_omap_probe(struct platform_device *pdev)
                 * platforms have all clocks and we can function without
                 * them
                 */
-               omap->utmi_clk[i] = clk_get(dev, clkname);
-               if (IS_ERR(omap->utmi_clk[i]))
-                       dev_dbg(dev, "Failed to get clock : %s : %ld\n",
-                               clkname, PTR_ERR(omap->utmi_clk[i]));
+               omap->utmi_clk[i] = devm_clk_get(dev, clkname);
+               if (IS_ERR(omap->utmi_clk[i])) {
+                       ret = PTR_ERR(omap->utmi_clk[i]);
+                       dev_err(dev, "Failed to get clock : %s : %d\n",
+                               clkname, ret);
+                       goto err_mem;
+               }
 
                snprintf(clkname, sizeof(clkname),
                                "usb_host_hs_hsic480m_p%d_clk", i + 1);
-               omap->hsic480m_clk[i] = clk_get(dev, clkname);
-               if (IS_ERR(omap->hsic480m_clk[i]))
-                       dev_dbg(dev, "Failed to get clock : %s : %ld\n",
-                               clkname, PTR_ERR(omap->hsic480m_clk[i]));
+               omap->hsic480m_clk[i] = devm_clk_get(dev, clkname);
+               if (IS_ERR(omap->hsic480m_clk[i])) {
+                       ret = PTR_ERR(omap->hsic480m_clk[i]);
+                       dev_err(dev, "Failed to get clock : %s : %d\n",
+                               clkname, ret);
+                       goto err_mem;
+               }
 
                snprintf(clkname, sizeof(clkname),
                                "usb_host_hs_hsic60m_p%d_clk", i + 1);
-               omap->hsic60m_clk[i] = clk_get(dev, clkname);
-               if (IS_ERR(omap->hsic60m_clk[i]))
-                       dev_dbg(dev, "Failed to get clock : %s : %ld\n",
-                               clkname, PTR_ERR(omap->hsic60m_clk[i]));
+               omap->hsic60m_clk[i] = devm_clk_get(dev, clkname);
+               if (IS_ERR(omap->hsic60m_clk[i])) {
+                       ret = PTR_ERR(omap->hsic60m_clk[i]);
+                       dev_err(dev, "Failed to get clock : %s : %d\n",
+                               clkname, ret);
+                       goto err_mem;
+               }
        }
 
        if (is_ehci_phy_mode(pdata->port_mode[0])) {
-               /* for OMAP3, clk_set_parent fails */
                ret = clk_set_parent(omap->utmi_p1_gfclk,
                                        omap->xclk60mhsp1_ck);
-               if (ret != 0)
-                       dev_dbg(dev, "xclk60mhsp1_ck set parent failed: %d\n",
-                                       ret);
+               if (ret != 0) {
+                       dev_err(dev, "xclk60mhsp1_ck set parent failed: %d\n",
+                               ret);
+                       goto err_mem;
+               }
        } else if (is_ehci_tll_mode(pdata->port_mode[0])) {
                ret = clk_set_parent(omap->utmi_p1_gfclk,
                                        omap->init_60m_fclk);
-               if (ret != 0)
-                       dev_dbg(dev, "P0 init_60m_fclk set parent failed: %d\n",
-                                       ret);
+               if (ret != 0) {
+                       dev_err(dev, "P0 init_60m_fclk set parent failed: %d\n",
+                               ret);
+                       goto err_mem;
+               }
        }
 
        if (is_ehci_phy_mode(pdata->port_mode[1])) {
                ret = clk_set_parent(omap->utmi_p2_gfclk,
                                        omap->xclk60mhsp2_ck);
-               if (ret != 0)
-                       dev_dbg(dev, "xclk60mhsp2_ck set parent failed: %d\n",
-                                       ret);
+               if (ret != 0) {
+                       dev_err(dev, "xclk60mhsp2_ck set parent failed: %d\n",
+                               ret);
+                       goto err_mem;
+               }
        } else if (is_ehci_tll_mode(pdata->port_mode[1])) {
                ret = clk_set_parent(omap->utmi_p2_gfclk,
                                                omap->init_60m_fclk);
-               if (ret != 0)
-                       dev_dbg(dev, "P1 init_60m_fclk set parent failed: %d\n",
-                                       ret);
+               if (ret != 0) {
+                       dev_err(dev, "P1 init_60m_fclk set parent failed: %d\n",
+                               ret);
+                       goto err_mem;
+               }
        }
 
+initialize:
        omap_usbhs_init(dev);
 
        if (dev->of_node) {
@@ -784,7 +824,7 @@ static int usbhs_omap_probe(struct platform_device *pdev)
 
                if (ret) {
                        dev_err(dev, "Failed to create DT children: %d\n", ret);
-                       goto err_alloc;
+                       goto err_mem;
                }
 
        } else {
@@ -792,40 +832,12 @@ static int usbhs_omap_probe(struct platform_device *pdev)
                if (ret) {
                        dev_err(dev, "omap_usbhs_alloc_children failed: %d\n",
                                                ret);
-                       goto err_alloc;
+                       goto err_mem;
                }
        }
 
        return 0;
 
-err_alloc:
-       for (i = 0; i < omap->nports; i++) {
-               if (!IS_ERR(omap->utmi_clk[i]))
-                       clk_put(omap->utmi_clk[i]);
-               if (!IS_ERR(omap->hsic60m_clk[i]))
-                       clk_put(omap->hsic60m_clk[i]);
-               if (!IS_ERR(omap->hsic480m_clk[i]))
-                       clk_put(omap->hsic480m_clk[i]);
-       }
-
-       clk_put(omap->init_60m_fclk);
-
-err_init60m:
-       clk_put(omap->xclk60mhsp2_ck);
-
-err_xclk60mhsp2:
-       clk_put(omap->xclk60mhsp1_ck);
-
-err_xclk60mhsp1:
-       clk_put(omap->utmi_p2_gfclk);
-
-err_p2_gfclk:
-       clk_put(omap->utmi_p1_gfclk);
-
-err_p1_gfclk:
-       if (!IS_ERR(omap->ehci_logic_fck))
-               clk_put(omap->ehci_logic_fck);
-
 err_mem:
        pm_runtime_disable(dev);
 
@@ -847,27 +859,6 @@ static int usbhs_omap_remove_child(struct device *dev, void *data)
  */
 static int usbhs_omap_remove(struct platform_device *pdev)
 {
-       struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev);
-       int i;
-
-       for (i = 0; i < omap->nports; i++) {
-               if (!IS_ERR(omap->utmi_clk[i]))
-                       clk_put(omap->utmi_clk[i]);
-               if (!IS_ERR(omap->hsic60m_clk[i]))
-                       clk_put(omap->hsic60m_clk[i]);
-               if (!IS_ERR(omap->hsic480m_clk[i]))
-                       clk_put(omap->hsic480m_clk[i]);
-       }
-
-       clk_put(omap->init_60m_fclk);
-       clk_put(omap->utmi_p1_gfclk);
-       clk_put(omap->utmi_p2_gfclk);
-       clk_put(omap->xclk60mhsp2_ck);
-       clk_put(omap->xclk60mhsp1_ck);
-
-       if (!IS_ERR(omap->ehci_logic_fck))
-               clk_put(omap->ehci_logic_fck);
-
        pm_runtime_disable(&pdev->dev);
 
        /* remove children */
index 5ee50f7..532eaca 100644 (file)
@@ -252,7 +252,7 @@ static int usbtll_omap_probe(struct platform_device *pdev)
                break;
        }
 
-       tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk * [tll->nch]),
+       tll->ch_clk = devm_kzalloc(dev, sizeof(struct clk *) * tll->nch,
                                                GFP_KERNEL);
        if (!tll->ch_clk) {
                ret = -ENOMEM;
index b8941a5..c1984b0 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/completion.h>
index 484fe66..b97a971 100644 (file)
 #define pr_fmt(fmt) "%s: " fmt, __func__
 
 #include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/ssbi.h>
+#include <linux/regmap.h>
+#include <linux/of_platform.h>
 #include <linux/mfd/core.h>
-#include <linux/mfd/pm8xxx/pm8921.h>
 #include <linux/mfd/pm8xxx/core.h>
 
+#define        SSBI_REG_ADDR_IRQ_BASE          0x1BB
+
+#define        SSBI_REG_ADDR_IRQ_ROOT          (SSBI_REG_ADDR_IRQ_BASE + 0)
+#define        SSBI_REG_ADDR_IRQ_M_STATUS1     (SSBI_REG_ADDR_IRQ_BASE + 1)
+#define        SSBI_REG_ADDR_IRQ_M_STATUS2     (SSBI_REG_ADDR_IRQ_BASE + 2)
+#define        SSBI_REG_ADDR_IRQ_M_STATUS3     (SSBI_REG_ADDR_IRQ_BASE + 3)
+#define        SSBI_REG_ADDR_IRQ_M_STATUS4     (SSBI_REG_ADDR_IRQ_BASE + 4)
+#define        SSBI_REG_ADDR_IRQ_BLK_SEL       (SSBI_REG_ADDR_IRQ_BASE + 5)
+#define        SSBI_REG_ADDR_IRQ_IT_STATUS     (SSBI_REG_ADDR_IRQ_BASE + 6)
+#define        SSBI_REG_ADDR_IRQ_CONFIG        (SSBI_REG_ADDR_IRQ_BASE + 7)
+#define        SSBI_REG_ADDR_IRQ_RT_STATUS     (SSBI_REG_ADDR_IRQ_BASE + 8)
+
+#define        PM_IRQF_LVL_SEL                 0x01    /* level select */
+#define        PM_IRQF_MASK_FE                 0x02    /* mask falling edge */
+#define        PM_IRQF_MASK_RE                 0x04    /* mask rising edge */
+#define        PM_IRQF_CLR                     0x08    /* clear interrupt */
+#define        PM_IRQF_BITS_MASK               0x70
+#define        PM_IRQF_BITS_SHIFT              4
+#define        PM_IRQF_WRITE                   0x80
+
+#define        PM_IRQF_MASK_ALL                (PM_IRQF_MASK_FE | \
+                                       PM_IRQF_MASK_RE)
+
 #define REG_HWREV              0x002  /* PMIC4 revision */
 #define REG_HWREV_2            0x0E8  /* PMIC4 revision 2 */
 
+#define PM8921_NR_IRQS         256
+
+struct pm_irq_chip {
+       struct device           *dev;
+       struct regmap           *regmap;
+       spinlock_t              pm_irq_lock;
+       struct irq_domain       *irqdomain;
+       unsigned int            num_irqs;
+       unsigned int            num_blocks;
+       unsigned int            num_masters;
+       u8                      config[0];
+};
+
 struct pm8921 {
        struct device                   *dev;
        struct pm_irq_chip              *irq_chip;
 };
 
+static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, unsigned int bp,
+                                unsigned int *ip)
+{
+       int     rc;
+
+       spin_lock(&chip->pm_irq_lock);
+       rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+       if (rc) {
+               pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
+               goto bail;
+       }
+
+       rc = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
+       if (rc)
+               pr_err("Failed Reading Status rc=%d\n", rc);
+bail:
+       spin_unlock(&chip->pm_irq_lock);
+       return rc;
+}
+
+static int
+pm8xxx_config_irq(struct pm_irq_chip *chip, unsigned int bp, unsigned int cp)
+{
+       int     rc;
+
+       spin_lock(&chip->pm_irq_lock);
+       rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
+       if (rc) {
+               pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
+               goto bail;
+       }
+
+       cp |= PM_IRQF_WRITE;
+       rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_CONFIG, cp);
+       if (rc)
+               pr_err("Failed Configuring IRQ rc=%d\n", rc);
+bail:
+       spin_unlock(&chip->pm_irq_lock);
+       return rc;
+}
+
+static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
+{
+       int pmirq, irq, i, ret = 0;
+       unsigned int bits;
+
+       ret = pm8xxx_read_block_irq(chip, block, &bits);
+       if (ret) {
+               pr_err("Failed reading %d block ret=%d", block, ret);
+               return ret;
+       }
+       if (!bits) {
+               pr_err("block bit set in master but no irqs: %d", block);
+               return 0;
+       }
+
+       /* Check IRQ bits */
+       for (i = 0; i < 8; i++) {
+               if (bits & (1 << i)) {
+                       pmirq = block * 8 + i;
+                       irq = irq_find_mapping(chip->irqdomain, pmirq);
+                       generic_handle_irq(irq);
+               }
+       }
+       return 0;
+}
+
+static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master)
+{
+       unsigned int blockbits;
+       int block_number, i, ret = 0;
+
+       ret = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_M_STATUS1 + master,
+                         &blockbits);
+       if (ret) {
+               pr_err("Failed to read master %d ret=%d\n", master, ret);
+               return ret;
+       }
+       if (!blockbits) {
+               pr_err("master bit set in root but no blocks: %d", master);
+               return 0;
+       }
+
+       for (i = 0; i < 8; i++)
+               if (blockbits & (1 << i)) {
+                       block_number = master * 8 + i;  /* block # */
+                       ret |= pm8xxx_irq_block_handler(chip, block_number);
+               }
+       return ret;
+}
+
+static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+       struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
+       struct irq_chip *irq_chip = irq_desc_get_chip(desc);
+       unsigned int root;
+       int     i, ret, masters = 0;
+
+       chained_irq_enter(irq_chip, desc);
+
+       ret = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_ROOT, &root);
+       if (ret) {
+               pr_err("Can't read root status ret=%d\n", ret);
+               return;
+       }
+
+       /* on pm8xxx series masters start from bit 1 of the root */
+       masters = root >> 1;
+
+       /* Read allowed masters for blocks. */
+       for (i = 0; i < chip->num_masters; i++)
+               if (masters & (1 << i))
+                       pm8xxx_irq_master_handler(chip, i);
+
+       chained_irq_exit(irq_chip, desc);
+}
+
+static void pm8xxx_irq_mask_ack(struct irq_data *d)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = irqd_to_hwirq(d);
+       int     irq_bit;
+       u8      block, config;
+
+       block = pmirq / 8;
+       irq_bit = pmirq % 8;
+
+       config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
+       pm8xxx_config_irq(chip, block, config);
+}
+
+static void pm8xxx_irq_unmask(struct irq_data *d)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = irqd_to_hwirq(d);
+       int     irq_bit;
+       u8      block, config;
+
+       block = pmirq / 8;
+       irq_bit = pmirq % 8;
+
+       config = chip->config[pmirq];
+       pm8xxx_config_irq(chip, block, config);
+}
+
+static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
+{
+       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
+       unsigned int pmirq = irqd_to_hwirq(d);
+       int irq_bit;
+       u8 block, config;
+
+       block = pmirq / 8;
+       irq_bit  = pmirq % 8;
+
+       chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
+                                                       | PM_IRQF_MASK_ALL;
+       if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
+               if (flow_type & IRQF_TRIGGER_RISING)
+                       chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
+               if (flow_type & IRQF_TRIGGER_FALLING)
+                       chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
+       } else {
+               chip->config[pmirq] |= PM_IRQF_LVL_SEL;
+
+               if (flow_type & IRQF_TRIGGER_HIGH)
+                       chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
+               else
+                       chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
+       }
+
+       config = chip->config[pmirq] | PM_IRQF_CLR;
+       return pm8xxx_config_irq(chip, block, config);
+}
+
+static struct irq_chip pm8xxx_irq_chip = {
+       .name           = "pm8xxx",
+       .irq_mask_ack   = pm8xxx_irq_mask_ack,
+       .irq_unmask     = pm8xxx_irq_unmask,
+       .irq_set_type   = pm8xxx_irq_set_type,
+       .flags          = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
+};
+
+/**
+ * pm8xxx_get_irq_stat - get the status of the irq line
+ * @chip: pointer to identify a pmic irq controller
+ * @irq: the irq number
+ *
+ * The pm8xxx gpio and mpp rely on the interrupt block to read
+ * the values on their pins. This function is to facilitate reading
+ * the status of a gpio or an mpp line. The caller has to convert the
+ * gpio number to irq number.
+ *
+ * RETURNS:
+ * an int indicating the value read on that line
+ */
+static int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
+{
+       int pmirq, rc;
+       unsigned int  block, bits, bit;
+       unsigned long flags;
+       struct irq_data *irq_data = irq_get_irq_data(irq);
+
+       pmirq = irq_data->hwirq;
+
+       block = pmirq / 8;
+       bit = pmirq % 8;
+
+       spin_lock_irqsave(&chip->pm_irq_lock, flags);
+
+       rc = regmap_write(chip->regmap, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
+       if (rc) {
+               pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
+                       irq, pmirq, block, rc);
+               goto bail_out;
+       }
+
+       rc = regmap_read(chip->regmap, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
+       if (rc) {
+               pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
+                       irq, pmirq, block, rc);
+               goto bail_out;
+       }
+
+       rc = (bits & (1 << bit)) ? 1 : 0;
+
+bail_out:
+       spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
+
+       return rc;
+}
+
+static int pm8xxx_irq_domain_map(struct irq_domain *d, unsigned int irq,
+                                  irq_hw_number_t hwirq)
+{
+       struct pm_irq_chip *chip = d->host_data;
+
+       irq_set_chip_and_handler(irq, &pm8xxx_irq_chip, handle_level_irq);
+       irq_set_chip_data(irq, chip);
+#ifdef CONFIG_ARM
+       set_irq_flags(irq, IRQF_VALID);
+#else
+       irq_set_noprobe(irq);
+#endif
+       return 0;
+}
+
+static const struct irq_domain_ops pm8xxx_irq_domain_ops = {
+       .xlate = irq_domain_xlate_twocell,
+       .map = pm8xxx_irq_domain_map,
+};
+
 static int pm8921_readb(const struct device *dev, u16 addr, u8 *val)
 {
        const struct pm8xxx_drvdata *pm8921_drvdata = dev_get_drvdata(dev);
@@ -81,42 +374,35 @@ static struct pm8xxx_drvdata pm8921_drvdata = {
        .pmic_read_irq_stat     = pm8921_read_irq_stat,
 };
 
-static int pm8921_add_subdevices(const struct pm8921_platform_data
-                                          *pdata,
-                                          struct pm8921 *pmic,
-                                          u32 rev)
-{
-       int ret = 0, irq_base = 0;
-       struct pm_irq_chip *irq_chip;
-
-       if (pdata->irq_pdata) {
-               pdata->irq_pdata->irq_cdata.nirqs = PM8921_NR_IRQS;
-               pdata->irq_pdata->irq_cdata.rev = rev;
-               irq_base = pdata->irq_pdata->irq_base;
-               irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
+static const struct regmap_config ssbi_regmap_config = {
+       .reg_bits = 16,
+       .val_bits = 8,
+       .max_register = 0x3ff,
+       .fast_io = true,
+       .reg_read = ssbi_reg_read,
+       .reg_write = ssbi_reg_write
+};
 
-               if (IS_ERR(irq_chip)) {
-                       pr_err("Failed to init interrupts ret=%ld\n",
-                                       PTR_ERR(irq_chip));
-                       return PTR_ERR(irq_chip);
-               }
-               pmic->irq_chip = irq_chip;
-       }
-       return ret;
-}
+static const struct of_device_id pm8921_id_table[] = {
+       { .compatible = "qcom,pm8058", },
+       { .compatible = "qcom,pm8921", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, pm8921_id_table);
 
 static int pm8921_probe(struct platform_device *pdev)
 {
-       const struct pm8921_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct pm8921 *pmic;
-       int rc;
-       u8 val;
+       struct regmap *regmap;
+       int irq, rc;
+       unsigned int val;
        u32 rev;
+       struct pm_irq_chip *chip;
+       unsigned int nirqs = PM8921_NR_IRQS;
 
-       if (!pdata) {
-               pr_err("missing platform data\n");
-               return -EINVAL;
-       }
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0)
+               return irq;
 
        pmic = devm_kzalloc(&pdev->dev, sizeof(struct pm8921), GFP_KERNEL);
        if (!pmic) {
@@ -124,8 +410,13 @@ static int pm8921_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       regmap = devm_regmap_init(&pdev->dev, NULL, pdev->dev.parent,
+                                 &ssbi_regmap_config);
+       if (IS_ERR(regmap))
+               return PTR_ERR(regmap);
+
        /* Read PMIC chip revision */
-       rc = ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
+       rc = regmap_read(regmap, REG_HWREV, &val);
        if (rc) {
                pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
                return rc;
@@ -134,7 +425,7 @@ static int pm8921_probe(struct platform_device *pdev)
        rev = val;
 
        /* Read PMIC chip revision 2 */
-       rc = ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
+       rc = regmap_read(regmap, REG_HWREV_2, &val);
        if (rc) {
                pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
                        REG_HWREV_2, rc);
@@ -147,37 +438,56 @@ static int pm8921_probe(struct platform_device *pdev)
        pm8921_drvdata.pm_chip_data = pmic;
        platform_set_drvdata(pdev, &pm8921_drvdata);
 
-       rc = pm8921_add_subdevices(pdata, pmic, rev);
+       chip = devm_kzalloc(&pdev->dev, sizeof(*chip) +
+                                       sizeof(chip->config[0]) * nirqs,
+                                       GFP_KERNEL);
+       if (!chip)
+               return -ENOMEM;
+
+       pmic->irq_chip = chip;
+       chip->dev = &pdev->dev;
+       chip->regmap = regmap;
+       chip->num_irqs = nirqs;
+       chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
+       chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
+       spin_lock_init(&chip->pm_irq_lock);
+
+       chip->irqdomain = irq_domain_add_linear(pdev->dev.of_node, nirqs,
+                                               &pm8xxx_irq_domain_ops,
+                                               chip);
+       if (!chip->irqdomain)
+               return -ENODEV;
+
+       irq_set_handler_data(irq, chip);
+       irq_set_chained_handler(irq, pm8xxx_irq_handler);
+       irq_set_irq_wake(irq, 1);
+
+       rc = of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
        if (rc) {
-               pr_err("Cannot add subdevices rc=%d\n", rc);
-               goto err;
+               irq_set_chained_handler(irq, NULL);
+               irq_set_handler_data(irq, NULL);
+               irq_domain_remove(chip->irqdomain);
        }
 
-       /* gpio might not work if no irq device is found */
-       WARN_ON(pmic->irq_chip == NULL);
+       return rc;
+}
 
+static int pm8921_remove_child(struct device *dev, void *unused)
+{
+       platform_device_unregister(to_platform_device(dev));
        return 0;
-
-err:
-       mfd_remove_devices(pmic->dev);
-       return rc;
 }
 
 static int pm8921_remove(struct platform_device *pdev)
 {
-       struct pm8xxx_drvdata *drvdata;
-       struct pm8921 *pmic = NULL;
-
-       drvdata = platform_get_drvdata(pdev);
-       if (drvdata)
-               pmic = drvdata->pm_chip_data;
-       if (pmic) {
-               mfd_remove_devices(pmic->dev);
-               if (pmic->irq_chip) {
-                       pm8xxx_irq_exit(pmic->irq_chip);
-                       pmic->irq_chip = NULL;
-               }
-       }
+       int irq = platform_get_irq(pdev, 0);
+       struct pm8921 *pmic = pm8921_drvdata.pm_chip_data;
+       struct pm_irq_chip *chip = pmic->irq_chip;
+
+       device_for_each_child(&pdev->dev, NULL, pm8921_remove_child);
+       irq_set_chained_handler(irq, NULL);
+       irq_set_handler_data(irq, NULL);
+       irq_domain_remove(chip->irqdomain);
 
        return 0;
 }
@@ -188,6 +498,7 @@ static struct platform_driver pm8921_driver = {
        .driver         = {
                .name   = "pm8921-core",
                .owner  = THIS_MODULE,
+               .of_match_table = pm8921_id_table,
        },
 };
 
diff --git a/drivers/mfd/pm8xxx-irq.c b/drivers/mfd/pm8xxx-irq.c
deleted file mode 100644 (file)
index 1360e20..0000000
+++ /dev/null
@@ -1,371 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-
-#define pr_fmt(fmt)    "%s: " fmt, __func__
-
-#include <linux/err.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/mfd/pm8xxx/core.h>
-#include <linux/mfd/pm8xxx/irq.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-
-/* PMIC8xxx IRQ */
-
-#define        SSBI_REG_ADDR_IRQ_BASE          0x1BB
-
-#define        SSBI_REG_ADDR_IRQ_ROOT          (SSBI_REG_ADDR_IRQ_BASE + 0)
-#define        SSBI_REG_ADDR_IRQ_M_STATUS1     (SSBI_REG_ADDR_IRQ_BASE + 1)
-#define        SSBI_REG_ADDR_IRQ_M_STATUS2     (SSBI_REG_ADDR_IRQ_BASE + 2)
-#define        SSBI_REG_ADDR_IRQ_M_STATUS3     (SSBI_REG_ADDR_IRQ_BASE + 3)
-#define        SSBI_REG_ADDR_IRQ_M_STATUS4     (SSBI_REG_ADDR_IRQ_BASE + 4)
-#define        SSBI_REG_ADDR_IRQ_BLK_SEL       (SSBI_REG_ADDR_IRQ_BASE + 5)
-#define        SSBI_REG_ADDR_IRQ_IT_STATUS     (SSBI_REG_ADDR_IRQ_BASE + 6)
-#define        SSBI_REG_ADDR_IRQ_CONFIG        (SSBI_REG_ADDR_IRQ_BASE + 7)
-#define        SSBI_REG_ADDR_IRQ_RT_STATUS     (SSBI_REG_ADDR_IRQ_BASE + 8)
-
-#define        PM_IRQF_LVL_SEL                 0x01    /* level select */
-#define        PM_IRQF_MASK_FE                 0x02    /* mask falling edge */
-#define        PM_IRQF_MASK_RE                 0x04    /* mask rising edge */
-#define        PM_IRQF_CLR                     0x08    /* clear interrupt */
-#define        PM_IRQF_BITS_MASK               0x70
-#define        PM_IRQF_BITS_SHIFT              4
-#define        PM_IRQF_WRITE                   0x80
-
-#define        PM_IRQF_MASK_ALL                (PM_IRQF_MASK_FE | \
-                                       PM_IRQF_MASK_RE)
-
-struct pm_irq_chip {
-       struct device           *dev;
-       spinlock_t              pm_irq_lock;
-       unsigned int            devirq;
-       unsigned int            irq_base;
-       unsigned int            num_irqs;
-       unsigned int            num_blocks;
-       unsigned int            num_masters;
-       u8                      config[0];
-};
-
-static int pm8xxx_read_root_irq(const struct pm_irq_chip *chip, u8 *rp)
-{
-       return pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_ROOT, rp);
-}
-
-static int pm8xxx_read_master_irq(const struct pm_irq_chip *chip, u8 m, u8 *bp)
-{
-       return pm8xxx_readb(chip->dev,
-                       SSBI_REG_ADDR_IRQ_M_STATUS1 + m, bp);
-}
-
-static int pm8xxx_read_block_irq(struct pm_irq_chip *chip, u8 bp, u8 *ip)
-{
-       int     rc;
-
-       spin_lock(&chip->pm_irq_lock);
-       rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
-       if (rc) {
-               pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
-               goto bail;
-       }
-
-       rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_IT_STATUS, ip);
-       if (rc)
-               pr_err("Failed Reading Status rc=%d\n", rc);
-bail:
-       spin_unlock(&chip->pm_irq_lock);
-       return rc;
-}
-
-static int pm8xxx_config_irq(struct pm_irq_chip *chip, u8 bp, u8 cp)
-{
-       int     rc;
-
-       spin_lock(&chip->pm_irq_lock);
-       rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, bp);
-       if (rc) {
-               pr_err("Failed Selecting Block %d rc=%d\n", bp, rc);
-               goto bail;
-       }
-
-       cp |= PM_IRQF_WRITE;
-       rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_CONFIG, cp);
-       if (rc)
-               pr_err("Failed Configuring IRQ rc=%d\n", rc);
-bail:
-       spin_unlock(&chip->pm_irq_lock);
-       return rc;
-}
-
-static int pm8xxx_irq_block_handler(struct pm_irq_chip *chip, int block)
-{
-       int pmirq, irq, i, ret = 0;
-       u8 bits;
-
-       ret = pm8xxx_read_block_irq(chip, block, &bits);
-       if (ret) {
-               pr_err("Failed reading %d block ret=%d", block, ret);
-               return ret;
-       }
-       if (!bits) {
-               pr_err("block bit set in master but no irqs: %d", block);
-               return 0;
-       }
-
-       /* Check IRQ bits */
-       for (i = 0; i < 8; i++) {
-               if (bits & (1 << i)) {
-                       pmirq = block * 8 + i;
-                       irq = pmirq + chip->irq_base;
-                       generic_handle_irq(irq);
-               }
-       }
-       return 0;
-}
-
-static int pm8xxx_irq_master_handler(struct pm_irq_chip *chip, int master)
-{
-       u8 blockbits;
-       int block_number, i, ret = 0;
-
-       ret = pm8xxx_read_master_irq(chip, master, &blockbits);
-       if (ret) {
-               pr_err("Failed to read master %d ret=%d\n", master, ret);
-               return ret;
-       }
-       if (!blockbits) {
-               pr_err("master bit set in root but no blocks: %d", master);
-               return 0;
-       }
-
-       for (i = 0; i < 8; i++)
-               if (blockbits & (1 << i)) {
-                       block_number = master * 8 + i;  /* block # */
-                       ret |= pm8xxx_irq_block_handler(chip, block_number);
-               }
-       return ret;
-}
-
-static void pm8xxx_irq_handler(unsigned int irq, struct irq_desc *desc)
-{
-       struct pm_irq_chip *chip = irq_desc_get_handler_data(desc);
-       struct irq_chip *irq_chip = irq_desc_get_chip(desc);
-       u8      root;
-       int     i, ret, masters = 0;
-
-       ret = pm8xxx_read_root_irq(chip, &root);
-       if (ret) {
-               pr_err("Can't read root status ret=%d\n", ret);
-               return;
-       }
-
-       /* on pm8xxx series masters start from bit 1 of the root */
-       masters = root >> 1;
-
-       /* Read allowed masters for blocks. */
-       for (i = 0; i < chip->num_masters; i++)
-               if (masters & (1 << i))
-                       pm8xxx_irq_master_handler(chip, i);
-
-       irq_chip->irq_ack(&desc->irq_data);
-}
-
-static void pm8xxx_irq_mask_ack(struct irq_data *d)
-{
-       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
-       unsigned int pmirq = d->irq - chip->irq_base;
-       int     master, irq_bit;
-       u8      block, config;
-
-       block = pmirq / 8;
-       master = block / 8;
-       irq_bit = pmirq % 8;
-
-       config = chip->config[pmirq] | PM_IRQF_MASK_ALL | PM_IRQF_CLR;
-       pm8xxx_config_irq(chip, block, config);
-}
-
-static void pm8xxx_irq_unmask(struct irq_data *d)
-{
-       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
-       unsigned int pmirq = d->irq - chip->irq_base;
-       int     master, irq_bit;
-       u8      block, config;
-
-       block = pmirq / 8;
-       master = block / 8;
-       irq_bit = pmirq % 8;
-
-       config = chip->config[pmirq];
-       pm8xxx_config_irq(chip, block, config);
-}
-
-static int pm8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
-{
-       struct pm_irq_chip *chip = irq_data_get_irq_chip_data(d);
-       unsigned int pmirq = d->irq - chip->irq_base;
-       int master, irq_bit;
-       u8 block, config;
-
-       block = pmirq / 8;
-       master = block / 8;
-       irq_bit  = pmirq % 8;
-
-       chip->config[pmirq] = (irq_bit << PM_IRQF_BITS_SHIFT)
-                                                       | PM_IRQF_MASK_ALL;
-       if (flow_type & (IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING)) {
-               if (flow_type & IRQF_TRIGGER_RISING)
-                       chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
-               if (flow_type & IRQF_TRIGGER_FALLING)
-                       chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
-       } else {
-               chip->config[pmirq] |= PM_IRQF_LVL_SEL;
-
-               if (flow_type & IRQF_TRIGGER_HIGH)
-                       chip->config[pmirq] &= ~PM_IRQF_MASK_RE;
-               else
-                       chip->config[pmirq] &= ~PM_IRQF_MASK_FE;
-       }
-
-       config = chip->config[pmirq] | PM_IRQF_CLR;
-       return pm8xxx_config_irq(chip, block, config);
-}
-
-static int pm8xxx_irq_set_wake(struct irq_data *d, unsigned int on)
-{
-       return 0;
-}
-
-static struct irq_chip pm8xxx_irq_chip = {
-       .name           = "pm8xxx",
-       .irq_mask_ack   = pm8xxx_irq_mask_ack,
-       .irq_unmask     = pm8xxx_irq_unmask,
-       .irq_set_type   = pm8xxx_irq_set_type,
-       .irq_set_wake   = pm8xxx_irq_set_wake,
-       .flags          = IRQCHIP_MASK_ON_SUSPEND,
-};
-
-/**
- * pm8xxx_get_irq_stat - get the status of the irq line
- * @chip: pointer to identify a pmic irq controller
- * @irq: the irq number
- *
- * The pm8xxx gpio and mpp rely on the interrupt block to read
- * the values on their pins. This function is to facilitate reading
- * the status of a gpio or an mpp line. The caller has to convert the
- * gpio number to irq number.
- *
- * RETURNS:
- * an int indicating the value read on that line
- */
-int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
-{
-       int pmirq, rc;
-       u8  block, bits, bit;
-       unsigned long flags;
-
-       if (chip == NULL || irq < chip->irq_base ||
-                       irq >= chip->irq_base + chip->num_irqs)
-               return -EINVAL;
-
-       pmirq = irq - chip->irq_base;
-
-       block = pmirq / 8;
-       bit = pmirq % 8;
-
-       spin_lock_irqsave(&chip->pm_irq_lock, flags);
-
-       rc = pm8xxx_writeb(chip->dev, SSBI_REG_ADDR_IRQ_BLK_SEL, block);
-       if (rc) {
-               pr_err("Failed Selecting block irq=%d pmirq=%d blk=%d rc=%d\n",
-                       irq, pmirq, block, rc);
-               goto bail_out;
-       }
-
-       rc = pm8xxx_readb(chip->dev, SSBI_REG_ADDR_IRQ_RT_STATUS, &bits);
-       if (rc) {
-               pr_err("Failed Configuring irq=%d pmirq=%d blk=%d rc=%d\n",
-                       irq, pmirq, block, rc);
-               goto bail_out;
-       }
-
-       rc = (bits & (1 << bit)) ? 1 : 0;
-
-bail_out:
-       spin_unlock_irqrestore(&chip->pm_irq_lock, flags);
-
-       return rc;
-}
-EXPORT_SYMBOL_GPL(pm8xxx_get_irq_stat);
-
-struct pm_irq_chip *  pm8xxx_irq_init(struct device *dev,
-                               const struct pm8xxx_irq_platform_data *pdata)
-{
-       struct pm_irq_chip  *chip;
-       int devirq, rc;
-       unsigned int pmirq;
-
-       if (!pdata) {
-               pr_err("No platform data\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       devirq = pdata->devirq;
-       if (devirq < 0) {
-               pr_err("missing devirq\n");
-               rc = devirq;
-               return ERR_PTR(-EINVAL);
-       }
-
-       chip = kzalloc(sizeof(struct pm_irq_chip)
-                       + sizeof(u8) * pdata->irq_cdata.nirqs, GFP_KERNEL);
-       if (!chip) {
-               pr_err("Cannot alloc pm_irq_chip struct\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       chip->dev = dev;
-       chip->devirq = devirq;
-       chip->irq_base = pdata->irq_base;
-       chip->num_irqs = pdata->irq_cdata.nirqs;
-       chip->num_blocks = DIV_ROUND_UP(chip->num_irqs, 8);
-       chip->num_masters = DIV_ROUND_UP(chip->num_blocks, 8);
-       spin_lock_init(&chip->pm_irq_lock);
-
-       for (pmirq = 0; pmirq < chip->num_irqs; pmirq++) {
-               irq_set_chip_and_handler(chip->irq_base + pmirq,
-                               &pm8xxx_irq_chip,
-                               handle_level_irq);
-               irq_set_chip_data(chip->irq_base + pmirq, chip);
-#ifdef CONFIG_ARM
-               set_irq_flags(chip->irq_base + pmirq, IRQF_VALID);
-#else
-               irq_set_noprobe(chip->irq_base + pmirq);
-#endif
-       }
-
-       irq_set_irq_type(devirq, pdata->irq_trigger_flag);
-       irq_set_handler_data(devirq, chip);
-       irq_set_chained_handler(devirq, pm8xxx_irq_handler);
-       set_irq_wake(devirq, 1);
-
-       return chip;
-}
-
-int pm8xxx_irq_exit(struct pm_irq_chip *chip)
-{
-       irq_set_chained_handler(chip->devirq, NULL);
-       kfree(chip);
-       return 0;
-}
index b41db59..bb85020 100644 (file)
@@ -22,7 +22,6 @@
  */
 #include <linux/interrupt.h>
 #include <linux/irq.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/mfd/rc5t583.h>
 
index d346146..c795697 100644 (file)
@@ -19,7 +19,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
index c8f345f..663f8a3 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/err.h>
 #include <linux/i2c.h>
 #include <linux/irq.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
index 1d15735..c9de3d5 100644 (file)
@@ -338,58 +338,28 @@ int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
                int num_sg, bool read, int timeout)
 {
        struct completion trans_done;
-       u8 dir;
-       int err = 0, i, count;
+       int err = 0, count;
        long timeleft;
        unsigned long flags;
-       struct scatterlist *sg;
-       enum dma_data_direction dma_dir;
-       u32 val;
-       dma_addr_t addr;
-       unsigned int len;
-
-       dev_dbg(&(pcr->pci->dev), "--> %s: num_sg = %d\n", __func__, num_sg);
-
-       /* don't transfer data during abort processing */
-       if (pcr->remove_pci)
-               return -EINVAL;
-
-       if ((sglist == NULL) || (num_sg <= 0))
-               return -EINVAL;
 
-       if (read) {
-               dir = DEVICE_TO_HOST;
-               dma_dir = DMA_FROM_DEVICE;
-       } else {
-               dir = HOST_TO_DEVICE;
-               dma_dir = DMA_TO_DEVICE;
-       }
-
-       count = dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
+       count = rtsx_pci_dma_map_sg(pcr, sglist, num_sg, read);
        if (count < 1) {
                dev_err(&(pcr->pci->dev), "scatterlist map failed\n");
                return -EINVAL;
        }
        dev_dbg(&(pcr->pci->dev), "DMA mapping count: %d\n", count);
 
-       val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
-       pcr->sgi = 0;
-       for_each_sg(sglist, sg, count, i) {
-               addr = sg_dma_address(sg);
-               len = sg_dma_len(sg);
-               rtsx_pci_add_sg_tbl(pcr, addr, len, i == count - 1);
-       }
 
        spin_lock_irqsave(&pcr->lock, flags);
 
        pcr->done = &trans_done;
        pcr->trans_result = TRANS_NOT_READY;
        init_completion(&trans_done);
-       rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
-       rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
 
        spin_unlock_irqrestore(&pcr->lock, flags);
 
+       rtsx_pci_dma_transfer(pcr, sglist, count, read);
+
        timeleft = wait_for_completion_interruptible_timeout(
                        &trans_done, msecs_to_jiffies(timeout));
        if (timeleft <= 0) {
@@ -413,7 +383,7 @@ out:
        pcr->done = NULL;
        spin_unlock_irqrestore(&pcr->lock, flags);
 
-       dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dma_dir);
+       rtsx_pci_dma_unmap_sg(pcr, sglist, num_sg, read);
 
        if ((err < 0) && (err != -ENODEV))
                rtsx_pci_stop_cmd(pcr);
@@ -425,6 +395,73 @@ out:
 }
 EXPORT_SYMBOL_GPL(rtsx_pci_transfer_data);
 
+int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int num_sg, bool read)
+{
+       enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+       if (pcr->remove_pci)
+               return -EINVAL;
+
+       if ((sglist == NULL) || num_sg < 1)
+               return -EINVAL;
+
+       return dma_map_sg(&(pcr->pci->dev), sglist, num_sg, dir);
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_dma_map_sg);
+
+int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int num_sg, bool read)
+{
+       enum dma_data_direction dir = read ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+
+       if (pcr->remove_pci)
+               return -EINVAL;
+
+       if (sglist == NULL || num_sg < 1)
+               return -EINVAL;
+
+       dma_unmap_sg(&(pcr->pci->dev), sglist, num_sg, dir);
+       return num_sg;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_dma_unmap_sg);
+
+int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int sg_count, bool read)
+{
+       struct scatterlist *sg;
+       dma_addr_t addr;
+       unsigned int len;
+       int i;
+       u32 val;
+       u8 dir = read ? DEVICE_TO_HOST : HOST_TO_DEVICE;
+       unsigned long flags;
+
+       if (pcr->remove_pci)
+               return -EINVAL;
+
+       if ((sglist == NULL) || (sg_count < 1))
+               return -EINVAL;
+
+       val = ((u32)(dir & 0x01) << 29) | TRIG_DMA | ADMA_MODE;
+       pcr->sgi = 0;
+       for_each_sg(sglist, sg, sg_count, i) {
+               addr = sg_dma_address(sg);
+               len = sg_dma_len(sg);
+               rtsx_pci_add_sg_tbl(pcr, addr, len, i == sg_count - 1);
+       }
+
+       spin_lock_irqsave(&pcr->lock, flags);
+
+       rtsx_pci_writel(pcr, RTSX_HDBAR, pcr->host_sg_tbl_addr);
+       rtsx_pci_writel(pcr, RTSX_HDBCTLR, val);
+
+       spin_unlock_irqrestore(&pcr->lock, flags);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_pci_dma_transfer);
+
 int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len)
 {
        int err;
@@ -836,6 +873,8 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
        int_reg = rtsx_pci_readl(pcr, RTSX_BIPR);
        /* Clear interrupt flag */
        rtsx_pci_writel(pcr, RTSX_BIPR, int_reg);
+       dev_dbg(&pcr->pci->dev, "=========== BIPR 0x%8x ==========\n", int_reg);
+
        if ((int_reg & pcr->bier) == 0) {
                spin_unlock(&pcr->lock);
                return IRQ_NONE;
@@ -866,17 +905,28 @@ static irqreturn_t rtsx_pci_isr(int irq, void *dev_id)
        }
 
        if (int_reg & (NEED_COMPLETE_INT | DELINK_INT)) {
-               if (int_reg & (TRANS_FAIL_INT | DELINK_INT)) {
+               if (int_reg & (TRANS_FAIL_INT | DELINK_INT))
                        pcr->trans_result = TRANS_RESULT_FAIL;
-                       if (pcr->done)
-                               complete(pcr->done);
-               } else if (int_reg & TRANS_OK_INT) {
+               else if (int_reg & TRANS_OK_INT)
                        pcr->trans_result = TRANS_RESULT_OK;
-                       if (pcr->done)
-                               complete(pcr->done);
+
+               if (pcr->done)
+                       complete(pcr->done);
+
+               if (int_reg & SD_EXIST) {
+                       struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
+                       if (slot && slot->done_transfer)
+                               slot->done_transfer(slot->p_dev);
+               }
+
+               if (int_reg & MS_EXIST) {
+                       struct rtsx_slot *slot = &pcr->slots[RTSX_SD_CARD];
+                       if (slot && slot->done_transfer)
+                               slot->done_transfer(slot->p_dev);
                }
        }
 
+
        if (pcr->card_inserted || pcr->card_removed)
                schedule_delayed_work(&pcr->carddet_work,
                                msecs_to_jiffies(200));
diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c
new file mode 100644 (file)
index 0000000..b53b9d4
--- /dev/null
@@ -0,0 +1,760 @@
+/* Driver for Realtek USB card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Roger Tseng <rogerable@realtek.com>
+ */
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/usb.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rtsx_usb.h>
+
+static int polling_pipe = 1;
+module_param(polling_pipe, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(polling_pipe, "polling pipe (0: ctl, 1: bulk)");
+
+static struct mfd_cell rtsx_usb_cells[] = {
+       [RTSX_USB_SD_CARD] = {
+               .name = "rtsx_usb_sdmmc",
+               .pdata_size = 0,
+       },
+       [RTSX_USB_MS_CARD] = {
+               .name = "rtsx_usb_ms",
+               .pdata_size = 0,
+       },
+};
+
+static void rtsx_usb_sg_timed_out(unsigned long data)
+{
+       struct rtsx_ucr *ucr = (struct rtsx_ucr *)data;
+
+       dev_dbg(&ucr->pusb_intf->dev, "%s: sg transfer timed out", __func__);
+       usb_sg_cancel(&ucr->current_sg);
+
+       /* we know the cancellation is caused by time-out */
+       ucr->current_sg.status = -ETIMEDOUT;
+}
+
+static int rtsx_usb_bulk_transfer_sglist(struct rtsx_ucr *ucr,
+               unsigned int pipe, struct scatterlist *sg, int num_sg,
+               unsigned int length, unsigned int *act_len, int timeout)
+{
+       int ret;
+
+       dev_dbg(&ucr->pusb_intf->dev, "%s: xfer %u bytes, %d entries\n",
+                       __func__, length, num_sg);
+       ret = usb_sg_init(&ucr->current_sg, ucr->pusb_dev, pipe, 0,
+                       sg, num_sg, length, GFP_NOIO);
+       if (ret)
+               return ret;
+
+       ucr->sg_timer.expires = jiffies + msecs_to_jiffies(timeout);
+       add_timer(&ucr->sg_timer);
+       usb_sg_wait(&ucr->current_sg);
+       del_timer(&ucr->sg_timer);
+
+       if (act_len)
+               *act_len = ucr->current_sg.bytes;
+
+       return ucr->current_sg.status;
+}
+
+int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
+                             void *buf, unsigned int len, int num_sg,
+                             unsigned int *act_len, int timeout)
+{
+       if (timeout < 600)
+               timeout = 600;
+
+       if (num_sg)
+               return rtsx_usb_bulk_transfer_sglist(ucr, pipe,
+                               (struct scatterlist *)buf, num_sg, len, act_len,
+                               timeout);
+       else
+               return usb_bulk_msg(ucr->pusb_dev, pipe, buf, len, act_len,
+                               timeout);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_transfer_data);
+
+static inline void rtsx_usb_seq_cmd_hdr(struct rtsx_ucr *ucr,
+               u16 addr, u16 len, u8 seq_type)
+{
+       rtsx_usb_cmd_hdr_tag(ucr);
+
+       ucr->cmd_buf[PACKET_TYPE] = seq_type;
+       ucr->cmd_buf[5] = (u8)(len >> 8);
+       ucr->cmd_buf[6] = (u8)len;
+       ucr->cmd_buf[8] = (u8)(addr >> 8);
+       ucr->cmd_buf[9] = (u8)addr;
+
+       if (seq_type == SEQ_WRITE)
+               ucr->cmd_buf[STAGE_FLAG] = 0;
+       else
+               ucr->cmd_buf[STAGE_FLAG] = STAGE_R;
+}
+
+static int rtsx_usb_seq_write_register(struct rtsx_ucr *ucr,
+               u16 addr, u16 len, u8 *data)
+{
+       u16 cmd_len = ALIGN(SEQ_WRITE_DATA_OFFSET + len, 4);
+
+       if (!data)
+               return -EINVAL;
+
+       if (cmd_len > IOBUF_SIZE)
+               return -EINVAL;
+
+       rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_WRITE);
+       memcpy(ucr->cmd_buf + SEQ_WRITE_DATA_OFFSET, data, len);
+
+       return rtsx_usb_transfer_data(ucr,
+                       usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
+                       ucr->cmd_buf, cmd_len, 0, NULL, 100);
+}
+
+static int rtsx_usb_seq_read_register(struct rtsx_ucr *ucr,
+               u16 addr, u16 len, u8 *data)
+{
+       int i, ret;
+       u16 rsp_len = round_down(len, 4);
+       u16 res_len = len - rsp_len;
+
+       if (!data)
+               return -EINVAL;
+
+       /* 4-byte aligned part */
+       if (rsp_len) {
+               rtsx_usb_seq_cmd_hdr(ucr, addr, len, SEQ_READ);
+               ret = rtsx_usb_transfer_data(ucr,
+                               usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
+                               ucr->cmd_buf, 12, 0, NULL, 100);
+               if (ret)
+                       return ret;
+
+               ret = rtsx_usb_transfer_data(ucr,
+                               usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN),
+                               data, rsp_len, 0, NULL, 100);
+               if (ret)
+                       return ret;
+       }
+
+       /* unaligned part */
+       for (i = 0; i < res_len; i++) {
+               ret = rtsx_usb_read_register(ucr, addr + rsp_len + i,
+                               data + rsp_len + i);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int rtsx_usb_read_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len)
+{
+       return rtsx_usb_seq_read_register(ucr, PPBUF_BASE2, (u16)buf_len, buf);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_read_ppbuf);
+
+int rtsx_usb_write_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len)
+{
+       return rtsx_usb_seq_write_register(ucr, PPBUF_BASE2, (u16)buf_len, buf);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_write_ppbuf);
+
+int rtsx_usb_ep0_write_register(struct rtsx_ucr *ucr, u16 addr,
+               u8 mask, u8 data)
+{
+       u16 value, index;
+
+       addr |= EP0_WRITE_REG_CMD << EP0_OP_SHIFT;
+       value = swab16(addr);
+       index = mask | data << 8;
+
+       return usb_control_msg(ucr->pusb_dev,
+                       usb_sndctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
+                       USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, index, NULL, 0, 100);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_ep0_write_register);
+
+int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
+{
+       u16 value;
+
+       if (!data)
+               return -EINVAL;
+       *data = 0;
+
+       addr |= EP0_READ_REG_CMD << EP0_OP_SHIFT;
+       value = swab16(addr);
+
+       return usb_control_msg(ucr->pusb_dev,
+                       usb_rcvctrlpipe(ucr->pusb_dev, 0), RTSX_USB_REQ_REG_OP,
+                       USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                       value, 0, data, 1, 100);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_ep0_read_register);
+
+void rtsx_usb_add_cmd(struct rtsx_ucr *ucr, u8 cmd_type, u16 reg_addr,
+               u8 mask, u8 data)
+{
+       int i;
+
+       if (ucr->cmd_idx < (IOBUF_SIZE - CMD_OFFSET) / 4) {
+               i = CMD_OFFSET + ucr->cmd_idx * 4;
+
+               ucr->cmd_buf[i++] = ((cmd_type & 0x03) << 6) |
+                       (u8)((reg_addr >> 8) & 0x3F);
+               ucr->cmd_buf[i++] = (u8)reg_addr;
+               ucr->cmd_buf[i++] = mask;
+               ucr->cmd_buf[i++] = data;
+
+               ucr->cmd_idx++;
+       }
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_add_cmd);
+
+int rtsx_usb_send_cmd(struct rtsx_ucr *ucr, u8 flag, int timeout)
+{
+       int ret;
+
+       ucr->cmd_buf[CNT_H] = (u8)(ucr->cmd_idx >> 8);
+       ucr->cmd_buf[CNT_L] = (u8)(ucr->cmd_idx);
+       ucr->cmd_buf[STAGE_FLAG] = flag;
+
+       ret = rtsx_usb_transfer_data(ucr,
+                       usb_sndbulkpipe(ucr->pusb_dev, EP_BULK_OUT),
+                       ucr->cmd_buf, ucr->cmd_idx * 4 + CMD_OFFSET,
+                       0, NULL, timeout);
+       if (ret) {
+               rtsx_usb_clear_fsm_err(ucr);
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_send_cmd);
+
+int rtsx_usb_get_rsp(struct rtsx_ucr *ucr, int rsp_len, int timeout)
+{
+       if (rsp_len <= 0)
+               return -EINVAL;
+
+       rsp_len = ALIGN(rsp_len, 4);
+
+       return rtsx_usb_transfer_data(ucr,
+                       usb_rcvbulkpipe(ucr->pusb_dev, EP_BULK_IN),
+                       ucr->rsp_buf, rsp_len, 0, NULL, timeout);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_get_rsp);
+
+static int rtsx_usb_get_status_with_bulk(struct rtsx_ucr *ucr, u16 *status)
+{
+       int ret;
+
+       rtsx_usb_init_cmd(ucr);
+       rtsx_usb_add_cmd(ucr, READ_REG_CMD, CARD_EXIST, 0x00, 0x00);
+       rtsx_usb_add_cmd(ucr, READ_REG_CMD, OCPSTAT, 0x00, 0x00);
+       ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
+       if (ret)
+               return ret;
+
+       ret = rtsx_usb_get_rsp(ucr, 2, 100);
+       if (ret)
+               return ret;
+
+       *status = ((ucr->rsp_buf[0] >> 2) & 0x0f) |
+                 ((ucr->rsp_buf[1] & 0x03) << 4);
+
+       return 0;
+}
+
+int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status)
+{
+       int ret;
+
+       if (!status)
+               return -EINVAL;
+
+       if (polling_pipe == 0)
+               ret = usb_control_msg(ucr->pusb_dev,
+                               usb_rcvctrlpipe(ucr->pusb_dev, 0),
+                               RTSX_USB_REQ_POLL,
+                               USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+                               0, 0, status, 2, 100);
+       else
+               ret = rtsx_usb_get_status_with_bulk(ucr, status);
+
+       /* usb_control_msg may return positive when success */
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_get_card_status);
+
+static int rtsx_usb_write_phy_register(struct rtsx_ucr *ucr, u8 addr, u8 val)
+{
+       dev_dbg(&ucr->pusb_intf->dev, "Write 0x%x to phy register 0x%x\n",
+                       val, addr);
+
+       rtsx_usb_init_cmd(ucr);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VSTAIN, 0xFF, val);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL, 0xFF, addr & 0x0F);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VCONTROL,
+                       0xFF, (addr >> 4) & 0x0F);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x00);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, HS_VLOADM, 0xFF, 0x01);
+
+       return rtsx_usb_send_cmd(ucr, MODE_C, 100);
+}
+
+int rtsx_usb_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask, u8 data)
+{
+       rtsx_usb_init_cmd(ucr);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, addr, mask, data);
+       return rtsx_usb_send_cmd(ucr, MODE_C, 100);
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_write_register);
+
+int rtsx_usb_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data)
+{
+       int ret;
+
+       if (data != NULL)
+               *data = 0;
+
+       rtsx_usb_init_cmd(ucr);
+       rtsx_usb_add_cmd(ucr, READ_REG_CMD, addr, 0, 0);
+       ret = rtsx_usb_send_cmd(ucr, MODE_CR, 100);
+       if (ret)
+               return ret;
+
+       ret = rtsx_usb_get_rsp(ucr, 1, 100);
+       if (ret)
+               return ret;
+
+       if (data != NULL)
+               *data = ucr->rsp_buf[0];
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_read_register);
+
+static inline u8 double_ssc_depth(u8 depth)
+{
+       return (depth > 1) ? (depth - 1) : depth;
+}
+
+static u8 revise_ssc_depth(u8 ssc_depth, u8 div)
+{
+       if (div > CLK_DIV_1) {
+               if (ssc_depth > div - 1)
+                       ssc_depth -= (div - 1);
+               else
+                       ssc_depth = SSC_DEPTH_2M;
+       }
+
+       return ssc_depth;
+}
+
+int rtsx_usb_switch_clock(struct rtsx_ucr *ucr, unsigned int card_clock,
+               u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk)
+{
+       int ret;
+       u8 n, clk_divider, mcu_cnt, div;
+
+       if (!card_clock) {
+               ucr->cur_clk = 0;
+               return 0;
+       }
+
+       if (initial_mode) {
+               /* We use 250k(around) here, in initial stage */
+               clk_divider = SD_CLK_DIVIDE_128;
+               card_clock = 30000000;
+       } else {
+               clk_divider = SD_CLK_DIVIDE_0;
+       }
+
+       ret = rtsx_usb_write_register(ucr, SD_CFG1,
+                       SD_CLK_DIVIDE_MASK, clk_divider);
+       if (ret < 0)
+               return ret;
+
+       card_clock /= 1000000;
+       dev_dbg(&ucr->pusb_intf->dev,
+                       "Switch card clock to %dMHz\n", card_clock);
+
+       if (!initial_mode && double_clk)
+               card_clock *= 2;
+       dev_dbg(&ucr->pusb_intf->dev,
+                       "Internal SSC clock: %dMHz (cur_clk = %d)\n",
+                       card_clock, ucr->cur_clk);
+
+       if (card_clock == ucr->cur_clk)
+               return 0;
+
+       /* Converting clock value into internal settings: n and div */
+       n = card_clock - 2;
+       if ((card_clock <= 2) || (n > MAX_DIV_N))
+               return -EINVAL;
+
+       mcu_cnt = 60/card_clock + 3;
+       if (mcu_cnt > 15)
+               mcu_cnt = 15;
+
+       /* Make sure that the SSC clock div_n is not less than MIN_DIV_N */
+
+       div = CLK_DIV_1;
+       while (n < MIN_DIV_N && div < CLK_DIV_4) {
+               n = (n + 2) * 2 - 2;
+               div++;
+       }
+       dev_dbg(&ucr->pusb_intf->dev, "n = %d, div = %d\n", n, div);
+
+       if (double_clk)
+               ssc_depth = double_ssc_depth(ssc_depth);
+
+       ssc_depth = revise_ssc_depth(ssc_depth, div);
+       dev_dbg(&ucr->pusb_intf->dev, "ssc_depth = %d\n", ssc_depth);
+
+       rtsx_usb_init_cmd(ucr);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV, CLK_CHANGE, CLK_CHANGE);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CLK_DIV,
+                       0x3F, (div << 4) | mcu_cnt);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, 0);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL2,
+                       SSC_DEPTH_MASK, ssc_depth);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_DIV_N_0, 0xFF, n);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SSC_CTL1, SSC_RSTB, SSC_RSTB);
+       if (vpclk) {
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+                               PHASE_NOT_RESET, 0);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD_VPCLK0_CTL,
+                               PHASE_NOT_RESET, PHASE_NOT_RESET);
+       }
+
+       ret = rtsx_usb_send_cmd(ucr, MODE_C, 2000);
+       if (ret < 0)
+               return ret;
+
+       ret = rtsx_usb_write_register(ucr, SSC_CTL1, 0xff,
+                       SSC_RSTB | SSC_8X_EN | SSC_SEL_4M);
+       if (ret < 0)
+               return ret;
+
+       /* Wait SSC clock stable */
+       usleep_range(100, 1000);
+
+       ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0);
+       if (ret < 0)
+               return ret;
+
+       ucr->cur_clk = card_clock;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_switch_clock);
+
+int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card)
+{
+       int ret;
+       u16 val;
+       u16 cd_mask[] = {
+               [RTSX_USB_SD_CARD] = (CD_MASK & ~SD_CD),
+               [RTSX_USB_MS_CARD] = (CD_MASK & ~MS_CD)
+       };
+
+       ret = rtsx_usb_get_card_status(ucr, &val);
+       /*
+        * If get status fails, return 0 (ok) for the exclusive check
+        * and let the flow fail at somewhere else.
+        */
+       if (ret)
+               return 0;
+
+       if (val & cd_mask[card])
+               return -EIO;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(rtsx_usb_card_exclusive_check);
+
+static int rtsx_usb_reset_chip(struct rtsx_ucr *ucr)
+{
+       int ret;
+       u8 val;
+
+       rtsx_usb_init_cmd(ucr);
+
+       if (CHECK_PKG(ucr, LQFP48)) {
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
+                               LDO3318_PWR_MASK, LDO_SUSPEND);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PWR_CTL,
+                               FORCE_LDO_POWERB, FORCE_LDO_POWERB);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL1,
+                               0x30, 0x10);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL5,
+                               0x03, 0x01);
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_PULL_CTL6,
+                               0x0C, 0x04);
+       }
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SYS_DUMMY0, NYET_MSAK, NYET_EN);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CD_DEGLITCH_WIDTH, 0xFF, 0x08);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                       CD_DEGLITCH_EN, XD_CD_DEGLITCH_EN, 0x0);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, SD30_DRIVE_SEL,
+                       SD30_DRIVE_MASK, DRIVER_TYPE_D);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                       CARD_DRIVE_SEL, SD20_DRIVE_MASK, 0x0);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, LDO_POWER_CFG, 0xE0, 0x0);
+
+       if (ucr->is_rts5179)
+               rtsx_usb_add_cmd(ucr, WRITE_REG_CMD,
+                               CARD_PULL_CTL5, 0x03, 0x01);
+
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_DMA1_CTL,
+                      EXTEND_DMA1_ASYNC_SIGNAL, EXTEND_DMA1_ASYNC_SIGNAL);
+       rtsx_usb_add_cmd(ucr, WRITE_REG_CMD, CARD_INT_PEND,
+                       XD_INT | MS_INT | SD_INT,
+                       XD_INT | MS_INT | SD_INT);
+
+       ret = rtsx_usb_send_cmd(ucr, MODE_C, 100);
+       if (ret)
+               return ret;
+
+       /* config non-crystal mode */
+       rtsx_usb_read_register(ucr, CFG_MODE, &val);
+       if ((val & XTAL_FREE) || ((val & CLK_MODE_MASK) == CLK_MODE_NON_XTAL)) {
+               ret = rtsx_usb_write_phy_register(ucr, 0xC2, 0x7C);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int rtsx_usb_init_chip(struct rtsx_ucr *ucr)
+{
+       int ret;
+       u8 val;
+
+       rtsx_usb_clear_fsm_err(ucr);
+
+       /* power on SSC */
+       ret = rtsx_usb_write_register(ucr,
+                       FPDCTL, SSC_POWER_MASK, SSC_POWER_ON);
+       if (ret)
+               return ret;
+
+       usleep_range(100, 1000);
+       ret = rtsx_usb_write_register(ucr, CLK_DIV, CLK_CHANGE, 0x00);
+       if (ret)
+               return ret;
+
+       /* determine IC version */
+       ret = rtsx_usb_read_register(ucr, HW_VERSION, &val);
+       if (ret)
+               return ret;
+
+       ucr->ic_version = val & HW_VER_MASK;
+
+       /* determine package */
+       ret = rtsx_usb_read_register(ucr, CARD_SHARE_MODE, &val);
+       if (ret)
+               return ret;
+
+       if (val & CARD_SHARE_LQFP_SEL) {
+               ucr->package = LQFP48;
+               dev_dbg(&ucr->pusb_intf->dev, "Package: LQFP48\n");
+       } else {
+               ucr->package = QFN24;
+               dev_dbg(&ucr->pusb_intf->dev, "Package: QFN24\n");
+       }
+
+       /* determine IC variations */
+       rtsx_usb_read_register(ucr, CFG_MODE_1, &val);
+       if (val & RTS5179) {
+               ucr->is_rts5179 = true;
+               dev_dbg(&ucr->pusb_intf->dev, "Device is rts5179\n");
+       } else {
+               ucr->is_rts5179 = false;
+       }
+
+       return rtsx_usb_reset_chip(ucr);
+}
+
+static int rtsx_usb_probe(struct usb_interface *intf,
+                        const struct usb_device_id *id)
+{
+       struct usb_device *usb_dev = interface_to_usbdev(intf);
+       struct rtsx_ucr *ucr;
+       int ret;
+
+       dev_dbg(&intf->dev,
+               ": Realtek USB Card Reader found at bus %03d address %03d\n",
+                usb_dev->bus->busnum, usb_dev->devnum);
+
+       ucr = devm_kzalloc(&intf->dev, sizeof(*ucr), GFP_KERNEL);
+       if (!ucr)
+               return -ENOMEM;
+
+       ucr->pusb_dev = usb_dev;
+
+       ucr->iobuf = usb_alloc_coherent(ucr->pusb_dev, IOBUF_SIZE,
+                       GFP_KERNEL, &ucr->iobuf_dma);
+       if (!ucr->iobuf)
+               return -ENOMEM;
+
+       usb_set_intfdata(intf, ucr);
+
+       ucr->vendor_id = id->idVendor;
+       ucr->product_id = id->idProduct;
+       ucr->cmd_buf = ucr->rsp_buf = ucr->iobuf;
+
+       mutex_init(&ucr->dev_mutex);
+
+       ucr->pusb_intf = intf;
+
+       /* initialize */
+       ret = rtsx_usb_init_chip(ucr);
+       if (ret)
+               goto out_init_fail;
+
+       ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells,
+                       ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
+       if (ret)
+               goto out_init_fail;
+
+       /* initialize USB SG transfer timer */
+       init_timer(&ucr->sg_timer);
+       setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
+#ifdef CONFIG_PM
+       intf->needs_remote_wakeup = 1;
+       usb_enable_autosuspend(usb_dev);
+#endif
+
+       return 0;
+
+out_init_fail:
+       usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
+                       ucr->iobuf_dma);
+       return ret;
+}
+
+static void rtsx_usb_disconnect(struct usb_interface *intf)
+{
+       struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
+
+       dev_dbg(&intf->dev, "%s called\n", __func__);
+
+       mfd_remove_devices(&intf->dev);
+
+       usb_set_intfdata(ucr->pusb_intf, NULL);
+       usb_free_coherent(ucr->pusb_dev, IOBUF_SIZE, ucr->iobuf,
+                       ucr->iobuf_dma);
+}
+
+#ifdef CONFIG_PM
+static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       struct rtsx_ucr *ucr =
+               (struct rtsx_ucr *)usb_get_intfdata(intf);
+
+       dev_dbg(&intf->dev, "%s called with pm message 0x%04u\n",
+                       __func__, message.event);
+
+       mutex_lock(&ucr->dev_mutex);
+       rtsx_usb_turn_off_led(ucr);
+       mutex_unlock(&ucr->dev_mutex);
+       return 0;
+}
+
+static int rtsx_usb_resume(struct usb_interface *intf)
+{
+       return 0;
+}
+
+static int rtsx_usb_reset_resume(struct usb_interface *intf)
+{
+       struct rtsx_ucr *ucr =
+               (struct rtsx_ucr *)usb_get_intfdata(intf);
+
+       rtsx_usb_reset_chip(ucr);
+       return 0;
+}
+
+#else /* CONFIG_PM */
+
+#define rtsx_usb_suspend NULL
+#define rtsx_usb_resume NULL
+#define rtsx_usb_reset_resume NULL
+
+#endif /* CONFIG_PM */
+
+
+static int rtsx_usb_pre_reset(struct usb_interface *intf)
+{
+       struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
+
+       mutex_lock(&ucr->dev_mutex);
+       return 0;
+}
+
+static int rtsx_usb_post_reset(struct usb_interface *intf)
+{
+       struct rtsx_ucr *ucr = (struct rtsx_ucr *)usb_get_intfdata(intf);
+
+       mutex_unlock(&ucr->dev_mutex);
+       return 0;
+}
+
+static struct usb_device_id rtsx_usb_usb_ids[] = {
+       { USB_DEVICE(0x0BDA, 0x0129) },
+       { USB_DEVICE(0x0BDA, 0x0139) },
+       { USB_DEVICE(0x0BDA, 0x0140) },
+       { }
+};
+
+static struct usb_driver rtsx_usb_driver = {
+       .name                   = "rtsx_usb",
+       .probe                  = rtsx_usb_probe,
+       .disconnect             = rtsx_usb_disconnect,
+       .suspend                = rtsx_usb_suspend,
+       .resume                 = rtsx_usb_resume,
+       .reset_resume           = rtsx_usb_reset_resume,
+       .pre_reset              = rtsx_usb_pre_reset,
+       .post_reset             = rtsx_usb_post_reset,
+       .id_table               = rtsx_usb_usb_ids,
+       .supports_autosuspend   = 1,
+       .soft_unbind            = 1,
+};
+
+module_usb_driver(rtsx_usb_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Roger Tseng <rogerable@realtek.com>");
+MODULE_DESCRIPTION("Realtek USB Card Reader Driver");
index 281a827..1cf2752 100644 (file)
@@ -60,6 +60,7 @@ static const struct mfd_cell s5m8767_devs[] = {
                .name = "s5m-rtc",
        }, {
                .name = "s5m8767-clk",
+               .of_compatible = "samsung,s5m8767-clk",
        }
 };
 
@@ -68,6 +69,7 @@ static const struct mfd_cell s2mps11_devs[] = {
                .name = "s2mps11-pmic",
        }, {
                .name = "s2mps11-clk",
+               .of_compatible = "samsung,s2mps11-clk",
        }
 };
 
@@ -78,6 +80,7 @@ static const struct mfd_cell s2mps14_devs[] = {
                .name = "s2mps14-rtc",
        }, {
                .name = "s2mps14-clk",
+               .of_compatible = "samsung,s2mps14-clk",
        }
 };
 
@@ -295,6 +298,13 @@ static int sec_pmic_probe(struct i2c_client *i2c,
        switch (sec_pmic->device_type) {
        case S2MPA01:
                regmap = &s2mpa01_regmap_config;
+               /*
+                * The rtc-s5m driver does not support S2MPA01 and there
+                * is no mfd_cell for S2MPA01 RTC device.
+                * However we must pass something to devm_regmap_init_i2c()
+                * so use S5M-like regmap config even though it wouldn't work.
+                */
+               regmap_rtc = &s5m_rtc_regmap_config;
                break;
        case S2MPS11X:
                regmap = &s2mps11_regmap_config;
@@ -344,7 +354,7 @@ static int sec_pmic_probe(struct i2c_client *i2c,
                ret = PTR_ERR(sec_pmic->regmap_rtc);
                dev_err(&i2c->dev, "Failed to allocate RTC register map: %d\n",
                        ret);
-               return ret;
+               goto err_regmap_rtc;
        }
 
        if (pdata && pdata->cfg_pmic_irq)
@@ -385,14 +395,15 @@ static int sec_pmic_probe(struct i2c_client *i2c,
        }
 
        if (ret)
-               goto err;
+               goto err_mfd;
 
        device_init_wakeup(sec_pmic->dev, sec_pmic->wakeup);
 
        return ret;
 
-err:
+err_mfd:
        sec_irq_exit(sec_pmic);
+err_regmap_rtc:
        i2c_unregister_device(sec_pmic->rtc);
        return ret;
 }
index 24ae3d8..90112d4 100644 (file)
@@ -13,7 +13,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
index 42ccd05..4a91f67 100644 (file)
@@ -706,7 +706,7 @@ static int stmpe1801_reset(struct stmpe *stmpe)
                if (!(ret & STMPE1801_MSK_SYS_CTRL_RESET))
                        return 0;
                usleep_range(100, 200);
-       };
+       }
        return -EIO;
 }
 
index 1243d5c..7ceb3df 100644 (file)
@@ -167,7 +167,7 @@ static struct mfd_cell stw481x_cells[] = {
        },
 };
 
-const struct regmap_config stw481x_regmap_config = {
+static const struct regmap_config stw481x_regmap_config = {
        .reg_bits = 8,
        .val_bits = 8,
 };
@@ -186,6 +186,12 @@ static int stw481x_probe(struct i2c_client *client,
        i2c_set_clientdata(client, stw481x);
        stw481x->client = client;
        stw481x->map = devm_regmap_init_i2c(client, &stw481x_regmap_config);
+       if (IS_ERR(stw481x->map)) {
+               ret = PTR_ERR(stw481x->map);
+               dev_err(&client->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
 
        ret = stw481x_startup(stw481x);
        if (ret) {
index 71841f9..dbea55d 100644 (file)
@@ -69,13 +69,6 @@ EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_compatible);
 
 static int syscon_match_pdevname(struct device *dev, void *data)
 {
-       struct platform_device *pdev = to_platform_device(dev);
-       const struct platform_device_id *id = platform_get_device_id(pdev);
-
-       if (id)
-               if (!strcmp(id->name, (const char *)data))
-                       return 1;
-
        return !strcmp(dev_name(dev), (const char *)data);
 }
 
@@ -152,7 +145,7 @@ static int syscon_probe(struct platform_device *pdev)
 
        platform_set_drvdata(pdev, syscon);
 
-       dev_info(dev, "regmap %pR registered\n", res);
+       dev_dbg(dev, "regmap %pR registered\n", res);
 
        return 0;
 }
index 2cf636c..bd83acc 100644 (file)
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/mfd/core.h>
 #include <linux/mfd/tc3589x.h>
+#include <linux/err.h>
 
 /**
  * enum tc3589x_version - indicates the TC3589x version
@@ -160,7 +162,7 @@ static const struct mfd_cell tc3589x_dev_gpio[] = {
                .name           = "tc3589x-gpio",
                .num_resources  = ARRAY_SIZE(gpio_resources),
                .resources      = &gpio_resources[0],
-               .of_compatible  = "tc3589x-gpio",
+               .of_compatible  = "toshiba,tc3589x-gpio",
        },
 };
 
@@ -169,7 +171,7 @@ static const struct mfd_cell tc3589x_dev_keypad[] = {
                .name           = "tc3589x-keypad",
                .num_resources  = ARRAY_SIZE(keypad_resources),
                .resources      = &keypad_resources[0],
-               .of_compatible  = "tc3589x-keypad",
+               .of_compatible  = "toshiba,tc3589x-keypad",
        },
 };
 
@@ -318,45 +320,74 @@ static int tc3589x_device_init(struct tc3589x *tc3589x)
        return ret;
 }
 
-static int tc3589x_of_probe(struct device_node *np,
-                       struct tc3589x_platform_data *pdata)
+#ifdef CONFIG_OF
+static const struct of_device_id tc3589x_match[] = {
+       /* Legacy compatible string */
+       { .compatible = "tc3589x", .data = (void *) TC3589X_UNKNOWN },
+       { .compatible = "toshiba,tc35890", .data = (void *) TC3589X_TC35890 },
+       { .compatible = "toshiba,tc35892", .data = (void *) TC3589X_TC35892 },
+       { .compatible = "toshiba,tc35893", .data = (void *) TC3589X_TC35893 },
+       { .compatible = "toshiba,tc35894", .data = (void *) TC3589X_TC35894 },
+       { .compatible = "toshiba,tc35895", .data = (void *) TC3589X_TC35895 },
+       { .compatible = "toshiba,tc35896", .data = (void *) TC3589X_TC35896 },
+       { }
+};
+
+MODULE_DEVICE_TABLE(of, tc3589x_match);
+
+static struct tc3589x_platform_data *
+tc3589x_of_probe(struct device *dev, enum tc3589x_version *version)
 {
+       struct device_node *np = dev->of_node;
+       struct tc3589x_platform_data *pdata;
        struct device_node *child;
+       const struct of_device_id *of_id;
+
+       pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+       if (!pdata)
+               return ERR_PTR(-ENOMEM);
+
+       of_id = of_match_device(tc3589x_match, dev);
+       if (!of_id)
+               return ERR_PTR(-ENODEV);
+       *version = (enum tc3589x_version) of_id->data;
 
        for_each_child_of_node(np, child) {
-               if (!strcmp(child->name, "tc3589x_gpio")) {
+               if (of_device_is_compatible(child, "toshiba,tc3589x-gpio"))
                        pdata->block |= TC3589x_BLOCK_GPIO;
-               }
-               if (!strcmp(child->name, "tc3589x_keypad")) {
+               if (of_device_is_compatible(child, "toshiba,tc3589x-keypad"))
                        pdata->block |= TC3589x_BLOCK_KEYPAD;
-               }
        }
 
-       return 0;
+       return pdata;
 }
+#else
+static inline struct tc3589x_platform_data *
+tc3589x_of_probe(struct device *dev, enum tc3589x_version *version)
+{
+       dev_err(dev, "no device tree support\n");
+       return ERR_PTR(-ENODEV);
+}
+#endif
 
 static int tc3589x_probe(struct i2c_client *i2c,
                                   const struct i2c_device_id *id)
 {
-       struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev);
        struct device_node *np = i2c->dev.of_node;
+       struct tc3589x_platform_data *pdata = dev_get_platdata(&i2c->dev);
        struct tc3589x *tc3589x;
+       enum tc3589x_version version;
        int ret;
 
        if (!pdata) {
-               if (np) {
-                       pdata = devm_kzalloc(&i2c->dev, sizeof(*pdata), GFP_KERNEL);
-                       if (!pdata)
-                               return -ENOMEM;
-
-                       ret = tc3589x_of_probe(np, pdata);
-                       if (ret)
-                               return ret;
-               }
-               else {
+               pdata = tc3589x_of_probe(&i2c->dev, &version);
+               if (IS_ERR(pdata)) {
                        dev_err(&i2c->dev, "No platform data or DT found\n");
-                       return -EINVAL;
+                       return PTR_ERR(pdata);
                }
+       } else {
+               /* When not probing from device tree we have this ID */
+               version = id->driver_data;
        }
 
        if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA
@@ -375,7 +406,7 @@ static int tc3589x_probe(struct i2c_client *i2c,
        tc3589x->pdata = pdata;
        tc3589x->irq_base = pdata->irq_base;
 
-       switch (id->driver_data) {
+       switch (version) {
        case TC3589X_TC35893:
        case TC3589X_TC35895:
        case TC3589X_TC35896:
@@ -471,9 +502,12 @@ static const struct i2c_device_id tc3589x_id[] = {
 MODULE_DEVICE_TABLE(i2c, tc3589x_id);
 
 static struct i2c_driver tc3589x_driver = {
-       .driver.name    = "tc3589x",
-       .driver.owner   = THIS_MODULE,
-       .driver.pm      = &tc3589x_dev_pm_ops,
+       .driver = {
+               .name   = "tc3589x",
+               .owner  = THIS_MODULE,
+               .pm     = &tc3589x_dev_pm_ops,
+               .of_match_table = of_match_ptr(tc3589x_match),
+       },
        .probe          = tc3589x_probe,
        .remove         = tc3589x_remove,
        .id_table       = tc3589x_id,
diff --git a/drivers/mfd/ti-ssp.c b/drivers/mfd/ti-ssp.c
deleted file mode 100644 (file)
index a542457..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Sequencer Serial Port (SSP) driver for Texas Instruments' SoCs
- *
- * Copyright (C) 2010 Texas Instruments Inc
- *
- * 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/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/clk.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/sched.h>
-#include <linux/mfd/core.h>
-#include <linux/mfd/ti_ssp.h>
-
-/* Register Offsets */
-#define REG_REV                0x00
-#define REG_IOSEL_1    0x04
-#define REG_IOSEL_2    0x08
-#define REG_PREDIV     0x0c
-#define REG_INTR_ST    0x10
-#define REG_INTR_EN    0x14
-#define REG_TEST_CTRL  0x18
-
-/* Per port registers */
-#define PORT_CFG_2     0x00
-#define PORT_ADDR      0x04
-#define PORT_DATA      0x08
-#define PORT_CFG_1     0x0c
-#define PORT_STATE     0x10
-
-#define SSP_PORT_CONFIG_MASK   (SSP_EARLY_DIN | SSP_DELAY_DOUT)
-#define SSP_PORT_CLKRATE_MASK  0x0f
-
-#define SSP_SEQRAM_WR_EN       BIT(4)
-#define SSP_SEQRAM_RD_EN       BIT(5)
-#define SSP_START              BIT(15)
-#define SSP_BUSY               BIT(10)
-#define SSP_PORT_ASL           BIT(7)
-#define SSP_PORT_CFO1          BIT(6)
-
-#define SSP_PORT_SEQRAM_SIZE   32
-
-static const int ssp_port_base[]   = {0x040, 0x080};
-static const int ssp_port_seqram[] = {0x100, 0x180};
-
-struct ti_ssp {
-       struct resource         *res;
-       struct device           *dev;
-       void __iomem            *regs;
-       spinlock_t              lock;
-       struct clk              *clk;
-       int                     irq;
-       wait_queue_head_t       wqh;
-
-       /*
-        * Some of the iosel2 register bits always read-back as 0, we need to
-        * remember these values so that we don't clobber previously set
-        * values.
-        */
-       u32                     iosel2;
-};
-
-static inline struct ti_ssp *dev_to_ssp(struct device *dev)
-{
-       return dev_get_drvdata(dev->parent);
-}
-
-static inline int dev_to_port(struct device *dev)
-{
-       return to_platform_device(dev)->id;
-}
-
-/* Register Access Helpers, rmw() functions need to run locked */
-static inline u32 ssp_read(struct ti_ssp *ssp, int reg)
-{
-       return __raw_readl(ssp->regs + reg);
-}
-
-static inline void ssp_write(struct ti_ssp *ssp, int reg, u32 val)
-{
-       __raw_writel(val, ssp->regs + reg);
-}
-
-static inline void ssp_rmw(struct ti_ssp *ssp, int reg, u32 mask, u32 bits)
-{
-       ssp_write(ssp, reg, (ssp_read(ssp, reg) & ~mask) | bits);
-}
-
-static inline u32 ssp_port_read(struct ti_ssp *ssp, int port, int reg)
-{
-       return ssp_read(ssp, ssp_port_base[port] + reg);
-}
-
-static inline void ssp_port_write(struct ti_ssp *ssp, int port, int reg,
-                                 u32 val)
-{
-       ssp_write(ssp, ssp_port_base[port] + reg, val);
-}
-
-static inline void ssp_port_rmw(struct ti_ssp *ssp, int port, int reg,
-                               u32 mask, u32 bits)
-{
-       ssp_rmw(ssp, ssp_port_base[port] + reg, mask, bits);
-}
-
-static inline void ssp_port_clr_bits(struct ti_ssp *ssp, int port, int reg,
-                                    u32 bits)
-{
-       ssp_port_rmw(ssp, port, reg, bits, 0);
-}
-
-static inline void ssp_port_set_bits(struct ti_ssp *ssp, int port, int reg,
-                                    u32 bits)
-{
-       ssp_port_rmw(ssp, port, reg, 0, bits);
-}
-
-/* Called to setup port clock mode, caller must hold ssp->lock */
-static int __set_mode(struct ti_ssp *ssp, int port, int mode)
-{
-       mode &= SSP_PORT_CONFIG_MASK;
-       ssp_port_rmw(ssp, port, PORT_CFG_1, SSP_PORT_CONFIG_MASK, mode);
-
-       return 0;
-}
-
-int ti_ssp_set_mode(struct device *dev, int mode)
-{
-       struct ti_ssp *ssp = dev_to_ssp(dev);
-       int port = dev_to_port(dev);
-       int ret;
-
-       spin_lock(&ssp->lock);
-       ret = __set_mode(ssp, port, mode);
-       spin_unlock(&ssp->lock);
-
-       return ret;
-}
-EXPORT_SYMBOL(ti_ssp_set_mode);
-
-/* Called to setup iosel2, caller must hold ssp->lock */
-static void __set_iosel2(struct ti_ssp *ssp, u32 mask, u32 val)
-{
-       ssp->iosel2 = (ssp->iosel2 & ~mask) | val;
-       ssp_write(ssp, REG_IOSEL_2, ssp->iosel2);
-}
-
-/* Called to setup port iosel, caller must hold ssp->lock */
-static void __set_iosel(struct ti_ssp *ssp, int port, u32 iosel)
-{
-       unsigned val, shift = port ? 16 : 0;
-
-       /* IOSEL1 gets the least significant 16 bits */
-       val = ssp_read(ssp, REG_IOSEL_1);
-       val &= 0xffff << (port ? 0 : 16);
-       val |= (iosel & 0xffff) << (port ? 16 : 0);
-       ssp_write(ssp, REG_IOSEL_1, val);
-
-       /* IOSEL2 gets the most significant 16 bits */
-       val = (iosel >> 16) & 0x7;
-       __set_iosel2(ssp, 0x7 << shift, val << shift);
-}
-
-int ti_ssp_set_iosel(struct device *dev, u32 iosel)
-{
-       struct ti_ssp *ssp = dev_to_ssp(dev);
-       int port = dev_to_port(dev);
-
-       spin_lock(&ssp->lock);
-       __set_iosel(ssp, port, iosel);
-       spin_unlock(&ssp->lock);
-
-       return 0;
-}
-EXPORT_SYMBOL(ti_ssp_set_iosel);
-
-int ti_ssp_load(struct device *dev, int offs, u32* prog, int len)
-{
-       struct ti_ssp *ssp = dev_to_ssp(dev);
-       int port = dev_to_port(dev);
-       int i;
-
-       if (len > SSP_PORT_SEQRAM_SIZE)
-               return -ENOSPC;
-
-       spin_lock(&ssp->lock);
-
-       /* Enable SeqRAM access */
-       ssp_port_set_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
-
-       /* Copy code */
-       for (i = 0; i < len; i++) {
-               __raw_writel(prog[i], ssp->regs + offs + 4*i +
-                            ssp_port_seqram[port]);
-       }
-
-       /* Disable SeqRAM access */
-       ssp_port_clr_bits(ssp, port, PORT_CFG_2, SSP_SEQRAM_WR_EN);
-
-       spin_unlock(&ssp->lock);
-
-       return 0;
-}
-EXPORT_SYMBOL(ti_ssp_load);
-
-int ti_ssp_raw_read(struct device *dev)
-{
-       struct ti_ssp *ssp = dev_to_ssp(dev);
-       int port = dev_to_port(dev);
-       int shift = port ? 27 : 11;
-
-       return (ssp_read(ssp, REG_IOSEL_2) >> shift) & 0xf;
-}
-EXPORT_SYMBOL(ti_ssp_raw_read);
-
-int ti_ssp_raw_write(struct device *dev, u32 val)
-{
-       struct ti_ssp *ssp = dev_to_ssp(dev);
-       int port = dev_to_port(dev), shift;
-
-       spin_lock(&ssp->lock);
-
-       shift = port ? 22 : 6;
-       val &= 0xf;
-       __set_iosel2(ssp, 0xf << shift, val << shift);
-
-       spin_unlock(&ssp->lock);
-
-       return 0;
-}
-EXPORT_SYMBOL(ti_ssp_raw_write);
-
-static inline int __xfer_done(struct ti_ssp *ssp, int port)
-{
-       return !(ssp_port_read(ssp, port, PORT_CFG_1) & SSP_BUSY);
-}
-
-int ti_ssp_run(struct device *dev, u32 pc, u32 input, u32 *output)
-{
-       struct ti_ssp *ssp = dev_to_ssp(dev);
-       int port = dev_to_port(dev);
-       int ret;
-
-       if (pc & ~(0x3f))
-               return -EINVAL;
-
-       /* Grab ssp->lock to serialize rmw on ssp registers */
-       spin_lock(&ssp->lock);
-
-       ssp_port_write(ssp, port, PORT_ADDR, input >> 16);
-       ssp_port_write(ssp, port, PORT_DATA, input & 0xffff);
-       ssp_port_rmw(ssp, port, PORT_CFG_1, 0x3f, pc);
-
-       /* grab wait queue head lock to avoid race with the isr */
-       spin_lock_irq(&ssp->wqh.lock);
-
-       /* kick off sequence execution in hardware */
-       ssp_port_set_bits(ssp, port, PORT_CFG_1, SSP_START);
-
-       /* drop ssp lock; no register writes beyond this */
-       spin_unlock(&ssp->lock);
-
-       ret = wait_event_interruptible_locked_irq(ssp->wqh,
-                                                 __xfer_done(ssp, port));
-       spin_unlock_irq(&ssp->wqh.lock);
-
-       if (ret < 0)
-               return ret;
-
-       if (output) {
-               *output = (ssp_port_read(ssp, port, PORT_ADDR) << 16) |
-                         (ssp_port_read(ssp, port, PORT_DATA) &  0xffff);
-       }
-
-       ret = ssp_port_read(ssp, port, PORT_STATE) & 0x3f; /* stop address */
-
-       return ret;
-}
-EXPORT_SYMBOL(ti_ssp_run);
-
-static irqreturn_t ti_ssp_interrupt(int irq, void *dev_data)
-{
-       struct ti_ssp *ssp = dev_data;
-
-       spin_lock(&ssp->wqh.lock);
-
-       ssp_write(ssp, REG_INTR_ST, 0x3);
-       wake_up_locked(&ssp->wqh);
-
-       spin_unlock(&ssp->wqh.lock);
-
-       return IRQ_HANDLED;
-}
-
-static int ti_ssp_probe(struct platform_device *pdev)
-{
-       static struct ti_ssp *ssp;
-       const struct ti_ssp_data *pdata = dev_get_platdata(&pdev->dev);
-       int error = 0, prediv = 0xff, id;
-       unsigned long sysclk;
-       struct device *dev = &pdev->dev;
-       struct mfd_cell cells[2];
-
-       ssp = kzalloc(sizeof(*ssp), GFP_KERNEL);
-       if (!ssp) {
-               dev_err(dev, "cannot allocate device info\n");
-               return -ENOMEM;
-       }
-
-       ssp->dev = dev;
-       dev_set_drvdata(dev, ssp);
-
-       ssp->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!ssp->res) {
-               error = -ENODEV;
-               dev_err(dev, "cannot determine register area\n");
-               goto error_res;
-       }
-
-       if (!request_mem_region(ssp->res->start, resource_size(ssp->res),
-                               pdev->name)) {
-               error = -ENOMEM;
-               dev_err(dev, "cannot claim register memory\n");
-               goto error_res;
-       }
-
-       ssp->regs = ioremap(ssp->res->start, resource_size(ssp->res));
-       if (!ssp->regs) {
-               error = -ENOMEM;
-               dev_err(dev, "cannot map register memory\n");
-               goto error_map;
-       }
-
-       ssp->clk = clk_get(dev, NULL);
-       if (IS_ERR(ssp->clk)) {
-               error = PTR_ERR(ssp->clk);
-               dev_err(dev, "cannot claim device clock\n");
-               goto error_clk;
-       }
-
-       ssp->irq = platform_get_irq(pdev, 0);
-       if (ssp->irq < 0) {
-               error = -ENODEV;
-               dev_err(dev, "unknown irq\n");
-               goto error_irq;
-       }
-
-       error = request_threaded_irq(ssp->irq, NULL, ti_ssp_interrupt, 0,
-                                    dev_name(dev), ssp);
-       if (error < 0) {
-               dev_err(dev, "cannot acquire irq\n");
-               goto error_irq;
-       }
-
-       spin_lock_init(&ssp->lock);
-       init_waitqueue_head(&ssp->wqh);
-
-       /* Power on and initialize SSP */
-       error = clk_enable(ssp->clk);
-       if (error) {
-               dev_err(dev, "cannot enable device clock\n");
-               goto error_enable;
-       }
-
-       /* Reset registers to a sensible known state */
-       ssp_write(ssp, REG_IOSEL_1, 0);
-       ssp_write(ssp, REG_IOSEL_2, 0);
-       ssp_write(ssp, REG_INTR_EN, 0x3);
-       ssp_write(ssp, REG_INTR_ST, 0x3);
-       ssp_write(ssp, REG_TEST_CTRL, 0);
-       ssp_port_write(ssp, 0, PORT_CFG_1, SSP_PORT_ASL);
-       ssp_port_write(ssp, 1, PORT_CFG_1, SSP_PORT_ASL);
-       ssp_port_write(ssp, 0, PORT_CFG_2, SSP_PORT_CFO1);
-       ssp_port_write(ssp, 1, PORT_CFG_2, SSP_PORT_CFO1);
-
-       sysclk = clk_get_rate(ssp->clk);
-       if (pdata && pdata->out_clock)
-               prediv = (sysclk / pdata->out_clock) - 1;
-       prediv = clamp(prediv, 0, 0xff);
-       ssp_rmw(ssp, REG_PREDIV, 0xff, prediv);
-
-       memset(cells, 0, sizeof(cells));
-       for (id = 0; id < 2; id++) {
-               const struct ti_ssp_dev_data *data = &pdata->dev_data[id];
-
-               cells[id].id            = id;
-               cells[id].name          = data->dev_name;
-               cells[id].platform_data = data->pdata;
-       }
-
-       error = mfd_add_devices(dev, 0, cells, 2, NULL, 0, NULL);
-       if (error < 0) {
-               dev_err(dev, "cannot add mfd cells\n");
-               goto error_enable;
-       }
-
-       return 0;
-
-error_enable:
-       free_irq(ssp->irq, ssp);
-error_irq:
-       clk_put(ssp->clk);
-error_clk:
-       iounmap(ssp->regs);
-error_map:
-       release_mem_region(ssp->res->start, resource_size(ssp->res));
-error_res:
-       kfree(ssp);
-       return error;
-}
-
-static int ti_ssp_remove(struct platform_device *pdev)
-{
-       struct device *dev = &pdev->dev;
-       struct ti_ssp *ssp = dev_get_drvdata(dev);
-
-       mfd_remove_devices(dev);
-       clk_disable(ssp->clk);
-       free_irq(ssp->irq, ssp);
-       clk_put(ssp->clk);
-       iounmap(ssp->regs);
-       release_mem_region(ssp->res->start, resource_size(ssp->res));
-       kfree(ssp);
-       return 0;
-}
-
-static struct platform_driver ti_ssp_driver = {
-       .probe          = ti_ssp_probe,
-       .remove         = ti_ssp_remove,
-       .driver         = {
-               .name   = "ti-ssp",
-               .owner  = THIS_MODULE,
-       }
-};
-
-module_platform_driver(ti_ssp_driver);
-
-MODULE_DESCRIPTION("Sequencer Serial Port (SSP) Driver");
-MODULE_AUTHOR("Cyril Chemparathy");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:ti-ssp");
index d4e8604..dd4bf58 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/io.h>
@@ -184,12 +183,6 @@ static     int ti_tscadc_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "no memory resource defined.\n");
-               return -EINVAL;
-       }
-
        /* Allocate memory for device */
        tscadc = devm_kzalloc(&pdev->dev,
                        sizeof(struct ti_tscadc_dev), GFP_KERNEL);
@@ -206,19 +199,10 @@ static    int ti_tscadc_probe(struct platform_device *pdev)
        } else
                tscadc->irq = err;
 
-       res = devm_request_mem_region(&pdev->dev,
-                       res->start, resource_size(res), pdev->name);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to reserve registers.\n");
-               return -EBUSY;
-       }
-
-       tscadc->tscadc_base = devm_ioremap(&pdev->dev,
-                       res->start, resource_size(res));
-       if (!tscadc->tscadc_base) {
-               dev_err(&pdev->dev, "failed to map registers.\n");
-               return -ENOMEM;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       tscadc->tscadc_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(tscadc->tscadc_base))
+               return PTR_ERR(tscadc->tscadc_base);
 
        tscadc->regmap_tscadc = devm_regmap_init_mmio(&pdev->dev,
                        tscadc->tscadc_base, &tscadc_regmap_config);
index 2bc5cfb..6ce36d6 100644 (file)
@@ -715,7 +715,7 @@ static int timb_probe(struct pci_dev *dev,
        for (i = 0; i < TIMBERDALE_NR_IRQS; i++)
                msix_entries[i].entry = i;
 
-       err = pci_enable_msix(dev, msix_entries, TIMBERDALE_NR_IRQS);
+       err = pci_enable_msix_exact(dev, msix_entries, TIMBERDALE_NR_IRQS);
        if (err) {
                dev_err(&dev->dev,
                        "MSI-X init failed: %d, expected entries: %d\n",
diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c
new file mode 100644 (file)
index 0000000..a74bfb5
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * Driver for TPS65218 Integrated power management chipsets
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether expressed or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2 for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mutex.h>
+
+#include <linux/mfd/core.h>
+#include <linux/mfd/tps65218.h>
+
+#define TPS65218_PASSWORD_REGS_UNLOCK   0x7D
+
+/**
+ * tps65218_reg_read: Read a single tps65218 register.
+ *
+ * @tps: Device to read from.
+ * @reg: Register to read.
+ * @val: Contians the value
+ */
+int tps65218_reg_read(struct tps65218 *tps, unsigned int reg,
+                       unsigned int *val)
+{
+       return regmap_read(tps->regmap, reg, val);
+}
+EXPORT_SYMBOL_GPL(tps65218_reg_read);
+
+/**
+ * tps65218_reg_write: Write a single tps65218 register.
+ *
+ * @tps65218: Device to write to.
+ * @reg: Register to write to.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+int tps65218_reg_write(struct tps65218 *tps, unsigned int reg,
+                       unsigned int val, unsigned int level)
+{
+       int ret;
+       unsigned int xor_reg_val;
+
+       switch (level) {
+       case TPS65218_PROTECT_NONE:
+               return regmap_write(tps->regmap, reg, val);
+       case TPS65218_PROTECT_L1:
+               xor_reg_val = reg ^ TPS65218_PASSWORD_REGS_UNLOCK;
+               ret = regmap_write(tps->regmap, TPS65218_REG_PASSWORD,
+                                                       xor_reg_val);
+               if (ret < 0)
+                       return ret;
+
+               return regmap_write(tps->regmap, reg, val);
+       default:
+               return -EINVAL;
+       }
+}
+EXPORT_SYMBOL_GPL(tps65218_reg_write);
+
+/**
+ * tps65218_update_bits: Modify bits w.r.t mask, val and level.
+ *
+ * @tps65218: Device to write to.
+ * @reg: Register to read-write to.
+ * @mask: Mask.
+ * @val: Value to write.
+ * @level: Password protected level
+ */
+static int tps65218_update_bits(struct tps65218 *tps, unsigned int reg,
+               unsigned int mask, unsigned int val, unsigned int level)
+{
+       int ret;
+       unsigned int data;
+
+       ret = tps65218_reg_read(tps, reg, &data);
+       if (ret) {
+               dev_err(tps->dev, "Read from reg 0x%x failed\n", reg);
+               return ret;
+       }
+
+       data &= ~mask;
+       data |= val & mask;
+
+       mutex_lock(&tps->tps_lock);
+       ret = tps65218_reg_write(tps, reg, data, level);
+       if (ret)
+               dev_err(tps->dev, "Write for reg 0x%x failed\n", reg);
+       mutex_unlock(&tps->tps_lock);
+
+       return ret;
+}
+
+int tps65218_set_bits(struct tps65218 *tps, unsigned int reg,
+               unsigned int mask, unsigned int val, unsigned int level)
+{
+       return tps65218_update_bits(tps, reg, mask, val, level);
+}
+EXPORT_SYMBOL_GPL(tps65218_set_bits);
+
+int tps65218_clear_bits(struct tps65218 *tps, unsigned int reg,
+               unsigned int mask, unsigned int level)
+{
+       return tps65218_update_bits(tps, reg, mask, 0, level);
+}
+EXPORT_SYMBOL_GPL(tps65218_clear_bits);
+
+static struct regmap_config tps65218_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct regmap_irq tps65218_irqs[] = {
+       /* INT1 IRQs */
+       [TPS65218_PRGC_IRQ] = {
+               .mask = TPS65218_INT1_PRGC,
+       },
+       [TPS65218_CC_AQC_IRQ] = {
+               .mask = TPS65218_INT1_CC_AQC,
+       },
+       [TPS65218_HOT_IRQ] = {
+               .mask = TPS65218_INT1_HOT,
+       },
+       [TPS65218_PB_IRQ] = {
+               .mask = TPS65218_INT1_PB,
+       },
+       [TPS65218_AC_IRQ] = {
+               .mask = TPS65218_INT1_AC,
+       },
+       [TPS65218_VPRG_IRQ] = {
+               .mask = TPS65218_INT1_VPRG,
+       },
+       [TPS65218_INVALID1_IRQ] = {
+       },
+       [TPS65218_INVALID2_IRQ] = {
+       },
+       /* INT2 IRQs*/
+       [TPS65218_LS1_I_IRQ] = {
+               .mask = TPS65218_INT2_LS1_I,
+               .reg_offset = 1,
+       },
+       [TPS65218_LS2_I_IRQ] = {
+               .mask = TPS65218_INT2_LS2_I,
+               .reg_offset = 1,
+       },
+       [TPS65218_LS3_I_IRQ] = {
+               .mask = TPS65218_INT2_LS3_I,
+               .reg_offset = 1,
+       },
+       [TPS65218_LS1_F_IRQ] = {
+               .mask = TPS65218_INT2_LS1_F,
+               .reg_offset = 1,
+       },
+       [TPS65218_LS2_F_IRQ] = {
+               .mask = TPS65218_INT2_LS2_F,
+               .reg_offset = 1,
+       },
+       [TPS65218_LS3_F_IRQ] = {
+               .mask = TPS65218_INT2_LS3_F,
+               .reg_offset = 1,
+       },
+       [TPS65218_INVALID3_IRQ] = {
+       },
+       [TPS65218_INVALID4_IRQ] = {
+       },
+};
+
+static struct regmap_irq_chip tps65218_irq_chip = {
+       .name = "tps65218",
+       .irqs = tps65218_irqs,
+       .num_irqs = ARRAY_SIZE(tps65218_irqs),
+
+       .num_regs = 2,
+       .mask_base = TPS65218_REG_INT_MASK1,
+};
+
+static const struct of_device_id of_tps65218_match_table[] = {
+       { .compatible = "ti,tps65218", },
+};
+
+static int tps65218_probe(struct i2c_client *client,
+                               const struct i2c_device_id *ids)
+{
+       struct tps65218 *tps;
+       const struct of_device_id *match;
+       int ret;
+
+       match = of_match_device(of_tps65218_match_table, &client->dev);
+       if (!match) {
+               dev_err(&client->dev,
+                       "Failed to find matching dt id\n");
+               return -EINVAL;
+       }
+
+       tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+       if (!tps)
+               return -ENOMEM;
+
+       i2c_set_clientdata(client, tps);
+       tps->dev = &client->dev;
+       tps->irq = client->irq;
+       tps->regmap = devm_regmap_init_i2c(client, &tps65218_regmap_config);
+       if (IS_ERR(tps->regmap)) {
+               ret = PTR_ERR(tps->regmap);
+               dev_err(tps->dev, "Failed to allocate register map: %d\n",
+                       ret);
+               return ret;
+       }
+
+       mutex_init(&tps->tps_lock);
+
+       ret = regmap_add_irq_chip(tps->regmap, tps->irq,
+                       IRQF_ONESHOT, 0, &tps65218_irq_chip,
+                       &tps->irq_data);
+       if (ret < 0)
+               return ret;
+
+       ret = of_platform_populate(client->dev.of_node, NULL, NULL,
+                                  &client->dev);
+       if (ret < 0)
+               goto err_irq;
+
+       return 0;
+
+err_irq:
+       regmap_del_irq_chip(tps->irq, tps->irq_data);
+
+       return ret;
+}
+
+static int tps65218_remove(struct i2c_client *client)
+{
+       struct tps65218 *tps = i2c_get_clientdata(client);
+
+       regmap_del_irq_chip(tps->irq, tps->irq_data);
+
+       return 0;
+}
+
+static const struct i2c_device_id tps65218_id_table[] = {
+       { "tps65218", TPS65218 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, tps65218_id_table);
+
+static struct i2c_driver tps65218_driver = {
+       .driver         = {
+               .name   = "tps65218",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_tps65218_match_table,
+       },
+       .probe          = tps65218_probe,
+       .remove         = tps65218_remove,
+       .id_table       = tps65218_id_table,
+};
+
+module_i2c_driver(tps65218_driver);
+
+MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>");
+MODULE_DESCRIPTION("TPS65218 chip family multi-function driver");
+MODULE_LICENSE("GPL v2");
index 1f142d7..460a014 100644 (file)
@@ -255,8 +255,10 @@ static int tps65910_irq_init(struct tps65910 *tps65910, int irq,
        ret = regmap_add_irq_chip(tps65910->regmap, tps65910->chip_irq,
                IRQF_ONESHOT, pdata->irq_base,
                tps6591x_irqs_chip, &tps65910->irq_data);
-       if (ret < 0)
+       if (ret < 0) {
                dev_warn(tps65910->dev, "Failed to add irq_chip %d\n", ret);
+               tps65910->chip_irq = 0;
+       }
        return ret;
 }
 
@@ -509,6 +511,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c,
                              regmap_irq_get_domain(tps65910->irq_data));
        if (ret < 0) {
                dev_err(&i2c->dev, "mfd_add_devices failed: %d\n", ret);
+               tps65910_irq_exit(tps65910);
                return ret;
        }
 
index 27a518e..1f82d60 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
 #include <linux/mfd/core.h>
index d360a83..fbecec7 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/bug.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
index ed71832..e87140b 100644 (file)
@@ -282,11 +282,11 @@ static struct reg_default twl4030_49_defaults[] = {
 static bool twl4030_49_nop_reg(struct device *dev, unsigned int reg)
 {
        switch (reg) {
-       case 0:
-       case 3:
-       case 40:
-       case 41:
-       case 42:
+       case 0x00:
+       case 0x03:
+       case 0x40:
+       case 0x41:
+       case 0x42:
                return false;
        default:
                return true;
index 9aa6d1e..596b1f6 100644 (file)
@@ -27,7 +27,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <linux/init.h>
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
diff --git a/drivers/mfd/twl4030-madc.c b/drivers/mfd/twl4030-madc.c
deleted file mode 100644 (file)
index 4c583e4..0000000
+++ /dev/null
@@ -1,818 +0,0 @@
-/*
- *
- * TWL4030 MADC module driver-This driver monitors the real time
- * conversion of analog signals like battery temperature,
- * battery type, battery level etc.
- *
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
- * J Keerthy <j-keerthy@ti.com>
- *
- * Based on twl4030-madc.c
- * Copyright (C) 2008 Nokia Corporation
- * Mikko Ylinen <mikko.k.ylinen@nokia.com>
- *
- * Amit Kucheria <amit.kucheria@canonical.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/device.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/i2c/twl.h>
-#include <linux/i2c/twl4030-madc.h>
-#include <linux/module.h>
-#include <linux/stddef.h>
-#include <linux/mutex.h>
-#include <linux/bitops.h>
-#include <linux/jiffies.h>
-#include <linux/types.h>
-#include <linux/gfp.h>
-#include <linux/err.h>
-
-/*
- * struct twl4030_madc_data - a container for madc info
- * @dev - pointer to device structure for madc
- * @lock - mutex protecting this data structure
- * @requests - Array of request struct corresponding to SW1, SW2 and RT
- * @imr - Interrupt mask register of MADC
- * @isr - Interrupt status register of MADC
- */
-struct twl4030_madc_data {
-       struct device *dev;
-       struct mutex lock;      /* mutex protecting this data structure */
-       struct twl4030_madc_request requests[TWL4030_MADC_NUM_METHODS];
-       int imr;
-       int isr;
-};
-
-static struct twl4030_madc_data *twl4030_madc;
-
-struct twl4030_prescale_divider_ratios {
-       s16 numerator;
-       s16 denominator;
-};
-
-static const struct twl4030_prescale_divider_ratios
-twl4030_divider_ratios[16] = {
-       {1, 1},         /* CHANNEL 0 No Prescaler */
-       {1, 1},         /* CHANNEL 1 No Prescaler */
-       {6, 10},        /* CHANNEL 2 */
-       {6, 10},        /* CHANNEL 3 */
-       {6, 10},        /* CHANNEL 4 */
-       {6, 10},        /* CHANNEL 5 */
-       {6, 10},        /* CHANNEL 6 */
-       {6, 10},        /* CHANNEL 7 */
-       {3, 14},        /* CHANNEL 8 */
-       {1, 3},         /* CHANNEL 9 */
-       {1, 1},         /* CHANNEL 10 No Prescaler */
-       {15, 100},      /* CHANNEL 11 */
-       {1, 4},         /* CHANNEL 12 */
-       {1, 1},         /* CHANNEL 13 Reserved channels */
-       {1, 1},         /* CHANNEL 14 Reseved channels */
-       {5, 11},        /* CHANNEL 15 */
-};
-
-
-/*
- * Conversion table from -3 to 55 degree Celcius
- */
-static int therm_tbl[] = {
-30800, 29500,  28300,  27100,
-26000, 24900,  23900,  22900,  22000,  21100,  20300,  19400,  18700,  17900,
-17200, 16500,  15900,  15300,  14700,  14100,  13600,  13100,  12600,  12100,
-11600, 11200,  10800,  10400,  10000,  9630,   9280,   8950,   8620,   8310,
-8020,  7730,   7460,   7200,   6950,   6710,   6470,   6250,   6040,   5830,
-5640,  5450,   5260,   5090,   4920,   4760,   4600,   4450,   4310,   4170,
-4040,  3910,   3790,   3670,   3550
-};
-
-/*
- * Structure containing the registers
- * of different conversion methods supported by MADC.
- * Hardware or RT real time conversion request initiated by external host
- * processor for RT Signal conversions.
- * External host processors can also request for non RT conversions
- * SW1 and SW2 software conversions also called asynchronous or GPC request.
- */
-static
-const struct twl4030_madc_conversion_method twl4030_conversion_methods[] = {
-       [TWL4030_MADC_RT] = {
-                            .sel = TWL4030_MADC_RTSELECT_LSB,
-                            .avg = TWL4030_MADC_RTAVERAGE_LSB,
-                            .rbase = TWL4030_MADC_RTCH0_LSB,
-                            },
-       [TWL4030_MADC_SW1] = {
-                             .sel = TWL4030_MADC_SW1SELECT_LSB,
-                             .avg = TWL4030_MADC_SW1AVERAGE_LSB,
-                             .rbase = TWL4030_MADC_GPCH0_LSB,
-                             .ctrl = TWL4030_MADC_CTRL_SW1,
-                             },
-       [TWL4030_MADC_SW2] = {
-                             .sel = TWL4030_MADC_SW2SELECT_LSB,
-                             .avg = TWL4030_MADC_SW2AVERAGE_LSB,
-                             .rbase = TWL4030_MADC_GPCH0_LSB,
-                             .ctrl = TWL4030_MADC_CTRL_SW2,
-                             },
-};
-
-/*
- * Function to read a particular channel value.
- * @madc - pointer to struct twl4030_madc_data
- * @reg - lsb of ADC Channel
- * If the i2c read fails it returns an error else returns 0.
- */
-static int twl4030_madc_channel_raw_read(struct twl4030_madc_data *madc, u8 reg)
-{
-       u8 msb, lsb;
-       int ret;
-       /*
-        * For each ADC channel, we have MSB and LSB register pair. MSB address
-        * is always LSB address+1. reg parameter is the address of LSB register
-        */
-       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &msb, reg + 1);
-       if (ret) {
-               dev_err(madc->dev, "unable to read MSB register 0x%X\n",
-                       reg + 1);
-               return ret;
-       }
-       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &lsb, reg);
-       if (ret) {
-               dev_err(madc->dev, "unable to read LSB register 0x%X\n", reg);
-               return ret;
-       }
-
-       return (int)(((msb << 8) | lsb) >> 6);
-}
-
-/*
- * Return battery temperature
- * Or < 0 on failure.
- */
-static int twl4030battery_temperature(int raw_volt)
-{
-       u8 val;
-       int temp, curr, volt, res, ret;
-
-       volt = (raw_volt * TEMP_STEP_SIZE) / TEMP_PSR_R;
-       /* Getting and calculating the supply current in micro ampers */
-       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
-               REG_BCICTL2);
-       if (ret < 0)
-               return ret;
-       curr = ((val & TWL4030_BCI_ITHEN) + 1) * 10;
-       /* Getting and calculating the thermistor resistance in ohms */
-       res = volt * 1000 / curr;
-       /* calculating temperature */
-       for (temp = 58; temp >= 0; temp--) {
-               int actual = therm_tbl[temp];
-
-               if ((actual - res) >= 0)
-                       break;
-       }
-
-       return temp + 1;
-}
-
-static int twl4030battery_current(int raw_volt)
-{
-       int ret;
-       u8 val;
-
-       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE, &val,
-               TWL4030_BCI_BCICTL1);
-       if (ret)
-               return ret;
-       if (val & TWL4030_BCI_CGAIN) /* slope of 0.44 mV/mA */
-               return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R1;
-       else /* slope of 0.88 mV/mA */
-               return (raw_volt * CURR_STEP_SIZE) / CURR_PSR_R2;
-}
-/*
- * Function to read channel values
- * @madc - pointer to twl4030_madc_data struct
- * @reg_base - Base address of the first channel
- * @Channels - 16 bit bitmap. If the bit is set, channel value is read
- * @buf - The channel values are stored here. if read fails error
- * @raw - Return raw values without conversion
- * value is stored
- * Returns the number of successfully read channels.
- */
-static int twl4030_madc_read_channels(struct twl4030_madc_data *madc,
-                                     u8 reg_base, unsigned
-                                     long channels, int *buf,
-                                     bool raw)
-{
-       int count = 0, count_req = 0, i;
-       u8 reg;
-
-       for_each_set_bit(i, &channels, TWL4030_MADC_MAX_CHANNELS) {
-               reg = reg_base + 2 * i;
-               buf[i] = twl4030_madc_channel_raw_read(madc, reg);
-               if (buf[i] < 0) {
-                       dev_err(madc->dev,
-                               "Unable to read register 0x%X\n", reg);
-                       count_req++;
-                       continue;
-               }
-               if (raw) {
-                       count++;
-                       continue;
-               }
-               switch (i) {
-               case 10:
-                       buf[i] = twl4030battery_current(buf[i]);
-                       if (buf[i] < 0) {
-                               dev_err(madc->dev, "err reading current\n");
-                               count_req++;
-                       } else {
-                               count++;
-                               buf[i] = buf[i] - 750;
-                       }
-                       break;
-               case 1:
-                       buf[i] = twl4030battery_temperature(buf[i]);
-                       if (buf[i] < 0) {
-                               dev_err(madc->dev, "err reading temperature\n");
-                               count_req++;
-                       } else {
-                               buf[i] -= 3;
-                               count++;
-                       }
-                       break;
-               default:
-                       count++;
-                       /* Analog Input (V) = conv_result * step_size / R
-                        * conv_result = decimal value of 10-bit conversion
-                        *               result
-                        * step size = 1.5 / (2 ^ 10 -1)
-                        * R = Prescaler ratio for input channels.
-                        * Result given in mV hence multiplied by 1000.
-                        */
-                       buf[i] = (buf[i] * 3 * 1000 *
-                                twl4030_divider_ratios[i].denominator)
-                               / (2 * 1023 *
-                               twl4030_divider_ratios[i].numerator);
-               }
-       }
-       if (count_req)
-               dev_err(madc->dev, "%d channel conversion failed\n", count_req);
-
-       return count;
-}
-
-/*
- * Enables irq.
- * @madc - pointer to twl4030_madc_data struct
- * @id - irq number to be enabled
- * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
- * corresponding to RT, SW1, SW2 conversion requests.
- * If the i2c read fails it returns an error else returns 0.
- */
-static int twl4030_madc_enable_irq(struct twl4030_madc_data *madc, u8 id)
-{
-       u8 val;
-       int ret;
-
-       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
-       if (ret) {
-               dev_err(madc->dev, "unable to read imr register 0x%X\n",
-                       madc->imr);
-               return ret;
-       }
-       val &= ~(1 << id);
-       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
-       if (ret) {
-               dev_err(madc->dev,
-                       "unable to write imr register 0x%X\n", madc->imr);
-               return ret;
-
-       }
-
-       return 0;
-}
-
-/*
- * Disables irq.
- * @madc - pointer to twl4030_madc_data struct
- * @id - irq number to be disabled
- * can take one of TWL4030_MADC_RT, TWL4030_MADC_SW1, TWL4030_MADC_SW2
- * corresponding to RT, SW1, SW2 conversion requests.
- * Returns error if i2c read/write fails.
- */
-static int twl4030_madc_disable_irq(struct twl4030_madc_data *madc, u8 id)
-{
-       u8 val;
-       int ret;
-
-       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &val, madc->imr);
-       if (ret) {
-               dev_err(madc->dev, "unable to read imr register 0x%X\n",
-                       madc->imr);
-               return ret;
-       }
-       val |= (1 << id);
-       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, val, madc->imr);
-       if (ret) {
-               dev_err(madc->dev,
-                       "unable to write imr register 0x%X\n", madc->imr);
-               return ret;
-       }
-
-       return 0;
-}
-
-static irqreturn_t twl4030_madc_threaded_irq_handler(int irq, void *_madc)
-{
-       struct twl4030_madc_data *madc = _madc;
-       const struct twl4030_madc_conversion_method *method;
-       u8 isr_val, imr_val;
-       int i, len, ret;
-       struct twl4030_madc_request *r;
-
-       mutex_lock(&madc->lock);
-       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &isr_val, madc->isr);
-       if (ret) {
-               dev_err(madc->dev, "unable to read isr register 0x%X\n",
-                       madc->isr);
-               goto err_i2c;
-       }
-       ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &imr_val, madc->imr);
-       if (ret) {
-               dev_err(madc->dev, "unable to read imr register 0x%X\n",
-                       madc->imr);
-               goto err_i2c;
-       }
-       isr_val &= ~imr_val;
-       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
-               if (!(isr_val & (1 << i)))
-                       continue;
-               ret = twl4030_madc_disable_irq(madc, i);
-               if (ret < 0)
-                       dev_dbg(madc->dev, "Disable interrupt failed%d\n", i);
-               madc->requests[i].result_pending = 1;
-       }
-       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
-               r = &madc->requests[i];
-               /* No pending results for this method, move to next one */
-               if (!r->result_pending)
-                       continue;
-               method = &twl4030_conversion_methods[r->method];
-               /* Read results */
-               len = twl4030_madc_read_channels(madc, method->rbase,
-                                                r->channels, r->rbuf, r->raw);
-               /* Return results to caller */
-               if (r->func_cb != NULL) {
-                       r->func_cb(len, r->channels, r->rbuf);
-                       r->func_cb = NULL;
-               }
-               /* Free request */
-               r->result_pending = 0;
-               r->active = 0;
-       }
-       mutex_unlock(&madc->lock);
-
-       return IRQ_HANDLED;
-
-err_i2c:
-       /*
-        * In case of error check whichever request is active
-        * and service the same.
-        */
-       for (i = 0; i < TWL4030_MADC_NUM_METHODS; i++) {
-               r = &madc->requests[i];
-               if (r->active == 0)
-                       continue;
-               method = &twl4030_conversion_methods[r->method];
-               /* Read results */
-               len = twl4030_madc_read_channels(madc, method->rbase,
-                                                r->channels, r->rbuf, r->raw);
-               /* Return results to caller */
-               if (r->func_cb != NULL) {
-                       r->func_cb(len, r->channels, r->rbuf);
-                       r->func_cb = NULL;
-               }
-               /* Free request */
-               r->result_pending = 0;
-               r->active = 0;
-       }
-       mutex_unlock(&madc->lock);
-
-       return IRQ_HANDLED;
-}
-
-static int twl4030_madc_set_irq(struct twl4030_madc_data *madc,
-                               struct twl4030_madc_request *req)
-{
-       struct twl4030_madc_request *p;
-       int ret;
-
-       p = &madc->requests[req->method];
-       memcpy(p, req, sizeof(*req));
-       ret = twl4030_madc_enable_irq(madc, req->method);
-       if (ret < 0) {
-               dev_err(madc->dev, "enable irq failed!!\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-/*
- * Function which enables the madc conversion
- * by writing to the control register.
- * @madc - pointer to twl4030_madc_data struct
- * @conv_method - can be TWL4030_MADC_RT, TWL4030_MADC_SW2, TWL4030_MADC_SW1
- * corresponding to RT SW1 or SW2 conversion methods.
- * Returns 0 if succeeds else a negative error value
- */
-static int twl4030_madc_start_conversion(struct twl4030_madc_data *madc,
-                                        int conv_method)
-{
-       const struct twl4030_madc_conversion_method *method;
-       int ret = 0;
-       method = &twl4030_conversion_methods[conv_method];
-       switch (conv_method) {
-       case TWL4030_MADC_SW1:
-       case TWL4030_MADC_SW2:
-               ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
-                                      TWL4030_MADC_SW_START, method->ctrl);
-               if (ret) {
-                       dev_err(madc->dev,
-                               "unable to write ctrl register 0x%X\n",
-                               method->ctrl);
-                       return ret;
-               }
-               break;
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-/*
- * Function that waits for conversion to be ready
- * @madc - pointer to twl4030_madc_data struct
- * @timeout_ms - timeout value in milliseconds
- * @status_reg - ctrl register
- * returns 0 if succeeds else a negative error value
- */
-static int twl4030_madc_wait_conversion_ready(struct twl4030_madc_data *madc,
-                                             unsigned int timeout_ms,
-                                             u8 status_reg)
-{
-       unsigned long timeout;
-       int ret;
-
-       timeout = jiffies + msecs_to_jiffies(timeout_ms);
-       do {
-               u8 reg;
-
-               ret = twl_i2c_read_u8(TWL4030_MODULE_MADC, &reg, status_reg);
-               if (ret) {
-                       dev_err(madc->dev,
-                               "unable to read status register 0x%X\n",
-                               status_reg);
-                       return ret;
-               }
-               if (!(reg & TWL4030_MADC_BUSY) && (reg & TWL4030_MADC_EOC_SW))
-                       return 0;
-               usleep_range(500, 2000);
-       } while (!time_after(jiffies, timeout));
-       dev_err(madc->dev, "conversion timeout!\n");
-
-       return -EAGAIN;
-}
-
-/*
- * An exported function which can be called from other kernel drivers.
- * @req twl4030_madc_request structure
- * req->rbuf will be filled with read values of channels based on the
- * channel index. If a particular channel reading fails there will
- * be a negative error value in the corresponding array element.
- * returns 0 if succeeds else error value
- */
-int twl4030_madc_conversion(struct twl4030_madc_request *req)
-{
-       const struct twl4030_madc_conversion_method *method;
-       u8 ch_msb, ch_lsb;
-       int ret;
-
-       if (!req || !twl4030_madc)
-               return -EINVAL;
-
-       mutex_lock(&twl4030_madc->lock);
-       if (req->method < TWL4030_MADC_RT || req->method > TWL4030_MADC_SW2) {
-               ret = -EINVAL;
-               goto out;
-       }
-       /* Do we have a conversion request ongoing */
-       if (twl4030_madc->requests[req->method].active) {
-               ret = -EBUSY;
-               goto out;
-       }
-       ch_msb = (req->channels >> 8) & 0xff;
-       ch_lsb = req->channels & 0xff;
-       method = &twl4030_conversion_methods[req->method];
-       /* Select channels to be converted */
-       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_msb, method->sel + 1);
-       if (ret) {
-               dev_err(twl4030_madc->dev,
-                       "unable to write sel register 0x%X\n", method->sel + 1);
-               goto out;
-       }
-       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, ch_lsb, method->sel);
-       if (ret) {
-               dev_err(twl4030_madc->dev,
-                       "unable to write sel register 0x%X\n", method->sel + 1);
-               goto out;
-       }
-       /* Select averaging for all channels if do_avg is set */
-       if (req->do_avg) {
-               ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
-                                      ch_msb, method->avg + 1);
-               if (ret) {
-                       dev_err(twl4030_madc->dev,
-                               "unable to write avg register 0x%X\n",
-                               method->avg + 1);
-                       goto out;
-               }
-               ret = twl_i2c_write_u8(TWL4030_MODULE_MADC,
-                                      ch_lsb, method->avg);
-               if (ret) {
-                       dev_err(twl4030_madc->dev,
-                               "unable to write sel reg 0x%X\n",
-                               method->sel + 1);
-                       goto out;
-               }
-       }
-       if (req->type == TWL4030_MADC_IRQ_ONESHOT && req->func_cb != NULL) {
-               ret = twl4030_madc_set_irq(twl4030_madc, req);
-               if (ret < 0)
-                       goto out;
-               ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
-               if (ret < 0)
-                       goto out;
-               twl4030_madc->requests[req->method].active = 1;
-               ret = 0;
-               goto out;
-       }
-       /* With RT method we should not be here anymore */
-       if (req->method == TWL4030_MADC_RT) {
-               ret = -EINVAL;
-               goto out;
-       }
-       ret = twl4030_madc_start_conversion(twl4030_madc, req->method);
-       if (ret < 0)
-               goto out;
-       twl4030_madc->requests[req->method].active = 1;
-       /* Wait until conversion is ready (ctrl register returns EOC) */
-       ret = twl4030_madc_wait_conversion_ready(twl4030_madc, 5, method->ctrl);
-       if (ret) {
-               twl4030_madc->requests[req->method].active = 0;
-               goto out;
-       }
-       ret = twl4030_madc_read_channels(twl4030_madc, method->rbase,
-                                        req->channels, req->rbuf, req->raw);
-       twl4030_madc->requests[req->method].active = 0;
-
-out:
-       mutex_unlock(&twl4030_madc->lock);
-
-       return ret;
-}
-EXPORT_SYMBOL_GPL(twl4030_madc_conversion);
-
-/*
- * Return channel value
- * Or < 0 on failure.
- */
-int twl4030_get_madc_conversion(int channel_no)
-{
-       struct twl4030_madc_request req;
-       int temp = 0;
-       int ret;
-
-       req.channels = (1 << channel_no);
-       req.method = TWL4030_MADC_SW2;
-       req.active = 0;
-       req.func_cb = NULL;
-       ret = twl4030_madc_conversion(&req);
-       if (ret < 0)
-               return ret;
-       if (req.rbuf[channel_no] > 0)
-               temp = req.rbuf[channel_no];
-
-       return temp;
-}
-EXPORT_SYMBOL_GPL(twl4030_get_madc_conversion);
-
-/*
- * Function to enable or disable bias current for
- * main battery type reading or temperature sensing
- * @madc - pointer to twl4030_madc_data struct
- * @chan - can be one of the two values
- * TWL4030_BCI_ITHEN - Enables bias current for main battery type reading
- * TWL4030_BCI_TYPEN - Enables bias current for main battery temperature
- * sensing
- * @on - enable or disable chan.
- */
-static int twl4030_madc_set_current_generator(struct twl4030_madc_data *madc,
-                                             int chan, int on)
-{
-       int ret;
-       u8 regval;
-
-       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
-                             &regval, TWL4030_BCI_BCICTL1);
-       if (ret) {
-               dev_err(madc->dev, "unable to read BCICTL1 reg 0x%X",
-                       TWL4030_BCI_BCICTL1);
-               return ret;
-       }
-       if (on)
-               regval |= chan ? TWL4030_BCI_ITHEN : TWL4030_BCI_TYPEN;
-       else
-               regval &= chan ? ~TWL4030_BCI_ITHEN : ~TWL4030_BCI_TYPEN;
-       ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
-                              regval, TWL4030_BCI_BCICTL1);
-       if (ret) {
-               dev_err(madc->dev, "unable to write BCICTL1 reg 0x%X\n",
-                       TWL4030_BCI_BCICTL1);
-               return ret;
-       }
-
-       return 0;
-}
-
-/*
- * Function that sets MADC software power on bit to enable MADC
- * @madc - pointer to twl4030_madc_data struct
- * @on - Enable or disable MADC software powen on bit.
- * returns error if i2c read/write fails else 0
- */
-static int twl4030_madc_set_power(struct twl4030_madc_data *madc, int on)
-{
-       u8 regval;
-       int ret;
-
-       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
-                             &regval, TWL4030_MADC_CTRL1);
-       if (ret) {
-               dev_err(madc->dev, "unable to read madc ctrl1 reg 0x%X\n",
-                       TWL4030_MADC_CTRL1);
-               return ret;
-       }
-       if (on)
-               regval |= TWL4030_MADC_MADCON;
-       else
-               regval &= ~TWL4030_MADC_MADCON;
-       ret = twl_i2c_write_u8(TWL4030_MODULE_MADC, regval, TWL4030_MADC_CTRL1);
-       if (ret) {
-               dev_err(madc->dev, "unable to write madc ctrl1 reg 0x%X\n",
-                       TWL4030_MADC_CTRL1);
-               return ret;
-       }
-
-       return 0;
-}
-
-/*
- * Initialize MADC and request for threaded irq
- */
-static int twl4030_madc_probe(struct platform_device *pdev)
-{
-       struct twl4030_madc_data *madc;
-       struct twl4030_madc_platform_data *pdata = dev_get_platdata(&pdev->dev);
-       int ret;
-       u8 regval;
-
-       if (!pdata) {
-               dev_err(&pdev->dev, "platform_data not available\n");
-               return -EINVAL;
-       }
-       madc = kzalloc(sizeof(*madc), GFP_KERNEL);
-       if (!madc)
-               return -ENOMEM;
-
-       madc->dev = &pdev->dev;
-
-       /*
-        * Phoenix provides 2 interrupt lines. The first one is connected to
-        * the OMAP. The other one can be connected to the other processor such
-        * as modem. Hence two separate ISR and IMR registers.
-        */
-       madc->imr = (pdata->irq_line == 1) ?
-           TWL4030_MADC_IMR1 : TWL4030_MADC_IMR2;
-       madc->isr = (pdata->irq_line == 1) ?
-           TWL4030_MADC_ISR1 : TWL4030_MADC_ISR2;
-       ret = twl4030_madc_set_power(madc, 1);
-       if (ret < 0)
-               goto err_power;
-       ret = twl4030_madc_set_current_generator(madc, 0, 1);
-       if (ret < 0)
-               goto err_current_generator;
-
-       ret = twl_i2c_read_u8(TWL_MODULE_MAIN_CHARGE,
-                             &regval, TWL4030_BCI_BCICTL1);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to read reg BCI CTL1 0x%X\n",
-                       TWL4030_BCI_BCICTL1);
-               goto err_i2c;
-       }
-       regval |= TWL4030_BCI_MESBAT;
-       ret = twl_i2c_write_u8(TWL_MODULE_MAIN_CHARGE,
-                              regval, TWL4030_BCI_BCICTL1);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to write reg BCI Ctl1 0x%X\n",
-                       TWL4030_BCI_BCICTL1);
-               goto err_i2c;
-       }
-
-       /* Check that MADC clock is on */
-       ret = twl_i2c_read_u8(TWL4030_MODULE_INTBR, &regval, TWL4030_REG_GPBR1);
-       if (ret) {
-               dev_err(&pdev->dev, "unable to read reg GPBR1 0x%X\n",
-                               TWL4030_REG_GPBR1);
-               goto err_i2c;
-       }
-
-       /* If MADC clk is not on, turn it on */
-       if (!(regval & TWL4030_GPBR1_MADC_HFCLK_EN)) {
-               dev_info(&pdev->dev, "clk disabled, enabling\n");
-               regval |= TWL4030_GPBR1_MADC_HFCLK_EN;
-               ret = twl_i2c_write_u8(TWL4030_MODULE_INTBR, regval,
-                                      TWL4030_REG_GPBR1);
-               if (ret) {
-                       dev_err(&pdev->dev, "unable to write reg GPBR1 0x%X\n",
-                                       TWL4030_REG_GPBR1);
-                       goto err_i2c;
-               }
-       }
-
-       platform_set_drvdata(pdev, madc);
-       mutex_init(&madc->lock);
-       ret = request_threaded_irq(platform_get_irq(pdev, 0), NULL,
-                                  twl4030_madc_threaded_irq_handler,
-                                  IRQF_TRIGGER_RISING, "twl4030_madc", madc);
-       if (ret) {
-               dev_dbg(&pdev->dev, "could not request irq\n");
-               goto err_i2c;
-       }
-       twl4030_madc = madc;
-       return 0;
-err_i2c:
-       twl4030_madc_set_current_generator(madc, 0, 0);
-err_current_generator:
-       twl4030_madc_set_power(madc, 0);
-err_power:
-       kfree(madc);
-
-       return ret;
-}
-
-static int twl4030_madc_remove(struct platform_device *pdev)
-{
-       struct twl4030_madc_data *madc = platform_get_drvdata(pdev);
-
-       free_irq(platform_get_irq(pdev, 0), madc);
-       twl4030_madc_set_current_generator(madc, 0, 0);
-       twl4030_madc_set_power(madc, 0);
-       kfree(madc);
-
-       return 0;
-}
-
-static struct platform_driver twl4030_madc_driver = {
-       .probe = twl4030_madc_probe,
-       .remove = twl4030_madc_remove,
-       .driver = {
-                  .name = "twl4030_madc",
-                  .owner = THIS_MODULE,
-                  },
-};
-
-module_platform_driver(twl4030_madc_driver);
-
-MODULE_DESCRIPTION("TWL4030 ADC driver");
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("J Keerthy");
-MODULE_ALIAS("platform:twl4030_madc");
index 18a607e..a6bb17d 100644 (file)
@@ -31,7 +31,6 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  */
 
-#include <linux/init.h>
 #include <linux/export.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
index 75316fb..6e88f25 100644 (file)
@@ -661,6 +661,11 @@ static int twl6040_probe(struct i2c_client *client,
        init_completion(&twl6040->ready);
 
        twl6040->rev = twl6040_reg_read(twl6040, TWL6040_REG_ASICREV);
+       if (twl6040->rev < 0) {
+               dev_err(&client->dev, "Failed to read revision register: %d\n",
+                       twl6040->rev);
+               goto gpio_err;
+       }
 
        /* ERRATA: Automatic power-up is not possible in ES1.0 */
        if (twl6040_get_revid(twl6040) > TWL6040_REV_ES1_0)
@@ -703,7 +708,6 @@ static int twl6040_probe(struct i2c_client *client,
        }
 
        /* dual-access registers controlled by I2C only */
-       twl6040_set_bits(twl6040, TWL6040_REG_ACCCTL, TWL6040_I2CSEL);
        regmap_register_patch(twl6040->regmap, twl6040_patch,
                              ARRAY_SIZE(twl6040_patch));
 
index 0313f83..153d595 100644 (file)
@@ -742,9 +742,7 @@ static int ucb1x00_resume(struct device *dev)
 }
 #endif
 
-static const struct dev_pm_ops ucb1x00_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(ucb1x00_suspend, ucb1x00_resume)
-};
+static SIMPLE_DEV_PM_OPS(ucb1x00_pm_ops, ucb1x00_suspend, ucb1x00_resume);
 
 static struct mcp_driver ucb1x00_driver = {
        .drv            = {
index 84ce6b9..d0db89d 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/bitops.h>
 #include <linux/completion.h>
 #include <linux/export.h>
-#include <linux/init.h>
 #include <linux/list.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
@@ -27,7 +26,7 @@
 
 #define VEXPRESS_CONFIG_MAX_BRIDGES 2
 
-struct vexpress_config_bridge {
+static struct vexpress_config_bridge {
        struct device_node *node;
        struct vexpress_config_bridge_info *info;
        struct list_head transactions;
index 981bef4..35281e8 100644 (file)
@@ -168,7 +168,7 @@ static void *vexpress_sysreg_config_func_get(struct device *dev,
                struct device_node *node)
 {
        struct vexpress_sysreg_config_func *config_func;
-       u32 site;
+       u32 site = 0;
        u32 position = 0;
        u32 dcc = 0;
        u32 func_device[2];
index bffc584..070f8cf 100644 (file)
@@ -73,6 +73,7 @@ static const struct reg_default wm5102_revb_patch[] = {
        { 0x171, 0x0000 },
        { 0x35E, 0x000C },
        { 0x2D4, 0x0000 },
+       { 0x4DC, 0x0900 },
        { 0x80, 0x0000 },
 };
 
@@ -1839,6 +1840,23 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
        case ARIZONA_DSP1_STATUS_3:
+       case ARIZONA_DSP1_WDMA_BUFFER_1:
+       case ARIZONA_DSP1_WDMA_BUFFER_2:
+       case ARIZONA_DSP1_WDMA_BUFFER_3:
+       case ARIZONA_DSP1_WDMA_BUFFER_4:
+       case ARIZONA_DSP1_WDMA_BUFFER_5:
+       case ARIZONA_DSP1_WDMA_BUFFER_6:
+       case ARIZONA_DSP1_WDMA_BUFFER_7:
+       case ARIZONA_DSP1_WDMA_BUFFER_8:
+       case ARIZONA_DSP1_RDMA_BUFFER_1:
+       case ARIZONA_DSP1_RDMA_BUFFER_2:
+       case ARIZONA_DSP1_RDMA_BUFFER_3:
+       case ARIZONA_DSP1_RDMA_BUFFER_4:
+       case ARIZONA_DSP1_RDMA_BUFFER_5:
+       case ARIZONA_DSP1_RDMA_BUFFER_6:
+       case ARIZONA_DSP1_WDMA_CONFIG_1:
+       case ARIZONA_DSP1_WDMA_CONFIG_2:
+       case ARIZONA_DSP1_RDMA_CONFIG_1:
        case ARIZONA_DSP1_SCRATCH_0:
        case ARIZONA_DSP1_SCRATCH_1:
        case ARIZONA_DSP1_SCRATCH_2:
@@ -1894,9 +1912,27 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
        case ARIZONA_AOD_IRQ1:
        case ARIZONA_AOD_IRQ2:
        case ARIZONA_AOD_IRQ_RAW_STATUS:
+       case ARIZONA_DSP1_CLOCKING_1:
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
        case ARIZONA_DSP1_STATUS_3:
+       case ARIZONA_DSP1_WDMA_BUFFER_1:
+       case ARIZONA_DSP1_WDMA_BUFFER_2:
+       case ARIZONA_DSP1_WDMA_BUFFER_3:
+       case ARIZONA_DSP1_WDMA_BUFFER_4:
+       case ARIZONA_DSP1_WDMA_BUFFER_5:
+       case ARIZONA_DSP1_WDMA_BUFFER_6:
+       case ARIZONA_DSP1_WDMA_BUFFER_7:
+       case ARIZONA_DSP1_WDMA_BUFFER_8:
+       case ARIZONA_DSP1_RDMA_BUFFER_1:
+       case ARIZONA_DSP1_RDMA_BUFFER_2:
+       case ARIZONA_DSP1_RDMA_BUFFER_3:
+       case ARIZONA_DSP1_RDMA_BUFFER_4:
+       case ARIZONA_DSP1_RDMA_BUFFER_5:
+       case ARIZONA_DSP1_RDMA_BUFFER_6:
+       case ARIZONA_DSP1_WDMA_CONFIG_1:
+       case ARIZONA_DSP1_WDMA_CONFIG_2:
+       case ARIZONA_DSP1_RDMA_CONFIG_1:
        case ARIZONA_DSP1_SCRATCH_0:
        case ARIZONA_DSP1_SCRATCH_1:
        case ARIZONA_DSP1_SCRATCH_2:
index 11632f1..1942b6f 100644 (file)
@@ -538,7 +538,7 @@ static const struct reg_default wm5110_reg_default[] = {
        { 0x00000219, 0x01A6 },    /* R537   - Mic Bias Ctrl 2 */
        { 0x0000021A, 0x01A6 },    /* R538   - Mic Bias Ctrl 3 */
        { 0x00000293, 0x0000 },    /* R659   - Accessory Detect Mode 1 */
-       { 0x0000029B, 0x0020 },    /* R667   - Headphone Detect 1 */
+       { 0x0000029B, 0x0028 },    /* R667   - Headphone Detect 1 */
        { 0x0000029C, 0x0000 },    /* R668   - Headphone Detect 2 */
        { 0x000002A2, 0x0000 },    /* R674   - Micd clamp control */
        { 0x000002A3, 0x1102 },    /* R675   - Mic Detect 1 */
@@ -2461,6 +2461,27 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
        case ARIZONA_DSP1_STATUS_3:
+       case ARIZONA_DSP1_STATUS_4:
+       case ARIZONA_DSP1_WDMA_BUFFER_1:
+       case ARIZONA_DSP1_WDMA_BUFFER_2:
+       case ARIZONA_DSP1_WDMA_BUFFER_3:
+       case ARIZONA_DSP1_WDMA_BUFFER_4:
+       case ARIZONA_DSP1_WDMA_BUFFER_5:
+       case ARIZONA_DSP1_WDMA_BUFFER_6:
+       case ARIZONA_DSP1_WDMA_BUFFER_7:
+       case ARIZONA_DSP1_WDMA_BUFFER_8:
+       case ARIZONA_DSP1_RDMA_BUFFER_1:
+       case ARIZONA_DSP1_RDMA_BUFFER_2:
+       case ARIZONA_DSP1_RDMA_BUFFER_3:
+       case ARIZONA_DSP1_RDMA_BUFFER_4:
+       case ARIZONA_DSP1_RDMA_BUFFER_5:
+       case ARIZONA_DSP1_RDMA_BUFFER_6:
+       case ARIZONA_DSP1_WDMA_CONFIG_1:
+       case ARIZONA_DSP1_WDMA_CONFIG_2:
+       case ARIZONA_DSP1_WDMA_OFFSET_1:
+       case ARIZONA_DSP1_RDMA_CONFIG_1:
+       case ARIZONA_DSP1_RDMA_OFFSET_1:
+       case ARIZONA_DSP1_EXTERNAL_START_SELECT_1:
        case ARIZONA_DSP1_SCRATCH_0:
        case ARIZONA_DSP1_SCRATCH_1:
        case ARIZONA_DSP1_SCRATCH_2:
@@ -2470,6 +2491,27 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP2_STATUS_1:
        case ARIZONA_DSP2_STATUS_2:
        case ARIZONA_DSP2_STATUS_3:
+       case ARIZONA_DSP2_STATUS_4:
+       case ARIZONA_DSP2_WDMA_BUFFER_1:
+       case ARIZONA_DSP2_WDMA_BUFFER_2:
+       case ARIZONA_DSP2_WDMA_BUFFER_3:
+       case ARIZONA_DSP2_WDMA_BUFFER_4:
+       case ARIZONA_DSP2_WDMA_BUFFER_5:
+       case ARIZONA_DSP2_WDMA_BUFFER_6:
+       case ARIZONA_DSP2_WDMA_BUFFER_7:
+       case ARIZONA_DSP2_WDMA_BUFFER_8:
+       case ARIZONA_DSP2_RDMA_BUFFER_1:
+       case ARIZONA_DSP2_RDMA_BUFFER_2:
+       case ARIZONA_DSP2_RDMA_BUFFER_3:
+       case ARIZONA_DSP2_RDMA_BUFFER_4:
+       case ARIZONA_DSP2_RDMA_BUFFER_5:
+       case ARIZONA_DSP2_RDMA_BUFFER_6:
+       case ARIZONA_DSP2_WDMA_CONFIG_1:
+       case ARIZONA_DSP2_WDMA_CONFIG_2:
+       case ARIZONA_DSP2_WDMA_OFFSET_1:
+       case ARIZONA_DSP2_RDMA_CONFIG_1:
+       case ARIZONA_DSP2_RDMA_OFFSET_1:
+       case ARIZONA_DSP2_EXTERNAL_START_SELECT_1:
        case ARIZONA_DSP2_SCRATCH_0:
        case ARIZONA_DSP2_SCRATCH_1:
        case ARIZONA_DSP2_SCRATCH_2:
@@ -2479,6 +2521,27 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP3_STATUS_1:
        case ARIZONA_DSP3_STATUS_2:
        case ARIZONA_DSP3_STATUS_3:
+       case ARIZONA_DSP3_STATUS_4:
+       case ARIZONA_DSP3_WDMA_BUFFER_1:
+       case ARIZONA_DSP3_WDMA_BUFFER_2:
+       case ARIZONA_DSP3_WDMA_BUFFER_3:
+       case ARIZONA_DSP3_WDMA_BUFFER_4:
+       case ARIZONA_DSP3_WDMA_BUFFER_5:
+       case ARIZONA_DSP3_WDMA_BUFFER_6:
+       case ARIZONA_DSP3_WDMA_BUFFER_7:
+       case ARIZONA_DSP3_WDMA_BUFFER_8:
+       case ARIZONA_DSP3_RDMA_BUFFER_1:
+       case ARIZONA_DSP3_RDMA_BUFFER_2:
+       case ARIZONA_DSP3_RDMA_BUFFER_3:
+       case ARIZONA_DSP3_RDMA_BUFFER_4:
+       case ARIZONA_DSP3_RDMA_BUFFER_5:
+       case ARIZONA_DSP3_RDMA_BUFFER_6:
+       case ARIZONA_DSP3_WDMA_CONFIG_1:
+       case ARIZONA_DSP3_WDMA_CONFIG_2:
+       case ARIZONA_DSP3_WDMA_OFFSET_1:
+       case ARIZONA_DSP3_RDMA_CONFIG_1:
+       case ARIZONA_DSP3_RDMA_OFFSET_1:
+       case ARIZONA_DSP3_EXTERNAL_START_SELECT_1:
        case ARIZONA_DSP3_SCRATCH_0:
        case ARIZONA_DSP3_SCRATCH_1:
        case ARIZONA_DSP3_SCRATCH_2:
@@ -2488,6 +2551,27 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP4_STATUS_1:
        case ARIZONA_DSP4_STATUS_2:
        case ARIZONA_DSP4_STATUS_3:
+       case ARIZONA_DSP4_STATUS_4:
+       case ARIZONA_DSP4_WDMA_BUFFER_1:
+       case ARIZONA_DSP4_WDMA_BUFFER_2:
+       case ARIZONA_DSP4_WDMA_BUFFER_3:
+       case ARIZONA_DSP4_WDMA_BUFFER_4:
+       case ARIZONA_DSP4_WDMA_BUFFER_5:
+       case ARIZONA_DSP4_WDMA_BUFFER_6:
+       case ARIZONA_DSP4_WDMA_BUFFER_7:
+       case ARIZONA_DSP4_WDMA_BUFFER_8:
+       case ARIZONA_DSP4_RDMA_BUFFER_1:
+       case ARIZONA_DSP4_RDMA_BUFFER_2:
+       case ARIZONA_DSP4_RDMA_BUFFER_3:
+       case ARIZONA_DSP4_RDMA_BUFFER_4:
+       case ARIZONA_DSP4_RDMA_BUFFER_5:
+       case ARIZONA_DSP4_RDMA_BUFFER_6:
+       case ARIZONA_DSP4_WDMA_CONFIG_1:
+       case ARIZONA_DSP4_WDMA_CONFIG_2:
+       case ARIZONA_DSP4_WDMA_OFFSET_1:
+       case ARIZONA_DSP4_RDMA_CONFIG_1:
+       case ARIZONA_DSP4_RDMA_OFFSET_1:
+       case ARIZONA_DSP4_EXTERNAL_START_SELECT_1:
        case ARIZONA_DSP4_SCRATCH_0:
        case ARIZONA_DSP4_SCRATCH_1:
        case ARIZONA_DSP4_SCRATCH_2:
@@ -2543,31 +2627,119 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
        case ARIZONA_DSP1_STATUS_1:
        case ARIZONA_DSP1_STATUS_2:
        case ARIZONA_DSP1_STATUS_3:
+       case ARIZONA_DSP1_STATUS_4:
+       case ARIZONA_DSP1_WDMA_BUFFER_1:
+       case ARIZONA_DSP1_WDMA_BUFFER_2:
+       case ARIZONA_DSP1_WDMA_BUFFER_3:
+       case ARIZONA_DSP1_WDMA_BUFFER_4:
+       case ARIZONA_DSP1_WDMA_BUFFER_5:
+       case ARIZONA_DSP1_WDMA_BUFFER_6:
+       case ARIZONA_DSP1_WDMA_BUFFER_7:
+       case ARIZONA_DSP1_WDMA_BUFFER_8:
+       case ARIZONA_DSP1_RDMA_BUFFER_1:
+       case ARIZONA_DSP1_RDMA_BUFFER_2:
+       case ARIZONA_DSP1_RDMA_BUFFER_3:
+       case ARIZONA_DSP1_RDMA_BUFFER_4:
+       case ARIZONA_DSP1_RDMA_BUFFER_5:
+       case ARIZONA_DSP1_RDMA_BUFFER_6:
+       case ARIZONA_DSP1_WDMA_CONFIG_1:
+       case ARIZONA_DSP1_WDMA_CONFIG_2:
+       case ARIZONA_DSP1_WDMA_OFFSET_1:
+       case ARIZONA_DSP1_RDMA_CONFIG_1:
+       case ARIZONA_DSP1_RDMA_OFFSET_1:
+       case ARIZONA_DSP1_EXTERNAL_START_SELECT_1:
        case ARIZONA_DSP1_SCRATCH_0:
        case ARIZONA_DSP1_SCRATCH_1:
        case ARIZONA_DSP1_SCRATCH_2:
        case ARIZONA_DSP1_SCRATCH_3:
+       case ARIZONA_DSP1_CLOCKING_1:
        case ARIZONA_DSP2_STATUS_1:
        case ARIZONA_DSP2_STATUS_2:
        case ARIZONA_DSP2_STATUS_3:
+       case ARIZONA_DSP2_STATUS_4:
+       case ARIZONA_DSP2_WDMA_BUFFER_1:
+       case ARIZONA_DSP2_WDMA_BUFFER_2:
+       case ARIZONA_DSP2_WDMA_BUFFER_3:
+       case ARIZONA_DSP2_WDMA_BUFFER_4:
+       case ARIZONA_DSP2_WDMA_BUFFER_5:
+       case ARIZONA_DSP2_WDMA_BUFFER_6:
+       case ARIZONA_DSP2_WDMA_BUFFER_7:
+       case ARIZONA_DSP2_WDMA_BUFFER_8:
+       case ARIZONA_DSP2_RDMA_BUFFER_1:
+       case ARIZONA_DSP2_RDMA_BUFFER_2:
+       case ARIZONA_DSP2_RDMA_BUFFER_3:
+       case ARIZONA_DSP2_RDMA_BUFFER_4:
+       case ARIZONA_DSP2_RDMA_BUFFER_5:
+       case ARIZONA_DSP2_RDMA_BUFFER_6:
+       case ARIZONA_DSP2_WDMA_CONFIG_1:
+       case ARIZONA_DSP2_WDMA_CONFIG_2:
+       case ARIZONA_DSP2_WDMA_OFFSET_1:
+       case ARIZONA_DSP2_RDMA_CONFIG_1:
+       case ARIZONA_DSP2_RDMA_OFFSET_1:
+       case ARIZONA_DSP2_EXTERNAL_START_SELECT_1:
        case ARIZONA_DSP2_SCRATCH_0:
        case ARIZONA_DSP2_SCRATCH_1:
        case ARIZONA_DSP2_SCRATCH_2:
        case ARIZONA_DSP2_SCRATCH_3:
+       case ARIZONA_DSP2_CLOCKING_1:
        case ARIZONA_DSP3_STATUS_1:
        case ARIZONA_DSP3_STATUS_2:
        case ARIZONA_DSP3_STATUS_3:
+       case ARIZONA_DSP3_STATUS_4:
+       case ARIZONA_DSP3_WDMA_BUFFER_1:
+       case ARIZONA_DSP3_WDMA_BUFFER_2:
+       case ARIZONA_DSP3_WDMA_BUFFER_3:
+       case ARIZONA_DSP3_WDMA_BUFFER_4:
+       case ARIZONA_DSP3_WDMA_BUFFER_5:
+       case ARIZONA_DSP3_WDMA_BUFFER_6:
+       case ARIZONA_DSP3_WDMA_BUFFER_7:
+       case ARIZONA_DSP3_WDMA_BUFFER_8:
+       case ARIZONA_DSP3_RDMA_BUFFER_1:
+       case ARIZONA_DSP3_RDMA_BUFFER_2:
+       case ARIZONA_DSP3_RDMA_BUFFER_3:
+       case ARIZONA_DSP3_RDMA_BUFFER_4:
+       case ARIZONA_DSP3_RDMA_BUFFER_5:
+       case ARIZONA_DSP3_RDMA_BUFFER_6:
+       case ARIZONA_DSP3_WDMA_CONFIG_1:
+       case ARIZONA_DSP3_WDMA_CONFIG_2:
+       case ARIZONA_DSP3_WDMA_OFFSET_1:
+       case ARIZONA_DSP3_RDMA_CONFIG_1:
+       case ARIZONA_DSP3_RDMA_OFFSET_1:
+       case ARIZONA_DSP3_EXTERNAL_START_SELECT_1:
        case ARIZONA_DSP3_SCRATCH_0:
        case ARIZONA_DSP3_SCRATCH_1:
        case ARIZONA_DSP3_SCRATCH_2:
        case ARIZONA_DSP3_SCRATCH_3:
+       case ARIZONA_DSP3_CLOCKING_1:
        case ARIZONA_DSP4_STATUS_1:
        case ARIZONA_DSP4_STATUS_2:
        case ARIZONA_DSP4_STATUS_3:
+       case ARIZONA_DSP4_STATUS_4:
+       case ARIZONA_DSP4_WDMA_BUFFER_1:
+       case ARIZONA_DSP4_WDMA_BUFFER_2:
+       case ARIZONA_DSP4_WDMA_BUFFER_3:
+       case ARIZONA_DSP4_WDMA_BUFFER_4:
+       case ARIZONA_DSP4_WDMA_BUFFER_5:
+       case ARIZONA_DSP4_WDMA_BUFFER_6:
+       case ARIZONA_DSP4_WDMA_BUFFER_7:
+       case ARIZONA_DSP4_WDMA_BUFFER_8:
+       case ARIZONA_DSP4_RDMA_BUFFER_1:
+       case ARIZONA_DSP4_RDMA_BUFFER_2:
+       case ARIZONA_DSP4_RDMA_BUFFER_3:
+       case ARIZONA_DSP4_RDMA_BUFFER_4:
+       case ARIZONA_DSP4_RDMA_BUFFER_5:
+       case ARIZONA_DSP4_RDMA_BUFFER_6:
+       case ARIZONA_DSP4_WDMA_CONFIG_1:
+       case ARIZONA_DSP4_WDMA_CONFIG_2:
+       case ARIZONA_DSP4_WDMA_OFFSET_1:
+       case ARIZONA_DSP4_RDMA_CONFIG_1:
+       case ARIZONA_DSP4_RDMA_OFFSET_1:
+       case ARIZONA_DSP4_EXTERNAL_START_SELECT_1:
        case ARIZONA_DSP4_SCRATCH_0:
        case ARIZONA_DSP4_SCRATCH_1:
        case ARIZONA_DSP4_SCRATCH_2:
        case ARIZONA_DSP4_SCRATCH_3:
+       case ARIZONA_DSP4_CLOCKING_1:
                return true;
        default:
                return wm5110_is_adsp_memory(dev, reg);
index 7c1ae24..4ab527f 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/bug.h>
 #include <linux/device.h>
index 624ff90..cd01f79 100644 (file)
@@ -14,7 +14,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/bug.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
index d66d256..e5eae75 100644 (file)
@@ -161,31 +161,19 @@ static int wm8400_i2c_probe(struct i2c_client *i2c,
                            const struct i2c_device_id *id)
 {
        struct wm8400 *wm8400;
-       int ret;
 
        wm8400 = devm_kzalloc(&i2c->dev, sizeof(struct wm8400), GFP_KERNEL);
-       if (wm8400 == NULL) {
-               ret = -ENOMEM;
-               goto err;
-       }
+       if (!wm8400)
+               return -ENOMEM;
 
        wm8400->regmap = devm_regmap_init_i2c(i2c, &wm8400_regmap_config);
-       if (IS_ERR(wm8400->regmap)) {
-               ret = PTR_ERR(wm8400->regmap);
-               goto err;
-       }
+       if (IS_ERR(wm8400->regmap))
+               return PTR_ERR(wm8400->regmap);
 
        wm8400->dev = &i2c->dev;
        i2c_set_clientdata(i2c, wm8400);
 
-       ret = wm8400_init(wm8400, dev_get_platdata(&i2c->dev));
-       if (ret != 0)
-               goto err;
-
-       return 0;
-
-err:
-       return ret;
+       return wm8400_init(wm8400, dev_get_platdata(&i2c->dev));
 }
 
 static int wm8400_i2c_remove(struct i2c_client *i2c)
index 2bef3f7..a3700a5 100644 (file)
@@ -178,10 +178,10 @@ static int gru_dump_context(struct gru_state *gru, int ctxnum,
        hdr.cbrcnt = cbrcnt;
        hdr.dsrcnt = dsrcnt;
        hdr.cch_locked = cch_locked;
-       if (!ret && copy_to_user((void __user *)uhdr, &hdr, sizeof(hdr)))
-               ret = -EFAULT;
+       if (copy_to_user(uhdr, &hdr, sizeof(hdr)))
+               return -EFAULT;
 
-       return ret ? ret : bytes;
+       return bytes;
 }
 
 int gru_dump_chiplet_request(unsigned long arg)
index 7b5424f..452782b 100644 (file)
@@ -415,8 +415,7 @@ static int ioctl_do_sanitize(struct mmc_card *card)
 {
        int err;
 
-       if (!(mmc_can_sanitize(card) &&
-             (card->host->caps2 & MMC_CAP2_SANITIZE))) {
+       if (!mmc_can_sanitize(card)) {
                        pr_warn("%s: %s - SANITIZE is not supported\n",
                                mmc_hostname(card->host), __func__);
                        err = -EOPNOTSUPP;
@@ -722,19 +721,6 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
        return result;
 }
 
-static int send_stop(struct mmc_card *card, u32 *status)
-{
-       struct mmc_command cmd = {0};
-       int err;
-
-       cmd.opcode = MMC_STOP_TRANSMISSION;
-       cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-       err = mmc_wait_for_cmd(card->host, &cmd, 5);
-       if (err == 0)
-               *status = cmd.resp[0];
-       return err;
-}
-
 static int get_card_status(struct mmc_card *card, u32 *status, int retries)
 {
        struct mmc_command cmd = {0};
@@ -750,6 +736,99 @@ static int get_card_status(struct mmc_card *card, u32 *status, int retries)
        return err;
 }
 
+static int card_busy_detect(struct mmc_card *card, unsigned int timeout_ms,
+               bool hw_busy_detect, struct request *req, int *gen_err)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(timeout_ms);
+       int err = 0;
+       u32 status;
+
+       do {
+               err = get_card_status(card, &status, 5);
+               if (err) {
+                       pr_err("%s: error %d requesting status\n",
+                              req->rq_disk->disk_name, err);
+                       return err;
+               }
+
+               if (status & R1_ERROR) {
+                       pr_err("%s: %s: error sending status cmd, status %#x\n",
+                               req->rq_disk->disk_name, __func__, status);
+                       *gen_err = 1;
+               }
+
+               /* We may rely on the host hw to handle busy detection.*/
+               if ((card->host->caps & MMC_CAP_WAIT_WHILE_BUSY) &&
+                       hw_busy_detect)
+                       break;
+
+               /*
+                * Timeout if the device never becomes ready for data and never
+                * leaves the program state.
+                */
+               if (time_after(jiffies, timeout)) {
+                       pr_err("%s: Card stuck in programming state! %s %s\n",
+                               mmc_hostname(card->host),
+                               req->rq_disk->disk_name, __func__);
+                       return -ETIMEDOUT;
+               }
+
+               /*
+                * Some cards mishandle the status bits,
+                * so make sure to check both the busy
+                * indication and the card state.
+                */
+       } while (!(status & R1_READY_FOR_DATA) ||
+                (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+
+       return err;
+}
+
+static int send_stop(struct mmc_card *card, unsigned int timeout_ms,
+               struct request *req, int *gen_err, u32 *stop_status)
+{
+       struct mmc_host *host = card->host;
+       struct mmc_command cmd = {0};
+       int err;
+       bool use_r1b_resp = rq_data_dir(req) == WRITE;
+
+       /*
+        * Normally we use R1B responses for WRITE, but in cases where the host
+        * has specified a max_busy_timeout we need to validate it. A failure
+        * means we need to prevent the host from doing hw busy detection, which
+        * is done by converting to a R1 response instead.
+        */
+       if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout))
+               use_r1b_resp = false;
+
+       cmd.opcode = MMC_STOP_TRANSMISSION;
+       if (use_r1b_resp) {
+               cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+               cmd.busy_timeout = timeout_ms;
+       } else {
+               cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+       }
+
+       err = mmc_wait_for_cmd(host, &cmd, 5);
+       if (err)
+               return err;
+
+       *stop_status = cmd.resp[0];
+
+       /* No need to check card status in case of READ. */
+       if (rq_data_dir(req) == READ)
+               return 0;
+
+       if (!mmc_host_is_spi(host) &&
+               (*stop_status & R1_ERROR)) {
+               pr_err("%s: %s: general error sending stop command, resp %#x\n",
+                       req->rq_disk->disk_name, __func__, *stop_status);
+               *gen_err = 1;
+       }
+
+       return card_busy_detect(card, timeout_ms, use_r1b_resp, req, gen_err);
+}
+
 #define ERR_NOMEDIUM   3
 #define ERR_RETRY      2
 #define ERR_ABORT      1
@@ -866,26 +945,21 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
         */
        if (R1_CURRENT_STATE(status) == R1_STATE_DATA ||
            R1_CURRENT_STATE(status) == R1_STATE_RCV) {
-               err = send_stop(card, &stop_status);
-               if (err)
+               err = send_stop(card,
+                       DIV_ROUND_UP(brq->data.timeout_ns, 1000000),
+                       req, gen_err, &stop_status);
+               if (err) {
                        pr_err("%s: error %d sending stop command\n",
                               req->rq_disk->disk_name, err);
-
-               /*
-                * If the stop cmd also timed out, the card is probably
-                * not present, so abort.  Other errors are bad news too.
-                */
-               if (err)
+                       /*
+                        * If the stop cmd also timed out, the card is probably
+                        * not present, so abort. Other errors are bad news too.
+                        */
                        return ERR_ABORT;
+               }
+
                if (stop_status & R1_CARD_ECC_FAILED)
                        *ecc_err = 1;
-               if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ)
-                       if (stop_status & R1_ERROR) {
-                               pr_err("%s: %s: general error sending stop command, stop cmd response %#x\n",
-                                      req->rq_disk->disk_name, __func__,
-                                      stop_status);
-                               *gen_err = 1;
-                       }
        }
 
        /* Check for set block count errors */
@@ -1157,8 +1231,7 @@ static int mmc_blk_err_check(struct mmc_card *card,
         * program mode, which we have to wait for it to complete.
         */
        if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
-               u32 status;
-               unsigned long timeout;
+               int err;
 
                /* Check stop command response */
                if (brq->stop.resp[0] & R1_ERROR) {
@@ -1168,39 +1241,10 @@ static int mmc_blk_err_check(struct mmc_card *card,
                        gen_err = 1;
                }
 
-               timeout = jiffies + msecs_to_jiffies(MMC_BLK_TIMEOUT_MS);
-               do {
-                       int err = get_card_status(card, &status, 5);
-                       if (err) {
-                               pr_err("%s: error %d requesting status\n",
-                                      req->rq_disk->disk_name, err);
-                               return MMC_BLK_CMD_ERR;
-                       }
-
-                       if (status & R1_ERROR) {
-                               pr_err("%s: %s: general error sending status command, card status %#x\n",
-                                      req->rq_disk->disk_name, __func__,
-                                      status);
-                               gen_err = 1;
-                       }
-
-                       /* Timeout if the device never becomes ready for data
-                        * and never leaves the program state.
-                        */
-                       if (time_after(jiffies, timeout)) {
-                               pr_err("%s: Card stuck in programming state!"\
-                                       " %s %s\n", mmc_hostname(card->host),
-                                       req->rq_disk->disk_name, __func__);
-
-                               return MMC_BLK_CMD_ERR;
-                       }
-                       /*
-                        * Some cards mishandle the status bits,
-                        * so make sure to check both the busy
-                        * indication and the card state.
-                        */
-               } while (!(status & R1_READY_FOR_DATA) ||
-                        (R1_CURRENT_STATE(status) == R1_STATE_PRG));
+               err = card_busy_detect(card, MMC_BLK_TIMEOUT_MS, false, req,
+                                       &gen_err);
+               if (err)
+                       return MMC_BLK_CMD_ERR;
        }
 
        /* if general error occurs, retry the write operation. */
@@ -1335,7 +1379,6 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
        brq->data.blksz = 512;
        brq->stop.opcode = MMC_STOP_TRANSMISSION;
        brq->stop.arg = 0;
-       brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
        brq->data.blocks = blk_rq_sectors(req);
 
        /*
@@ -1378,9 +1421,15 @@ static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
        if (rq_data_dir(req) == READ) {
                brq->cmd.opcode = readcmd;
                brq->data.flags |= MMC_DATA_READ;
+               if (brq->mrq.stop)
+                       brq->stop.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 |
+                                       MMC_CMD_AC;
        } else {
                brq->cmd.opcode = writecmd;
                brq->data.flags |= MMC_DATA_WRITE;
+               if (brq->mrq.stop)
+                       brq->stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B |
+                                       MMC_CMD_AC;
        }
 
        if (do_rel_wr)
index 269d072..9ebee72 100644 (file)
@@ -2,21 +2,6 @@
 # MMC core configuration
 #
 
-config MMC_UNSAFE_RESUME
-       bool "Assume MMC/SD cards are non-removable (DANGEROUS)"
-       help
-         If you say Y here, the MMC layer will assume that all cards
-         stayed in their respective slots during the suspend. The
-         normal behaviour is to remove them at suspend and
-         redetecting them at resume. Breaking this assumption will
-         in most cases result in data corruption.
-
-         This option is usually just for embedded systems which use
-         a MMC/SD card for rootfs. Most people should say N here.
-
-         This option sets a default which can be overridden by the
-         module parameter "removable=0" or "removable=1".
-
 config MMC_CLKGATE
        bool "MMC host clock gating"
        help
index 64145a3..8246448 100644 (file)
@@ -185,24 +185,16 @@ static int mmc_runtime_suspend(struct device *dev)
 {
        struct mmc_card *card = mmc_dev_to_card(dev);
        struct mmc_host *host = card->host;
-       int ret = 0;
 
-       if (host->bus_ops->runtime_suspend)
-               ret = host->bus_ops->runtime_suspend(host);
-
-       return ret;
+       return host->bus_ops->runtime_suspend(host);
 }
 
 static int mmc_runtime_resume(struct device *dev)
 {
        struct mmc_card *card = mmc_dev_to_card(dev);
        struct mmc_host *host = card->host;
-       int ret = 0;
 
-       if (host->bus_ops->runtime_resume)
-               ret = host->bus_ops->runtime_resume(host);
-
-       return ret;
+       return host->bus_ops->runtime_resume(host);
 }
 
 static int mmc_runtime_idle(struct device *dev)
index 098374b..acbc3f2 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sd.h>
+#include <linux/mmc/slot-gpio.h>
 
 #include "core.h"
 #include "bus.h"
@@ -64,23 +65,6 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
 bool use_spi_crc = 1;
 module_param(use_spi_crc, bool, 0);
 
-/*
- * We normally treat cards as removed during suspend if they are not
- * known to be on a non-removable bus, to avoid the risk of writing
- * back data to a different card after resume.  Allow this to be
- * overridden if necessary.
- */
-#ifdef CONFIG_MMC_UNSAFE_RESUME
-bool mmc_assume_removable;
-#else
-bool mmc_assume_removable = 1;
-#endif
-EXPORT_SYMBOL(mmc_assume_removable);
-module_param_named(removable, mmc_assume_removable, bool, 0644);
-MODULE_PARM_DESC(
-       removable,
-       "MMC/SD cards are removable and may be removed during suspend");
-
 /*
  * Internal function. Schedule delayed work in the MMC work queue.
  */
@@ -302,7 +286,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
        }
 
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                       EXT_CSD_BKOPS_START, 1, timeout, use_busy_signal, true);
+                       EXT_CSD_BKOPS_START, 1, timeout,
+                       use_busy_signal, true, false);
        if (err) {
                pr_warn("%s: Error %d starting bkops\n",
                        mmc_hostname(card->host), err);
@@ -1950,7 +1935,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,
        cmd.opcode = MMC_ERASE;
        cmd.arg = arg;
        cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-       cmd.cmd_timeout_ms = mmc_erase_timeout(card, arg, qty);
+       cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);
        err = mmc_wait_for_cmd(card->host, &cmd, 0);
        if (err) {
                pr_err("mmc_erase: erase error %d, status %#x\n",
@@ -2137,7 +2122,7 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
                y = 0;
                for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
                        timeout = mmc_erase_timeout(card, arg, qty + x);
-                       if (timeout > host->max_discard_to)
+                       if (timeout > host->max_busy_timeout)
                                break;
                        if (timeout < last_timeout)
                                break;
@@ -2169,7 +2154,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
        struct mmc_host *host = card->host;
        unsigned int max_discard, max_trim;
 
-       if (!host->max_discard_to)
+       if (!host->max_busy_timeout)
                return UINT_MAX;
 
        /*
@@ -2189,7 +2174,7 @@ unsigned int mmc_calc_max_discard(struct mmc_card *card)
                max_discard = 0;
        }
        pr_debug("%s: calculated max. discard sectors %u for timeout %u ms\n",
-                mmc_hostname(host), max_discard, host->max_discard_to);
+                mmc_hostname(host), max_discard, host->max_busy_timeout);
        return max_discard;
 }
 EXPORT_SYMBOL(mmc_calc_max_discard);
@@ -2248,9 +2233,6 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
 {
        struct mmc_card *card = host->card;
 
-       if (!host->bus_ops->power_restore)
-               return -EOPNOTSUPP;
-
        if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
                return -EOPNOTSUPP;
 
@@ -2352,7 +2334,7 @@ int _mmc_detect_card_removed(struct mmc_host *host)
 {
        int ret;
 
-       if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
+       if (host->caps & MMC_CAP_NONREMOVABLE)
                return 0;
 
        if (!host->card || mmc_card_removed(host->card))
@@ -2435,7 +2417,7 @@ void mmc_rescan(struct work_struct *work)
         * if there is a _removable_ card registered, check whether it is
         * still present
         */
-       if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
+       if (host->bus_ops && !host->bus_dead
            && !(host->caps & MMC_CAP_NONREMOVABLE))
                host->bus_ops->detect(host);
 
@@ -2490,6 +2472,7 @@ void mmc_start_host(struct mmc_host *host)
                mmc_power_off(host);
        else
                mmc_power_up(host, host->ocr_avail);
+       mmc_gpiod_request_cd_irq(host);
        _mmc_detect_change(host, 0, false);
 }
 
@@ -2501,6 +2484,8 @@ void mmc_stop_host(struct mmc_host *host)
        host->removed = 1;
        spin_unlock_irqrestore(&host->lock, flags);
 #endif
+       if (host->slot.cd_irq >= 0)
+               disable_irq(host->slot.cd_irq);
 
        host->rescan_disable = 1;
        cancel_delayed_work_sync(&host->detect);
@@ -2537,7 +2522,7 @@ int mmc_power_save_host(struct mmc_host *host)
 
        mmc_bus_get(host);
 
-       if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
+       if (!host->bus_ops || host->bus_dead) {
                mmc_bus_put(host);
                return -EINVAL;
        }
@@ -2563,7 +2548,7 @@ int mmc_power_restore_host(struct mmc_host *host)
 
        mmc_bus_get(host);
 
-       if (!host->bus_ops || host->bus_dead || !host->bus_ops->power_restore) {
+       if (!host->bus_ops || host->bus_dead) {
                mmc_bus_put(host);
                return -EINVAL;
        }
@@ -2582,12 +2567,8 @@ EXPORT_SYMBOL(mmc_power_restore_host);
  */
 int mmc_flush_cache(struct mmc_card *card)
 {
-       struct mmc_host *host = card->host;
        int err = 0;
 
-       if (!(host->caps2 & MMC_CAP2_CACHE_CTRL))
-               return err;
-
        if (mmc_card_mmc(card) &&
                        (card->ext_csd.cache_size > 0) &&
                        (card->ext_csd.cache_ctrl & 1)) {
@@ -2602,44 +2583,6 @@ int mmc_flush_cache(struct mmc_card *card)
 }
 EXPORT_SYMBOL(mmc_flush_cache);
 
-/*
- * Turn the cache ON/OFF.
- * Turning the cache OFF shall trigger flushing of the data
- * to the non-volatile storage.
- * This function should be called with host claimed
- */
-int mmc_cache_ctrl(struct mmc_host *host, u8 enable)
-{
-       struct mmc_card *card = host->card;
-       unsigned int timeout;
-       int err = 0;
-
-       if (!(host->caps2 & MMC_CAP2_CACHE_CTRL) ||
-                       mmc_card_is_removable(host))
-               return err;
-
-       if (card && mmc_card_mmc(card) &&
-                       (card->ext_csd.cache_size > 0)) {
-               enable = !!enable;
-
-               if (card->ext_csd.cache_ctrl ^ enable) {
-                       timeout = enable ? card->ext_csd.generic_cmd6_time : 0;
-                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                       EXT_CSD_CACHE_CTRL, enable, timeout);
-                       if (err)
-                               pr_err("%s: cache %s error %d\n",
-                                               mmc_hostname(card->host),
-                                               enable ? "on" : "off",
-                                               err);
-                       else
-                               card->ext_csd.cache_ctrl = enable;
-               }
-       }
-
-       return err;
-}
-EXPORT_SYMBOL(mmc_cache_ctrl);
-
 #ifdef CONFIG_PM
 
 /* Do the card removal on suspend if card is assumed removeable
@@ -2668,7 +2611,7 @@ int mmc_pm_notify(struct notifier_block *notify_block,
                /* Validate prerequisites for suspend */
                if (host->bus_ops->pre_suspend)
                        err = host->bus_ops->pre_suspend(host);
-               if (!err && host->bus_ops->suspend)
+               if (!err)
                        break;
 
                /* Calling bus_ops->remove() with a claimed host can deadlock */
index 114f6bd..fdea825 100644 (file)
@@ -419,6 +419,16 @@ int mmc_of_parse(struct mmc_host *host)
                host->caps |= MMC_CAP_SD_HIGHSPEED;
        if (of_find_property(np, "cap-mmc-highspeed", &len))
                host->caps |= MMC_CAP_MMC_HIGHSPEED;
+       if (of_find_property(np, "sd-uhs-sdr12", &len))
+               host->caps |= MMC_CAP_UHS_SDR12;
+       if (of_find_property(np, "sd-uhs-sdr25", &len))
+               host->caps |= MMC_CAP_UHS_SDR25;
+       if (of_find_property(np, "sd-uhs-sdr50", &len))
+               host->caps |= MMC_CAP_UHS_SDR50;
+       if (of_find_property(np, "sd-uhs-sdr104", &len))
+               host->caps |= MMC_CAP_UHS_SDR104;
+       if (of_find_property(np, "sd-uhs-ddr50", &len))
+               host->caps |= MMC_CAP_UHS_DDR50;
        if (of_find_property(np, "cap-power-off-card", &len))
                host->caps |= MMC_CAP_POWER_OFF_CARD;
        if (of_find_property(np, "cap-sdio-irq", &len))
@@ -429,6 +439,14 @@ int mmc_of_parse(struct mmc_host *host)
                host->pm_caps |= MMC_PM_KEEP_POWER;
        if (of_find_property(np, "enable-sdio-wakeup", &len))
                host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+       if (of_find_property(np, "mmc-ddr-1_8v", &len))
+               host->caps |= MMC_CAP_1_8V_DDR;
+       if (of_find_property(np, "mmc-ddr-1_2v", &len))
+               host->caps |= MMC_CAP_1_2V_DDR;
+       if (of_find_property(np, "mmc-hs200-1_8v", &len))
+               host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
+       if (of_find_property(np, "mmc-hs200-1_2v", &len))
+               host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
 
        return 0;
 
index 98e9eb0..1ab5f3a 100644 (file)
@@ -856,8 +856,10 @@ static int mmc_select_hs200(struct mmc_card *card)
 
        /* switch to HS200 mode if bus width set successfully */
        if (!err)
-               err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                EXT_CSD_HS_TIMING, 2, 0);
+               err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                               EXT_CSD_HS_TIMING, 2,
+                               card->ext_csd.generic_cmd6_time,
+                               true, true, true);
 err:
        return err;
 }
@@ -1074,9 +1076,10 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
                    host->caps2 & MMC_CAP2_HS200)
                        err = mmc_select_hs200(card);
                else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
-                       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
-                                        EXT_CSD_HS_TIMING, 1,
-                                        card->ext_csd.generic_cmd6_time);
+                       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+                                       EXT_CSD_HS_TIMING, 1,
+                                       card->ext_csd.generic_cmd6_time,
+                                       true, true, true);
 
                if (err && err != -EBADMSG)
                        goto free_card;
@@ -1287,8 +1290,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
         * If cache size is higher than 0, this indicates
         * the existence of cache and it can be turned on.
         */
-       if ((host->caps2 & MMC_CAP2_CACHE_CTRL) &&
-                       card->ext_csd.cache_size > 0) {
+       if (card->ext_csd.cache_size > 0) {
                err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                                EXT_CSD_CACHE_CTRL, 1,
                                card->ext_csd.generic_cmd6_time);
@@ -1356,11 +1358,9 @@ static int mmc_sleep(struct mmc_host *host)
 {
        struct mmc_command cmd = {0};
        struct mmc_card *card = host->card;
+       unsigned int timeout_ms = DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000);
        int err;
 
-       if (host->caps2 & MMC_CAP2_NO_SLEEP_CMD)
-               return 0;
-
        err = mmc_deselect_cards(host);
        if (err)
                return err;
@@ -1369,7 +1369,19 @@ static int mmc_sleep(struct mmc_host *host)
        cmd.arg = card->rca << 16;
        cmd.arg |= 1 << 15;
 
-       cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+       /*
+        * If the max_busy_timeout of the host is specified, validate it against
+        * the sleep cmd timeout. A failure means we need to prevent the host
+        * from doing hw busy detection, which is done by converting to a R1
+        * response instead of a R1B.
+        */
+       if (host->max_busy_timeout && (timeout_ms > host->max_busy_timeout)) {
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+       } else {
+               cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
+               cmd.busy_timeout = timeout_ms;
+       }
+
        err = mmc_wait_for_cmd(host, &cmd, 0);
        if (err)
                return err;
@@ -1380,8 +1392,8 @@ static int mmc_sleep(struct mmc_host *host)
         * SEND_STATUS command to poll the status because that command (and most
         * others) is invalid while the card sleeps.
         */
-       if (!(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
-               mmc_delay(DIV_ROUND_UP(card->ext_csd.sa_timeout, 10000));
+       if (!cmd.busy_timeout || !(host->caps & MMC_CAP_WAIT_WHILE_BUSY))
+               mmc_delay(timeout_ms);
 
        return err;
 }
@@ -1404,7 +1416,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
 
        err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
                        EXT_CSD_POWER_OFF_NOTIFICATION,
-                       notify_type, timeout, true, false);
+                       notify_type, timeout, true, false, false);
        if (err)
                pr_err("%s: Power Off Notification timed out, %u\n",
                       mmc_hostname(card->host), timeout);
@@ -1484,7 +1496,7 @@ static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
                        goto out;
        }
 
-       err = mmc_cache_ctrl(host, 0);
+       err = mmc_flush_cache(host->card);
        if (err)
                goto out;
 
@@ -1634,16 +1646,6 @@ static int mmc_power_restore(struct mmc_host *host)
 }
 
 static const struct mmc_bus_ops mmc_ops = {
-       .remove = mmc_remove,
-       .detect = mmc_detect,
-       .suspend = NULL,
-       .resume = NULL,
-       .power_restore = mmc_power_restore,
-       .alive = mmc_alive,
-       .shutdown = mmc_shutdown,
-};
-
-static const struct mmc_bus_ops mmc_ops_unsafe = {
        .remove = mmc_remove,
        .detect = mmc_detect,
        .suspend = mmc_suspend,
@@ -1655,17 +1657,6 @@ static const struct mmc_bus_ops mmc_ops_unsafe = {
        .shutdown = mmc_shutdown,
 };
 
-static void mmc_attach_bus_ops(struct mmc_host *host)
-{
-       const struct mmc_bus_ops *bus_ops;
-
-       if (!mmc_card_is_removable(host))
-               bus_ops = &mmc_ops_unsafe;
-       else
-               bus_ops = &mmc_ops;
-       mmc_attach_bus(host, bus_ops);
-}
-
 /*
  * Starting point for MMC card init.
  */
@@ -1685,7 +1676,7 @@ int mmc_attach_mmc(struct mmc_host *host)
        if (err)
                return err;
 
-       mmc_attach_bus_ops(host);
+       mmc_attach_bus(host, &mmc_ops);
        if (host->ocr_avail_mmc)
                host->ocr_avail = host->ocr_avail_mmc;
 
index e5b5eeb..f51b5ba 100644 (file)
@@ -405,20 +405,30 @@ int mmc_spi_set_crc(struct mmc_host *host, int use_crc)
  *                   timeout of zero implies maximum possible timeout
  *     @use_busy_signal: use the busy signal as response type
  *     @send_status: send status cmd to poll for busy
+ *     @ignore_crc: ignore CRC errors when sending status cmd to poll for busy
  *
  *     Modifies the EXT_CSD register for selected card.
  */
 int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
-               unsigned int timeout_ms, bool use_busy_signal, bool send_status)
+               unsigned int timeout_ms, bool use_busy_signal, bool send_status,
+               bool ignore_crc)
 {
+       struct mmc_host *host = card->host;
        int err;
        struct mmc_command cmd = {0};
        unsigned long timeout;
        u32 status = 0;
-       bool ignore_crc = false;
+       bool use_r1b_resp = use_busy_signal;
 
-       BUG_ON(!card);
-       BUG_ON(!card->host);
+       /*
+        * If the cmd timeout and the max_busy_timeout of the host are both
+        * specified, let's validate them. A failure means we need to prevent
+        * the host from doing hw busy detection, which is done by converting
+        * to a R1 response instead of a R1B.
+        */
+       if (timeout_ms && host->max_busy_timeout &&
+               (timeout_ms > host->max_busy_timeout))
+               use_r1b_resp = false;
 
        cmd.opcode = MMC_SWITCH;
        cmd.arg = (MMC_SWITCH_MODE_WRITE_BYTE << 24) |
@@ -426,17 +436,21 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                  (value << 8) |
                  set;
        cmd.flags = MMC_CMD_AC;
-       if (use_busy_signal)
+       if (use_r1b_resp) {
                cmd.flags |= MMC_RSP_SPI_R1B | MMC_RSP_R1B;
-       else
+               /*
+                * A busy_timeout of zero means the host can decide to use
+                * whatever value it finds suitable.
+                */
+               cmd.busy_timeout = timeout_ms;
+       } else {
                cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
+       }
 
-
-       cmd.cmd_timeout_ms = timeout_ms;
        if (index == EXT_CSD_SANITIZE_START)
                cmd.sanitize_busy = true;
 
-       err = mmc_wait_for_cmd(card->host, &cmd, MMC_CMD_RETRIES);
+       err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
        if (err)
                return err;
 
@@ -445,24 +459,27 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                return 0;
 
        /*
-        * Must check status to be sure of no errors
-        * If CMD13 is to check the busy completion of the timing change,
-        * disable the check of CRC error.
+        * CRC errors shall only be ignored in cases were CMD13 is used to poll
+        * to detect busy completion.
         */
-       if (index == EXT_CSD_HS_TIMING &&
-           !(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY))
-               ignore_crc = true;
+       if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
+               ignore_crc = false;
+
+       /* We have an unspecified cmd timeout, use the fallback value. */
+       if (!timeout_ms)
+               timeout_ms = MMC_OPS_TIMEOUT_MS;
 
-       timeout = jiffies + msecs_to_jiffies(MMC_OPS_TIMEOUT_MS);
+       /* Must check status to be sure of no errors. */
+       timeout = jiffies + msecs_to_jiffies(timeout_ms);
        do {
                if (send_status) {
                        err = __mmc_send_status(card, &status, ignore_crc);
                        if (err)
                                return err;
                }
-               if (card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)
+               if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
                        break;
-               if (mmc_host_is_spi(card->host))
+               if (mmc_host_is_spi(host))
                        break;
 
                /*
@@ -478,18 +495,18 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                /* Timeout if the device never leaves the program state. */
                if (time_after(jiffies, timeout)) {
                        pr_err("%s: Card stuck in programming state! %s\n",
-                               mmc_hostname(card->host), __func__);
+                               mmc_hostname(host), __func__);
                        return -ETIMEDOUT;
                }
        } while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
 
-       if (mmc_host_is_spi(card->host)) {
+       if (mmc_host_is_spi(host)) {
                if (status & R1_SPI_ILLEGAL_COMMAND)
                        return -EBADMSG;
        } else {
                if (status & 0xFDFFA000)
-                       pr_warning("%s: unexpected status %#x after "
-                              "switch", mmc_hostname(card->host), status);
+                       pr_warn("%s: unexpected status %#x after switch\n",
+                               mmc_hostname(host), status);
                if (status & R1_SWITCH_ERROR)
                        return -EBADMSG;
        }
@@ -501,7 +518,8 @@ EXPORT_SYMBOL_GPL(__mmc_switch);
 int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
                unsigned int timeout_ms)
 {
-       return __mmc_switch(card, set, index, value, timeout_ms, true, true);
+       return __mmc_switch(card, set, index, value, timeout_ms, true, true,
+                               false);
 }
 EXPORT_SYMBOL_GPL(mmc_switch);
 
index 692fdb1..2dd359d 100644 (file)
@@ -1207,16 +1207,6 @@ static int mmc_sd_power_restore(struct mmc_host *host)
 }
 
 static const struct mmc_bus_ops mmc_sd_ops = {
-       .remove = mmc_sd_remove,
-       .detect = mmc_sd_detect,
-       .suspend = NULL,
-       .resume = NULL,
-       .power_restore = mmc_sd_power_restore,
-       .alive = mmc_sd_alive,
-       .shutdown = mmc_sd_suspend,
-};
-
-static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
        .remove = mmc_sd_remove,
        .detect = mmc_sd_detect,
        .runtime_suspend = mmc_sd_runtime_suspend,
@@ -1228,17 +1218,6 @@ static const struct mmc_bus_ops mmc_sd_ops_unsafe = {
        .shutdown = mmc_sd_suspend,
 };
 
-static void mmc_sd_attach_bus_ops(struct mmc_host *host)
-{
-       const struct mmc_bus_ops *bus_ops;
-
-       if (!mmc_card_is_removable(host))
-               bus_ops = &mmc_sd_ops_unsafe;
-       else
-               bus_ops = &mmc_sd_ops;
-       mmc_attach_bus(host, bus_ops);
-}
-
 /*
  * Starting point for SD card init.
  */
@@ -1254,7 +1233,7 @@ int mmc_attach_sd(struct mmc_host *host)
        if (err)
                return err;
 
-       mmc_sd_attach_bus_ops(host);
+       mmc_attach_bus(host, &mmc_sd_ops);
        if (host->ocr_avail_sd)
                host->ocr_avail = host->ocr_avail_sd;
 
index 46596b7..f7650b8 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/err.h>
 #include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/mmc/host.h>
 #include <linux/slab.h>
 
 struct mmc_gpio {
-       int ro_gpio;
-       int cd_gpio;
+       struct gpio_desc *ro_gpio;
+       struct gpio_desc *cd_gpio;
+       bool override_ro_active_level;
+       bool override_cd_active_level;
        char *ro_label;
        char cd_label[0];
 };
@@ -57,8 +60,6 @@ static int mmc_gpio_alloc(struct mmc_host *host)
                        ctx->ro_label = ctx->cd_label + len;
                        snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
                        snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
-                       ctx->cd_gpio = -EINVAL;
-                       ctx->ro_gpio = -EINVAL;
                        host->slot.handler_priv = ctx;
                }
        }
@@ -72,11 +73,14 @@ int mmc_gpio_get_ro(struct mmc_host *host)
 {
        struct mmc_gpio *ctx = host->slot.handler_priv;
 
-       if (!ctx || !gpio_is_valid(ctx->ro_gpio))
+       if (!ctx || !ctx->ro_gpio)
                return -ENOSYS;
 
-       return !gpio_get_value_cansleep(ctx->ro_gpio) ^
-               !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH);
+       if (ctx->override_ro_active_level)
+               return !gpiod_get_raw_value_cansleep(ctx->ro_gpio) ^
+                       !!(host->caps2 & MMC_CAP2_RO_ACTIVE_HIGH);
+
+       return gpiod_get_value_cansleep(ctx->ro_gpio);
 }
 EXPORT_SYMBOL(mmc_gpio_get_ro);
 
@@ -84,11 +88,14 @@ int mmc_gpio_get_cd(struct mmc_host *host)
 {
        struct mmc_gpio *ctx = host->slot.handler_priv;
 
-       if (!ctx || !gpio_is_valid(ctx->cd_gpio))
+       if (!ctx || !ctx->cd_gpio)
                return -ENOSYS;
 
-       return !gpio_get_value_cansleep(ctx->cd_gpio) ^
-               !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
+       if (ctx->override_cd_active_level)
+               return !gpiod_get_raw_value_cansleep(ctx->cd_gpio) ^
+                       !!(host->caps2 & MMC_CAP2_CD_ACTIVE_HIGH);
+
+       return gpiod_get_value_cansleep(ctx->cd_gpio);
 }
 EXPORT_SYMBOL(mmc_gpio_get_cd);
 
@@ -125,12 +132,47 @@ int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
        if (ret < 0)
                return ret;
 
-       ctx->ro_gpio = gpio;
+       ctx->override_ro_active_level = true;
+       ctx->ro_gpio = gpio_to_desc(gpio);
 
        return 0;
 }
 EXPORT_SYMBOL(mmc_gpio_request_ro);
 
+void mmc_gpiod_request_cd_irq(struct mmc_host *host)
+{
+       struct mmc_gpio *ctx = host->slot.handler_priv;
+       int ret, irq;
+
+       if (host->slot.cd_irq >= 0 || !ctx || !ctx->cd_gpio)
+               return;
+
+       irq = gpiod_to_irq(ctx->cd_gpio);
+
+       /*
+        * Even if gpiod_to_irq() returns a valid IRQ number, the platform might
+        * still prefer to poll, e.g., because that IRQ number is already used
+        * by another unit and cannot be shared.
+        */
+       if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
+               irq = -EINVAL;
+
+       if (irq >= 0) {
+               ret = devm_request_threaded_irq(&host->class_dev, irq,
+                       NULL, mmc_gpio_cd_irqt,
+                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                       ctx->cd_label, host);
+               if (ret < 0)
+                       irq = ret;
+       }
+
+       host->slot.cd_irq = irq;
+
+       if (irq < 0)
+               host->caps |= MMC_CAP_NEEDS_POLL;
+}
+EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
+
 /**
  * mmc_gpio_request_cd - request a gpio for card-detection
  * @host: mmc host
@@ -154,7 +196,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
                        unsigned int debounce)
 {
        struct mmc_gpio *ctx;
-       int irq = gpio_to_irq(gpio);
        int ret;
 
        ret = mmc_gpio_alloc(host);
@@ -179,29 +220,10 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
                        return ret;
        }
 
-       /*
-        * Even if gpio_to_irq() returns a valid IRQ number, the platform might
-        * still prefer to poll, e.g., because that IRQ number is already used
-        * by another unit and cannot be shared.
-        */
-       if (irq >= 0 && host->caps & MMC_CAP_NEEDS_POLL)
-               irq = -EINVAL;
-
-       if (irq >= 0) {
-               ret = devm_request_threaded_irq(&host->class_dev, irq,
-                       NULL, mmc_gpio_cd_irqt,
-                       IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
-                       ctx->cd_label, host);
-               if (ret < 0)
-                       irq = ret;
-       }
-
-       host->slot.cd_irq = irq;
-
-       if (irq < 0)
-               host->caps |= MMC_CAP_NEEDS_POLL;
+       ctx->override_cd_active_level = true;
+       ctx->cd_gpio = gpio_to_desc(gpio);
 
-       ctx->cd_gpio = gpio;
+       mmc_gpiod_request_cd_irq(host);
 
        return 0;
 }
@@ -219,11 +241,11 @@ void mmc_gpio_free_ro(struct mmc_host *host)
        struct mmc_gpio *ctx = host->slot.handler_priv;
        int gpio;
 
-       if (!ctx || !gpio_is_valid(ctx->ro_gpio))
+       if (!ctx || !ctx->ro_gpio)
                return;
 
-       gpio = ctx->ro_gpio;
-       ctx->ro_gpio = -EINVAL;
+       gpio = desc_to_gpio(ctx->ro_gpio);
+       ctx->ro_gpio = NULL;
 
        devm_gpio_free(&host->class_dev, gpio);
 }
@@ -241,7 +263,7 @@ void mmc_gpio_free_cd(struct mmc_host *host)
        struct mmc_gpio *ctx = host->slot.handler_priv;
        int gpio;
 
-       if (!ctx || !gpio_is_valid(ctx->cd_gpio))
+       if (!ctx || !ctx->cd_gpio)
                return;
 
        if (host->slot.cd_irq >= 0) {
@@ -249,9 +271,87 @@ void mmc_gpio_free_cd(struct mmc_host *host)
                host->slot.cd_irq = -EINVAL;
        }
 
-       gpio = ctx->cd_gpio;
-       ctx->cd_gpio = -EINVAL;
+       gpio = desc_to_gpio(ctx->cd_gpio);
+       ctx->cd_gpio = NULL;
 
        devm_gpio_free(&host->class_dev, gpio);
 }
 EXPORT_SYMBOL(mmc_gpio_free_cd);
+
+/**
+ * mmc_gpiod_request_cd - request a gpio descriptor for card-detection
+ * @host: mmc host
+ * @con_id: function within the GPIO consumer
+ * @idx: index of the GPIO to obtain in the consumer
+ * @override_active_level: ignore %GPIO_ACTIVE_LOW flag
+ * @debounce: debounce time in microseconds
+ *
+ * Use this function in place of mmc_gpio_request_cd() to use the GPIO
+ * descriptor API.  Note that it is paired with mmc_gpiod_free_cd() not
+ * mmc_gpio_free_cd().  Note also that it must be called prior to mmc_add_host()
+ * otherwise the caller must also call mmc_gpiod_request_cd_irq().
+ *
+ * Returns zero on success, else an error.
+ */
+int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
+                        unsigned int idx, bool override_active_level,
+                        unsigned int debounce)
+{
+       struct mmc_gpio *ctx;
+       struct gpio_desc *desc;
+       int ret;
+
+       ret = mmc_gpio_alloc(host);
+       if (ret < 0)
+               return ret;
+
+       ctx = host->slot.handler_priv;
+
+       if (!con_id)
+               con_id = ctx->cd_label;
+
+       desc = devm_gpiod_get_index(host->parent, con_id, idx);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       ret = gpiod_direction_input(desc);
+       if (ret < 0)
+               return ret;
+
+       if (debounce) {
+               ret = gpiod_set_debounce(desc, debounce);
+               if (ret < 0)
+                       return ret;
+       }
+
+       ctx->override_cd_active_level = override_active_level;
+       ctx->cd_gpio = desc;
+
+       return 0;
+}
+EXPORT_SYMBOL(mmc_gpiod_request_cd);
+
+/**
+ * mmc_gpiod_free_cd - free the card-detection gpio descriptor
+ * @host: mmc host
+ *
+ * It's provided only for cases that client drivers need to manually free
+ * up the card-detection gpio requested by mmc_gpiod_request_cd().
+ */
+void mmc_gpiod_free_cd(struct mmc_host *host)
+{
+       struct mmc_gpio *ctx = host->slot.handler_priv;
+
+       if (!ctx || !ctx->cd_gpio)
+               return;
+
+       if (host->slot.cd_irq >= 0) {
+               devm_free_irq(&host->class_dev, host->slot.cd_irq, host);
+               host->slot.cd_irq = -EINVAL;
+       }
+
+       devm_gpiod_put(&host->class_dev, ctx->cd_gpio);
+
+       ctx->cd_gpio = NULL;
+}
+EXPORT_SYMBOL(mmc_gpiod_free_cd);
index 1384f67..8aaf8c1 100644 (file)
@@ -263,7 +263,7 @@ config MMC_SDHCI_S3C_DMA
 
 config MMC_SDHCI_BCM_KONA
        tristate "SDHCI support on Broadcom KONA platform"
-       depends on ARCH_BCM
+       depends on ARCH_BCM_MOBILE
        select MMC_SDHCI_PLTFM
        help
          This selects the Broadcom Kona Secure Digital Host Controller
@@ -334,6 +334,19 @@ config MMC_ATMELMCI
 
          If unsure, say N.
 
+config MMC_SDHCI_MSM
+       tristate "Qualcomm SDHCI Controller Support"
+       depends on ARCH_QCOM
+       depends on MMC_SDHCI_PLTFM
+       help
+         This selects the Secure Digital Host Controller Interface (SDHCI)
+         support present in Qualcomm SOCs. The controller supports
+         SD/MMC/SDIO devices.
+
+         If you have a controller with this interface, say Y or M here.
+
+         If unsure, say N.
+
 config MMC_MSM
        tristate "Qualcomm SDCC Controller Support"
        depends on MMC && (ARCH_MSM7X00A || ARCH_MSM7X30 || ARCH_QSD8X50)
@@ -580,14 +593,6 @@ config MMC_DW_EXYNOS
          Synopsys DesignWare Memory Card Interface driver. Select this option
          for platforms based on Exynos4 and Exynos5 SoC's.
 
-config MMC_DW_SOCFPGA
-       tristate "SOCFPGA specific extensions for Synopsys DW Memory Card Interface"
-       depends on MMC_DW && MFD_SYSCON
-       select MMC_DW_PLTFM
-       help
-         This selects support for Altera SoCFPGA specific extensions to the
-         Synopsys DesignWare Memory Card Interface driver.
-
 config MMC_DW_K3
        tristate "K3 specific extensions for Synopsys DW Memory Card Interface"
        depends on MMC_DW
index 3483b6b..0c8aa5e 100644 (file)
@@ -43,7 +43,6 @@ obj-$(CONFIG_SDH_BFIN)                += bfin_sdh.o
 obj-$(CONFIG_MMC_DW)           += dw_mmc.o
 obj-$(CONFIG_MMC_DW_PLTFM)     += dw_mmc-pltfm.o
 obj-$(CONFIG_MMC_DW_EXYNOS)    += dw_mmc-exynos.o
-obj-$(CONFIG_MMC_DW_SOCFPGA)   += dw_mmc-socfpga.o
 obj-$(CONFIG_MMC_DW_K3)                += dw_mmc-k3.o
 obj-$(CONFIG_MMC_DW_PCI)       += dw_mmc-pci.o
 obj-$(CONFIG_MMC_SH_MMCIF)     += sh_mmcif.o
@@ -64,6 +63,7 @@ obj-$(CONFIG_MMC_SDHCI_OF_ESDHC)      += sdhci-of-esdhc.o
 obj-$(CONFIG_MMC_SDHCI_OF_HLWD)                += sdhci-of-hlwd.o
 obj-$(CONFIG_MMC_SDHCI_BCM_KONA)       += sdhci-bcm-kona.o
 obj-$(CONFIG_MMC_SDHCI_BCM2835)                += sdhci-bcm2835.o
+obj-$(CONFIG_MMC_SDHCI_MSM)            += sdhci-msm.o
 
 ifeq ($(CONFIG_CB710_DEBUG),y)
        CFLAGS-cb710-mmc        += -DDEBUG
index d615374..5d4c5e0 100644 (file)
@@ -1192,7 +1192,7 @@ static struct davinci_mmc_config
        struct device_node *np;
        struct davinci_mmc_config *pdata = pdev->dev.platform_data;
        const struct of_device_id *match =
-               of_match_device(of_match_ptr(davinci_mmc_dt_ids), &pdev->dev);
+               of_match_device(davinci_mmc_dt_ids, &pdev->dev);
        u32 data;
 
        np = pdev->dev.of_node;
@@ -1468,7 +1468,7 @@ static struct platform_driver davinci_mmcsd_driver = {
                .name   = "davinci_mmc",
                .owner  = THIS_MODULE,
                .pm     = davinci_mmcsd_pm_ops,
-               .of_match_table = of_match_ptr(davinci_mmc_dt_ids),
+               .of_match_table = davinci_mmc_dt_ids,
        },
        .remove         = __exit_p(davinci_mmcsd_remove),
        .id_table       = davinci_mmc_devtype,
index f567c21..650f9cc 100644 (file)
@@ -50,6 +50,7 @@ static int dw_mci_k3_probe(struct platform_device *pdev)
        return dw_mci_pltfm_register(pdev, drv_data);
 }
 
+#ifdef CONFIG_PM_SLEEP
 static int dw_mci_k3_suspend(struct device *dev)
 {
        struct dw_mci *host = dev_get_drvdata(dev);
@@ -75,6 +76,7 @@ static int dw_mci_k3_resume(struct device *dev)
 
        return dw_mci_resume(host);
 }
+#endif /* CONFIG_PM_SLEEP */
 
 static SIMPLE_DEV_PM_OPS(dw_mci_k3_pmops, dw_mci_k3_suspend, dw_mci_k3_resume);
 
index 5c49656..d4a47a9 100644 (file)
 #include "dw_mmc.h"
 #include "dw_mmc-pltfm.h"
 
-static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
+static void dw_mci_pltfm_prepare_command(struct dw_mci *host, u32 *cmdr)
 {
        *cmdr |= SDMMC_CMD_USE_HOLD_REG;
 }
 
 static const struct dw_mci_drv_data rockchip_drv_data = {
-       .prepare_command        = dw_mci_rockchip_prepare_command,
+       .prepare_command        = dw_mci_pltfm_prepare_command,
+};
+
+static const struct dw_mci_drv_data socfpga_drv_data = {
+       .prepare_command        = dw_mci_pltfm_prepare_command,
 };
 
 int dw_mci_pltfm_register(struct platform_device *pdev,
@@ -92,6 +96,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
        { .compatible = "snps,dw-mshc", },
        { .compatible = "rockchip,rk2928-dw-mshc",
                .data = &rockchip_drv_data },
+       { .compatible = "altr,socfpga-dw-mshc",
+               .data = &socfpga_drv_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
@@ -123,7 +129,7 @@ static struct platform_driver dw_mci_pltfm_driver = {
        .remove         = dw_mci_pltfm_remove,
        .driver         = {
                .name           = "dw_mmc",
-               .of_match_table = of_match_ptr(dw_mci_pltfm_match),
+               .of_match_table = dw_mci_pltfm_match,
                .pm             = &dw_mci_pltfm_pmops,
        },
 };
diff --git a/drivers/mmc/host/dw_mmc-socfpga.c b/drivers/mmc/host/dw_mmc-socfpga.c
deleted file mode 100644 (file)
index 3e8e53a..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Altera SoCFPGA Specific Extensions for Synopsys DW Multimedia Card Interface
- * driver
- *
- *  Copyright (C) 2012, Samsung Electronics Co., Ltd.
- *  Copyright (C) 2013 Altera 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.
- *
- * Taken from dw_mmc-exynos.c
- */
-#include <linux/clk.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/dw_mmc.h>
-#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/platform_device.h>
-#include <linux/regmap.h>
-
-#include "dw_mmc.h"
-#include "dw_mmc-pltfm.h"
-
-#define SYSMGR_SDMMCGRP_CTRL_OFFSET            0x108
-#define DRV_CLK_PHASE_SHIFT_SEL_MASK   0x7
-#define SYSMGR_SDMMC_CTRL_SET(smplsel, drvsel)          \
-       ((((smplsel) & 0x7) << 3) | (((drvsel) & 0x7) << 0))
-
-/* SOCFPGA implementation specific driver private data */
-struct dw_mci_socfpga_priv_data {
-       u8      ciu_div; /* card interface unit divisor */
-       u32     hs_timing; /* bitmask for CIU clock phase shift */
-       struct regmap   *sysreg; /* regmap for system manager register */
-};
-
-static int dw_mci_socfpga_priv_init(struct dw_mci *host)
-{
-       return 0;
-}
-
-static int dw_mci_socfpga_setup_clock(struct dw_mci *host)
-{
-       struct dw_mci_socfpga_priv_data *priv = host->priv;
-
-       clk_disable_unprepare(host->ciu_clk);
-       regmap_write(priv->sysreg, SYSMGR_SDMMCGRP_CTRL_OFFSET,
-               priv->hs_timing);
-       clk_prepare_enable(host->ciu_clk);
-
-       host->bus_hz /= (priv->ciu_div + 1);
-       return 0;
-}
-
-static void dw_mci_socfpga_prepare_command(struct dw_mci *host, u32 *cmdr)
-{
-       struct dw_mci_socfpga_priv_data *priv = host->priv;
-
-       if (priv->hs_timing & DRV_CLK_PHASE_SHIFT_SEL_MASK)
-               *cmdr |= SDMMC_CMD_USE_HOLD_REG;
-}
-
-static int dw_mci_socfpga_parse_dt(struct dw_mci *host)
-{
-       struct dw_mci_socfpga_priv_data *priv;
-       struct device_node *np = host->dev->of_node;
-       u32 timing[2];
-       u32 div = 0;
-       int ret;
-
-       priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
-       if (!priv) {
-               dev_err(host->dev, "mem alloc failed for private data\n");
-               return -ENOMEM;
-       }
-
-       priv->sysreg = syscon_regmap_lookup_by_compatible("altr,sys-mgr");
-       if (IS_ERR(priv->sysreg)) {
-               dev_err(host->dev, "regmap for altr,sys-mgr lookup failed.\n");
-               return PTR_ERR(priv->sysreg);
-       }
-
-       ret = of_property_read_u32(np, "altr,dw-mshc-ciu-div", &div);
-       if (ret)
-               dev_info(host->dev, "No dw-mshc-ciu-div specified, assuming 1");
-       priv->ciu_div = div;
-
-       ret = of_property_read_u32_array(np,
-                       "altr,dw-mshc-sdr-timing", timing, 2);
-       if (ret)
-               return ret;
-
-       priv->hs_timing = SYSMGR_SDMMC_CTRL_SET(timing[0], timing[1]);
-       host->priv = priv;
-       return 0;
-}
-
-static const struct dw_mci_drv_data socfpga_drv_data = {
-       .init                   = dw_mci_socfpga_priv_init,
-       .setup_clock            = dw_mci_socfpga_setup_clock,
-       .prepare_command        = dw_mci_socfpga_prepare_command,
-       .parse_dt               = dw_mci_socfpga_parse_dt,
-};
-
-static const struct of_device_id dw_mci_socfpga_match[] = {
-       { .compatible = "altr,socfpga-dw-mshc",
-                       .data = &socfpga_drv_data, },
-       {},
-};
-MODULE_DEVICE_TABLE(of, dw_mci_socfpga_match);
-
-static int dw_mci_socfpga_probe(struct platform_device *pdev)
-{
-       const struct dw_mci_drv_data *drv_data;
-       const struct of_device_id *match;
-
-       match = of_match_node(dw_mci_socfpga_match, pdev->dev.of_node);
-       drv_data = match->data;
-       return dw_mci_pltfm_register(pdev, drv_data);
-}
-
-static struct platform_driver dw_mci_socfpga_pltfm_driver = {
-       .probe          = dw_mci_socfpga_probe,
-       .remove         = __exit_p(dw_mci_pltfm_remove),
-       .driver         = {
-               .name           = "dwmmc_socfpga",
-               .of_match_table = dw_mci_socfpga_match,
-               .pm             = &dw_mci_pltfm_pmops,
-       },
-};
-
-module_platform_driver(dw_mci_socfpga_pltfm_driver);
-
-MODULE_DESCRIPTION("Altera SOCFPGA Specific DW-MSHC Driver Extension");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:dwmmc-socfpga");
index c204b7d..cced599 100644 (file)
@@ -1345,7 +1345,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
 
                        if (!err) {
                                if (!data->stop || mrq->sbc) {
-                                       if (mrq->sbc)
+                                       if (mrq->sbc && data->stop)
                                                data->stop->error = 0;
                                        dw_mci_request_end(host, mrq);
                                        goto unlock;
index 6bf24ab..6834977 100644 (file)
 
 extern int dw_mci_probe(struct dw_mci *host);
 extern void dw_mci_remove(struct dw_mci *host);
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 extern int dw_mci_suspend(struct dw_mci *host);
 extern int dw_mci_resume(struct dw_mci *host);
 #endif
@@ -244,6 +244,7 @@ struct dw_mci_tuning_data {
  * @prepare_command: handle CMD register extensions.
  * @set_ios: handle bus specific extensions.
  * @parse_dt: parse implementation specific device tree properties.
+ * @execute_tuning: implementation specific tuning procedure.
  *
  * Provide controller implementation specific extensions. The usage of this
  * data structure is fully optional and usage of each member in this structure
index b931226..771c60a 100644 (file)
@@ -921,6 +921,29 @@ mmci_cmd_irq(struct mmci_host *host, struct mmc_command *cmd,
 {
        void __iomem *base = host->base;
        bool sbc = (cmd == host->mrq->sbc);
+       bool busy_resp = host->variant->busy_detect &&
+                       (cmd->flags & MMC_RSP_BUSY);
+
+       /* Check if we need to wait for busy completion. */
+       if (host->busy_status && (status & MCI_ST_CARDBUSY))
+               return;
+
+       /* Enable busy completion if needed and supported. */
+       if (!host->busy_status && busy_resp &&
+               !(status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT)) &&
+               (readl(base + MMCISTATUS) & MCI_ST_CARDBUSY)) {
+               writel(readl(base + MMCIMASK0) | MCI_ST_BUSYEND,
+                       base + MMCIMASK0);
+               host->busy_status = status & (MCI_CMDSENT|MCI_CMDRESPEND);
+               return;
+       }
+
+       /* At busy completion, mask the IRQ and complete the request. */
+       if (host->busy_status) {
+               writel(readl(base + MMCIMASK0) & ~MCI_ST_BUSYEND,
+                       base + MMCIMASK0);
+               host->busy_status = 0;
+       }
 
        host->cmd = NULL;
 
@@ -1139,20 +1162,30 @@ static irqreturn_t mmci_irq(int irq, void *dev_id)
                        status &= ~MCI_IRQ1MASK;
                }
 
+               /*
+                * We intentionally clear the MCI_ST_CARDBUSY IRQ here (if it's
+                * enabled) since the HW seems to be triggering the IRQ on both
+                * edges while monitoring DAT0 for busy completion.
+                */
                status &= readl(host->base + MMCIMASK0);
                writel(status, host->base + MMCICLEAR);
 
                dev_dbg(mmc_dev(host->mmc), "irq0 (data+cmd) %08x\n", status);
 
+               cmd = host->cmd;
+               if ((status|host->busy_status) & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|
+                       MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
+                       mmci_cmd_irq(host, cmd, status);
+
                data = host->data;
                if (status & (MCI_DATACRCFAIL|MCI_DATATIMEOUT|MCI_STARTBITERR|
                              MCI_TXUNDERRUN|MCI_RXOVERRUN|MCI_DATAEND|
                              MCI_DATABLOCKEND) && data)
                        mmci_data_irq(host, data, status);
 
-               cmd = host->cmd;
-               if (status & (MCI_CMDCRCFAIL|MCI_CMDTIMEOUT|MCI_CMDSENT|MCI_CMDRESPEND) && cmd)
-                       mmci_cmd_irq(host, cmd, status);
+               /* Don't poll for busy completion in irq context. */
+               if (host->busy_status)
+                       status &= ~MCI_ST_CARDBUSY;
 
                ret = 1;
        } while (status);
@@ -1503,12 +1536,6 @@ static int mmci_probe(struct amba_device *dev,
                goto clk_disable;
        }
 
-       if (variant->busy_detect) {
-               mmci_ops.card_busy = mmci_card_busy;
-               mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
-       }
-
-       mmc->ops = &mmci_ops;
        /*
         * The ARM and ST versions of the block have slightly different
         * clock divider equations which means that the minimum divider
@@ -1542,6 +1569,15 @@ static int mmci_probe(struct amba_device *dev,
        mmc->caps = plat->capabilities;
        mmc->caps2 = plat->capabilities2;
 
+       if (variant->busy_detect) {
+               mmci_ops.card_busy = mmci_card_busy;
+               mmci_write_datactrlreg(host, MCI_ST_DPSM_BUSYMODE);
+               mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY;
+               mmc->max_busy_timeout = 0;
+       }
+
+       mmc->ops = &mmci_ops;
+
        /* We support these PM capabilities. */
        mmc->pm_caps = MMC_PM_KEEP_POWER;
 
index 84c0e59..58b1b88 100644 (file)
 /* Extended status bits for the ST Micro variants */
 #define MCI_ST_SDIOITMASK      (1 << 22)
 #define MCI_ST_CEATAENDMASK    (1 << 23)
+#define MCI_ST_BUSYEND         (1 << 24)
 
 #define MMCIMASK1              0x040
 #define MMCIFIFOCNT            0x048
@@ -187,6 +188,7 @@ struct mmci_host {
        u32                     pwr_reg;
        u32                     clk_reg;
        u32                     datactrl_reg;
+       u32                     busy_status;
        bool                    vqmmc_enabled;
        struct mmci_platform_data *plat;
        struct variant_data     *variant;
index 98b6b6e..5c2e58b 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/omap-dma.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/clk.h>
 #include <linux/scatterlist.h>
 #include <linux/slab.h>
@@ -130,7 +131,6 @@ struct mmc_omap_host {
        u32                     dma_rx_burst;
        struct dma_chan         *dma_tx;
        u32                     dma_tx_burst;
-       struct resource         *mem_res;
        void __iomem            *virt_base;
        unsigned int            phys_base;
        int                     irq;
@@ -153,7 +153,6 @@ struct mmc_omap_host {
        u32                     total_bytes_left;
 
        unsigned                features;
-       unsigned                use_dma:1;
        unsigned                brs_received:1, dma_done:1;
        unsigned                dma_in_use:1;
        spinlock_t              dma_lock;
@@ -338,6 +337,7 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
        u32 cmdreg;
        u32 resptype;
        u32 cmdtype;
+       u16 irq_mask;
 
        host->cmd = cmd;
 
@@ -390,12 +390,14 @@ mmc_omap_start_command(struct mmc_omap_host *host, struct mmc_command *cmd)
        OMAP_MMC_WRITE(host, CTO, 200);
        OMAP_MMC_WRITE(host, ARGL, cmd->arg & 0xffff);
        OMAP_MMC_WRITE(host, ARGH, cmd->arg >> 16);
-       OMAP_MMC_WRITE(host, IE,
-                      OMAP_MMC_STAT_A_EMPTY    | OMAP_MMC_STAT_A_FULL    |
-                      OMAP_MMC_STAT_CMD_CRC    | OMAP_MMC_STAT_CMD_TOUT  |
-                      OMAP_MMC_STAT_DATA_CRC   | OMAP_MMC_STAT_DATA_TOUT |
-                      OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR  |
-                      OMAP_MMC_STAT_END_OF_DATA);
+       irq_mask = OMAP_MMC_STAT_A_EMPTY    | OMAP_MMC_STAT_A_FULL    |
+                  OMAP_MMC_STAT_CMD_CRC    | OMAP_MMC_STAT_CMD_TOUT  |
+                  OMAP_MMC_STAT_DATA_CRC   | OMAP_MMC_STAT_DATA_TOUT |
+                  OMAP_MMC_STAT_END_OF_CMD | OMAP_MMC_STAT_CARD_ERR  |
+                  OMAP_MMC_STAT_END_OF_DATA;
+       if (cmd->opcode == MMC_ERASE)
+               irq_mask &= ~OMAP_MMC_STAT_DATA_TOUT;
+       OMAP_MMC_WRITE(host, IE, irq_mask);
        OMAP_MMC_WRITE(host, CMD, cmdreg);
 }
 
@@ -945,7 +947,7 @@ static void
 mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
 {
        struct mmc_data *data = req->data;
-       int i, use_dma, block_size;
+       int i, use_dma = 1, block_size;
        unsigned sg_len;
 
        host->data = data;
@@ -970,13 +972,10 @@ mmc_omap_prepare_data(struct mmc_omap_host *host, struct mmc_request *req)
        sg_len = (data->blocks == 1) ? 1 : data->sg_len;
 
        /* Only do DMA for entire blocks */
-       use_dma = host->use_dma;
-       if (use_dma) {
-               for (i = 0; i < sg_len; i++) {
-                       if ((data->sg[i].length % block_size) != 0) {
-                               use_dma = 0;
-                               break;
-                       }
+       for (i = 0; i < sg_len; i++) {
+               if ((data->sg[i].length % block_size) != 0) {
+                       use_dma = 0;
+                       break;
                }
        }
 
@@ -1239,7 +1238,7 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
 
        mmc->caps = 0;
        if (host->pdata->slots[id].wires >= 4)
-               mmc->caps |= MMC_CAP_4_BIT_DATA;
+               mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_ERASE;
 
        mmc->ops = &mmc_omap_ops;
        mmc->f_min = 400000;
@@ -1262,6 +1261,13 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
        mmc->max_req_size = mmc->max_blk_size * mmc->max_blk_count;
        mmc->max_seg_size = mmc->max_req_size;
 
+       if (slot->pdata->get_cover_state != NULL) {
+               setup_timer(&slot->cover_timer, mmc_omap_cover_timer,
+                           (unsigned long)slot);
+               tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler,
+                            (unsigned long)slot);
+       }
+
        r = mmc_add_host(mmc);
        if (r < 0)
                goto err_remove_host;
@@ -1278,11 +1284,6 @@ static int mmc_omap_new_slot(struct mmc_omap_host *host, int id)
                                        &dev_attr_cover_switch);
                if (r < 0)
                        goto err_remove_slot_name;
-
-               setup_timer(&slot->cover_timer, mmc_omap_cover_timer,
-                           (unsigned long)slot);
-               tasklet_init(&slot->cover_tasklet, mmc_omap_cover_handler,
-                            (unsigned long)slot);
                tasklet_schedule(&slot->cover_tasklet);
        }
 
@@ -1333,21 +1334,19 @@ static int mmc_omap_probe(struct platform_device *pdev)
                return -EPROBE_DEFER;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host = devm_kzalloc(&pdev->dev, sizeof(struct mmc_omap_host),
+                           GFP_KERNEL);
+       if (host == NULL)
+               return -ENOMEM;
+
        irq = platform_get_irq(pdev, 0);
-       if (res == NULL || irq < 0)
+       if (irq < 0)
                return -ENXIO;
 
-       res = request_mem_region(res->start, resource_size(res),
-                                pdev->name);
-       if (res == NULL)
-               return -EBUSY;
-
-       host = kzalloc(sizeof(struct mmc_omap_host), GFP_KERNEL);
-       if (host == NULL) {
-               ret = -ENOMEM;
-               goto err_free_mem_region;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->virt_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(host->virt_base))
+               return PTR_ERR(host->virt_base);
 
        INIT_WORK(&host->slot_release_work, mmc_omap_slot_release_work);
        INIT_WORK(&host->send_stop_work, mmc_omap_send_stop_work);
@@ -1369,20 +1368,11 @@ static int mmc_omap_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, host);
 
        host->id = pdev->id;
-       host->mem_res = res;
-       host->irq = irq;
-       host->use_dma = 1;
        host->irq = irq;
-       host->phys_base = host->mem_res->start;
-       host->virt_base = ioremap(res->start, resource_size(res));
-       if (!host->virt_base)
-               goto err_ioremap;
-
+       host->phys_base = res->start;
        host->iclk = clk_get(&pdev->dev, "ick");
-       if (IS_ERR(host->iclk)) {
-               ret = PTR_ERR(host->iclk);
-               goto err_free_mmc_host;
-       }
+       if (IS_ERR(host->iclk))
+               return PTR_ERR(host->iclk);
        clk_enable(host->iclk);
 
        host->fclk = clk_get(&pdev->dev, "fck");
@@ -1460,12 +1450,6 @@ err_free_dma:
 err_free_iclk:
        clk_disable(host->iclk);
        clk_put(host->iclk);
-err_free_mmc_host:
-       iounmap(host->virt_base);
-err_ioremap:
-       kfree(host);
-err_free_mem_region:
-       release_mem_region(res->start, resource_size(res));
        return ret;
 }
 
@@ -1493,13 +1477,8 @@ static int mmc_omap_remove(struct platform_device *pdev)
        if (host->dma_rx)
                dma_release_channel(host->dma_rx);
 
-       iounmap(host->virt_base);
-       release_mem_region(pdev->resource[0].start,
-                          pdev->resource[0].end - pdev->resource[0].start + 1);
        destroy_workqueue(host->mmc_omap_wq);
 
-       kfree(host);
-
        return 0;
 }
 
index dbd32ad..e91ee21 100644 (file)
@@ -45,6 +45,7 @@
 /* OMAP HSMMC Host Controller Registers */
 #define OMAP_HSMMC_SYSSTATUS   0x0014
 #define OMAP_HSMMC_CON         0x002C
+#define OMAP_HSMMC_SDMASA      0x0100
 #define OMAP_HSMMC_BLK         0x0104
 #define OMAP_HSMMC_ARG         0x0108
 #define OMAP_HSMMC_CMD         0x010C
@@ -58,6 +59,7 @@
 #define OMAP_HSMMC_STAT                0x0130
 #define OMAP_HSMMC_IE          0x0134
 #define OMAP_HSMMC_ISE         0x0138
+#define OMAP_HSMMC_AC12                0x013C
 #define OMAP_HSMMC_CAPA                0x0140
 
 #define VS18                   (1 << 26)
@@ -81,6 +83,7 @@
 #define DTO_MASK               0x000F0000
 #define DTO_SHIFT              16
 #define INIT_STREAM            (1 << 1)
+#define ACEN_ACMD23            (2 << 2)
 #define DP_SELECT              (1 << 21)
 #define DDIR                   (1 << 4)
 #define DMAE                   0x1
 #define SRC                    (1 << 25)
 #define SRD                    (1 << 26)
 #define SOFTRESET              (1 << 1)
-#define RESETDONE              (1 << 0)
 
 /* Interrupt masks for IE and ISE register */
 #define CC_EN                  (1 << 0)
 #define DTO_EN                 (1 << 20)
 #define DCRC_EN                        (1 << 21)
 #define DEB_EN                 (1 << 22)
+#define ACE_EN                 (1 << 24)
 #define CERR_EN                        (1 << 28)
 #define BADA_EN                        (1 << 29)
 
-#define INT_EN_MASK            (BADA_EN | CERR_EN | DEB_EN | DCRC_EN |\
+#define INT_EN_MASK (BADA_EN | CERR_EN | ACE_EN | DEB_EN | DCRC_EN |\
                DTO_EN | CIE_EN | CEB_EN | CCRC_EN | CTO_EN | \
                BRR_EN | BWR_EN | TC_EN | CC_EN)
 
+#define CNI    (1 << 7)
+#define ACIE   (1 << 4)
+#define ACEB   (1 << 3)
+#define ACCE   (1 << 2)
+#define ACTO   (1 << 1)
+#define ACNE   (1 << 0)
+
 #define MMC_AUTOSUSPEND_DELAY  100
 #define MMC_TIMEOUT_MS         20              /* 20 mSec */
 #define MMC_TIMEOUT_US         20000           /* 20000 micro Sec */
 #define OMAP_MMC_MAX_CLOCK     52000000
 #define DRIVER_NAME            "omap_hsmmc"
 
+#define VDD_1V8                        1800000         /* 180000 uV */
+#define VDD_3V0                        3000000         /* 300000 uV */
+#define VDD_165_195            (ffs(MMC_VDD_165_195) - 1)
+
+#define AUTO_CMD23             (1 << 1)        /* Auto CMD23 support */
 /*
  * One controller can have multiple slots, like on some omap boards using
  * omap.c controller driver. Luckily this is not currently done on any known
@@ -164,7 +179,8 @@ struct omap_hsmmc_host {
         */
        struct  regulator       *vcc;
        struct  regulator       *vcc_aux;
-       int                     pbias_disable;
+       struct  regulator       *pbias;
+       bool                    pbias_enabled;
        void    __iomem         *base;
        resource_size_t         mapbase;
        spinlock_t              irq_lock; /* Prevent races with irq handler */
@@ -188,10 +204,19 @@ struct omap_hsmmc_host {
        int                     reqs_blocked;
        int                     use_reg;
        int                     req_in_progress;
+       unsigned long           clk_rate;
+       unsigned int            flags;
        struct omap_hsmmc_next  next_data;
        struct  omap_mmc_platform_data  *pdata;
 };
 
+struct omap_mmc_of_data {
+       u32 reg_offset;
+       u8 controller_flags;
+};
+
+static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host);
+
 static int omap_hsmmc_card_detect(struct device *dev, int slot)
 {
        struct omap_hsmmc_host *host = dev_get_drvdata(dev);
@@ -261,17 +286,19 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
         */
        if (!host->vcc)
                return 0;
-       /*
-        * With DT, never turn OFF the regulator for MMC1. This is because
-        * the pbias cell programming support is still missing when
-        * booting with Device tree
-        */
-       if (host->pbias_disable && !vdd)
-               return 0;
 
        if (mmc_slot(host).before_set_reg)
                mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
 
+       if (host->pbias) {
+               if (host->pbias_enabled == 1) {
+                       ret = regulator_disable(host->pbias);
+                       if (!ret)
+                               host->pbias_enabled = 0;
+               }
+               regulator_set_voltage(host->pbias, VDD_3V0, VDD_3V0);
+       }
+
        /*
         * Assume Vcc regulator is used only to power the card ... OMAP
         * VDDS is used to power the pins, optionally with a transceiver to
@@ -286,11 +313,12 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
         * chips/cards need an interface voltage rail too.
         */
        if (power_on) {
-               ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
+               if (host->vcc)
+                       ret = mmc_regulator_set_ocr(host->mmc, host->vcc, vdd);
                /* Enable interface voltage rail, if needed */
                if (ret == 0 && host->vcc_aux) {
                        ret = regulator_enable(host->vcc_aux);
-                       if (ret < 0)
+                       if (ret < 0 && host->vcc)
                                ret = mmc_regulator_set_ocr(host->mmc,
                                                        host->vcc, 0);
                }
@@ -298,16 +326,34 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
                /* Shut down the rail */
                if (host->vcc_aux)
                        ret = regulator_disable(host->vcc_aux);
-               if (!ret) {
+               if (host->vcc) {
                        /* Then proceed to shut down the local regulator */
                        ret = mmc_regulator_set_ocr(host->mmc,
                                                host->vcc, 0);
                }
        }
 
+       if (host->pbias) {
+               if (vdd <= VDD_165_195)
+                       ret = regulator_set_voltage(host->pbias, VDD_1V8,
+                                                               VDD_1V8);
+               else
+                       ret = regulator_set_voltage(host->pbias, VDD_3V0,
+                                                               VDD_3V0);
+               if (ret < 0)
+                       goto error_set_power;
+
+               if (host->pbias_enabled == 0) {
+                       ret = regulator_enable(host->pbias);
+                       if (!ret)
+                               host->pbias_enabled = 1;
+               }
+       }
+
        if (mmc_slot(host).after_set_reg)
                mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
 
+error_set_power:
        return ret;
 }
 
@@ -316,12 +362,12 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
        struct regulator *reg;
        int ocr_value = 0;
 
-       reg = regulator_get(host->dev, "vmmc");
+       reg = devm_regulator_get(host->dev, "vmmc");
        if (IS_ERR(reg)) {
-               dev_err(host->dev, "vmmc regulator missing\n");
+               dev_err(host->dev, "unable to get vmmc regulator %ld\n",
+                       PTR_ERR(reg));
                return PTR_ERR(reg);
        } else {
-               mmc_slot(host).set_power = omap_hsmmc_set_power;
                host->vcc = reg;
                ocr_value = mmc_regulator_get_ocrmask(reg);
                if (!mmc_slot(host).ocr_mask) {
@@ -334,31 +380,29 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
                                return -EINVAL;
                        }
                }
+       }
+       mmc_slot(host).set_power = omap_hsmmc_set_power;
 
-               /* Allow an aux regulator */
-               reg = regulator_get(host->dev, "vmmc_aux");
-               host->vcc_aux = IS_ERR(reg) ? NULL : reg;
+       /* Allow an aux regulator */
+       reg = devm_regulator_get_optional(host->dev, "vmmc_aux");
+       host->vcc_aux = IS_ERR(reg) ? NULL : reg;
 
-               /* For eMMC do not power off when not in sleep state */
-               if (mmc_slot(host).no_regulator_off_init)
-                       return 0;
-               /*
-               * UGLY HACK:  workaround regulator framework bugs.
-               * When the bootloader leaves a supply active, it's
-               * initialized with zero usecount ... and we can't
-               * disable it without first enabling it.  Until the
-               * framework is fixed, we need a workaround like this
-               * (which is safe for MMC, but not in general).
-               */
-               if (regulator_is_enabled(host->vcc) > 0 ||
-                   (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
-                       int vdd = ffs(mmc_slot(host).ocr_mask) - 1;
+       reg = devm_regulator_get_optional(host->dev, "pbias");
+       host->pbias = IS_ERR(reg) ? NULL : reg;
 
-                       mmc_slot(host).set_power(host->dev, host->slot_id,
-                                                1, vdd);
-                       mmc_slot(host).set_power(host->dev, host->slot_id,
-                                                0, 0);
-               }
+       /* For eMMC do not power off when not in sleep state */
+       if (mmc_slot(host).no_regulator_off_init)
+               return 0;
+       /*
+        * To disable boot_on regulator, enable regulator
+        * to increase usecount and then disable it.
+        */
+       if ((host->vcc && regulator_is_enabled(host->vcc) > 0) ||
+           (host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
+               int vdd = ffs(mmc_slot(host).ocr_mask) - 1;
+
+               mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd);
+               mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
        }
 
        return 0;
@@ -366,8 +410,6 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
 
 static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
 {
-       regulator_put(host->vcc);
-       regulator_put(host->vcc_aux);
        mmc_slot(host).set_power = NULL;
 }
 
@@ -605,9 +647,6 @@ static int omap_hsmmc_context_restore(struct omap_hsmmc_host *host)
        u32 hctl, capa;
        unsigned long timeout;
 
-       if (!OMAP_HSMMC_READ(host->base, SYSSTATUS) & RESETDONE)
-               return 1;
-
        if (host->con == OMAP_HSMMC_READ(host->base, CON) &&
            host->hctl == OMAP_HSMMC_READ(host->base, HCTL) &&
            host->sysctl == OMAP_HSMMC_READ(host->base, SYSCTL) &&
@@ -787,6 +826,11 @@ omap_hsmmc_start_command(struct omap_hsmmc_host *host, struct mmc_command *cmd,
 
        cmdreg = (cmd->opcode << 24) | (resptype << 16) | (cmdtype << 22);
 
+       if ((host->flags & AUTO_CMD23) && mmc_op_multi(cmd->opcode) &&
+           host->mrq->sbc) {
+               cmdreg |= ACEN_ACMD23;
+               OMAP_HSMMC_WRITE(host->base, SDMASA, host->mrq->sbc->arg);
+       }
        if (data) {
                cmdreg |= DP_SELECT | MSBS | BCE;
                if (data->flags & MMC_DATA_READ)
@@ -864,11 +908,10 @@ omap_hsmmc_xfer_done(struct omap_hsmmc_host *host, struct mmc_data *data)
        else
                data->bytes_xfered = 0;
 
-       if (!data->stop) {
+       if (data->stop && (data->error || !host->mrq->sbc))
+               omap_hsmmc_start_command(host, data->stop, NULL);
+       else
                omap_hsmmc_request_done(host, data->mrq);
-               return;
-       }
-       omap_hsmmc_start_command(host, data->stop, NULL);
 }
 
 /*
@@ -879,6 +922,14 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
 {
        host->cmd = NULL;
 
+       if (host->mrq->sbc && (host->cmd == host->mrq->sbc) &&
+           !host->mrq->sbc->error && !(host->flags & AUTO_CMD23)) {
+               omap_hsmmc_start_dma_transfer(host);
+               omap_hsmmc_start_command(host, host->mrq->cmd,
+                                               host->mrq->data);
+               return;
+       }
+
        if (cmd->flags & MMC_RSP_PRESENT) {
                if (cmd->flags & MMC_RSP_136) {
                        /* response type 2 */
@@ -892,7 +943,7 @@ omap_hsmmc_cmd_done(struct omap_hsmmc_host *host, struct mmc_command *cmd)
                }
        }
        if ((host->data == NULL && !host->response_busy) || cmd->error)
-               omap_hsmmc_request_done(host, cmd->mrq);
+               omap_hsmmc_request_done(host, host->mrq);
 }
 
 /*
@@ -1015,6 +1066,7 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
 {
        struct mmc_data *data;
        int end_cmd = 0, end_trans = 0;
+       int error = 0;
 
        data = host->data;
        dev_vdbg(mmc_dev(host->mmc), "IRQ Status is %x\n", status);
@@ -1029,6 +1081,20 @@ static void omap_hsmmc_do_irq(struct omap_hsmmc_host *host, int status)
                else if (status & (CCRC_EN | DCRC_EN))
                        hsmmc_command_incomplete(host, -EILSEQ, end_cmd);
 
+               if (status & ACE_EN) {
+                       u32 ac12;
+                       ac12 = OMAP_HSMMC_READ(host->base, AC12);
+                       if (!(ac12 & ACNE) && host->mrq->sbc) {
+                               end_cmd = 1;
+                               if (ac12 & ACTO)
+                                       error =  -ETIMEDOUT;
+                               else if (ac12 & (ACCE | ACEB | ACIE))
+                                       error = -EILSEQ;
+                               host->mrq->sbc->error = error;
+                               hsmmc_command_incomplete(host, error, end_cmd);
+                       }
+                       dev_dbg(mmc_dev(host->mmc), "AC12 err: 0x%x\n", ac12);
+               }
                if (host->data || host->response_busy) {
                        end_trans = !end_cmd;
                        host->response_busy = 0;
@@ -1236,8 +1302,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
        }
 
        /* Check if next job is already prepared */
-       if (next ||
-           (!next && data->host_cookie != host->next_data.cookie)) {
+       if (next || data->host_cookie != host->next_data.cookie) {
                dma_len = dma_map_sg(chan->device->dev, data->sg, data->sg_len,
                                     omap_hsmmc_get_dma_dir(host, data));
 
@@ -1262,7 +1327,7 @@ static int omap_hsmmc_pre_dma_transfer(struct omap_hsmmc_host *host,
 /*
  * Routine to configure and start DMA for the MMC card
  */
-static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
+static int omap_hsmmc_setup_dma_transfer(struct omap_hsmmc_host *host,
                                        struct mmc_request *req)
 {
        struct dma_slave_config cfg;
@@ -1321,8 +1386,6 @@ static int omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host,
 
        host->dma_ch = 1;
 
-       dma_async_issue_pending(chan);
-
        return 0;
 }
 
@@ -1338,7 +1401,7 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
        if (clkd == 0)
                clkd = 1;
 
-       cycle_ns = 1000000000 / (clk_get_rate(host->fclk) / clkd);
+       cycle_ns = 1000000000 / (host->clk_rate / clkd);
        timeout = timeout_ns / cycle_ns;
        timeout += timeout_clks;
        if (timeout) {
@@ -1363,6 +1426,21 @@ static void set_data_timeout(struct omap_hsmmc_host *host,
        OMAP_HSMMC_WRITE(host->base, SYSCTL, reg);
 }
 
+static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host)
+{
+       struct mmc_request *req = host->mrq;
+       struct dma_chan *chan;
+
+       if (!req->data)
+               return;
+       OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
+                               | (req->data->blocks << 16));
+       set_data_timeout(host, req->data->timeout_ns,
+                               req->data->timeout_clks);
+       chan = omap_hsmmc_get_dma_chan(host, req->data);
+       dma_async_issue_pending(chan);
+}
+
 /*
  * Configure block length for MMC/SD cards and initiate the transfer.
  */
@@ -1383,12 +1461,8 @@ omap_hsmmc_prepare_data(struct omap_hsmmc_host *host, struct mmc_request *req)
                return 0;
        }
 
-       OMAP_HSMMC_WRITE(host->base, BLK, (req->data->blksz)
-                                       | (req->data->blocks << 16));
-       set_data_timeout(host, req->data->timeout_ns, req->data->timeout_clks);
-
        if (host->use_dma) {
-               ret = omap_hsmmc_start_dma_transfer(host, req);
+               ret = omap_hsmmc_setup_dma_transfer(host, req);
                if (ret != 0) {
                        dev_err(mmc_dev(host->mmc), "MMC start dma failure\n");
                        return ret;
@@ -1462,6 +1536,7 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
                host->reqs_blocked = 0;
        WARN_ON(host->mrq != NULL);
        host->mrq = req;
+       host->clk_rate = clk_get_rate(host->fclk);
        err = omap_hsmmc_prepare_data(host, req);
        if (err) {
                req->cmd->error = err;
@@ -1471,7 +1546,12 @@ static void omap_hsmmc_request(struct mmc_host *mmc, struct mmc_request *req)
                mmc_request_done(mmc, req);
                return;
        }
+       if (req->sbc && !(host->flags & AUTO_CMD23)) {
+               omap_hsmmc_start_command(host, req->sbc, NULL);
+               return;
+       }
 
+       omap_hsmmc_start_dma_transfer(host);
        omap_hsmmc_start_command(host, req->cmd, req->data);
 }
 
@@ -1509,13 +1589,7 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
                 * of external transceiver; but they all handle 1.8V.
                 */
                if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
-                       (ios->vdd == DUAL_VOLT_OCR_BIT) &&
-                       /*
-                        * With pbias cell programming missing, this
-                        * can't be allowed on MMC1 when booting with device
-                        * tree.
-                        */
-                       !host->pbias_disable) {
+                       (ios->vdd == DUAL_VOLT_OCR_BIT)) {
                                /*
                                 * The mmc_select_voltage fn of the core does
                                 * not seem to set the power_mode to
@@ -1678,18 +1752,29 @@ static void omap_hsmmc_debugfs(struct mmc_host *mmc)
 #endif
 
 #ifdef CONFIG_OF
-static u16 omap4_reg_offset = 0x100;
+static const struct omap_mmc_of_data omap3_pre_es3_mmc_of_data = {
+       /* See 35xx errata 2.1.1.128 in SPRZ278F */
+       .controller_flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
+};
+
+static const struct omap_mmc_of_data omap4_mmc_of_data = {
+       .reg_offset = 0x100,
+};
 
 static const struct of_device_id omap_mmc_of_match[] = {
        {
                .compatible = "ti,omap2-hsmmc",
        },
+       {
+               .compatible = "ti,omap3-pre-es3-hsmmc",
+               .data = &omap3_pre_es3_mmc_of_data,
+       },
        {
                .compatible = "ti,omap3-hsmmc",
        },
        {
                .compatible = "ti,omap4-hsmmc",
-               .data = &omap4_reg_offset,
+               .data = &omap4_mmc_of_data,
        },
        {},
 };
@@ -1709,7 +1794,7 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
 
        pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
-               return NULL; /* out of memory */
+               return ERR_PTR(-ENOMEM); /* out of memory */
 
        if (of_find_property(np, "ti,dual-volt", NULL))
                pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
@@ -1738,13 +1823,19 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
        if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
                pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT;
 
+       if (of_find_property(np, "keep-power-in-suspend", NULL))
+               pdata->slots[0].pm_caps |= MMC_PM_KEEP_POWER;
+
+       if (of_find_property(np, "enable-sdio-wakeup", NULL))
+               pdata->slots[0].pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+
        return pdata;
 }
 #else
 static inline struct omap_mmc_platform_data
                        *of_get_hsmmc_pdata(struct device *dev)
 {
-       return NULL;
+       return ERR_PTR(-EINVAL);
 }
 #endif
 
@@ -1759,6 +1850,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
        dma_cap_mask_t mask;
        unsigned tx_req, rx_req;
        struct pinctrl *pinctrl;
+       const struct omap_mmc_of_data *data;
 
        match = of_match_device(of_match_ptr(omap_mmc_of_match), &pdev->dev);
        if (match) {
@@ -1768,8 +1860,9 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
                        return PTR_ERR(pdata);
 
                if (match->data) {
-                       const u16 *offsetp = match->data;
-                       pdata->reg_offset = *offsetp;
+                       data = match->data;
+                       pdata->reg_offset = data->reg_offset;
+                       pdata->controller_flags |= data->controller_flags;
                }
        }
 
@@ -1814,6 +1907,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
        host->base      = ioremap(host->mapbase, SZ_4K);
        host->power_mode = MMC_POWER_OFF;
        host->next_data.cookie = 1;
+       host->pbias_enabled = 0;
 
        platform_set_drvdata(pdev, host);
 
@@ -1847,10 +1941,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
 
        omap_hsmmc_context_save(host);
 
-       /* This can be removed once we support PBIAS with DT */
-       if (host->dev->of_node && res->start == 0x4809c000)
-               host->pbias_disable = 1;
-
        host->dbclk = clk_get(&pdev->dev, "mmchsdb_fck");
        /*
         * MMC can still work without debounce clock.
index c46feda..5fb994f 100644 (file)
 #include <linux/mfd/rtsx_pci.h>
 #include <asm/unaligned.h>
 
-/* SD Tuning Data Structure
- * Record continuous timing phase path
- */
-struct timing_phase_path {
-       int start;
-       int end;
-       int mid;
-       int len;
+struct realtek_next {
+       unsigned int    sg_count;
+       s32             cookie;
 };
 
 struct realtek_pci_sdmmc {
@@ -46,9 +41,18 @@ struct realtek_pci_sdmmc {
        struct rtsx_pcr         *pcr;
        struct mmc_host         *mmc;
        struct mmc_request      *mrq;
-
-       struct mutex            host_mutex;
-
+       struct mmc_command      *cmd;
+       struct mmc_data         *data;
+
+       spinlock_t              lock;
+       struct timer_list       timer;
+       struct tasklet_struct   cmd_tasklet;
+       struct tasklet_struct   data_tasklet;
+       struct tasklet_struct   finish_tasklet;
+
+       u8                      rsp_type;
+       u8                      rsp_len;
+       int                     sg_count;
        u8                      ssc_depth;
        unsigned int            clock;
        bool                    vpclk;
@@ -58,8 +62,13 @@ struct realtek_pci_sdmmc {
        int                     power_state;
 #define SDMMC_POWER_ON         1
 #define SDMMC_POWER_OFF                0
+
+       struct realtek_next     next_data;
 };
 
+static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
+               struct mmc_request *mrq);
+
 static inline struct device *sdmmc_dev(struct realtek_pci_sdmmc *host)
 {
        return &(host->pdev->dev);
@@ -96,6 +105,95 @@ static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
 #define sd_print_debug_regs(host)
 #endif /* DEBUG */
 
+static void sd_isr_done_transfer(struct platform_device *pdev)
+{
+       struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
+
+       spin_lock(&host->lock);
+       if (host->cmd)
+               tasklet_schedule(&host->cmd_tasklet);
+       if (host->data)
+               tasklet_schedule(&host->data_tasklet);
+       spin_unlock(&host->lock);
+}
+
+static void sd_request_timeout(unsigned long host_addr)
+{
+       struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (!host->mrq) {
+               dev_err(sdmmc_dev(host), "error: no request exist\n");
+               goto out;
+       }
+
+       if (host->cmd)
+               host->cmd->error = -ETIMEDOUT;
+       if (host->data)
+               host->data->error = -ETIMEDOUT;
+
+       dev_dbg(sdmmc_dev(host), "timeout for request\n");
+
+out:
+       tasklet_schedule(&host->finish_tasklet);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void sd_finish_request(unsigned long host_addr)
+{
+       struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
+       struct rtsx_pcr *pcr = host->pcr;
+       struct mmc_request *mrq;
+       struct mmc_command *cmd;
+       struct mmc_data *data;
+       unsigned long flags;
+       bool any_error;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       del_timer(&host->timer);
+       mrq = host->mrq;
+       if (!mrq) {
+               dev_err(sdmmc_dev(host), "error: no request need finish\n");
+               goto out;
+       }
+
+       cmd = mrq->cmd;
+       data = mrq->data;
+
+       any_error = (mrq->sbc && mrq->sbc->error) ||
+               (mrq->stop && mrq->stop->error) ||
+               (cmd && cmd->error) || (data && data->error);
+
+       if (any_error) {
+               rtsx_pci_stop_cmd(pcr);
+               sd_clear_error(host);
+       }
+
+       if (data) {
+               if (any_error)
+                       data->bytes_xfered = 0;
+               else
+                       data->bytes_xfered = data->blocks * data->blksz;
+
+               if (!data->host_cookie)
+                       rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len,
+                                       data->flags & MMC_DATA_READ);
+
+       }
+
+       host->mrq = NULL;
+       host->cmd = NULL;
+       host->data = NULL;
+
+out:
+       spin_unlock_irqrestore(&host->lock, flags);
+       mutex_unlock(&pcr->pcr_mutex);
+       mmc_request_done(host->mmc, mrq);
+}
+
 static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
                u8 *buf, int buf_len, int timeout)
 {
@@ -213,8 +311,7 @@ static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
        return 0;
 }
 
-static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
-               struct mmc_command *cmd)
+static void sd_send_cmd(struct realtek_pci_sdmmc *host, struct mmc_command *cmd)
 {
        struct rtsx_pcr *pcr = host->pcr;
        u8 cmd_idx = (u8)cmd->opcode;
@@ -222,11 +319,14 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
        int err = 0;
        int timeout = 100;
        int i;
-       u8 *ptr;
-       int stat_idx = 0;
        u8 rsp_type;
        int rsp_len = 5;
-       bool clock_toggled = false;
+       unsigned long flags;
+
+       if (host->cmd)
+               dev_err(sdmmc_dev(host), "error: cmd already exist\n");
+
+       host->cmd = cmd;
 
        dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
                        __func__, cmd_idx, arg);
@@ -261,6 +361,8 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
                err = -EINVAL;
                goto out;
        }
+       host->rsp_type = rsp_type;
+       host->rsp_len = rsp_len;
 
        if (rsp_type == SD_RSP_TYPE_R1b)
                timeout = 3000;
@@ -270,8 +372,6 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
                                0xFF, SD_CLK_TOGGLE_EN);
                if (err < 0)
                        goto out;
-
-               clock_toggled = true;
        }
 
        rtsx_pci_init_cmd(pcr);
@@ -295,25 +395,60 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
                /* Read data from ping-pong buffer */
                for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
                        rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
-               stat_idx = 16;
        } else if (rsp_type != SD_RSP_TYPE_R0) {
                /* Read data from SD_CMDx registers */
                for (i = SD_CMD0; i <= SD_CMD4; i++)
                        rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
-               stat_idx = 5;
        }
 
        rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0);
 
-       err = rtsx_pci_send_cmd(pcr, timeout);
-       if (err < 0) {
-               sd_print_debug_regs(host);
-               sd_clear_error(host);
-               dev_dbg(sdmmc_dev(host),
-                       "rtsx_pci_send_cmd error (err = %d)\n", err);
+       mod_timer(&host->timer, jiffies + msecs_to_jiffies(timeout));
+
+       spin_lock_irqsave(&pcr->lock, flags);
+       pcr->trans_result = TRANS_NOT_READY;
+       rtsx_pci_send_cmd_no_wait(pcr);
+       spin_unlock_irqrestore(&pcr->lock, flags);
+
+       return;
+
+out:
+       cmd->error = err;
+       tasklet_schedule(&host->finish_tasklet);
+}
+
+static void sd_get_rsp(unsigned long host_addr)
+{
+       struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
+       struct rtsx_pcr *pcr = host->pcr;
+       struct mmc_command *cmd;
+       int i, err = 0, stat_idx;
+       u8 *ptr, rsp_type;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       cmd = host->cmd;
+       host->cmd = NULL;
+
+       if (!cmd) {
+               dev_err(sdmmc_dev(host), "error: cmd not exist\n");
                goto out;
        }
 
+       spin_lock(&pcr->lock);
+       if (pcr->trans_result == TRANS_NO_DEVICE)
+               err = -ENODEV;
+       else if (pcr->trans_result != TRANS_RESULT_OK)
+               err = -EINVAL;
+       spin_unlock(&pcr->lock);
+
+       if (err < 0)
+               goto out;
+
+       rsp_type = host->rsp_type;
+       stat_idx = host->rsp_len;
+
        if (rsp_type == SD_RSP_TYPE_R0) {
                err = 0;
                goto out;
@@ -350,26 +485,106 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
                                cmd->resp[0]);
        }
 
+       if (cmd == host->mrq->sbc) {
+               sd_send_cmd(host, host->mrq->cmd);
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+       if (cmd == host->mrq->stop)
+               goto out;
+
+       if (cmd->data) {
+               sd_start_multi_rw(host, host->mrq);
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
 out:
        cmd->error = err;
 
-       if (err && clock_toggled)
-               rtsx_pci_write_register(pcr, SD_BUS_STAT,
-                               SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
+       tasklet_schedule(&host->finish_tasklet);
+       spin_unlock_irqrestore(&host->lock, flags);
 }
 
-static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
+static int sd_pre_dma_transfer(struct realtek_pci_sdmmc *host,
+                       struct mmc_data *data, struct realtek_next *next)
+{
+       struct rtsx_pcr *pcr = host->pcr;
+       int read = data->flags & MMC_DATA_READ;
+       int sg_count = 0;
+
+       if (!next && data->host_cookie &&
+               data->host_cookie != host->next_data.cookie) {
+               dev_err(sdmmc_dev(host),
+                       "error: invalid cookie data[%d] host[%d]\n",
+                       data->host_cookie, host->next_data.cookie);
+               data->host_cookie = 0;
+       }
+
+       if (next || (!next && data->host_cookie != host->next_data.cookie))
+               sg_count = rtsx_pci_dma_map_sg(pcr,
+                               data->sg, data->sg_len, read);
+       else
+               sg_count = host->next_data.sg_count;
+
+       if (next) {
+               next->sg_count = sg_count;
+               if (++next->cookie < 0)
+                       next->cookie = 1;
+               data->host_cookie = next->cookie;
+       }
+
+       return sg_count;
+}
+
+static void sdmmc_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+               bool is_first_req)
+{
+       struct realtek_pci_sdmmc *host = mmc_priv(mmc);
+       struct mmc_data *data = mrq->data;
+
+       if (data->host_cookie) {
+               dev_err(sdmmc_dev(host),
+                       "error: descard already cookie data[%d]\n",
+                       data->host_cookie);
+               data->host_cookie = 0;
+       }
+
+       dev_dbg(sdmmc_dev(host), "dma sg prepared: %d\n",
+               sd_pre_dma_transfer(host, data, &host->next_data));
+}
+
+static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+               int err)
+{
+       struct realtek_pci_sdmmc *host = mmc_priv(mmc);
+       struct rtsx_pcr *pcr = host->pcr;
+       struct mmc_data *data = mrq->data;
+       int read = data->flags & MMC_DATA_READ;
+
+       rtsx_pci_dma_unmap_sg(pcr, data->sg, data->sg_len, read);
+       data->host_cookie = 0;
+}
+
+static int sd_start_multi_rw(struct realtek_pci_sdmmc *host,
+               struct mmc_request *mrq)
 {
        struct rtsx_pcr *pcr = host->pcr;
        struct mmc_host *mmc = host->mmc;
        struct mmc_card *card = mmc->card;
        struct mmc_data *data = mrq->data;
        int uhs = mmc_card_uhs(card);
-       int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
+       int read = data->flags & MMC_DATA_READ;
        u8 cfg2, trans_mode;
        int err;
        size_t data_len = data->blksz * data->blocks;
 
+       if (host->data)
+               dev_err(sdmmc_dev(host), "error: data already exist\n");
+
+       host->data = data;
+
        if (read) {
                cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
                        SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
@@ -420,17 +635,56 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
        rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
                        SD_TRANSFER_END, SD_TRANSFER_END);
 
+       mod_timer(&host->timer, jiffies + 10 * HZ);
        rtsx_pci_send_cmd_no_wait(pcr);
 
-       err = rtsx_pci_transfer_data(pcr, data->sg, data->sg_len, read, 10000);
+       err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read);
        if (err < 0) {
-               sd_clear_error(host);
-               return err;
+               data->error = err;
+               tasklet_schedule(&host->finish_tasklet);
        }
-
        return 0;
 }
 
+static void sd_finish_multi_rw(unsigned long host_addr)
+{
+       struct realtek_pci_sdmmc *host = (struct realtek_pci_sdmmc *)host_addr;
+       struct rtsx_pcr *pcr = host->pcr;
+       struct mmc_data *data;
+       int err = 0;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (!host->data) {
+               dev_err(sdmmc_dev(host), "error: no data exist\n");
+               goto out;
+       }
+
+       data = host->data;
+       host->data = NULL;
+
+       if (pcr->trans_result == TRANS_NO_DEVICE)
+               err = -ENODEV;
+       else if (pcr->trans_result != TRANS_RESULT_OK)
+               err = -EINVAL;
+
+       if (err < 0) {
+               data->error = err;
+               goto out;
+       }
+
+       if (!host->mrq->sbc && data->stop) {
+               sd_send_cmd(host, data->stop);
+               spin_unlock_irqrestore(&host->lock, flags);
+               return;
+       }
+
+out:
+       tasklet_schedule(&host->finish_tasklet);
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
 static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host)
 {
        rtsx_pci_write_register(host->pcr, SD_CFG1,
@@ -511,85 +765,47 @@ static int sd_change_phase(struct realtek_pci_sdmmc *host,
        return 0;
 }
 
-static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map)
+static inline u32 test_phase_bit(u32 phase_map, unsigned int bit)
 {
-       struct timing_phase_path path[MAX_PHASE + 1];
-       int i, j, cont_path_cnt;
-       int new_block, max_len, final_path_idx;
-       u8 final_phase = 0xFF;
+       bit %= RTSX_PHASE_MAX;
+       return phase_map & (1 << bit);
+}
 
-       /* Parse phase_map, take it as a bit-ring */
-       cont_path_cnt = 0;
-       new_block = 1;
-       j = 0;
-       for (i = 0; i < MAX_PHASE + 1; i++) {
-               if (phase_map & (1 << i)) {
-                       if (new_block) {
-                               new_block = 0;
-                               j = cont_path_cnt++;
-                               path[j].start = i;
-                               path[j].end = i;
-                       } else {
-                               path[j].end = i;
-                       }
-               } else {
-                       new_block = 1;
-                       if (cont_path_cnt) {
-                               /* Calculate path length and middle point */
-                               int idx = cont_path_cnt - 1;
-                               path[idx].len =
-                                       path[idx].end - path[idx].start + 1;
-                               path[idx].mid =
-                                       path[idx].start + path[idx].len / 2;
-                       }
-               }
-       }
+static int sd_get_phase_len(u32 phase_map, unsigned int start_bit)
+{
+       int i;
 
-       if (cont_path_cnt == 0) {
-               dev_dbg(sdmmc_dev(host), "No continuous phase path\n");
-               goto finish;
-       } else {
-               /* Calculate last continuous path length and middle point */
-               int idx = cont_path_cnt - 1;
-               path[idx].len = path[idx].end - path[idx].start + 1;
-               path[idx].mid = path[idx].start + path[idx].len / 2;
+       for (i = 0; i < RTSX_PHASE_MAX; i++) {
+               if (test_phase_bit(phase_map, start_bit + i) == 0)
+                       return i;
        }
+       return RTSX_PHASE_MAX;
+}
+
+static u8 sd_search_final_phase(struct realtek_pci_sdmmc *host, u32 phase_map)
+{
+       int start = 0, len = 0;
+       int start_final = 0, len_final = 0;
+       u8 final_phase = 0xFF;
 
-       /* Connect the first and last continuous paths if they are adjacent */
-       if (!path[0].start && (path[cont_path_cnt - 1].end == MAX_PHASE)) {
-               /* Using negative index */
-               path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1;
-               path[0].len += path[cont_path_cnt - 1].len;
-               path[0].mid = path[0].start + path[0].len / 2;
-               /* Convert negative middle point index to positive one */
-               if (path[0].mid < 0)
-                       path[0].mid += MAX_PHASE + 1;
-               cont_path_cnt--;
+       if (phase_map == 0) {
+               dev_err(sdmmc_dev(host), "phase error: [map:%x]\n", phase_map);
+               return final_phase;
        }
 
-       /* Choose the longest continuous phase path */
-       max_len = 0;
-       final_phase = 0;
-       final_path_idx = 0;
-       for (i = 0; i < cont_path_cnt; i++) {
-               if (path[i].len > max_len) {
-                       max_len = path[i].len;
-                       final_phase = (u8)path[i].mid;
-                       final_path_idx = i;
+       while (start < RTSX_PHASE_MAX) {
+               len = sd_get_phase_len(phase_map, start);
+               if (len_final < len) {
+                       start_final = start;
+                       len_final = len;
                }
-
-               dev_dbg(sdmmc_dev(host), "path[%d].start = %d\n",
-                               i, path[i].start);
-               dev_dbg(sdmmc_dev(host), "path[%d].end = %d\n",
-                               i, path[i].end);
-               dev_dbg(sdmmc_dev(host), "path[%d].len = %d\n",
-                               i, path[i].len);
-               dev_dbg(sdmmc_dev(host), "path[%d].mid = %d\n",
-                               i, path[i].mid);
+               start += len ? len : 1;
        }
 
-finish:
-       dev_dbg(sdmmc_dev(host), "Final chosen phase: %d\n", final_phase);
+       final_phase = (start_final + len_final / 2) % RTSX_PHASE_MAX;
+       dev_dbg(sdmmc_dev(host), "phase: [map:%x] [maxlen:%d] [final:%d]\n",
+               phase_map, len_final, final_phase);
+
        return final_phase;
 }
 
@@ -635,7 +851,7 @@ static int sd_tuning_phase(struct realtek_pci_sdmmc *host,
        int err, i;
        u32 raw_phase_map = 0;
 
-       for (i = MAX_PHASE; i >= 0; i--) {
+       for (i = 0; i < RTSX_PHASE_MAX; i++) {
                err = sd_tuning_rx_cmd(host, opcode, (u8)i);
                if (err == 0)
                        raw_phase_map |= 1 << i;
@@ -685,6 +901,13 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode)
        return 0;
 }
 
+static inline bool sd_use_muti_rw(struct mmc_command *cmd)
+{
+       return mmc_op_multi(cmd->opcode) ||
+               (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
+               (cmd->opcode == MMC_WRITE_BLOCK);
+}
+
 static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
 {
        struct realtek_pci_sdmmc *host = mmc_priv(mmc);
@@ -693,6 +916,14 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        struct mmc_data *data = mrq->data;
        unsigned int data_size = 0;
        int err;
+       unsigned long flags;
+
+       mutex_lock(&pcr->pcr_mutex);
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (host->mrq)
+               dev_err(sdmmc_dev(host), "error: request already exist\n");
+       host->mrq = mrq;
 
        if (host->eject) {
                cmd->error = -ENOMEDIUM;
@@ -705,8 +936,6 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
                goto finish;
        }
 
-       mutex_lock(&pcr->pcr_mutex);
-
        rtsx_pci_start_run(pcr);
 
        rtsx_pci_switch_clock(pcr, host->clock, host->ssc_depth,
@@ -715,46 +944,28 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
        rtsx_pci_write_register(pcr, CARD_SHARE_MODE,
                        CARD_SHARE_MASK, CARD_SHARE_48_SD);
 
-       mutex_lock(&host->host_mutex);
-       host->mrq = mrq;
-       mutex_unlock(&host->host_mutex);
-
        if (mrq->data)
                data_size = data->blocks * data->blksz;
 
-       if (!data_size || mmc_op_multi(cmd->opcode) ||
-                       (cmd->opcode == MMC_READ_SINGLE_BLOCK) ||
-                       (cmd->opcode == MMC_WRITE_BLOCK)) {
-               sd_send_cmd_get_rsp(host, cmd);
-
-               if (!cmd->error && data_size) {
-                       sd_rw_multi(host, mrq);
+       if (sd_use_muti_rw(cmd))
+               host->sg_count = sd_pre_dma_transfer(host, data, NULL);
 
-                       if (mmc_op_multi(cmd->opcode) && mrq->stop)
-                               sd_send_cmd_get_rsp(host, mrq->stop);
-               }
+       if (!data_size || sd_use_muti_rw(cmd)) {
+               if (mrq->sbc)
+                       sd_send_cmd(host, mrq->sbc);
+               else
+                       sd_send_cmd(host, cmd);
+               spin_unlock_irqrestore(&host->lock, flags);
        } else {
+               spin_unlock_irqrestore(&host->lock, flags);
                sd_normal_rw(host, mrq);
+               tasklet_schedule(&host->finish_tasklet);
        }
-
-       if (mrq->data) {
-               if (cmd->error || data->error)
-                       data->bytes_xfered = 0;
-               else
-                       data->bytes_xfered = data->blocks * data->blksz;
-       }
-
-       mutex_unlock(&pcr->pcr_mutex);
+       return;
 
 finish:
-       if (cmd->error)
-               dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error);
-
-       mutex_lock(&host->host_mutex);
-       host->mrq = NULL;
-       mutex_unlock(&host->host_mutex);
-
-       mmc_request_done(mmc, mrq);
+       tasklet_schedule(&host->finish_tasklet);
+       spin_unlock_irqrestore(&host->lock, flags);
 }
 
 static int sd_set_bus_width(struct realtek_pci_sdmmc *host,
@@ -1189,6 +1400,8 @@ out:
 }
 
 static const struct mmc_host_ops realtek_pci_sdmmc_ops = {
+       .pre_req = sdmmc_pre_req,
+       .post_req = sdmmc_post_req,
        .request = sdmmc_request,
        .set_ios = sdmmc_set_ios,
        .get_ro = sdmmc_get_ro,
@@ -1252,6 +1465,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
        struct realtek_pci_sdmmc *host;
        struct rtsx_pcr *pcr;
        struct pcr_handle *handle = pdev->dev.platform_data;
+       unsigned long host_addr;
 
        if (!handle)
                return -ENXIO;
@@ -1275,8 +1489,15 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
        pcr->slots[RTSX_SD_CARD].p_dev = pdev;
        pcr->slots[RTSX_SD_CARD].card_event = rtsx_pci_sdmmc_card_event;
 
-       mutex_init(&host->host_mutex);
+       host_addr = (unsigned long)host;
+       host->next_data.cookie = 1;
+       setup_timer(&host->timer, sd_request_timeout, host_addr);
+       tasklet_init(&host->cmd_tasklet, sd_get_rsp, host_addr);
+       tasklet_init(&host->data_tasklet, sd_finish_multi_rw, host_addr);
+       tasklet_init(&host->finish_tasklet, sd_finish_request, host_addr);
+       spin_lock_init(&host->lock);
 
+       pcr->slots[RTSX_SD_CARD].done_transfer = sd_isr_done_transfer;
        realtek_init_host(host);
 
        mmc_add_host(mmc);
@@ -1289,6 +1510,8 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
        struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
        struct rtsx_pcr *pcr;
        struct mmc_host *mmc;
+       struct mmc_request *mrq;
+       unsigned long flags;
 
        if (!host)
                return 0;
@@ -1296,25 +1519,37 @@ static int rtsx_pci_sdmmc_drv_remove(struct platform_device *pdev)
        pcr = host->pcr;
        pcr->slots[RTSX_SD_CARD].p_dev = NULL;
        pcr->slots[RTSX_SD_CARD].card_event = NULL;
+       pcr->slots[RTSX_SD_CARD].done_transfer = NULL;
        mmc = host->mmc;
-       host->eject = true;
+       mrq = host->mrq;
 
-       mutex_lock(&host->host_mutex);
+       spin_lock_irqsave(&host->lock, flags);
        if (host->mrq) {
                dev_dbg(&(pdev->dev),
                        "%s: Controller removed during transfer\n",
                        mmc_hostname(mmc));
 
-               rtsx_pci_complete_unfinished_transfer(pcr);
+               if (mrq->sbc)
+                       mrq->sbc->error = -ENOMEDIUM;
+               if (mrq->cmd)
+                       mrq->cmd->error = -ENOMEDIUM;
+               if (mrq->stop)
+                       mrq->stop->error = -ENOMEDIUM;
+               if (mrq->data)
+                       mrq->data->error = -ENOMEDIUM;
 
-               host->mrq->cmd->error = -ENOMEDIUM;
-               if (host->mrq->stop)
-                       host->mrq->stop->error = -ENOMEDIUM;
-               mmc_request_done(mmc, host->mrq);
+               tasklet_schedule(&host->finish_tasklet);
        }
-       mutex_unlock(&host->host_mutex);
+       spin_unlock_irqrestore(&host->lock, flags);
+
+       del_timer_sync(&host->timer);
+       tasklet_kill(&host->cmd_tasklet);
+       tasklet_kill(&host->data_tasklet);
+       tasklet_kill(&host->finish_tasklet);
 
        mmc_remove_host(mmc);
+       host->eject = true;
+
        mmc_free_host(mmc);
 
        dev_dbg(&(pdev->dev),
index 9ce17f6..ebb3f39 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/bitops.h>
 #include <linux/types.h>
 #include <linux/err.h>
-#include <linux/gpio/consumer.h>
 #include <linux/interrupt.h>
 #include <linux/acpi.h>
 #include <linux/pm.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/pm.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/mmc/sdhci.h>
 
 #include "sdhci.h"
 
 enum {
-       SDHCI_ACPI_SD_CD        = BIT(0),
-       SDHCI_ACPI_RUNTIME_PM   = BIT(1),
+       SDHCI_ACPI_SD_CD                = BIT(0),
+       SDHCI_ACPI_RUNTIME_PM           = BIT(1),
+       SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL = BIT(2),
 };
 
 struct sdhci_acpi_chip {
@@ -121,6 +122,7 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
+       .quirks  = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
        .quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
        .caps    = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
        .flags   = SDHCI_ACPI_RUNTIME_PM,
@@ -128,7 +130,8 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
 };
 
 static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
-       .flags   = SDHCI_ACPI_SD_CD | SDHCI_ACPI_RUNTIME_PM,
+       .flags   = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
+                  SDHCI_ACPI_RUNTIME_PM,
        .quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON,
 };
 
@@ -141,6 +144,7 @@ struct sdhci_acpi_uid_slot {
 static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
        { "80860F14" , "1" , &sdhci_acpi_slot_int_emmc },
        { "80860F14" , "3" , &sdhci_acpi_slot_int_sd   },
+       { "80860F16" , NULL, &sdhci_acpi_slot_int_sd   },
        { "INT33BB"  , "2" , &sdhci_acpi_slot_int_sdio },
        { "INT33C6"  , NULL, &sdhci_acpi_slot_int_sdio },
        { "INT3436"  , NULL, &sdhci_acpi_slot_int_sdio },
@@ -150,6 +154,7 @@ static const struct sdhci_acpi_uid_slot sdhci_acpi_uids[] = {
 
 static const struct acpi_device_id sdhci_acpi_ids[] = {
        { "80860F14" },
+       { "80860F16" },
        { "INT33BB"  },
        { "INT33C6"  },
        { "INT3436"  },
@@ -192,59 +197,6 @@ static const struct sdhci_acpi_slot *sdhci_acpi_get_slot(acpi_handle handle,
        return slot;
 }
 
-#ifdef CONFIG_PM_RUNTIME
-
-static irqreturn_t sdhci_acpi_sd_cd(int irq, void *dev_id)
-{
-       mmc_detect_change(dev_id, msecs_to_jiffies(200));
-       return IRQ_HANDLED;
-}
-
-static int sdhci_acpi_add_own_cd(struct device *dev, struct mmc_host *mmc)
-{
-       struct gpio_desc *desc;
-       unsigned long flags;
-       int err, irq;
-
-       desc = devm_gpiod_get_index(dev, "sd_cd", 0);
-       if (IS_ERR(desc)) {
-               err = PTR_ERR(desc);
-               goto out;
-       }
-
-       err = gpiod_direction_input(desc);
-       if (err)
-               goto out_free;
-
-       irq = gpiod_to_irq(desc);
-       if (irq < 0) {
-               err = irq;
-               goto out_free;
-       }
-
-       flags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING;
-       err = devm_request_irq(dev, irq, sdhci_acpi_sd_cd, flags, "sd_cd", mmc);
-       if (err)
-               goto out_free;
-
-       return 0;
-
-out_free:
-       devm_gpiod_put(dev, desc);
-out:
-       dev_warn(dev, "failed to setup card detect wake up\n");
-       return err;
-}
-
-#else
-
-static int sdhci_acpi_add_own_cd(struct device *dev, struct mmc_host *mmc)
-{
-       return 0;
-}
-
-#endif
-
 static int sdhci_acpi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -332,15 +284,19 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
 
        host->mmc->caps2 |= MMC_CAP2_NO_PRESCAN_POWERUP;
 
-       err = sdhci_add_host(host);
-       if (err)
-               goto err_free;
-
        if (sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD)) {
-               if (sdhci_acpi_add_own_cd(dev, host->mmc))
+               bool v = sdhci_acpi_flag(c, SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL);
+
+               if (mmc_gpiod_request_cd(host->mmc, NULL, 0, v, 0)) {
+                       dev_warn(dev, "failed to setup card detect gpio\n");
                        c->use_runtime_pm = false;
+               }
        }
 
+       err = sdhci_add_host(host);
+       if (err)
+               goto err_free;
+
        if (c->use_runtime_pm) {
                pm_runtime_set_active(dev);
                pm_suspend_ignore_children(dev, 1);
index 7a190fe..6f166e6 100644 (file)
@@ -54,6 +54,7 @@
 
 struct sdhci_bcm_kona_dev {
        struct mutex    write_lock; /* protect back to back writes */
+       struct clk      *external_clk;
 };
 
 
@@ -257,6 +258,24 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
                goto err_pltfm_free;
        }
 
+       /* Get and enable the external clock */
+       kona_dev->external_clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(kona_dev->external_clk)) {
+               dev_err(dev, "Failed to get external clock\n");
+               ret = PTR_ERR(kona_dev->external_clk);
+               goto err_pltfm_free;
+       }
+
+       if (clk_set_rate(kona_dev->external_clk, host->mmc->f_max) != 0) {
+               dev_err(dev, "Failed to set rate external clock\n");
+               goto err_pltfm_free;
+       }
+
+       if (clk_prepare_enable(kona_dev->external_clk) != 0) {
+               dev_err(dev, "Failed to enable external clock\n");
+               goto err_pltfm_free;
+       }
+
        dev_dbg(dev, "non-removable=%c\n",
                (host->mmc->caps & MMC_CAP_NONREMOVABLE) ? 'Y' : 'N');
        dev_dbg(dev, "cd_gpio %c, wp_gpio %c\n",
@@ -271,7 +290,7 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
 
        ret = sdhci_bcm_kona_sd_reset(host);
        if (ret)
-               goto err_pltfm_free;
+               goto err_clk_disable;
 
        sdhci_bcm_kona_sd_init(host);
 
@@ -307,6 +326,9 @@ err_remove_host:
 err_reset:
        sdhci_bcm_kona_sd_reset(host);
 
+err_clk_disable:
+       clk_disable_unprepare(kona_dev->external_clk);
+
 err_pltfm_free:
        sdhci_pltfm_free(pdev);
 
@@ -314,9 +336,20 @@ err_pltfm_free:
        return ret;
 }
 
-static int __exit sdhci_bcm_kona_remove(struct platform_device *pdev)
+static int sdhci_bcm_kona_remove(struct platform_device *pdev)
 {
-       return sdhci_pltfm_unregister(pdev);
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_pltfm_host *pltfm_priv = sdhci_priv(host);
+       struct sdhci_bcm_kona_dev *kona_dev = sdhci_pltfm_priv(pltfm_priv);
+       int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
+
+       sdhci_remove_host(host, dead);
+
+       clk_disable_unprepare(kona_dev->external_clk);
+
+       sdhci_pltfm_free(pdev);
+
+       return 0;
 }
 
 static struct platform_driver sdhci_bcm_kona_driver = {
index 8424839..736d7a2 100644 (file)
@@ -208,7 +208,7 @@ static struct platform_driver sdhci_dove_driver = {
                .name   = "sdhci-dove",
                .owner  = THIS_MODULE,
                .pm     = SDHCI_PLTFM_PMOPS,
-               .of_match_table = of_match_ptr(sdhci_dove_of_match_table),
+               .of_match_table = sdhci_dove_of_match_table,
        },
        .probe          = sdhci_dove_probe,
        .remove         = sdhci_dove_remove,
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
new file mode 100644 (file)
index 0000000..acb0e9e
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+ * drivers/mmc/host/sdhci-msm.c - Qualcomm SDHCI Platform driver
+ *
+ * Copyright (c) 2013-2014, The Linux Foundation. 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 version 2 and
+ * only 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/module.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/mmc/mmc.h>
+#include <linux/slab.h>
+
+#include "sdhci-pltfm.h"
+
+#define CORE_HC_MODE           0x78
+#define HC_MODE_EN             0x1
+#define CORE_POWER             0x0
+#define CORE_SW_RST            BIT(7)
+
+#define MAX_PHASES             16
+#define CORE_DLL_LOCK          BIT(7)
+#define CORE_DLL_EN            BIT(16)
+#define CORE_CDR_EN            BIT(17)
+#define CORE_CK_OUT_EN         BIT(18)
+#define CORE_CDR_EXT_EN                BIT(19)
+#define CORE_DLL_PDN           BIT(29)
+#define CORE_DLL_RST           BIT(30)
+#define CORE_DLL_CONFIG                0x100
+#define CORE_DLL_STATUS                0x108
+
+#define CORE_VENDOR_SPEC       0x10c
+#define CORE_CLK_PWRSAVE       BIT(1)
+
+#define CDR_SELEXT_SHIFT       20
+#define CDR_SELEXT_MASK                (0xf << CDR_SELEXT_SHIFT)
+#define CMUX_SHIFT_PHASE_SHIFT 24
+#define CMUX_SHIFT_PHASE_MASK  (7 << CMUX_SHIFT_PHASE_SHIFT)
+
+static const u32 tuning_block_64[] = {
+       0x00ff0fff, 0xccc3ccff, 0xffcc3cc3, 0xeffefffe,
+       0xddffdfff, 0xfbfffbff, 0xff7fffbf, 0xefbdf777,
+       0xf0fff0ff, 0x3cccfc0f, 0xcfcc33cc, 0xeeffefff,
+       0xfdfffdff, 0xffbfffdf, 0xfff7ffbb, 0xde7b7ff7
+};
+
+static const u32 tuning_block_128[] = {
+       0xff00ffff, 0x0000ffff, 0xccccffff, 0xcccc33cc,
+       0xcc3333cc, 0xffffcccc, 0xffffeeff, 0xffeeeeff,
+       0xffddffff, 0xddddffff, 0xbbffffff, 0xbbffffff,
+       0xffffffbb, 0xffffff77, 0x77ff7777, 0xffeeddbb,
+       0x00ffffff, 0x00ffffff, 0xccffff00, 0xcc33cccc,
+       0x3333cccc, 0xffcccccc, 0xffeeffff, 0xeeeeffff,
+       0xddffffff, 0xddffffff, 0xffffffdd, 0xffffffbb,
+       0xffffbbbb, 0xffff77ff, 0xff7777ff, 0xeeddbb77
+};
+
+struct sdhci_msm_host {
+       struct platform_device *pdev;
+       void __iomem *core_mem; /* MSM SDCC mapped address */
+       struct clk *clk;        /* main SD/MMC bus clock */
+       struct clk *pclk;       /* SDHC peripheral bus clock */
+       struct clk *bus_clk;    /* SDHC bus voter clock */
+       struct mmc_host *mmc;
+       struct sdhci_pltfm_data sdhci_msm_pdata;
+};
+
+/* Platform specific tuning */
+static inline int msm_dll_poll_ck_out_en(struct sdhci_host *host, u8 poll)
+{
+       u32 wait_cnt = 50;
+       u8 ck_out_en;
+       struct mmc_host *mmc = host->mmc;
+
+       /* Poll for CK_OUT_EN bit.  max. poll time = 50us */
+       ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
+                       CORE_CK_OUT_EN);
+
+       while (ck_out_en != poll) {
+               if (--wait_cnt == 0) {
+                       dev_err(mmc_dev(mmc), "%s: CK_OUT_EN bit is not %d\n",
+                              mmc_hostname(mmc), poll);
+                       return -ETIMEDOUT;
+               }
+               udelay(1);
+
+               ck_out_en = !!(readl_relaxed(host->ioaddr + CORE_DLL_CONFIG) &
+                               CORE_CK_OUT_EN);
+       }
+
+       return 0;
+}
+
+static int msm_config_cm_dll_phase(struct sdhci_host *host, u8 phase)
+{
+       int rc;
+       static const u8 grey_coded_phase_table[] = {
+               0x0, 0x1, 0x3, 0x2, 0x6, 0x7, 0x5, 0x4,
+               0xc, 0xd, 0xf, 0xe, 0xa, 0xb, 0x9, 0x8
+       };
+       unsigned long flags;
+       u32 config;
+       struct mmc_host *mmc = host->mmc;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+       config &= ~(CORE_CDR_EN | CORE_CK_OUT_EN);
+       config |= (CORE_CDR_EXT_EN | CORE_DLL_EN);
+       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '0' */
+       rc = msm_dll_poll_ck_out_en(host, 0);
+       if (rc)
+               goto err_out;
+
+       /*
+        * Write the selected DLL clock output phase (0 ... 15)
+        * to CDR_SELEXT bit field of DLL_CONFIG register.
+        */
+       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+       config &= ~CDR_SELEXT_MASK;
+       config |= grey_coded_phase_table[phase] << CDR_SELEXT_SHIFT;
+       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Set CK_OUT_EN bit of DLL_CONFIG register to 1. */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Wait until CK_OUT_EN bit of DLL_CONFIG register becomes '1' */
+       rc = msm_dll_poll_ck_out_en(host, 1);
+       if (rc)
+               goto err_out;
+
+       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+       config |= CORE_CDR_EN;
+       config &= ~CORE_CDR_EXT_EN;
+       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+       goto out;
+
+err_out:
+       dev_err(mmc_dev(mmc), "%s: Failed to set DLL phase: %d\n",
+              mmc_hostname(mmc), phase);
+out:
+       spin_unlock_irqrestore(&host->lock, flags);
+       return rc;
+}
+
+/*
+ * Find out the greatest range of consecuitive selected
+ * DLL clock output phases that can be used as sampling
+ * setting for SD3.0 UHS-I card read operation (in SDR104
+ * timing mode) or for eMMC4.5 card read operation (in HS200
+ * timing mode).
+ * Select the 3/4 of the range and configure the DLL with the
+ * selected DLL clock output phase.
+ */
+
+static int msm_find_most_appropriate_phase(struct sdhci_host *host,
+                                          u8 *phase_table, u8 total_phases)
+{
+       int ret;
+       u8 ranges[MAX_PHASES][MAX_PHASES] = { {0}, {0} };
+       u8 phases_per_row[MAX_PHASES] = { 0 };
+       int row_index = 0, col_index = 0, selected_row_index = 0, curr_max = 0;
+       int i, cnt, phase_0_raw_index = 0, phase_15_raw_index = 0;
+       bool phase_0_found = false, phase_15_found = false;
+       struct mmc_host *mmc = host->mmc;
+
+       if (!total_phases || (total_phases > MAX_PHASES)) {
+               dev_err(mmc_dev(mmc), "%s: Invalid argument: total_phases=%d\n",
+                      mmc_hostname(mmc), total_phases);
+               return -EINVAL;
+       }
+
+       for (cnt = 0; cnt < total_phases; cnt++) {
+               ranges[row_index][col_index] = phase_table[cnt];
+               phases_per_row[row_index] += 1;
+               col_index++;
+
+               if ((cnt + 1) == total_phases) {
+                       continue;
+               /* check if next phase in phase_table is consecutive or not */
+               } else if ((phase_table[cnt] + 1) != phase_table[cnt + 1]) {
+                       row_index++;
+                       col_index = 0;
+               }
+       }
+
+       if (row_index >= MAX_PHASES)
+               return -EINVAL;
+
+       /* Check if phase-0 is present in first valid window? */
+       if (!ranges[0][0]) {
+               phase_0_found = true;
+               phase_0_raw_index = 0;
+               /* Check if cycle exist between 2 valid windows */
+               for (cnt = 1; cnt <= row_index; cnt++) {
+                       if (phases_per_row[cnt]) {
+                               for (i = 0; i < phases_per_row[cnt]; i++) {
+                                       if (ranges[cnt][i] == 15) {
+                                               phase_15_found = true;
+                                               phase_15_raw_index = cnt;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* If 2 valid windows form cycle then merge them as single window */
+       if (phase_0_found && phase_15_found) {
+               /* number of phases in raw where phase 0 is present */
+               u8 phases_0 = phases_per_row[phase_0_raw_index];
+               /* number of phases in raw where phase 15 is present */
+               u8 phases_15 = phases_per_row[phase_15_raw_index];
+
+               if (phases_0 + phases_15 >= MAX_PHASES)
+                       /*
+                        * If there are more than 1 phase windows then total
+                        * number of phases in both the windows should not be
+                        * more than or equal to MAX_PHASES.
+                        */
+                       return -EINVAL;
+
+               /* Merge 2 cyclic windows */
+               i = phases_15;
+               for (cnt = 0; cnt < phases_0; cnt++) {
+                       ranges[phase_15_raw_index][i] =
+                           ranges[phase_0_raw_index][cnt];
+                       if (++i >= MAX_PHASES)
+                               break;
+               }
+
+               phases_per_row[phase_0_raw_index] = 0;
+               phases_per_row[phase_15_raw_index] = phases_15 + phases_0;
+       }
+
+       for (cnt = 0; cnt <= row_index; cnt++) {
+               if (phases_per_row[cnt] > curr_max) {
+                       curr_max = phases_per_row[cnt];
+                       selected_row_index = cnt;
+               }
+       }
+
+       i = (curr_max * 3) / 4;
+       if (i)
+               i--;
+
+       ret = ranges[selected_row_index][i];
+
+       if (ret >= MAX_PHASES) {
+               ret = -EINVAL;
+               dev_err(mmc_dev(mmc), "%s: Invalid phase selected=%d\n",
+                      mmc_hostname(mmc), ret);
+       }
+
+       return ret;
+}
+
+static inline void msm_cm_dll_set_freq(struct sdhci_host *host)
+{
+       u32 mclk_freq = 0, config;
+
+       /* Program the MCLK value to MCLK_FREQ bit field */
+       if (host->clock <= 112000000)
+               mclk_freq = 0;
+       else if (host->clock <= 125000000)
+               mclk_freq = 1;
+       else if (host->clock <= 137000000)
+               mclk_freq = 2;
+       else if (host->clock <= 150000000)
+               mclk_freq = 3;
+       else if (host->clock <= 162000000)
+               mclk_freq = 4;
+       else if (host->clock <= 175000000)
+               mclk_freq = 5;
+       else if (host->clock <= 187000000)
+               mclk_freq = 6;
+       else if (host->clock <= 200000000)
+               mclk_freq = 7;
+
+       config = readl_relaxed(host->ioaddr + CORE_DLL_CONFIG);
+       config &= ~CMUX_SHIFT_PHASE_MASK;
+       config |= mclk_freq << CMUX_SHIFT_PHASE_SHIFT;
+       writel_relaxed(config, host->ioaddr + CORE_DLL_CONFIG);
+}
+
+/* Initialize the DLL (Programmable Delay Line) */
+static int msm_init_cm_dll(struct sdhci_host *host)
+{
+       struct mmc_host *mmc = host->mmc;
+       int wait_cnt = 50;
+       unsigned long flags;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       /*
+        * Make sure that clock is always enabled when DLL
+        * tuning is in progress. Keeping PWRSAVE ON may
+        * turn off the clock.
+        */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_VENDOR_SPEC)
+                       & ~CORE_CLK_PWRSAVE), host->ioaddr + CORE_VENDOR_SPEC);
+
+       /* Write 1 to DLL_RST bit of DLL_CONFIG register */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Write 1 to DLL_PDN bit of DLL_CONFIG register */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+       msm_cm_dll_set_freq(host);
+
+       /* Write 0 to DLL_RST bit of DLL_CONFIG register */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       & ~CORE_DLL_RST), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Write 0 to DLL_PDN bit of DLL_CONFIG register */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       & ~CORE_DLL_PDN), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Set DLL_EN bit to 1. */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_DLL_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Set CK_OUT_EN bit to 1. */
+       writel_relaxed((readl_relaxed(host->ioaddr + CORE_DLL_CONFIG)
+                       | CORE_CK_OUT_EN), host->ioaddr + CORE_DLL_CONFIG);
+
+       /* Wait until DLL_LOCK bit of DLL_STATUS register becomes '1' */
+       while (!(readl_relaxed(host->ioaddr + CORE_DLL_STATUS) &
+                CORE_DLL_LOCK)) {
+               /* max. wait for 50us sec for LOCK bit to be set */
+               if (--wait_cnt == 0) {
+                       dev_err(mmc_dev(mmc), "%s: DLL failed to LOCK\n",
+                              mmc_hostname(mmc));
+                       spin_unlock_irqrestore(&host->lock, flags);
+                       return -ETIMEDOUT;
+               }
+               udelay(1);
+       }
+
+       spin_unlock_irqrestore(&host->lock, flags);
+       return 0;
+}
+
+static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+       int tuning_seq_cnt = 3;
+       u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
+       const u32 *tuning_block_pattern = tuning_block_64;
+       int size = sizeof(tuning_block_64);     /* Pattern size in bytes */
+       int rc;
+       struct mmc_host *mmc = host->mmc;
+       struct mmc_ios ios = host->mmc->ios;
+
+       /*
+        * Tuning is required for SDR104, HS200 and HS400 cards and
+        * if clock frequency is greater than 100MHz in these modes.
+        */
+       if (host->clock <= 100 * 1000 * 1000 ||
+           !((ios.timing == MMC_TIMING_MMC_HS200) ||
+             (ios.timing == MMC_TIMING_UHS_SDR104)))
+               return 0;
+
+       if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
+           (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
+               tuning_block_pattern = tuning_block_128;
+               size = sizeof(tuning_block_128);
+       }
+
+       data_buf = kmalloc(size, GFP_KERNEL);
+       if (!data_buf)
+               return -ENOMEM;
+
+retry:
+       /* First of all reset the tuning block */
+       rc = msm_init_cm_dll(host);
+       if (rc)
+               goto out;
+
+       phase = 0;
+       do {
+               struct mmc_command cmd = { 0 };
+               struct mmc_data data = { 0 };
+               struct mmc_request mrq = {
+                       .cmd = &cmd,
+                       .data = &data
+               };
+               struct scatterlist sg;
+
+               /* Set the phase in delay line hw block */
+               rc = msm_config_cm_dll_phase(host, phase);
+               if (rc)
+                       goto out;
+
+               cmd.opcode = opcode;
+               cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+               data.blksz = size;
+               data.blocks = 1;
+               data.flags = MMC_DATA_READ;
+               data.timeout_ns = NSEC_PER_SEC; /* 1 second */
+
+               data.sg = &sg;
+               data.sg_len = 1;
+               sg_init_one(&sg, data_buf, size);
+               memset(data_buf, 0, size);
+               mmc_wait_for_req(mmc, &mrq);
+
+               if (!cmd.error && !data.error &&
+                   !memcmp(data_buf, tuning_block_pattern, size)) {
+                       /* Tuning is successful at this tuning point */
+                       tuned_phases[tuned_phase_cnt++] = phase;
+                       dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
+                                mmc_hostname(mmc), phase);
+               }
+       } while (++phase < ARRAY_SIZE(tuned_phases));
+
+       if (tuned_phase_cnt) {
+               rc = msm_find_most_appropriate_phase(host, tuned_phases,
+                                                    tuned_phase_cnt);
+               if (rc < 0)
+                       goto out;
+               else
+                       phase = rc;
+
+               /*
+                * Finally set the selected phase in delay
+                * line hw block.
+                */
+               rc = msm_config_cm_dll_phase(host, phase);
+               if (rc)
+                       goto out;
+               dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
+                        mmc_hostname(mmc), phase);
+       } else {
+               if (--tuning_seq_cnt)
+                       goto retry;
+               /* Tuning failed */
+               dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
+                      mmc_hostname(mmc));
+               rc = -EIO;
+       }
+
+out:
+       kfree(data_buf);
+       return rc;
+}
+
+static const struct of_device_id sdhci_msm_dt_match[] = {
+       { .compatible = "qcom,sdhci-msm-v4" },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, sdhci_msm_dt_match);
+
+static struct sdhci_ops sdhci_msm_ops = {
+       .platform_execute_tuning = sdhci_msm_execute_tuning,
+};
+
+static int sdhci_msm_probe(struct platform_device *pdev)
+{
+       struct sdhci_host *host;
+       struct sdhci_pltfm_host *pltfm_host;
+       struct sdhci_msm_host *msm_host;
+       struct resource *core_memres;
+       int ret;
+       u16 host_version;
+
+       msm_host = devm_kzalloc(&pdev->dev, sizeof(*msm_host), GFP_KERNEL);
+       if (!msm_host)
+               return -ENOMEM;
+
+       msm_host->sdhci_msm_pdata.ops = &sdhci_msm_ops;
+       host = sdhci_pltfm_init(pdev, &msm_host->sdhci_msm_pdata, 0);
+       if (IS_ERR(host))
+               return PTR_ERR(host);
+
+       pltfm_host = sdhci_priv(host);
+       pltfm_host->priv = msm_host;
+       msm_host->mmc = host->mmc;
+       msm_host->pdev = pdev;
+
+       ret = mmc_of_parse(host->mmc);
+       if (ret)
+               goto pltfm_free;
+
+       sdhci_get_of_property(pdev);
+
+       /* Setup SDCC bus voter clock. */
+       msm_host->bus_clk = devm_clk_get(&pdev->dev, "bus");
+       if (!IS_ERR(msm_host->bus_clk)) {
+               /* Vote for max. clk rate for max. performance */
+               ret = clk_set_rate(msm_host->bus_clk, INT_MAX);
+               if (ret)
+                       goto pltfm_free;
+               ret = clk_prepare_enable(msm_host->bus_clk);
+               if (ret)
+                       goto pltfm_free;
+       }
+
+       /* Setup main peripheral bus clock */
+       msm_host->pclk = devm_clk_get(&pdev->dev, "iface");
+       if (IS_ERR(msm_host->pclk)) {
+               ret = PTR_ERR(msm_host->pclk);
+               dev_err(&pdev->dev, "Perpheral clk setup failed (%d)\n", ret);
+               goto bus_clk_disable;
+       }
+
+       ret = clk_prepare_enable(msm_host->pclk);
+       if (ret)
+               goto bus_clk_disable;
+
+       /* Setup SDC MMC clock */
+       msm_host->clk = devm_clk_get(&pdev->dev, "core");
+       if (IS_ERR(msm_host->clk)) {
+               ret = PTR_ERR(msm_host->clk);
+               dev_err(&pdev->dev, "SDC MMC clk setup failed (%d)\n", ret);
+               goto pclk_disable;
+       }
+
+       ret = clk_prepare_enable(msm_host->clk);
+       if (ret)
+               goto pclk_disable;
+
+       core_memres = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       msm_host->core_mem = devm_ioremap_resource(&pdev->dev, core_memres);
+
+       if (IS_ERR(msm_host->core_mem)) {
+               dev_err(&pdev->dev, "Failed to remap registers\n");
+               ret = PTR_ERR(msm_host->core_mem);
+               goto clk_disable;
+       }
+
+       /* Reset the core and Enable SDHC mode */
+       writel_relaxed(readl_relaxed(msm_host->core_mem + CORE_POWER) |
+                      CORE_SW_RST, msm_host->core_mem + CORE_POWER);
+
+       /* SW reset can take upto 10HCLK + 15MCLK cycles. (min 40us) */
+       usleep_range(1000, 5000);
+       if (readl(msm_host->core_mem + CORE_POWER) & CORE_SW_RST) {
+               dev_err(&pdev->dev, "Stuck in reset\n");
+               ret = -ETIMEDOUT;
+               goto clk_disable;
+       }
+
+       /* Set HC_MODE_EN bit in HC_MODE register */
+       writel_relaxed(HC_MODE_EN, (msm_host->core_mem + CORE_HC_MODE));
+
+       host->quirks |= SDHCI_QUIRK_BROKEN_CARD_DETECTION;
+       host->quirks |= SDHCI_QUIRK_SINGLE_POWER_WRITE;
+
+       host_version = readw_relaxed((host->ioaddr + SDHCI_HOST_VERSION));
+       dev_dbg(&pdev->dev, "Host Version: 0x%x Vendor Version 0x%x\n",
+               host_version, ((host_version & SDHCI_VENDOR_VER_MASK) >>
+                              SDHCI_VENDOR_VER_SHIFT));
+
+       ret = sdhci_add_host(host);
+       if (ret)
+               goto clk_disable;
+
+       return 0;
+
+clk_disable:
+       clk_disable_unprepare(msm_host->clk);
+pclk_disable:
+       clk_disable_unprepare(msm_host->pclk);
+bus_clk_disable:
+       if (!IS_ERR(msm_host->bus_clk))
+               clk_disable_unprepare(msm_host->bus_clk);
+pltfm_free:
+       sdhci_pltfm_free(pdev);
+       return ret;
+}
+
+static int sdhci_msm_remove(struct platform_device *pdev)
+{
+       struct sdhci_host *host = platform_get_drvdata(pdev);
+       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+       struct sdhci_msm_host *msm_host = pltfm_host->priv;
+       int dead = (readl_relaxed(host->ioaddr + SDHCI_INT_STATUS) ==
+                   0xffffffff);
+
+       sdhci_remove_host(host, dead);
+       sdhci_pltfm_free(pdev);
+       clk_disable_unprepare(msm_host->clk);
+       clk_disable_unprepare(msm_host->pclk);
+       if (!IS_ERR(msm_host->bus_clk))
+               clk_disable_unprepare(msm_host->bus_clk);
+       return 0;
+}
+
+static struct platform_driver sdhci_msm_driver = {
+       .probe = sdhci_msm_probe,
+       .remove = sdhci_msm_remove,
+       .driver = {
+                  .name = "sdhci_msm",
+                  .owner = THIS_MODULE,
+                  .of_match_table = sdhci_msm_dt_match,
+       },
+};
+
+module_platform_driver(sdhci_msm_driver);
+
+MODULE_DESCRIPTION("Qualcomm Secure Digital Host Controller Interface driver");
+MODULE_LICENSE("GPL v2");
index 0955777..fdc6121 100644 (file)
@@ -610,6 +610,18 @@ static const struct sdhci_pci_fixes sdhci_via = {
        .probe          = via_probe,
 };
 
+static int rtsx_probe_slot(struct sdhci_pci_slot *slot)
+{
+       slot->host->mmc->caps2 |= MMC_CAP2_HS200;
+       return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_rtsx = {
+       .quirks2        = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
+                       SDHCI_QUIRK2_BROKEN_DDR50,
+       .probe_slot     = rtsx_probe_slot,
+};
+
 static const struct pci_device_id pci_ids[] = {
        {
                .vendor         = PCI_VENDOR_ID_RICOH,
@@ -731,6 +743,14 @@ static const struct pci_device_id pci_ids[] = {
                .driver_data    = (kernel_ulong_t)&sdhci_via,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_REALTEK,
+               .device         = 0x5250,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = (kernel_ulong_t)&sdhci_rtsx,
+       },
+
        {
                .vendor         = PCI_VENDOR_ID_INTEL,
                .device         = PCI_DEVICE_ID_INTEL_MRST_SD0,
index 793dacd..2fd73b3 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/of_gpio.h>
 #include <linux/pm.h>
 #include <linux/pm_runtime.h>
+#include <linux/mbus.h>
 
 #include "sdhci.h"
 #include "sdhci-pltfm.h"
 #define SDCE_MISC_INT          (1<<2)
 #define SDCE_MISC_INT_EN       (1<<1)
 
+/*
+ * These registers are relative to the second register region, for the
+ * MBus bridge.
+ */
+#define SDHCI_WINDOW_CTRL(i)   (0x80 + ((i) << 3))
+#define SDHCI_WINDOW_BASE(i)   (0x84 + ((i) << 3))
+#define SDHCI_MAX_WIN_NUM      8
+
+static int mv_conf_mbus_windows(struct platform_device *pdev,
+                               const struct mbus_dram_target_info *dram)
+{
+       int i;
+       void __iomem *regs;
+       struct resource *res;
+
+       if (!dram) {
+               dev_err(&pdev->dev, "no mbus dram info\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res) {
+               dev_err(&pdev->dev, "cannot get mbus registers\n");
+               return -EINVAL;
+       }
+
+       regs = ioremap(res->start, resource_size(res));
+       if (!regs) {
+               dev_err(&pdev->dev, "cannot map mbus registers\n");
+               return -ENOMEM;
+       }
+
+       for (i = 0; i < SDHCI_MAX_WIN_NUM; i++) {
+               writel(0, regs + SDHCI_WINDOW_CTRL(i));
+               writel(0, regs + SDHCI_WINDOW_BASE(i));
+       }
+
+       for (i = 0; i < dram->num_cs; i++) {
+               const struct mbus_dram_window *cs = dram->cs + i;
+
+               /* Write size, attributes and target id to control register */
+               writel(((cs->size - 1) & 0xffff0000) |
+                       (cs->mbus_attr << 8) |
+                       (dram->mbus_dram_target_id << 4) | 1,
+                       regs + SDHCI_WINDOW_CTRL(i));
+               /* Write base address to base register */
+               writel(cs->base, regs + SDHCI_WINDOW_BASE(i));
+       }
+
+       iounmap(regs);
+
+       return 0;
+}
+
 static void pxav3_set_private_registers(struct sdhci_host *host, u8 mask)
 {
        struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
@@ -187,6 +242,9 @@ static const struct of_device_id sdhci_pxav3_of_match[] = {
        {
                .compatible = "mrvl,pxav3-mmc",
        },
+       {
+               .compatible = "marvell,armada-380-sdhci",
+       },
        {},
 };
 MODULE_DEVICE_TABLE(of, sdhci_pxav3_of_match);
@@ -219,6 +277,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
        struct sdhci_pltfm_host *pltfm_host;
        struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
        struct device *dev = &pdev->dev;
+       struct device_node *np = pdev->dev.of_node;
        struct sdhci_host *host = NULL;
        struct sdhci_pxa *pxa = NULL;
        const struct of_device_id *match;
@@ -235,6 +294,14 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
                kfree(pxa);
                return PTR_ERR(host);
        }
+
+       if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) {
+               ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info());
+               if (ret < 0)
+                       goto err_mbus_win;
+       }
+
+
        pltfm_host = sdhci_priv(host);
        pltfm_host->priv = pxa;
 
@@ -321,6 +388,7 @@ err_add_host:
        clk_disable_unprepare(clk);
        clk_put(clk);
 err_clk_get:
+err_mbus_win:
        sdhci_pltfm_free(pdev);
        kfree(pxa);
        return ret;
index 6debda9..d61eb5a 100644 (file)
@@ -51,12 +51,13 @@ struct sdhci_s3c {
        struct platform_device  *pdev;
        struct resource         *ioarea;
        struct s3c_sdhci_platdata *pdata;
-       unsigned int            cur_clk;
+       int                     cur_clk;
        int                     ext_cd_irq;
        int                     ext_cd_gpio;
 
        struct clk              *clk_io;
        struct clk              *clk_bus[MAX_BUS_CLK];
+       unsigned long           clk_rates[MAX_BUS_CLK];
 };
 
 /**
@@ -76,32 +77,6 @@ static inline struct sdhci_s3c *to_s3c(struct sdhci_host *host)
        return sdhci_priv(host);
 }
 
-/**
- * get_curclk - convert ctrl2 register to clock source number
- * @ctrl2: Control2 register value.
- */
-static u32 get_curclk(u32 ctrl2)
-{
-       ctrl2 &= S3C_SDHCI_CTRL2_SELBASECLK_MASK;
-       ctrl2 >>= S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
-
-       return ctrl2;
-}
-
-static void sdhci_s3c_check_sclk(struct sdhci_host *host)
-{
-       struct sdhci_s3c *ourhost = to_s3c(host);
-       u32 tmp = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
-
-       if (get_curclk(tmp) != ourhost->cur_clk) {
-               dev_dbg(&ourhost->pdev->dev, "restored ctrl2 clock setting\n");
-
-               tmp &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
-               tmp |= ourhost->cur_clk << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
-               writel(tmp, host->ioaddr + S3C_SDHCI_CONTROL2);
-       }
-}
-
 /**
  * sdhci_s3c_get_max_clk - callback to get maximum clock frequency.
  * @host: The SDHCI host instance.
@@ -111,20 +86,11 @@ static void sdhci_s3c_check_sclk(struct sdhci_host *host)
 static unsigned int sdhci_s3c_get_max_clk(struct sdhci_host *host)
 {
        struct sdhci_s3c *ourhost = to_s3c(host);
-       struct clk *busclk;
-       unsigned int rate, max;
-       int clk;
-
-       /* note, a reset will reset the clock source */
-
-       sdhci_s3c_check_sclk(host);
-
-       for (max = 0, clk = 0; clk < MAX_BUS_CLK; clk++) {
-               busclk = ourhost->clk_bus[clk];
-               if (!busclk)
-                       continue;
+       unsigned long rate, max = 0;
+       int src;
 
-               rate = clk_get_rate(busclk);
+       for (src = 0; src < MAX_BUS_CLK; src++) {
+               rate = ourhost->clk_rates[src];
                if (rate > max)
                        max = rate;
        }
@@ -144,9 +110,9 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
 {
        unsigned long rate;
        struct clk *clksrc = ourhost->clk_bus[src];
-       int div;
+       int shift;
 
-       if (!clksrc)
+       if (IS_ERR(clksrc))
                return UINT_MAX;
 
        /*
@@ -158,17 +124,24 @@ static unsigned int sdhci_s3c_consider_clock(struct sdhci_s3c *ourhost,
                return wanted - rate;
        }
 
-       rate = clk_get_rate(clksrc);
+       rate = ourhost->clk_rates[src];
 
-       for (div = 1; div < 256; div *= 2) {
-               if ((rate / div) <= wanted)
+       for (shift = 0; shift <= 8; ++shift) {
+               if ((rate >> shift) <= wanted)
                        break;
        }
 
+       if (shift > 8) {
+               dev_dbg(&ourhost->pdev->dev,
+                       "clk %d: rate %ld, min rate %lu > wanted %u\n",
+                       src, rate, rate / 256, wanted);
+               return UINT_MAX;
+       }
+
        dev_dbg(&ourhost->pdev->dev, "clk %d: rate %ld, want %d, got %ld\n",
-               src, rate, wanted, rate / div);
+               src, rate, wanted, rate >> shift);
 
-       return wanted - (rate / div);
+       return wanted - (rate >> shift);
 }
 
 /**
@@ -209,20 +182,22 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
                struct clk *clk = ourhost->clk_bus[best_src];
 
                clk_prepare_enable(clk);
-               clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);
-
-               /* turn clock off to card before changing clock source */
-               writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
+               if (ourhost->cur_clk >= 0)
+                       clk_disable_unprepare(
+                                       ourhost->clk_bus[ourhost->cur_clk]);
 
                ourhost->cur_clk = best_src;
-               host->max_clk = clk_get_rate(clk);
-
-               ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
-               ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
-               ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
-               writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2);
+               host->max_clk = ourhost->clk_rates[best_src];
        }
 
+       /* turn clock off to card before changing clock source */
+       writew(0, host->ioaddr + SDHCI_CLOCK_CONTROL);
+
+       ctrl = readl(host->ioaddr + S3C_SDHCI_CONTROL2);
+       ctrl &= ~S3C_SDHCI_CTRL2_SELBASECLK_MASK;
+       ctrl |= best_src << S3C_SDHCI_CTRL2_SELBASECLK_SHIFT;
+       writel(ctrl, host->ioaddr + S3C_SDHCI_CONTROL2);
+
        /* reprogram default hardware configuration */
        writel(S3C64XX_SDHCI_CONTROL4_DRIVE_9mA,
                host->ioaddr + S3C64XX_SDHCI_CONTROL4);
@@ -254,17 +229,17 @@ static void sdhci_s3c_set_clock(struct sdhci_host *host, unsigned int clock)
 static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
 {
        struct sdhci_s3c *ourhost = to_s3c(host);
-       unsigned int delta, min = UINT_MAX;
+       unsigned long rate, min = ULONG_MAX;
        int src;
 
        for (src = 0; src < MAX_BUS_CLK; src++) {
-               delta = sdhci_s3c_consider_clock(ourhost, src, 0);
-               if (delta == UINT_MAX)
+               rate = ourhost->clk_rates[src] / 256;
+               if (!rate)
                        continue;
-               /* delta is a negative value in this case */
-               if (-delta < min)
-                       min = -delta;
+               if (rate < min)
+                       min = rate;
        }
+
        return min;
 }
 
@@ -272,20 +247,44 @@ static unsigned int sdhci_s3c_get_min_clock(struct sdhci_host *host)
 static unsigned int sdhci_cmu_get_max_clock(struct sdhci_host *host)
 {
        struct sdhci_s3c *ourhost = to_s3c(host);
+       unsigned long rate, max = 0;
+       int src;
 
-       return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], UINT_MAX);
+       for (src = 0; src < MAX_BUS_CLK; src++) {
+               struct clk *clk;
+
+               clk = ourhost->clk_bus[src];
+               if (IS_ERR(clk))
+                       continue;
+
+               rate = clk_round_rate(clk, ULONG_MAX);
+               if (rate > max)
+                       max = rate;
+       }
+
+       return max;
 }
 
 /* sdhci_cmu_get_min_clock - callback to get minimal supported clock value. */
 static unsigned int sdhci_cmu_get_min_clock(struct sdhci_host *host)
 {
        struct sdhci_s3c *ourhost = to_s3c(host);
+       unsigned long rate, min = ULONG_MAX;
+       int src;
 
-       /*
-        * initial clock can be in the frequency range of
-        * 100KHz-400KHz, so we set it as max value.
-        */
-       return clk_round_rate(ourhost->clk_bus[ourhost->cur_clk], 400000);
+       for (src = 0; src < MAX_BUS_CLK; src++) {
+               struct clk *clk;
+
+               clk = ourhost->clk_bus[src];
+               if (IS_ERR(clk))
+                       continue;
+
+               rate = clk_round_rate(clk, 0);
+               if (rate < min)
+                       min = rate;
+       }
+
+       return min;
 }
 
 /* sdhci_cmu_set_clock - callback on clock change.*/
@@ -552,6 +551,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        sc->host = host;
        sc->pdev = pdev;
        sc->pdata = pdata;
+       sc->cur_clk = -1;
 
        platform_set_drvdata(pdev, host);
 
@@ -566,25 +566,18 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        clk_prepare_enable(sc->clk_io);
 
        for (clks = 0, ptr = 0; ptr < MAX_BUS_CLK; ptr++) {
-               struct clk *clk;
                char name[14];
 
                snprintf(name, 14, "mmc_busclk.%d", ptr);
-               clk = devm_clk_get(dev, name);
-               if (IS_ERR(clk))
+               sc->clk_bus[ptr] = devm_clk_get(dev, name);
+               if (IS_ERR(sc->clk_bus[ptr]))
                        continue;
 
                clks++;
-               sc->clk_bus[ptr] = clk;
-
-               /*
-                * save current clock index to know which clock bus
-                * is used later in overriding functions.
-                */
-               sc->cur_clk = ptr;
+               sc->clk_rates[ptr] = clk_get_rate(sc->clk_bus[ptr]);
 
                dev_info(dev, "clock source %d: %s (%ld Hz)\n",
-                        ptr, name, clk_get_rate(clk));
+                               ptr, name, sc->clk_rates[ptr]);
        }
 
        if (clks == 0) {
@@ -593,10 +586,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
                goto err_no_busclks;
        }
 
-#ifndef CONFIG_PM_RUNTIME
-       clk_prepare_enable(sc->clk_bus[sc->cur_clk]);
-#endif
-
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->ioaddr = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(host->ioaddr)) {
@@ -709,10 +698,6 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
        return 0;
 
  err_req_regs:
-#ifndef CONFIG_PM_RUNTIME
-       clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
-#endif
-
  err_no_busclks:
        clk_disable_unprepare(sc->clk_io);
 
@@ -743,9 +728,6 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
        pm_runtime_dont_use_autosuspend(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
 
-#ifndef CONFIG_PM_RUNTIME
-       clk_disable_unprepare(sc->clk_bus[sc->cur_clk]);
-#endif
        clk_disable_unprepare(sc->clk_io);
 
        sdhci_free_host(host);
@@ -779,7 +761,8 @@ static int sdhci_s3c_runtime_suspend(struct device *dev)
 
        ret = sdhci_runtime_suspend_host(host);
 
-       clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);
+       if (ourhost->cur_clk >= 0)
+               clk_disable_unprepare(ourhost->clk_bus[ourhost->cur_clk]);
        clk_disable_unprepare(busclk);
        return ret;
 }
@@ -792,7 +775,8 @@ static int sdhci_s3c_runtime_resume(struct device *dev)
        int ret;
 
        clk_prepare_enable(busclk);
-       clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]);
+       if (ourhost->cur_clk >= 0)
+               clk_prepare_enable(ourhost->clk_bus[ourhost->cur_clk]);
        ret = sdhci_runtime_resume_host(host);
        return ret;
 }
index 2dba9f8..0316dec 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/slab.h>
 #include <linux/mmc/host.h>
 #include <linux/mmc/sdhci-spear.h>
+#include <linux/mmc/slot-gpio.h>
 #include <linux/io.h>
 #include "sdhci.h"
 
@@ -40,36 +41,6 @@ static const struct sdhci_ops sdhci_pltfm_ops = {
        /* Nothing to do for now. */
 };
 
-/* gpio card detection interrupt handler */
-static irqreturn_t sdhci_gpio_irq(int irq, void *dev_id)
-{
-       struct platform_device *pdev = dev_id;
-       struct sdhci_host *host = platform_get_drvdata(pdev);
-       struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
-       unsigned long gpio_irq_type;
-       int val;
-
-       val = gpio_get_value(sdhci->data->card_int_gpio);
-
-       /* val == 1 -> card removed, val == 0 -> card inserted */
-       /* if card removed - set irq for low level, else vice versa */
-       gpio_irq_type = val ? IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH;
-       irq_set_irq_type(irq, gpio_irq_type);
-
-       if (sdhci->data->card_power_gpio >= 0) {
-               if (!sdhci->data->power_always_enb) {
-                       /* if card inserted, give power, otherwise remove it */
-                       val = sdhci->data->power_active_high ? !val : val ;
-                       gpio_set_value(sdhci->data->card_power_gpio, val);
-               }
-       }
-
-       /* inform sdhci driver about card insertion/removal */
-       tasklet_schedule(&host->card_tasklet);
-
-       return IRQ_HANDLED;
-}
-
 #ifdef CONFIG_OF
 static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pdev)
 {
@@ -84,14 +55,12 @@ static struct sdhci_plat_data *sdhci_probe_config_dt(struct platform_device *pde
        /* If pdata is required */
        if (cd_gpio != -1) {
                pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
-               if (!pdata) {
+               if (!pdata)
                        dev_err(&pdev->dev, "DT: kzalloc failed\n");
-                       return ERR_PTR(-ENOMEM);
-               }
+               else
+                       pdata->card_int_gpio = cd_gpio;
        }
 
-       pdata->card_int_gpio = cd_gpio;
-
        return pdata;
 }
 #else
@@ -107,41 +76,44 @@ static int sdhci_probe(struct platform_device *pdev)
        struct sdhci_host *host;
        struct resource *iomem;
        struct spear_sdhci *sdhci;
+       struct device *dev;
        int ret;
 
-       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!iomem) {
-               ret = -ENOMEM;
-               dev_dbg(&pdev->dev, "memory resource not defined\n");
+       dev = pdev->dev.parent ? pdev->dev.parent : &pdev->dev;
+       host = sdhci_alloc_host(dev, sizeof(*sdhci));
+       if (IS_ERR(host)) {
+               ret = PTR_ERR(host);
+               dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n");
                goto err;
        }
 
-       if (!devm_request_mem_region(&pdev->dev, iomem->start,
-                               resource_size(iomem), "spear-sdhci")) {
-               ret = -EBUSY;
-               dev_dbg(&pdev->dev, "cannot request region\n");
-               goto err;
+       iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       host->ioaddr = devm_ioremap_resource(&pdev->dev, iomem);
+       if (IS_ERR(host->ioaddr)) {
+               ret = PTR_ERR(host->ioaddr);
+               dev_dbg(&pdev->dev, "unable to map iomem: %d\n", ret);
+               goto err_host;
        }
 
-       sdhci = devm_kzalloc(&pdev->dev, sizeof(*sdhci), GFP_KERNEL);
-       if (!sdhci) {
-               ret = -ENOMEM;
-               dev_dbg(&pdev->dev, "cannot allocate memory for sdhci\n");
-               goto err;
-       }
+       host->hw_name = "sdhci";
+       host->ops = &sdhci_pltfm_ops;
+       host->irq = platform_get_irq(pdev, 0);
+       host->quirks = SDHCI_QUIRK_BROKEN_ADMA;
+
+       sdhci = sdhci_priv(host);
 
        /* clk enable */
-       sdhci->clk = clk_get(&pdev->dev, NULL);
+       sdhci->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(sdhci->clk)) {
                ret = PTR_ERR(sdhci->clk);
                dev_dbg(&pdev->dev, "Error getting clock\n");
-               goto err;
+               goto err_host;
        }
 
        ret = clk_prepare_enable(sdhci->clk);
        if (ret) {
                dev_dbg(&pdev->dev, "Error enabling clock\n");
-               goto put_clk;
+               goto err_host;
        }
 
        ret = clk_set_rate(sdhci->clk, 50000000);
@@ -153,118 +125,42 @@ static int sdhci_probe(struct platform_device *pdev)
                sdhci->data = sdhci_probe_config_dt(pdev);
                if (IS_ERR(sdhci->data)) {
                        dev_err(&pdev->dev, "DT: Failed to get pdata\n");
-                       return -ENODEV;
+                       goto disable_clk;
                }
        } else {
                sdhci->data = dev_get_platdata(&pdev->dev);
        }
 
-       pdev->dev.platform_data = sdhci;
-
-       if (pdev->dev.parent)
-               host = sdhci_alloc_host(pdev->dev.parent, 0);
-       else
-               host = sdhci_alloc_host(&pdev->dev, 0);
-
-       if (IS_ERR(host)) {
-               ret = PTR_ERR(host);
-               dev_dbg(&pdev->dev, "error allocating host\n");
-               goto disable_clk;
-       }
-
-       host->hw_name = "sdhci";
-       host->ops = &sdhci_pltfm_ops;
-       host->irq = platform_get_irq(pdev, 0);
-       host->quirks = SDHCI_QUIRK_BROKEN_ADMA;
-
-       host->ioaddr = devm_ioremap(&pdev->dev, iomem->start,
-                       resource_size(iomem));
-       if (!host->ioaddr) {
-               ret = -ENOMEM;
-               dev_dbg(&pdev->dev, "failed to remap registers\n");
-               goto free_host;
+       /*
+        * It is optional to use GPIOs for sdhci card detection. If
+        * sdhci->data is NULL, then use original sdhci lines otherwise
+        * GPIO lines. We use the built-in GPIO support for this.
+        */
+       if (sdhci->data && sdhci->data->card_int_gpio >= 0) {
+               ret = mmc_gpio_request_cd(host->mmc,
+                                         sdhci->data->card_int_gpio, 0);
+               if (ret < 0) {
+                       dev_dbg(&pdev->dev,
+                               "failed to request card-detect gpio%d\n",
+                               sdhci->data->card_int_gpio);
+                       goto disable_clk;
+               }
        }
 
        ret = sdhci_add_host(host);
        if (ret) {
                dev_dbg(&pdev->dev, "error adding host\n");
-               goto free_host;
+               goto disable_clk;
        }
 
        platform_set_drvdata(pdev, host);
 
-       /*
-        * It is optional to use GPIOs for sdhci Power control & sdhci card
-        * interrupt detection. If sdhci->data is NULL, then use original sdhci
-        * lines otherwise GPIO lines.
-        * If GPIO is selected for power control, then power should be disabled
-        * after card removal and should be enabled when card insertion
-        * interrupt occurs
-        */
-       if (!sdhci->data)
-               return 0;
-
-       if (sdhci->data->card_power_gpio >= 0) {
-               int val = 0;
-
-               ret = devm_gpio_request(&pdev->dev,
-                               sdhci->data->card_power_gpio, "sdhci");
-               if (ret < 0) {
-                       dev_dbg(&pdev->dev, "gpio request fail: %d\n",
-                                       sdhci->data->card_power_gpio);
-                       goto set_drvdata;
-               }
-
-               if (sdhci->data->power_always_enb)
-                       val = sdhci->data->power_active_high;
-               else
-                       val = !sdhci->data->power_active_high;
-
-               ret = gpio_direction_output(sdhci->data->card_power_gpio, val);
-               if (ret) {
-                       dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
-                                       sdhci->data->card_power_gpio);
-                       goto set_drvdata;
-               }
-       }
-
-       if (sdhci->data->card_int_gpio >= 0) {
-               ret = devm_gpio_request(&pdev->dev, sdhci->data->card_int_gpio,
-                               "sdhci");
-               if (ret < 0) {
-                       dev_dbg(&pdev->dev, "gpio request fail: %d\n",
-                                       sdhci->data->card_int_gpio);
-                       goto set_drvdata;
-               }
-
-               ret = gpio_direction_input(sdhci->data->card_int_gpio);
-               if (ret) {
-                       dev_dbg(&pdev->dev, "gpio set direction fail: %d\n",
-                                       sdhci->data->card_int_gpio);
-                       goto set_drvdata;
-               }
-               ret = devm_request_irq(&pdev->dev,
-                               gpio_to_irq(sdhci->data->card_int_gpio),
-                               sdhci_gpio_irq, IRQF_TRIGGER_LOW,
-                               mmc_hostname(host->mmc), pdev);
-               if (ret) {
-                       dev_dbg(&pdev->dev, "gpio request irq fail: %d\n",
-                                       sdhci->data->card_int_gpio);
-                       goto set_drvdata;
-               }
-
-       }
-
        return 0;
 
-set_drvdata:
-       sdhci_remove_host(host, 1);
-free_host:
-       sdhci_free_host(host);
 disable_clk:
        clk_disable_unprepare(sdhci->clk);
-put_clk:
-       clk_put(sdhci->clk);
+err_host:
+       sdhci_free_host(host);
 err:
        dev_err(&pdev->dev, "spear-sdhci probe failed: %d\n", ret);
        return ret;
@@ -273,7 +169,7 @@ err:
 static int sdhci_remove(struct platform_device *pdev)
 {
        struct sdhci_host *host = platform_get_drvdata(pdev);
-       struct spear_sdhci *sdhci = dev_get_platdata(&pdev->dev);
+       struct spear_sdhci *sdhci = sdhci_priv(host);
        int dead = 0;
        u32 scratch;
 
@@ -282,9 +178,8 @@ static int sdhci_remove(struct platform_device *pdev)
                dead = 1;
 
        sdhci_remove_host(host, dead);
-       sdhci_free_host(host);
        clk_disable_unprepare(sdhci->clk);
-       clk_put(sdhci->clk);
+       sdhci_free_host(host);
 
        return 0;
 }
@@ -293,7 +188,7 @@ static int sdhci_remove(struct platform_device *pdev)
 static int sdhci_suspend(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
-       struct spear_sdhci *sdhci = dev_get_platdata(dev);
+       struct spear_sdhci *sdhci = sdhci_priv(host);
        int ret;
 
        ret = sdhci_suspend_host(host);
@@ -306,7 +201,7 @@ static int sdhci_suspend(struct device *dev)
 static int sdhci_resume(struct device *dev)
 {
        struct sdhci_host *host = dev_get_drvdata(dev);
-       struct spear_sdhci *sdhci = dev_get_platdata(dev);
+       struct spear_sdhci *sdhci = sdhci_priv(host);
        int ret;
 
        ret = clk_enable(sdhci->clk);
index 9ddef47..9a79fc4 100644 (file)
@@ -675,12 +675,12 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
                return 0xE;
 
        /* Unspecified timeout, assume max */
-       if (!data && !cmd->cmd_timeout_ms)
+       if (!data && !cmd->busy_timeout)
                return 0xE;
 
        /* timeout in us */
        if (!data)
-               target_timeout = cmd->cmd_timeout_ms * 1000;
+               target_timeout = cmd->busy_timeout * 1000;
        else {
                target_timeout = data->timeout_ns / 1000;
                if (host->clock)
@@ -1019,8 +1019,8 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        }
 
        timeout = jiffies;
-       if (!cmd->data && cmd->cmd_timeout_ms > 9000)
-               timeout += DIV_ROUND_UP(cmd->cmd_timeout_ms, 1000) * HZ + HZ;
+       if (!cmd->data && cmd->busy_timeout > 9000)
+               timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
        else
                timeout += 10 * HZ;
        mod_timer(&host->timer, timeout);
@@ -2026,12 +2026,11 @@ out:
                        host->tuning_count * HZ);
                /* Tuning mode 1 limits the maximum data length to 4MB */
                mmc->max_blk_count = (4 * 1024 * 1024) / mmc->max_blk_size;
-       } else {
+       } else if (host->flags & SDHCI_USING_RETUNING_TIMER) {
                host->flags &= ~SDHCI_NEEDS_RETUNING;
                /* Reload the new initial value for timer */
-               if (host->tuning_mode == SDHCI_TUNING_MODE_1)
-                       mod_timer(&host->tuning_timer, jiffies +
-                               host->tuning_count * HZ);
+               mod_timer(&host->tuning_timer, jiffies +
+                         host->tuning_count * HZ);
        }
 
        /*
@@ -2434,9 +2433,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
        if (host->runtime_suspended) {
                spin_unlock(&host->lock);
-               pr_warning("%s: got irq while runtime suspended\n",
-                      mmc_hostname(host->mmc));
-               return IRQ_HANDLED;
+               return IRQ_NONE;
        }
 
        intmask = sdhci_readl(host, SDHCI_INT_STATUS);
@@ -2941,7 +2938,7 @@ int sdhci_add_host(struct sdhci_host *host)
        if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
                host->timeout_clk = mmc->f_max / 1000;
 
-       mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+       mmc->max_busy_timeout = (1 << 27) / host->timeout_clk;
 
        mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
 
@@ -3020,7 +3017,8 @@ int sdhci_add_host(struct sdhci_host *host)
        } else if (caps[1] & SDHCI_SUPPORT_SDR50)
                mmc->caps |= MMC_CAP_UHS_SDR50;
 
-       if (caps[1] & SDHCI_SUPPORT_DDR50)
+       if ((caps[1] & SDHCI_SUPPORT_DDR50) &&
+               !(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
                mmc->caps |= MMC_CAP_UHS_DDR50;
 
        /* Does the host need tuning for SDR50? */
index 2d6ce25..91058da 100644 (file)
@@ -37,6 +37,8 @@
 
 struct sh_mobile_sdhi_of_data {
        unsigned long tmio_flags;
+       unsigned long capabilities;
+       unsigned long capabilities2;
 };
 
 static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
@@ -45,6 +47,31 @@ static const struct sh_mobile_sdhi_of_data sh_mobile_sdhi_of_cfg[] = {
        },
 };
 
+static const struct sh_mobile_sdhi_of_data of_rcar_gen1_compatible = {
+       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE,
+       .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+};
+
+static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
+       .tmio_flags     = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE,
+       .capabilities   = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+       .capabilities2  = MMC_CAP2_NO_MULTI_READ,
+};
+
+static const struct of_device_id sh_mobile_sdhi_of_match[] = {
+       { .compatible = "renesas,sdhi-shmobile" },
+       { .compatible = "renesas,sdhi-sh7372" },
+       { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], },
+       { .compatible = "renesas,sdhi-r8a7778", .data = &of_rcar_gen1_compatible, },
+       { .compatible = "renesas,sdhi-r8a7779", .data = &of_rcar_gen1_compatible, },
+       { .compatible = "renesas,sdhi-r8a7790", .data = &of_rcar_gen2_compatible, },
+       { .compatible = "renesas,sdhi-r8a7791", .data = &of_rcar_gen2_compatible, },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
+
 struct sh_mobile_sdhi {
        struct clk *clk;
        struct tmio_mmc_data mmc_data;
@@ -114,19 +141,6 @@ static const struct sh_mobile_sdhi_ops sdhi_ops = {
        .cd_wakeup = sh_mobile_sdhi_cd_wakeup,
 };
 
-static const struct of_device_id sh_mobile_sdhi_of_match[] = {
-       { .compatible = "renesas,sdhi-shmobile" },
-       { .compatible = "renesas,sdhi-sh7372" },
-       { .compatible = "renesas,sdhi-sh73a0", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a73a4", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a7740", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a7778", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a7779", .data = &sh_mobile_sdhi_of_cfg[0], },
-       { .compatible = "renesas,sdhi-r8a7790", .data = &sh_mobile_sdhi_of_cfg[0], },
-       {},
-};
-MODULE_DEVICE_TABLE(of, sh_mobile_sdhi_of_match);
-
 static int sh_mobile_sdhi_probe(struct platform_device *pdev)
 {
        const struct of_device_id *of_id =
@@ -212,6 +226,8 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
        if (of_id && of_id->data) {
                const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
                mmc_data->flags |= of_data->tmio_flags;
+               mmc_data->capabilities |= of_data->capabilities;
+               mmc_data->capabilities2 |= of_data->capabilities2;
        }
 
        /* SD control register space size is 0x100, 0x200 for bus_shift=1 */
@@ -316,10 +332,10 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
 }
 
 static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
-       .suspend = tmio_mmc_host_suspend,
-       .resume = tmio_mmc_host_resume,
-       .runtime_suspend = tmio_mmc_host_runtime_suspend,
-       .runtime_resume = tmio_mmc_host_runtime_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_host_suspend, tmio_mmc_host_resume)
+       SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+                       tmio_mmc_host_runtime_resume,
+                       NULL)
 };
 
 static struct platform_driver sh_mobile_sdhi_driver = {
index 1900abb..cfad844 100644 (file)
 
 #include "tmio_mmc.h"
 
-#ifdef CONFIG_PM
-static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int tmio_mmc_suspend(struct device *dev)
 {
-       const struct mfd_cell *cell = mfd_get_cell(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
        int ret;
 
-       ret = tmio_mmc_host_suspend(&dev->dev);
+       ret = tmio_mmc_host_suspend(dev);
 
        /* Tell MFD core it can disable us now.*/
        if (!ret && cell->disable)
-               cell->disable(dev);
+               cell->disable(pdev);
 
        return ret;
 }
 
-static int tmio_mmc_resume(struct platform_device *dev)
+static int tmio_mmc_resume(struct device *dev)
 {
-       const struct mfd_cell *cell = mfd_get_cell(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+       const struct mfd_cell *cell = mfd_get_cell(pdev);
        int ret = 0;
 
        /* Tell the MFD core we are ready to be enabled */
        if (cell->resume)
-               ret = cell->resume(dev);
+               ret = cell->resume(pdev);
 
        if (!ret)
-               ret = tmio_mmc_host_resume(&dev->dev);
+               ret = tmio_mmc_host_resume(dev);
 
        return ret;
 }
-#else
-#define tmio_mmc_suspend NULL
-#define tmio_mmc_resume NULL
 #endif
 
 static int tmio_mmc_probe(struct platform_device *pdev)
@@ -134,15 +133,18 @@ static int tmio_mmc_remove(struct platform_device *pdev)
 
 /* ------------------- device registration ----------------------- */
 
+static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume)
+};
+
 static struct platform_driver tmio_mmc_driver = {
        .driver = {
                .name = "tmio-mmc",
                .owner = THIS_MODULE,
+               .pm = &tmio_mmc_dev_pm_ops,
        },
        .probe = tmio_mmc_probe,
        .remove = tmio_mmc_remove,
-       .suspend = tmio_mmc_suspend,
-       .resume = tmio_mmc_resume,
 };
 
 module_platform_driver(tmio_mmc_driver);
index aaa9c7e..100ffe0 100644 (file)
@@ -162,16 +162,15 @@ static inline void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
 }
 #endif
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int tmio_mmc_host_suspend(struct device *dev);
 int tmio_mmc_host_resume(struct device *dev);
-#else
-#define tmio_mmc_host_suspend NULL
-#define tmio_mmc_host_resume NULL
 #endif
 
+#ifdef CONFIG_PM_RUNTIME
 int tmio_mmc_host_runtime_suspend(struct device *dev);
 int tmio_mmc_host_runtime_resume(struct device *dev);
+#endif
 
 static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
 {
index 8d8abf2..faf0924 100644 (file)
@@ -1142,7 +1142,7 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
 }
 EXPORT_SYMBOL(tmio_mmc_host_remove);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
 int tmio_mmc_host_suspend(struct device *dev)
 {
        struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -1165,9 +1165,9 @@ int tmio_mmc_host_resume(struct device *dev)
        return 0;
 }
 EXPORT_SYMBOL(tmio_mmc_host_resume);
+#endif
 
-#endif /* CONFIG_PM */
-
+#ifdef CONFIG_PM_RUNTIME
 int tmio_mmc_host_runtime_suspend(struct device *dev)
 {
        return 0;
@@ -1184,5 +1184,6 @@ int tmio_mmc_host_runtime_resume(struct device *dev)
        return 0;
 }
 EXPORT_SYMBOL(tmio_mmc_host_runtime_resume);
+#endif
 
 MODULE_LICENSE("GPL v2");
index c0105a2..d2c386f 100644 (file)
@@ -504,7 +504,7 @@ static int ushc_probe(struct usb_interface *intf, const struct usb_device_id *id
                ret = -ENOMEM;
                goto err;
        }
-       ushc->csw = kzalloc(sizeof(struct ushc_cbw), GFP_KERNEL);
+       ushc->csw = kzalloc(sizeof(struct ushc_csw), GFP_KERNEL);
        if (ushc->csw == NULL) {
                ret = -ENOMEM;
                goto err;
index e902ed7..498d1f7 100644 (file)
@@ -757,7 +757,7 @@ static int wmt_mci_probe(struct platform_device *pdev)
        struct device_node *np = pdev->dev.of_node;
        const struct of_device_id *of_id =
                of_match_device(wmt_mci_dt_ids, &pdev->dev);
-       const struct wmt_mci_caps *wmt_caps = of_id->data;
+       const struct wmt_mci_caps *wmt_caps;
        int ret;
        int regular_irq, dma_irq;
 
@@ -766,6 +766,8 @@ static int wmt_mci_probe(struct platform_device *pdev)
                return -EFAULT;
        }
 
+       wmt_caps = of_id->data;
+
        if (!np) {
                dev_err(&pdev->dev, "Missing SDMMC description in devicetree\n");
                return -EFAULT;
index 5ebcda3..5d49a21 100644 (file)
@@ -150,7 +150,7 @@ config MTD_BCM63XX_PARTS
 
 config MTD_BCM47XX_PARTS
        tristate "BCM47XX partitioning support"
-       depends on BCM47XX
+       depends on BCM47XX || ARCH_BCM_5301X
        help
          This provides partitions parser for devices based on BCM47xx
          boards.
index de1eb92..adfa74c 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/slab.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
-#include <bcm47xx_nvram.h>
 
 /* 10 parts were found on sflash on Netgear WNDR4500 */
 #define BCM47XXPART_MAX_PARTS          12
@@ -30,6 +29,7 @@
 #define BOARD_DATA_MAGIC2              0xBD0D0BBD
 #define CFE_MAGIC                      0x43464531      /* 1EFC */
 #define FACTORY_MAGIC                  0x59544346      /* FCTY */
+#define NVRAM_HEADER                   0x48534C46      /* FLSH */
 #define POT_MAGIC1                     0x54544f50      /* POTT */
 #define POT_MAGIC2                     0x504f          /* OP */
 #define ML_MAGIC1                      0x39685a42
@@ -91,7 +91,7 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                if (offset >= 0x2000000)
                        break;
 
-               if (curr_part > BCM47XXPART_MAX_PARTS) {
+               if (curr_part >= BCM47XXPART_MAX_PARTS) {
                        pr_warn("Reached maximum number of partitions, scanning stopped!\n");
                        break;
                }
@@ -147,6 +147,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
 
                /* TRX */
                if (buf[0x000 / 4] == TRX_MAGIC) {
+                       if (BCM47XXPART_MAX_PARTS - curr_part < 4) {
+                               pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
+                               break;
+                       }
+
                        trx = (struct trx_header *)buf;
 
                        trx_part = curr_part;
@@ -212,7 +217,7 @@ static int bcm47xxpart_parse(struct mtd_info *master,
 
        /* Look for NVRAM at the end of the last block. */
        for (i = 0; i < ARRAY_SIZE(possible_nvram_sizes); i++) {
-               if (curr_part > BCM47XXPART_MAX_PARTS) {
+               if (curr_part >= BCM47XXPART_MAX_PARTS) {
                        pr_warn("Reached maximum number of partitions, scanning stopped!\n");
                        break;
                }
index 7751443..e4ec355 100644 (file)
@@ -21,7 +21,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
@@ -69,10 +68,10 @@ static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, s
 static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_write_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int cfi_intelext_lock_user_prot_reg (struct mtd_info *, loff_t, size_t);
-static int cfi_intelext_get_fact_prot_info (struct mtd_info *,
-                                           struct otp_info *, size_t);
-static int cfi_intelext_get_user_prot_info (struct mtd_info *,
-                                           struct otp_info *, size_t);
+static int cfi_intelext_get_fact_prot_info(struct mtd_info *, size_t,
+                                          size_t *, struct otp_info *);
+static int cfi_intelext_get_user_prot_info(struct mtd_info *, size_t,
+                                          size_t *, struct otp_info *);
 #endif
 static int cfi_intelext_suspend (struct mtd_info *);
 static void cfi_intelext_resume (struct mtd_info *);
@@ -435,10 +434,8 @@ struct mtd_info *cfi_cmdset_0001(struct map_info *map, int primary)
        int i;
 
        mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-       if (!mtd) {
-               printk(KERN_ERR "Failed to allocate memory for MTD device\n");
+       if (!mtd)
                return NULL;
-       }
        mtd->priv = map;
        mtd->type = MTD_NORFLASH;
 
@@ -564,10 +561,8 @@ static struct mtd_info *cfi_intelext_setup(struct mtd_info *mtd)
        mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
        mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
                        * mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) {
-               printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
+       if (!mtd->eraseregions)
                goto setup_err;
-       }
 
        for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
                unsigned long ernum, ersize;
@@ -2399,24 +2394,19 @@ static int cfi_intelext_lock_user_prot_reg(struct mtd_info *mtd,
                                     NULL, do_otp_lock, 1);
 }
 
-static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd,
-                                          struct otp_info *buf, size_t len)
-{
-       size_t retlen;
-       int ret;
+static int cfi_intelext_get_fact_prot_info(struct mtd_info *mtd, size_t len,
+                                          size_t *retlen, struct otp_info *buf)
 
-       ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 0);
-       return ret ? : retlen;
+{
+       return cfi_intelext_otp_walk(mtd, 0, len, retlen, (u_char *)buf,
+                                    NULL, 0);
 }
 
-static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd,
-                                          struct otp_info *buf, size_t len)
+static int cfi_intelext_get_user_prot_info(struct mtd_info *mtd, size_t len,
+                                          size_t *retlen, struct otp_info *buf)
 {
-       size_t retlen;
-       int ret;
-
-       ret = cfi_intelext_otp_walk(mtd, 0, len, &retlen, (u_char *)buf, NULL, 1);
-       return ret ? : retlen;
+       return cfi_intelext_otp_walk(mtd, 0, len, retlen, (u_char *)buf,
+                                    NULL, 1);
 }
 
 #endif
index 89b9d68..e21fde9 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
@@ -507,10 +506,8 @@ struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary)
        int i;
 
        mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-       if (!mtd) {
-               printk(KERN_WARNING "Failed to allocate memory for MTD device\n");
+       if (!mtd)
                return NULL;
-       }
        mtd->priv = map;
        mtd->type = MTD_NORFLASH;
 
@@ -661,10 +658,8 @@ static struct mtd_info *cfi_amdstd_setup(struct mtd_info *mtd)
        mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips;
        mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
                                    * mtd->numeraseregions, GFP_KERNEL);
-       if (!mtd->eraseregions) {
-               printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
+       if (!mtd->eraseregions)
                goto setup_err;
-       }
 
        for (i=0; i<cfi->cfiq->NumEraseRegions; i++) {
                unsigned long ernum, ersize;
index 096993f..6293855 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <asm/io.h>
 #include <asm/byteorder.h>
 
@@ -176,7 +175,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
        //printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips);
 
        if (!mtd) {
-               printk(KERN_ERR "Failed to allocate memory for MTD device\n");
                kfree(cfi->cmdset_priv);
                return NULL;
        }
@@ -189,7 +187,6 @@ static struct mtd_info *cfi_staa_setup(struct map_info *map)
        mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info)
                        * mtd->numeraseregions, GFP_KERNEL);
        if (!mtd->eraseregions) {
-               printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
                kfree(cfi->cmdset_priv);
                kfree(mtd);
                return NULL;
index d255352..e8d0164 100644 (file)
@@ -168,10 +168,8 @@ static int __xipram cfi_chip_setup(struct map_info *map,
                return 0;
 
        cfi->cfiq = kmalloc(sizeof(struct cfi_ident) + num_erase_regions * 4, GFP_KERNEL);
-       if (!cfi->cfiq) {
-               printk(KERN_WARNING "%s: kmalloc failed for CFI ident structure\n", map->name);
+       if (!cfi->cfiq)
                return 0;
-       }
 
        memset(cfi->cfiq,0,sizeof(struct cfi_ident));
 
index f992418..08049f6 100644 (file)
@@ -116,10 +116,8 @@ __xipram cfi_read_pri(struct map_info *map, __u16 adr, __u16 size, const char* n
        printk(KERN_INFO "%s Extended Query Table at 0x%4.4X\n", name, adr);
 
        extp = kmalloc(size, GFP_KERNEL);
-       if (!extp) {
-               printk(KERN_ERR "Failed to allocate memory\n");
+       if (!extp)
                goto out;
-       }
 
 #ifdef CONFIG_MTD_XIP
        local_irq_disable();
index ffb36ba..b57ceea 100644 (file)
@@ -114,7 +114,6 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
        mapsize = sizeof(long) * DIV_ROUND_UP(max_chips, BITS_PER_LONG);
        chip_map = kzalloc(mapsize, GFP_KERNEL);
        if (!chip_map) {
-               printk(KERN_WARNING "%s: kmalloc failed for CFI chip map\n", map->name);
                kfree(cfi.cfiq);
                return NULL;
        }
@@ -139,7 +138,6 @@ static struct cfi_private *genprobe_ident_chips(struct map_info *map, struct chi
        retcfi = kmalloc(sizeof(struct cfi_private) + cfi.numchips * sizeof(struct flchip), GFP_KERNEL);
 
        if (!retcfi) {
-               printk(KERN_WARNING "%s: kmalloc failed for CFI private structure\n", map->name);
                kfree(cfi.cfiq);
                kfree(chip_map);
                return NULL;
index 0128138..1210bc2 100644 (file)
@@ -210,6 +210,14 @@ config MTD_DOCG3
          M-Systems and now Sandisk. The support is very experimental,
          and doesn't give access to any write operations.
 
+config MTD_ST_SPI_FSM
+       tristate "ST Microelectronics SPI FSM Serial Flash Controller"
+       depends on ARM || SH
+       help
+         This provides an MTD device driver for the ST Microelectronics
+         SPI Fast Sequence Mode (FSM) Serial Flash Controller and support
+         for a subset of connected Serial Flash devices.
+
 if MTD_DOCG3
 config BCH_CONST_M
        default 14
index d83bd73..c68868f 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_NAND_OMAP_BCH)       += elm.o
 obj-$(CONFIG_MTD_SPEAR_SMI)    += spear_smi.o
 obj-$(CONFIG_MTD_SST25L)       += sst25l.o
 obj-$(CONFIG_MTD_BCM47XXSFLASH)        += bcm47xxsflash.o
+obj-$(CONFIG_MTD_ST_SPI_FSM)    += st_spi_fsm.o
 
 
 CFLAGS_docg3.o                 += -I$(src)
index d9fd87a..66f0405 100644 (file)
@@ -209,7 +209,6 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
 }
 
 
-/* FIXME: ensure that mtd->size % erase_size == 0 */
 static struct block2mtd_dev *add_device(char *devname, int erase_size)
 {
        const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
@@ -240,13 +239,18 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 
        if (IS_ERR(bdev)) {
                pr_err("error: cannot open device %s\n", devname);
-               goto devinit_err;
+               goto err_free_block2mtd;
        }
        dev->blkdev = bdev;
 
        if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
                pr_err("attempting to use an MTD device as a block device\n");
-               goto devinit_err;
+               goto err_free_block2mtd;
+       }
+
+       if ((long)dev->blkdev->bd_inode->i_size % erase_size) {
+               pr_err("erasesize must be a divisor of device size\n");
+               goto err_free_block2mtd;
        }
 
        mutex_init(&dev->write_mutex);
@@ -255,7 +259,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
        /* make the name contain the block device in */
        name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname);
        if (!name)
-               goto devinit_err;
+               goto err_destroy_mutex;
 
        dev->mtd.name = name;
 
@@ -274,7 +278,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
 
        if (mtd_device_register(&dev->mtd, NULL, 0)) {
                /* Device didn't get added, so free the entry */
-               goto devinit_err;
+               goto err_destroy_mutex;
        }
        list_add(&dev->list, &blkmtd_device_list);
        pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
@@ -283,7 +287,9 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size)
                dev->mtd.erasesize >> 10, dev->mtd.erasesize);
        return dev;
 
-devinit_err:
+err_destroy_mutex:
+       mutex_destroy(&dev->write_mutex);
+err_free_block2mtd:
        block2mtd_free_device(dev);
        return NULL;
 }
@@ -448,6 +454,7 @@ static void block2mtd_exit(void)
                struct block2mtd_dev *dev = list_entry(pos, typeof(*dev), list);
                block2mtd_sync(&dev->mtd);
                mtd_device_unregister(&dev->mtd);
+               mutex_destroy(&dev->write_mutex);
                pr_info("mtd%d: [%s] removed\n",
                        dev->mtd.index,
                        dev->mtd.name + strlen("block2mtd: "));
index d1dd6a3..1fd4a0f 100644 (file)
@@ -15,6 +15,8 @@
  *
  */
 
+#define DRIVER_NAME    "omap-elm"
+
 #include <linux/platform_device.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
@@ -84,6 +86,8 @@ struct elm_info {
        struct list_head list;
        enum bch_ecc bch_type;
        struct elm_registers elm_regs;
+       int ecc_steps;
+       int ecc_syndrome_size;
 };
 
 static LIST_HEAD(elm_devices);
@@ -103,7 +107,8 @@ static u32 elm_read_reg(struct elm_info *info, int offset)
  * @dev:       ELM device
  * @bch_type:  Type of BCH ecc
  */
-int elm_config(struct device *dev, enum bch_ecc bch_type)
+int elm_config(struct device *dev, enum bch_ecc bch_type,
+       int ecc_steps, int ecc_step_size, int ecc_syndrome_size)
 {
        u32 reg_val;
        struct elm_info *info = dev_get_drvdata(dev);
@@ -112,10 +117,22 @@ int elm_config(struct device *dev, enum bch_ecc bch_type)
                dev_err(dev, "Unable to configure elm - device not probed?\n");
                return -ENODEV;
        }
+       /* ELM cannot detect ECC errors for chunks > 1KB */
+       if (ecc_step_size > ((ELM_ECC_SIZE + 1) / 2)) {
+               dev_err(dev, "unsupported config ecc-size=%d\n", ecc_step_size);
+               return -EINVAL;
+       }
+       /* ELM support 8 error syndrome process */
+       if (ecc_steps > ERROR_VECTOR_MAX) {
+               dev_err(dev, "unsupported config ecc-step=%d\n", ecc_steps);
+               return -EINVAL;
+       }
 
        reg_val = (bch_type & ECC_BCH_LEVEL_MASK) | (ELM_ECC_SIZE << 16);
        elm_write_reg(info, ELM_LOCATION_CONFIG, reg_val);
-       info->bch_type = bch_type;
+       info->bch_type          = bch_type;
+       info->ecc_steps         = ecc_steps;
+       info->ecc_syndrome_size = ecc_syndrome_size;
 
        return 0;
 }
@@ -157,17 +174,15 @@ static void elm_load_syndrome(struct elm_info *info,
        int i, offset;
        u32 val;
 
-       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+       for (i = 0; i < info->ecc_steps; i++) {
 
                /* Check error reported */
                if (err_vec[i].error_reported) {
                        elm_configure_page_mode(info, i, true);
                        offset = ELM_SYNDROME_FRAGMENT_0 +
                                SYNDROME_FRAGMENT_REG_SIZE * i;
-
-                       /* BCH8 */
-                       if (info->bch_type) {
-
+                       switch (info->bch_type) {
+                       case BCH8_ECC:
                                /* syndrome fragment 0 = ecc[9-12B] */
                                val = cpu_to_be32(*(u32 *) &ecc[9]);
                                elm_write_reg(info, offset, val);
@@ -186,7 +201,8 @@ static void elm_load_syndrome(struct elm_info *info,
                                offset += 4;
                                val = ecc[0];
                                elm_write_reg(info, offset, val);
-                       } else {
+                               break;
+                       case BCH4_ECC:
                                /* syndrome fragment 0 = ecc[20-52b] bits */
                                val = (cpu_to_be32(*(u32 *) &ecc[3]) >> 4) |
                                        ((ecc[2] & 0xf) << 28);
@@ -196,11 +212,14 @@ static void elm_load_syndrome(struct elm_info *info,
                                offset += 4;
                                val = cpu_to_be32(*(u32 *) &ecc[0]) >> 12;
                                elm_write_reg(info, offset, val);
+                               break;
+                       default:
+                               pr_err("invalid config bch_type\n");
                        }
                }
 
                /* Update ecc pointer with ecc byte size */
-               ecc += info->bch_type ? BCH8_SIZE : BCH4_SIZE;
+               ecc += info->ecc_syndrome_size;
        }
 }
 
@@ -223,7 +242,7 @@ static void elm_start_processing(struct elm_info *info,
         * Set syndrome vector valid, so that ELM module
         * will process it for vectors error is reported
         */
-       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+       for (i = 0; i < info->ecc_steps; i++) {
                if (err_vec[i].error_reported) {
                        offset = ELM_SYNDROME_FRAGMENT_6 +
                                SYNDROME_FRAGMENT_REG_SIZE * i;
@@ -252,7 +271,7 @@ static void elm_error_correction(struct elm_info *info,
        int offset;
        u32 reg_val;
 
-       for (i = 0; i < ERROR_VECTOR_MAX; i++) {
+       for (i = 0; i < info->ecc_steps; i++) {
 
                /* Check error reported */
                if (err_vec[i].error_reported) {
@@ -354,10 +373,8 @@ static int elm_probe(struct platform_device *pdev)
        struct elm_info *info;
 
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-       if (!info) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
+       if (!info)
                return -ENOMEM;
-       }
 
        info->dev = &pdev->dev;
 
@@ -380,7 +397,7 @@ static int elm_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
-       if (pm_runtime_get_sync(&pdev->dev)) {
+       if (pm_runtime_get_sync(&pdev->dev) < 0) {
                ret = -EINVAL;
                pm_runtime_disable(&pdev->dev);
                dev_err(&pdev->dev, "can't enable clock\n");
@@ -505,7 +522,7 @@ MODULE_DEVICE_TABLE(of, elm_of_match);
 
 static struct platform_driver elm_driver = {
        .driver = {
-               .name   = "elm",
+               .name   = DRIVER_NAME,
                .owner  = THIS_MODULE,
                .of_match_table = of_match_ptr(elm_of_match),
                .pm     = &elm_pm_ops,
index ad19139..524dab3 100644 (file)
@@ -15,7 +15,6 @@
  *
  */
 
-#include <linux/init.h>
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/module.h>
@@ -41,7 +40,8 @@
 #define        OPCODE_WRSR             0x01    /* Write status register 1 byte */
 #define        OPCODE_NORM_READ        0x03    /* Read data bytes (low frequency) */
 #define        OPCODE_FAST_READ        0x0b    /* Read data bytes (high frequency) */
-#define        OPCODE_QUAD_READ        0x6b    /* Read data bytes */
+#define        OPCODE_DUAL_READ        0x3b    /* Read data bytes (Dual SPI) */
+#define        OPCODE_QUAD_READ        0x6b    /* Read data bytes (Quad SPI) */
 #define        OPCODE_PP               0x02    /* Page program (up to 256 bytes) */
 #define        OPCODE_BE_4K            0x20    /* Erase 4KiB block */
 #define        OPCODE_BE_4K_PMC        0xd7    /* Erase 4KiB block on PMC chips */
@@ -54,7 +54,8 @@
 /* 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_QUAD_READ_4B     0x6c    /* Read data bytes */
+#define        OPCODE_DUAL_READ_4B     0x3c    /* Read data bytes (Dual SPI) */
+#define        OPCODE_QUAD_READ_4B     0x6c    /* Read data bytes (Quad SPI) */
 #define        OPCODE_PP_4B            0x12    /* Page program (up to 256 bytes) */
 #define        OPCODE_SE_4B            0xdc    /* Sector erase (usually 64KiB) */
 
@@ -95,6 +96,7 @@
 enum read_type {
        M25P80_NORMAL = 0,
        M25P80_FAST,
+       M25P80_DUAL,
        M25P80_QUAD,
 };
 
@@ -479,6 +481,7 @@ static inline int m25p80_dummy_cycles_read(struct m25p *flash)
 {
        switch (flash->flash_read) {
        case M25P80_FAST:
+       case M25P80_DUAL:
        case M25P80_QUAD:
                return 1;
        case M25P80_NORMAL:
@@ -492,6 +495,8 @@ static inline int m25p80_dummy_cycles_read(struct m25p *flash)
 static inline unsigned int m25p80_rx_nbits(const struct m25p *flash)
 {
        switch (flash->flash_read) {
+       case M25P80_DUAL:
+               return 2;
        case M25P80_QUAD:
                return 4;
        default:
@@ -855,7 +860,8 @@ struct flash_info {
 #define        SST_WRITE       0x04            /* use SST byte programming */
 #define        M25P_NO_FR      0x08            /* Can't do fastread */
 #define        SECT_4K_PMC     0x10            /* OPCODE_BE_4K_PMC works uniformly */
-#define        M25P80_QUAD_READ        0x20    /* Flash supports Quad Read */
+#define        M25P80_DUAL_READ        0x20    /* Flash supports Dual Read */
+#define        M25P80_QUAD_READ        0x40    /* Flash supports Quad Read */
 };
 
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
@@ -934,6 +940,7 @@ static const struct spi_device_id m25p_ids[] = {
        { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
        { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
        { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) },
+       { "mx66l1g55g",  INFO(0xc2261b, 0, 64 * 1024, 2048, M25P80_QUAD_READ) },
 
        /* Micron */
        { "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, 0) },
@@ -953,8 +960,8 @@ static const struct spi_device_id m25p_ids[] = {
        { "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, 0) },
        { "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, 0) },
        { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
-       { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, M25P80_QUAD_READ) },
-       { "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_QUAD_READ) },
+       { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, M25P80_DUAL_READ | M25P80_QUAD_READ) },
+       { "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_DUAL_READ | M25P80_QUAD_READ) },
        { "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
        { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
        { "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
@@ -965,6 +972,7 @@ static const struct spi_device_id m25p_ids[] = {
        { "s25sl016a",  INFO(0x010214,      0,  64 * 1024,  32, 0) },
        { "s25sl032a",  INFO(0x010215,      0,  64 * 1024,  64, 0) },
        { "s25sl064a",  INFO(0x010216,      0,  64 * 1024, 128, 0) },
+       { "s25fl008k",  INFO(0xef4014,      0,  64 * 1024,  16, SECT_4K) },
        { "s25fl016k",  INFO(0xef4015,      0,  64 * 1024,  32, SECT_4K) },
        { "s25fl064k",  INFO(0xef4017,      0,  64 * 1024, 128, SECT_4K) },
 
@@ -1072,9 +1080,8 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi)
        for (tmp = 0; tmp < ARRAY_SIZE(m25p_ids) - 1; tmp++) {
                info = (void *)m25p_ids[tmp].driver_data;
                if (info->jedec_id == jedec) {
-                       if (info->ext_id != 0 && info->ext_id != ext_jedec)
-                               continue;
-                       return &m25p_ids[tmp];
+                       if (info->ext_id == 0 || info->ext_id == ext_jedec)
+                               return &m25p_ids[tmp];
                }
        }
        dev_err(&spi->dev, "unrecognized JEDEC id %06x\n", jedec);
@@ -1226,7 +1233,7 @@ static int m25p_probe(struct spi_device *spi)
        if (info->flags & M25P_NO_FR)
                flash->flash_read = M25P80_NORMAL;
 
-       /* Quad-read mode takes precedence over fast/normal */
+       /* Quad/Dual-read mode takes precedence over fast/normal */
        if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) {
                ret = set_quad_mode(flash, info->jedec_id);
                if (ret) {
@@ -1234,6 +1241,8 @@ static int m25p_probe(struct spi_device *spi)
                        return ret;
                }
                flash->flash_read = M25P80_QUAD;
+       } else if (spi->mode & SPI_RX_DUAL && info->flags & M25P80_DUAL_READ) {
+               flash->flash_read = M25P80_DUAL;
        }
 
        /* Default commands */
@@ -1241,6 +1250,9 @@ static int m25p_probe(struct spi_device *spi)
        case M25P80_QUAD:
                flash->read_opcode = OPCODE_QUAD_READ;
                break;
+       case M25P80_DUAL:
+               flash->read_opcode = OPCODE_DUAL_READ;
+               break;
        case M25P80_FAST:
                flash->read_opcode = OPCODE_FAST_READ;
                break;
@@ -1265,6 +1277,9 @@ static int m25p_probe(struct spi_device *spi)
                        case M25P80_QUAD:
                                flash->read_opcode = OPCODE_QUAD_READ_4B;
                                break;
+                       case M25P80_DUAL:
+                               flash->read_opcode = OPCODE_DUAL_READ_4B;
+                               break;
                        case M25P80_FAST:
                                flash->read_opcode = OPCODE_FAST_READ_4B;
                                break;
index 624069d..dd22ce2 100644 (file)
@@ -10,7 +10,6 @@
  * 2 of the License, or (at your option) any later version.
 */
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/device.h>
@@ -440,8 +439,8 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
 
 #ifdef CONFIG_MTD_DATAFLASH_OTP
 
-static int dataflash_get_otp_info(struct mtd_info *mtd,
-               struct otp_info *info, size_t len)
+static int dataflash_get_otp_info(struct mtd_info *mtd, size_t len,
+                                 size_t *retlen, struct otp_info *info)
 {
        /* Report both blocks as identical:  bytes 0..64, locked.
         * Unless the user block changed from all-ones, we can't
@@ -450,7 +449,8 @@ static int dataflash_get_otp_info(struct mtd_info *mtd,
        info->start = 0;
        info->length = 64;
        info->locked = 1;
-       return sizeof(*info);
+       *retlen = sizeof(*info);
+       return 0;
 }
 
 static ssize_t otp_read(struct spi_device *spi, unsigned base,
@@ -542,14 +542,18 @@ static int dataflash_write_user_otp(struct mtd_info *mtd,
        struct dataflash        *priv = mtd->priv;
        int                     status;
 
-       if (len > 64)
-               return -EINVAL;
+       if (from >= 64) {
+               /*
+                * Attempting to write beyond the end of OTP memory,
+                * no data can be written.
+                */
+               *retlen = 0;
+               return 0;
+       }
 
-       /* Strictly speaking, we *could* truncate the write ... but
-        * let's not do that for the only write that's ever possible.
-        */
+       /* Truncate the write to fit into OTP memory. */
        if ((from + len) > 64)
-               return -EINVAL;
+               len = 64 - from;
 
        /* OUT: OP_WRITE_SECURITY, 3 zeroes, 64 data-or-zero bytes
         * IN:  ignore all
index e1f2aeb..2cceebf 100644 (file)
@@ -205,6 +205,8 @@ static inline void kill_final_newline(char *str)
        return 1;               \
 } while (0)
 
+#ifndef MODULE
+static int phram_init_called;
 /*
  * This shall contain the module parameter if any. It is of the form:
  * - phram=<device>,<address>,<size> for module case
@@ -213,9 +215,10 @@ static inline void kill_final_newline(char *str)
  * size.
  * Example: phram.phram=rootfs,0xa0000000,512Mi
  */
-static __initdata char phram_paramline[64 + 20 + 20];
+static char phram_paramline[64 + 20 + 20];
+#endif
 
-static int __init phram_setup(const char *val)
+static int phram_setup(const char *val)
 {
        char buf[64 + 20 + 20], *str = buf;
        char *token[3];
@@ -264,17 +267,36 @@ static int __init phram_setup(const char *val)
        return ret;
 }
 
-static int __init phram_param_call(const char *val, struct kernel_param *kp)
+static int phram_param_call(const char *val, struct kernel_param *kp)
 {
+#ifdef MODULE
+       return phram_setup(val);
+#else
        /*
-        * This function is always called before 'init_phram()', whether
-        * built-in or module.
+        * If more parameters are later passed in via
+        * /sys/module/phram/parameters/phram
+        * and init_phram() has already been called,
+        * we can parse the argument now.
         */
+
+       if (phram_init_called)
+               return phram_setup(val);
+
+       /*
+        * During early boot stage, we only save the parameters
+        * here. We must parse them later: if the param passed
+        * from kernel boot command line, phram_param_call() is
+        * called so early that it is not possible to resolve
+        * the device (even kmalloc() fails). Defer that work to
+        * phram_setup().
+        */
+
        if (strlen(val) >= sizeof(phram_paramline))
                return -ENOSPC;
        strcpy(phram_paramline, val);
 
        return 0;
+#endif
 }
 
 module_param_call(phram, phram_param_call, NULL, NULL, 000);
@@ -283,10 +305,15 @@ MODULE_PARM_DESC(phram, "Memory region to map. \"phram=<name>,<start>,<length>\"
 
 static int __init init_phram(void)
 {
+       int ret = 0;
+
+#ifndef MODULE
        if (phram_paramline[0])
-               return phram_setup(phram_paramline);
+               ret = phram_setup(phram_paramline);
+       phram_init_called = 1;
+#endif
 
-       return 0;
+       return ret;
 }
 
 static void __exit cleanup_phram(void)
index 0c51b98..f02603e 100644 (file)
@@ -725,16 +725,11 @@ static int __init init_pmc551(void)
                }
 
                mtd = kzalloc(sizeof(struct mtd_info), GFP_KERNEL);
-               if (!mtd) {
-                       printk(KERN_NOTICE "pmc551: Cannot allocate new MTD "
-                               "device.\n");
+               if (!mtd)
                        break;
-               }
 
                priv = kzalloc(sizeof(struct mypriv), GFP_KERNEL);
                if (!priv) {
-                       printk(KERN_NOTICE "pmc551: Cannot allocate new MTD "
-                               "device.\n");
                        kfree(mtd);
                        break;
                }
diff --git a/drivers/mtd/devices/serial_flash_cmds.h b/drivers/mtd/devices/serial_flash_cmds.h
new file mode 100644 (file)
index 0000000..4f0c2c7
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * Generic/SFDP Flash Commands and Device Capabilities
+ *
+ * Copyright (C) 2013 Lee Jones <lee.jones@lianro.org>
+ *
+ * This code 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 _MTD_SERIAL_FLASH_CMDS_H
+#define _MTD_SERIAL_FLASH_CMDS_H
+
+/* Generic Flash Commands/OPCODEs */
+#define FLASH_CMD_WREN         0x06
+#define FLASH_CMD_WRDI         0x04
+#define FLASH_CMD_RDID         0x9f
+#define FLASH_CMD_RDSR         0x05
+#define FLASH_CMD_RDSR2                0x35
+#define FLASH_CMD_WRSR         0x01
+#define FLASH_CMD_SE_4K                0x20
+#define FLASH_CMD_SE_32K       0x52
+#define FLASH_CMD_SE           0xd8
+#define FLASH_CMD_CHIPERASE    0xc7
+#define FLASH_CMD_WRVCR                0x81
+#define FLASH_CMD_RDVCR                0x85
+
+/* JEDEC Standard - Serial Flash Discoverable Parmeters (SFDP) Commands */
+#define FLASH_CMD_READ         0x03    /* READ */
+#define FLASH_CMD_READ_FAST    0x0b    /* FAST READ */
+#define FLASH_CMD_READ_1_1_2   0x3b    /* DUAL OUTPUT READ */
+#define FLASH_CMD_READ_1_2_2   0xbb    /* DUAL I/O READ */
+#define FLASH_CMD_READ_1_1_4   0x6b    /* QUAD OUTPUT READ */
+#define FLASH_CMD_READ_1_4_4   0xeb    /* QUAD I/O READ */
+
+#define FLASH_CMD_WRITE                0x02    /* PAGE PROGRAM */
+#define FLASH_CMD_WRITE_1_1_2  0xa2    /* DUAL INPUT PROGRAM */
+#define FLASH_CMD_WRITE_1_2_2  0xd2    /* DUAL INPUT EXT PROGRAM */
+#define FLASH_CMD_WRITE_1_1_4  0x32    /* QUAD INPUT PROGRAM */
+#define FLASH_CMD_WRITE_1_4_4  0x12    /* QUAD INPUT EXT PROGRAM */
+
+#define FLASH_CMD_EN4B_ADDR    0xb7    /* Enter 4-byte address mode */
+#define FLASH_CMD_EX4B_ADDR    0xe9    /* Exit 4-byte address mode */
+
+/* READ commands with 32-bit addressing */
+#define FLASH_CMD_READ4                0x13
+#define FLASH_CMD_READ4_FAST   0x0c
+#define FLASH_CMD_READ4_1_1_2  0x3c
+#define FLASH_CMD_READ4_1_2_2  0xbc
+#define FLASH_CMD_READ4_1_1_4  0x6c
+#define FLASH_CMD_READ4_1_4_4  0xec
+
+/* Configuration flags */
+#define FLASH_FLAG_SINGLE      0x000000ff
+#define FLASH_FLAG_READ_WRITE  0x00000001
+#define FLASH_FLAG_READ_FAST   0x00000002
+#define FLASH_FLAG_SE_4K       0x00000004
+#define FLASH_FLAG_SE_32K      0x00000008
+#define FLASH_FLAG_CE          0x00000010
+#define FLASH_FLAG_32BIT_ADDR  0x00000020
+#define FLASH_FLAG_RESET       0x00000040
+#define FLASH_FLAG_DYB_LOCKING 0x00000080
+
+#define FLASH_FLAG_DUAL                0x0000ff00
+#define FLASH_FLAG_READ_1_1_2  0x00000100
+#define FLASH_FLAG_READ_1_2_2  0x00000200
+#define FLASH_FLAG_READ_2_2_2  0x00000400
+#define FLASH_FLAG_WRITE_1_1_2 0x00001000
+#define FLASH_FLAG_WRITE_1_2_2 0x00002000
+#define FLASH_FLAG_WRITE_2_2_2 0x00004000
+
+#define FLASH_FLAG_QUAD                0x00ff0000
+#define FLASH_FLAG_READ_1_1_4  0x00010000
+#define FLASH_FLAG_READ_1_4_4  0x00020000
+#define FLASH_FLAG_READ_4_4_4  0x00040000
+#define FLASH_FLAG_WRITE_1_1_4 0x00100000
+#define FLASH_FLAG_WRITE_1_4_4 0x00200000
+#define FLASH_FLAG_WRITE_4_4_4 0x00400000
+
+#endif /* _MTD_SERIAL_FLASH_CMDS_H */
index 4238214..363da96 100644 (file)
@@ -913,7 +913,6 @@ static int spear_smi_probe(struct platform_device *pdev)
        if (np) {
                pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
                if (!pdata) {
-                       pr_err("%s: ERROR: no memory", __func__);
                        ret = -ENOMEM;
                        goto err;
                }
@@ -943,7 +942,6 @@ static int spear_smi_probe(struct platform_device *pdev)
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_ATOMIC);
        if (!dev) {
                ret = -ENOMEM;
-               dev_err(&pdev->dev, "mem alloc fail\n");
                goto err;
        }
 
index 687bf27..c63ecbc 100644 (file)
@@ -15,7 +15,6 @@
  *
  */
 
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
new file mode 100644 (file)
index 0000000..1957d7c
--- /dev/null
@@ -0,0 +1,2108 @@
+/*
+ * st_spi_fsm.c        - ST Fast Sequence Mode (FSM) Serial Flash Controller
+ *
+ * Author: Angus Clark <angus.clark@st.com>
+ *
+ * Copyright (C) 2010-2014 STMicroelectronics Limited
+ *
+ * JEDEC probe based on drivers/mtd/devices/m25p80.c
+ *
+ * This code 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/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/of.h>
+
+#include "serial_flash_cmds.h"
+
+/*
+ * FSM SPI Controller Registers
+ */
+#define SPI_CLOCKDIV                   0x0010
+#define SPI_MODESELECT                 0x0018
+#define SPI_CONFIGDATA                 0x0020
+#define SPI_STA_MODE_CHANGE            0x0028
+#define SPI_FAST_SEQ_TRANSFER_SIZE     0x0100
+#define SPI_FAST_SEQ_ADD1              0x0104
+#define SPI_FAST_SEQ_ADD2              0x0108
+#define SPI_FAST_SEQ_ADD_CFG           0x010c
+#define SPI_FAST_SEQ_OPC1              0x0110
+#define SPI_FAST_SEQ_OPC2              0x0114
+#define SPI_FAST_SEQ_OPC3              0x0118
+#define SPI_FAST_SEQ_OPC4              0x011c
+#define SPI_FAST_SEQ_OPC5              0x0120
+#define SPI_MODE_BITS                  0x0124
+#define SPI_DUMMY_BITS                 0x0128
+#define SPI_FAST_SEQ_FLASH_STA_DATA    0x012c
+#define SPI_FAST_SEQ_1                 0x0130
+#define SPI_FAST_SEQ_2                 0x0134
+#define SPI_FAST_SEQ_3                 0x0138
+#define SPI_FAST_SEQ_4                 0x013c
+#define SPI_FAST_SEQ_CFG               0x0140
+#define SPI_FAST_SEQ_STA               0x0144
+#define SPI_QUAD_BOOT_SEQ_INIT_1       0x0148
+#define SPI_QUAD_BOOT_SEQ_INIT_2       0x014c
+#define SPI_QUAD_BOOT_READ_SEQ_1       0x0150
+#define SPI_QUAD_BOOT_READ_SEQ_2       0x0154
+#define SPI_PROGRAM_ERASE_TIME         0x0158
+#define SPI_MULT_PAGE_REPEAT_SEQ_1     0x015c
+#define SPI_MULT_PAGE_REPEAT_SEQ_2     0x0160
+#define SPI_STATUS_WR_TIME_REG         0x0164
+#define SPI_FAST_SEQ_DATA_REG          0x0300
+
+/*
+ * Register: SPI_MODESELECT
+ */
+#define SPI_MODESELECT_CONTIG          0x01
+#define SPI_MODESELECT_FASTREAD                0x02
+#define SPI_MODESELECT_DUALIO          0x04
+#define SPI_MODESELECT_FSM             0x08
+#define SPI_MODESELECT_QUADBOOT                0x10
+
+/*
+ * Register: SPI_CONFIGDATA
+ */
+#define SPI_CFG_DEVICE_ST              0x1
+#define SPI_CFG_DEVICE_ATMEL           0x4
+#define SPI_CFG_MIN_CS_HIGH(x)         (((x) & 0xfff) << 4)
+#define SPI_CFG_CS_SETUPHOLD(x)                (((x) & 0xff) << 16)
+#define SPI_CFG_DATA_HOLD(x)           (((x) & 0xff) << 24)
+
+#define SPI_CFG_DEFAULT_MIN_CS_HIGH    SPI_CFG_MIN_CS_HIGH(0x0AA)
+#define SPI_CFG_DEFAULT_CS_SETUPHOLD   SPI_CFG_CS_SETUPHOLD(0xA0)
+#define SPI_CFG_DEFAULT_DATA_HOLD      SPI_CFG_DATA_HOLD(0x00)
+
+/*
+ * Register: SPI_FAST_SEQ_TRANSFER_SIZE
+ */
+#define TRANSFER_SIZE(x)               ((x) * 8)
+
+/*
+ * Register: SPI_FAST_SEQ_ADD_CFG
+ */
+#define ADR_CFG_CYCLES_ADD1(x)         ((x) << 0)
+#define ADR_CFG_PADS_1_ADD1            (0x0 << 6)
+#define ADR_CFG_PADS_2_ADD1            (0x1 << 6)
+#define ADR_CFG_PADS_4_ADD1            (0x3 << 6)
+#define ADR_CFG_CSDEASSERT_ADD1                (1   << 8)
+#define ADR_CFG_CYCLES_ADD2(x)         ((x) << (0+16))
+#define ADR_CFG_PADS_1_ADD2            (0x0 << (6+16))
+#define ADR_CFG_PADS_2_ADD2            (0x1 << (6+16))
+#define ADR_CFG_PADS_4_ADD2            (0x3 << (6+16))
+#define ADR_CFG_CSDEASSERT_ADD2                (1   << (8+16))
+
+/*
+ * Register: SPI_FAST_SEQ_n
+ */
+#define SEQ_OPC_OPCODE(x)              ((x) << 0)
+#define SEQ_OPC_CYCLES(x)              ((x) << 8)
+#define SEQ_OPC_PADS_1                 (0x0 << 14)
+#define SEQ_OPC_PADS_2                 (0x1 << 14)
+#define SEQ_OPC_PADS_4                 (0x3 << 14)
+#define SEQ_OPC_CSDEASSERT             (1   << 16)
+
+/*
+ * Register: SPI_FAST_SEQ_CFG
+ */
+#define SEQ_CFG_STARTSEQ               (1 << 0)
+#define SEQ_CFG_SWRESET                        (1 << 5)
+#define SEQ_CFG_CSDEASSERT             (1 << 6)
+#define SEQ_CFG_READNOTWRITE           (1 << 7)
+#define SEQ_CFG_ERASE                  (1 << 8)
+#define SEQ_CFG_PADS_1                 (0x0 << 16)
+#define SEQ_CFG_PADS_2                 (0x1 << 16)
+#define SEQ_CFG_PADS_4                 (0x3 << 16)
+
+/*
+ * Register: SPI_MODE_BITS
+ */
+#define MODE_DATA(x)                   (x & 0xff)
+#define MODE_CYCLES(x)                 ((x & 0x3f) << 16)
+#define MODE_PADS_1                    (0x0 << 22)
+#define MODE_PADS_2                    (0x1 << 22)
+#define MODE_PADS_4                    (0x3 << 22)
+#define DUMMY_CSDEASSERT               (1   << 24)
+
+/*
+ * Register: SPI_DUMMY_BITS
+ */
+#define DUMMY_CYCLES(x)                        ((x & 0x3f) << 16)
+#define DUMMY_PADS_1                   (0x0 << 22)
+#define DUMMY_PADS_2                   (0x1 << 22)
+#define DUMMY_PADS_4                   (0x3 << 22)
+#define DUMMY_CSDEASSERT               (1   << 24)
+
+/*
+ * Register: SPI_FAST_SEQ_FLASH_STA_DATA
+ */
+#define STA_DATA_BYTE1(x)              ((x & 0xff) << 0)
+#define STA_DATA_BYTE2(x)              ((x & 0xff) << 8)
+#define STA_PADS_1                     (0x0 << 16)
+#define STA_PADS_2                     (0x1 << 16)
+#define STA_PADS_4                     (0x3 << 16)
+#define STA_CSDEASSERT                 (0x1 << 20)
+#define STA_RDNOTWR                    (0x1 << 21)
+
+/*
+ * FSM SPI Instruction Opcodes
+ */
+#define STFSM_OPC_CMD                  0x1
+#define STFSM_OPC_ADD                  0x2
+#define STFSM_OPC_STA                  0x3
+#define STFSM_OPC_MODE                 0x4
+#define STFSM_OPC_DUMMY                0x5
+#define STFSM_OPC_DATA                 0x6
+#define STFSM_OPC_WAIT                 0x7
+#define STFSM_OPC_JUMP                 0x8
+#define STFSM_OPC_GOTO                 0x9
+#define STFSM_OPC_STOP                 0xF
+
+/*
+ * FSM SPI Instructions (== opcode + operand).
+ */
+#define STFSM_INSTR(cmd, op)           ((cmd) | ((op) << 4))
+
+#define STFSM_INST_CMD1                        STFSM_INSTR(STFSM_OPC_CMD,      1)
+#define STFSM_INST_CMD2                        STFSM_INSTR(STFSM_OPC_CMD,      2)
+#define STFSM_INST_CMD3                        STFSM_INSTR(STFSM_OPC_CMD,      3)
+#define STFSM_INST_CMD4                        STFSM_INSTR(STFSM_OPC_CMD,      4)
+#define STFSM_INST_CMD5                        STFSM_INSTR(STFSM_OPC_CMD,      5)
+#define STFSM_INST_ADD1                        STFSM_INSTR(STFSM_OPC_ADD,      1)
+#define STFSM_INST_ADD2                        STFSM_INSTR(STFSM_OPC_ADD,      2)
+
+#define STFSM_INST_DATA_WRITE          STFSM_INSTR(STFSM_OPC_DATA,     1)
+#define STFSM_INST_DATA_READ           STFSM_INSTR(STFSM_OPC_DATA,     2)
+
+#define STFSM_INST_STA_RD1             STFSM_INSTR(STFSM_OPC_STA,      0x1)
+#define STFSM_INST_STA_WR1             STFSM_INSTR(STFSM_OPC_STA,      0x1)
+#define STFSM_INST_STA_RD2             STFSM_INSTR(STFSM_OPC_STA,      0x2)
+#define STFSM_INST_STA_WR1_2           STFSM_INSTR(STFSM_OPC_STA,      0x3)
+
+#define STFSM_INST_MODE                        STFSM_INSTR(STFSM_OPC_MODE,     0)
+#define STFSM_INST_DUMMY               STFSM_INSTR(STFSM_OPC_DUMMY,    0)
+#define STFSM_INST_WAIT                        STFSM_INSTR(STFSM_OPC_WAIT,     0)
+#define STFSM_INST_STOP                        STFSM_INSTR(STFSM_OPC_STOP,     0)
+
+#define STFSM_DEFAULT_EMI_FREQ 100000000UL                        /* 100 MHz */
+#define STFSM_DEFAULT_WR_TIME  (STFSM_DEFAULT_EMI_FREQ * (15/1000)) /* 15ms */
+
+#define STFSM_FLASH_SAFE_FREQ  10000000UL                         /* 10 MHz */
+
+#define STFSM_MAX_WAIT_SEQ_MS  1000     /* FSM execution time */
+
+/* Flash Commands */
+#define FLASH_CMD_WREN         0x06
+#define FLASH_CMD_WRDI         0x04
+#define FLASH_CMD_RDID         0x9f
+#define FLASH_CMD_RDSR         0x05
+#define FLASH_CMD_RDSR2                0x35
+#define FLASH_CMD_WRSR         0x01
+#define FLASH_CMD_SE_4K                0x20
+#define FLASH_CMD_SE_32K       0x52
+#define FLASH_CMD_SE           0xd8
+#define FLASH_CMD_CHIPERASE    0xc7
+#define FLASH_CMD_WRVCR                0x81
+#define FLASH_CMD_RDVCR                0x85
+
+#define FLASH_CMD_READ         0x03    /* READ */
+#define FLASH_CMD_READ_FAST    0x0b    /* FAST READ */
+#define FLASH_CMD_READ_1_1_2   0x3b    /* DUAL OUTPUT READ */
+#define FLASH_CMD_READ_1_2_2   0xbb    /* DUAL I/O READ */
+#define FLASH_CMD_READ_1_1_4   0x6b    /* QUAD OUTPUT READ */
+#define FLASH_CMD_READ_1_4_4   0xeb    /* QUAD I/O READ */
+
+#define FLASH_CMD_WRITE                0x02    /* PAGE PROGRAM */
+#define FLASH_CMD_WRITE_1_1_2  0xa2    /* DUAL INPUT PROGRAM */
+#define FLASH_CMD_WRITE_1_2_2  0xd2    /* DUAL INPUT EXT PROGRAM */
+#define FLASH_CMD_WRITE_1_1_4  0x32    /* QUAD INPUT PROGRAM */
+#define FLASH_CMD_WRITE_1_4_4  0x12    /* QUAD INPUT EXT PROGRAM */
+
+#define FLASH_CMD_EN4B_ADDR    0xb7    /* Enter 4-byte address mode */
+#define FLASH_CMD_EX4B_ADDR    0xe9    /* Exit 4-byte address mode */
+
+/* READ commands with 32-bit addressing (N25Q256 and S25FLxxxS) */
+#define FLASH_CMD_READ4                0x13
+#define FLASH_CMD_READ4_FAST   0x0c
+#define FLASH_CMD_READ4_1_1_2  0x3c
+#define FLASH_CMD_READ4_1_2_2  0xbc
+#define FLASH_CMD_READ4_1_1_4  0x6c
+#define FLASH_CMD_READ4_1_4_4  0xec
+
+/* S25FLxxxS commands */
+#define S25FL_CMD_WRITE4_1_1_4 0x34
+#define S25FL_CMD_SE4          0xdc
+#define S25FL_CMD_CLSR         0x30
+#define S25FL_CMD_DYBWR                0xe1
+#define S25FL_CMD_DYBRD                0xe0
+#define S25FL_CMD_WRITE4       0x12    /* Note, opcode clashes with
+                                       * 'FLASH_CMD_WRITE_1_4_4'
+                                       * as found on N25Qxxx devices! */
+
+/* Status register */
+#define FLASH_STATUS_BUSY      0x01
+#define FLASH_STATUS_WEL       0x02
+#define FLASH_STATUS_BP0       0x04
+#define FLASH_STATUS_BP1       0x08
+#define FLASH_STATUS_BP2       0x10
+#define FLASH_STATUS_SRWP0     0x80
+#define FLASH_STATUS_TIMEOUT   0xff
+/* S25FL Error Flags */
+#define S25FL_STATUS_E_ERR     0x20
+#define S25FL_STATUS_P_ERR     0x40
+
+#define FLASH_PAGESIZE         256                     /* In Bytes    */
+#define FLASH_PAGESIZE_32      (FLASH_PAGESIZE / 4)    /* In uint32_t */
+#define FLASH_MAX_BUSY_WAIT    (300 * HZ)      /* Maximum 'CHIPERASE' time */
+
+/*
+ * Flags to tweak operation of default read/write/erase routines
+ */
+#define CFG_READ_TOGGLE_32BIT_ADDR     0x00000001
+#define CFG_WRITE_TOGGLE_32BIT_ADDR    0x00000002
+#define CFG_WRITE_EX_32BIT_ADDR_DELAY  0x00000004
+#define CFG_ERASESEC_TOGGLE_32BIT_ADDR 0x00000008
+#define CFG_S25FL_CHECK_ERROR_FLAGS    0x00000010
+
+struct stfsm_seq {
+       uint32_t data_size;
+       uint32_t addr1;
+       uint32_t addr2;
+       uint32_t addr_cfg;
+       uint32_t seq_opc[5];
+       uint32_t mode;
+       uint32_t dummy;
+       uint32_t status;
+       uint8_t  seq[16];
+       uint32_t seq_cfg;
+} __packed __aligned(4);
+
+struct stfsm {
+       struct device           *dev;
+       void __iomem            *base;
+       struct resource         *region;
+       struct mtd_info         mtd;
+       struct mutex            lock;
+       struct flash_info       *info;
+
+       uint32_t                configuration;
+       uint32_t                fifo_dir_delay;
+       bool                    booted_from_spi;
+       bool                    reset_signal;
+       bool                    reset_por;
+
+       struct stfsm_seq stfsm_seq_read;
+       struct stfsm_seq stfsm_seq_write;
+       struct stfsm_seq stfsm_seq_en_32bit_addr;
+};
+
+/* Parameters to configure a READ or WRITE FSM sequence */
+struct seq_rw_config {
+       uint32_t        flags;          /* flags to support config */
+       uint8_t         cmd;            /* FLASH command */
+       int             write;          /* Write Sequence */
+       uint8_t         addr_pads;      /* No. of addr pads (MODE & DUMMY) */
+       uint8_t         data_pads;      /* No. of data pads */
+       uint8_t         mode_data;      /* MODE data */
+       uint8_t         mode_cycles;    /* No. of MODE cycles */
+       uint8_t         dummy_cycles;   /* No. of DUMMY cycles */
+};
+
+/* SPI Flash Device Table */
+struct flash_info {
+       char            *name;
+       /*
+        * JEDEC id zero means "no ID" (most older chips); otherwise it has
+        * a high byte of zero plus three data bytes: the manufacturer id,
+        * then a two byte device id.
+        */
+       u32             jedec_id;
+       u16             ext_id;
+       /*
+        * The size listed here is what works with FLASH_CMD_SE, which isn't
+        * necessarily called a "sector" by the vendor.
+        */
+       unsigned        sector_size;
+       u16             n_sectors;
+       u32             flags;
+       /*
+        * Note, where FAST_READ is supported, freq_max specifies the
+        * FAST_READ frequency, not the READ frequency.
+        */
+       u32             max_freq;
+       int             (*config)(struct stfsm *);
+};
+
+static int stfsm_n25q_config(struct stfsm *fsm);
+static int stfsm_mx25_config(struct stfsm *fsm);
+static int stfsm_s25fl_config(struct stfsm *fsm);
+static int stfsm_w25q_config(struct stfsm *fsm);
+
+static struct flash_info flash_types[] = {
+       /*
+        * ST Microelectronics/Numonyx --
+        * (newer production versions may have feature updates
+        * (eg faster operating frequency)
+        */
+#define M25P_FLAG (FLASH_FLAG_READ_WRITE | FLASH_FLAG_READ_FAST)
+       { "m25p40",  0x202013, 0,  64 * 1024,   8, M25P_FLAG, 25, NULL },
+       { "m25p80",  0x202014, 0,  64 * 1024,  16, M25P_FLAG, 25, NULL },
+       { "m25p16",  0x202015, 0,  64 * 1024,  32, M25P_FLAG, 25, NULL },
+       { "m25p32",  0x202016, 0,  64 * 1024,  64, M25P_FLAG, 50, NULL },
+       { "m25p64",  0x202017, 0,  64 * 1024, 128, M25P_FLAG, 50, NULL },
+       { "m25p128", 0x202018, 0, 256 * 1024,  64, M25P_FLAG, 50, NULL },
+
+#define M25PX_FLAG (FLASH_FLAG_READ_WRITE      |       \
+                   FLASH_FLAG_READ_FAST        |       \
+                   FLASH_FLAG_READ_1_1_2       |       \
+                   FLASH_FLAG_WRITE_1_1_2)
+       { "m25px32", 0x207116, 0,  64 * 1024,  64, M25PX_FLAG, 75, NULL },
+       { "m25px64", 0x207117, 0,  64 * 1024, 128, M25PX_FLAG, 75, NULL },
+
+#define MX25_FLAG (FLASH_FLAG_READ_WRITE       |       \
+                  FLASH_FLAG_READ_FAST         |       \
+                  FLASH_FLAG_READ_1_1_2        |       \
+                  FLASH_FLAG_READ_1_2_2        |       \
+                  FLASH_FLAG_READ_1_1_4        |       \
+                  FLASH_FLAG_READ_1_4_4        |       \
+                  FLASH_FLAG_SE_4K             |       \
+                  FLASH_FLAG_SE_32K)
+       { "mx25l25635e", 0xc22019, 0, 64*1024, 512,
+         (MX25_FLAG | FLASH_FLAG_32BIT_ADDR | FLASH_FLAG_RESET), 70,
+         stfsm_mx25_config },
+
+#define N25Q_FLAG (FLASH_FLAG_READ_WRITE       |       \
+                  FLASH_FLAG_READ_FAST         |       \
+                  FLASH_FLAG_READ_1_1_2        |       \
+                  FLASH_FLAG_READ_1_2_2        |       \
+                  FLASH_FLAG_READ_1_1_4        |       \
+                  FLASH_FLAG_READ_1_4_4        |       \
+                  FLASH_FLAG_WRITE_1_1_2       |       \
+                  FLASH_FLAG_WRITE_1_2_2       |       \
+                  FLASH_FLAG_WRITE_1_1_4       |       \
+                  FLASH_FLAG_WRITE_1_4_4)
+       { "n25q128", 0x20ba18, 0, 64 * 1024,  256, N25Q_FLAG, 108,
+         stfsm_n25q_config },
+       { "n25q256", 0x20ba19, 0, 64 * 1024,  512,
+         N25Q_FLAG | FLASH_FLAG_32BIT_ADDR, 108, stfsm_n25q_config },
+
+       /*
+        * Spansion S25FLxxxP
+        *     - 256KiB and 64KiB sector variants (identified by ext. JEDEC)
+        */
+#define S25FLXXXP_FLAG (FLASH_FLAG_READ_WRITE  |       \
+                       FLASH_FLAG_READ_1_1_2   |       \
+                       FLASH_FLAG_READ_1_2_2   |       \
+                       FLASH_FLAG_READ_1_1_4   |       \
+                       FLASH_FLAG_READ_1_4_4   |       \
+                       FLASH_FLAG_WRITE_1_1_4  |       \
+                       FLASH_FLAG_READ_FAST)
+       { "s25fl129p0", 0x012018, 0x4d00, 256 * 1024,  64, S25FLXXXP_FLAG, 80,
+         stfsm_s25fl_config },
+       { "s25fl129p1", 0x012018, 0x4d01,  64 * 1024, 256, S25FLXXXP_FLAG, 80,
+         stfsm_s25fl_config },
+
+       /*
+        * Spansion S25FLxxxS
+        *     - 256KiB and 64KiB sector variants (identified by ext. JEDEC)
+        *     - RESET# signal supported by die but not bristled out on all
+        *       package types.  The package type is a function of board design,
+        *       so this information is captured in the board's flags.
+        *     - Supports 'DYB' sector protection. Depending on variant, sectors
+        *       may default to locked state on power-on.
+        */
+#define S25FLXXXS_FLAG (S25FLXXXP_FLAG         |       \
+                       FLASH_FLAG_RESET        |       \
+                       FLASH_FLAG_DYB_LOCKING)
+       { "s25fl128s0", 0x012018, 0x0300,  256 * 1024, 64, S25FLXXXS_FLAG, 80,
+         stfsm_s25fl_config },
+       { "s25fl128s1", 0x012018, 0x0301,  64 * 1024, 256, S25FLXXXS_FLAG, 80,
+         stfsm_s25fl_config },
+       { "s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128,
+         S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, stfsm_s25fl_config },
+       { "s25fl256s1", 0x010219, 0x4d01,  64 * 1024, 512,
+         S25FLXXXS_FLAG | FLASH_FLAG_32BIT_ADDR, 80, stfsm_s25fl_config },
+
+       /* Winbond -- w25x "blocks" are 64K, "sectors" are 4KiB */
+#define W25X_FLAG (FLASH_FLAG_READ_WRITE       |       \
+                  FLASH_FLAG_READ_FAST         |       \
+                  FLASH_FLAG_READ_1_1_2        |       \
+                  FLASH_FLAG_WRITE_1_1_2)
+       { "w25x40",  0xef3013, 0,  64 * 1024,   8, W25X_FLAG, 75, NULL },
+       { "w25x80",  0xef3014, 0,  64 * 1024,  16, W25X_FLAG, 75, NULL },
+       { "w25x16",  0xef3015, 0,  64 * 1024,  32, W25X_FLAG, 75, NULL },
+       { "w25x32",  0xef3016, 0,  64 * 1024,  64, W25X_FLAG, 75, NULL },
+       { "w25x64",  0xef3017, 0,  64 * 1024, 128, W25X_FLAG, 75, NULL },
+
+       /* Winbond -- w25q "blocks" are 64K, "sectors" are 4KiB */
+#define W25Q_FLAG (FLASH_FLAG_READ_WRITE       |       \
+                  FLASH_FLAG_READ_FAST         |       \
+                  FLASH_FLAG_READ_1_1_2        |       \
+                  FLASH_FLAG_READ_1_2_2        |       \
+                  FLASH_FLAG_READ_1_1_4        |       \
+                  FLASH_FLAG_READ_1_4_4        |       \
+                  FLASH_FLAG_WRITE_1_1_4)
+       { "w25q80",  0xef4014, 0,  64 * 1024,  16, W25Q_FLAG, 80,
+         stfsm_w25q_config },
+       { "w25q16",  0xef4015, 0,  64 * 1024,  32, W25Q_FLAG, 80,
+         stfsm_w25q_config },
+       { "w25q32",  0xef4016, 0,  64 * 1024,  64, W25Q_FLAG, 80,
+         stfsm_w25q_config },
+       { "w25q64",  0xef4017, 0,  64 * 1024, 128, W25Q_FLAG, 80,
+         stfsm_w25q_config },
+
+       /* Sentinel */
+       { NULL, 0x000000, 0, 0, 0, 0, 0, NULL },
+};
+
+/*
+ * FSM message sequence configurations:
+ *
+ * All configs are presented in order of preference
+ */
+
+/* Default READ configurations, in order of preference */
+static struct seq_rw_config default_read_configs[] = {
+       {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ_1_4_4,   0, 4, 4, 0x00, 2, 4},
+       {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ_1_1_4,   0, 1, 4, 0x00, 4, 0},
+       {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ_1_2_2,   0, 2, 2, 0x00, 4, 0},
+       {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ_1_1_2,   0, 1, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_FAST,  FLASH_CMD_READ_FAST,    0, 1, 1, 0x00, 0, 8},
+       {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ,         0, 1, 1, 0x00, 0, 0},
+       {0x00,                  0,                      0, 0, 0, 0x00, 0, 0},
+};
+
+/* Default WRITE configurations */
+static struct seq_rw_config default_write_configs[] = {
+       {FLASH_FLAG_WRITE_1_4_4, FLASH_CMD_WRITE_1_4_4, 1, 4, 4, 0x00, 0, 0},
+       {FLASH_FLAG_WRITE_1_1_4, FLASH_CMD_WRITE_1_1_4, 1, 1, 4, 0x00, 0, 0},
+       {FLASH_FLAG_WRITE_1_2_2, FLASH_CMD_WRITE_1_2_2, 1, 2, 2, 0x00, 0, 0},
+       {FLASH_FLAG_WRITE_1_1_2, FLASH_CMD_WRITE_1_1_2, 1, 1, 2, 0x00, 0, 0},
+       {FLASH_FLAG_READ_WRITE,  FLASH_CMD_WRITE,       1, 1, 1, 0x00, 0, 0},
+       {0x00,                   0,                     0, 0, 0, 0x00, 0, 0},
+};
+
+/*
+ * [N25Qxxx] Configuration
+ */
+#define N25Q_VCR_DUMMY_CYCLES(x)       (((x) & 0xf) << 4)
+#define N25Q_VCR_XIP_DISABLED          ((uint8_t)0x1 << 3)
+#define N25Q_VCR_WRAP_CONT             0x3
+
+/* N25Q 3-byte Address READ configurations
+ *     - 'FAST' variants configured for 8 dummy cycles.
+ *
+ * Note, the number of dummy cycles used for 'FAST' READ operations is
+ * configurable and would normally be tuned according to the READ command and
+ * operating frequency.  However, this applies universally to all 'FAST' READ
+ * commands, including those used by the SPIBoot controller, and remains in
+ * force until the device is power-cycled.  Since the SPIBoot controller is
+ * hard-wired to use 8 dummy cycles, we must configure the device to also use 8
+ * cycles.
+ */
+static struct seq_rw_config n25q_read3_configs[] = {
+       {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ_1_4_4,   0, 4, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ_1_1_4,   0, 1, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ_1_2_2,   0, 2, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ_1_1_2,   0, 1, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_FAST,  FLASH_CMD_READ_FAST,    0, 1, 1, 0x00, 0, 8},
+       {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ,         0, 1, 1, 0x00, 0, 0},
+       {0x00,                  0,                      0, 0, 0, 0x00, 0, 0},
+};
+
+/* N25Q 4-byte Address READ configurations
+ *     - use special 4-byte address READ commands (reduces overheads, and
+ *        reduces risk of hitting watchdog reset issues).
+ *     - 'FAST' variants configured for 8 dummy cycles (see note above.)
+ */
+static struct seq_rw_config n25q_read4_configs[] = {
+       {FLASH_FLAG_READ_1_4_4, FLASH_CMD_READ4_1_4_4,  0, 4, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_1_4, FLASH_CMD_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_2_2, FLASH_CMD_READ4_1_2_2,  0, 2, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_1_2, FLASH_CMD_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_FAST,  FLASH_CMD_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
+       {FLASH_FLAG_READ_WRITE, FLASH_CMD_READ4,        0, 1, 1, 0x00, 0, 0},
+       {0x00,                  0,                      0, 0, 0, 0x00, 0, 0},
+};
+
+/*
+ * [MX25xxx] Configuration
+ */
+#define MX25_STATUS_QE                 (0x1 << 6)
+
+static int stfsm_mx25_en_32bit_addr_seq(struct stfsm_seq *seq)
+{
+       seq->seq_opc[0] = (SEQ_OPC_PADS_1 |
+                          SEQ_OPC_CYCLES(8) |
+                          SEQ_OPC_OPCODE(FLASH_CMD_EN4B_ADDR) |
+                          SEQ_OPC_CSDEASSERT);
+
+       seq->seq[0] = STFSM_INST_CMD1;
+       seq->seq[1] = STFSM_INST_WAIT;
+       seq->seq[2] = STFSM_INST_STOP;
+
+       seq->seq_cfg = (SEQ_CFG_PADS_1 |
+                       SEQ_CFG_ERASE |
+                       SEQ_CFG_READNOTWRITE |
+                       SEQ_CFG_CSDEASSERT |
+                       SEQ_CFG_STARTSEQ);
+
+       return 0;
+}
+
+/*
+ * [S25FLxxx] Configuration
+ */
+#define STFSM_S25FL_CONFIG_QE          (0x1 << 1)
+
+/*
+ * S25FLxxxS devices provide three ways of supporting 32-bit addressing: Bank
+ * Register, Extended Address Modes, and a 32-bit address command set.  The
+ * 32-bit address command set is used here, since it avoids any problems with
+ * entering a state that is incompatible with the SPIBoot Controller.
+ */
+static struct seq_rw_config stfsm_s25fl_read4_configs[] = {
+       {FLASH_FLAG_READ_1_4_4,  FLASH_CMD_READ4_1_4_4,  0, 4, 4, 0x00, 2, 4},
+       {FLASH_FLAG_READ_1_1_4,  FLASH_CMD_READ4_1_1_4,  0, 1, 4, 0x00, 0, 8},
+       {FLASH_FLAG_READ_1_2_2,  FLASH_CMD_READ4_1_2_2,  0, 2, 2, 0x00, 4, 0},
+       {FLASH_FLAG_READ_1_1_2,  FLASH_CMD_READ4_1_1_2,  0, 1, 2, 0x00, 0, 8},
+       {FLASH_FLAG_READ_FAST,   FLASH_CMD_READ4_FAST,   0, 1, 1, 0x00, 0, 8},
+       {FLASH_FLAG_READ_WRITE,  FLASH_CMD_READ4,        0, 1, 1, 0x00, 0, 0},
+       {0x00,                   0,                      0, 0, 0, 0x00, 0, 0},
+};
+
+static struct seq_rw_config stfsm_s25fl_write4_configs[] = {
+       {FLASH_FLAG_WRITE_1_1_4, S25FL_CMD_WRITE4_1_1_4, 1, 1, 4, 0x00, 0, 0},
+       {FLASH_FLAG_READ_WRITE,  S25FL_CMD_WRITE4,       1, 1, 1, 0x00, 0, 0},
+       {0x00,                   0,                      0, 0, 0, 0x00, 0, 0},
+};
+
+/*
+ * [W25Qxxx] Configuration
+ */
+#define W25Q_STATUS_QE                 (0x1 << 9)
+
+static struct stfsm_seq stfsm_seq_read_jedec = {
+       .data_size = TRANSFER_SIZE(8),
+       .seq_opc[0] = (SEQ_OPC_PADS_1 |
+                      SEQ_OPC_CYCLES(8) |
+                      SEQ_OPC_OPCODE(FLASH_CMD_RDID)),
+       .seq = {
+               STFSM_INST_CMD1,
+               STFSM_INST_DATA_READ,
+               STFSM_INST_STOP,
+       },
+       .seq_cfg = (SEQ_CFG_PADS_1 |
+                   SEQ_CFG_READNOTWRITE |
+                   SEQ_CFG_CSDEASSERT |
+                   SEQ_CFG_STARTSEQ),
+};
+
+static struct stfsm_seq stfsm_seq_read_status_fifo = {
+       .data_size = TRANSFER_SIZE(4),
+       .seq_opc[0] = (SEQ_OPC_PADS_1 |
+                      SEQ_OPC_CYCLES(8) |
+                      SEQ_OPC_OPCODE(FLASH_CMD_RDSR)),
+       .seq = {
+               STFSM_INST_CMD1,
+               STFSM_INST_DATA_READ,
+               STFSM_INST_STOP,
+       },
+       .seq_cfg = (SEQ_CFG_PADS_1 |
+                   SEQ_CFG_READNOTWRITE |
+                   SEQ_CFG_CSDEASSERT |
+                   SEQ_CFG_STARTSEQ),
+};
+
+static struct stfsm_seq stfsm_seq_erase_sector = {
+       /* 'addr_cfg' configured during initialisation */
+       .seq_opc = {
+               (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT),
+
+               (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                SEQ_OPC_OPCODE(FLASH_CMD_SE)),
+       },
+       .seq = {
+               STFSM_INST_CMD1,
+               STFSM_INST_CMD2,
+               STFSM_INST_ADD1,
+               STFSM_INST_ADD2,
+               STFSM_INST_STOP,
+       },
+       .seq_cfg = (SEQ_CFG_PADS_1 |
+                   SEQ_CFG_READNOTWRITE |
+                   SEQ_CFG_CSDEASSERT |
+                   SEQ_CFG_STARTSEQ),
+};
+
+static struct stfsm_seq stfsm_seq_erase_chip = {
+       .seq_opc = {
+               (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT),
+
+               (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                SEQ_OPC_OPCODE(FLASH_CMD_CHIPERASE) | SEQ_OPC_CSDEASSERT),
+       },
+       .seq = {
+               STFSM_INST_CMD1,
+               STFSM_INST_CMD2,
+               STFSM_INST_WAIT,
+               STFSM_INST_STOP,
+       },
+       .seq_cfg = (SEQ_CFG_PADS_1 |
+                   SEQ_CFG_ERASE |
+                   SEQ_CFG_READNOTWRITE |
+                   SEQ_CFG_CSDEASSERT |
+                   SEQ_CFG_STARTSEQ),
+};
+
+static struct stfsm_seq stfsm_seq_write_status = {
+       .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                      SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT),
+       .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                      SEQ_OPC_OPCODE(FLASH_CMD_WRSR)),
+       .seq = {
+               STFSM_INST_CMD1,
+               STFSM_INST_CMD2,
+               STFSM_INST_STA_WR1,
+               STFSM_INST_STOP,
+       },
+       .seq_cfg = (SEQ_CFG_PADS_1 |
+                   SEQ_CFG_READNOTWRITE |
+                   SEQ_CFG_CSDEASSERT |
+                   SEQ_CFG_STARTSEQ),
+};
+
+static struct stfsm_seq stfsm_seq_wrvcr = {
+       .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                      SEQ_OPC_OPCODE(FLASH_CMD_WREN) | SEQ_OPC_CSDEASSERT),
+       .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                      SEQ_OPC_OPCODE(FLASH_CMD_WRVCR)),
+       .seq = {
+               STFSM_INST_CMD1,
+               STFSM_INST_CMD2,
+               STFSM_INST_STA_WR1,
+               STFSM_INST_STOP,
+       },
+       .seq_cfg = (SEQ_CFG_PADS_1 |
+                   SEQ_CFG_READNOTWRITE |
+                   SEQ_CFG_CSDEASSERT |
+                   SEQ_CFG_STARTSEQ),
+};
+
+static int stfsm_n25q_en_32bit_addr_seq(struct stfsm_seq *seq)
+{
+       seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                          SEQ_OPC_OPCODE(FLASH_CMD_EN4B_ADDR));
+       seq->seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                          SEQ_OPC_OPCODE(FLASH_CMD_WREN) |
+                          SEQ_OPC_CSDEASSERT);
+
+       seq->seq[0] = STFSM_INST_CMD2;
+       seq->seq[1] = STFSM_INST_CMD1;
+       seq->seq[2] = STFSM_INST_WAIT;
+       seq->seq[3] = STFSM_INST_STOP;
+
+       seq->seq_cfg = (SEQ_CFG_PADS_1 |
+                       SEQ_CFG_ERASE |
+                       SEQ_CFG_READNOTWRITE |
+                       SEQ_CFG_CSDEASSERT |
+                       SEQ_CFG_STARTSEQ);
+
+       return 0;
+}
+
+static inline int stfsm_is_idle(struct stfsm *fsm)
+{
+       return readl(fsm->base + SPI_FAST_SEQ_STA) & 0x10;
+}
+
+static inline uint32_t stfsm_fifo_available(struct stfsm *fsm)
+{
+       return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f;
+}
+
+static void stfsm_clear_fifo(struct stfsm *fsm)
+{
+       uint32_t avail;
+
+       for (;;) {
+               avail = stfsm_fifo_available(fsm);
+               if (!avail)
+                       break;
+
+               while (avail) {
+                       readl(fsm->base + SPI_FAST_SEQ_DATA_REG);
+                       avail--;
+               }
+       }
+}
+
+static inline void stfsm_load_seq(struct stfsm *fsm,
+                                 const struct stfsm_seq *seq)
+{
+       void __iomem *dst = fsm->base + SPI_FAST_SEQ_TRANSFER_SIZE;
+       const uint32_t *src = (const uint32_t *)seq;
+       int words = sizeof(*seq) / sizeof(*src);
+
+       BUG_ON(!stfsm_is_idle(fsm));
+
+       while (words--) {
+               writel(*src, dst);
+               src++;
+               dst += 4;
+       }
+}
+
+static void stfsm_wait_seq(struct stfsm *fsm)
+{
+       unsigned long deadline;
+       int timeout = 0;
+
+       deadline = jiffies + msecs_to_jiffies(STFSM_MAX_WAIT_SEQ_MS);
+
+       while (!timeout) {
+               if (time_after_eq(jiffies, deadline))
+                       timeout = 1;
+
+               if (stfsm_is_idle(fsm))
+                       return;
+
+               cond_resched();
+       }
+
+       dev_err(fsm->dev, "timeout on sequence completion\n");
+}
+
+static void stfsm_read_fifo(struct stfsm *fsm, uint32_t *buf, uint32_t size)
+{
+       uint32_t remaining = size >> 2;
+       uint32_t avail;
+       uint32_t words;
+
+       dev_dbg(fsm->dev, "Reading %d bytes from FIFO\n", size);
+
+       BUG_ON((((uint32_t)buf) & 0x3) || (size & 0x3));
+
+       while (remaining) {
+               for (;;) {
+                       avail = stfsm_fifo_available(fsm);
+                       if (avail)
+                               break;
+                       udelay(1);
+               }
+               words = min(avail, remaining);
+               remaining -= words;
+
+               readsl(fsm->base + SPI_FAST_SEQ_DATA_REG, buf, words);
+               buf += words;
+       }
+}
+
+static int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf,
+                           uint32_t size)
+{
+       uint32_t words = size >> 2;
+
+       dev_dbg(fsm->dev, "writing %d bytes to FIFO\n", size);
+
+       BUG_ON((((uint32_t)buf) & 0x3) || (size & 0x3));
+
+       writesl(fsm->base + SPI_FAST_SEQ_DATA_REG, buf, words);
+
+       return size;
+}
+
+static int stfsm_enter_32bit_addr(struct stfsm *fsm, int enter)
+{
+       struct stfsm_seq *seq = &fsm->stfsm_seq_en_32bit_addr;
+       uint32_t cmd = enter ? FLASH_CMD_EN4B_ADDR : FLASH_CMD_EX4B_ADDR;
+
+       seq->seq_opc[0] = (SEQ_OPC_PADS_1 |
+                          SEQ_OPC_CYCLES(8) |
+                          SEQ_OPC_OPCODE(cmd) |
+                          SEQ_OPC_CSDEASSERT);
+
+       stfsm_load_seq(fsm, seq);
+
+       stfsm_wait_seq(fsm);
+
+       return 0;
+}
+
+static uint8_t stfsm_wait_busy(struct stfsm *fsm)
+{
+       struct stfsm_seq *seq = &stfsm_seq_read_status_fifo;
+       unsigned long deadline;
+       uint32_t status;
+       int timeout = 0;
+
+       /* Use RDRS1 */
+       seq->seq_opc[0] = (SEQ_OPC_PADS_1 |
+                          SEQ_OPC_CYCLES(8) |
+                          SEQ_OPC_OPCODE(FLASH_CMD_RDSR));
+
+       /* Load read_status sequence */
+       stfsm_load_seq(fsm, seq);
+
+       /*
+        * Repeat until busy bit is deasserted, or timeout, or error (S25FLxxxS)
+        */
+       deadline = jiffies + FLASH_MAX_BUSY_WAIT;
+       while (!timeout) {
+               if (time_after_eq(jiffies, deadline))
+                       timeout = 1;
+
+               stfsm_wait_seq(fsm);
+
+               stfsm_read_fifo(fsm, &status, 4);
+
+               if ((status & FLASH_STATUS_BUSY) == 0)
+                       return 0;
+
+               if ((fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS) &&
+                   ((status & S25FL_STATUS_P_ERR) ||
+                    (status & S25FL_STATUS_E_ERR)))
+                       return (uint8_t)(status & 0xff);
+
+               if (!timeout)
+                       /* Restart */
+                       writel(seq->seq_cfg, fsm->base + SPI_FAST_SEQ_CFG);
+
+               cond_resched();
+       }
+
+       dev_err(fsm->dev, "timeout on wait_busy\n");
+
+       return FLASH_STATUS_TIMEOUT;
+}
+
+static int stfsm_read_status(struct stfsm *fsm, uint8_t cmd,
+                          uint8_t *status)
+{
+       struct stfsm_seq *seq = &stfsm_seq_read_status_fifo;
+       uint32_t tmp;
+
+       dev_dbg(fsm->dev, "reading STA[%s]\n",
+               (cmd == FLASH_CMD_RDSR) ? "1" : "2");
+
+       seq->seq_opc[0] = (SEQ_OPC_PADS_1 |
+                          SEQ_OPC_CYCLES(8) |
+                          SEQ_OPC_OPCODE(cmd)),
+
+       stfsm_load_seq(fsm, seq);
+
+       stfsm_read_fifo(fsm, &tmp, 4);
+
+       *status = (uint8_t)(tmp >> 24);
+
+       stfsm_wait_seq(fsm);
+
+       return 0;
+}
+
+static int stfsm_write_status(struct stfsm *fsm, uint16_t status,
+                              int sta_bytes)
+{
+       struct stfsm_seq *seq = &stfsm_seq_write_status;
+
+       dev_dbg(fsm->dev, "writing STA[%s] 0x%04x\n",
+               (sta_bytes == 1) ? "1" : "1+2", status);
+
+       seq->status = (uint32_t)status | STA_PADS_1 | STA_CSDEASSERT;
+       seq->seq[2] = (sta_bytes == 1) ?
+               STFSM_INST_STA_WR1 : STFSM_INST_STA_WR1_2;
+
+       stfsm_load_seq(fsm, seq);
+
+       stfsm_wait_seq(fsm);
+
+       return 0;
+};
+
+static int stfsm_wrvcr(struct stfsm *fsm, uint8_t data)
+{
+       struct stfsm_seq *seq = &stfsm_seq_wrvcr;
+
+       dev_dbg(fsm->dev, "writing VCR 0x%02x\n", data);
+
+       seq->status = (STA_DATA_BYTE1(data) | STA_PADS_1 | STA_CSDEASSERT);
+
+       stfsm_load_seq(fsm, seq);
+
+       stfsm_wait_seq(fsm);
+
+       return 0;
+}
+
+/*
+ * SoC reset on 'boot-from-spi' systems
+ *
+ * Certain modes of operation cause the Flash device to enter a particular state
+ * for a period of time (e.g. 'Erase Sector', 'Quad Enable', and 'Enter 32-bit
+ * Addr' commands).  On boot-from-spi systems, it is important to consider what
+ * happens if a warm reset occurs during this period.  The SPIBoot controller
+ * assumes that Flash device is in its default reset state, 24-bit address mode,
+ * and ready to accept commands.  This can be achieved using some form of
+ * on-board logic/controller to force a device POR in response to a SoC-level
+ * reset or by making use of the device reset signal if available (limited
+ * number of devices only).
+ *
+ * Failure to take such precautions can cause problems following a warm reset.
+ * For some operations (e.g. ERASE), there is little that can be done.  For
+ * other modes of operation (e.g. 32-bit addressing), options are often
+ * available that can help minimise the window in which a reset could cause a
+ * problem.
+ *
+ */
+static bool stfsm_can_handle_soc_reset(struct stfsm *fsm)
+{
+       /* Reset signal is available on the board and supported by the device */
+       if (fsm->reset_signal && fsm->info->flags & FLASH_FLAG_RESET)
+               return true;
+
+       /* Board-level logic forces a power-on-reset */
+       if (fsm->reset_por)
+               return true;
+
+       /* Reset is not properly handled and may result in failure to reboot */
+       return false;
+}
+
+/* Configure 'addr_cfg' according to addressing mode */
+static void stfsm_prepare_erasesec_seq(struct stfsm *fsm,
+                                      struct stfsm_seq *seq)
+{
+       int addr1_cycles = fsm->info->flags & FLASH_FLAG_32BIT_ADDR ? 16 : 8;
+
+       seq->addr_cfg = (ADR_CFG_CYCLES_ADD1(addr1_cycles) |
+                        ADR_CFG_PADS_1_ADD1 |
+                        ADR_CFG_CYCLES_ADD2(16) |
+                        ADR_CFG_PADS_1_ADD2 |
+                        ADR_CFG_CSDEASSERT_ADD2);
+}
+
+/* Search for preferred configuration based on available flags */
+static struct seq_rw_config *
+stfsm_search_seq_rw_configs(struct stfsm *fsm,
+                           struct seq_rw_config cfgs[])
+{
+       struct seq_rw_config *config;
+       int flags = fsm->info->flags;
+
+       for (config = cfgs; config->cmd != 0; config++)
+               if ((config->flags & flags) == config->flags)
+                       return config;
+
+       return NULL;
+}
+
+/* Prepare a READ/WRITE sequence according to configuration parameters */
+static void stfsm_prepare_rw_seq(struct stfsm *fsm,
+                                struct stfsm_seq *seq,
+                                struct seq_rw_config *cfg)
+{
+       int addr1_cycles, addr2_cycles;
+       int i = 0;
+
+       memset(seq, 0, sizeof(*seq));
+
+       /* Add READ/WRITE OPC  */
+       seq->seq_opc[i++] = (SEQ_OPC_PADS_1 |
+                            SEQ_OPC_CYCLES(8) |
+                            SEQ_OPC_OPCODE(cfg->cmd));
+
+       /* Add WREN OPC for a WRITE sequence */
+       if (cfg->write)
+               seq->seq_opc[i++] = (SEQ_OPC_PADS_1 |
+                                    SEQ_OPC_CYCLES(8) |
+                                    SEQ_OPC_OPCODE(FLASH_CMD_WREN) |
+                                    SEQ_OPC_CSDEASSERT);
+
+       /* Address configuration (24 or 32-bit addresses) */
+       addr1_cycles  = (fsm->info->flags & FLASH_FLAG_32BIT_ADDR) ? 16 : 8;
+       addr1_cycles /= cfg->addr_pads;
+       addr2_cycles  = 16 / cfg->addr_pads;
+       seq->addr_cfg = ((addr1_cycles & 0x3f) << 0 |   /* ADD1 cycles */
+                        (cfg->addr_pads - 1) << 6 |    /* ADD1 pads */
+                        (addr2_cycles & 0x3f) << 16 |  /* ADD2 cycles */
+                        ((cfg->addr_pads - 1) << 22)); /* ADD2 pads */
+
+       /* Data/Sequence configuration */
+       seq->seq_cfg = ((cfg->data_pads - 1) << 16 |
+                       SEQ_CFG_STARTSEQ |
+                       SEQ_CFG_CSDEASSERT);
+       if (!cfg->write)
+               seq->seq_cfg |= SEQ_CFG_READNOTWRITE;
+
+       /* Mode configuration (no. of pads taken from addr cfg) */
+       seq->mode = ((cfg->mode_data & 0xff) << 0 |     /* data */
+                    (cfg->mode_cycles & 0x3f) << 16 |  /* cycles */
+                    (cfg->addr_pads - 1) << 22);       /* pads */
+
+       /* Dummy configuration (no. of pads taken from addr cfg) */
+       seq->dummy = ((cfg->dummy_cycles & 0x3f) << 16 |        /* cycles */
+                     (cfg->addr_pads - 1) << 22);              /* pads */
+
+
+       /* Instruction sequence */
+       i = 0;
+       if (cfg->write)
+               seq->seq[i++] = STFSM_INST_CMD2;
+
+       seq->seq[i++] = STFSM_INST_CMD1;
+
+       seq->seq[i++] = STFSM_INST_ADD1;
+       seq->seq[i++] = STFSM_INST_ADD2;
+
+       if (cfg->mode_cycles)
+               seq->seq[i++] = STFSM_INST_MODE;
+
+       if (cfg->dummy_cycles)
+               seq->seq[i++] = STFSM_INST_DUMMY;
+
+       seq->seq[i++] =
+               cfg->write ? STFSM_INST_DATA_WRITE : STFSM_INST_DATA_READ;
+       seq->seq[i++] = STFSM_INST_STOP;
+}
+
+static int stfsm_search_prepare_rw_seq(struct stfsm *fsm,
+                                      struct stfsm_seq *seq,
+                                      struct seq_rw_config *cfgs)
+{
+       struct seq_rw_config *config;
+
+       config = stfsm_search_seq_rw_configs(fsm, cfgs);
+       if (!config) {
+               dev_err(fsm->dev, "failed to find suitable config\n");
+               return -EINVAL;
+       }
+
+       stfsm_prepare_rw_seq(fsm, seq, config);
+
+       return 0;
+}
+
+/* Prepare a READ/WRITE/ERASE 'default' sequences */
+static int stfsm_prepare_rwe_seqs_default(struct stfsm *fsm)
+{
+       uint32_t flags = fsm->info->flags;
+       int ret;
+
+       /* Configure 'READ' sequence */
+       ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read,
+                                         default_read_configs);
+       if (ret) {
+               dev_err(fsm->dev,
+                       "failed to prep READ sequence with flags [0x%08x]\n",
+                       flags);
+               return ret;
+       }
+
+       /* Configure 'WRITE' sequence */
+       ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_write,
+                                         default_write_configs);
+       if (ret) {
+               dev_err(fsm->dev,
+                       "failed to prep WRITE sequence with flags [0x%08x]\n",
+                       flags);
+               return ret;
+       }
+
+       /* Configure 'ERASE_SECTOR' sequence */
+       stfsm_prepare_erasesec_seq(fsm, &stfsm_seq_erase_sector);
+
+       return 0;
+}
+
+static int stfsm_mx25_config(struct stfsm *fsm)
+{
+       uint32_t flags = fsm->info->flags;
+       uint32_t data_pads;
+       uint8_t sta;
+       int ret;
+       bool soc_reset;
+
+       /*
+        * Use default READ/WRITE sequences
+        */
+       ret = stfsm_prepare_rwe_seqs_default(fsm);
+       if (ret)
+               return ret;
+
+       /*
+        * Configure 32-bit Address Support
+        */
+       if (flags & FLASH_FLAG_32BIT_ADDR) {
+               /* Configure 'enter_32bitaddr' FSM sequence */
+               stfsm_mx25_en_32bit_addr_seq(&fsm->stfsm_seq_en_32bit_addr);
+
+               soc_reset = stfsm_can_handle_soc_reset(fsm);
+               if (soc_reset || !fsm->booted_from_spi) {
+                       /* If we can handle SoC resets, we enable 32-bit address
+                        * mode pervasively */
+                       stfsm_enter_32bit_addr(fsm, 1);
+
+               } else {
+                       /* Else, enable/disable 32-bit addressing before/after
+                        * each operation */
+                       fsm->configuration = (CFG_READ_TOGGLE_32BIT_ADDR |
+                                             CFG_WRITE_TOGGLE_32BIT_ADDR |
+                                             CFG_ERASESEC_TOGGLE_32BIT_ADDR);
+                       /* It seems a small delay is required after exiting
+                        * 32-bit mode following a write operation.  The issue
+                        * is under investigation.
+                        */
+                       fsm->configuration |= CFG_WRITE_EX_32BIT_ADDR_DELAY;
+               }
+       }
+
+       /* For QUAD mode, set 'QE' STATUS bit */
+       data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
+       if (data_pads == 4) {
+               stfsm_read_status(fsm, FLASH_CMD_RDSR, &sta);
+               sta |= MX25_STATUS_QE;
+               stfsm_write_status(fsm, sta, 1);
+       }
+
+       return 0;
+}
+
+static int stfsm_n25q_config(struct stfsm *fsm)
+{
+       uint32_t flags = fsm->info->flags;
+       uint8_t vcr;
+       int ret = 0;
+       bool soc_reset;
+
+       /* Configure 'READ' sequence */
+       if (flags & FLASH_FLAG_32BIT_ADDR)
+               ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read,
+                                                 n25q_read4_configs);
+       else
+               ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read,
+                                                 n25q_read3_configs);
+       if (ret) {
+               dev_err(fsm->dev,
+                       "failed to prepare READ sequence with flags [0x%08x]\n",
+                       flags);
+               return ret;
+       }
+
+       /* Configure 'WRITE' sequence (default configs) */
+       ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_write,
+                                         default_write_configs);
+       if (ret) {
+               dev_err(fsm->dev,
+                       "preparing WRITE sequence using flags [0x%08x] failed\n",
+                       flags);
+               return ret;
+       }
+
+       /* * Configure 'ERASE_SECTOR' sequence */
+       stfsm_prepare_erasesec_seq(fsm, &stfsm_seq_erase_sector);
+
+       /* Configure 32-bit address support */
+       if (flags & FLASH_FLAG_32BIT_ADDR) {
+               stfsm_n25q_en_32bit_addr_seq(&fsm->stfsm_seq_en_32bit_addr);
+
+               soc_reset = stfsm_can_handle_soc_reset(fsm);
+               if (soc_reset || !fsm->booted_from_spi) {
+                       /*
+                        * If we can handle SoC resets, we enable 32-bit
+                        * address mode pervasively
+                        */
+                       stfsm_enter_32bit_addr(fsm, 1);
+               } else {
+                       /*
+                        * If not, enable/disable for WRITE and ERASE
+                        * operations (READ uses special commands)
+                        */
+                       fsm->configuration = (CFG_WRITE_TOGGLE_32BIT_ADDR |
+                                             CFG_ERASESEC_TOGGLE_32BIT_ADDR);
+               }
+       }
+
+       /*
+        * Configure device to use 8 dummy cycles
+        */
+       vcr = (N25Q_VCR_DUMMY_CYCLES(8) | N25Q_VCR_XIP_DISABLED |
+              N25Q_VCR_WRAP_CONT);
+       stfsm_wrvcr(fsm, vcr);
+
+       return 0;
+}
+
+static void stfsm_s25fl_prepare_erasesec_seq_32(struct stfsm_seq *seq)
+{
+       seq->seq_opc[1] = (SEQ_OPC_PADS_1 |
+                          SEQ_OPC_CYCLES(8) |
+                          SEQ_OPC_OPCODE(S25FL_CMD_SE4));
+
+       seq->addr_cfg = (ADR_CFG_CYCLES_ADD1(16) |
+                        ADR_CFG_PADS_1_ADD1 |
+                        ADR_CFG_CYCLES_ADD2(16) |
+                        ADR_CFG_PADS_1_ADD2 |
+                        ADR_CFG_CSDEASSERT_ADD2);
+}
+
+static void stfsm_s25fl_read_dyb(struct stfsm *fsm, uint32_t offs, uint8_t *dby)
+{
+       uint32_t tmp;
+       struct stfsm_seq seq = {
+               .data_size = TRANSFER_SIZE(4),
+               .seq_opc[0] = (SEQ_OPC_PADS_1 |
+                              SEQ_OPC_CYCLES(8) |
+                              SEQ_OPC_OPCODE(S25FL_CMD_DYBRD)),
+               .addr_cfg = (ADR_CFG_CYCLES_ADD1(16) |
+                            ADR_CFG_PADS_1_ADD1 |
+                            ADR_CFG_CYCLES_ADD2(16) |
+                            ADR_CFG_PADS_1_ADD2),
+               .addr1 = (offs >> 16) & 0xffff,
+               .addr2 = offs & 0xffff,
+               .seq = {
+                       STFSM_INST_CMD1,
+                       STFSM_INST_ADD1,
+                       STFSM_INST_ADD2,
+                       STFSM_INST_DATA_READ,
+                       STFSM_INST_STOP,
+               },
+               .seq_cfg = (SEQ_CFG_PADS_1 |
+                           SEQ_CFG_READNOTWRITE |
+                           SEQ_CFG_CSDEASSERT |
+                           SEQ_CFG_STARTSEQ),
+       };
+
+       stfsm_load_seq(fsm, &seq);
+
+       stfsm_read_fifo(fsm, &tmp, 4);
+
+       *dby = (uint8_t)(tmp >> 24);
+
+       stfsm_wait_seq(fsm);
+}
+
+static void stfsm_s25fl_write_dyb(struct stfsm *fsm, uint32_t offs, uint8_t dby)
+{
+       struct stfsm_seq seq = {
+               .seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                              SEQ_OPC_OPCODE(FLASH_CMD_WREN) |
+                              SEQ_OPC_CSDEASSERT),
+               .seq_opc[1] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
+                              SEQ_OPC_OPCODE(S25FL_CMD_DYBWR)),
+               .addr_cfg = (ADR_CFG_CYCLES_ADD1(16) |
+                            ADR_CFG_PADS_1_ADD1 |
+                            ADR_CFG_CYCLES_ADD2(16) |
+                            ADR_CFG_PADS_1_ADD2),
+               .status = (uint32_t)dby | STA_PADS_1 | STA_CSDEASSERT,
+               .addr1 = (offs >> 16) & 0xffff,
+               .addr2 = offs & 0xffff,
+               .seq = {
+                       STFSM_INST_CMD1,
+                       STFSM_INST_CMD2,
+                       STFSM_INST_ADD1,
+                       STFSM_INST_ADD2,
+                       STFSM_INST_STA_WR1,
+                       STFSM_INST_STOP,
+               },
+               .seq_cfg = (SEQ_CFG_PADS_1 |
+                           SEQ_CFG_READNOTWRITE |
+                           SEQ_CFG_CSDEASSERT |
+                           SEQ_CFG_STARTSEQ),
+       };
+
+       stfsm_load_seq(fsm, &seq);
+       stfsm_wait_seq(fsm);
+
+       stfsm_wait_busy(fsm);
+}
+
+static int stfsm_s25fl_clear_status_reg(struct stfsm *fsm)
+{
+       struct stfsm_seq seq = {
+               .seq_opc[0] = (SEQ_OPC_PADS_1 |
+                              SEQ_OPC_CYCLES(8) |
+                              SEQ_OPC_OPCODE(S25FL_CMD_CLSR) |
+                              SEQ_OPC_CSDEASSERT),
+               .seq_opc[1] = (SEQ_OPC_PADS_1 |
+                              SEQ_OPC_CYCLES(8) |
+                              SEQ_OPC_OPCODE(FLASH_CMD_WRDI) |
+                              SEQ_OPC_CSDEASSERT),
+               .seq = {
+                       STFSM_INST_CMD1,
+                       STFSM_INST_CMD2,
+                       STFSM_INST_WAIT,
+                       STFSM_INST_STOP,
+               },
+               .seq_cfg = (SEQ_CFG_PADS_1 |
+                           SEQ_CFG_ERASE |
+                           SEQ_CFG_READNOTWRITE |
+                           SEQ_CFG_CSDEASSERT |
+                           SEQ_CFG_STARTSEQ),
+       };
+
+       stfsm_load_seq(fsm, &seq);
+
+       stfsm_wait_seq(fsm);
+
+       return 0;
+}
+
+static int stfsm_s25fl_config(struct stfsm *fsm)
+{
+       struct flash_info *info = fsm->info;
+       uint32_t flags = info->flags;
+       uint32_t data_pads;
+       uint32_t offs;
+       uint16_t sta_wr;
+       uint8_t sr1, cr1, dyb;
+       int ret;
+
+       if (flags & FLASH_FLAG_32BIT_ADDR) {
+               /*
+                * Prepare Read/Write/Erase sequences according to S25FLxxx
+                * 32-bit address command set
+                */
+               ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_read,
+                                                 stfsm_s25fl_read4_configs);
+               if (ret)
+                       return ret;
+
+               ret = stfsm_search_prepare_rw_seq(fsm, &fsm->stfsm_seq_write,
+                                                 stfsm_s25fl_write4_configs);
+               if (ret)
+                       return ret;
+
+               stfsm_s25fl_prepare_erasesec_seq_32(&stfsm_seq_erase_sector);
+
+       } else {
+               /* Use default configurations for 24-bit addressing */
+               ret = stfsm_prepare_rwe_seqs_default(fsm);
+               if (ret)
+                       return ret;
+       }
+
+       /*
+        * For devices that support 'DYB' sector locking, check lock status and
+        * unlock sectors if necessary (some variants power-on with sectors
+        * locked by default)
+        */
+       if (flags & FLASH_FLAG_DYB_LOCKING) {
+               offs = 0;
+               for (offs = 0; offs < info->sector_size * info->n_sectors;) {
+                       stfsm_s25fl_read_dyb(fsm, offs, &dyb);
+                       if (dyb == 0x00)
+                               stfsm_s25fl_write_dyb(fsm, offs, 0xff);
+
+                       /* Handle bottom/top 4KiB parameter sectors */
+                       if ((offs < info->sector_size * 2) ||
+                           (offs >= (info->sector_size - info->n_sectors * 4)))
+                               offs += 0x1000;
+                       else
+                               offs += 0x10000;
+               }
+       }
+
+       /* Check status of 'QE' bit */
+       data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
+       stfsm_read_status(fsm, FLASH_CMD_RDSR2, &cr1);
+       if (data_pads == 4) {
+               if (!(cr1 & STFSM_S25FL_CONFIG_QE)) {
+                       /* Set 'QE' */
+                       cr1 |= STFSM_S25FL_CONFIG_QE;
+
+                       stfsm_read_status(fsm, FLASH_CMD_RDSR, &sr1);
+                       sta_wr = ((uint16_t)cr1  << 8) | sr1;
+
+                       stfsm_write_status(fsm, sta_wr, 2);
+
+                       stfsm_wait_busy(fsm);
+               }
+       } else {
+               if ((cr1 & STFSM_S25FL_CONFIG_QE)) {
+                       /* Clear 'QE' */
+                       cr1 &= ~STFSM_S25FL_CONFIG_QE;
+
+                       stfsm_read_status(fsm, FLASH_CMD_RDSR, &sr1);
+                       sta_wr = ((uint16_t)cr1  << 8) | sr1;
+
+                       stfsm_write_status(fsm, sta_wr, 2);
+
+                       stfsm_wait_busy(fsm);
+               }
+
+       }
+
+       /*
+        * S25FLxxx devices support Program and Error error flags.
+        * Configure driver to check flags and clear if necessary.
+        */
+       fsm->configuration |= CFG_S25FL_CHECK_ERROR_FLAGS;
+
+       return 0;
+}
+
+static int stfsm_w25q_config(struct stfsm *fsm)
+{
+       uint32_t data_pads;
+       uint16_t sta_wr;
+       uint8_t sta1, sta2;
+       int ret;
+
+       ret = stfsm_prepare_rwe_seqs_default(fsm);
+       if (ret)
+               return ret;
+
+       /* If using QUAD mode, set QE STATUS bit */
+       data_pads = ((fsm->stfsm_seq_read.seq_cfg >> 16) & 0x3) + 1;
+       if (data_pads == 4) {
+               stfsm_read_status(fsm, FLASH_CMD_RDSR, &sta1);
+               stfsm_read_status(fsm, FLASH_CMD_RDSR2, &sta2);
+
+               sta_wr = ((uint16_t)sta2 << 8) | sta1;
+
+               sta_wr |= W25Q_STATUS_QE;
+
+               stfsm_write_status(fsm, sta_wr, 2);
+
+               stfsm_wait_busy(fsm);
+       }
+
+       return 0;
+}
+
+static int stfsm_read(struct stfsm *fsm, uint8_t *buf, uint32_t size,
+                     uint32_t offset)
+{
+       struct stfsm_seq *seq = &fsm->stfsm_seq_read;
+       uint32_t data_pads;
+       uint32_t read_mask;
+       uint32_t size_ub;
+       uint32_t size_lb;
+       uint32_t size_mop;
+       uint32_t tmp[4];
+       uint32_t page_buf[FLASH_PAGESIZE_32];
+       uint8_t *p;
+
+       dev_dbg(fsm->dev, "reading %d bytes from 0x%08x\n", size, offset);
+
+       /* Enter 32-bit address mode, if required */
+       if (fsm->configuration & CFG_READ_TOGGLE_32BIT_ADDR)
+               stfsm_enter_32bit_addr(fsm, 1);
+
+       /* Must read in multiples of 32 cycles (or 32*pads/8 Bytes) */
+       data_pads = ((seq->seq_cfg >> 16) & 0x3) + 1;
+       read_mask = (data_pads << 2) - 1;
+
+       /* Handle non-aligned buf */
+       p = ((uint32_t)buf & 0x3) ? (uint8_t *)page_buf : buf;
+
+       /* Handle non-aligned size */
+       size_ub = (size + read_mask) & ~read_mask;
+       size_lb = size & ~read_mask;
+       size_mop = size & read_mask;
+
+       seq->data_size = TRANSFER_SIZE(size_ub);
+       seq->addr1 = (offset >> 16) & 0xffff;
+       seq->addr2 = offset & 0xffff;
+
+       stfsm_load_seq(fsm, seq);
+
+       if (size_lb)
+               stfsm_read_fifo(fsm, (uint32_t *)p, size_lb);
+
+       if (size_mop) {
+               stfsm_read_fifo(fsm, tmp, read_mask + 1);
+               memcpy(p + size_lb, &tmp, size_mop);
+       }
+
+       /* Handle non-aligned buf */
+       if ((uint32_t)buf & 0x3)
+               memcpy(buf, page_buf, size);
+
+       /* Wait for sequence to finish */
+       stfsm_wait_seq(fsm);
+
+       stfsm_clear_fifo(fsm);
+
+       /* Exit 32-bit address mode, if required */
+       if (fsm->configuration & CFG_READ_TOGGLE_32BIT_ADDR)
+               stfsm_enter_32bit_addr(fsm, 0);
+
+       return 0;
+}
+
+static int stfsm_write(struct stfsm *fsm, const uint8_t *buf,
+                      uint32_t size, uint32_t offset)
+{
+       struct stfsm_seq *seq = &fsm->stfsm_seq_write;
+       uint32_t data_pads;
+       uint32_t write_mask;
+       uint32_t size_ub;
+       uint32_t size_lb;
+       uint32_t size_mop;
+       uint32_t tmp[4];
+       uint32_t page_buf[FLASH_PAGESIZE_32];
+       uint8_t *t = (uint8_t *)&tmp;
+       const uint8_t *p;
+       int ret;
+       int i;
+
+       dev_dbg(fsm->dev, "writing %d bytes to 0x%08x\n", size, offset);
+
+       /* Enter 32-bit address mode, if required */
+       if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR)
+               stfsm_enter_32bit_addr(fsm, 1);
+
+       /* Must write in multiples of 32 cycles (or 32*pads/8 bytes) */
+       data_pads = ((seq->seq_cfg >> 16) & 0x3) + 1;
+       write_mask = (data_pads << 2) - 1;
+
+       /* Handle non-aligned buf */
+       if ((uint32_t)buf & 0x3) {
+               memcpy(page_buf, buf, size);
+               p = (uint8_t *)page_buf;
+       } else {
+               p = buf;
+       }
+
+       /* Handle non-aligned size */
+       size_ub = (size + write_mask) & ~write_mask;
+       size_lb = size & ~write_mask;
+       size_mop = size & write_mask;
+
+       seq->data_size = TRANSFER_SIZE(size_ub);
+       seq->addr1 = (offset >> 16) & 0xffff;
+       seq->addr2 = offset & 0xffff;
+
+       /* Need to set FIFO to write mode, before writing data to FIFO (see
+        * GNBvb79594)
+        */
+       writel(0x00040000, fsm->base + SPI_FAST_SEQ_CFG);
+
+       /*
+        * Before writing data to the FIFO, apply a small delay to allow a
+        * potential change of FIFO direction to complete.
+        */
+       if (fsm->fifo_dir_delay == 0)
+               readl(fsm->base + SPI_FAST_SEQ_CFG);
+       else
+               udelay(fsm->fifo_dir_delay);
+
+
+       /* Write data to FIFO, before starting sequence (see GNBvd79593) */
+       if (size_lb) {
+               stfsm_write_fifo(fsm, (uint32_t *)p, size_lb);
+               p += size_lb;
+       }
+
+       /* Handle non-aligned size */
+       if (size_mop) {
+               memset(t, 0xff, write_mask + 1);        /* fill with 0xff's */
+               for (i = 0; i < size_mop; i++)
+                       t[i] = *p++;
+
+               stfsm_write_fifo(fsm, tmp, write_mask + 1);
+       }
+
+       /* Start sequence */
+       stfsm_load_seq(fsm, seq);
+
+       /* Wait for sequence to finish */
+       stfsm_wait_seq(fsm);
+
+       /* Wait for completion */
+       ret = stfsm_wait_busy(fsm);
+       if (ret && fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS)
+               stfsm_s25fl_clear_status_reg(fsm);
+
+       /* Exit 32-bit address mode, if required */
+       if (fsm->configuration & CFG_WRITE_TOGGLE_32BIT_ADDR) {
+               stfsm_enter_32bit_addr(fsm, 0);
+               if (fsm->configuration & CFG_WRITE_EX_32BIT_ADDR_DELAY)
+                       udelay(1);
+       }
+
+       return 0;
+}
+
+/*
+ * Read an address range from the flash chip. The address range
+ * may be any size provided it is within the physical boundaries.
+ */
+static int stfsm_mtd_read(struct mtd_info *mtd, loff_t from, size_t len,
+                         size_t *retlen, u_char *buf)
+{
+       struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent);
+       uint32_t bytes;
+
+       dev_dbg(fsm->dev, "%s from 0x%08x, len %zd\n",
+               __func__, (u32)from, len);
+
+       mutex_lock(&fsm->lock);
+
+       while (len > 0) {
+               bytes = min_t(size_t, len, FLASH_PAGESIZE);
+
+               stfsm_read(fsm, buf, bytes, from);
+
+               buf += bytes;
+               from += bytes;
+               len -= bytes;
+
+               *retlen += bytes;
+       }
+
+       mutex_unlock(&fsm->lock);
+
+       return 0;
+}
+
+static int stfsm_erase_sector(struct stfsm *fsm, uint32_t offset)
+{
+       struct stfsm_seq *seq = &stfsm_seq_erase_sector;
+       int ret;
+
+       dev_dbg(fsm->dev, "erasing sector at 0x%08x\n", offset);
+
+       /* Enter 32-bit address mode, if required */
+       if (fsm->configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR)
+               stfsm_enter_32bit_addr(fsm, 1);
+
+       seq->addr1 = (offset >> 16) & 0xffff;
+       seq->addr2 = offset & 0xffff;
+
+       stfsm_load_seq(fsm, seq);
+
+       stfsm_wait_seq(fsm);
+
+       /* Wait for completion */
+       ret = stfsm_wait_busy(fsm);
+       if (ret && fsm->configuration & CFG_S25FL_CHECK_ERROR_FLAGS)
+               stfsm_s25fl_clear_status_reg(fsm);
+
+       /* Exit 32-bit address mode, if required */
+       if (fsm->configuration & CFG_ERASESEC_TOGGLE_32BIT_ADDR)
+               stfsm_enter_32bit_addr(fsm, 0);
+
+       return ret;
+}
+
+static int stfsm_erase_chip(struct stfsm *fsm)
+{
+       const struct stfsm_seq *seq = &stfsm_seq_erase_chip;
+
+       dev_dbg(fsm->dev, "erasing chip\n");
+
+       stfsm_load_seq(fsm, seq);
+
+       stfsm_wait_seq(fsm);
+
+       return stfsm_wait_busy(fsm);
+}
+
+/*
+ * Write an address range to the flash chip.  Data must be written in
+ * FLASH_PAGESIZE chunks.  The address range may be any size provided
+ * it is within the physical boundaries.
+ */
+static int stfsm_mtd_write(struct mtd_info *mtd, loff_t to, size_t len,
+                          size_t *retlen, const u_char *buf)
+{
+       struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent);
+
+       u32 page_offs;
+       u32 bytes;
+       uint8_t *b = (uint8_t *)buf;
+       int ret = 0;
+
+       dev_dbg(fsm->dev, "%s to 0x%08x, len %zd\n", __func__, (u32)to, len);
+
+       /* Offset within page */
+       page_offs = to % FLASH_PAGESIZE;
+
+       mutex_lock(&fsm->lock);
+
+       while (len) {
+               /* Write up to page boundary */
+               bytes = min(FLASH_PAGESIZE - page_offs, len);
+
+               ret = stfsm_write(fsm, b, bytes, to);
+               if (ret)
+                       goto out1;
+
+               b += bytes;
+               len -= bytes;
+               to += bytes;
+
+               /* We are now page-aligned */
+               page_offs = 0;
+
+               *retlen += bytes;
+
+       }
+
+out1:
+       mutex_unlock(&fsm->lock);
+
+       return ret;
+}
+
+/*
+ * Erase an address range on the flash chip. The address range may extend
+ * one or more erase sectors.  Return an error is there is a problem erasing.
+ */
+static int stfsm_mtd_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+       struct stfsm *fsm = dev_get_drvdata(mtd->dev.parent);
+       u32 addr, len;
+       int ret;
+
+       dev_dbg(fsm->dev, "%s at 0x%llx, len %lld\n", __func__,
+               (long long)instr->addr, (long long)instr->len);
+
+       addr = instr->addr;
+       len = instr->len;
+
+       mutex_lock(&fsm->lock);
+
+       /* Whole-chip erase? */
+       if (len == mtd->size) {
+               ret = stfsm_erase_chip(fsm);
+               if (ret)
+                       goto out1;
+       } else {
+               while (len) {
+                       ret = stfsm_erase_sector(fsm, addr);
+                       if (ret)
+                               goto out1;
+
+                       addr += mtd->erasesize;
+                       len -= mtd->erasesize;
+               }
+       }
+
+       mutex_unlock(&fsm->lock);
+
+       instr->state = MTD_ERASE_DONE;
+       mtd_erase_callback(instr);
+
+       return 0;
+
+out1:
+       instr->state = MTD_ERASE_FAILED;
+       mutex_unlock(&fsm->lock);
+
+       return ret;
+}
+
+static void stfsm_read_jedec(struct stfsm *fsm, uint8_t *jedec)
+{
+       const struct stfsm_seq *seq = &stfsm_seq_read_jedec;
+       uint32_t tmp[2];
+
+       stfsm_load_seq(fsm, seq);
+
+       stfsm_read_fifo(fsm, tmp, 8);
+
+       memcpy(jedec, tmp, 5);
+
+       stfsm_wait_seq(fsm);
+}
+
+static struct flash_info *stfsm_jedec_probe(struct stfsm *fsm)
+{
+       struct flash_info       *info;
+       u16                     ext_jedec;
+       u32                     jedec;
+       u8                      id[5];
+
+       stfsm_read_jedec(fsm, id);
+
+       jedec     = id[0] << 16 | id[1] << 8 | id[2];
+       /*
+        * JEDEC also defines an optional "extended device information"
+        * string for after vendor-specific data, after the three bytes
+        * we use here. Supporting some chips might require using it.
+        */
+       ext_jedec = id[3] << 8  | id[4];
+
+       dev_dbg(fsm->dev, "JEDEC =  0x%08x [%02x %02x %02x %02x %02x]\n",
+               jedec, id[0], id[1], id[2], id[3], id[4]);
+
+       for (info = flash_types; info->name; info++) {
+               if (info->jedec_id == jedec) {
+                       if (info->ext_id && info->ext_id != ext_jedec)
+                               continue;
+                       return info;
+               }
+       }
+       dev_err(fsm->dev, "Unrecognized JEDEC id %06x\n", jedec);
+
+       return NULL;
+}
+
+static int stfsm_set_mode(struct stfsm *fsm, uint32_t mode)
+{
+       int ret, timeout = 10;
+
+       /* Wait for controller to accept mode change */
+       while (--timeout) {
+               ret = readl(fsm->base + SPI_STA_MODE_CHANGE);
+               if (ret & 0x1)
+                       break;
+               udelay(1);
+       }
+
+       if (!timeout)
+               return -EBUSY;
+
+       writel(mode, fsm->base + SPI_MODESELECT);
+
+       return 0;
+}
+
+static void stfsm_set_freq(struct stfsm *fsm, uint32_t spi_freq)
+{
+       uint32_t emi_freq;
+       uint32_t clk_div;
+
+       /* TODO: Make this dynamic */
+       emi_freq = STFSM_DEFAULT_EMI_FREQ;
+
+       /*
+        * Calculate clk_div - values between 2 and 128
+        * Multiple of 2, rounded up
+        */
+       clk_div = 2 * DIV_ROUND_UP(emi_freq, 2 * spi_freq);
+       if (clk_div < 2)
+               clk_div = 2;
+       else if (clk_div > 128)
+               clk_div = 128;
+
+       /*
+        * Determine a suitable delay for the IP to complete a change of
+        * direction of the FIFO. The required delay is related to the clock
+        * divider used. The following heuristics are based on empirical tests,
+        * using a 100MHz EMI clock.
+        */
+       if (clk_div <= 4)
+               fsm->fifo_dir_delay = 0;
+       else if (clk_div <= 10)
+               fsm->fifo_dir_delay = 1;
+       else
+               fsm->fifo_dir_delay = DIV_ROUND_UP(clk_div, 10);
+
+       dev_dbg(fsm->dev, "emi_clk = %uHZ, spi_freq = %uHZ, clk_div = %u\n",
+               emi_freq, spi_freq, clk_div);
+
+       writel(clk_div, fsm->base + SPI_CLOCKDIV);
+}
+
+static int stfsm_init(struct stfsm *fsm)
+{
+       int ret;
+
+       /* Perform a soft reset of the FSM controller */
+       writel(SEQ_CFG_SWRESET, fsm->base + SPI_FAST_SEQ_CFG);
+       udelay(1);
+       writel(0, fsm->base + SPI_FAST_SEQ_CFG);
+
+       /* Set clock to 'safe' frequency initially */
+       stfsm_set_freq(fsm, STFSM_FLASH_SAFE_FREQ);
+
+       /* Switch to FSM */
+       ret = stfsm_set_mode(fsm, SPI_MODESELECT_FSM);
+       if (ret)
+               return ret;
+
+       /* Set timing parameters */
+       writel(SPI_CFG_DEVICE_ST            |
+              SPI_CFG_DEFAULT_MIN_CS_HIGH  |
+              SPI_CFG_DEFAULT_CS_SETUPHOLD |
+              SPI_CFG_DEFAULT_DATA_HOLD,
+              fsm->base + SPI_CONFIGDATA);
+       writel(STFSM_DEFAULT_WR_TIME, fsm->base + SPI_STATUS_WR_TIME_REG);
+
+       /* Clear FIFO, just in case */
+       stfsm_clear_fifo(fsm);
+
+       return 0;
+}
+
+static void stfsm_fetch_platform_configs(struct platform_device *pdev)
+{
+       struct stfsm *fsm = platform_get_drvdata(pdev);
+       struct device_node *np = pdev->dev.of_node;
+       struct regmap *regmap;
+       uint32_t boot_device_reg;
+       uint32_t boot_device_spi;
+       uint32_t boot_device;     /* Value we read from *boot_device_reg */
+       int ret;
+
+       /* Booting from SPI NOR Flash is the default */
+       fsm->booted_from_spi = true;
+
+       regmap = syscon_regmap_lookup_by_phandle(np, "st,syscfg");
+       if (IS_ERR(regmap))
+               goto boot_device_fail;
+
+       fsm->reset_signal = of_property_read_bool(np, "st,reset-signal");
+
+       fsm->reset_por = of_property_read_bool(np, "st,reset-por");
+
+       /* Where in the syscon the boot device information lives */
+       ret = of_property_read_u32(np, "st,boot-device-reg", &boot_device_reg);
+       if (ret)
+               goto boot_device_fail;
+
+       /* Boot device value when booted from SPI NOR */
+       ret = of_property_read_u32(np, "st,boot-device-spi", &boot_device_spi);
+       if (ret)
+               goto boot_device_fail;
+
+       ret = regmap_read(regmap, boot_device_reg, &boot_device);
+       if (ret)
+               goto boot_device_fail;
+
+       if (boot_device != boot_device_spi)
+               fsm->booted_from_spi = false;
+
+       return;
+
+boot_device_fail:
+       dev_warn(&pdev->dev,
+                "failed to fetch boot device, assuming boot from SPI\n");
+}
+
+static int stfsm_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct mtd_part_parser_data ppdata;
+       struct flash_info *info;
+       struct resource *res;
+       struct stfsm *fsm;
+       int ret;
+
+       if (!np) {
+               dev_err(&pdev->dev, "No DT found\n");
+               return -EINVAL;
+       }
+       ppdata.of_node = np;
+
+       fsm = devm_kzalloc(&pdev->dev, sizeof(*fsm), GFP_KERNEL);
+       if (!fsm)
+               return -ENOMEM;
+
+       fsm->dev = &pdev->dev;
+
+       platform_set_drvdata(pdev, fsm);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "Resource not found\n");
+               return -ENODEV;
+       }
+
+       fsm->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(fsm->base)) {
+               dev_err(&pdev->dev,
+                       "Failed to reserve memory region %pR\n", res);
+               return PTR_ERR(fsm->base);
+       }
+
+       mutex_init(&fsm->lock);
+
+       ret = stfsm_init(fsm);
+       if (ret) {
+               dev_err(&pdev->dev, "Failed to initialise FSM Controller\n");
+               return ret;
+       }
+
+       stfsm_fetch_platform_configs(pdev);
+
+       /* Detect SPI FLASH device */
+       info = stfsm_jedec_probe(fsm);
+       if (!info)
+               return -ENODEV;
+       fsm->info = info;
+
+       /* Use device size to determine address width */
+       if (info->sector_size * info->n_sectors > 0x1000000)
+               info->flags |= FLASH_FLAG_32BIT_ADDR;
+
+       /*
+        * Configure READ/WRITE/ERASE sequences according to platform and
+        * device flags.
+        */
+       if (info->config) {
+               ret = info->config(fsm);
+               if (ret)
+                       return ret;
+       } else {
+               ret = stfsm_prepare_rwe_seqs_default(fsm);
+               if (ret)
+                       return ret;
+       }
+
+       fsm->mtd.name           = info->name;
+       fsm->mtd.dev.parent     = &pdev->dev;
+       fsm->mtd.type           = MTD_NORFLASH;
+       fsm->mtd.writesize      = 4;
+       fsm->mtd.writebufsize   = fsm->mtd.writesize;
+       fsm->mtd.flags          = MTD_CAP_NORFLASH;
+       fsm->mtd.size           = info->sector_size * info->n_sectors;
+       fsm->mtd.erasesize      = info->sector_size;
+
+       fsm->mtd._read  = stfsm_mtd_read;
+       fsm->mtd._write = stfsm_mtd_write;
+       fsm->mtd._erase = stfsm_mtd_erase;
+
+       dev_info(&pdev->dev,
+               "Found serial flash device: %s\n"
+               " size = %llx (%lldMiB) erasesize = 0x%08x (%uKiB)\n",
+               info->name,
+               (long long)fsm->mtd.size, (long long)(fsm->mtd.size >> 20),
+               fsm->mtd.erasesize, (fsm->mtd.erasesize >> 10));
+
+       return mtd_device_parse_register(&fsm->mtd, NULL, &ppdata, NULL, 0);
+}
+
+static int stfsm_remove(struct platform_device *pdev)
+{
+       struct stfsm *fsm = platform_get_drvdata(pdev);
+
+       return mtd_device_unregister(&fsm->mtd);
+}
+
+static struct of_device_id stfsm_match[] = {
+       { .compatible = "st,spi-fsm", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, stfsm_match);
+
+static struct platform_driver stfsm_driver = {
+       .probe          = stfsm_probe,
+       .remove         = stfsm_remove,
+       .driver         = {
+               .name   = "st-spi-fsm",
+               .owner  = THIS_MODULE,
+               .of_match_table = stfsm_match,
+       },
+};
+module_platform_driver(stfsm_driver);
+
+MODULE_AUTHOR("Angus Clark <angus.clark@st.com>");
+MODULE_DESCRIPTION("ST SPI FSM driver");
+MODULE_LICENSE("GPL");
index 4adc037..487e64f 100644 (file)
@@ -30,7 +30,6 @@
 #include <asm/uaccess.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nftl.h>
 #include <linux/mtd/inftl.h>
index d38b646..018c75f 100644 (file)
@@ -55,10 +55,8 @@ struct mtd_info *lpddr_cmdset(struct map_info *map)
        int i, j;
 
        mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
-       if (!mtd) {
-               printk(KERN_ERR "Failed to allocate memory for MTD device\n");
+       if (!mtd)
                return NULL;
-       }
        mtd->priv = map;
        mtd->type = MTD_NORFLASH;
 
index 45abed6..69f2112 100644 (file)
@@ -135,11 +135,8 @@ static int lpddr_chip_setup(struct map_info *map, struct lpddr_private *lpddr)
 {
 
        lpddr->qinfo = kzalloc(sizeof(struct qinfo_chip), GFP_KERNEL);
-       if (!lpddr->qinfo) {
-               printk(KERN_WARNING "%s: no memory for LPDDR qinfo structure\n",
-                               map->name);
+       if (!lpddr->qinfo)
                return 0;
-       }
 
        /* Get the ManuID */
        lpddr->ManufactId = CMDVAL(map_read(map, map->pfow_base + PFOW_MANUFACTURER_ID));
index 310dc7c..fce23fe 100644 (file)
@@ -66,11 +66,11 @@ config MTD_PHYSMAP_BANKWIDTH
          used internally by the CFI drivers.
 
 config MTD_PHYSMAP_OF
-       tristate "Flash device in physical memory map based on OF description"
-       depends on OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM)
+       tristate "Memory device in physical memory map based on OF description"
+       depends on OF && (MTD_CFI || MTD_JEDECPROBE || MTD_ROM || MTD_RAM)
        help
-         This provides a 'mapping' driver which allows the NOR Flash and
-         ROM driver code to communicate with chips which are mapped
+         This provides a 'mapping' driver which allows the NOR Flash, ROM
+         and RAM driver code to communicate with chips which are mapped
          physically into the CPU's memory. The mapping description here is
          taken from OF device tree.
 
@@ -124,7 +124,7 @@ config MTD_NETSC520
 
 config MTD_TS5500
        tristate "JEDEC Flash device mapped on Technologic Systems TS-5500"
-       depends on X86
+       depends on TS5500 || COMPILE_TEST
        select MTD_JEDECPROBE
        select MTD_CFI_AMDSTD
        help
index 5434d8d..6ea51e5 100644 (file)
@@ -14,7 +14,6 @@
  * Licensed under the GPL-2 or later.
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
index 1adba86..a4c477b 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/gpio.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
index 46d195f..5ab71f0 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
index d6b2451..6a589f1 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/slab.h>
index 93c507a..7aa682c 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
index 98bb5d5..cadfbe0 100644 (file)
@@ -10,7 +10,6 @@
  * kind, whether express or implied.
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
index 36da518..eb0242e 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 
 #include <linux/mtd/mtd.h>
index d111097..217c25d 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
index 10196f5..d597e89 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
@@ -138,7 +137,6 @@ static int platram_probe(struct platform_device *pdev)
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (info == NULL) {
-               dev_err(&pdev->dev, "no memory for flash info\n");
                err = -ENOMEM;
                goto exit_error;
        }
index 9aad854..cb4d92e 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
index 9352512..146b604 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
index 3051c4c..b7a22a6 100644 (file)
@@ -47,7 +47,6 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <asm/io.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
index 39cc418..b6f1aac 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/module.h>
 #include <linux/fs.h>
 #include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
index 5073cbc..0b2ccb6 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/blkpg.h>
 #include <linux/spinlock.h>
 #include <linux/hdreg.h>
-#include <linux/init.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.h>
 
index 2147e73..7d4e7b9 100644 (file)
@@ -324,6 +324,15 @@ static ssize_t mtdchar_write(struct file *file, const char __user *buf, size_t c
                default:
                        ret = mtd_write(mtd, *ppos, len, &retlen, kbuf);
                }
+
+               /*
+                * Return -ENOSPC only if no data could be written at all.
+                * Otherwise just return the number of bytes that actually
+                * have been written.
+                */
+               if ((ret == -ENOSPC) && (total_retlen))
+                       break;
+
                if (!ret) {
                        *ppos += retlen;
                        total_retlen += retlen;
@@ -889,25 +898,26 @@ static int mtdchar_ioctl(struct file *file, u_int cmd, u_long arg)
        case OTPGETREGIONINFO:
        {
                struct otp_info *buf = kmalloc(4096, GFP_KERNEL);
+               size_t retlen;
                if (!buf)
                        return -ENOMEM;
                switch (mfi->mode) {
                case MTD_FILE_MODE_OTP_FACTORY:
-                       ret = mtd_get_fact_prot_info(mtd, buf, 4096);
+                       ret = mtd_get_fact_prot_info(mtd, 4096, &retlen, buf);
                        break;
                case MTD_FILE_MODE_OTP_USER:
-                       ret = mtd_get_user_prot_info(mtd, buf, 4096);
+                       ret = mtd_get_user_prot_info(mtd, 4096, &retlen, buf);
                        break;
                default:
                        ret = -EINVAL;
                        break;
                }
-               if (ret >= 0) {
+               if (!ret) {
                        if (cmd == OTPGETREGIONCOUNT) {
-                               int nbr = ret / sizeof(struct otp_info);
+                               int nbr = retlen / sizeof(struct otp_info);
                                ret = copy_to_user(argp, &nbr, sizeof(int));
                        } else
-                               ret = copy_to_user(argp, buf, ret);
+                               ret = copy_to_user(argp, buf, retlen);
                        if (ret)
                                ret = -EFAULT;
                }
index 34c0b16..d201fee 100644 (file)
@@ -883,14 +883,14 @@ EXPORT_SYMBOL_GPL(mtd_read_oob);
  * devices. The user data is one time programmable but the factory data is read
  * only.
  */
-int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
-                          size_t len)
+int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
+                          struct otp_info *buf)
 {
        if (!mtd->_get_fact_prot_info)
                return -EOPNOTSUPP;
        if (!len)
                return 0;
-       return mtd->_get_fact_prot_info(mtd, buf, len);
+       return mtd->_get_fact_prot_info(mtd, len, retlen, buf);
 }
 EXPORT_SYMBOL_GPL(mtd_get_fact_prot_info);
 
@@ -906,14 +906,14 @@ int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
 }
 EXPORT_SYMBOL_GPL(mtd_read_fact_prot_reg);
 
-int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
-                          size_t len)
+int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
+                          struct otp_info *buf)
 {
        if (!mtd->_get_user_prot_info)
                return -EOPNOTSUPP;
        if (!len)
                return 0;
-       return mtd->_get_user_prot_info(mtd, buf, len);
+       return mtd->_get_user_prot_info(mtd, len, retlen, buf);
 }
 EXPORT_SYMBOL_GPL(mtd_get_user_prot_info);
 
@@ -932,12 +932,22 @@ EXPORT_SYMBOL_GPL(mtd_read_user_prot_reg);
 int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
                            size_t *retlen, u_char *buf)
 {
+       int ret;
+
        *retlen = 0;
        if (!mtd->_write_user_prot_reg)
                return -EOPNOTSUPP;
        if (!len)
                return 0;
-       return mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
+       ret = mtd->_write_user_prot_reg(mtd, to, len, retlen, buf);
+       if (ret)
+               return ret;
+
+       /*
+        * If no data could be written at all, we are out of memory and
+        * must return -ENOSPC.
+        */
+       return (*retlen) ? 0 : -ENOSPC;
 }
 EXPORT_SYMBOL_GPL(mtd_write_user_prot_reg);
 
index 3c7d6d7..1ca9aec 100644 (file)
@@ -150,11 +150,12 @@ static int part_read_user_prot_reg(struct mtd_info *mtd, loff_t from,
                                                 retlen, buf);
 }
 
-static int part_get_user_prot_info(struct mtd_info *mtd,
-               struct otp_info *buf, size_t len)
+static int part_get_user_prot_info(struct mtd_info *mtd, size_t len,
+                                  size_t *retlen, struct otp_info *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->_get_user_prot_info(part->master, buf, len);
+       return part->master->_get_user_prot_info(part->master, len, retlen,
+                                                buf);
 }
 
 static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
@@ -165,11 +166,12 @@ static int part_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
                                                 retlen, buf);
 }
 
-static int part_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
-               size_t len)
+static int part_get_fact_prot_info(struct mtd_info *mtd, size_t len,
+                                  size_t *retlen, struct otp_info *buf)
 {
        struct mtd_part *part = PART(mtd);
-       return part->master->_get_fact_prot_info(part->master, buf, len);
+       return part->master->_get_fact_prot_info(part->master, len, retlen,
+                                                buf);
 }
 
 static int part_write(struct mtd_info *mtd, loff_t to, size_t len,
index a4bee41..f1cf503 100644 (file)
@@ -460,6 +460,8 @@ config MTD_NAND_MXC
 config MTD_NAND_SH_FLCTL
        tristate "Support for NAND on Renesas SuperH FLCTL"
        depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
+       depends on HAS_IOMEM
+       depends on HAS_DMA
        help
          Several Renesas SuperH CPU has FLCTL. This option enables support
          for NAND Flash using FLCTL.
index 8611eb4..4936e9e 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/mtd/mtd.h>
index c36e9b8..4ce181a 100644 (file)
@@ -430,7 +430,7 @@ err_dma:
        dma_unmap_single(dma_dev->dev, phys_addr, len, dir);
 err_buf:
        if (err != 0)
-               dev_warn(host->dev, "Fall back to CPU I/O\n");
+               dev_dbg(host->dev, "Fall back to CPU I/O\n");
        return err;
 }
 
@@ -1220,6 +1220,7 @@ static int atmel_pmecc_nand_init_params(struct platform_device *pdev,
                goto err;
        }
 
+       nand_chip->options |= NAND_NO_SUBPAGE_WRITE;
        nand_chip->ecc.read_page = atmel_nand_pmecc_read_page;
        nand_chip->ecc.write_page = atmel_nand_pmecc_write_page;
 
@@ -1659,8 +1660,8 @@ static void nfc_select_chip(struct mtd_info *mtd, int chip)
                nfc_writel(host->nfc->hsmc_regs, CTRL, NFC_CTRL_ENABLE);
 }
 
-static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr,
-               unsigned int *addr1234, unsigned int *cycle0)
+static int nfc_make_addr(struct mtd_info *mtd, int command, int column,
+               int page_addr, unsigned int *addr1234, unsigned int *cycle0)
 {
        struct nand_chip *chip = mtd->priv;
 
@@ -1674,7 +1675,8 @@ static int nfc_make_addr(struct mtd_info *mtd, int column, int page_addr,
        *addr1234 = 0;
 
        if (column != -1) {
-               if (chip->options & NAND_BUSWIDTH_16)
+               if (chip->options & NAND_BUSWIDTH_16 &&
+                               !nand_opcode_8bits(command))
                        column >>= 1;
                addr_bytes[acycle++] = column & 0xff;
                if (mtd->writesize > 512)
@@ -1787,8 +1789,8 @@ static void nfc_nand_command(struct mtd_info *mtd, unsigned int command,
        }
 
        if (do_addr)
-               acycle = nfc_make_addr(mtd, column, page_addr, &addr1234,
-                               &cycle0);
+               acycle = nfc_make_addr(mtd, command, column, page_addr,
+                               &addr1234, &cycle0);
 
        nfc_addr_cmd = cmd1 | cmd2 | vcmd2 | acycle | csid | dataen | nfcwr;
        nfc_send_command(host, nfc_addr_cmd, addr1234, cycle0);
index 2880d88..bc5c518 100644 (file)
@@ -11,7 +11,6 @@
 
 #include <linux/slab.h>
 #include <linux/gpio.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/mtd/mtd.h>
@@ -308,7 +307,8 @@ static void au1550_command(struct mtd_info *mtd, unsigned command, int column, i
                /* Serially input address */
                if (column != -1) {
                        /* Adjust columns for 16 bit buswidth */
-                       if (this->options & NAND_BUSWIDTH_16)
+                       if (this->options & NAND_BUSWIDTH_16 &&
+                                       !nand_opcode_8bits(command))
                                column >>= 1;
                        ctx->write_byte(mtd, column);
                }
index 94f55db..b7a2494 100644 (file)
@@ -37,7 +37,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
index f2f64ad..4e66726 100644 (file)
@@ -627,6 +627,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        struct cafe_priv *cafe;
        uint32_t ctrl;
        int err = 0;
+       int old_dma;
+       struct nand_buffers *nbuf;
 
        /* Very old versions shared the same PCI ident for all three
           functions on the chip. Verify the class too... */
@@ -655,13 +657,6 @@ static int cafe_nand_probe(struct pci_dev *pdev,
                err = -ENOMEM;
                goto out_free_mtd;
        }
-       cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev, 2112 + sizeof(struct nand_buffers),
-                                         &cafe->dmaaddr, GFP_KERNEL);
-       if (!cafe->dmabuf) {
-               err = -ENOMEM;
-               goto out_ior;
-       }
-       cafe->nand.buffers = (void *)cafe->dmabuf + 2112;
 
        cafe->rs = init_rs_non_canonical(12, &cafe_mul, 0, 1, 8);
        if (!cafe->rs) {
@@ -721,7 +716,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
                          "CAFE NAND", mtd);
        if (err) {
                dev_warn(&pdev->dev, "Could not register IRQ %d\n", pdev->irq);
-               goto out_free_dma;
+               goto out_ior;
        }
 
        /* Disable master reset, enable NAND clock */
@@ -735,6 +730,32 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        cafe_writel(cafe, 0x7006, GLOBAL_CTRL);
        cafe_writel(cafe, 0x700a, GLOBAL_CTRL);
 
+       /* Enable NAND IRQ in global IRQ mask register */
+       cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
+       cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
+               cafe_readl(cafe, GLOBAL_CTRL),
+               cafe_readl(cafe, GLOBAL_IRQ_MASK));
+
+       /* Do not use the DMA for the nand_scan_ident() */
+       old_dma = usedma;
+       usedma = 0;
+
+       /* Scan to find existence of the device */
+       if (nand_scan_ident(mtd, 2, NULL)) {
+               err = -ENXIO;
+               goto out_irq;
+       }
+
+       cafe->dmabuf = dma_alloc_coherent(&cafe->pdev->dev,
+                               2112 + sizeof(struct nand_buffers) +
+                               mtd->writesize + mtd->oobsize,
+                               &cafe->dmaaddr, GFP_KERNEL);
+       if (!cafe->dmabuf) {
+               err = -ENOMEM;
+               goto out_irq;
+       }
+       cafe->nand.buffers = nbuf = (void *)cafe->dmabuf + 2112;
+
        /* Set up DMA address */
        cafe_writel(cafe, cafe->dmaaddr & 0xffffffff, NAND_DMA_ADDR0);
        if (sizeof(cafe->dmaaddr) > 4)
@@ -746,16 +767,13 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        cafe_dev_dbg(&cafe->pdev->dev, "Set DMA address to %x (virt %p)\n",
                cafe_readl(cafe, NAND_DMA_ADDR0), cafe->dmabuf);
 
-       /* Enable NAND IRQ in global IRQ mask register */
-       cafe_writel(cafe, 0x80000007, GLOBAL_IRQ_MASK);
-       cafe_dev_dbg(&cafe->pdev->dev, "Control %x, IRQ mask %x\n",
-               cafe_readl(cafe, GLOBAL_CTRL), cafe_readl(cafe, GLOBAL_IRQ_MASK));
+       /* this driver does not need the @ecccalc and @ecccode */
+       nbuf->ecccalc = NULL;
+       nbuf->ecccode = NULL;
+       nbuf->databuf = (uint8_t *)(nbuf + 1);
 
-       /* Scan to find existence of the device */
-       if (nand_scan_ident(mtd, 2, NULL)) {
-               err = -ENXIO;
-               goto out_irq;
-       }
+       /* Restore the DMA flag */
+       usedma = old_dma;
 
        cafe->ctl2 = 1<<27; /* Reed-Solomon ECC */
        if (mtd->writesize == 2048)
@@ -773,7 +791,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        } else {
                printk(KERN_WARNING "Unexpected NAND flash writesize %d. Aborting\n",
                       mtd->writesize);
-               goto out_irq;
+               goto out_free_dma;
        }
        cafe->nand.ecc.mode = NAND_ECC_HW_SYNDROME;
        cafe->nand.ecc.size = mtd->writesize;
@@ -790,7 +808,7 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 
        err = nand_scan_tail(mtd);
        if (err)
-               goto out_irq;
+               goto out_free_dma;
 
        pci_set_drvdata(pdev, mtd);
 
@@ -799,12 +817,15 @@ static int cafe_nand_probe(struct pci_dev *pdev,
 
        goto out;
 
+ out_free_dma:
+       dma_free_coherent(&cafe->pdev->dev,
+                       2112 + sizeof(struct nand_buffers) +
+                       mtd->writesize + mtd->oobsize,
+                       cafe->dmabuf, cafe->dmaaddr);
  out_irq:
        /* Disable NAND IRQ in global IRQ mask register */
        cafe_writel(cafe, ~1 & cafe_readl(cafe, GLOBAL_IRQ_MASK), GLOBAL_IRQ_MASK);
        free_irq(pdev->irq, mtd);
- out_free_dma:
-       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
  out_ior:
        pci_iounmap(pdev, cafe->mmio);
  out_free_mtd:
@@ -824,7 +845,10 @@ static void cafe_nand_remove(struct pci_dev *pdev)
        nand_release(mtd);
        free_rs(cafe->rs);
        pci_iounmap(pdev, cafe->mmio);
-       dma_free_coherent(&cafe->pdev->dev, 2112, cafe->dmabuf, cafe->dmaaddr);
+       dma_free_coherent(&cafe->pdev->dev,
+                       2112 + sizeof(struct nand_buffers) +
+                       mtd->writesize + mtd->oobsize,
+                       cafe->dmabuf, cafe->dmaaddr);
        kfree(mtd);
 }
 
index 8eb6a36..4615d79 100644 (file)
@@ -24,7 +24,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/err.h>
index babb02c..35cb17f 100644 (file)
@@ -30,24 +30,6 @@ struct denali_dt {
        struct clk              *clk;
 };
 
-static void __iomem *request_and_map(struct device *dev,
-                                    const struct resource *res)
-{
-       void __iomem *ptr;
-
-       if (!devm_request_mem_region(dev, res->start, resource_size(res),
-                                    "denali-dt")) {
-               dev_err(dev, "unable to request %s\n", res->name);
-               return NULL;
-       }
-
-       ptr = devm_ioremap_nocache(dev, res->start, resource_size(res));
-       if (!ptr)
-               dev_err(dev, "ioremap_nocache of %s failed!", res->name);
-
-       return ptr;
-}
-
 static const struct of_device_id denali_nand_dt_ids[] = {
                { .compatible = "denali,denali-nand-dt" },
                { /* sentinel */ }
@@ -78,13 +60,6 @@ static int denali_dt_probe(struct platform_device *ofdev)
                return -ENOMEM;
        denali = &dt->denali;
 
-       denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg");
-       nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data");
-       if (!denali_reg || !nand_data) {
-               dev_err(&ofdev->dev, "resources not completely defined\n");
-               return -EINVAL;
-       }
-
        denali->platform = DT;
        denali->dev = &ofdev->dev;
        denali->irq = platform_get_irq(ofdev, 0);
@@ -93,13 +68,15 @@ static int denali_dt_probe(struct platform_device *ofdev)
                return denali->irq;
        }
 
-       denali->flash_reg = request_and_map(&ofdev->dev, denali_reg);
-       if (!denali->flash_reg)
-               return -ENOMEM;
+       denali_reg = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "denali_reg");
+       denali->flash_reg = devm_ioremap_resource(&ofdev->dev, denali_reg);
+       if (IS_ERR(denali->flash_reg))
+               return PTR_ERR(denali->flash_reg);
 
-       denali->flash_mem = request_and_map(&ofdev->dev, nand_data);
-       if (!denali->flash_mem)
-               return -ENOMEM;
+       nand_data = platform_get_resource_byname(ofdev, IORESOURCE_MEM, "nand_data");
+       denali->flash_mem = devm_ioremap_resource(&ofdev->dev, nand_data);
+       if (IS_ERR(denali->flash_mem))
+               return PTR_ERR(denali->flash_mem);
 
        if (!of_property_read_u32(ofdev->dev.of_node,
                "dma-mask", (u32 *)&denali_dma_mask)) {
index fec31d7..f68a7bc 100644 (file)
@@ -698,7 +698,8 @@ static void doc2001plus_command(struct mtd_info *mtd, unsigned command, int colu
                /* Serially input address */
                if (column != -1) {
                        /* Adjust columns for 16 bit buswidth */
-                       if (this->options & NAND_BUSWIDTH_16)
+                       if (this->options & NAND_BUSWIDTH_16 &&
+                                       !nand_opcode_8bits(command))
                                column >>= 1;
                        WriteDOC(column, docptr, Mplus_FlashAddress);
                }
@@ -1438,7 +1439,7 @@ static int __init doc_probe(unsigned long physadr)
        int reg, len, numchips;
        int ret = 0;
 
-       if (!request_mem_region(physadr, DOC_IOREMAP_LEN, NULL))
+       if (!request_mem_region(physadr, DOC_IOREMAP_LEN, "DiskOnChip"))
                return -EBUSY;
        virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
        if (!virtadr) {
index bcf6080..ec549cd 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/ioport.h>
index 50d9161..cb45d2f 100644 (file)
@@ -22,7 +22,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/of_address.h>
 #include <linux/slab.h>
index 8e6148a..117ce33 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/kernel.h>
 #include <linux/err.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
index ca6369f..bb77f75 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/of_device.h>
 #include <linux/of_mtd.h>
 #include "gpmi-nand.h"
+#include "bch-regs.h"
 
 /* Resource names for the GPMI NAND driver. */
 #define GPMI_NAND_GPMI_REGS_ADDR_RES_NAME  "gpmi-nand"
@@ -985,7 +986,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        int           ret;
 
        dev_dbg(this->dev, "page number is : %d\n", page);
-       ret = read_page_prepare(this, buf, mtd->writesize,
+       ret = read_page_prepare(this, buf, nfc_geo->payload_size,
                                        this->payload_virt, this->payload_phys,
                                        nfc_geo->payload_size,
                                        &payload_virt, &payload_phys);
@@ -999,7 +1000,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
 
        /* go! */
        ret = gpmi_read_page(this, payload_phys, auxiliary_phys);
-       read_page_end(this, buf, mtd->writesize,
+       read_page_end(this, buf, nfc_geo->payload_size,
                        this->payload_virt, this->payload_phys,
                        nfc_geo->payload_size,
                        payload_virt, payload_phys);
@@ -1041,7 +1042,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                chip->oob_poi[0] = ((uint8_t *) auxiliary_virt)[0];
        }
 
-       read_page_swap_end(this, buf, mtd->writesize,
+       read_page_swap_end(this, buf, nfc_geo->payload_size,
                        this->payload_virt, this->payload_phys,
                        nfc_geo->payload_size,
                        payload_virt, payload_phys);
@@ -1049,6 +1050,90 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        return max_bitflips;
 }
 
+/* Fake a virtual small page for the subpage read */
+static int gpmi_ecc_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
+                       uint32_t offs, uint32_t len, uint8_t *buf, int page)
+{
+       struct gpmi_nand_data *this = chip->priv;
+       void __iomem *bch_regs = this->resources.bch_regs;
+       struct bch_geometry old_geo = this->bch_geometry;
+       struct bch_geometry *geo = &this->bch_geometry;
+       int size = chip->ecc.size; /* ECC chunk size */
+       int meta, n, page_size;
+       u32 r1_old, r2_old, r1_new, r2_new;
+       unsigned int max_bitflips;
+       int first, last, marker_pos;
+       int ecc_parity_size;
+       int col = 0;
+
+       /* The size of ECC parity */
+       ecc_parity_size = geo->gf_len * geo->ecc_strength / 8;
+
+       /* Align it with the chunk size */
+       first = offs / size;
+       last = (offs + len - 1) / size;
+
+       /*
+        * Find the chunk which contains the Block Marker. If this chunk is
+        * in the range of [first, last], we have to read out the whole page.
+        * Why? since we had swapped the data at the position of Block Marker
+        * to the metadata which is bound with the chunk 0.
+        */
+       marker_pos = geo->block_mark_byte_offset / size;
+       if (last >= marker_pos && first <= marker_pos) {
+               dev_dbg(this->dev, "page:%d, first:%d, last:%d, marker at:%d\n",
+                               page, first, last, marker_pos);
+               return gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+       }
+
+       meta = geo->metadata_size;
+       if (first) {
+               col = meta + (size + ecc_parity_size) * first;
+               chip->cmdfunc(mtd, NAND_CMD_RNDOUT, col, -1);
+
+               meta = 0;
+               buf = buf + first * size;
+       }
+
+       /* Save the old environment */
+       r1_old = r1_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT0);
+       r2_old = r2_new = readl(bch_regs + HW_BCH_FLASH0LAYOUT1);
+
+       /* change the BCH registers and bch_geometry{} */
+       n = last - first + 1;
+       page_size = meta + (size + ecc_parity_size) * n;
+
+       r1_new &= ~(BM_BCH_FLASH0LAYOUT0_NBLOCKS |
+                       BM_BCH_FLASH0LAYOUT0_META_SIZE);
+       r1_new |= BF_BCH_FLASH0LAYOUT0_NBLOCKS(n - 1)
+                       | BF_BCH_FLASH0LAYOUT0_META_SIZE(meta);
+       writel(r1_new, bch_regs + HW_BCH_FLASH0LAYOUT0);
+
+       r2_new &= ~BM_BCH_FLASH0LAYOUT1_PAGE_SIZE;
+       r2_new |= BF_BCH_FLASH0LAYOUT1_PAGE_SIZE(page_size);
+       writel(r2_new, bch_regs + HW_BCH_FLASH0LAYOUT1);
+
+       geo->ecc_chunk_count = n;
+       geo->payload_size = n * size;
+       geo->page_size = page_size;
+       geo->auxiliary_status_offset = ALIGN(meta, 4);
+
+       dev_dbg(this->dev, "page:%d(%d:%d)%d, chunk:(%d:%d), BCH PG size:%d\n",
+               page, offs, len, col, first, n, page_size);
+
+       /* Read the subpage now */
+       this->swap_block_mark = false;
+       max_bitflips = gpmi_ecc_read_page(mtd, chip, buf, 0, page);
+
+       /* Restore */
+       writel(r1_old, bch_regs + HW_BCH_FLASH0LAYOUT0);
+       writel(r2_old, bch_regs + HW_BCH_FLASH0LAYOUT1);
+       this->bch_geometry = old_geo;
+       this->swap_block_mark = true;
+
+       return max_bitflips;
+}
+
 static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                const uint8_t *buf, int oob_required)
 {
@@ -1565,6 +1650,17 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
        ecc->strength   = bch_geo->ecc_strength;
        ecc->layout     = &gpmi_hw_ecclayout;
 
+       /*
+        * We only enable the subpage read when:
+        *  (1) the chip is imx6, and
+        *  (2) the size of the ECC parity is byte aligned.
+        */
+       if (GPMI_IS_MX6Q(this) &&
+               ((bch_geo->gf_len * bch_geo->ecc_strength) % 8) == 0) {
+               ecc->read_subpage = gpmi_ecc_read_subpage;
+               chip->options |= NAND_SUBPAGE_READ;
+       }
+
        /*
         * Can we enable the extra features? such as EDO or Sync mode.
         *
index 31ee7cf..e78841a 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/gfp.h>
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/mtd/mtd.h>
index e9a4835..dba262b 100644 (file)
@@ -1501,6 +1501,8 @@ static int mxcnd_probe(struct platform_device *pdev)
        init_completion(&host->op_completion);
 
        host->irq = platform_get_irq(pdev, 0);
+       if (host->irq < 0)
+               return host->irq;
 
        /*
         * Use host->devtype_data->irq_control() here instead of irq_control()
index 9715a7b..9d01c4d 100644 (file)
@@ -589,7 +589,8 @@ static void nand_command(struct mtd_info *mtd, unsigned int command,
        /* Serially input address */
        if (column != -1) {
                /* Adjust columns for 16 bit buswidth */
-               if (chip->options & NAND_BUSWIDTH_16)
+               if (chip->options & NAND_BUSWIDTH_16 &&
+                               !nand_opcode_8bits(command))
                        column >>= 1;
                chip->cmd_ctrl(mtd, column, ctrl);
                ctrl &= ~NAND_CTRL_CHANGE;
@@ -680,7 +681,8 @@ static void nand_command_lp(struct mtd_info *mtd, unsigned int command,
                /* Serially input address */
                if (column != -1) {
                        /* Adjust columns for 16 bit buswidth */
-                       if (chip->options & NAND_BUSWIDTH_16)
+                       if (chip->options & NAND_BUSWIDTH_16 &&
+                                       !nand_opcode_8bits(command))
                                column >>= 1;
                        chip->cmd_ctrl(mtd, column, ctrl);
                        ctrl &= ~NAND_CTRL_CHANGE;
@@ -1160,9 +1162,11 @@ static int nand_read_page_swecc(struct mtd_info *mtd, struct nand_chip *chip,
  * @data_offs: offset of requested data within the page
  * @readlen: data length
  * @bufpoi: buffer to store read data
+ * @page: page number to read
  */
 static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi)
+                       uint32_t data_offs, uint32_t readlen, uint8_t *bufpoi,
+                       int page)
 {
        int start_step, end_step, num_steps;
        uint32_t *eccpos = chip->ecc.layout->eccpos;
@@ -1170,13 +1174,14 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
        int data_col_addr, i, gaps = 0;
        int datafrag_len, eccfrag_len, aligned_len, aligned_pos;
        int busw = (chip->options & NAND_BUSWIDTH_16) ? 2 : 1;
-       int index = 0;
+       int index;
        unsigned int max_bitflips = 0;
 
        /* Column address within the page aligned to ECC size (256bytes) */
        start_step = data_offs / chip->ecc.size;
        end_step = (data_offs + readlen - 1) / chip->ecc.size;
        num_steps = end_step - start_step + 1;
+       index = start_step * chip->ecc.bytes;
 
        /* Data size aligned to ECC ecc.size */
        datafrag_len = num_steps * chip->ecc.size;
@@ -1213,8 +1218,6 @@ static int nand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
                 * Send the command to read the particular ECC bytes take care
                 * about buswidth alignment in read_buf.
                 */
-               index = start_step * chip->ecc.bytes;
-
                aligned_pos = eccpos[index] & ~(busw - 1);
                aligned_len = eccfrag_len;
                if (eccpos[index] & (busw - 1))
@@ -1538,7 +1541,8 @@ read_retry:
                        else if (!aligned && NAND_HAS_SUBPAGE_READ(chip) &&
                                 !oob)
                                ret = chip->ecc.read_subpage(mtd, chip,
-                                                       col, bytes, bufpoi);
+                                                       col, bytes, bufpoi,
+                                                       page);
                        else
                                ret = chip->ecc.read_page(mtd, chip, bufpoi,
                                                          oob_required, page);
@@ -2000,7 +2004,7 @@ static int nand_write_page_raw_syndrome(struct mtd_info *mtd,
                        oob += chip->ecc.prepad;
                }
 
-               chip->read_buf(mtd, oob, eccbytes);
+               chip->write_buf(mtd, oob, eccbytes);
                oob += eccbytes;
 
                if (chip->ecc.postpad) {
@@ -3063,7 +3067,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
                                        int *busw)
 {
        struct nand_onfi_params *p = &chip->onfi_params;
-       int i;
+       int i, j;
        int val;
 
        /* Try ONFI for unknown chip or LP */
@@ -3072,18 +3076,10 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
                chip->read_byte(mtd) != 'F' || chip->read_byte(mtd) != 'I')
                return 0;
 
-       /*
-        * ONFI must be probed in 8-bit mode or with NAND_BUSWIDTH_AUTO, not
-        * with NAND_BUSWIDTH_16
-        */
-       if (chip->options & NAND_BUSWIDTH_16) {
-               pr_err("ONFI cannot be probed in 16-bit mode; aborting\n");
-               return 0;
-       }
-
        chip->cmdfunc(mtd, NAND_CMD_PARAM, 0, -1);
        for (i = 0; i < 3; i++) {
-               chip->read_buf(mtd, (uint8_t *)p, sizeof(*p));
+               for (j = 0; j < sizeof(*p); j++)
+                       ((uint8_t *)p)[j] = chip->read_byte(mtd);
                if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 254) ==
                                le16_to_cpu(p->crc)) {
                        break;
@@ -3168,6 +3164,87 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
        return 1;
 }
 
+/*
+ * Check if the NAND chip is JEDEC compliant, returns 1 if it is, 0 otherwise.
+ */
+static int nand_flash_detect_jedec(struct mtd_info *mtd, struct nand_chip *chip,
+                                       int *busw)
+{
+       struct nand_jedec_params *p = &chip->jedec_params;
+       struct jedec_ecc_info *ecc;
+       int val;
+       int i, j;
+
+       /* Try JEDEC for unknown chip or LP */
+       chip->cmdfunc(mtd, NAND_CMD_READID, 0x40, -1);
+       if (chip->read_byte(mtd) != 'J' || chip->read_byte(mtd) != 'E' ||
+               chip->read_byte(mtd) != 'D' || chip->read_byte(mtd) != 'E' ||
+               chip->read_byte(mtd) != 'C')
+               return 0;
+
+       chip->cmdfunc(mtd, NAND_CMD_PARAM, 0x40, -1);
+       for (i = 0; i < 3; i++) {
+               for (j = 0; j < sizeof(*p); j++)
+                       ((uint8_t *)p)[j] = chip->read_byte(mtd);
+
+               if (onfi_crc16(ONFI_CRC_BASE, (uint8_t *)p, 510) ==
+                               le16_to_cpu(p->crc))
+                       break;
+       }
+
+       if (i == 3) {
+               pr_err("Could not find valid JEDEC parameter page; aborting\n");
+               return 0;
+       }
+
+       /* Check version */
+       val = le16_to_cpu(p->revision);
+       if (val & (1 << 2))
+               chip->jedec_version = 10;
+       else if (val & (1 << 1))
+               chip->jedec_version = 1; /* vendor specific version */
+
+       if (!chip->jedec_version) {
+               pr_info("unsupported JEDEC version: %d\n", val);
+               return 0;
+       }
+
+       sanitize_string(p->manufacturer, sizeof(p->manufacturer));
+       sanitize_string(p->model, sizeof(p->model));
+       if (!mtd->name)
+               mtd->name = p->model;
+
+       mtd->writesize = le32_to_cpu(p->byte_per_page);
+
+       /* Please reference to the comment for nand_flash_detect_onfi. */
+       mtd->erasesize = 1 << (fls(le32_to_cpu(p->pages_per_block)) - 1);
+       mtd->erasesize *= mtd->writesize;
+
+       mtd->oobsize = le16_to_cpu(p->spare_bytes_per_page);
+
+       /* Please reference to the comment for nand_flash_detect_onfi. */
+       chip->chipsize = 1 << (fls(le32_to_cpu(p->blocks_per_lun)) - 1);
+       chip->chipsize *= (uint64_t)mtd->erasesize * p->lun_count;
+       chip->bits_per_cell = p->bits_per_cell;
+
+       if (jedec_feature(chip) & JEDEC_FEATURE_16_BIT_BUS)
+               *busw = NAND_BUSWIDTH_16;
+       else
+               *busw = 0;
+
+       /* ECC info */
+       ecc = &p->ecc_info[0];
+
+       if (ecc->codeword_size >= 9) {
+               chip->ecc_strength_ds = ecc->ecc_bits;
+               chip->ecc_step_ds = 1 << ecc->codeword_size;
+       } else {
+               pr_warn("Invalid codeword size\n");
+       }
+
+       return 1;
+}
+
 /*
  * nand_id_has_period - Check if an ID string has a given wraparound period
  * @id_data: the ID string
@@ -3474,10 +3551,10 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
  */
 static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                                                  struct nand_chip *chip,
-                                                 int busw,
                                                  int *maf_id, int *dev_id,
                                                  struct nand_flash_dev *type)
 {
+       int busw;
        int i, maf_idx;
        u8 id_data[8];
 
@@ -3533,6 +3610,10 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                /* Check is chip is ONFI compliant */
                if (nand_flash_detect_onfi(mtd, chip, &busw))
                        goto ident_done;
+
+               /* Check if the chip is JEDEC compliant */
+               if (nand_flash_detect_jedec(mtd, chip, &busw))
+                       goto ident_done;
        }
 
        if (!type->name)
@@ -3612,8 +3693,17 @@ ident_done:
 
        pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
                *maf_id, *dev_id);
-       pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
-               chip->onfi_version ? chip->onfi_params.model : type->name);
+
+       if (chip->onfi_version)
+               pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
+                               chip->onfi_params.model);
+       else if (chip->jedec_version)
+               pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
+                               chip->jedec_params.model);
+       else
+               pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
+                               type->name);
+
        pr_info("%dMiB, %s, page size: %d, OOB size: %d\n",
                (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
                mtd->writesize, mtd->oobsize);
@@ -3634,18 +3724,16 @@ ident_done:
 int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                    struct nand_flash_dev *table)
 {
-       int i, busw, nand_maf_id, nand_dev_id;
+       int i, nand_maf_id, nand_dev_id;
        struct nand_chip *chip = mtd->priv;
        struct nand_flash_dev *type;
 
-       /* Get buswidth to select the correct functions */
-       busw = chip->options & NAND_BUSWIDTH_16;
        /* Set the default functions */
-       nand_set_defaults(chip, busw);
+       nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
 
        /* Read the flash type */
-       type = nand_get_flash_type(mtd, chip, busw,
-                               &nand_maf_id, &nand_dev_id, table);
+       type = nand_get_flash_type(mtd, chip, &nand_maf_id,
+                                  &nand_dev_id, table);
 
        if (IS_ERR(type)) {
                if (!(chip->options & NAND_SCAN_SILENT_NODEV))
@@ -3696,15 +3784,26 @@ int nand_scan_tail(struct mtd_info *mtd)
        int i;
        struct nand_chip *chip = mtd->priv;
        struct nand_ecc_ctrl *ecc = &chip->ecc;
+       struct nand_buffers *nbuf;
 
        /* New bad blocks should be marked in OOB, flash-based BBT, or both */
        BUG_ON((chip->bbt_options & NAND_BBT_NO_OOB_BBM) &&
                        !(chip->bbt_options & NAND_BBT_USE_FLASH));
 
-       if (!(chip->options & NAND_OWN_BUFFERS))
-               chip->buffers = kmalloc(sizeof(*chip->buffers), GFP_KERNEL);
-       if (!chip->buffers)
-               return -ENOMEM;
+       if (!(chip->options & NAND_OWN_BUFFERS)) {
+               nbuf = kzalloc(sizeof(*nbuf) + mtd->writesize
+                               + mtd->oobsize * 3, GFP_KERNEL);
+               if (!nbuf)
+                       return -ENOMEM;
+               nbuf->ecccalc = (uint8_t *)(nbuf + 1);
+               nbuf->ecccode = nbuf->ecccalc + mtd->oobsize;
+               nbuf->databuf = nbuf->ecccode + mtd->oobsize;
+
+               chip->buffers = nbuf;
+       } else {
+               if (!chip->buffers)
+                       return -ENOMEM;
+       }
 
        /* Set the internal oob buffer location, just after the page data */
        chip->oob_poi = chip->buffers->databuf + mtd->writesize;
@@ -3825,7 +3924,7 @@ int nand_scan_tail(struct mtd_info *mtd)
 
        case NAND_ECC_SOFT_BCH:
                if (!mtd_nand_has_bch()) {
-                       pr_warn("CONFIG_MTD_ECC_BCH not enabled\n");
+                       pr_warn("CONFIG_MTD_NAND_ECC_BCH not enabled\n");
                        BUG();
                }
                ecc->calculate = nand_bch_calculate_ecc;
index daa2faa..3d7c89f 100644 (file)
@@ -43,6 +43,9 @@ struct nand_flash_dev nand_flash_ids[] = {
        {"TC58NVG6D2 64G 3.3V 8-bit",
                { .id = {0x98, 0xde, 0x94, 0x82, 0x76, 0x56, 0x04, 0x20} },
                  SZ_8K, SZ_8K, SZ_2M, 0, 8, 640, NAND_ECC_INFO(40, SZ_1K) },
+       {"SDTNRGAMA 64G 3.3V 8-bit",
+               { .id = {0x45, 0xde, 0x94, 0x93, 0x76, 0x50} },
+                 SZ_16K, SZ_8K, SZ_4M, 0, 6, 1280, NAND_ECC_INFO(40, SZ_1K) },
 
        LEGACY_ID_NAND("NAND 4MiB 5V 8-bit",   0x6B, 4, SZ_8K, SP_OPTIONS),
        LEGACY_ID_NAND("NAND 4MiB 3,3V 8-bit", 0xE3, 4, SZ_8K, SP_OPTIONS),
index 9ee09a8..e8a5fff 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
@@ -152,7 +151,8 @@ static void nuc900_nand_command_lp(struct mtd_info *mtd, unsigned int command,
        if (column != -1 || page_addr != -1) {
 
                if (column != -1) {
-                       if (chip->options & NAND_BUSWIDTH_16)
+                       if (chip->options & NAND_BUSWIDTH_16 &&
+                                       !nand_opcode_8bits(command))
                                column >>= 1;
                        write_addr_reg(nand, column);
                        write_addr_reg(nand, column >> 8 | ENDADDR);
@@ -225,7 +225,7 @@ static void nuc900_nand_enable(struct nuc900_nand *nand)
        val = __raw_readl(nand->reg + REG_FMICSR);
 
        if (!(val & NAND_EN))
-               __raw_writel(val | NAND_EN, REG_FMICSR);
+               __raw_writel(val | NAND_EN, nand->reg + REG_FMICSR);
 
        val = __raw_readl(nand->reg + REG_SMCSR);
 
index bf642ce..1ff49b8 100644 (file)
 
 #define OMAP24XX_DMA_GPMC              4
 
-#define BCH8_MAX_ERROR         8       /* upto 8 bit correctable */
-#define BCH4_MAX_ERROR         4       /* upto 4 bit correctable */
-
 #define SECTOR_BYTES           512
 /* 4 bit padding to make byte aligned, 56 = 52 + 4 */
 #define BCH4_BIT_PAD           4
-#define BCH8_ECC_MAX           ((SECTOR_BYTES + BCH8_ECC_OOB_BYTES) * 8)
-#define BCH4_ECC_MAX           ((SECTOR_BYTES + BCH4_ECC_OOB_BYTES) * 8)
 
 /* GPMC ecc engine settings for read */
 #define BCH_WRAPMODE_1         1       /* BCH wrap mode 1 */
@@ -159,7 +154,7 @@ struct omap_nand_info {
 
        int                             gpmc_cs;
        unsigned long                   phys_base;
-       unsigned long                   mem_size;
+       enum omap_ecc                   ecc_opt;
        struct completion               comp;
        struct dma_chan                 *dma;
        int                             gpmc_irq_fifo;
@@ -172,7 +167,6 @@ struct omap_nand_info {
        int                                     buf_len;
        struct gpmc_nand_regs           reg;
        /* fields specific for BCHx_HW ECC scheme */
-       bool                            is_elm_used;
        struct device                   *elm_dev;
        struct device_node              *of_node;
 };
@@ -1043,9 +1037,8 @@ static int omap_dev_ready(struct mtd_info *mtd)
        }
 }
 
-#if defined(CONFIG_MTD_NAND_ECC_BCH) || defined(CONFIG_MTD_NAND_OMAP_BCH)
 /**
- * omap3_enable_hwecc_bch - Program OMAP3 GPMC to perform BCH ECC correction
+ * omap_enable_hwecc_bch - Program GPMC to perform BCH ECC calculation
  * @mtd: MTD device structure
  * @mode: Read/Write mode
  *
@@ -1056,50 +1049,73 @@ static int omap_dev_ready(struct mtd_info *mtd)
  * eccsize0 = 0  (no additional protected byte in spare area)
  * eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
  */
-static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
+static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
 {
-       int nerrors;
+       unsigned int bch_type;
        unsigned int dev_width, nsectors;
        struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
                                                   mtd);
+       enum omap_ecc ecc_opt = info->ecc_opt;
        struct nand_chip *chip = mtd->priv;
        u32 val, wr_mode;
        unsigned int ecc_size1, ecc_size0;
 
-       /* Using wrapping mode 6 for writing */
-       wr_mode = BCH_WRAPMODE_6;
-
-       /*
-        * ECC engine enabled for valid ecc_size0 nibbles
-        * and disabled for ecc_size1 nibbles.
-        */
-       ecc_size0 = BCH_ECC_SIZE0;
-       ecc_size1 = BCH_ECC_SIZE1;
-
-       /* Perform ecc calculation on 512-byte sector */
-       nsectors = 1;
-
-       /* Update number of error correction */
-       nerrors = info->nand.ecc.strength;
-
-       /* Multi sector reading/writing for NAND flash with page size < 4096 */
-       if (info->is_elm_used && (mtd->writesize <= 4096)) {
+       /* GPMC configurations for calculating ECC */
+       switch (ecc_opt) {
+       case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+               bch_type = 0;
+               nsectors = 1;
+               if (mode == NAND_ECC_READ) {
+                       wr_mode   = BCH_WRAPMODE_6;
+                       ecc_size0 = BCH_ECC_SIZE0;
+                       ecc_size1 = BCH_ECC_SIZE1;
+               } else {
+                       wr_mode   = BCH_WRAPMODE_6;
+                       ecc_size0 = BCH_ECC_SIZE0;
+                       ecc_size1 = BCH_ECC_SIZE1;
+               }
+               break;
+       case OMAP_ECC_BCH4_CODE_HW:
+               bch_type = 0;
+               nsectors = chip->ecc.steps;
                if (mode == NAND_ECC_READ) {
-                       /* Using wrapping mode 1 for reading */
-                       wr_mode = BCH_WRAPMODE_1;
-
-                       /*
-                        * ECC engine enabled for ecc_size0 nibbles
-                        * and disabled for ecc_size1 nibbles.
-                        */
-                       ecc_size0 = (nerrors == 8) ?
-                               BCH8R_ECC_SIZE0 : BCH4R_ECC_SIZE0;
-                       ecc_size1 = (nerrors == 8) ?
-                               BCH8R_ECC_SIZE1 : BCH4R_ECC_SIZE1;
+                       wr_mode   = BCH_WRAPMODE_1;
+                       ecc_size0 = BCH4R_ECC_SIZE0;
+                       ecc_size1 = BCH4R_ECC_SIZE1;
+               } else {
+                       wr_mode   = BCH_WRAPMODE_6;
+                       ecc_size0 = BCH_ECC_SIZE0;
+                       ecc_size1 = BCH_ECC_SIZE1;
                }
-
-               /* Perform ecc calculation for one page (< 4096) */
-               nsectors = info->nand.ecc.steps;
+               break;
+       case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+               bch_type = 1;
+               nsectors = 1;
+               if (mode == NAND_ECC_READ) {
+                       wr_mode   = BCH_WRAPMODE_6;
+                       ecc_size0 = BCH_ECC_SIZE0;
+                       ecc_size1 = BCH_ECC_SIZE1;
+               } else {
+                       wr_mode   = BCH_WRAPMODE_6;
+                       ecc_size0 = BCH_ECC_SIZE0;
+                       ecc_size1 = BCH_ECC_SIZE1;
+               }
+               break;
+       case OMAP_ECC_BCH8_CODE_HW:
+               bch_type = 1;
+               nsectors = chip->ecc.steps;
+               if (mode == NAND_ECC_READ) {
+                       wr_mode   = BCH_WRAPMODE_1;
+                       ecc_size0 = BCH8R_ECC_SIZE0;
+                       ecc_size1 = BCH8R_ECC_SIZE1;
+               } else {
+                       wr_mode   = BCH_WRAPMODE_6;
+                       ecc_size0 = BCH_ECC_SIZE0;
+                       ecc_size1 = BCH_ECC_SIZE1;
+               }
+               break;
+       default:
+               return;
        }
 
        writel(ECC1, info->reg.gpmc_ecc_control);
@@ -1112,7 +1128,7 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
 
        /* BCH configuration */
        val = ((1                        << 16) | /* enable BCH */
-              (((nerrors == 8) ? 1 : 0) << 12) | /* 8 or 4 bits */
+              (bch_type                 << 12) | /* BCH4/BCH8/BCH16 */
               (wr_mode                  <<  8) | /* wrap mode */
               (dev_width                <<  7) | /* bus width */
               (((nsectors-1) & 0x7)     <<  4) | /* number of sectors */
@@ -1124,132 +1140,40 @@ static void omap3_enable_hwecc_bch(struct mtd_info *mtd, int mode)
        /* Clear ecc and enable bits */
        writel(ECCCLEAR | ECC1, info->reg.gpmc_ecc_control);
 }
-#endif
-
-#ifdef CONFIG_MTD_NAND_ECC_BCH
-/**
- * omap3_calculate_ecc_bch4 - Generate 7 bytes of ECC bytes
- * @mtd: MTD device structure
- * @dat: The pointer to data on which ecc is computed
- * @ecc_code: The ecc_code buffer
- */
-static int omap3_calculate_ecc_bch4(struct mtd_info *mtd, const u_char *dat,
-                                   u_char *ecc_code)
-{
-       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-                                                  mtd);
-       unsigned long nsectors, val1, val2;
-       int i;
-
-       nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
-
-       for (i = 0; i < nsectors; i++) {
 
-               /* Read hw-computed remainder */
-               val1 = readl(info->reg.gpmc_bch_result0[i]);
-               val2 = readl(info->reg.gpmc_bch_result1[i]);
-
-               /*
-                * Add constant polynomial to remainder, in order to get an ecc
-                * sequence of 0xFFs for a buffer filled with 0xFFs; and
-                * left-justify the resulting polynomial.
-                */
-               *ecc_code++ = 0x28 ^ ((val2 >> 12) & 0xFF);
-               *ecc_code++ = 0x13 ^ ((val2 >>  4) & 0xFF);
-               *ecc_code++ = 0xcc ^ (((val2 & 0xF) << 4)|((val1 >> 28) & 0xF));
-               *ecc_code++ = 0x39 ^ ((val1 >> 20) & 0xFF);
-               *ecc_code++ = 0x96 ^ ((val1 >> 12) & 0xFF);
-               *ecc_code++ = 0xac ^ ((val1 >> 4) & 0xFF);
-               *ecc_code++ = 0x7f ^ ((val1 & 0xF) << 4);
-       }
-
-       return 0;
-}
+static u8  bch4_polynomial[] = {0x28, 0x13, 0xcc, 0x39, 0x96, 0xac, 0x7f};
+static u8  bch8_polynomial[] = {0xef, 0x51, 0x2e, 0x09, 0xed, 0x93, 0x9a, 0xc2,
+                               0x97, 0x79, 0xe5, 0x24, 0xb5};
 
 /**
- * omap3_calculate_ecc_bch8 - Generate 13 bytes of ECC bytes
- * @mtd: MTD device structure
- * @dat: The pointer to data on which ecc is computed
- * @ecc_code: The ecc_code buffer
- */
-static int omap3_calculate_ecc_bch8(struct mtd_info *mtd, const u_char *dat,
-                                   u_char *ecc_code)
-{
-       struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
-                                                  mtd);
-       unsigned long nsectors, val1, val2, val3, val4;
-       int i;
-
-       nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
-
-       for (i = 0; i < nsectors; i++) {
-
-               /* Read hw-computed remainder */
-               val1 = readl(info->reg.gpmc_bch_result0[i]);
-               val2 = readl(info->reg.gpmc_bch_result1[i]);
-               val3 = readl(info->reg.gpmc_bch_result2[i]);
-               val4 = readl(info->reg.gpmc_bch_result3[i]);
-
-               /*
-                * Add constant polynomial to remainder, in order to get an ecc
-                * sequence of 0xFFs for a buffer filled with 0xFFs.
-                */
-               *ecc_code++ = 0xef ^ (val4 & 0xFF);
-               *ecc_code++ = 0x51 ^ ((val3 >> 24) & 0xFF);
-               *ecc_code++ = 0x2e ^ ((val3 >> 16) & 0xFF);
-               *ecc_code++ = 0x09 ^ ((val3 >> 8) & 0xFF);
-               *ecc_code++ = 0xed ^ (val3 & 0xFF);
-               *ecc_code++ = 0x93 ^ ((val2 >> 24) & 0xFF);
-               *ecc_code++ = 0x9a ^ ((val2 >> 16) & 0xFF);
-               *ecc_code++ = 0xc2 ^ ((val2 >> 8) & 0xFF);
-               *ecc_code++ = 0x97 ^ (val2 & 0xFF);
-               *ecc_code++ = 0x79 ^ ((val1 >> 24) & 0xFF);
-               *ecc_code++ = 0xe5 ^ ((val1 >> 16) & 0xFF);
-               *ecc_code++ = 0x24 ^ ((val1 >> 8) & 0xFF);
-               *ecc_code++ = 0xb5 ^ (val1 & 0xFF);
-       }
-
-       return 0;
-}
-#endif /* CONFIG_MTD_NAND_ECC_BCH */
-
-#ifdef CONFIG_MTD_NAND_OMAP_BCH
-/**
- * omap3_calculate_ecc_bch - Generate bytes of ECC bytes
+ * omap_calculate_ecc_bch - Generate bytes of ECC bytes
  * @mtd:       MTD device structure
  * @dat:       The pointer to data on which ecc is computed
  * @ecc_code:  The ecc_code buffer
  *
  * Support calculating of BCH4/8 ecc vectors for the page
  */
-static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat,
-                                   u_char *ecc_code)
+static int __maybe_unused omap_calculate_ecc_bch(struct mtd_info *mtd,
+                                       const u_char *dat, u_char *ecc_calc)
 {
        struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
                                                   mtd);
+       int eccbytes    = info->nand.ecc.bytes;
+       struct gpmc_nand_regs   *gpmc_regs = &info->reg;
+       u8 *ecc_code;
        unsigned long nsectors, bch_val1, bch_val2, bch_val3, bch_val4;
-       int i, eccbchtsel;
+       int i;
 
        nsectors = ((readl(info->reg.gpmc_ecc_config) >> 4) & 0x7) + 1;
-       /*
-        * find BCH scheme used
-        * 0 -> BCH4
-        * 1 -> BCH8
-        */
-       eccbchtsel = ((readl(info->reg.gpmc_ecc_config) >> 12) & 0x3);
-
        for (i = 0; i < nsectors; i++) {
-
-               /* Read hw-computed remainder */
-               bch_val1 = readl(info->reg.gpmc_bch_result0[i]);
-               bch_val2 = readl(info->reg.gpmc_bch_result1[i]);
-               if (eccbchtsel) {
-                       bch_val3 = readl(info->reg.gpmc_bch_result2[i]);
-                       bch_val4 = readl(info->reg.gpmc_bch_result3[i]);
-               }
-
-               if (eccbchtsel) {
-                       /* BCH8 ecc scheme */
+               ecc_code = ecc_calc;
+               switch (info->ecc_opt) {
+               case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+               case OMAP_ECC_BCH8_CODE_HW:
+                       bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
+                       bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
+                       bch_val3 = readl(gpmc_regs->gpmc_bch_result2[i]);
+                       bch_val4 = readl(gpmc_regs->gpmc_bch_result3[i]);
                        *ecc_code++ = (bch_val4 & 0xFF);
                        *ecc_code++ = ((bch_val3 >> 24) & 0xFF);
                        *ecc_code++ = ((bch_val3 >> 16) & 0xFF);
@@ -1263,14 +1187,11 @@ static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat,
                        *ecc_code++ = ((bch_val1 >> 16) & 0xFF);
                        *ecc_code++ = ((bch_val1 >> 8) & 0xFF);
                        *ecc_code++ = (bch_val1 & 0xFF);
-                       /*
-                        * Setting 14th byte to zero to handle
-                        * erased page & maintain compatibility
-                        * with RBL
-                        */
-                       *ecc_code++ = 0x0;
-               } else {
-                       /* BCH4 ecc scheme */
+                       break;
+               case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+               case OMAP_ECC_BCH4_CODE_HW:
+                       bch_val1 = readl(gpmc_regs->gpmc_bch_result0[i]);
+                       bch_val2 = readl(gpmc_regs->gpmc_bch_result1[i]);
                        *ecc_code++ = ((bch_val2 >> 12) & 0xFF);
                        *ecc_code++ = ((bch_val2 >> 4) & 0xFF);
                        *ecc_code++ = ((bch_val2 & 0xF) << 4) |
@@ -1279,12 +1200,38 @@ static int omap3_calculate_ecc_bch(struct mtd_info *mtd, const u_char *dat,
                        *ecc_code++ = ((bch_val1 >> 12) & 0xFF);
                        *ecc_code++ = ((bch_val1 >> 4) & 0xFF);
                        *ecc_code++ = ((bch_val1 & 0xF) << 4);
-                       /*
-                        * Setting 8th byte to zero to handle
-                        * erased page
-                        */
-                       *ecc_code++ = 0x0;
+                       break;
+               default:
+                       return -EINVAL;
                }
+
+               /* ECC scheme specific syndrome customizations */
+               switch (info->ecc_opt) {
+               case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
+                       /* Add constant polynomial to remainder, so that
+                        * ECC of blank pages results in 0x0 on reading back */
+                       for (i = 0; i < eccbytes; i++)
+                               ecc_calc[i] ^= bch4_polynomial[i];
+                       break;
+               case OMAP_ECC_BCH4_CODE_HW:
+                       /* Set  8th ECC byte as 0x0 for ROM compatibility */
+                       ecc_calc[eccbytes - 1] = 0x0;
+                       break;
+               case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
+                       /* Add constant polynomial to remainder, so that
+                        * ECC of blank pages results in 0x0 on reading back */
+                       for (i = 0; i < eccbytes; i++)
+                               ecc_calc[i] ^= bch8_polynomial[i];
+                       break;
+               case OMAP_ECC_BCH8_CODE_HW:
+                       /* Set 14th ECC byte as 0x0 for ROM compatibility */
+                       ecc_calc[eccbytes - 1] = 0x0;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+       ecc_calc += eccbytes;
        }
 
        return 0;
@@ -1329,6 +1276,7 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
        return flip_bits;
 }
 
+#ifdef CONFIG_MTD_NAND_OMAP_BCH
 /**
  * omap_elm_correct_data - corrects page data area in case error reported
  * @mtd:       MTD device structure
@@ -1337,55 +1285,46 @@ static int erased_sector_bitflips(u_char *data, u_char *oob,
  * @calc_ecc:  ecc read from HW ECC registers
  *
  * Calculated ecc vector reported as zero in case of non-error pages.
- * In case of error/erased pages non-zero error vector is reported.
- * In case of non-zero ecc vector, check read_ecc at fixed offset
- * (x = 13/7 in case of BCH8/4 == 0) to find page programmed or not.
- * To handle bit flips in this data, count the number of 0's in
- * read_ecc[x] and check if it greater than 4. If it is less, it is
- * programmed page, else erased page.
- *
- * 1. If page is erased, check with standard ecc vector (ecc vector
- * for erased page to find any bit flip). If check fails, bit flip
- * is present in erased page. Count the bit flips in erased page and
- * if it falls under correctable level, report page with 0xFF and
- * update the correctable bit information.
- * 2. If error is reported on programmed page, update elm error
- * vector and correct the page with ELM error correction routine.
- *
+ * In case of non-zero ecc vector, first filter out erased-pages, and
+ * then process data via ELM to detect bit-flips.
  */
 static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
                                u_char *read_ecc, u_char *calc_ecc)
 {
        struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
                        mtd);
+       struct nand_ecc_ctrl *ecc = &info->nand.ecc;
        int eccsteps = info->nand.ecc.steps;
        int i , j, stat = 0;
-       int eccsize, eccflag, ecc_vector_size;
+       int eccflag, actual_eccbytes;
        struct elm_errorvec err_vec[ERROR_VECTOR_MAX];
        u_char *ecc_vec = calc_ecc;
        u_char *spare_ecc = read_ecc;
        u_char *erased_ecc_vec;
-       enum bch_ecc type;
+       u_char *buf;
+       int bitflip_count;
        bool is_error_reported = false;
+       u32 bit_pos, byte_pos, error_max, pos;
+       int err;
 
-       /* Initialize elm error vector to zero */
-       memset(err_vec, 0, sizeof(err_vec));
-
-       if (info->nand.ecc.strength == BCH8_MAX_ERROR) {
-               type = BCH8_ECC;
-               erased_ecc_vec = bch8_vector;
-       } else {
-               type = BCH4_ECC;
+       switch (info->ecc_opt) {
+       case OMAP_ECC_BCH4_CODE_HW:
+               /* omit  7th ECC byte reserved for ROM code compatibility */
+               actual_eccbytes = ecc->bytes - 1;
                erased_ecc_vec = bch4_vector;
+               break;
+       case OMAP_ECC_BCH8_CODE_HW:
+               /* omit 14th ECC byte reserved for ROM code compatibility */
+               actual_eccbytes = ecc->bytes - 1;
+               erased_ecc_vec = bch8_vector;
+               break;
+       default:
+               pr_err("invalid driver configuration\n");
+               return -EINVAL;
        }
 
-       ecc_vector_size = info->nand.ecc.bytes;
-
-       /*
-        * Remove extra byte padding for BCH8 RBL
-        * compatibility and erased page handling
-        */
-       eccsize = ecc_vector_size - 1;
+       /* Initialize elm error vector to zero */
+       memset(err_vec, 0, sizeof(err_vec));
 
        for (i = 0; i < eccsteps ; i++) {
                eccflag = 0;    /* initialize eccflag */
@@ -1394,8 +1333,7 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
                 * Check any error reported,
                 * In case of error, non zero ecc reported.
                 */
-
-               for (j = 0; (j < eccsize); j++) {
+               for (j = 0; j < actual_eccbytes; j++) {
                        if (calc_ecc[j] != 0) {
                                eccflag = 1; /* non zero ecc, error present */
                                break;
@@ -1403,50 +1341,43 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
                }
 
                if (eccflag == 1) {
-                       /*
-                        * Set threshold to minimum of 4, half of ecc.strength/2
-                        * to allow max bit flip in byte to 4
-                        */
-                       unsigned int threshold = min_t(unsigned int, 4,
-                                       info->nand.ecc.strength / 2);
-
-                       /*
-                        * Check data area is programmed by counting
-                        * number of 0's at fixed offset in spare area.
-                        * Checking count of 0's against threshold.
-                        * In case programmed page expects at least threshold
-                        * zeros in byte.
-                        * If zeros are less than threshold for programmed page/
-                        * zeros are more than threshold erased page, either
-                        * case page reported as uncorrectable.
-                        */
-                       if (hweight8(~read_ecc[eccsize]) >= threshold) {
+                       if (memcmp(calc_ecc, erased_ecc_vec,
+                                               actual_eccbytes) == 0) {
                                /*
-                                * Update elm error vector as
-                                * data area is programmed
+                                * calc_ecc[] matches pattern for ECC(all 0xff)
+                                * so this is definitely an erased-page
                                 */
-                               err_vec[i].error_reported = true;
-                               is_error_reported = true;
                        } else {
-                               /* Error reported in erased page */
-                               int bitflip_count;
-                               u_char *buf = &data[info->nand.ecc.size * i];
-
-                               if (memcmp(calc_ecc, erased_ecc_vec, eccsize)) {
-                                       bitflip_count = erased_sector_bitflips(
-                                                       buf, read_ecc, info);
-
-                                       if (bitflip_count)
-                                               stat += bitflip_count;
-                                       else
-                                               return -EINVAL;
+                               buf = &data[info->nand.ecc.size * i];
+                               /*
+                                * count number of 0-bits in read_buf.
+                                * This check can be removed once a similar
+                                * check is introduced in generic NAND driver
+                                */
+                               bitflip_count = erased_sector_bitflips(
+                                               buf, read_ecc, info);
+                               if (bitflip_count) {
+                                       /*
+                                        * number of 0-bits within ECC limits
+                                        * So this may be an erased-page
+                                        */
+                                       stat += bitflip_count;
+                               } else {
+                                       /*
+                                        * Too many 0-bits. It may be a
+                                        * - programmed-page, OR
+                                        * - erased-page with many bit-flips
+                                        * So this page requires check by ELM
+                                        */
+                                       err_vec[i].error_reported = true;
+                                       is_error_reported = true;
                                }
                        }
                }
 
                /* Update the ecc vector */
-               calc_ecc += ecc_vector_size;
-               read_ecc += ecc_vector_size;
+               calc_ecc += ecc->bytes;
+               read_ecc += ecc->bytes;
        }
 
        /* Check if any error reported */
@@ -1456,23 +1387,26 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
        /* Decode BCH error using ELM module */
        elm_decode_bch_error_page(info->elm_dev, ecc_vec, err_vec);
 
+       err = 0;
        for (i = 0; i < eccsteps; i++) {
-               if (err_vec[i].error_reported) {
+               if (err_vec[i].error_uncorrectable) {
+                       pr_err("nand: uncorrectable bit-flips found\n");
+                       err = -EBADMSG;
+               } else if (err_vec[i].error_reported) {
                        for (j = 0; j < err_vec[i].error_count; j++) {
-                               u32 bit_pos, byte_pos, error_max, pos;
-
-                               if (type == BCH8_ECC)
-                                       error_max = BCH8_ECC_MAX;
-                               else
-                                       error_max = BCH4_ECC_MAX;
-
-                               if (info->nand.ecc.strength == BCH8_MAX_ERROR)
-                                       pos = err_vec[i].error_loc[j];
-                               else
-                                       /* Add 4 to take care 4 bit padding */
+                               switch (info->ecc_opt) {
+                               case OMAP_ECC_BCH4_CODE_HW:
+                                       /* Add 4 bits to take care of padding */
                                        pos = err_vec[i].error_loc[j] +
                                                BCH4_BIT_PAD;
-
+                                       break;
+                               case OMAP_ECC_BCH8_CODE_HW:
+                                       pos = err_vec[i].error_loc[j];
+                                       break;
+                               default:
+                                       return -EINVAL;
+                               }
+                               error_max = (ecc->size + actual_eccbytes) * 8;
                                /* Calculate bit position of error */
                                bit_pos = pos % 8;
 
@@ -1480,13 +1414,22 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
                                byte_pos = (error_max - pos - 1) / 8;
 
                                if (pos < error_max) {
-                                       if (byte_pos < 512)
+                                       if (byte_pos < 512) {
+                                               pr_debug("bitflip@dat[%d]=%x\n",
+                                                    byte_pos, data[byte_pos]);
                                                data[byte_pos] ^= 1 << bit_pos;
-                                       else
+                                       } else {
+                                               pr_debug("bitflip@oob[%d]=%x\n",
+                                                       (byte_pos - 512),
+                                                    spare_ecc[byte_pos - 512]);
                                                spare_ecc[byte_pos - 512] ^=
                                                        1 << bit_pos;
+                                       }
+                               } else {
+                                       pr_err("invalid bit-flip @ %d:%d\n",
+                                                        byte_pos, bit_pos);
+                                       err = -EBADMSG;
                                }
-                               /* else, not interested to correct ecc */
                        }
                }
 
@@ -1494,16 +1437,11 @@ static int omap_elm_correct_data(struct mtd_info *mtd, u_char *data,
                stat += err_vec[i].error_count;
 
                /* Update page data with sector size */
-               data += info->nand.ecc.size;
-               spare_ecc += ecc_vector_size;
+               data += ecc->size;
+               spare_ecc += ecc->bytes;
        }
 
-       for (i = 0; i < eccsteps; i++)
-               /* Return error if uncorrectable error present */
-               if (err_vec[i].error_uncorrectable)
-                       return -EINVAL;
-
-       return stat;
+       return (err) ? err : stat;
 }
 
 /**
@@ -1601,7 +1539,8 @@ static int is_elm_present(struct omap_nand_info *info,
                        struct device_node *elm_node, enum bch_ecc bch_type)
 {
        struct platform_device *pdev;
-       info->is_elm_used = false;
+       struct nand_ecc_ctrl *ecc = &info->nand.ecc;
+       int err;
        /* check whether elm-id is passed via DT */
        if (!elm_node) {
                pr_err("nand: error: ELM DT node not found\n");
@@ -1615,10 +1554,10 @@ static int is_elm_present(struct omap_nand_info *info,
        }
        /* ELM module available, now configure it */
        info->elm_dev = &pdev->dev;
-       if (elm_config(info->elm_dev, bch_type))
-               return -ENODEV;
-       info->is_elm_used = true;
-       return 0;
+       err = elm_config(info->elm_dev, bch_type,
+               (info->mtd.writesize / ecc->size), ecc->size, ecc->bytes);
+
+       return err;
 }
 #endif /* CONFIG_MTD_NAND_ECC_BCH */
 
@@ -1657,6 +1596,7 @@ static int omap_nand_probe(struct platform_device *pdev)
        info->gpmc_cs           = pdata->cs;
        info->reg               = pdata->reg;
        info->of_node           = pdata->of_node;
+       info->ecc_opt           = pdata->ecc_opt;
        mtd                     = &info->mtd;
        mtd->priv               = &info->nand;
        mtd->name               = dev_name(&pdev->dev);
@@ -1666,27 +1606,11 @@ static int omap_nand_probe(struct platform_device *pdev)
        nand_chip->options      |= NAND_SKIP_BBTSCAN;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (res == NULL) {
-               err = -EINVAL;
-               dev_err(&pdev->dev, "error getting memory resource\n");
-               goto return_error;
-       }
+       nand_chip->IO_ADDR_R = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nand_chip->IO_ADDR_R))
+               return PTR_ERR(nand_chip->IO_ADDR_R);
 
        info->phys_base = res->start;
-       info->mem_size = resource_size(res);
-
-       if (!devm_request_mem_region(&pdev->dev, info->phys_base,
-                               info->mem_size, pdev->dev.driver->name)) {
-               err = -EBUSY;
-               goto return_error;
-       }
-
-       nand_chip->IO_ADDR_R = devm_ioremap(&pdev->dev, info->phys_base,
-                                               info->mem_size);
-       if (!nand_chip->IO_ADDR_R) {
-               err = -ENOMEM;
-               goto return_error;
-       }
 
        nand_chip->controller = &info->controller;
 
@@ -1812,7 +1736,7 @@ static int omap_nand_probe(struct platform_device *pdev)
        /* populate MTD interface based on ECC scheme */
        nand_chip->ecc.layout   = &omap_oobinfo;
        ecclayout               = &omap_oobinfo;
-       switch (pdata->ecc_opt) {
+       switch (info->ecc_opt) {
        case OMAP_ECC_HAM1_CODE_HW:
                pr_info("nand: using OMAP_ECC_HAM1_CODE_HW\n");
                nand_chip->ecc.mode             = NAND_ECC_HW;
@@ -1844,9 +1768,9 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.size             = 512;
                nand_chip->ecc.bytes            = 7;
                nand_chip->ecc.strength         = 4;
-               nand_chip->ecc.hwctl            = omap3_enable_hwecc_bch;
+               nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
                nand_chip->ecc.correct          = nand_bch_correct_data;
-               nand_chip->ecc.calculate        = omap3_calculate_ecc_bch4;
+               nand_chip->ecc.calculate        = omap_calculate_ecc_bch;
                /* define ECC layout */
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
@@ -1884,9 +1808,9 @@ static int omap_nand_probe(struct platform_device *pdev)
                /* 14th bit is kept reserved for ROM-code compatibility */
                nand_chip->ecc.bytes            = 7 + 1;
                nand_chip->ecc.strength         = 4;
-               nand_chip->ecc.hwctl            = omap3_enable_hwecc_bch;
+               nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
                nand_chip->ecc.correct          = omap_elm_correct_data;
-               nand_chip->ecc.calculate        = omap3_calculate_ecc_bch;
+               nand_chip->ecc.calculate        = omap_calculate_ecc_bch;
                nand_chip->ecc.read_page        = omap_read_page_bch;
                nand_chip->ecc.write_page       = omap_write_page_bch;
                /* define ECC layout */
@@ -1919,9 +1843,9 @@ static int omap_nand_probe(struct platform_device *pdev)
                nand_chip->ecc.size             = 512;
                nand_chip->ecc.bytes            = 13;
                nand_chip->ecc.strength         = 8;
-               nand_chip->ecc.hwctl            = omap3_enable_hwecc_bch;
+               nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
                nand_chip->ecc.correct          = nand_bch_correct_data;
-               nand_chip->ecc.calculate        = omap3_calculate_ecc_bch8;
+               nand_chip->ecc.calculate        = omap_calculate_ecc_bch;
                /* define ECC layout */
                ecclayout->eccbytes             = nand_chip->ecc.bytes *
                                                        (mtd->writesize /
@@ -1960,9 +1884,9 @@ static int omap_nand_probe(struct platform_device *pdev)
                /* 14th bit is kept reserved for ROM-code compatibility */
                nand_chip->ecc.bytes            = 13 + 1;
                nand_chip->ecc.strength         = 8;
-               nand_chip->ecc.hwctl            = omap3_enable_hwecc_bch;
+               nand_chip->ecc.hwctl            = omap_enable_hwecc_bch;
                nand_chip->ecc.correct          = omap_elm_correct_data;
-               nand_chip->ecc.calculate        = omap3_calculate_ecc_bch;
+               nand_chip->ecc.calculate        = omap_calculate_ecc_bch;
                nand_chip->ecc.read_page        = omap_read_page_bch;
                nand_chip->ecc.write_page       = omap_write_page_bch;
                /* This ECC scheme requires ELM H/W block */
index 90f871a..2c98f9d 100644 (file)
@@ -23,7 +23,6 @@
 #undef DEBUG
 
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/nand.h>
index 2a7a0b2..7588fe2 100644 (file)
@@ -38,7 +38,6 @@
 
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
 
-#define NAND_DEV_READY_TIMEOUT  50
 #define        CHIP_DELAY_TIMEOUT      (2 * HZ/10)
 #define NAND_STOP_DELAY                (2 * HZ/50)
 #define PAGE_CHUNK_SIZE                (2048)
@@ -1531,7 +1530,7 @@ KEEP_CONFIG:
        if (!ret) {
                dev_err(&info->pdev->dev,
                        "ECC strength %d at page size %d is not supported\n",
-                       chip->ecc_strength_ds, mtd->writesize);
+                       ecc_strength, mtd->writesize);
                return -ENODEV;
        }
 
index f0918e7..79acbb8 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <linux/module.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/io.h>
index 8e1919b..093c29a 100644 (file)
@@ -13,7 +13,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
index 6547c84..d945473 100644 (file)
@@ -25,7 +25,6 @@
 
 #include <linux/device.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/onenand.h>
 #include <linux/mtd/partitions.h>
index 1de33b5..635ee00 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/delay.h>
 #include <linux/interrupt.h>
@@ -3238,20 +3237,17 @@ static int onenand_otp_walk(struct mtd_info *mtd, loff_t from, size_t len,
 /**
  * onenand_get_fact_prot_info - [MTD Interface] Read factory OTP info
  * @param mtd          MTD device structure
- * @param buf          the databuffer to put/get data
  * @param len          number of bytes to read
+ * @param retlen       pointer to variable to store the number of read bytes
+ * @param buf          the databuffer to put/get data
  *
  * Read factory OTP info.
  */
-static int onenand_get_fact_prot_info(struct mtd_info *mtd,
-                       struct otp_info *buf, size_t len)
+static int onenand_get_fact_prot_info(struct mtd_info *mtd, size_t len,
+                                     size_t *retlen, struct otp_info *buf)
 {
-       size_t retlen;
-       int ret;
-
-       ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_FACTORY);
-
-       return ret ? : retlen;
+       return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL,
+                               MTD_OTP_FACTORY);
 }
 
 /**
@@ -3273,20 +3269,17 @@ static int onenand_read_fact_prot_reg(struct mtd_info *mtd, loff_t from,
 /**
  * onenand_get_user_prot_info - [MTD Interface] Read user OTP info
  * @param mtd          MTD device structure
- * @param buf          the databuffer to put/get data
+ * @param retlen       pointer to variable to store the number of read bytes
  * @param len          number of bytes to read
+ * @param buf          the databuffer to put/get data
  *
  * Read user OTP info.
  */
-static int onenand_get_user_prot_info(struct mtd_info *mtd,
-                       struct otp_info *buf, size_t len)
+static int onenand_get_user_prot_info(struct mtd_info *mtd, size_t len,
+                                     size_t *retlen, struct otp_info *buf)
 {
-       size_t retlen;
-       int ret;
-
-       ret = onenand_otp_walk(mtd, 0, len, &retlen, (u_char *) buf, NULL, MTD_OTP_USER);
-
-       return ret ? : retlen;
+       return onenand_otp_walk(mtd, 0, len, retlen, (u_char *) buf, NULL,
+                               MTD_OTP_USER);
 }
 
 /**
@@ -3995,11 +3988,8 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
        /* Allocate buffers, if necessary */
        if (!this->page_buf) {
                this->page_buf = kzalloc(mtd->writesize, GFP_KERNEL);
-               if (!this->page_buf) {
-                       printk(KERN_ERR "%s: Can't allocate page_buf\n",
-                               __func__);
+               if (!this->page_buf)
                        return -ENOMEM;
-               }
 #ifdef CONFIG_MTD_ONENAND_VERIFY_WRITE
                this->verify_buf = kzalloc(mtd->writesize, GFP_KERNEL);
                if (!this->verify_buf) {
@@ -4012,8 +4002,6 @@ int onenand_scan(struct mtd_info *mtd, int maxchips)
        if (!this->oob_buf) {
                this->oob_buf = kzalloc(mtd->oobsize, GFP_KERNEL);
                if (!this->oob_buf) {
-                       printk(KERN_ERR "%s: Can't allocate oob_buf\n",
-                               __func__);
                        if (this->options & ONENAND_PAGEBUF_ALLOC) {
                                this->options &= ~ONENAND_PAGEBUF_ALLOC;
                                kfree(this->page_buf);
index df7400d..b1a792f 100644 (file)
@@ -872,10 +872,8 @@ static int s3c_onenand_probe(struct platform_device *pdev)
 
        size = sizeof(struct mtd_info) + sizeof(struct onenand_chip);
        mtd = kzalloc(size, GFP_KERNEL);
-       if (!mtd) {
-               dev_err(&pdev->dev, "failed to allocate memory\n");
+       if (!mtd)
                return -ENOMEM;
-       }
 
        onenand = kzalloc(sizeof(struct s3c_onenand), GFP_KERNEL);
        if (!onenand) {
index 233b946..d1cbf26 100644 (file)
@@ -602,8 +602,7 @@ static int mark_sector_deleted(struct partition *part, u_long old_addr)
        if (rc) {
                printk(KERN_ERR PREFIX "error writing '%s' at "
                        "0x%lx\n", part->mbd.mtd->name, addr);
-               if (rc)
-                       goto err;
+               goto err;
        }
        if (block == part->current_block)
                part->header_cache[offset + HEADER_MAP_OFFSET] = del;
@@ -675,8 +674,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
        if (rc) {
                printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n",
                                part->mbd.mtd->name, addr);
-               if (rc)
-                       goto err;
+               goto err;
        }
 
        part->sector_map[sector] = addr;
@@ -695,8 +693,7 @@ static int do_writesect(struct mtd_blktrans_dev *dev, u_long sector, char *buf,
        if (rc) {
                printk(KERN_ERR PREFIX "error writing '%s' at 0x%lx\n",
                                part->mbd.mtd->name, addr);
-               if (rc)
-                       goto err;
+               goto err;
        }
        block->used_sectors++;
        block->free_sectors--;
index 4b8e895..cf49c22 100644 (file)
@@ -59,15 +59,12 @@ static struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
        struct attribute_group *attr_group;
        struct attribute **attributes;
        struct sm_sysfs_attribute *vendor_attribute;
+       char *vendor;
 
-       int vendor_len = strnlen(ftl->cis_buffer + SM_CIS_VENDOR_OFFSET,
-                                       SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET);
-
-       char *vendor = kmalloc(vendor_len, GFP_KERNEL);
+       vendor = kstrndup(ftl->cis_buffer + SM_CIS_VENDOR_OFFSET,
+                         SM_SMALL_PAGE - SM_CIS_VENDOR_OFFSET, GFP_KERNEL);
        if (!vendor)
                goto error1;
-       memcpy(vendor, ftl->cis_buffer + SM_CIS_VENDOR_OFFSET, vendor_len);
-       vendor[vendor_len] = 0;
 
        /* Initialize sysfs attributes */
        vendor_attribute =
@@ -78,7 +75,7 @@ static struct attribute_group *sm_create_sysfs_attributes(struct sm_ftl *ftl)
        sysfs_attr_init(&vendor_attribute->dev_attr.attr);
 
        vendor_attribute->data = vendor;
-       vendor_attribute->len = vendor_len;
+       vendor_attribute->len = strlen(vendor);
        vendor_attribute->dev_attr.attr.name = "vendor";
        vendor_attribute->dev_attr.attr.mode = S_IRUGO;
        vendor_attribute->dev_attr.show = sm_attr_show;
index c818a63..111ee46 100644 (file)
@@ -1,6 +1,5 @@
 #define pr_fmt(fmt) "mtd_test: " fmt
 
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/printk.h>
index 0ba8b0a..7bf4163 100644 (file)
@@ -22,7 +22,6 @@
 #ifndef __UBI_UBI_H__
 #define __UBI_UBI_H__
 
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/list.h>
 #include <linux/rbtree.h>
index 95a6ca7..d9f8546 100644 (file)
@@ -3077,7 +3077,7 @@ static int bond_open(struct net_device *bond_dev)
        if (bond_has_slaves(bond)) {
                read_lock(&bond->curr_slave_lock);
                bond_for_each_slave(bond, slave, iter) {
-                       if ((bond->params.mode == BOND_MODE_ACTIVEBACKUP)
+                       if (USES_PRIMARY(bond->params.mode)
                                && (slave != bond->curr_active_slave)) {
                                bond_set_slave_inactive_flags(slave,
                                                              BOND_SLAVE_NOTIFY_NOW);
index 4b18b87..1e65cb6 100644 (file)
@@ -39,7 +39,7 @@ config CAN_EMS_PCI
 config CAN_PEAK_PCMCIA
        tristate "PEAK PCAN-PC Card"
        depends on PCMCIA
-       depends on HAS_IOPORT
+       depends on HAS_IOPORT_MAP
        ---help---
          This driver is for the PCAN-PC Card PCMCIA adapter (1 or 2 channels)
          from PEAK-System (http://www.peak-system.com). To compile this
index 65b735d..afaab4b 100644 (file)
@@ -66,7 +66,7 @@ config PCMCIA_3C589
 
 config VORTEX
        tristate "3c590/3c900 series (592/595/597) \"Vortex/Boomerang\" support"
-       depends on (PCI || EISA) && HAS_IOPORT
+       depends on (PCI || EISA) && HAS_IOPORT_MAP
        select MII
        ---help---
          This option enables driver support for a large number of 10Mbps and
index 05f4f5f..3448cc0 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/irq.h>
 
 #include "bnx2x.h"
 #include "bnx2x_sriov.h"
index adf8acb..0966bd0 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/dma-mapping.h>
 #include <linux/pm.h>
 #include <linux/clk.h>
-#include <linux/version.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
index ce75de9..4a79eda 100644 (file)
@@ -342,6 +342,9 @@ static int __init at91ether_probe(struct platform_device *pdev)
        }
        clk_enable(lp->pclk);
 
+       lp->hclk = ERR_PTR(-ENOENT);
+       lp->tx_clk = ERR_PTR(-ENOENT);
+
        /* Install the interrupt handler */
        dev->irq = platform_get_irq(pdev, 0);
        res = devm_request_irq(&pdev->dev, dev->irq, at91ether_interrupt, 0, dev->name, dev);
index e9f7c65..e35c8e0 100644 (file)
@@ -29,6 +29,7 @@
 #include "vnic_stats.h"
 #include "vnic_nic.h"
 #include "vnic_rss.h"
+#include <linux/irq.h>
 
 #define DRV_NAME               "enic"
 #define DRV_DESCRIPTION                "Cisco VIC Ethernet NIC Driver"
index f31bb5e..7b52a88 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/ethtool.h>
 #include <linux/mii.h>
 #include <linux/timer.h>
+#include <linux/irq.h>
 
 #include <linux/vmalloc.h>
 
index 7902341..2360d81 100644 (file)
@@ -3,14 +3,30 @@
 #
 
 config NET_VENDOR_SAMSUNG
-       bool "Samsung Ethernet device"
+       bool "Samsung Ethernet devices"
        default y
        ---help---
-         This is the driver for the SXGBE 10G Ethernet IP block found on Samsung
-         platforms.
+         If you have a network (Ethernet) chipset belonging to this class,
+         say Y.
+
+         Note that the answer to this question does not directly affect
+         the kernel: saying N will just case the configurator to skip all
+         the questions about Samsung chipsets. If you say Y, you will be asked
+         for your specific chipset/driver in the following questions.
 
 if NET_VENDOR_SAMSUNG
 
-source "drivers/net/ethernet/samsung/sxgbe/Kconfig"
+config SXGBE_ETH
+       tristate "Samsung 10G/2.5G/1G SXGBE Ethernet driver"
+       depends on HAS_IOMEM && HAS_DMA
+       select PHYLIB
+       select CRC32
+       select PTP_1588_CLOCK
+       ---help---
+         This is the driver for the SXGBE 10G Ethernet IP block found on
+         Samsung platforms.
+
+         To compile this driver as a module, choose M here: the module
+         will be called samsung-sxgbe.
 
 endif # NET_VENDOR_SAMSUNG
diff --git a/drivers/net/ethernet/samsung/sxgbe/Kconfig b/drivers/net/ethernet/samsung/sxgbe/Kconfig
deleted file mode 100644 (file)
index d79288c..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-config SXGBE_ETH
-       tristate "Samsung 10G/2.5G/1G SXGBE Ethernet driver"
-       depends on HAS_IOMEM && HAS_DMA
-       select PHYLIB
-       select CRC32
-       select PTP_1588_CLOCK
-       ---help---
-         This is the driver for the SXGBE 10G Ethernet IP block found on Samsung
-         platforms.
index 28f89c4..4d989ff 100644 (file)
@@ -9,7 +9,6 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#include <linux/io.h>
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/io.h>
index a72688e..27e8c82 100644 (file)
@@ -2113,11 +2113,11 @@ struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device,
        /* allocate memory resources for Descriptor rings */
        ret = txring_mem_alloc(priv);
        if (ret)
-               goto error_free_netdev;
+               goto error_free_hw;
 
        ret = rxring_mem_alloc(priv);
        if (ret)
-               goto error_free_netdev;
+               goto error_free_hw;
 
        ndev->netdev_ops = &sxgbe_netdev_ops;
 
@@ -2163,7 +2163,7 @@ struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device,
        if (IS_ERR(priv->sxgbe_clk)) {
                netdev_warn(ndev, "%s: warning: cannot get CSR clock\n",
                            __func__);
-               goto error_clk_get;
+               goto error_napi_del;
        }
 
        /* If a specific clk_csr value is passed from the platform
@@ -2182,24 +2182,27 @@ struct sxgbe_priv_data *sxgbe_drv_probe(struct device *device,
        if (ret < 0) {
                netdev_dbg(ndev, "%s: MDIO bus (id: %d) registration failed\n",
                           __func__, priv->plat->bus_id);
-               goto error_mdio_register;
+               goto error_clk_put;
        }
 
        ret = register_netdev(ndev);
        if (ret) {
                pr_err("%s: ERROR %i registering the device\n", __func__, ret);
-               goto error_netdev_register;
+               goto error_mdio_unregister;
        }
 
        sxgbe_check_ether_addr(priv);
 
        return priv;
 
-error_mdio_register:
+error_mdio_unregister:
+       sxgbe_mdio_unregister(ndev);
+error_clk_put:
        clk_put(priv->sxgbe_clk);
-error_clk_get:
-error_netdev_register:
+error_napi_del:
        netif_napi_del(&priv->napi);
+error_free_hw:
+       kfree(priv->hw);
 error_free_netdev:
        free_netdev(ndev);
 
@@ -2224,11 +2227,15 @@ int sxgbe_drv_remove(struct net_device *ndev)
        priv->hw->mac->enable_tx(priv->ioaddr, false);
        priv->hw->mac->enable_rx(priv->ioaddr, false);
 
-       netif_napi_del(&priv->napi);
+       unregister_netdev(ndev);
 
        sxgbe_mdio_unregister(ndev);
 
-       unregister_netdev(ndev);
+       clk_put(priv->sxgbe_clk);
+
+       netif_napi_del(&priv->napi);
+
+       kfree(priv->hw);
 
        free_netdev(ndev);
 
index 66b05e6..1c44e67 100644 (file)
@@ -1211,7 +1211,6 @@ static void
 smc911x_rx_dma_irq(int dma, void *data)
 {
        struct net_device *dev = (struct net_device *)data;
-       unsigned long ioaddr = dev->base_addr;
        struct smc911x_local *lp = netdev_priv(dev);
        struct sk_buff *skb = lp->current_rx_skb;
        unsigned long flags;
index a3bbf59..2435139 100644 (file)
@@ -26,6 +26,8 @@
 #include <linux/time.h>
 #include <linux/uaccess.h>
 #include <linux/workqueue.h>
+#include <linux/if_ether.h>
+#include <linux/if_vlan.h>
 
 #include "cpts.h"
 
index 89417ac..430bb0d 100644 (file)
@@ -852,7 +852,7 @@ at86rf212_set_csma_params(struct ieee802154_dev *dev, u8 min_be, u8 max_be,
        if (rc)
                return rc;
 
-       return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, max_be);
+       return at86rf230_write_subreg(lp, SR_MAX_CSMA_RETRIES, retries);
 }
 
 static int
index 4cf5fb9..22b047f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * SPI driver for Micrel/Kendin KS8995M ethernet switch
+ * SPI driver for Micrel/Kendin KS8995M and KSZ8864RMN ethernet switches
  *
  * Copyright (C) 2008 Gabor Juhos <juhosg at openwrt.org>
  *
 #define KS8995_REG_IAD1                0x76    /* Indirect Access Data 1 */
 #define KS8995_REG_IAD0                0x77    /* Indirect Access Data 0 */
 
+#define KSZ8864_REG_ID1                0xfe    /* Chip ID in bit 7 */
+
 #define KS8995_REGS_SIZE       0x80
+#define KSZ8864_REGS_SIZE      0x100
 
 #define ID1_CHIPID_M           0xf
 #define ID1_CHIPID_S           4
@@ -94,6 +97,7 @@ struct ks8995_switch {
        struct spi_device       *spi;
        struct mutex            lock;
        struct ks8995_pdata     *pdata;
+       struct bin_attribute    regs_attr;
 };
 
 static inline u8 get_chip_id(u8 val)
@@ -216,11 +220,11 @@ static ssize_t ks8995_registers_read(struct file *filp, struct kobject *kobj,
        dev = container_of(kobj, struct device, kobj);
        ks8995 = dev_get_drvdata(dev);
 
-       if (unlikely(off > KS8995_REGS_SIZE))
+       if (unlikely(off > ks8995->regs_attr.size))
                return 0;
 
-       if ((off + count) > KS8995_REGS_SIZE)
-               count = KS8995_REGS_SIZE - off;
+       if ((off + count) > ks8995->regs_attr.size)
+               count = ks8995->regs_attr.size - off;
 
        if (unlikely(!count))
                return count;
@@ -238,11 +242,11 @@ static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj,
        dev = container_of(kobj, struct device, kobj);
        ks8995 = dev_get_drvdata(dev);
 
-       if (unlikely(off >= KS8995_REGS_SIZE))
+       if (unlikely(off >= ks8995->regs_attr.size))
                return -EFBIG;
 
-       if ((off + count) > KS8995_REGS_SIZE)
-               count = KS8995_REGS_SIZE - off;
+       if ((off + count) > ks8995->regs_attr.size)
+               count = ks8995->regs_attr.size - off;
 
        if (unlikely(!count))
                return count;
@@ -251,7 +255,7 @@ static ssize_t ks8995_registers_write(struct file *filp, struct kobject *kobj,
 }
 
 
-static struct bin_attribute ks8995_registers_attr = {
+static const struct bin_attribute ks8995_registers_attr = {
        .attr = {
                .name   = "registers",
                .mode   = S_IRUSR | S_IWUSR,
@@ -306,20 +310,44 @@ static int ks8995_probe(struct spi_device *spi)
                goto err_drvdata;
        }
 
+       memcpy(&ks->regs_attr, &ks8995_registers_attr, sizeof(ks->regs_attr));
+       if (get_chip_id(ids[1]) != CHIPID_M) {
+               u8 val;
+
+               /* Check if this is a KSZ8864RMN */
+               err = ks8995_read(ks, &val, KSZ8864_REG_ID1, sizeof(val));
+               if (err < 0) {
+                       dev_err(&spi->dev,
+                               "unable to read chip id register, err=%d\n",
+                               err);
+                       goto err_drvdata;
+               }
+               if ((val & 0x80) == 0) {
+                       dev_err(&spi->dev, "unknown chip:%02x,0\n", ids[1]);
+                       goto err_drvdata;
+               }
+               ks->regs_attr.size = KSZ8864_REGS_SIZE;
+       }
+
        err = ks8995_reset(ks);
        if (err)
                goto err_drvdata;
 
-       err = sysfs_create_bin_file(&spi->dev.kobj, &ks8995_registers_attr);
+       err = sysfs_create_bin_file(&spi->dev.kobj, &ks->regs_attr);
        if (err) {
                dev_err(&spi->dev, "unable to create sysfs file, err=%d\n",
                                    err);
                goto err_drvdata;
        }
 
-       dev_info(&spi->dev, "KS89%02X device found, Chip ID:%01x, "
-                       "Revision:%01x\n", ids[0],
-                       get_chip_id(ids[1]), get_chip_rev(ids[1]));
+       if (get_chip_id(ids[1]) == CHIPID_M) {
+               dev_info(&spi->dev,
+                        "KS8995 device found, Chip ID:%x, Revision:%x\n",
+                        get_chip_id(ids[1]), get_chip_rev(ids[1]));
+       } else {
+               dev_info(&spi->dev, "KSZ8864 device found, Revision:%x\n",
+                        get_chip_rev(ids[1]));
+       }
 
        return 0;
 
index 6d1f6ed..a849718 100644 (file)
@@ -493,6 +493,7 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
        ndev->netdev_ops = &rionet_netdev_ops;
        ndev->mtu = RIO_MAX_MSG_SIZE - 14;
        ndev->features = NETIF_F_LLTX;
+       SET_NETDEV_DEV(ndev, &mport->dev);
        SET_ETHTOOL_OPS(ndev, &rionet_ethtool_ops);
 
        spin_lock_init(&rnet->lock);
index 0d862a5..c55e316 100644 (file)
@@ -871,6 +871,9 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
        if (err)
                return err;
 
+       if (vxlan->default_dst.remote_ip.sa.sa_family != ip.sa.sa_family)
+               return -EAFNOSUPPORT;
+
        spin_lock_bh(&vxlan->hash_lock);
        err = vxlan_fdb_create(vxlan, addr, &ip, ndm->ndm_state, flags,
                               port, vni, ifindex, ndm->ndm_flags);
@@ -2601,9 +2604,10 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
        vni = nla_get_u32(data[IFLA_VXLAN_ID]);
        dst->remote_vni = vni;
 
+       /* Unless IPv6 is explicitly requested, assume IPv4 */
+       dst->remote_ip.sa.sa_family = AF_INET;
        if (data[IFLA_VXLAN_GROUP]) {
                dst->remote_ip.sin.sin_addr.s_addr = nla_get_be32(data[IFLA_VXLAN_GROUP]);
-               dst->remote_ip.sa.sa_family = AF_INET;
        } else if (data[IFLA_VXLAN_GROUP6]) {
                if (!IS_ENABLED(CONFIG_IPV6))
                        return -EPFNOSUPPORT;
index 89d1d05..630a3fc 100644 (file)
@@ -124,6 +124,7 @@ struct xenvif {
        struct pending_tx_info pending_tx_info[MAX_PENDING_REQS];
        grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
 
+       struct gnttab_copy tx_copy_ops[MAX_PENDING_REQS];
        struct gnttab_map_grant_ref tx_map_ops[MAX_PENDING_REQS];
        struct gnttab_unmap_grant_ref tx_unmap_ops[MAX_PENDING_REQS];
        /* passed to gnttab_[un]map_refs with pages under (un)mapping */
index 3f021e0..7666540 100644 (file)
@@ -820,13 +820,13 @@ struct xenvif_tx_cb {
 
 #define XENVIF_TX_CB(skb) ((struct xenvif_tx_cb *)(skb)->cb)
 
-static inline void xenvif_tx_create_gop(struct xenvif *vif,
-                                       u16 pending_idx,
-                                       struct xen_netif_tx_request *txp,
-                                       struct gnttab_map_grant_ref *gop)
+static inline void xenvif_tx_create_map_op(struct xenvif *vif,
+                                         u16 pending_idx,
+                                         struct xen_netif_tx_request *txp,
+                                         struct gnttab_map_grant_ref *mop)
 {
-       vif->pages_to_map[gop-vif->tx_map_ops] = vif->mmap_pages[pending_idx];
-       gnttab_set_map_op(gop, idx_to_kaddr(vif, pending_idx),
+       vif->pages_to_map[mop-vif->tx_map_ops] = vif->mmap_pages[pending_idx];
+       gnttab_set_map_op(mop, idx_to_kaddr(vif, pending_idx),
                          GNTMAP_host_map | GNTMAP_readonly,
                          txp->gref, vif->domid);
 
@@ -880,7 +880,7 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif,
             shinfo->nr_frags++, txp++, gop++) {
                index = pending_index(vif->pending_cons++);
                pending_idx = vif->pending_ring[index];
-               xenvif_tx_create_gop(vif, pending_idx, txp, gop);
+               xenvif_tx_create_map_op(vif, pending_idx, txp, gop);
                frag_set_pending_idx(&frags[shinfo->nr_frags], pending_idx);
        }
 
@@ -900,7 +900,7 @@ static struct gnttab_map_grant_ref *xenvif_get_requests(struct xenvif *vif,
                     shinfo->nr_frags++, txp++, gop++) {
                        index = pending_index(vif->pending_cons++);
                        pending_idx = vif->pending_ring[index];
-                       xenvif_tx_create_gop(vif, pending_idx, txp, gop);
+                       xenvif_tx_create_map_op(vif, pending_idx, txp, gop);
                        frag_set_pending_idx(&frags[shinfo->nr_frags],
                                             pending_idx);
                }
@@ -940,38 +940,42 @@ static inline void xenvif_grant_handle_reset(struct xenvif *vif,
 
 static int xenvif_tx_check_gop(struct xenvif *vif,
                               struct sk_buff *skb,
-                              struct gnttab_map_grant_ref **gopp)
+                              struct gnttab_map_grant_ref **gopp_map,
+                              struct gnttab_copy **gopp_copy)
 {
-       struct gnttab_map_grant_ref *gop = *gopp;
+       struct gnttab_map_grant_ref *gop_map = *gopp_map;
        u16 pending_idx = XENVIF_TX_CB(skb)->pending_idx;
        struct skb_shared_info *shinfo = skb_shinfo(skb);
-       struct pending_tx_info *tx_info;
        int nr_frags = shinfo->nr_frags;
-       int i, err, start;
+       int i, err;
        struct sk_buff *first_skb = NULL;
 
        /* Check status of header. */
-       err = gop->status;
-       if (unlikely(err))
+       err = (*gopp_copy)->status;
+       (*gopp_copy)++;
+       if (unlikely(err)) {
+               if (net_ratelimit())
+                       netdev_dbg(vif->dev,
+                                  "Grant copy of header failed! status: %d pending_idx: %u ref: %u\n",
+                                  (*gopp_copy)->status,
+                                  pending_idx,
+                                  (*gopp_copy)->source.u.ref);
                xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
-       else
-               xenvif_grant_handle_set(vif, pending_idx , gop->handle);
-
-       /* Skip first skb fragment if it is on same page as header fragment. */
-       start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
+       }
 
 check_frags:
-       for (i = start; i < nr_frags; i++) {
+       for (i = 0; i < nr_frags; i++, gop_map++) {
                int j, newerr;
 
                pending_idx = frag_get_pending_idx(&shinfo->frags[i]);
-               tx_info = &vif->pending_tx_info[pending_idx];
 
                /* Check error status: if okay then remember grant handle. */
-               newerr = (++gop)->status;
+               newerr = gop_map->status;
 
                if (likely(!newerr)) {
-                       xenvif_grant_handle_set(vif, pending_idx , gop->handle);
+                       xenvif_grant_handle_set(vif,
+                                               pending_idx,
+                                               gop_map->handle);
                        /* Had a previous error? Invalidate this fragment. */
                        if (unlikely(err))
                                xenvif_idx_unmap(vif, pending_idx);
@@ -979,18 +983,20 @@ check_frags:
                }
 
                /* Error on this fragment: respond to client with an error. */
+               if (net_ratelimit())
+                       netdev_dbg(vif->dev,
+                                  "Grant map of %d. frag failed! status: %d pending_idx: %u ref: %u\n",
+                                  i,
+                                  gop_map->status,
+                                  pending_idx,
+                                  gop_map->ref);
                xenvif_idx_release(vif, pending_idx, XEN_NETIF_RSP_ERROR);
 
                /* Not the first error? Preceding frags already invalidated. */
                if (err)
                        continue;
-               /* First error: invalidate header and preceding fragments. */
-               if (!first_skb)
-                       pending_idx = XENVIF_TX_CB(skb)->pending_idx;
-               else
-                       pending_idx = XENVIF_TX_CB(skb)->pending_idx;
-               xenvif_idx_unmap(vif, pending_idx);
-               for (j = start; j < i; j++) {
+               /* First error: invalidate preceding fragments. */
+               for (j = 0; j < i; j++) {
                        pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
                        xenvif_idx_unmap(vif, pending_idx);
                }
@@ -1004,7 +1010,6 @@ check_frags:
                skb = shinfo->frag_list;
                shinfo = skb_shinfo(skb);
                nr_frags = shinfo->nr_frags;
-               start = 0;
 
                goto check_frags;
        }
@@ -1015,15 +1020,13 @@ check_frags:
        if (first_skb && err) {
                int j;
                shinfo = skb_shinfo(first_skb);
-               pending_idx = XENVIF_TX_CB(skb)->pending_idx;
-               start = (frag_get_pending_idx(&shinfo->frags[0]) == pending_idx);
-               for (j = start; j < shinfo->nr_frags; j++) {
+               for (j = 0; j < shinfo->nr_frags; j++) {
                        pending_idx = frag_get_pending_idx(&shinfo->frags[j]);
                        xenvif_idx_unmap(vif, pending_idx);
                }
        }
 
-       *gopp = gop + 1;
+       *gopp_map = gop_map;
        return err;
 }
 
@@ -1034,9 +1037,6 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
        int i;
        u16 prev_pending_idx = INVALID_PENDING_IDX;
 
-       if (skb_shinfo(skb)->destructor_arg)
-               prev_pending_idx = XENVIF_TX_CB(skb)->pending_idx;
-
        for (i = 0; i < nr_frags; i++) {
                skb_frag_t *frag = shinfo->frags + i;
                struct xen_netif_tx_request *txp;
@@ -1046,10 +1046,10 @@ static void xenvif_fill_frags(struct xenvif *vif, struct sk_buff *skb)
                pending_idx = frag_get_pending_idx(frag);
 
                /* If this is not the first frag, chain it to the previous*/
-               if (unlikely(prev_pending_idx == INVALID_PENDING_IDX))
+               if (prev_pending_idx == INVALID_PENDING_IDX)
                        skb_shinfo(skb)->destructor_arg =
                                &callback_param(vif, pending_idx);
-               else if (likely(pending_idx != prev_pending_idx))
+               else
                        callback_param(vif, prev_pending_idx).ctx =
                                &callback_param(vif, pending_idx);
 
@@ -1189,7 +1189,10 @@ static bool tx_credit_exceeded(struct xenvif *vif, unsigned size)
        return false;
 }
 
-static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
+static void xenvif_tx_build_gops(struct xenvif *vif,
+                                    int budget,
+                                    unsigned *copy_ops,
+                                    unsigned *map_ops)
 {
        struct gnttab_map_grant_ref *gop = vif->tx_map_ops, *request_gop;
        struct sk_buff *skb;
@@ -1292,22 +1295,36 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
                        }
                }
 
-               xenvif_tx_create_gop(vif, pending_idx, &txreq, gop);
-
-               gop++;
-
                XENVIF_TX_CB(skb)->pending_idx = pending_idx;
 
                __skb_put(skb, data_len);
+               vif->tx_copy_ops[*copy_ops].source.u.ref = txreq.gref;
+               vif->tx_copy_ops[*copy_ops].source.domid = vif->domid;
+               vif->tx_copy_ops[*copy_ops].source.offset = txreq.offset;
+
+               vif->tx_copy_ops[*copy_ops].dest.u.gmfn =
+                       virt_to_mfn(skb->data);
+               vif->tx_copy_ops[*copy_ops].dest.domid = DOMID_SELF;
+               vif->tx_copy_ops[*copy_ops].dest.offset =
+                       offset_in_page(skb->data);
+
+               vif->tx_copy_ops[*copy_ops].len = data_len;
+               vif->tx_copy_ops[*copy_ops].flags = GNTCOPY_source_gref;
+
+               (*copy_ops)++;
 
                skb_shinfo(skb)->nr_frags = ret;
                if (data_len < txreq.size) {
                        skb_shinfo(skb)->nr_frags++;
                        frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
                                             pending_idx);
+                       xenvif_tx_create_map_op(vif, pending_idx, &txreq, gop);
+                       gop++;
                } else {
                        frag_set_pending_idx(&skb_shinfo(skb)->frags[0],
                                             INVALID_PENDING_IDX);
+                       memcpy(&vif->pending_tx_info[pending_idx].req, &txreq,
+                              sizeof(txreq));
                }
 
                vif->pending_cons++;
@@ -1324,11 +1341,13 @@ static unsigned xenvif_tx_build_gops(struct xenvif *vif, int budget)
 
                vif->tx.req_cons = idx;
 
-               if ((gop-vif->tx_map_ops) >= ARRAY_SIZE(vif->tx_map_ops))
+               if (((gop-vif->tx_map_ops) >= ARRAY_SIZE(vif->tx_map_ops)) ||
+                   (*copy_ops >= ARRAY_SIZE(vif->tx_copy_ops)))
                        break;
        }
 
-       return gop - vif->tx_map_ops;
+       (*map_ops) = gop - vif->tx_map_ops;
+       return;
 }
 
 /* Consolidate skb with a frag_list into a brand new one with local pages on
@@ -1399,7 +1418,8 @@ static int xenvif_handle_frag_list(struct xenvif *vif, struct sk_buff *skb)
 
 static int xenvif_tx_submit(struct xenvif *vif)
 {
-       struct gnttab_map_grant_ref *gop = vif->tx_map_ops;
+       struct gnttab_map_grant_ref *gop_map = vif->tx_map_ops;
+       struct gnttab_copy *gop_copy = vif->tx_copy_ops;
        struct sk_buff *skb;
        int work_done = 0;
 
@@ -1412,27 +1432,22 @@ static int xenvif_tx_submit(struct xenvif *vif)
                txp = &vif->pending_tx_info[pending_idx].req;
 
                /* Check the remap error code. */
-               if (unlikely(xenvif_tx_check_gop(vif, skb, &gop))) {
-                       netdev_dbg(vif->dev, "netback grant failed.\n");
+               if (unlikely(xenvif_tx_check_gop(vif, skb, &gop_map, &gop_copy))) {
                        skb_shinfo(skb)->nr_frags = 0;
                        kfree_skb(skb);
                        continue;
                }
 
                data_len = skb->len;
-               memcpy(skb->data,
-                      (void *)(idx_to_kaddr(vif, pending_idx)|txp->offset),
-                      data_len);
                callback_param(vif, pending_idx).ctx = NULL;
                if (data_len < txp->size) {
                        /* Append the packet payload as a fragment. */
                        txp->offset += data_len;
                        txp->size -= data_len;
-                       skb_shinfo(skb)->destructor_arg =
-                               &callback_param(vif, pending_idx);
                } else {
                        /* Schedule a response immediately. */
-                       xenvif_idx_unmap(vif, pending_idx);
+                       xenvif_idx_release(vif, pending_idx,
+                                          XEN_NETIF_RSP_OKAY);
                }
 
                if (txp->flags & XEN_NETTXF_csum_blank)
@@ -1611,22 +1626,25 @@ static inline void xenvif_tx_dealloc_action(struct xenvif *vif)
 /* Called after netfront has transmitted */
 int xenvif_tx_action(struct xenvif *vif, int budget)
 {
-       unsigned nr_gops;
+       unsigned nr_mops, nr_cops = 0;
        int work_done, ret;
 
        if (unlikely(!tx_work_todo(vif)))
                return 0;
 
-       nr_gops = xenvif_tx_build_gops(vif, budget);
+       xenvif_tx_build_gops(vif, budget, &nr_cops, &nr_mops);
 
-       if (nr_gops == 0)
+       if (nr_cops == 0)
                return 0;
 
-       ret = gnttab_map_refs(vif->tx_map_ops,
-                             NULL,
-                             vif->pages_to_map,
-                             nr_gops);
-       BUG_ON(ret);
+       gnttab_batch_copy(vif->tx_copy_ops, nr_cops);
+       if (nr_mops != 0) {
+               ret = gnttab_map_refs(vif->tx_map_ops,
+                                     NULL,
+                                     vif->pages_to_map,
+                                     nr_mops);
+               BUG_ON(ret);
+       }
 
        work_done = xenvif_tx_submit(vif);
 
index a27ec94..b7361ed 100644 (file)
@@ -49,6 +49,40 @@ int of_get_nand_ecc_mode(struct device_node *np)
 }
 EXPORT_SYMBOL_GPL(of_get_nand_ecc_mode);
 
+/**
+ * of_get_nand_ecc_step_size - Get ECC step size associated to
+ * the required ECC strength (see below).
+ * @np:        Pointer to the given device_node
+ *
+ * return the ECC step size, or errno in error case.
+ */
+int of_get_nand_ecc_step_size(struct device_node *np)
+{
+       int ret;
+       u32 val;
+
+       ret = of_property_read_u32(np, "nand-ecc-step-size", &val);
+       return ret ? ret : val;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_ecc_step_size);
+
+/**
+ * of_get_nand_ecc_strength - Get required ECC strength over the
+ * correspnding step size as defined by 'nand-ecc-size'
+ * @np:        Pointer to the given device_node
+ *
+ * return the ECC strength, or errno in error case.
+ */
+int of_get_nand_ecc_strength(struct device_node *np)
+{
+       int ret;
+       u32 val;
+
+       ret = of_property_read_u32(np, "nand-ecc-strength", &val);
+       return ret ? ret : val;
+}
+EXPORT_SYMBOL_GPL(of_get_nand_ecc_strength);
+
 /**
  * of_get_nand_bus_width - Get nand bus witdh for given device_node
  * @np:        Pointer to the given device_node
index 76f1c93..9559829 100644 (file)
@@ -108,8 +108,8 @@ static void nmi_timer_shutdown(void)
        struct perf_event *event;
        int cpu;
 
-       get_online_cpus();
-       unregister_cpu_notifier(&nmi_timer_cpu_nb);
+       cpu_notifier_register_begin();
+       __unregister_cpu_notifier(&nmi_timer_cpu_nb);
        for_each_possible_cpu(cpu) {
                event = per_cpu(nmi_timer_events, cpu);
                if (!event)
@@ -119,7 +119,7 @@ static void nmi_timer_shutdown(void)
                perf_event_release_kernel(event);
        }
 
-       put_online_cpus();
+       cpu_notifier_register_done();
 }
 
 static int nmi_timer_setup(void)
@@ -132,20 +132,23 @@ static int nmi_timer_setup(void)
        do_div(period, HZ);
        nmi_timer_attr.sample_period = period;
 
-       get_online_cpus();
-       err = register_cpu_notifier(&nmi_timer_cpu_nb);
+       cpu_notifier_register_begin();
+       err = __register_cpu_notifier(&nmi_timer_cpu_nb);
        if (err)
                goto out;
+
        /* can't attach events to offline cpus: */
        for_each_online_cpu(cpu) {
                err = nmi_timer_start_cpu(cpu);
-               if (err)
-                       break;
+               if (err) {
+                       cpu_notifier_register_done();
+                       nmi_timer_shutdown();
+                       return err;
+               }
        }
-       if (err)
-               nmi_timer_shutdown();
+
 out:
-       put_online_cpus();
+       cpu_notifier_register_done();
        return err;
 }
 
index 7dd62fa..396c200 100644 (file)
@@ -116,11 +116,11 @@ static void pci_slot_release(struct kobject *kobj)
 }
 
 static struct pci_slot_attribute pci_slot_attr_address =
-       __ATTR(address, (S_IFREG | S_IRUGO), address_read_file, NULL);
+       __ATTR(address, S_IRUGO, address_read_file, NULL);
 static struct pci_slot_attribute pci_slot_attr_max_speed =
-       __ATTR(max_bus_speed, (S_IFREG | S_IRUGO), max_speed_read_file, NULL);
+       __ATTR(max_bus_speed, S_IRUGO, max_speed_read_file, NULL);
 static struct pci_slot_attribute pci_slot_attr_cur_speed =
-       __ATTR(cur_bus_speed, (S_IFREG | S_IRUGO), cur_speed_read_file, NULL);
+       __ATTR(cur_bus_speed, S_IRUGO, cur_speed_read_file, NULL);
 
 static struct attribute *pci_slot_default_attrs[] = {
        &pci_slot_attr_address.attr,
index 61b51e1..d9a0770 100644 (file)
@@ -1374,6 +1374,9 @@ static int __init rapl_init(void)
 
                return -ENODEV;
        }
+
+       cpu_notifier_register_begin();
+
        /* prevent CPU hotplug during detection */
        get_online_cpus();
        ret = rapl_detect_topology();
@@ -1385,20 +1388,23 @@ static int __init rapl_init(void)
                ret = -ENODEV;
                goto done;
        }
-       register_hotcpu_notifier(&rapl_cpu_notifier);
+       __register_hotcpu_notifier(&rapl_cpu_notifier);
 done:
        put_online_cpus();
+       cpu_notifier_register_done();
 
        return ret;
 }
 
 static void __exit rapl_exit(void)
 {
+       cpu_notifier_register_begin();
        get_online_cpus();
-       unregister_hotcpu_notifier(&rapl_cpu_notifier);
+       __unregister_hotcpu_notifier(&rapl_cpu_notifier);
        rapl_unregister_powercap();
        rapl_cleanup_data();
        put_online_cpus();
+       cpu_notifier_register_done();
 }
 
 module_init(rapl_init);
index ff7cbf2..1753dc6 100644 (file)
@@ -2256,6 +2256,7 @@ static int tsi721_setup_mport(struct tsi721_device *priv)
        mport->phy_type = RIO_PHY_SERIAL;
        mport->priv = (void *)priv;
        mport->phys_efptr = 0x100;
+       mport->dev.parent = &pdev->dev;
        priv->mport = mport;
 
        INIT_LIST_HEAD(&mport->dbells);
index 7061ac0..0305675 100644 (file)
@@ -644,6 +644,9 @@ enum tsi721_smsg_int_flag {
 
 #ifdef CONFIG_RAPIDIO_DMA_ENGINE
 
+#define TSI721_BDMA_BD_RING_SZ 128
+#define TSI721_BDMA_MAX_BCOUNT (TSI721_DMAD_BCOUNT1 + 1)
+
 struct tsi721_tx_desc {
        struct dma_async_tx_descriptor  txd;
        struct tsi721_dma_desc          *hw_desc;
@@ -652,6 +655,7 @@ struct tsi721_tx_desc {
        u64                             rio_addr;
        /* upper 2-bits of 66-bit RIO address */
        u8                              rio_addr_u;
+       u32                             bcount;
        bool                            interrupt;
        struct list_head                desc_node;
        struct list_head                tx_list;
index 91245f5..9b60b1f 100644 (file)
@@ -304,35 +304,17 @@ struct tsi721_tx_desc *tsi721_desc_get(struct tsi721_bdma_chan *bdma_chan)
 }
 
 static int
-tsi721_fill_desc(struct tsi721_bdma_chan *bdma_chan,
-       struct tsi721_tx_desc *desc, struct scatterlist *sg,
+tsi721_desc_fill_init(struct tsi721_tx_desc *desc, struct scatterlist *sg,
        enum dma_rtype rtype, u32 sys_size)
 {
        struct tsi721_dma_desc *bd_ptr = desc->hw_desc;
        u64 rio_addr;
 
-       if (sg_dma_len(sg) > TSI721_DMAD_BCOUNT1 + 1) {
-               dev_err(bdma_chan->dchan.device->dev,
-                       "SG element is too large\n");
-               return -EINVAL;
-       }
-
-       dev_dbg(bdma_chan->dchan.device->dev,
-               "desc: 0x%llx, addr: 0x%llx len: 0x%x\n",
-               (u64)desc->txd.phys, (unsigned long long)sg_dma_address(sg),
-               sg_dma_len(sg));
-
-       dev_dbg(bdma_chan->dchan.device->dev,
-               "bd_ptr = %p did=%d raddr=0x%llx\n",
-               bd_ptr, desc->destid, desc->rio_addr);
-
        /* Initialize DMA descriptor */
        bd_ptr->type_id = cpu_to_le32((DTYPE1 << 29) |
                                        (rtype << 19) | desc->destid);
-       if (desc->interrupt)
-               bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF);
        bd_ptr->bcount = cpu_to_le32(((desc->rio_addr & 0x3) << 30) |
-                                       (sys_size << 26) | sg_dma_len(sg));
+                                    (sys_size << 26));
        rio_addr = (desc->rio_addr >> 2) |
                                ((u64)(desc->rio_addr_u & 0x3) << 62);
        bd_ptr->raddr_lo = cpu_to_le32(rio_addr & 0xffffffff);
@@ -346,6 +328,20 @@ tsi721_fill_desc(struct tsi721_bdma_chan *bdma_chan,
        return 0;
 }
 
+static int
+tsi721_desc_fill_end(struct tsi721_tx_desc *desc)
+{
+       struct tsi721_dma_desc *bd_ptr = desc->hw_desc;
+
+       /* Update DMA descriptor */
+       if (desc->interrupt)
+               bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF);
+       bd_ptr->bcount |= cpu_to_le32(desc->bcount & TSI721_DMAD_BCOUNT1);
+
+       return 0;
+}
+
+
 static void tsi721_dma_chain_complete(struct tsi721_bdma_chan *bdma_chan,
                                      struct tsi721_tx_desc *desc)
 {
@@ -674,6 +670,7 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
        unsigned int i;
        u32 sys_size = dma_to_mport(dchan->device)->sys_size;
        enum dma_rtype rtype;
+       dma_addr_t next_addr = -1;
 
        if (!sgl || !sg_len) {
                dev_err(dchan->device->dev, "%s: No SG list\n", __func__);
@@ -704,36 +701,84 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
        for_each_sg(sgl, sg, sg_len, i) {
                int err;
 
-               dev_dbg(dchan->device->dev, "%s: sg #%d\n", __func__, i);
+               if (sg_dma_len(sg) > TSI721_BDMA_MAX_BCOUNT) {
+                       dev_err(dchan->device->dev,
+                               "%s: SG entry %d is too large\n", __func__, i);
+                       goto err_desc_put;
+               }
+
+               /*
+                * If this sg entry forms contiguous block with previous one,
+                * try to merge it into existing DMA descriptor
+                */
+               if (desc) {
+                       if (next_addr == sg_dma_address(sg) &&
+                           desc->bcount + sg_dma_len(sg) <=
+                                               TSI721_BDMA_MAX_BCOUNT) {
+                               /* Adjust byte count of the descriptor */
+                               desc->bcount += sg_dma_len(sg);
+                               goto entry_done;
+                       }
+
+                       /*
+                        * Finalize this descriptor using total
+                        * byte count value.
+                        */
+                       tsi721_desc_fill_end(desc);
+                       dev_dbg(dchan->device->dev, "%s: desc final len: %d\n",
+                               __func__, desc->bcount);
+               }
+
+               /*
+                * Obtain and initialize a new descriptor
+                */
                desc = tsi721_desc_get(bdma_chan);
                if (!desc) {
                        dev_err(dchan->device->dev,
-                               "Not enough descriptors available\n");
-                       goto err_desc_get;
+                               "%s: Failed to get new descriptor for SG %d\n",
+                               __func__, i);
+                       goto err_desc_put;
                }
 
-               if (sg_is_last(sg))
-                       desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0;
-               else
-                       desc->interrupt = false;
-
                desc->destid = rext->destid;
                desc->rio_addr = rio_addr;
                desc->rio_addr_u = 0;
+               desc->bcount = sg_dma_len(sg);
+
+               dev_dbg(dchan->device->dev,
+                       "sg%d desc: 0x%llx, addr: 0x%llx len: %d\n",
+                       i, (u64)desc->txd.phys,
+                       (unsigned long long)sg_dma_address(sg),
+                       sg_dma_len(sg));
+
+               dev_dbg(dchan->device->dev,
+                       "bd_ptr = %p did=%d raddr=0x%llx\n",
+                       desc->hw_desc, desc->destid, desc->rio_addr);
 
-               err = tsi721_fill_desc(bdma_chan, desc, sg, rtype, sys_size);
+               err = tsi721_desc_fill_init(desc, sg, rtype, sys_size);
                if (err) {
                        dev_err(dchan->device->dev,
                                "Failed to build desc: %d\n", err);
-                       goto err_desc_get;
+                       goto err_desc_put;
                }
 
-               rio_addr += sg_dma_len(sg);
+               next_addr = sg_dma_address(sg);
 
                if (!first)
                        first = desc;
                else
                        list_add_tail(&desc->desc_node, &first->tx_list);
+
+entry_done:
+               if (sg_is_last(sg)) {
+                       desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0;
+                       tsi721_desc_fill_end(desc);
+                       dev_dbg(dchan->device->dev, "%s: desc final len: %d\n",
+                               __func__, desc->bcount);
+               } else {
+                       rio_addr += sg_dma_len(sg);
+                       next_addr += sg_dma_len(sg);
+               }
        }
 
        first->txd.cookie = -EBUSY;
@@ -741,7 +786,7 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
 
        return &first->txd;
 
-err_desc_get:
+err_desc_put:
        tsi721_desc_put(bdma_chan, first);
        return NULL;
 }
@@ -792,7 +837,7 @@ int tsi721_register_dma(struct tsi721_device *priv)
                if (i == TSI721_DMACH_MAINT)
                        continue;
 
-               bdma_chan->bd_num = 64;
+               bdma_chan->bd_num = TSI721_BDMA_BD_RING_SZ;
                bdma_chan->regs = priv->regs + TSI721_DMAC_BASE(i);
 
                bdma_chan->dchan.device = &mport->dma;
index c9ae692..f301f05 100644 (file)
@@ -167,7 +167,6 @@ void rio_unregister_driver(struct rio_driver *rdrv)
 void rio_attach_device(struct rio_dev *rdev)
 {
        rdev->dev.bus = &rio_bus_type;
-       rdev->dev.parent = &rio_bus;
 }
 EXPORT_SYMBOL_GPL(rio_attach_device);
 
@@ -216,9 +215,12 @@ static int rio_uevent(struct device *dev, struct kobj_uevent_env *env)
        return 0;
 }
 
-struct device rio_bus = {
-       .init_name = "rapidio",
+struct class rio_mport_class = {
+       .name           = "rapidio_port",
+       .owner          = THIS_MODULE,
+       .dev_groups     = rio_mport_groups,
 };
+EXPORT_SYMBOL_GPL(rio_mport_class);
 
 struct bus_type rio_bus_type = {
        .name = "rapidio",
@@ -233,14 +235,20 @@ struct bus_type rio_bus_type = {
 /**
  *  rio_bus_init - Register the RapidIO bus with the device model
  *
- *  Registers the RIO bus device and RIO bus type with the Linux
+ *  Registers the RIO mport device class and RIO bus type with the Linux
  *  device model.
  */
 static int __init rio_bus_init(void)
 {
-       if (device_register(&rio_bus) < 0)
-               printk("RIO: failed to register RIO bus device\n");
-       return bus_register(&rio_bus_type);
+       int ret;
+
+       ret = class_register(&rio_mport_class);
+       if (!ret) {
+               ret = bus_register(&rio_bus_type);
+               if (ret)
+                       class_unregister(&rio_mport_class);
+       }
+       return ret;
 }
 
 postcore_initcall(rio_bus_init);
index d3a6539..47a1b2e 100644 (file)
@@ -461,6 +461,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
                             rdev->comp_tag & RIO_CTAG_UDEVID);
        }
 
+       rdev->dev.parent = &port->dev;
        rio_attach_device(rdev);
 
        device_initialize(&rdev->dev);
index e0221c6..cdb005c 100644 (file)
@@ -341,3 +341,43 @@ const struct attribute_group *rio_bus_groups[] = {
        &rio_bus_group,
        NULL,
 };
+
+static ssize_t
+port_destid_show(struct device *dev, struct device_attribute *attr,
+                char *buf)
+{
+       struct rio_mport *mport = to_rio_mport(dev);
+
+       if (mport)
+               return sprintf(buf, "0x%04x\n", mport->host_deviceid);
+       else
+               return -ENODEV;
+}
+static DEVICE_ATTR_RO(port_destid);
+
+static ssize_t sys_size_show(struct device *dev, struct device_attribute *attr,
+                          char *buf)
+{
+       struct rio_mport *mport = to_rio_mport(dev);
+
+       if (mport)
+               return sprintf(buf, "%u\n", mport->sys_size);
+       else
+               return -ENODEV;
+}
+static DEVICE_ATTR_RO(sys_size);
+
+static struct attribute *rio_mport_attrs[] = {
+       &dev_attr_port_destid.attr,
+       &dev_attr_sys_size.attr,
+       NULL,
+};
+
+static const struct attribute_group rio_mport_group = {
+       .attrs = rio_mport_attrs,
+};
+
+const struct attribute_group *rio_mport_groups[] = {
+       &rio_mport_group,
+       NULL,
+};
index 2e8a20c..a54ba04 100644 (file)
@@ -1884,6 +1884,7 @@ static int rio_get_hdid(int index)
 int rio_register_mport(struct rio_mport *port)
 {
        struct rio_scan_node *scan = NULL;
+       int res = 0;
 
        if (next_portid >= RIO_MAX_MPORTS) {
                pr_err("RIO: reached specified max number of mports\n");
@@ -1894,6 +1895,16 @@ int rio_register_mport(struct rio_mport *port)
        port->host_deviceid = rio_get_hdid(port->id);
        port->nscan = NULL;
 
+       dev_set_name(&port->dev, "rapidio%d", port->id);
+       port->dev.class = &rio_mport_class;
+
+       res = device_register(&port->dev);
+       if (res)
+               dev_err(&port->dev, "RIO: mport%d registration failed ERR=%d\n",
+                       port->id, res);
+       else
+               dev_dbg(&port->dev, "RIO: mport%d registered\n", port->id);
+
        mutex_lock(&rio_mport_list_lock);
        list_add_tail(&port->node, &rio_mports);
 
index 5f99d22..2d0550e 100644 (file)
@@ -50,6 +50,7 @@ extern int rio_mport_scan(int mport_id);
 /* Structures internal to the RIO core code */
 extern const struct attribute_group *rio_dev_groups[];
 extern const struct attribute_group *rio_bus_groups[];
+extern const struct attribute_group *rio_mport_groups[];
 
 #define RIO_GET_DID(size, x)   (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
 #define RIO_SET_DID(size, x)   (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
index 1cd8584..903eb37 100644 (file)
@@ -392,6 +392,15 @@ config REGULATOR_PALMAS
          on the muxing. This is handled automatically in the driver by
          reading the mux info from OTP.
 
+config REGULATOR_PBIAS
+       tristate "PBIAS OMAP regulator driver"
+       depends on (ARCH_OMAP || COMPILE_TEST) && MFD_SYSCON
+       help
+        Say y here to support pbias regulator for mmc1:SD card i/o
+        on OMAP SoCs.
+        This driver provides support for OMAP pbias modelled
+        regulators.
+
 config REGULATOR_PCAP
        tristate "Motorola PCAP2 regulator driver"
        depends on EZX_PCAP
index f0fe0c5..12ef277 100644 (file)
@@ -55,6 +55,7 @@ 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_PBIAS) += pbias-regulator.o
 obj-$(CONFIG_REGULATOR_PCAP) += pcap-regulator.o
 obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
 obj-$(CONFIG_REGULATOR_RC5T583)  += rc5t583-regulator.o
diff --git a/drivers/regulator/pbias-regulator.c b/drivers/regulator/pbias-regulator.c
new file mode 100644 (file)
index 0000000..ded3b35
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * pbias-regulator.c
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Balaji T K <balajitk@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/mfd/syscon.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/of_regulator.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+struct pbias_reg_info {
+       u32 enable;
+       u32 enable_mask;
+       u32 vmode;
+       unsigned int enable_time;
+       char *name;
+};
+
+struct pbias_regulator_data {
+       struct regulator_desc desc;
+       void __iomem *pbias_addr;
+       unsigned int pbias_reg;
+       struct regulator_dev *dev;
+       struct regmap *syscon;
+       const struct pbias_reg_info *info;
+       int voltage;
+};
+
+static int pbias_regulator_set_voltage(struct regulator_dev *dev,
+                       int min_uV, int max_uV, unsigned *selector)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(dev);
+       const struct pbias_reg_info *info = data->info;
+       int ret, vmode;
+
+       if (min_uV <= 1800000)
+               vmode = 0;
+       else if (min_uV > 1800000)
+               vmode = info->vmode;
+
+       ret = regmap_update_bits(data->syscon, data->pbias_reg,
+                                               info->vmode, vmode);
+
+       return ret;
+}
+
+static int pbias_regulator_get_voltage(struct regulator_dev *rdev)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+       const struct pbias_reg_info *info = data->info;
+       int value, voltage;
+
+       regmap_read(data->syscon, data->pbias_reg, &value);
+       value &= info->vmode;
+
+       voltage = value ? 3000000 : 1800000;
+
+       return voltage;
+}
+
+static int pbias_regulator_enable(struct regulator_dev *rdev)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+       const struct pbias_reg_info *info = data->info;
+       int ret;
+
+       ret = regmap_update_bits(data->syscon, data->pbias_reg,
+                                       info->enable_mask, info->enable);
+
+       return ret;
+}
+
+static int pbias_regulator_disable(struct regulator_dev *rdev)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+       const struct pbias_reg_info *info = data->info;
+       int ret;
+
+       ret = regmap_update_bits(data->syscon, data->pbias_reg,
+                                               info->enable_mask, 0);
+       return ret;
+}
+
+static int pbias_regulator_is_enable(struct regulator_dev *rdev)
+{
+       struct pbias_regulator_data *data = rdev_get_drvdata(rdev);
+       const struct pbias_reg_info *info = data->info;
+       int value;
+
+       regmap_read(data->syscon, data->pbias_reg, &value);
+
+       return (value & info->enable_mask) == info->enable_mask;
+}
+
+static struct regulator_ops pbias_regulator_voltage_ops = {
+       .set_voltage    = pbias_regulator_set_voltage,
+       .get_voltage    = pbias_regulator_get_voltage,
+       .enable         = pbias_regulator_enable,
+       .disable        = pbias_regulator_disable,
+       .is_enabled     = pbias_regulator_is_enable,
+};
+
+static const struct pbias_reg_info pbias_mmc_omap2430 = {
+       .enable = BIT(1),
+       .enable_mask = BIT(1),
+       .vmode = BIT(0),
+       .enable_time = 100,
+       .name = "pbias_mmc_omap2430"
+};
+
+static const struct pbias_reg_info pbias_sim_omap3 = {
+       .enable = BIT(9),
+       .enable_mask = BIT(9),
+       .vmode = BIT(8),
+       .enable_time = 100,
+       .name = "pbias_sim_omap3"
+};
+
+static const struct pbias_reg_info pbias_mmc_omap4 = {
+       .enable = BIT(26) | BIT(22),
+       .enable_mask = BIT(26) | BIT(25) | BIT(22),
+       .vmode = BIT(21),
+       .enable_time = 100,
+       .name = "pbias_mmc_omap4"
+};
+
+static const struct pbias_reg_info pbias_mmc_omap5 = {
+       .enable = BIT(27) | BIT(26),
+       .enable_mask = BIT(27) | BIT(25) | BIT(26),
+       .vmode = BIT(21),
+       .enable_time = 100,
+       .name = "pbias_mmc_omap5"
+};
+
+static struct of_regulator_match pbias_matches[] = {
+       { .name = "pbias_mmc_omap2430", .driver_data = (void *)&pbias_mmc_omap2430},
+       { .name = "pbias_sim_omap3", .driver_data = (void *)&pbias_sim_omap3},
+       { .name = "pbias_mmc_omap4", .driver_data = (void *)&pbias_mmc_omap4},
+       { .name = "pbias_mmc_omap5", .driver_data = (void *)&pbias_mmc_omap5},
+};
+#define PBIAS_NUM_REGS ARRAY_SIZE(pbias_matches)
+
+static const struct of_device_id pbias_of_match[] = {
+       { .compatible = "ti,pbias-omap", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, pbias_of_match);
+
+static int pbias_regulator_probe(struct platform_device *pdev)
+{
+       struct device_node *np = pdev->dev.of_node;
+       struct pbias_regulator_data *drvdata;
+       struct resource *res;
+       struct regulator_config cfg = { };
+       struct regmap *syscon;
+       const struct pbias_reg_info *info;
+       int ret = 0;
+       int count, idx, data_idx = 0;
+
+       count = of_regulator_match(&pdev->dev, np, pbias_matches,
+                                               PBIAS_NUM_REGS);
+       if (count < 0)
+               return count;
+
+       drvdata = devm_kzalloc(&pdev->dev, sizeof(struct pbias_regulator_data)
+                              * count, GFP_KERNEL);
+       if (drvdata == NULL) {
+               dev_err(&pdev->dev, "Failed to allocate device data\n");
+               return -ENOMEM;
+       }
+
+       syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
+       if (IS_ERR(syscon))
+               return PTR_ERR(syscon);
+
+       cfg.dev = &pdev->dev;
+
+       for (idx = 0; idx < PBIAS_NUM_REGS && data_idx < count; idx++) {
+               if (!pbias_matches[idx].init_data ||
+                       !pbias_matches[idx].of_node)
+                       continue;
+
+               info = pbias_matches[idx].driver_data;
+               if (!info)
+                       return -ENODEV;
+
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               if (!res)
+                       return -EINVAL;
+
+               drvdata[data_idx].pbias_reg = res->start;
+               drvdata[data_idx].syscon = syscon;
+               drvdata[data_idx].info = info;
+               drvdata[data_idx].desc.name = info->name;
+               drvdata[data_idx].desc.owner = THIS_MODULE;
+               drvdata[data_idx].desc.type = REGULATOR_VOLTAGE;
+               drvdata[data_idx].desc.ops = &pbias_regulator_voltage_ops;
+               drvdata[data_idx].desc.n_voltages = 2;
+               drvdata[data_idx].desc.enable_time = info->enable_time;
+
+               cfg.init_data = pbias_matches[idx].init_data;
+               cfg.driver_data = &drvdata[data_idx];
+               cfg.of_node = pbias_matches[idx].of_node;
+
+               drvdata[data_idx].dev = devm_regulator_register(&pdev->dev,
+                                       &drvdata[data_idx].desc, &cfg);
+               if (IS_ERR(drvdata[data_idx].dev)) {
+                       ret = PTR_ERR(drvdata[data_idx].dev);
+                       dev_err(&pdev->dev,
+                               "Failed to register regulator: %d\n", ret);
+                       goto err_regulator;
+               }
+               data_idx++;
+       }
+
+       platform_set_drvdata(pdev, drvdata);
+
+err_regulator:
+       return ret;
+}
+
+static struct platform_driver pbias_regulator_driver = {
+       .probe          = pbias_regulator_probe,
+       .driver         = {
+               .name           = "pbias-regulator",
+               .owner          = THIS_MODULE,
+               .of_match_table = of_match_ptr(pbias_of_match),
+       },
+};
+
+module_platform_driver(pbias_regulator_driver);
+
+MODULE_AUTHOR("Balaji T K <balajitk@ti.com>");
+MODULE_DESCRIPTION("pbias voltage regulator");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:pbias-regulator");
index 9cbc567..c062f16 100644 (file)
@@ -646,7 +646,7 @@ dasd_diag_init(void)
        ASCEBC(dasd_diag_discipline.ebcname, 4);
 
        irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
-       register_external_interrupt(0x2603, dasd_ext_handler);
+       register_external_irq(EXT_IRQ_CP_SERVICE, dasd_ext_handler);
        dasd_diag_discipline_pointer = &dasd_diag_discipline;
        return 0;
 }
@@ -654,7 +654,7 @@ dasd_diag_init(void)
 static void __exit
 dasd_diag_cleanup(void)
 {
-       unregister_external_interrupt(0x2603, dasd_ext_handler);
+       unregister_external_irq(EXT_IRQ_CP_SERVICE, dasd_ext_handler);
        irq_subclass_unregister(IRQ_SUBCLASS_SERVICE_SIGNAL);
        dasd_diag_discipline_pointer = NULL;
 }
index 9f849df..15b3459 100644 (file)
@@ -632,6 +632,8 @@ raw3270_reset_device_cb(struct raw3270_request *rq, void *data)
                raw3270_size_device_done(rp);
        } else
                raw3270_writesf_readpart(rp);
+       memset(&rp->init_reset, 0, sizeof(rp->init_reset));
+       memset(&rp->init_data, 0, sizeof(rp->init_data));
 }
 
 static int
@@ -639,9 +641,10 @@ __raw3270_reset_device(struct raw3270 *rp)
 {
        int rc;
 
+       /* Check if reset is already pending */
+       if (rp->init_reset.view)
+               return -EBUSY;
        /* Store reset data stream to init_data/init_reset */
-       memset(&rp->init_reset, 0, sizeof(rp->init_reset));
-       memset(&rp->init_data, 0, sizeof(rp->init_data));
        rp->init_data[0] = TW_KR;
        rp->init_reset.ccw.cmd_code = TC_EWRITEA;
        rp->init_reset.ccw.flags = CCW_FLAG_SLI;
@@ -850,7 +853,7 @@ raw3270_create_device(struct ccw_device *cdev)
        char *ascebc;
        int rc;
 
-       rp = kmalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
+       rp = kzalloc(sizeof(struct raw3270), GFP_KERNEL | GFP_DMA);
        if (!rp)
                return ERR_PTR(-ENOMEM);
        ascebc = kmalloc(256, GFP_KERNEL);
index 1fe2643..1990285 100644 (file)
@@ -91,6 +91,9 @@ static struct sclp_req sclp_suspend_req;
 /* Timer for request retries. */
 static struct timer_list sclp_request_timer;
 
+/* Timer for queued requests. */
+static struct timer_list sclp_queue_timer;
+
 /* Internal state: is the driver initialized? */
 static volatile enum sclp_init_state_t {
        sclp_init_state_uninitialized,
@@ -215,6 +218,76 @@ sclp_request_timeout(unsigned long data)
        sclp_process_queue();
 }
 
+/*
+ * Returns the expire value in jiffies of the next pending request timeout,
+ * if any. Needs to be called with sclp_lock.
+ */
+static unsigned long __sclp_req_queue_find_next_timeout(void)
+{
+       unsigned long expires_next = 0;
+       struct sclp_req *req;
+
+       list_for_each_entry(req, &sclp_req_queue, list) {
+               if (!req->queue_expires)
+                       continue;
+               if (!expires_next ||
+                  (time_before(req->queue_expires, expires_next)))
+                               expires_next = req->queue_expires;
+       }
+       return expires_next;
+}
+
+/*
+ * Returns expired request, if any, and removes it from the list.
+ */
+static struct sclp_req *__sclp_req_queue_remove_expired_req(void)
+{
+       unsigned long flags, now;
+       struct sclp_req *req;
+
+       spin_lock_irqsave(&sclp_lock, flags);
+       now = jiffies;
+       /* Don't need list_for_each_safe because we break out after list_del */
+       list_for_each_entry(req, &sclp_req_queue, list) {
+               if (!req->queue_expires)
+                       continue;
+               if (time_before_eq(req->queue_expires, now)) {
+                       if (req->status == SCLP_REQ_QUEUED) {
+                               req->status = SCLP_REQ_QUEUED_TIMEOUT;
+                               list_del(&req->list);
+                               goto out;
+                       }
+               }
+       }
+       req = NULL;
+out:
+       spin_unlock_irqrestore(&sclp_lock, flags);
+       return req;
+}
+
+/*
+ * Timeout handler for queued requests. Removes request from list and
+ * invokes callback. This timer can be set per request in situations where
+ * waiting too long would be harmful to the system, e.g. during SE reboot.
+ */
+static void sclp_req_queue_timeout(unsigned long data)
+{
+       unsigned long flags, expires_next;
+       struct sclp_req *req;
+
+       do {
+               req = __sclp_req_queue_remove_expired_req();
+               if (req && req->callback)
+                       req->callback(req, req->callback_data);
+       } while (req);
+
+       spin_lock_irqsave(&sclp_lock, flags);
+       expires_next = __sclp_req_queue_find_next_timeout();
+       if (expires_next)
+               mod_timer(&sclp_queue_timer, expires_next);
+       spin_unlock_irqrestore(&sclp_lock, flags);
+}
+
 /* Try to start a request. Return zero if the request was successfully
  * started or if it will be started at a later time. Return non-zero otherwise.
  * Called while sclp_lock is locked. */
@@ -317,6 +390,13 @@ sclp_add_request(struct sclp_req *req)
        req->start_count = 0;
        list_add_tail(&req->list, &sclp_req_queue);
        rc = 0;
+       if (req->queue_timeout) {
+               req->queue_expires = jiffies + req->queue_timeout * HZ;
+               if (!timer_pending(&sclp_queue_timer) ||
+                   time_after(sclp_queue_timer.expires, req->queue_expires))
+                       mod_timer(&sclp_queue_timer, req->queue_expires);
+       } else
+               req->queue_expires = 0;
        /* Start if request is first in list */
        if (sclp_running_state == sclp_running_state_idle &&
            req->list.prev == &sclp_req_queue) {
@@ -892,7 +972,7 @@ sclp_check_interface(void)
 
        spin_lock_irqsave(&sclp_lock, flags);
        /* Prepare init mask command */
-       rc = register_external_interrupt(0x2401, sclp_check_handler);
+       rc = register_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler);
        if (rc) {
                spin_unlock_irqrestore(&sclp_lock, flags);
                return rc;
@@ -925,7 +1005,7 @@ sclp_check_interface(void)
                } else
                        rc = -EBUSY;
        }
-       unregister_external_interrupt(0x2401, sclp_check_handler);
+       unregister_external_irq(EXT_IRQ_SERVICE_SIG, sclp_check_handler);
        spin_unlock_irqrestore(&sclp_lock, flags);
        return rc;
 }
@@ -1113,6 +1193,8 @@ sclp_init(void)
        INIT_LIST_HEAD(&sclp_reg_list);
        list_add(&sclp_state_change_event.list, &sclp_reg_list);
        init_timer(&sclp_request_timer);
+       init_timer(&sclp_queue_timer);
+       sclp_queue_timer.function = sclp_req_queue_timeout;
        /* Check interface */
        spin_unlock_irqrestore(&sclp_lock, flags);
        rc = sclp_check_interface();
@@ -1124,7 +1206,7 @@ sclp_init(void)
        if (rc)
                goto fail_init_state_uninitialized;
        /* Register interrupt handler */
-       rc = register_external_interrupt(0x2401, sclp_interrupt_handler);
+       rc = register_external_irq(EXT_IRQ_SERVICE_SIG, sclp_interrupt_handler);
        if (rc)
                goto fail_unregister_reboot_notifier;
        sclp_init_state = sclp_init_state_initialized;
index fea76ae..a68b5ec 100644 (file)
@@ -133,6 +133,11 @@ struct sclp_req {
        /* Callback that is called after reaching final status. */
        void (*callback)(struct sclp_req *, void *data);
        void *callback_data;
+       int queue_timeout;              /* request queue timeout (sec), set by
+                                          caller of sclp_add_request(), if
+                                          needed */
+       /* Internal fields */
+       unsigned long queue_expires;    /* request queue timeout (jiffies) */
 };
 
 #define SCLP_REQ_FILLED          0x00  /* request is ready to be processed */
@@ -140,6 +145,9 @@ struct sclp_req {
 #define SCLP_REQ_RUNNING  0x02 /* request is currently running */
 #define SCLP_REQ_DONE    0x03  /* request is completed successfully */
 #define SCLP_REQ_FAILED          0x05  /* request is finally failed */
+#define SCLP_REQ_QUEUED_TIMEOUT 0x06   /* request on queue timed out */
+
+#define SCLP_QUEUE_INTERVAL 5  /* timeout interval for request queue */
 
 /* function pointers that a high level driver has to use for registration */
 /* of some routines it wants to be called from the low level driver */
@@ -173,6 +181,7 @@ int sclp_deactivate(void);
 int sclp_reactivate(void);
 int sclp_service_call(sclp_cmdw_t command, void *sccb);
 int sclp_sync_request(sclp_cmdw_t command, void *sccb);
+int sclp_sync_request_timeout(sclp_cmdw_t command, void *sccb, int timeout);
 
 int sclp_sdias_init(void);
 void sclp_sdias_exit(void);
index 49af8ee..6e8f90f 100644 (file)
@@ -36,6 +36,11 @@ static void sclp_sync_callback(struct sclp_req *req, void *data)
 }
 
 int sclp_sync_request(sclp_cmdw_t cmd, void *sccb)
+{
+       return sclp_sync_request_timeout(cmd, sccb, 0);
+}
+
+int sclp_sync_request_timeout(sclp_cmdw_t cmd, void *sccb, int timeout)
 {
        struct completion completion;
        struct sclp_req *request;
@@ -44,6 +49,8 @@ int sclp_sync_request(sclp_cmdw_t cmd, void *sccb)
        request = kzalloc(sizeof(*request), GFP_KERNEL);
        if (!request)
                return -ENOMEM;
+       if (timeout)
+               request->queue_timeout = timeout;
        request->command = cmd;
        request->sccb = sccb;
        request->status = SCLP_REQ_FILLED;
@@ -110,7 +117,8 @@ int sclp_get_cpu_info(struct sclp_cpu_info *info)
        if (!sccb)
                return -ENOMEM;
        sccb->header.length = sizeof(*sccb);
-       rc = sclp_sync_request(SCLP_CMDW_READ_CPU_INFO, sccb);
+       rc = sclp_sync_request_timeout(SCLP_CMDW_READ_CPU_INFO, sccb,
+                                      SCLP_QUEUE_INTERVAL);
        if (rc)
                goto out;
        if (sccb->header.response_code != 0x0010) {
@@ -144,7 +152,7 @@ static int do_cpu_configure(sclp_cmdw_t cmd)
        if (!sccb)
                return -ENOMEM;
        sccb->header.length = sizeof(*sccb);
-       rc = sclp_sync_request(cmd, sccb);
+       rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL);
        if (rc)
                goto out;
        switch (sccb->header.response_code) {
@@ -214,7 +222,7 @@ static int do_assign_storage(sclp_cmdw_t cmd, u16 rn)
                return -ENOMEM;
        sccb->header.length = PAGE_SIZE;
        sccb->rn = rn;
-       rc = sclp_sync_request(cmd, sccb);
+       rc = sclp_sync_request_timeout(cmd, sccb, SCLP_QUEUE_INTERVAL);
        if (rc)
                goto out;
        switch (sccb->header.response_code) {
@@ -269,7 +277,8 @@ static int sclp_attach_storage(u8 id)
        if (!sccb)
                return -ENOMEM;
        sccb->header.length = PAGE_SIZE;
-       rc = sclp_sync_request(0x00080001 | id << 8, sccb);
+       rc = sclp_sync_request_timeout(0x00080001 | id << 8, sccb,
+                                      SCLP_QUEUE_INTERVAL);
        if (rc)
                goto out;
        switch (sccb->header.response_code) {
index 981a99f..3478e19 100644 (file)
@@ -78,7 +78,8 @@ tape_std_assign(struct tape_device *device)
 
        rc = tape_do_io_interruptible(device, request);
 
-       del_timer(&timeout);
+       del_timer_sync(&timeout);
+       destroy_timer_on_stack(&timeout);
 
        if (rc != 0) {
                DBF_EVENT(3, "%08x: assign failed - device might be busy\n",
index 4b824b1..5222ebe 100644 (file)
@@ -626,8 +626,8 @@ static long zcrypt_send_ep11_cprb(struct ep11_urb *xcrb)
                        return -ENOMEM;
 
                if (copy_from_user(ep11_dev_list.targets,
-                                  (struct ep11_target_dev *)xcrb->targets,
-                                  xcrb->targets_num *
+                                  (struct ep11_target_dev __force __user *)
+                                  xcrb->targets, xcrb->targets_num *
                                   sizeof(struct ep11_target_dev)))
                        return -EFAULT;
        }
index 0bc91e4..46b324c 100644 (file)
@@ -315,6 +315,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
        char *req_data = ap_msg->message + sizeof(struct type6_hdr) + rcblen;
        char *function_code;
 
+       if (CEIL4(xcRB->request_control_blk_length) <
+                       xcRB->request_control_blk_length)
+               return -EINVAL; /* overflow after alignment*/
+
        /* length checks */
        ap_msg->length = sizeof(struct type6_hdr) +
                CEIL4(xcRB->request_control_blk_length) +
@@ -333,6 +337,10 @@ static int XCRB_msg_to_type6CPRB_msgX(struct zcrypt_device *zdev,
                return -EINVAL;
        }
 
+       if (CEIL4(xcRB->reply_control_blk_length) <
+                       xcRB->reply_control_blk_length)
+               return -EINVAL; /* overflow after alignment*/
+
        replylen = sizeof(struct type86_fmt2_msg) +
                CEIL4(xcRB->reply_control_blk_length) +
                xcRB->reply_data_length;
@@ -415,12 +423,18 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
                unsigned int    dom_val;        /* domain id       */
        } __packed * payload_hdr;
 
+       if (CEIL4(xcRB->req_len) < xcRB->req_len)
+               return -EINVAL; /* overflow after alignment*/
+
        /* length checks */
        ap_msg->length = sizeof(struct type6_hdr) + xcRB->req_len;
        if (CEIL4(xcRB->req_len) > MSGTYPE06_MAX_MSG_SIZE -
                                   (sizeof(struct type6_hdr)))
                return -EINVAL;
 
+       if (CEIL4(xcRB->resp_len) < xcRB->resp_len)
+               return -EINVAL; /* overflow after alignment*/
+
        if (CEIL4(xcRB->resp_len) > MSGTYPE06_MAX_MSG_SIZE -
                                    (sizeof(struct type86_fmt2_msg)))
                return -EINVAL;
@@ -432,7 +446,7 @@ static int xcrb_msg_to_type6_ep11cprb_msgx(struct zcrypt_device *zdev,
 
        /* Import CPRB data from the ioctl input parameter */
        if (copy_from_user(&(msg->cprbx.cprb_len),
-                          (char *)xcRB->req, xcRB->req_len)) {
+                          (char __force __user *)xcRB->req, xcRB->req_len)) {
                return -EFAULT;
        }
 
@@ -645,7 +659,7 @@ static int convert_type86_ep11_xcrb(struct zcrypt_device *zdev,
                return -EINVAL;
 
        /* Copy response CPRB to user */
-       if (copy_to_user((char *)xcRB->resp,
+       if (copy_to_user((char __force __user *)xcRB->resp,
                         data + msg->fmt2.offset1, msg->fmt2.count1))
                return -EFAULT;
        xcRB->resp_len = msg->fmt2.count1;
index 1abd0db..a134965 100644 (file)
@@ -477,7 +477,7 @@ static int __init kvm_devices_init(void)
        INIT_WORK(&hotplug_work, hotplug_devices);
 
        irq_subclass_register(IRQ_SUBCLASS_SERVICE_SIGNAL);
-       register_external_interrupt(0x2603, kvm_extint_handler);
+       register_external_irq(EXT_IRQ_CP_SERVICE, kvm_extint_handler);
 
        scan_devices();
        return 0;
index f404f55..c461f2a 100644 (file)
@@ -899,6 +899,7 @@ lcs_send_lancmd(struct lcs_card *card, struct lcs_buffer *buffer,
        add_timer(&timer);
        wait_event(reply->wait_q, reply->received);
        del_timer_sync(&timer);
+       destroy_timer_on_stack(&timer);
        LCS_DBF_TEXT_(4, trace, "rc:%d",reply->rc);
        rc = reply->rc;
        lcs_put_reply(reply);
index 6287f6a..1d41f4b 100644 (file)
@@ -2592,12 +2592,16 @@ static int __init bnx2fc_mod_init(void)
                spin_lock_init(&p->fp_work_lock);
        }
 
+       cpu_notifier_register_begin();
+
        for_each_online_cpu(cpu) {
                bnx2fc_percpu_thread_create(cpu);
        }
 
        /* Initialize per CPU interrupt thread */
-       register_hotcpu_notifier(&bnx2fc_cpu_notifier);
+       __register_hotcpu_notifier(&bnx2fc_cpu_notifier);
+
+       cpu_notifier_register_done();
 
        cnic_register_driver(CNIC_ULP_FCOE, &bnx2fc_cnic_cb);
 
@@ -2662,13 +2666,17 @@ static void __exit bnx2fc_mod_exit(void)
        if (l2_thread)
                kthread_stop(l2_thread);
 
-       unregister_hotcpu_notifier(&bnx2fc_cpu_notifier);
+       cpu_notifier_register_begin();
 
        /* Destroy per cpu threads */
        for_each_online_cpu(cpu) {
                bnx2fc_percpu_thread_destroy(cpu);
        }
 
+       __unregister_hotcpu_notifier(&bnx2fc_cpu_notifier);
+
+       cpu_notifier_register_done();
+
        destroy_workqueue(bnx2fc_wq);
        /*
         * detach from scsi transport
index 34c294b..80c03b4 100644 (file)
@@ -537,11 +537,15 @@ static int __init bnx2i_mod_init(void)
                p->iothread = NULL;
        }
 
+       cpu_notifier_register_begin();
+
        for_each_online_cpu(cpu)
                bnx2i_percpu_thread_create(cpu);
 
        /* Initialize per CPU interrupt thread */
-       register_hotcpu_notifier(&bnx2i_cpu_notifier);
+       __register_hotcpu_notifier(&bnx2i_cpu_notifier);
+
+       cpu_notifier_register_done();
 
        return 0;
 
@@ -581,11 +585,15 @@ static void __exit bnx2i_mod_exit(void)
        }
        mutex_unlock(&bnx2i_dev_lock);
 
-       unregister_hotcpu_notifier(&bnx2i_cpu_notifier);
+       cpu_notifier_register_begin();
 
        for_each_online_cpu(cpu)
                bnx2i_percpu_thread_destroy(cpu);
 
+       __unregister_hotcpu_notifier(&bnx2i_cpu_notifier);
+
+       cpu_notifier_register_done();
+
        iscsi_unregister_transport(&bnx2i_iscsi_transport);
        cnic_unregister_driver(CNIC_ULP_ISCSI);
 }
index f317000..d5e105b 100644 (file)
@@ -2633,14 +2633,18 @@ static int __init fcoe_init(void)
                skb_queue_head_init(&p->fcoe_rx_list);
        }
 
+       cpu_notifier_register_begin();
+
        for_each_online_cpu(cpu)
                fcoe_percpu_thread_create(cpu);
 
        /* Initialize per CPU interrupt thread */
-       rc = register_hotcpu_notifier(&fcoe_cpu_notifier);
+       rc = __register_hotcpu_notifier(&fcoe_cpu_notifier);
        if (rc)
                goto out_free;
 
+       cpu_notifier_register_done();
+
        /* Setup link change notification */
        fcoe_dev_setup();
 
@@ -2655,6 +2659,9 @@ out_free:
        for_each_online_cpu(cpu) {
                fcoe_percpu_thread_destroy(cpu);
        }
+
+       cpu_notifier_register_done();
+
        mutex_unlock(&fcoe_config_mutex);
        destroy_workqueue(fcoe_wq);
        return rc;
@@ -2687,11 +2694,15 @@ static void __exit fcoe_exit(void)
        }
        rtnl_unlock();
 
-       unregister_hotcpu_notifier(&fcoe_cpu_notifier);
+       cpu_notifier_register_begin();
 
        for_each_online_cpu(cpu)
                fcoe_percpu_thread_destroy(cpu);
 
+       __unregister_hotcpu_notifier(&fcoe_cpu_notifier);
+
+       cpu_notifier_register_done();
+
        mutex_unlock(&fcoe_config_mutex);
 
        /*
index 5681c05..65a123d 100644 (file)
@@ -184,7 +184,7 @@ void scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
  */
 int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                 int data_direction, void *buffer, unsigned bufflen,
-                unsigned char *sense, int timeout, int retries, int flags,
+                unsigned char *sense, int timeout, int retries, u64 flags,
                 int *resid)
 {
        struct request *req;
@@ -235,7 +235,7 @@ EXPORT_SYMBOL(scsi_execute);
 int scsi_execute_req_flags(struct scsi_device *sdev, const unsigned char *cmd,
                     int data_direction, void *buffer, unsigned bufflen,
                     struct scsi_sense_hdr *sshdr, int timeout, int retries,
-                    int *resid, int flags)
+                    int *resid, u64 flags)
 {
        char *sense = NULL;
        int result;
index 47cf175..ea5efb4 100644 (file)
@@ -50,6 +50,8 @@ source "drivers/staging/rtl8712/Kconfig"
 
 source "drivers/staging/rtl8188eu/Kconfig"
 
+source "drivers/staging/rtl8723au/Kconfig"
+
 source "drivers/staging/rtl8821ae/Kconfig"
 
 source "drivers/staging/rts5139/Kconfig"
index d12f618..86e020c 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_RTL8192U)                += rtl8192u/
 obj-$(CONFIG_RTL8192E)         += rtl8192e/
 obj-$(CONFIG_R8712U)           += rtl8712/
 obj-$(CONFIG_R8188EU)          += rtl8188eu/
+obj-$(CONFIG_R8723AU)          += rtl8723au/
 obj-$(CONFIG_R8821AE)          += rtl8821ae/
 obj-$(CONFIG_RTS5139)          += rts5139/
 obj-$(CONFIG_RTS5208)          += rts5208/
index a8d0178..c48f640 100644 (file)
@@ -121,7 +121,7 @@ static int ipu_page_flip(struct drm_crtc *crtc,
 
        ipu_crtc->newfb = fb;
        ipu_crtc->page_flip_event = event;
-       crtc->fb = fb;
+       crtc->primary->fb = fb;
 
        return 0;
 }
@@ -193,7 +193,7 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
                return ret;
        }
 
-       return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->fb,
+       return ipu_plane_mode_set(ipu_crtc->plane[0], crtc, mode, crtc->primary->fb,
                                  0, 0, mode->hdisplay, mode->vdisplay,
                                  x, y, mode->hdisplay, mode->vdisplay);
 }
@@ -219,7 +219,7 @@ static irqreturn_t ipu_irq_handler(int irq, void *dev_id)
 
        if (ipu_crtc->newfb) {
                ipu_crtc->newfb = NULL;
-               ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.fb,
+               ipu_plane_set_base(ipu_crtc->plane[0], ipu_crtc->base.primary->fb,
                                ipu_crtc->plane[0]->x, ipu_crtc->plane[0]->y);
                ipu_crtc_handle_pageflip(ipu_crtc);
        }
index b0c9b6c..27a8d73 100644 (file)
@@ -68,7 +68,7 @@ int ipu_plane_set_base(struct ipu_plane *ipu_plane, struct drm_framebuffer *fb,
 
        cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
        if (!cma_obj) {
-               DRM_LOG_KMS("entry is null.\n");
+               DRM_DEBUG_KMS("entry is null.\n");
                return -EFAULT;
        }
 
diff --git a/drivers/staging/rtl8723au/Kconfig b/drivers/staging/rtl8723au/Kconfig
new file mode 100644 (file)
index 0000000..07fb5e4
--- /dev/null
@@ -0,0 +1,38 @@
+config R8723AU
+       tristate "Realtek RTL8723AU Wireless LAN NIC driver"
+       depends on USB && WLAN && RFKILL
+       select WIRELESS_EXT
+       select WEXT_PRIV
+       select CFG80211
+       default n
+       ---help---
+       This option adds the Realtek RTL8723AU USB device such as found in
+       the Lenovo Yogi 13 tablet. If built as a module, it will be called r8723au.
+
+if R8723AU
+
+config 8723AU_AP_MODE
+       bool "Realtek RTL8723AU AP mode"
+       default y
+       ---help---
+       This option enables Access Point mode. Unless you know that your system
+       will never be used as an AP, or the target system has limited memory,
+       "Y" should be selected.
+
+config 8723AU_P2P
+       bool "Realtek RTL8723AU Peer-to-peer mode"
+       default y
+       ---help---
+       This option enables peer-to-peer mode for the r8723au driver. Unless you
+       know that peer-to-peer (P2P) mode will never be used, or the target system has
+       limited memory, "Y" should be selected.
+
+config 8723AU_BT_COEXIST
+       bool "Realtek RTL8723AU BlueTooth Coexistence"
+       default y
+       ---help---
+       This option enables icoexistence with BlueTooth communications for the r8723au driver.
+       Unless you know that this driver will never by used with BT, or the target system has
+       limited memory, "Y" should be selected.
+
+endif
diff --git a/drivers/staging/rtl8723au/Makefile b/drivers/staging/rtl8723au/Makefile
new file mode 100644 (file)
index 0000000..11c6dd4
--- /dev/null
@@ -0,0 +1,58 @@
+r8723au-y :=                           \
+               core/rtw_ap.o           \
+               core/rtw_cmd.o          \
+               core/rtw_efuse.o        \
+               core/rtw_io.o           \
+               core/rtw_ioctl_set.o    \
+               core/rtw_ieee80211.o    \
+               core/rtw_led.o          \
+               core/rtw_mlme.o         \
+               core/rtw_mlme_ext.o     \
+               core/rtw_p2p.o          \
+               core/rtw_pwrctrl.o      \
+               core/rtw_recv.o         \
+               core/rtw_security.o     \
+               core/rtw_sreset.o       \
+               core/rtw_sta_mgt.o      \
+               core/rtw_xmit.o         \
+               core/rtw_wlan_util.o    \
+               hal/hal_com.o           \
+               hal/hal_intf.o          \
+               hal/Hal8723PwrSeq.o     \
+               hal/Hal8723UHWImg_CE.o  \
+               hal/HalDMOutSrc8723A_CE.o \
+               hal/HalHWImg8723A_BB.o  \
+               hal/HalHWImg8723A_MAC.o \
+               hal/HalHWImg8723A_RF.o  \
+               hal/HalPwrSeqCmd.o      \
+               hal/odm_RegConfig8723A.o \
+               hal/rtl8723a_bt-coexist.o \
+               hal/odm_debug.o         \
+               hal/odm_interface.o     \
+               hal/odm_HWConfig.o      \
+               hal/odm.o               \
+               hal/rtl8723a_cmd.o      \
+               hal/rtl8723a_dm.o       \
+               hal/rtl8723a_hal_init.o \
+               hal/rtl8723a_phycfg.o   \
+               hal/rtl8723a_rf6052.o   \
+               hal/rtl8723a_rxdesc.o   \
+               hal/rtl8723a_sreset.o   \
+               hal/rtl8723a_xmit.o     \
+               hal/rtl8723au_led.o     \
+               hal/rtl8723au_recv.o    \
+               hal/rtl8723au_xmit.o    \
+               hal/usb_halinit.o       \
+               hal/usb_ops_linux.o     \
+               os_dep/ioctl_cfg80211.o \
+               os_dep/mlme_linux.o     \
+               os_dep/osdep_service.o  \
+               os_dep/os_intfs.o       \
+               os_dep/recv_linux.o     \
+               os_dep/usb_intf.o       \
+               os_dep/usb_ops_linux.o  \
+               os_dep/xmit_linux.o
+
+obj-$(CONFIG_R8723AU)  := r8723au.o
+
+ccflags-y += -D__CHECK_ENDIAN__ -I$(src)/include
diff --git a/drivers/staging/rtl8723au/TODO b/drivers/staging/rtl8723au/TODO
new file mode 100644 (file)
index 0000000..175a0ce
--- /dev/null
@@ -0,0 +1,13 @@
+TODO:
+- find and remove code valid only for 5 HGz. Many of the obvious
+  ones have been removed, but things like channel > 14 still exist.
+- find and remove any code for other chips that is left over
+- convert any remaining unusual variable types
+- find codes that can use %pM and %Nph formatting
+- checkpatch.pl fixes - most of the remaining ones are lines too long. Many
+  of them will require refactoring
+- merge Realtek's bugfixes and new features into the driver
+- switch to use MAC80211
+
+Please send any patches to Greg Kroah-Hartman <gregkh@linux.com>,
+Jes Sorensen <Jes.Sorensen@redhat.com>, and Larry Finger <Larry.Finger@lwfinger.net>.
diff --git a/drivers/staging/rtl8723au/core/rtw_ap.c b/drivers/staging/rtl8723au/core/rtw_ap.c
new file mode 100644 (file)
index 0000000..a357e98
--- /dev/null
@@ -0,0 +1,2087 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_AP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <linux/ieee80211.h>
+#include <wifi.h>
+
+#ifdef CONFIG_8723AU_AP_MODE
+
+extern unsigned char RTW_WPA_OUI23A[];
+extern unsigned char WMM_OUI23A[];
+extern unsigned char WPS_OUI23A[];
+extern unsigned char P2P_OUI23A[];
+extern unsigned char WFD_OUI23A[];
+
+void init_mlme_ap_info23a(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+       spin_lock_init(&pmlmepriv->bcn_update_lock);
+
+       /* for ACL */
+       _rtw_init_queue23a(&pacl_list->acl_node_q);
+
+       start_ap_mode23a(padapter);
+}
+
+void free_mlme_ap_info23a(struct rtw_adapter *padapter)
+{
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       pmlmepriv->update_bcn = false;
+       pmlmeext->bstart_bss = false;
+
+       rtw_sta_flush23a(padapter);
+
+       pmlmeinfo->state = _HW_STATE_NOLINK_;
+
+       /* free_assoc_sta_resources */
+       rtw_free_all_stainfo23a(padapter);
+
+       /* free bc/mc sta_info */
+       psta = rtw_get_bcmc_stainfo23a(padapter);
+       spin_lock_bh(&pstapriv->sta_hash_lock);
+       rtw_free_stainfo23a(padapter, psta);
+       spin_unlock_bh(&pstapriv->sta_hash_lock);
+}
+
+static void update_BCNTIM(struct rtw_adapter *padapter)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network;
+       unsigned char *pie = pnetwork_mlmeext->IEs;
+       u8 *p, *dst_ie, *premainder_ie = NULL, *pbackup_remainder_ie = NULL;
+       u16 tim_bitmap_le;
+       uint offset, tmp_len, tim_ielen, tim_ie_offset, remainder_ielen;
+
+       tim_bitmap_le = cpu_to_le16(pstapriv->tim_bitmap);
+
+       p = rtw_get_ie23a(pie + _FIXED_IE_LENGTH_, _TIM_IE_, &tim_ielen, pnetwork_mlmeext->IELength - _FIXED_IE_LENGTH_);
+       if (p != NULL && tim_ielen>0) {
+               tim_ielen += 2;
+
+               premainder_ie = p+tim_ielen;
+
+               tim_ie_offset = (int)(p -pie);
+
+               remainder_ielen = pnetwork_mlmeext->IELength - tim_ie_offset - tim_ielen;
+
+               /* append TIM IE from dst_ie offset */
+               dst_ie = p;
+       } else {
+               tim_ielen = 0;
+
+               /* calulate head_len */
+               offset = _FIXED_IE_LENGTH_;
+
+               /* get ssid_ie len */
+               p = rtw_get_ie23a(pie + _BEACON_IE_OFFSET_, _SSID_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+               if (p != NULL)
+                       offset += tmp_len+2;
+
+               /*  get supported rates len */
+               p = rtw_get_ie23a(pie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &tmp_len, (pnetwork_mlmeext->IELength - _BEACON_IE_OFFSET_));
+               if (p !=  NULL)
+                       offset += tmp_len+2;
+
+               /* DS Parameter Set IE, len = 3 */
+               offset += 3;
+
+               premainder_ie = pie + offset;
+
+               remainder_ielen = pnetwork_mlmeext->IELength - offset - tim_ielen;
+
+               /* append TIM IE from offset */
+               dst_ie = pie + offset;
+       }
+
+       if (remainder_ielen > 0) {
+               pbackup_remainder_ie = kmalloc(remainder_ielen, GFP_ATOMIC);
+               if (pbackup_remainder_ie && premainder_ie)
+                       memcpy(pbackup_remainder_ie, premainder_ie, remainder_ielen);
+       }
+
+       *dst_ie++= _TIM_IE_;
+
+       if ((pstapriv->tim_bitmap&0xff00) && (pstapriv->tim_bitmap&0x00fc))
+               tim_ielen = 5;
+       else
+               tim_ielen = 4;
+
+       *dst_ie++= tim_ielen;
+
+       *dst_ie++= 0;/* DTIM count */
+       *dst_ie++= 1;/* DTIM peroid */
+
+       if (pstapriv->tim_bitmap & BIT(0))/* for bc/mc frames */
+               *dst_ie++ = BIT(0);/* bitmap ctrl */
+       else
+               *dst_ie++ = 0;
+
+       if (tim_ielen == 4) {
+               *dst_ie++ = *(u8*)&tim_bitmap_le;
+       } else if (tim_ielen == 5) {
+               memcpy(dst_ie, &tim_bitmap_le, 2);
+               dst_ie+= 2;
+       }
+
+       /* copy remainder IE */
+       if (pbackup_remainder_ie) {
+               memcpy(dst_ie, pbackup_remainder_ie, remainder_ielen);
+
+               kfree(pbackup_remainder_ie);
+       }
+
+       offset =  (uint)(dst_ie - pie);
+       pnetwork_mlmeext->IELength = offset + remainder_ielen;
+
+       set_tx_beacon_cmd23a(padapter);
+}
+
+static u8 chk_sta_is_alive(struct sta_info *psta)
+{
+       u8 ret = false;
+
+       if ((psta->sta_stats.last_rx_data_pkts +
+           psta->sta_stats.last_rx_ctrl_pkts) !=
+           (psta->sta_stats.rx_data_pkts + psta->sta_stats.rx_ctrl_pkts))
+               ret = true;
+
+       sta_update_last_rx_pkts(psta);
+
+       return ret;
+}
+
+void   expire_timeout_chk23a(struct rtw_adapter *padapter)
+{
+       struct list_head *phead, *plist, *ptmp;
+       u8 updated = 0;
+       struct sta_info *psta;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       u8 chk_alive_num = 0;
+       char chk_alive_list[NUM_STA];
+       int i;
+
+       spin_lock_bh(&pstapriv->auth_list_lock);
+
+       phead = &pstapriv->auth_list;
+
+       /* check auth_queue */
+       list_for_each_safe(plist, ptmp, phead) {
+               psta = container_of(plist, struct sta_info, auth_list);
+
+               if (psta->expire_to>0) {
+                       psta->expire_to--;
+                       if (psta->expire_to == 0) {
+                               list_del_init(&psta->auth_list);
+                               pstapriv->auth_list_cnt--;
+
+                               DBG_8723A("auth expire %pM\n", psta->hwaddr);
+
+                               spin_unlock_bh(&pstapriv->auth_list_lock);
+
+                               spin_lock_bh(&pstapriv->sta_hash_lock);
+                               rtw_free_stainfo23a(padapter, psta);
+                               spin_unlock_bh(&pstapriv->sta_hash_lock);
+
+                               spin_lock_bh(&pstapriv->auth_list_lock);
+                       }
+               }
+
+       }
+
+       spin_unlock_bh(&pstapriv->auth_list_lock);
+
+       spin_lock_bh(&pstapriv->asoc_list_lock);
+
+       phead = &pstapriv->asoc_list;
+
+       /* check asoc_queue */
+       list_for_each_safe(plist, ptmp, phead) {
+               psta = container_of(plist, struct sta_info, asoc_list);
+
+               if (chk_sta_is_alive(psta) || !psta->expire_to) {
+                       psta->expire_to = pstapriv->expire_to;
+                       psta->keep_alive_trycnt = 0;
+               } else {
+                       psta->expire_to--;
+               }
+
+               if (psta->expire_to <= 0)
+               {
+                       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+                       if (padapter->registrypriv.wifi_spec == 1)
+                       {
+                               psta->expire_to = pstapriv->expire_to;
+                               continue;
+                       }
+
+                       if (psta->state & WIFI_SLEEP_STATE) {
+                               if (!(psta->state & WIFI_STA_ALIVE_CHK_STATE)) {
+                                       /* to check if alive by another methods if staion is at ps mode. */
+                                       psta->expire_to = pstapriv->expire_to;
+                                       psta->state |= WIFI_STA_ALIVE_CHK_STATE;
+
+                                       /* to update bcn with tim_bitmap for this station */
+                                       pstapriv->tim_bitmap |= CHKBIT(psta->aid);
+                                       update_beacon23a(padapter, _TIM_IE_, NULL, false);
+
+                                       if (!pmlmeext->active_keep_alive_check)
+                                               continue;
+                               }
+                       }
+
+                       if (pmlmeext->active_keep_alive_check) {
+                               int stainfo_offset;
+
+                               stainfo_offset = rtw_stainfo_offset23a(pstapriv, psta);
+                               if (stainfo_offset_valid(stainfo_offset)) {
+                                       chk_alive_list[chk_alive_num++] = stainfo_offset;
+                               }
+
+                               continue;
+                       }
+
+                       list_del_init(&psta->asoc_list);
+                       pstapriv->asoc_list_cnt--;
+
+                       DBG_8723A("asoc expire "MAC_FMT", state = 0x%x\n", MAC_ARG(psta->hwaddr), psta->state);
+                       updated = ap_free_sta23a(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING);
+               } else {
+                       /* TODO: Aging mechanism to digest frames in sleep_q to avoid running out of xmitframe */
+                       if (psta->sleepq_len > (NR_XMITFRAME/pstapriv->asoc_list_cnt)
+                               && padapter->xmitpriv.free_xmitframe_cnt < ((NR_XMITFRAME/pstapriv->asoc_list_cnt)/2)
+                       ) {
+                               DBG_8723A("%s sta:"MAC_FMT", sleepq_len:%u, free_xmitframe_cnt:%u, asoc_list_cnt:%u, clear sleep_q\n", __func__,
+                                         MAC_ARG(psta->hwaddr),
+                                         psta->sleepq_len,
+                                         padapter->xmitpriv.free_xmitframe_cnt,
+                                         pstapriv->asoc_list_cnt);
+                               wakeup_sta_to_xmit23a(padapter, psta);
+                       }
+               }
+       }
+
+       spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+       if (chk_alive_num) {
+
+               u8 backup_oper_channel = 0;
+               struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+               /* switch to correct channel of current network  before issue keep-alive frames */
+               if (rtw_get_oper_ch23a(padapter) != pmlmeext->cur_channel) {
+                       backup_oper_channel = rtw_get_oper_ch23a(padapter);
+                       SelectChannel23a(padapter, pmlmeext->cur_channel);
+       }
+
+       /* issue null data to check sta alive*/
+       for (i = 0; i < chk_alive_num; i++) {
+
+               int ret = _FAIL;
+
+               psta = rtw_get_stainfo23a_by_offset23a(pstapriv, chk_alive_list[i]);
+               if (!(psta->state &_FW_LINKED))
+                       continue;
+
+               if (psta->state & WIFI_SLEEP_STATE)
+                       ret = issue_nulldata23a(padapter, psta->hwaddr, 0, 1, 50);
+               else
+                       ret = issue_nulldata23a(padapter, psta->hwaddr, 0, 3, 50);
+
+               psta->keep_alive_trycnt++;
+               if (ret == _SUCCESS)
+               {
+                       DBG_8723A("asoc check, sta(" MAC_FMT ") is alive\n", MAC_ARG(psta->hwaddr));
+                       psta->expire_to = pstapriv->expire_to;
+                       psta->keep_alive_trycnt = 0;
+                       continue;
+               }
+               else if (psta->keep_alive_trycnt <= 3)
+               {
+                       DBG_8723A("ack check for asoc expire, keep_alive_trycnt =%d\n", psta->keep_alive_trycnt);
+                       psta->expire_to = 1;
+                       continue;
+               }
+
+               psta->keep_alive_trycnt = 0;
+
+               DBG_8723A("asoc expire "MAC_FMT", state = 0x%x\n", MAC_ARG(psta->hwaddr), psta->state);
+               spin_lock_bh(&pstapriv->asoc_list_lock);
+               if (!list_empty(&psta->asoc_list)) {
+                       list_del_init(&psta->asoc_list);
+                       pstapriv->asoc_list_cnt--;
+                       updated = ap_free_sta23a(padapter, psta, false, WLAN_REASON_DEAUTH_LEAVING);
+               }
+               spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+       }
+
+       if (backup_oper_channel>0) /* back to the original operation channel */
+               SelectChannel23a(padapter, backup_oper_channel);
+}
+
+       associated_clients_update23a(padapter, updated);
+}
+
+void add_RATid23a(struct rtw_adapter *padapter, struct sta_info *psta, u8 rssi_level)
+{
+       int i;
+       u8 rf_type;
+       u32 init_rate = 0;
+       unsigned char sta_band = 0, raid, shortGIrate = false;
+       unsigned char limit;
+       unsigned int tx_ra_bitmap = 0;
+       struct ht_priv *psta_ht = NULL;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+
+       if (psta)
+               psta_ht = &psta->htpriv;
+       else
+               return;
+
+       if (!(psta->state & _FW_LINKED))
+               return;
+
+       /* b/g mode ra_bitmap */
+       for (i = 0; i<sizeof(psta->bssrateset); i++)
+       {
+               if (psta->bssrateset[i])
+                       tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value23a(psta->bssrateset[i]&0x7f);
+       }
+       /* n mode ra_bitmap */
+       if (psta_ht->ht_option)
+       {
+               rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+               if (rf_type == RF_2T2R)
+                       limit = 16;/*  2R */
+               else
+                       limit = 8;/*   1R */
+
+               for (i = 0; i<limit; i++) {
+                       if (psta_ht->ht_cap.mcs.rx_mask[i/8] & BIT(i%8))
+                               tx_ra_bitmap |= CHKBIT(i+12);
+               }
+
+               /* max short GI rate */
+               shortGIrate = psta_ht->sgi;
+       }
+
+       if (pcur_network->Configuration.DSConfig > 14) {
+               /*  5G band */
+               if (tx_ra_bitmap & 0xffff000)
+                       sta_band |= WIRELESS_11_5N | WIRELESS_11A;
+               else
+                       sta_band |= WIRELESS_11A;
+       } else {
+               if (tx_ra_bitmap & 0xffff000)
+                       sta_band |= WIRELESS_11_24N | WIRELESS_11G | WIRELESS_11B;
+               else if (tx_ra_bitmap & 0xff0)
+                       sta_band |= WIRELESS_11G |WIRELESS_11B;
+               else
+                       sta_band |= WIRELESS_11B;
+       }
+
+       psta->wireless_mode = sta_band;
+
+       raid = networktype_to_raid23a(sta_band);
+       init_rate = get_highest_rate_idx23a(tx_ra_bitmap&0x0fffffff)&0x3f;
+
+       if (psta->aid < NUM_STA)
+       {
+               u8 arg = 0;
+
+               arg = psta->mac_id&0x1f;
+
+               arg |= BIT(7);/* support entry 2~31 */
+
+               if (shortGIrate == true)
+                       arg |= BIT(5);
+
+               tx_ra_bitmap |= ((raid<<28)&0xf0000000);
+
+               DBG_8723A("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = "
+                         "0x%x\n",
+                         __func__, psta->mac_id, raid, tx_ra_bitmap, arg);
+
+               /* bitmap[0:27] = tx_rate_bitmap */
+               /* bitmap[28:31]= Rate Adaptive id */
+               /* arg[0:4] = macid */
+               /* arg[5] = Short GI */
+               rtw_hal_add_ra_tid23a(padapter, tx_ra_bitmap, arg, rssi_level);
+
+               if (shortGIrate == true)
+                       init_rate |= BIT(6);
+
+               /* set ra_id, init_rate */
+               psta->raid = raid;
+               psta->init_rate = init_rate;
+
+       }
+       else
+       {
+               DBG_8723A("station aid %d exceed the max number\n", psta->aid);
+       }
+}
+
+static void update_bmc_sta(struct rtw_adapter *padapter)
+{
+       u32 init_rate = 0;
+       unsigned char network_type, raid;
+       int i, supportRateNum = 0;
+       unsigned int tx_ra_bitmap = 0;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_bssid_ex *pcur_network = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+       struct sta_info *psta = rtw_get_bcmc_stainfo23a(padapter);
+
+       if (psta)
+       {
+               psta->aid = 0;/* default set to 0 */
+               psta->mac_id = psta->aid + 1;
+
+               psta->qos_option = 0;
+               psta->htpriv.ht_option = false;
+
+               psta->ieee8021x_blocked = 0;
+
+               memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+               /* prepare for add_RATid23a */
+               supportRateNum = rtw_get_rateset_len23a((u8*)&pcur_network->SupportedRates);
+               network_type = rtw_check_network_type23a((u8*)&pcur_network->SupportedRates, supportRateNum, 1);
+
+               memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum);
+               psta->bssratelen = supportRateNum;
+
+               /* b/g mode ra_bitmap */
+               for (i = 0; i<supportRateNum; i++)
+               {
+                       if (psta->bssrateset[i])
+                               tx_ra_bitmap |= rtw_get_bit_value_from_ieee_value23a(psta->bssrateset[i]&0x7f);
+               }
+
+               if (pcur_network->Configuration.DSConfig > 14) {
+                       /* force to A mode. 5G doesn't support CCK rates */
+                       network_type = WIRELESS_11A;
+                       tx_ra_bitmap = 0x150; /*  6, 12, 24 Mbps */
+               } else {
+                       /* force to b mode */
+                       network_type = WIRELESS_11B;
+                       tx_ra_bitmap = 0xf;
+               }
+
+               raid = networktype_to_raid23a(network_type);
+               init_rate = get_highest_rate_idx23a(tx_ra_bitmap&0x0fffffff)&0x3f;
+
+               /* ap mode */
+               rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, true);
+
+               {
+                       u8 arg = 0;
+
+                       arg = psta->mac_id&0x1f;
+
+                       arg |= BIT(7);
+
+                       tx_ra_bitmap |= ((raid<<28)&0xf0000000);
+
+                       DBG_8723A("update_bmc_sta, mask = 0x%x, arg = 0x%x\n", tx_ra_bitmap, arg);
+
+                       /* bitmap[0:27] = tx_rate_bitmap */
+                       /* bitmap[28:31]= Rate Adaptive id */
+                       /* arg[0:4] = macid */
+                       /* arg[5] = Short GI */
+                       rtw_hal_add_ra_tid23a(padapter, tx_ra_bitmap, arg, 0);
+
+               }
+
+               /* set ra_id, init_rate */
+               psta->raid = raid;
+               psta->init_rate = init_rate;
+
+               rtw_stassoc_hw_rpt23a(padapter, psta);
+
+               spin_lock_bh(&psta->lock);
+               psta->state = _FW_LINKED;
+               spin_unlock_bh(&psta->lock);
+
+       }
+       else
+       {
+               DBG_8723A("add_RATid23a_bmc_sta error!\n");
+       }
+}
+
+/* notes: */
+/* AID: 1~MAX for sta and 0 for bc/mc in ap/adhoc mode */
+/* MAC_ID = AID+1 for sta in ap/adhoc mode */
+/* MAC_ID = 1 for bc/mc for sta/ap/adhoc */
+/* MAC_ID = 0 for bssid for sta/ap/adhoc */
+/* CAM_ID = 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */
+
+void update_sta_info23a_apmode23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv;
+       struct ht_priv *phtpriv_sta = &psta->htpriv;
+       /* set intf_tag to if1 */
+
+       psta->mac_id = psta->aid+1;
+       DBG_8723A("%s\n", __func__);
+
+       /* ap mode */
+       rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, true);
+
+       if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
+               psta->ieee8021x_blocked = true;
+       else
+               psta->ieee8021x_blocked = false;
+
+       /* update sta's cap */
+
+       /* ERP */
+       VCS_update23a(padapter, psta);
+       /* HT related cap */
+       if (phtpriv_sta->ht_option)
+       {
+               /* check if sta supports rx ampdu */
+               phtpriv_sta->ampdu_enable = phtpriv_ap->ampdu_enable;
+
+               /* check if sta support s Short GI */
+               if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SGI_20|IEEE80211_HT_CAP_SGI_40))
+                       phtpriv_sta->sgi = true;
+
+               /*  bwmode */
+               if ((phtpriv_sta->ht_cap.cap_info & phtpriv_ap->ht_cap.cap_info) & cpu_to_le16(IEEE80211_HT_CAP_SUP_WIDTH_20_40)) {
+                       /* phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_40; */
+                       phtpriv_sta->bwmode = pmlmeext->cur_bwmode;
+                       phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+
+               }
+
+               psta->qos_option = true;
+
+       }
+       else
+       {
+               phtpriv_sta->ampdu_enable = false;
+
+               phtpriv_sta->sgi = false;
+               phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20;
+               phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+       }
+
+       /* Rx AMPDU */
+       send_delba23a(padapter, 0, psta->hwaddr);/*  recipient */
+
+       /* TX AMPDU */
+       send_delba23a(padapter, 1, psta->hwaddr);/*  originator */
+       phtpriv_sta->agg_enable_bitmap = 0x0;/* reset */
+       phtpriv_sta->candidate_tid_bitmap = 0x0;/* reset */
+
+       /* todo: init other variables */
+
+       memset((void*)&psta->sta_stats, 0, sizeof(struct stainfo_stats));
+
+       spin_lock_bh(&psta->lock);
+       psta->state |= _FW_LINKED;
+       spin_unlock_bh(&psta->lock);
+}
+
+static void update_hw_ht_param(struct rtw_adapter *padapter)
+{
+       unsigned char max_AMPDU_len;
+       unsigned char min_MPDU_spacing;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       DBG_8723A("%s\n", __func__);
+
+       /* handle A-MPDU parameter field */
+       /*
+               AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+               AMPDU_para [4:2]:Min MPDU Start Spacing
+       */
+       max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;
+
+       min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+
+       /*  Config SM Power Save setting */
+       pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2;
+       if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
+               DBG_8723A("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
+}
+
+static void start_bss_network(struct rtw_adapter *padapter, u8 *pbuf)
+{
+       u8 *p;
+       u8 val8, cur_channel, cur_bwmode, cur_ch_offset;
+       u16 bcn_interval;
+       u32 acparm;
+       int ie_len;
+       struct registry_priv *pregpriv = &padapter->registrypriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct security_priv* psecuritypriv = &padapter->securitypriv;
+       struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)&pmlmepriv->cur_network.network;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork_mlmeext = &pmlmeinfo->network;
+       struct HT_info_element *pht_info = NULL;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_8723AU_P2P */
+
+       bcn_interval = (u16)pnetwork->Configuration.BeaconPeriod;
+       cur_channel = pnetwork->Configuration.DSConfig;
+       cur_bwmode = HT_CHANNEL_WIDTH_20;;
+       cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+       /* check if there is wps ie, */
+       /* if there is wpsie in beacon, the hostapd will update beacon twice when stating hostapd, */
+       /* and at first time the security ie (RSN/WPA IE) will not include in beacon. */
+       if (NULL == rtw_get_wps_ie23a(pnetwork->IEs+_FIXED_IE_LENGTH_, pnetwork->IELength-_FIXED_IE_LENGTH_, NULL, NULL))
+               pmlmeext->bstart_bss = true;
+
+       /* todo: update wmm, ht cap */
+       /* pmlmeinfo->WMM_enable; */
+       /* pmlmeinfo->HT_enable; */
+       if (pmlmepriv->qospriv.qos_option)
+               pmlmeinfo->WMM_enable = true;
+       if (pmlmepriv->htpriv.ht_option) {
+               pmlmeinfo->WMM_enable = true;
+               pmlmeinfo->HT_enable = true;
+
+               update_hw_ht_param(padapter);
+       }
+
+       if (pmlmepriv->cur_network.join_res != true) {
+               /* setting only at  first time */
+               /* WEP Key will be set before this function, do not clear CAM. */
+               if ((psecuritypriv->dot11PrivacyAlgrthm != _WEP40_) && (psecuritypriv->dot11PrivacyAlgrthm != _WEP104_))
+                       flush_all_cam_entry23a(padapter);       /* clear CAM */
+       }
+
+       /* set MSR to AP_Mode */
+       Set_MSR23a(padapter, _HW_STATE_AP_);
+
+       /* Set BSSID REG */
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, pnetwork->MacAddress);
+
+       /* Set EDCA param reg */
+       acparm = 0x002F3217; /*  VO */
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acparm));
+       acparm = 0x005E4317; /*  VI */
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acparm));
+       acparm = 0x005ea42b;
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acparm));
+       acparm = 0x0000A444; /*  BK */
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acparm));
+
+       /* Set Security */
+       val8 = (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf;
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+       /* Beacon Control related register */
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&bcn_interval));
+
+       UpdateBrateTbl23a(padapter, pnetwork->SupportedRates);
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, pnetwork->SupportedRates);
+
+       if (!pmlmepriv->cur_network.join_res) {
+               /* setting only at  first time */
+
+               /* disable dynamic functions, such as high power, DIG */
+
+               /* turn on all dynamic functions */
+               Switch_DM_Func23a(padapter, DYNAMIC_ALL_FUNC_ENABLE, true);
+       }
+       /* set channel, bwmode */
+       p = rtw_get_ie23a((pnetwork->IEs + sizeof(struct ndis_802_11_fixed_ies)),
+                         _HT_ADD_INFO_IE_, &ie_len, (pnetwork->IELength -
+                         sizeof(struct ndis_802_11_fixed_ies)));
+       if (p && ie_len) {
+               pht_info = (struct HT_info_element *)(p+2);
+
+               if ((pregpriv->cbw40_enable) && (pht_info->infos[0] & BIT(2))) {
+                       /* switch to the 40M Hz mode */
+                       cur_bwmode = HT_CHANNEL_WIDTH_40;
+                       switch (pht_info->infos[0] & 0x3) {
+                       case 1:
+                               /* pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER; */
+                               cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+                               break;
+                       case 3:
+                               cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+                               break;
+                       default:
+                               cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+                               break;
+                       }
+               }
+       }
+       /* TODO: need to judge the phy parameters on concurrent mode for single phy */
+       set_channel_bwmode23a(padapter, cur_channel, cur_ch_offset, cur_bwmode);
+
+       DBG_8723A("CH =%d, BW =%d, offset =%d\n", cur_channel, cur_bwmode,
+                 cur_ch_offset);
+
+       pmlmeext->cur_channel = cur_channel;
+       pmlmeext->cur_bwmode = cur_bwmode;
+       pmlmeext->cur_ch_offset = cur_ch_offset;
+       pmlmeext->cur_wireless_mode = pmlmepriv->cur_network.network_type;
+
+       /* update cur_wireless_mode */
+       update_wireless_mode23a(padapter);
+
+       /* udpate capability after cur_wireless_mode updated */
+       update_capinfo23a(padapter, rtw_get_capability23a((struct wlan_bssid_ex *)pnetwork));
+
+       /* let pnetwork_mlmeext == pnetwork_mlme. */
+       memcpy(pnetwork_mlmeext, pnetwork, pnetwork->Length);
+
+#ifdef CONFIG_8723AU_P2P
+       memcpy(pwdinfo->p2p_group_ssid, pnetwork->Ssid.ssid,
+              pnetwork->Ssid.ssid_len);
+       pwdinfo->p2p_group_ssid_len = pnetwork->Ssid.ssid_len;
+#endif /* CONFIG_8723AU_P2P */
+
+       if (pmlmeext->bstart_bss) {
+               update_beacon23a(padapter, _TIM_IE_, NULL, false);
+
+               /* issue beacon frame */
+               if (send_beacon23a(padapter) == _FAIL)
+                       DBG_8723A("issue_beacon23a, fail!\n");
+       }
+
+       /* update bc/mc sta_info */
+       update_bmc_sta(padapter);
+}
+
+int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf,  int len)
+{
+       int ret = _SUCCESS;
+       u8 *p;
+       u8 *pHT_caps_ie = NULL;
+       u8 *pHT_info_ie = NULL;
+       struct sta_info *psta = NULL;
+       u16 cap, ht_cap = false;
+       uint ie_len = 0;
+       int group_cipher, pairwise_cipher;
+       u8 channel, network_type, supportRate[NDIS_802_11_LENGTH_RATES_EX];
+       int supportRateNum = 0;
+       u8 OUI1[] = {0x00, 0x50, 0xf2, 0x01};
+       u8 WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+       struct registry_priv *pregistrypriv = &padapter->registrypriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_bssid_ex *pbss_network = &pmlmepriv->cur_network.network;
+       u8 *ie = pbss_network->IEs;
+
+       /* SSID */
+       /* Supported rates */
+       /* DS Params */
+       /* WLAN_EID_COUNTRY */
+       /* ERP Information element */
+       /* Extended supported rates */
+       /* WPA/WPA2 */
+       /* Wi-Fi Wireless Multimedia Extensions */
+       /* ht_capab, ht_oper */
+       /* WPS IE */
+
+       DBG_8723A("%s, len =%d\n", __func__, len);
+
+       if (!check_fwstate(pmlmepriv, WIFI_AP_STATE))
+               return _FAIL;
+
+       if (len>MAX_IE_SZ)
+               return _FAIL;
+
+       pbss_network->IELength = len;
+
+       memset(ie, 0, MAX_IE_SZ);
+
+       memcpy(ie, pbuf, pbss_network->IELength);
+
+       if (pbss_network->InfrastructureMode!= Ndis802_11APMode)
+               return _FAIL;
+
+       pbss_network->Rssi = 0;
+
+       memcpy(pbss_network->MacAddress, myid(&padapter->eeprompriv), ETH_ALEN);
+
+       /* beacon interval */
+       /* ie + 8;  8: TimeStamp, 2: Beacon Interval 2:Capability */
+       p = rtw_get_beacon_interval23a_from_ie(ie);
+       pbss_network->Configuration.BeaconPeriod = get_unaligned_le16(p);
+
+       /* capability */
+       cap = get_unaligned_le16(ie);
+
+       /* SSID */
+       p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _SSID_IE_, &ie_len,
+                         (pbss_network->IELength -_BEACON_IE_OFFSET_));
+       if (p && ie_len > 0) {
+               memset(&pbss_network->Ssid, 0, sizeof(struct cfg80211_ssid));
+               memcpy(pbss_network->Ssid.ssid, (p + 2), ie_len);
+               pbss_network->Ssid.ssid_len = ie_len;
+       }
+
+       /* chnnel */
+       channel = 0;
+       pbss_network->Configuration.Length = 0;
+       p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _DSSET_IE_, &ie_len,
+                         (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p && ie_len > 0)
+               channel = *(p + 2);
+
+       pbss_network->Configuration.DSConfig = channel;
+
+       memset(supportRate, 0, NDIS_802_11_LENGTH_RATES_EX);
+       /*  get supported rates */
+       p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _SUPPORTEDRATES_IE_, &ie_len,
+                         (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p) {
+               memcpy(supportRate, p+2, ie_len);
+               supportRateNum = ie_len;
+       }
+
+       /* get ext_supported rates */
+       p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_,
+                         &ie_len, pbss_network->IELength - _BEACON_IE_OFFSET_);
+       if (p) {
+               memcpy(supportRate+supportRateNum, p+2, ie_len);
+               supportRateNum += ie_len;
+       }
+
+       network_type = rtw_check_network_type23a(supportRate,
+                                                supportRateNum, channel);
+
+       rtw_set_supported_rate23a(pbss_network->SupportedRates, network_type);
+
+       /* parsing ERP_IE */
+       p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &ie_len,
+                         (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p && ie_len > 0)
+               ERP_IE_handler23a(padapter, (struct ndis_802_11_var_ies *)p);
+
+       /* update privacy/security */
+       if (cap & BIT(4))
+               pbss_network->Privacy = 1;
+       else
+               pbss_network->Privacy = 0;
+
+       psecuritypriv->wpa_psk = 0;
+
+       /* wpa2 */
+       group_cipher = 0; pairwise_cipher = 0;
+       psecuritypriv->wpa2_group_cipher = _NO_PRIVACY_;
+       psecuritypriv->wpa2_pairwise_cipher = _NO_PRIVACY_;
+       p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _RSN_IE_2_, &ie_len,
+                         (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p && ie_len > 0) {
+               if (rtw_parse_wpa2_ie23a(p, ie_len+2, &group_cipher,
+                                        &pairwise_cipher, NULL) == _SUCCESS) {
+                       psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+                       psecuritypriv->dot8021xalg = 1;/* psk,  todo:802.1x */
+                       psecuritypriv->wpa_psk |= BIT(1);
+
+                       psecuritypriv->wpa2_group_cipher = group_cipher;
+                       psecuritypriv->wpa2_pairwise_cipher = pairwise_cipher;
+               }
+       }
+
+       /* wpa */
+       ie_len = 0;
+       group_cipher = 0;
+       pairwise_cipher = 0;
+       psecuritypriv->wpa_group_cipher = _NO_PRIVACY_;
+       psecuritypriv->wpa_pairwise_cipher = _NO_PRIVACY_;
+       for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) {
+               p = rtw_get_ie23a(p, _SSN_IE_1_, &ie_len,
+                                 (pbss_network->IELength - _BEACON_IE_OFFSET_ -
+                                 (ie_len + 2)));
+               if ((p) && (!memcmp(p+2, OUI1, 4))) {
+                       if (rtw_parse_wpa_ie23a(p, ie_len+2, &group_cipher,
+                                               &pairwise_cipher, NULL) == _SUCCESS) {
+                               psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+                               /* psk,  todo:802.1x */
+                               psecuritypriv->dot8021xalg = 1;
+
+                               psecuritypriv->wpa_psk |= BIT(0);
+
+                               psecuritypriv->wpa_group_cipher = group_cipher;
+                               psecuritypriv->wpa_pairwise_cipher = pairwise_cipher;
+                       }
+                       break;
+               }
+
+               if ((p == NULL) || (ie_len == 0))
+                               break;
+       }
+
+       /* wmm */
+       ie_len = 0;
+       pmlmepriv->qospriv.qos_option = 0;
+       if (pregistrypriv->wmm_enable) {
+               for (p = ie + _BEACON_IE_OFFSET_; ;p += (ie_len + 2)) {
+                       p = rtw_get_ie23a(p, _VENDOR_SPECIFIC_IE_, &ie_len,
+                                         (pbss_network->IELength -
+                                         _BEACON_IE_OFFSET_ - (ie_len + 2)));
+                       if ((p) && !memcmp(p+2, WMM_PARA_IE, 6)) {
+                               pmlmepriv->qospriv.qos_option = 1;
+
+                               *(p+8) |= BIT(7);/* QoS Info, support U-APSD */
+
+                               /* disable all ACM bits since the WMM admission
+                                * control is not supported
+                                */
+                               *(p + 10) &= ~BIT(4); /* BE */
+                               *(p + 14) &= ~BIT(4); /* BK */
+                               *(p + 18) &= ~BIT(4); /* VI */
+                               *(p + 22) &= ~BIT(4); /* VO */
+                               break;
+                       }
+                       if ((p == NULL) || (ie_len == 0))
+                               break;
+               }
+       }
+       /* parsing HT_CAP_IE */
+       p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _HT_CAPABILITY_IE_, &ie_len,
+                         (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p && ie_len > 0) {
+               u8 rf_type;
+
+               struct ieee80211_ht_cap *pht_cap = (struct ieee80211_ht_cap *)(p+2);
+
+               pHT_caps_ie = p;
+
+               ht_cap = true;
+               network_type |= WIRELESS_11_24N;
+
+               rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+               if ((psecuritypriv->wpa_pairwise_cipher & WPA_CIPHER_CCMP) ||
+                   (psecuritypriv->wpa2_pairwise_cipher & WPA_CIPHER_CCMP))
+                       pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY & (0x07<<2));
+               else
+                       pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_DENSITY&0x00);
+
+               /* set  Max Rx AMPDU size  to 64K */
+               pht_cap->ampdu_params_info |= (IEEE80211_HT_AMPDU_PARM_FACTOR & 0x03);
+
+               if (rf_type == RF_1T1R) {
+                       pht_cap->mcs.rx_mask[0] = 0xff;
+                       pht_cap->mcs.rx_mask[1] = 0x0;
+               }
+
+               memcpy(&pmlmepriv->htpriv.ht_cap, p+2, ie_len);
+       }
+
+       /* parsing HT_INFO_IE */
+       p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_, &ie_len,
+                         (pbss_network->IELength - _BEACON_IE_OFFSET_));
+       if (p && ie_len > 0)
+               pHT_info_ie = p;
+
+       switch (network_type) {
+       case WIRELESS_11B:
+               pbss_network->NetworkTypeInUse = Ndis802_11DS;
+               break;
+       case WIRELESS_11G:
+       case WIRELESS_11BG:
+            case WIRELESS_11G_24N:
+       case WIRELESS_11BG_24N:
+               pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+               break;
+       case WIRELESS_11A:
+               pbss_network->NetworkTypeInUse = Ndis802_11OFDM5;
+               break;
+       default :
+               pbss_network->NetworkTypeInUse = Ndis802_11OFDM24;
+               break;
+       }
+
+       pmlmepriv->cur_network.network_type = network_type;
+
+       pmlmepriv->htpriv.ht_option = false;
+
+       /* ht_cap */
+       if (pregistrypriv->ht_enable && ht_cap) {
+               pmlmepriv->htpriv.ht_option = true;
+               pmlmepriv->qospriv.qos_option = 1;
+
+               if (pregistrypriv->ampdu_enable == 1)
+                       pmlmepriv->htpriv.ampdu_enable = true;
+
+               HT_caps_handler23a(padapter, (struct ndis_802_11_var_ies *)pHT_caps_ie);
+
+               HT_info_handler23a(padapter, (struct ndis_802_11_var_ies *)pHT_info_ie);
+       }
+
+       pbss_network->Length = get_wlan_bssid_ex_sz((struct wlan_bssid_ex  *)pbss_network);
+
+       /* issue beacon to start bss network */
+       start_bss_network(padapter, (u8*)pbss_network);
+
+       /* alloc sta_info for ap itself */
+       psta = rtw_get_stainfo23a(&padapter->stapriv, pbss_network->MacAddress);
+       if (!psta) {
+               psta = rtw_alloc_stainfo23a(&padapter->stapriv, pbss_network->MacAddress);
+               if (!psta)
+                       return _FAIL;
+       }
+       /* fix bug of flush_cam_entry at STOP AP mode */
+       psta->state |= WIFI_AP_STATE;
+       rtw_indicate_connect23a(padapter);
+
+       /* for check if already set beacon */
+       pmlmepriv->cur_network.join_res = true;
+
+       return ret;
+}
+
+void rtw_set_macaddr_acl23a(struct rtw_adapter *padapter, int mode)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+       DBG_8723A("%s, mode =%d\n", __func__, mode);
+
+       pacl_list->mode = mode;
+}
+
+int rtw_acl_add_sta23a(struct rtw_adapter *padapter, u8 *addr)
+{
+       struct list_head *plist, *phead;
+       u8 added = false;
+       int i, ret = 0;
+       struct rtw_wlan_acl_node *paclnode;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+       struct rtw_queue *pacl_node_q = &pacl_list->acl_node_q;
+
+       DBG_8723A("%s(acl_num =%d) =" MAC_FMT "\n", __func__, pacl_list->num, MAC_ARG(addr));
+
+       if ((NUM_ACL-1) < pacl_list->num)
+               return -1;
+
+       spin_lock_bh(&pacl_node_q->lock);
+
+       phead = get_list_head(pacl_node_q);
+
+       list_for_each(plist, phead) {
+               paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+
+               if (!memcmp(paclnode->addr, addr, ETH_ALEN)) {
+                       if (paclnode->valid == true) {
+                               added = true;
+                               DBG_8723A("%s, sta has been added\n", __func__);
+                               break;
+                       }
+               }
+       }
+
+       spin_unlock_bh(&pacl_node_q->lock);
+
+       if (added)
+               return ret;
+
+       spin_lock_bh(&pacl_node_q->lock);
+
+       for (i = 0; i < NUM_ACL; i++) {
+               paclnode = &pacl_list->aclnode[i];
+
+               if (!paclnode->valid) {
+                       INIT_LIST_HEAD(&paclnode->list);
+
+                       memcpy(paclnode->addr, addr, ETH_ALEN);
+
+                       paclnode->valid = true;
+
+                       list_add_tail(&paclnode->list, get_list_head(pacl_node_q));
+
+                       pacl_list->num++;
+
+                       break;
+               }
+       }
+
+       DBG_8723A("%s, acl_num =%d\n", __func__, pacl_list->num);
+
+       spin_unlock_bh(&pacl_node_q->lock);
+       return ret;
+}
+
+int rtw_acl_remove_sta23a(struct rtw_adapter *padapter, u8 *addr)
+{
+       struct list_head *plist, *phead, *ptmp;
+       struct rtw_wlan_acl_node *paclnode;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+       struct rtw_queue *pacl_node_q = &pacl_list->acl_node_q;
+       int ret = 0;
+
+       DBG_8723A("%s(acl_num =%d) = %pM\n", __func__, pacl_list->num, addr);
+
+       spin_lock_bh(&pacl_node_q->lock);
+
+       phead = get_list_head(pacl_node_q);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+
+               if (!memcmp(paclnode->addr, addr, ETH_ALEN)) {
+                       if (paclnode->valid) {
+                               paclnode->valid = false;
+
+                               list_del_init(&paclnode->list);
+
+                               pacl_list->num--;
+                       }
+               }
+       }
+
+       spin_unlock_bh(&pacl_node_q->lock);
+
+       DBG_8723A("%s, acl_num =%d\n", __func__, pacl_list->num);
+
+       return ret;
+}
+
+static void update_bcn_fixed_ie(struct rtw_adapter *padapter)
+{
+       DBG_8723A("%s\n", __func__);
+}
+
+static void update_bcn_erpinfo_ie(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
+       unsigned char *p, *ie = pnetwork->IEs;
+       u32 len = 0;
+
+       DBG_8723A("%s, ERP_enable =%d\n", __func__, pmlmeinfo->ERP_enable);
+
+       if (!pmlmeinfo->ERP_enable)
+               return;
+
+       /* parsing ERP_IE */
+       p = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _ERPINFO_IE_, &len, (pnetwork->IELength - _BEACON_IE_OFFSET_));
+       if (p && len>0)
+       {
+               struct ndis_802_11_var_ies * pIE = (struct ndis_802_11_var_ies *)p;
+
+               if (pmlmepriv->num_sta_non_erp == 1)
+                       pIE->data[0] |= WLAN_ERP_NON_ERP_PRESENT |
+                               WLAN_ERP_USE_PROTECTION;
+               else
+                       pIE->data[0] &= ~(WLAN_ERP_NON_ERP_PRESENT |
+                                         WLAN_ERP_USE_PROTECTION);
+
+               if (pmlmepriv->num_sta_no_short_preamble > 0)
+                       pIE->data[0] |= WLAN_ERP_BARKER_PREAMBLE;
+               else
+                       pIE->data[0] &= ~(WLAN_ERP_BARKER_PREAMBLE);
+
+               ERP_IE_handler23a(padapter, pIE);
+       }
+}
+
+static void update_bcn_htcap_ie(struct rtw_adapter *padapter)
+{
+       DBG_8723A("%s\n", __func__);
+}
+
+static void update_bcn_htinfo_ie(struct rtw_adapter *padapter)
+{
+       DBG_8723A("%s\n", __func__);
+}
+
+static void update_bcn_rsn_ie(struct rtw_adapter *padapter)
+{
+       DBG_8723A("%s\n", __func__);
+}
+
+static void update_bcn_wpa_ie(struct rtw_adapter *padapter)
+{
+       DBG_8723A("%s\n", __func__);
+}
+
+static void update_bcn_wmm_ie(struct rtw_adapter *padapter)
+{
+       DBG_8723A("%s\n", __func__);
+}
+
+static void update_bcn_wps_ie(struct rtw_adapter *padapter)
+{
+       u8 *pwps_ie = NULL, *pwps_ie_src, *premainder_ie, *pbackup_remainder_ie = NULL;
+       uint wps_ielen = 0, wps_offset, remainder_ielen;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
+       unsigned char *ie = pnetwork->IEs;
+       u32 ielen = pnetwork->IELength;
+
+       DBG_8723A("%s\n", __func__);
+
+       pwps_ie = rtw_get_wps_ie23a(ie+_FIXED_IE_LENGTH_, ielen-_FIXED_IE_LENGTH_, NULL, &wps_ielen);
+
+       if (pwps_ie == NULL || wps_ielen == 0)
+               return;
+
+       wps_offset = (uint)(pwps_ie-ie);
+
+       premainder_ie = pwps_ie + wps_ielen;
+
+       remainder_ielen = ielen - wps_offset - wps_ielen;
+
+       if (remainder_ielen > 0) {
+               pbackup_remainder_ie = kmalloc(remainder_ielen, GFP_ATOMIC);
+               if (pbackup_remainder_ie)
+                       memcpy(pbackup_remainder_ie, premainder_ie,
+                              remainder_ielen);
+       }
+
+       pwps_ie_src = pmlmepriv->wps_beacon_ie;
+       if (pwps_ie_src == NULL)
+               return;
+
+       wps_ielen = (uint)pwps_ie_src[1];/* to get ie data len */
+       if ((wps_offset+wps_ielen+2+remainder_ielen)<= MAX_IE_SZ)
+       {
+               memcpy(pwps_ie, pwps_ie_src, wps_ielen+2);
+               pwps_ie += (wps_ielen+2);
+
+               if (pbackup_remainder_ie)
+                       memcpy(pwps_ie, pbackup_remainder_ie, remainder_ielen);
+
+               /* update IELength */
+               pnetwork->IELength = wps_offset + (wps_ielen+2) + remainder_ielen;
+       }
+
+       if (pbackup_remainder_ie)
+               kfree(pbackup_remainder_ie);
+}
+
+static void update_bcn_p2p_ie(struct rtw_adapter *padapter)
+{
+}
+
+static void update_bcn_vendor_spec_ie(struct rtw_adapter *padapter, u8*oui)
+{
+       DBG_8723A("%s\n", __func__);
+
+       if (!memcmp(RTW_WPA_OUI23A, oui, 4))
+       {
+               update_bcn_wpa_ie(padapter);
+       }
+       else if (!memcmp(WMM_OUI23A, oui, 4))
+       {
+               update_bcn_wmm_ie(padapter);
+       }
+       else if (!memcmp(WPS_OUI23A, oui, 4))
+       {
+               update_bcn_wps_ie(padapter);
+       }
+       else if (!memcmp(P2P_OUI23A, oui, 4))
+       {
+               update_bcn_p2p_ie(padapter);
+       }
+       else
+       {
+               DBG_8723A("unknown OUI type!\n");
+       }
+}
+
+void update_beacon23a(struct rtw_adapter *padapter, u8 ie_id, u8 *oui, u8 tx)
+{
+       struct mlme_priv *pmlmepriv;
+       struct mlme_ext_priv *pmlmeext;
+       /* struct mlme_ext_info *pmlmeinfo; */
+
+       /* DBG_8723A("%s\n", __func__); */
+
+       if (!padapter)
+               return;
+
+       pmlmepriv = &padapter->mlmepriv;
+       pmlmeext = &padapter->mlmeextpriv;
+       /* pmlmeinfo = &pmlmeext->mlmext_info; */
+
+       if (false == pmlmeext->bstart_bss)
+               return;
+
+       spin_lock_bh(&pmlmepriv->bcn_update_lock);
+
+       switch (ie_id)
+       {
+               case 0xFF:
+
+                       update_bcn_fixed_ie(padapter);/* 8: TimeStamp, 2: Beacon Interval 2:Capability */
+
+                       break;
+
+               case _TIM_IE_:
+
+                       update_BCNTIM(padapter);
+
+                       break;
+
+               case _ERPINFO_IE_:
+
+                       update_bcn_erpinfo_ie(padapter);
+
+                       break;
+
+               case _HT_CAPABILITY_IE_:
+
+                       update_bcn_htcap_ie(padapter);
+
+                       break;
+
+               case _RSN_IE_2_:
+
+                       update_bcn_rsn_ie(padapter);
+
+                       break;
+
+               case _HT_ADD_INFO_IE_:
+
+                       update_bcn_htinfo_ie(padapter);
+
+                       break;
+
+               case _VENDOR_SPECIFIC_IE_:
+
+                       update_bcn_vendor_spec_ie(padapter, oui);
+
+                       break;
+
+               default:
+                       break;
+       }
+
+       pmlmepriv->update_bcn = true;
+
+       spin_unlock_bh(&pmlmepriv->bcn_update_lock);
+
+       if (tx)
+               set_tx_beacon_cmd23a(padapter);
+}
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+       - all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+       - all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+       in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+       however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+       (currently non-GF HT station is considered as non-HT STA also)
+*/
+static int rtw_ht_operation_update(struct rtw_adapter *padapter)
+{
+       u16 cur_op_mode, new_op_mode;
+       int op_mode_changes = 0;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct ht_priv *phtpriv_ap = &pmlmepriv->htpriv;
+
+       if (pmlmepriv->htpriv.ht_option == true)
+               return 0;
+
+       /* if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed) */
+       /*      return 0; */
+
+       DBG_8723A("%s current operation mode = 0x%X\n",
+                  __func__, pmlmepriv->ht_op_mode);
+
+       if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
+           && pmlmepriv->num_sta_ht_no_gf) {
+               pmlmepriv->ht_op_mode |=
+                       HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+               op_mode_changes++;
+       } else if ((pmlmepriv->ht_op_mode &
+                   HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+                  pmlmepriv->num_sta_ht_no_gf == 0) {
+               pmlmepriv->ht_op_mode &=
+                       ~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+               op_mode_changes++;
+       }
+
+       if (!(pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+           (pmlmepriv->num_sta_no_ht || pmlmepriv->olbc_ht)) {
+               pmlmepriv->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+               op_mode_changes++;
+       } else if ((pmlmepriv->ht_op_mode &
+                   HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+                  (pmlmepriv->num_sta_no_ht == 0 && !pmlmepriv->olbc_ht)) {
+               pmlmepriv->ht_op_mode &=
+                       ~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+               op_mode_changes++;
+       }
+
+       /* Note: currently we switch to the MIXED op mode if HT non-greenfield
+        * station is associated. Probably it's a theoretical case, since
+        * it looks like all known HT STAs support greenfield.
+        */
+       new_op_mode = 0;
+       if (pmlmepriv->num_sta_no_ht ||
+           (pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT))
+               new_op_mode = OP_MODE_MIXED;
+       else if ((phtpriv_ap->ht_cap.cap_info & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+                && pmlmepriv->num_sta_ht_20mhz)
+               new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+       else if (pmlmepriv->olbc_ht)
+               new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+       else
+               new_op_mode = OP_MODE_PURE;
+
+       cur_op_mode = pmlmepriv->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+       if (cur_op_mode != new_op_mode) {
+               pmlmepriv->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+               pmlmepriv->ht_op_mode |= new_op_mode;
+               op_mode_changes++;
+       }
+
+       DBG_8723A("%s new operation mode = 0x%X changes =%d\n",
+                  __func__, pmlmepriv->ht_op_mode, op_mode_changes);
+
+       return op_mode_changes;
+}
+
+void associated_clients_update23a(struct rtw_adapter *padapter, u8 updated)
+{
+       /* update associcated stations cap. */
+       if (updated == true)
+       {
+               struct list_head *phead, *plist, *ptmp;
+               struct sta_info *psta;
+               struct sta_priv *pstapriv = &padapter->stapriv;
+
+               spin_lock_bh(&pstapriv->asoc_list_lock);
+
+               phead = &pstapriv->asoc_list;
+
+               list_for_each_safe(plist, ptmp, phead) {
+                       psta = container_of(plist, struct sta_info, asoc_list);
+
+                       VCS_update23a(padapter, psta);
+               }
+
+               spin_unlock_bh(&pstapriv->asoc_list_lock);
+       }
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void bss_cap_update_on_sta_join23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       u8 beacon_updated = false;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       if (!(psta->flags & WLAN_STA_SHORT_PREAMBLE))
+       {
+               if (!psta->no_short_preamble_set)
+               {
+                       psta->no_short_preamble_set = 1;
+
+                       pmlmepriv->num_sta_no_short_preamble++;
+
+                       if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+                               (pmlmepriv->num_sta_no_short_preamble == 1))
+                       {
+                               beacon_updated = true;
+                               update_beacon23a(padapter, 0xFF, NULL, true);
+                       }
+
+               }
+       }
+       else
+       {
+               if (psta->no_short_preamble_set)
+               {
+                       psta->no_short_preamble_set = 0;
+
+                       pmlmepriv->num_sta_no_short_preamble--;
+
+                       if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+                               (pmlmepriv->num_sta_no_short_preamble == 0))
+                       {
+                               beacon_updated = true;
+                               update_beacon23a(padapter, 0xFF, NULL, true);
+                       }
+
+               }
+       }
+
+       if (psta->flags & WLAN_STA_NONERP)
+       {
+               if (!psta->nonerp_set)
+               {
+                       psta->nonerp_set = 1;
+
+                       pmlmepriv->num_sta_non_erp++;
+
+                       if (pmlmepriv->num_sta_non_erp == 1)
+                       {
+                               beacon_updated = true;
+                               update_beacon23a(padapter, _ERPINFO_IE_, NULL, true);
+                       }
+               }
+
+       }
+       else
+       {
+               if (psta->nonerp_set)
+               {
+                       psta->nonerp_set = 0;
+
+                       pmlmepriv->num_sta_non_erp--;
+
+                       if (pmlmepriv->num_sta_non_erp == 0)
+                       {
+                               beacon_updated = true;
+                               update_beacon23a(padapter, _ERPINFO_IE_, NULL, true);
+                       }
+               }
+
+       }
+
+       if (!(psta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME))
+       {
+               if (!psta->no_short_slot_time_set)
+               {
+                       psta->no_short_slot_time_set = 1;
+
+                       pmlmepriv->num_sta_no_short_slot_time++;
+
+                       if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+                                (pmlmepriv->num_sta_no_short_slot_time == 1))
+                       {
+                               beacon_updated = true;
+                               update_beacon23a(padapter, 0xFF, NULL, true);
+                       }
+
+               }
+       }
+       else
+       {
+               if (psta->no_short_slot_time_set)
+               {
+                       psta->no_short_slot_time_set = 0;
+
+                       pmlmepriv->num_sta_no_short_slot_time--;
+
+                       if ((pmlmeext->cur_wireless_mode > WIRELESS_11B) &&
+                                (pmlmepriv->num_sta_no_short_slot_time == 0))
+                       {
+                               beacon_updated = true;
+                               update_beacon23a(padapter, 0xFF, NULL, true);
+                       }
+               }
+       }
+
+       if (psta->flags & WLAN_STA_HT)
+       {
+               u16 ht_capab = le16_to_cpu(psta->htpriv.ht_cap.cap_info);
+
+               DBG_8723A("HT: STA " MAC_FMT " HT Capabilities "
+                          "Info: 0x%04x\n", MAC_ARG(psta->hwaddr), ht_capab);
+
+               if (psta->no_ht_set) {
+                       psta->no_ht_set = 0;
+                       pmlmepriv->num_sta_no_ht--;
+               }
+
+               if ((ht_capab & IEEE80211_HT_CAP_GRN_FLD) == 0) {
+                       if (!psta->no_ht_gf_set) {
+                               psta->no_ht_gf_set = 1;
+                               pmlmepriv->num_sta_ht_no_gf++;
+                       }
+                       DBG_8723A("%s STA " MAC_FMT " - no "
+                                  "greenfield, num of non-gf stations %d\n",
+                                  __func__, MAC_ARG(psta->hwaddr),
+                                  pmlmepriv->num_sta_ht_no_gf);
+               }
+
+               if ((ht_capab & IEEE80211_HT_CAP_SUP_WIDTH_20_40) == 0) {
+                       if (!psta->ht_20mhz_set) {
+                               psta->ht_20mhz_set = 1;
+                               pmlmepriv->num_sta_ht_20mhz++;
+                       }
+                       DBG_8723A("%s STA " MAC_FMT " - 20 MHz HT, "
+                                  "num of 20MHz HT STAs %d\n",
+                                  __func__, MAC_ARG(psta->hwaddr),
+                                  pmlmepriv->num_sta_ht_20mhz);
+               }
+
+       }
+       else
+       {
+               if (!psta->no_ht_set) {
+                       psta->no_ht_set = 1;
+                       pmlmepriv->num_sta_no_ht++;
+               }
+               if (pmlmepriv->htpriv.ht_option == true) {
+                       DBG_8723A("%s STA " MAC_FMT
+                                  " - no HT, num of non-HT stations %d\n",
+                                  __func__, MAC_ARG(psta->hwaddr),
+                                  pmlmepriv->num_sta_no_ht);
+               }
+       }
+
+       if (rtw_ht_operation_update(padapter) > 0)
+       {
+               update_beacon23a(padapter, _HT_CAPABILITY_IE_, NULL, false);
+               update_beacon23a(padapter, _HT_ADD_INFO_IE_, NULL, true);
+       }
+
+       /* update associcated stations cap. */
+       associated_clients_update23a(padapter,  beacon_updated);
+
+       DBG_8723A("%s, updated =%d\n", __func__, beacon_updated);
+}
+
+u8 bss_cap_update_on_sta_leave23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       u8 beacon_updated = false;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       if (!psta)
+               return beacon_updated;
+
+       if (psta->no_short_preamble_set) {
+               psta->no_short_preamble_set = 0;
+               pmlmepriv->num_sta_no_short_preamble--;
+               if (pmlmeext->cur_wireless_mode > WIRELESS_11B
+                   && pmlmepriv->num_sta_no_short_preamble == 0)
+               {
+                       beacon_updated = true;
+                       update_beacon23a(padapter, 0xFF, NULL, true);
+               }
+       }
+
+       if (psta->nonerp_set) {
+               psta->nonerp_set = 0;
+               pmlmepriv->num_sta_non_erp--;
+               if (pmlmepriv->num_sta_non_erp == 0)
+               {
+                       beacon_updated = true;
+                       update_beacon23a(padapter, _ERPINFO_IE_, NULL, true);
+               }
+       }
+
+       if (psta->no_short_slot_time_set) {
+               psta->no_short_slot_time_set = 0;
+               pmlmepriv->num_sta_no_short_slot_time--;
+               if (pmlmeext->cur_wireless_mode > WIRELESS_11B
+                   && pmlmepriv->num_sta_no_short_slot_time == 0)
+               {
+                       beacon_updated = true;
+                       update_beacon23a(padapter, 0xFF, NULL, true);
+               }
+       }
+
+       if (psta->no_ht_gf_set) {
+               psta->no_ht_gf_set = 0;
+               pmlmepriv->num_sta_ht_no_gf--;
+       }
+
+       if (psta->no_ht_set) {
+               psta->no_ht_set = 0;
+               pmlmepriv->num_sta_no_ht--;
+       }
+
+       if (psta->ht_20mhz_set) {
+               psta->ht_20mhz_set = 0;
+               pmlmepriv->num_sta_ht_20mhz--;
+       }
+
+       if (rtw_ht_operation_update(padapter) > 0)
+       {
+               update_beacon23a(padapter, _HT_CAPABILITY_IE_, NULL, false);
+               update_beacon23a(padapter, _HT_ADD_INFO_IE_, NULL, true);
+       }
+
+       /* update associcated stations cap. */
+
+       DBG_8723A("%s, updated =%d\n", __func__, beacon_updated);
+
+       return beacon_updated;
+}
+
+u8 ap_free_sta23a(struct rtw_adapter *padapter, struct sta_info *psta, bool active, u16 reason)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       u8 beacon_updated = false;
+
+       if (!psta)
+               return beacon_updated;
+
+       if (active == true)
+       {
+               /* tear down Rx AMPDU */
+               send_delba23a(padapter, 0, psta->hwaddr);/*  recipient */
+
+               /* tear down TX AMPDU */
+               send_delba23a(padapter, 1, psta->hwaddr);/* originator */
+
+               issue_deauth23a(padapter, psta->hwaddr, reason);
+       }
+
+       psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+       psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+       /* report_del_sta_event23a(padapter, psta->hwaddr, reason); */
+
+       /* clear cam entry / key */
+       /* clear_cam_entry23a(padapter, (psta->mac_id + 3)); */
+       rtw_clearstakey_cmd23a(padapter, (u8*)psta, (u8)(psta->mac_id + 3), true);
+
+       spin_lock_bh(&psta->lock);
+       psta->state &= ~_FW_LINKED;
+       spin_unlock_bh(&psta->lock);
+
+       rtw_cfg80211_indicate_sta_disassoc(padapter, psta->hwaddr, reason);
+
+       report_del_sta_event23a(padapter, psta->hwaddr, reason);
+
+       beacon_updated = bss_cap_update_on_sta_leave23a(padapter, psta);
+
+       spin_lock_bh(&pstapriv->sta_hash_lock);
+       rtw_free_stainfo23a(padapter, psta);
+       spin_unlock_bh(&pstapriv->sta_hash_lock);
+
+       return beacon_updated;
+}
+
+int rtw_ap_inform_ch_switch23a (struct rtw_adapter *padapter, u8 new_ch, u8 ch_offset)
+{
+       struct list_head *phead, *plist;
+       int ret = 0;
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+       if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+               return ret;
+
+       DBG_8723A(FUNC_NDEV_FMT" with ch:%u, offset:%u\n",
+               FUNC_NDEV_ARG(padapter->pnetdev), new_ch, ch_offset);
+
+       spin_lock_bh(&pstapriv->asoc_list_lock);
+       phead = &pstapriv->asoc_list;
+
+       list_for_each(plist, phead) {
+               psta = container_of(plist, struct sta_info, asoc_list);
+
+               issue_action_spct_ch_switch23a (padapter, psta->hwaddr, new_ch, ch_offset);
+               psta->expire_to = ((pstapriv->expire_to * 2) > 5) ? 5 : (pstapriv->expire_to * 2);
+       }
+       spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+       issue_action_spct_ch_switch23a (padapter, bc_addr, new_ch, ch_offset);
+
+       return ret;
+}
+
+int rtw_sta_flush23a(struct rtw_adapter *padapter)
+{
+       struct list_head *phead, *plist, *ptmp;
+       int ret = 0;
+       struct sta_info *psta;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+       u8 chk_alive_num = 0;
+       char chk_alive_list[NUM_STA];
+       int i;
+
+       DBG_8723A(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(padapter->pnetdev));
+
+       if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+               return ret;
+
+       spin_lock_bh(&pstapriv->asoc_list_lock);
+       phead = &pstapriv->asoc_list;
+
+       list_for_each_safe(plist, ptmp, phead) {
+               int stainfo_offset;
+
+               psta = container_of(plist, struct sta_info, asoc_list);
+
+               /* Remove sta from asoc_list */
+               list_del_init(&psta->asoc_list);
+               pstapriv->asoc_list_cnt--;
+
+               /* Keep sta for ap_free_sta23a() beyond this asoc_list loop */
+               stainfo_offset = rtw_stainfo_offset23a(pstapriv, psta);
+               if (stainfo_offset_valid(stainfo_offset)) {
+                       chk_alive_list[chk_alive_num++] = stainfo_offset;
+               }
+       }
+       spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+       /* For each sta in chk_alive_list, call ap_free_sta23a */
+       for (i = 0; i < chk_alive_num; i++) {
+               psta = rtw_get_stainfo23a_by_offset23a(pstapriv, chk_alive_list[i]);
+               ap_free_sta23a(padapter, psta, true, WLAN_REASON_DEAUTH_LEAVING);
+       }
+
+       issue_deauth23a(padapter, bc_addr, WLAN_REASON_DEAUTH_LEAVING);
+
+       associated_clients_update23a(padapter, true);
+
+       return ret;
+}
+
+/* called > TSR LEVEL for USB or SDIO Interface*/
+void sta_info_update23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       int flags = psta->flags;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       /* update wmm cap. */
+       if (WLAN_STA_WME&flags)
+               psta->qos_option = 1;
+       else
+               psta->qos_option = 0;
+
+       if (pmlmepriv->qospriv.qos_option == 0)
+               psta->qos_option = 0;
+
+       /* update 802.11n ht cap. */
+       if (WLAN_STA_HT&flags)
+       {
+               psta->htpriv.ht_option = true;
+               psta->qos_option = 1;
+       }
+       else
+       {
+               psta->htpriv.ht_option = false;
+       }
+
+       if (pmlmepriv->htpriv.ht_option == false)
+               psta->htpriv.ht_option = false;
+
+       update_sta_info23a_apmode23a(padapter, psta);
+}
+
+/* called >= TSR LEVEL for USB or SDIO Interface*/
+void ap_sta_info_defer_update23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       if (psta->state & _FW_LINKED)
+       {
+               /* add ratid */
+               add_RATid23a(padapter, psta, 0);/* DM_RATR_STA_INIT */
+       }
+}
+
+/* restore hw setting from sw data structures */
+void rtw_ap_restore_network(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct sta_priv * pstapriv = &padapter->stapriv;
+       struct sta_info *psta;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct list_head *phead, *plist, *ptmp;
+       u8 chk_alive_num = 0;
+       char chk_alive_list[NUM_STA];
+       int i;
+
+       rtw_setopmode_cmd23a(padapter, Ndis802_11APMode);
+
+       set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+       start_bss_network(padapter, (u8*)&mlmepriv->cur_network.network);
+
+       if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
+               (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_))
+       {
+               /* restore group key, WEP keys is restored in ips_leave23a() */
+               rtw_set_key23a(padapter, psecuritypriv, psecuritypriv->dot118021XGrpKeyid, 0);
+       }
+
+       /* per sta pairwise key and settings */
+       if ((padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_) &&
+               (padapter->securitypriv.dot11PrivacyAlgrthm != _AES_)) {
+               return;
+       }
+
+       spin_lock_bh(&pstapriv->asoc_list_lock);
+
+       phead = &pstapriv->asoc_list;
+
+       list_for_each_safe(plist, ptmp, phead) {
+               int stainfo_offset;
+
+               psta = container_of(plist, struct sta_info, asoc_list);
+
+               stainfo_offset = rtw_stainfo_offset23a(pstapriv, psta);
+               if (stainfo_offset_valid(stainfo_offset)) {
+                       chk_alive_list[chk_alive_num++] = stainfo_offset;
+               }
+       }
+
+       spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+       for (i = 0; i < chk_alive_num; i++) {
+               psta = rtw_get_stainfo23a_by_offset23a(pstapriv, chk_alive_list[i]);
+
+               if (psta == NULL) {
+                       DBG_8723A(FUNC_ADPT_FMT" sta_info is null\n", FUNC_ADPT_ARG(padapter));
+               }
+               else if (psta->state &_FW_LINKED)
+               {
+                       Update_RA_Entry23a(padapter, psta);
+                       /* pairwise key */
+                       rtw_setstakey_cmd23a(padapter, (unsigned char *)psta, true);
+               }
+       }
+}
+
+void start_ap_mode23a(struct rtw_adapter *padapter)
+{
+       int i;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+
+       pmlmepriv->update_bcn = false;
+
+       /* init_mlme_ap_info23a(padapter); */
+       pmlmeext->bstart_bss = false;
+
+       pmlmepriv->num_sta_non_erp = 0;
+
+       pmlmepriv->num_sta_no_short_slot_time = 0;
+
+       pmlmepriv->num_sta_no_short_preamble = 0;
+
+       pmlmepriv->num_sta_ht_no_gf = 0;
+       pmlmepriv->num_sta_no_ht = 0;
+       pmlmepriv->num_sta_ht_20mhz = 0;
+
+       pmlmepriv->olbc = false;
+
+       pmlmepriv->olbc_ht = false;
+
+       pmlmepriv->ht_op_mode = 0;
+
+       for (i = 0; i<NUM_STA; i++)
+               pstapriv->sta_aid[i] = NULL;
+
+       pmlmepriv->wps_beacon_ie = NULL;
+       pmlmepriv->wps_probe_resp_ie = NULL;
+       pmlmepriv->wps_assoc_resp_ie = NULL;
+
+       pmlmepriv->p2p_beacon_ie = NULL;
+       pmlmepriv->p2p_probe_resp_ie = NULL;
+
+       /* for ACL */
+       INIT_LIST_HEAD(&pacl_list->acl_node_q.queue);
+       pacl_list->num = 0;
+       pacl_list->mode = 0;
+       for (i = 0; i < NUM_ACL; i++) {
+               INIT_LIST_HEAD(&pacl_list->aclnode[i].list);
+               pacl_list->aclnode[i].valid = false;
+       }
+}
+
+void stop_ap_mode23a(struct rtw_adapter *padapter)
+{
+       struct list_head *phead, *plist, *ptmp;
+       struct rtw_wlan_acl_node *paclnode;
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+       struct rtw_queue *pacl_node_q = &pacl_list->acl_node_q;
+
+       pmlmepriv->update_bcn = false;
+       pmlmeext->bstart_bss = false;
+
+       /* reset and init security priv , this can refine with rtw_reset_securitypriv23a */
+       memset((unsigned char *)&padapter->securitypriv, 0, sizeof (struct security_priv));
+       padapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+       padapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+
+       /* for ACL */
+       spin_lock_bh(&pacl_node_q->lock);
+       phead = get_list_head(pacl_node_q);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+
+               if (paclnode->valid == true) {
+                       paclnode->valid = false;
+
+                       list_del_init(&paclnode->list);
+
+                       pacl_list->num--;
+               }
+       }
+       spin_unlock_bh(&pacl_node_q->lock);
+
+       DBG_8723A("%s, free acl_node_queue, num =%d\n", __func__, pacl_list->num);
+
+       rtw_sta_flush23a(padapter);
+
+       /* free_assoc_sta_resources */
+       rtw_free_all_stainfo23a(padapter);
+
+       psta = rtw_get_bcmc_stainfo23a(padapter);
+       spin_lock_bh(&pstapriv->sta_hash_lock);
+       rtw_free_stainfo23a(padapter, psta);
+       spin_unlock_bh(&pstapriv->sta_hash_lock);
+
+       rtw_init_bcmc_stainfo23a(padapter);
+
+       rtw23a_free_mlme_priv_ie_data(pmlmepriv);
+}
+
+#endif /* CONFIG_8723AU_AP_MODE */
diff --git a/drivers/staging/rtl8723au/core/rtw_cmd.c b/drivers/staging/rtl8723au/core/rtw_cmd.c
new file mode 100644 (file)
index 0000000..5e3088a
--- /dev/null
@@ -0,0 +1,1876 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_CMD_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <cmd_osdep.h>
+#include <mlme_osdep.h>
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+#include <rtl8723a_hal.h>
+#endif /*  CONFIG_8723AU_BT_COEXIST */
+
+static struct cmd_hdl wlancmds[] = {
+       GEN_DRV_CMD_HANDLER(0, NULL) /*0*/
+       GEN_DRV_CMD_HANDLER(0, NULL)
+       GEN_DRV_CMD_HANDLER(0, NULL)
+       GEN_DRV_CMD_HANDLER(0, NULL)
+       GEN_DRV_CMD_HANDLER(0, NULL)
+       GEN_DRV_CMD_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL) /*10*/
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct wlan_bssid_ex), join_cmd_hdl23a) /*14*/
+       GEN_MLME_EXT_HANDLER(sizeof (struct disconnect_parm), disconnect_hdl23a)
+       GEN_MLME_EXT_HANDLER(sizeof (struct wlan_bssid_ex), createbss_hdl23a)
+       GEN_MLME_EXT_HANDLER(sizeof (struct setopmode_parm), setopmode_hdl23a)
+       GEN_MLME_EXT_HANDLER(sizeof (struct sitesurvey_parm), sitesurvey_cmd_hdl23a) /*18*/
+       GEN_MLME_EXT_HANDLER(sizeof (struct setauth_parm), setauth_hdl23a)
+       GEN_MLME_EXT_HANDLER(sizeof (struct setkey_parm), setkey_hdl23a) /*20*/
+       GEN_MLME_EXT_HANDLER(sizeof (struct set_stakey_parm), set_stakey_hdl23a)
+       GEN_MLME_EXT_HANDLER(sizeof (struct set_assocsta_parm), NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct del_assocsta_parm), NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct setstapwrstate_parm), NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct setbasicrate_parm), NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct getbasicrate_parm), NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct setdatarate_parm), NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct getdatarate_parm), NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct setphyinfo_parm), NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct getphyinfo_parm), NULL)  /*30*/
+       GEN_MLME_EXT_HANDLER(sizeof (struct setphy_parm), NULL)
+       GEN_MLME_EXT_HANDLER(sizeof (struct getphy_parm), NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)   /*40*/
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(sizeof(struct addBaReq_parm), add_ba_hdl23a)
+       GEN_MLME_EXT_HANDLER(sizeof(struct set_ch_parm), set_ch_hdl23a) /* 46 */
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL) /*50*/
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(0, NULL)
+       GEN_MLME_EXT_HANDLER(sizeof(struct Tx_Beacon_param), tx_beacon_hdl23a) /*55*/
+
+       GEN_MLME_EXT_HANDLER(0, mlme_evt_hdl23a) /*56*/
+       GEN_MLME_EXT_HANDLER(0, rtw_drvextra_cmd_hdl23a) /*57*/
+
+       GEN_MLME_EXT_HANDLER(0, h2c_msg_hdl23a) /*58*/
+       GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelPlan_param), set_chplan_hdl23a) /*59*/
+       GEN_MLME_EXT_HANDLER(sizeof(struct LedBlink_param), led_blink_hdl23a) /*60*/
+
+       GEN_MLME_EXT_HANDLER(sizeof(struct SetChannelSwitch_param), set_csa_hdl23a) /*61*/
+       GEN_MLME_EXT_HANDLER(sizeof(struct TDLSoption_param), tdls_hdl23a) /*62*/
+};
+
+struct _cmd_callback   rtw_cmd_callback[] = {
+       {GEN_CMD_CODE(_Read_MACREG), NULL}, /*0*/
+       {GEN_CMD_CODE(_Write_MACREG), NULL},
+       {GEN_CMD_CODE(_Read_BBREG), &rtw_getbbrfreg_cmdrsp_callback23a},
+       {GEN_CMD_CODE(_Write_BBREG), NULL},
+       {GEN_CMD_CODE(_Read_RFREG), &rtw_getbbrfreg_cmdrsp_callback23a},
+       {GEN_CMD_CODE(_Write_RFREG), NULL}, /*5*/
+       {GEN_CMD_CODE(_Read_EEPROM), NULL},
+       {GEN_CMD_CODE(_Write_EEPROM), NULL},
+       {GEN_CMD_CODE(_Read_EFUSE), NULL},
+       {GEN_CMD_CODE(_Write_EFUSE), NULL},
+
+       {GEN_CMD_CODE(_Read_CAM),       NULL},  /*10*/
+       {GEN_CMD_CODE(_Write_CAM),       NULL},
+       {GEN_CMD_CODE(_setBCNITV), NULL},
+       {GEN_CMD_CODE(_setMBIDCFG), NULL},
+       {GEN_CMD_CODE(_JoinBss), &rtw_joinbss_cmd23a_callback},  /*14*/
+       {GEN_CMD_CODE(_DisConnect), &rtw_disassoc_cmd23a_callback}, /*15*/
+       {GEN_CMD_CODE(_CreateBss), &rtw_createbss_cmd23a_callback},
+       {GEN_CMD_CODE(_SetOpMode), NULL},
+       {GEN_CMD_CODE(_SiteSurvey), &rtw_survey_cmd_callback23a}, /*18*/
+       {GEN_CMD_CODE(_SetAuth), NULL},
+
+       {GEN_CMD_CODE(_SetKey), NULL},  /*20*/
+       {GEN_CMD_CODE(_SetStaKey), &rtw_setstaKey_cmdrsp_callback23a},
+       {GEN_CMD_CODE(_SetAssocSta), &rtw_setassocsta_cmdrsp_callback23a},
+       {GEN_CMD_CODE(_DelAssocSta), NULL},
+       {GEN_CMD_CODE(_SetStaPwrState), NULL},
+       {GEN_CMD_CODE(_SetBasicRate), NULL}, /*25*/
+       {GEN_CMD_CODE(_GetBasicRate), NULL},
+       {GEN_CMD_CODE(_SetDataRate), NULL},
+       {GEN_CMD_CODE(_GetDataRate), NULL},
+       {GEN_CMD_CODE(_SetPhyInfo), NULL},
+
+       {GEN_CMD_CODE(_GetPhyInfo), NULL}, /*30*/
+       {GEN_CMD_CODE(_SetPhy), NULL},
+       {GEN_CMD_CODE(_GetPhy), NULL},
+       {GEN_CMD_CODE(_readRssi), NULL},
+       {GEN_CMD_CODE(_readGain), NULL},
+       {GEN_CMD_CODE(_SetAtim), NULL}, /*35*/
+       {GEN_CMD_CODE(_SetPwrMode), NULL},
+       {GEN_CMD_CODE(_JoinbssRpt), NULL},
+       {GEN_CMD_CODE(_SetRaTable), NULL},
+       {GEN_CMD_CODE(_GetRaTable), NULL},
+
+       {GEN_CMD_CODE(_GetCCXReport), NULL}, /*40*/
+       {GEN_CMD_CODE(_GetDTMReport),   NULL},
+       {GEN_CMD_CODE(_GetTXRateStatistics), NULL},
+       {GEN_CMD_CODE(_SetUsbSuspend), NULL},
+       {GEN_CMD_CODE(_SetH2cLbk), NULL},
+       {GEN_CMD_CODE(_AddBAReq), NULL}, /*45*/
+       {GEN_CMD_CODE(_SetChannel), NULL},              /*46*/
+       {GEN_CMD_CODE(_SetTxPower), NULL},
+       {GEN_CMD_CODE(_SwitchAntenna), NULL},
+       {GEN_CMD_CODE(_SetCrystalCap), NULL},
+       {GEN_CMD_CODE(_SetSingleCarrierTx), NULL},      /*50*/
+
+       {GEN_CMD_CODE(_SetSingleToneTx), NULL}, /*51*/
+       {GEN_CMD_CODE(_SetCarrierSuppressionTx), NULL},
+       {GEN_CMD_CODE(_SetContinuousTx), NULL},
+       {GEN_CMD_CODE(_SwitchBandwidth), NULL},         /*54*/
+       {GEN_CMD_CODE(_TX_Beacon), NULL},/*55*/
+
+       {GEN_CMD_CODE(_Set_MLME_EVT), NULL},/*56*/
+       {GEN_CMD_CODE(_Set_Drv_Extra), NULL},/*57*/
+       {GEN_CMD_CODE(_Set_H2C_MSG), NULL},/*58*/
+       {GEN_CMD_CODE(_SetChannelPlan), NULL},/*59*/
+       {GEN_CMD_CODE(_LedBlink), NULL},/*60*/
+
+       {GEN_CMD_CODE(_SetChannelSwitch), NULL},/*61*/
+       {GEN_CMD_CODE(_TDLS), NULL},/*62*/
+};
+
+/*
+Caller and the rtw_cmd_thread23a can protect cmd_q by spin_lock.
+No irqsave is necessary.
+*/
+
+int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv)
+{
+       int res = _SUCCESS;
+
+       sema_init(&pcmdpriv->cmd_queue_sema, 0);
+       sema_init(&pcmdpriv->terminate_cmdthread_sema, 0);
+
+       _rtw_init_queue23a(&pcmdpriv->cmd_queue);
+
+       pcmdpriv->cmd_seq = 1;
+
+       pcmdpriv->cmd_allocated_buf = kzalloc(MAX_CMDSZ + CMDBUFF_ALIGN_SZ,
+                                             GFP_KERNEL);
+
+       if (pcmdpriv->cmd_allocated_buf == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pcmdpriv->cmd_buf = pcmdpriv->cmd_allocated_buf + CMDBUFF_ALIGN_SZ -
+                           ((unsigned long)(pcmdpriv->cmd_allocated_buf) &
+                           (CMDBUFF_ALIGN_SZ - 1));
+
+       pcmdpriv->rsp_allocated_buf = kzalloc(MAX_RSPSZ + 4, GFP_KERNEL);
+
+       if (!pcmdpriv->rsp_allocated_buf) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pcmdpriv->rsp_buf = pcmdpriv->rsp_allocated_buf + 4 -
+                           ((unsigned long)(pcmdpriv->rsp_allocated_buf) & 3);
+
+       pcmdpriv->cmd_issued_cnt = 0;
+       pcmdpriv->cmd_done_cnt = 0;
+       pcmdpriv->rsp_cnt = 0;
+
+exit:
+
+       return res;
+}
+
+/* forward definition */
+
+static void c2h_wk_callback(struct work_struct *work);
+int _rtw_init_evt_priv23a(struct evt_priv *pevtpriv)
+{
+       int res = _SUCCESS;
+
+       /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+       atomic_set(&pevtpriv->event_seq, 0);
+       pevtpriv->evt_done_cnt = 0;
+
+       INIT_WORK(&pevtpriv->c2h_wk, c2h_wk_callback);
+       pevtpriv->c2h_wk_alive = false;
+       pevtpriv->c2h_queue = rtw_cbuf_alloc23a(C2H_QUEUE_MAX_LEN + 1);
+
+       return res;
+}
+
+void _rtw_free_evt_priv23a (struct evt_priv *pevtpriv)
+{
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                ("+_rtw_free_evt_priv23a\n"));
+       cancel_work_sync(&pevtpriv->c2h_wk);
+       while(pevtpriv->c2h_wk_alive)
+               msleep(10);
+
+       while (!rtw_cbuf_empty23a(pevtpriv->c2h_queue)) {
+               void *c2h;
+               if ((c2h = rtw_cbuf_pop23a(pevtpriv->c2h_queue)) != NULL &&
+                   c2h != (void *)pevtpriv) {
+                       kfree(c2h);
+               }
+       }
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                ("-_rtw_free_evt_priv23a\n"));
+}
+
+void _rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv)
+{
+       if (pcmdpriv) {
+               kfree(pcmdpriv->cmd_allocated_buf);
+               kfree(pcmdpriv->rsp_allocated_buf);
+       }
+}
+
+/*
+Calling Context:
+rtw_enqueue_cmd23a can only be called between kernel thread,
+since only spin_lock is used.
+
+ISR/Call-Back functions can't call this sub-function.
+*/
+
+int _rtw_enqueue_cmd23a(struct rtw_queue *queue, struct cmd_obj *obj)
+{
+       unsigned long irqL;
+
+       if (obj == NULL)
+               goto exit;
+
+       spin_lock_irqsave(&queue->lock, irqL);
+
+       list_add_tail(&obj->list, &queue->queue);
+
+       spin_unlock_irqrestore(&queue->lock, irqL);
+
+exit:
+
+       return _SUCCESS;
+}
+
+u32 rtw_init_evt_priv23a(struct evt_priv *pevtpriv)
+{
+       int res;
+
+       res = _rtw_init_evt_priv23a(pevtpriv);
+
+       return res;
+}
+
+void rtw_free_evt_priv23a(struct evt_priv *pevtpriv)
+{
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                ("rtw_free_evt_priv23a\n"));
+       _rtw_free_evt_priv23a(pevtpriv);
+}
+
+void rtw_free_cmd_priv23a(struct cmd_priv *pcmdpriv)
+{
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                ("rtw_free_cmd_priv23a\n"));
+       _rtw_free_cmd_priv23a(pcmdpriv);
+}
+
+static int rtw_cmd_filter(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+       struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+       /* set to true to allow enqueuing cmd when hw_init_completed is false */
+       u8 bAllow = false;
+
+       /* To decide allow or not */
+       if (pcmdpriv->padapter->pwrctrlpriv.bHWPwrPindetect &&
+           !pcmdpriv->padapter->registrypriv.usbss_enable) {
+               if (cmd_obj->cmdcode == GEN_CMD_CODE(_Set_Drv_Extra)) {
+                       pdrvextra_cmd_parm =
+                               (struct drvextra_cmd_parm *)cmd_obj->parmbuf;
+                       if (pdrvextra_cmd_parm->ec_id ==
+                           POWER_SAVING_CTRL_WK_CID)
+                               bAllow = true;
+               }
+       }
+
+       if (cmd_obj->cmdcode == GEN_CMD_CODE(_SetChannelPlan))
+               bAllow = true;
+
+       if ((pcmdpriv->padapter->hw_init_completed == false &&
+            bAllow == false) || pcmdpriv->cmdthd_running == false)
+               return _FAIL;
+       return _SUCCESS;
+}
+
+u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *cmd_obj)
+{
+       int res = _FAIL;
+       struct rtw_adapter *padapter = pcmdpriv->padapter;
+
+       if (!cmd_obj)
+               goto exit;
+
+       cmd_obj->padapter = padapter;
+
+       res = rtw_cmd_filter(pcmdpriv, cmd_obj);
+       if (res == _FAIL) {
+               rtw_free_cmd_obj23a(cmd_obj);
+               goto exit;
+       }
+
+       res = _rtw_enqueue_cmd23a(&pcmdpriv->cmd_queue, cmd_obj);
+
+       if (res == _SUCCESS)
+               up(&pcmdpriv->cmd_queue_sema);
+
+exit:
+       return res;
+}
+
+static struct cmd_obj *rtw_dequeue_cmd(struct cmd_priv *pcmdpriv)
+{
+       struct cmd_obj *obj;
+       struct rtw_queue *queue = &pcmdpriv->cmd_queue;
+       unsigned long irqL;
+
+       spin_lock_irqsave(&queue->lock, irqL);
+       if (list_empty(&queue->queue))
+               obj = NULL;
+       else {
+               obj = container_of((&queue->queue)->next, struct cmd_obj, list);
+               list_del_init(&obj->list);
+       }
+
+       spin_unlock_irqrestore(&queue->lock, irqL);
+
+       return obj;
+}
+
+void rtw_cmd_clr_isr23a(struct cmd_priv *pcmdpriv)
+{
+       pcmdpriv->cmd_done_cnt++;
+}
+
+void rtw_free_cmd_obj23a(struct cmd_obj *pcmd)
+{
+
+       if (pcmd->cmdcode != _JoinBss_CMD_ &&
+           pcmd->cmdcode != _CreateBss_CMD_) {
+               /* free parmbuf in cmd_obj */
+               kfree(pcmd->parmbuf);
+       }
+
+       if (pcmd->rsp) {
+               if (pcmd->rspsz != 0) {
+                       /* free rsp in cmd_obj */
+                       kfree(pcmd->rsp);
+               }
+       }
+
+       kfree(pcmd);
+}
+
+int rtw_cmd_thread23a(void *context)
+{
+       u8 ret;
+       struct cmd_obj *pcmd;
+       u8 *pcmdbuf, *prspbuf;
+       u8 (*cmd_hdl)(struct rtw_adapter *padapter, u8* pbuf);
+       void (*pcmd_callback)(struct rtw_adapter *dev, struct cmd_obj *pcmd);
+       struct rtw_adapter *padapter = (struct rtw_adapter *)context;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       allow_signal(SIGTERM);
+
+       pcmdbuf = pcmdpriv->cmd_buf;
+       prspbuf = pcmdpriv->rsp_buf;
+
+       pcmdpriv->cmdthd_running = true;
+       up(&pcmdpriv->terminate_cmdthread_sema);
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                ("start r871x rtw_cmd_thread23a !!!!\n"));
+
+       while(1) {
+               if (down_interruptible(&pcmdpriv->cmd_queue_sema))
+                       break;
+_next:
+               if ((padapter->bDriverStopped == true) ||
+                   (padapter->bSurpriseRemoved == true)) {
+                       DBG_8723A("%s: DriverStopped(%d) SurpriseRemoved(%d) "
+                                 "break at line %d\n", __func__,
+                                 padapter->bDriverStopped,
+                                 padapter->bSurpriseRemoved, __LINE__);
+                       break;
+               }
+
+               if (!(pcmd = rtw_dequeue_cmd(pcmdpriv)))
+                       continue;
+
+               if (rtw_cmd_filter(pcmdpriv, pcmd) == _FAIL) {
+                       pcmd->res = H2C_DROPPED;
+                       goto post_process;
+               }
+
+               pcmdpriv->cmd_issued_cnt++;
+
+               pcmd->cmdsz = ALIGN(pcmd->cmdsz, 4);
+
+               memcpy(pcmdbuf, pcmd->parmbuf, pcmd->cmdsz);
+
+               if (pcmd->cmdcode < (sizeof(wlancmds)/sizeof(struct cmd_hdl))) {
+                       cmd_hdl = wlancmds[pcmd->cmdcode].h2cfuns;
+
+                       if (cmd_hdl) {
+                               ret = cmd_hdl(pcmd->padapter, pcmdbuf);
+                               pcmd->res = ret;
+                       }
+
+                       pcmdpriv->cmd_seq++;
+               } else
+                       pcmd->res = H2C_PARAMETERS_ERROR;
+
+               cmd_hdl = NULL;
+
+post_process:
+               /* call callback function for post-processed */
+               if (pcmd->cmdcode < (sizeof(rtw_cmd_callback) /
+                                    sizeof(struct _cmd_callback))) {
+                       pcmd_callback =
+                               rtw_cmd_callback[pcmd->cmdcode].callback;
+                       if (!pcmd_callback) {
+                               RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                                        ("mlme_cmd_hdl(): pcmd_callback = "
+                                         "0x%p, cmdcode = 0x%x\n",
+                                         pcmd_callback, pcmd->cmdcode));
+                               rtw_free_cmd_obj23a(pcmd);
+                       } else {
+                               /* todo: !!! fill rsp_buf to pcmd->rsp
+                                  if (pcmd->rsp!= NULL) */
+                               /* need conider that free cmd_obj in
+                                  rtw_cmd_callback */
+                               pcmd_callback(pcmd->padapter, pcmd);
+                       }
+               } else {
+                       RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                                ("%s: cmdcode = 0x%x callback not defined!\n",
+                                 __func__, pcmd->cmdcode));
+                       rtw_free_cmd_obj23a(pcmd);
+               }
+
+               if (signal_pending (current))
+                       flush_signals(current);
+
+               goto _next;
+
+       }
+       pcmdpriv->cmdthd_running = false;
+
+       /*  free all cmd_obj resources */
+       do {
+               pcmd = rtw_dequeue_cmd(pcmdpriv);
+               if (!pcmd)
+                       break;
+
+               rtw_free_cmd_obj23a(pcmd);
+       } while(1);
+
+       up(&pcmdpriv->terminate_cmdthread_sema);
+
+       complete_and_exit(NULL, 0);
+}
+
+u8 rtw_sitesurvey_cmd23a(struct rtw_adapter *padapter,
+                        struct cfg80211_ssid *ssid, int ssid_num,
+                        struct rtw_ieee80211_channel *ch, int ch_num)
+{
+       u8 res = _FAIL;
+       struct cmd_obj *ph2c;
+       struct sitesurvey_parm *psurveyPara;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+               rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_SCAN, 1);
+
+#ifdef CONFIG_8723AU_P2P
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+               p2p_ps_wk_cmd23a(padapter, P2P_PS_SCAN, 1);
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!ph2c)
+               return _FAIL;
+
+       psurveyPara = kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC);
+       if (!psurveyPara) {
+               kfree(ph2c);
+               return _FAIL;
+       }
+
+       rtw_free_network_queue23a(padapter, false);
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                ("%s: flush network queue\n", __func__));
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara,
+                                  GEN_CMD_CODE(_SiteSurvey));
+
+       /* psurveyPara->bsslimit = 48; */
+       psurveyPara->scan_mode = pmlmepriv->scan_mode;
+
+       /* prepare ssid list */
+       if (ssid) {
+               int i;
+               for (i = 0; i < ssid_num && i < RTW_SSID_SCAN_AMOUNT; i++) {
+                       if (ssid[i].ssid_len) {
+                               memcpy(&psurveyPara->ssid[i], &ssid[i],
+                                      sizeof(struct cfg80211_ssid));
+                               psurveyPara->ssid_num++;
+                               if (0)
+                               DBG_8723A(FUNC_ADPT_FMT" ssid:(%s, %d)\n",
+                                         FUNC_ADPT_ARG(padapter),
+                                         psurveyPara->ssid[i].ssid,
+                                         psurveyPara->ssid[i].ssid_len);
+                       }
+               }
+       }
+
+       /* prepare channel list */
+       if (ch) {
+               int i;
+               for (i = 0; i < ch_num && i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
+                       if (ch[i].hw_value &&
+                           !(ch[i].flags & IEEE80211_CHAN_DISABLED)) {
+                               memcpy(&psurveyPara->ch[i], &ch[i],
+                                      sizeof(struct rtw_ieee80211_channel));
+                               psurveyPara->ch_num++;
+                               if (0)
+                               DBG_8723A(FUNC_ADPT_FMT" ch:%u\n",
+                                         FUNC_ADPT_ARG(padapter),
+                                         psurveyPara->ch[i].hw_value);
+                       }
+               }
+       }
+
+       set_fwstate(pmlmepriv, _FW_UNDER_SURVEY);
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+
+       if (res == _SUCCESS) {
+               mod_timer(&pmlmepriv->scan_to_timer, jiffies +
+                         msecs_to_jiffies(SCANNING_TIMEOUT));
+
+               rtw_led_control(padapter, LED_CTL_SITE_SURVEY);
+
+               pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
+       } else
+               _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+
+       return res;
+}
+
+void rtw_getbbrfreg_cmdrsp_callback23a(struct rtw_adapter *padapter,
+                                      struct cmd_obj *pcmd)
+{
+       kfree(pcmd->parmbuf);
+       kfree(pcmd);
+}
+
+u8 rtw_createbss_cmd23a(struct rtw_adapter  *padapter)
+{
+       struct cmd_obj *pcmd;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_bssid_ex *pdev_network;
+       u8 res = _SUCCESS;
+
+       pdev_network = &padapter->registrypriv.dev_network;
+
+       rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+       if (pmlmepriv->assoc_ssid.ssid_len == 0) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                        (" createbss for Any SSid:%s\n",
+                         pmlmepriv->assoc_ssid.ssid));
+       } else {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                        (" createbss for SSid:%s\n",
+                         pmlmepriv->assoc_ssid.ssid));
+       }
+
+       pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!pcmd) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       INIT_LIST_HEAD(&pcmd->list);
+       pcmd->cmdcode = _CreateBss_CMD_;
+       pcmd->parmbuf = (unsigned char *)pdev_network;
+       pcmd->cmdsz = get_wlan_bssid_ex_sz((struct wlan_bssid_ex*)pdev_network);
+       pcmd->rsp = NULL;
+       pcmd->rspsz = 0;
+
+       pdev_network->Length = pcmd->cmdsz;
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, pcmd);
+
+exit:
+
+       return res;
+}
+
+u8 rtw_joinbss_cmd23a(struct rtw_adapter *padapter,
+                     struct wlan_network * pnetwork)
+{
+       u8 *auth, res = _SUCCESS;
+       uint t_len = 0;
+       struct wlan_bssid_ex *psecnetwork;
+       struct cmd_obj *pcmd;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct registry_priv *pregistrypriv = &padapter->registrypriv;
+       struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+       enum ndis_802_11_net_infra ndis_network_mode;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       ndis_network_mode = pnetwork->network.InfrastructureMode;
+
+       rtw_led_control(padapter, LED_CTL_START_TO_LINK);
+
+       if (pmlmepriv->assoc_ssid.ssid_len == 0) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_info_,
+                        ("+Join cmd: Any SSid\n"));
+       } else {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_,
+                        ("+Join cmd: SSid =[%s]\n",
+                         pmlmepriv->assoc_ssid.ssid));
+       }
+
+       pcmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!pcmd) {
+               res = _FAIL;
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                        ("rtw_joinbss_cmd23a: memory allocate for cmd_obj "
+                         "fail!!!\n"));
+               goto exit;
+       }
+       /* for IEs is fix buf size */
+       t_len = sizeof(struct wlan_bssid_ex);
+
+       /* for hidden ap to set fw_state here */
+       if (!check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_ADHOC_STATE)) {
+               switch (ndis_network_mode) {
+               case Ndis802_11IBSS:
+                       set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+                       break;
+               case Ndis802_11Infrastructure:
+                       set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+                       break;
+               case Ndis802_11APMode:
+               case Ndis802_11AutoUnknown:
+               case Ndis802_11InfrastructureMax:
+                       break;
+               }
+       }
+
+       psecnetwork = (struct wlan_bssid_ex *)&psecuritypriv->sec_bss;
+       if (!psecnetwork) {
+               if (pcmd)
+                       kfree(pcmd);
+
+               res = _FAIL;
+
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                        ("rtw_joinbss_cmd23a :psecnetwork == NULL!!!\n"));
+
+               goto exit;
+       }
+
+       memset(psecnetwork, 0, t_len);
+
+       memcpy(psecnetwork, &pnetwork->network,
+              get_wlan_bssid_ex_sz(&pnetwork->network));
+
+       auth = &psecuritypriv->authenticator_ie[0];
+       psecuritypriv->authenticator_ie[0] =
+               (unsigned char)psecnetwork->IELength;
+
+       if ((psecnetwork->IELength-12) < (256-1)) {
+               memcpy(&psecuritypriv->authenticator_ie[1],
+                      &psecnetwork->IEs[12], psecnetwork->IELength - 12);
+       } else {
+               memcpy(&psecuritypriv->authenticator_ie[1],
+                      &psecnetwork->IEs[12], 256 - 1);
+       }
+
+       psecnetwork->IELength = 0;
+       /*  Added by Albert 2009/02/18 */
+       /*  If the the driver wants to use the bssid to create the
+        *  connection. If not,  we have to copy the connecting AP's
+        *  MAC address to it so that the driver just has the bssid
+        *  information for PMKIDList searching. */
+
+       if (pmlmepriv->assoc_by_bssid == false)
+               ether_addr_copy(&pmlmepriv->assoc_bssid[0],
+                               &pnetwork->network.MacAddress[0]);
+
+       psecnetwork->IELength =
+               rtw_restruct_sec_ie23a(padapter, &pnetwork->network.IEs[0],
+                                      &psecnetwork->IEs[0],
+                                      pnetwork->network.IELength);
+
+       pqospriv->qos_option = 0;
+
+       if (pregistrypriv->wmm_enable) {
+               u32 tmp_len;
+
+               tmp_len = rtw_restruct_wmm_ie23a(padapter,
+                                                &pnetwork->network.IEs[0],
+                                                &psecnetwork->IEs[0],
+                                                pnetwork->network.IELength,
+                                                psecnetwork->IELength);
+
+               if (psecnetwork->IELength != tmp_len) {
+                       psecnetwork->IELength = tmp_len;
+                       /* There is WMM IE in this corresp. beacon */
+                       pqospriv->qos_option = 1;
+               } else {
+                       /* There is no WMM IE in this corresp. beacon */
+                       pqospriv->qos_option = 0;
+               }
+       }
+
+       phtpriv->ht_option = false;
+       if (pregistrypriv->ht_enable) {
+               /*      Added by Albert 2010/06/23 */
+               /*      For the WEP mode, we will use the bg mode to do
+                       the connection to avoid some IOT issue. */
+               /*      Especially for Realtek 8192u SoftAP. */
+               if ((padapter->securitypriv.dot11PrivacyAlgrthm != _WEP40_) &&
+                   (padapter->securitypriv.dot11PrivacyAlgrthm != _WEP104_) &&
+                   (padapter->securitypriv.dot11PrivacyAlgrthm != _TKIP_)) {
+                       /* rtw_restructure_ht_ie23a */
+                       rtw_restructure_ht_ie23a(padapter,
+                                                &pnetwork->network.IEs[0],
+                                                &psecnetwork->IEs[0],
+                                                pnetwork->network.IELength,
+                                                &psecnetwork->IELength);
+               }
+       }
+
+       pmlmeinfo->assoc_AP_vendor =
+               check_assoc_AP23a(pnetwork->network.IEs,
+                                 pnetwork->network.IELength);
+
+       if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_TENDA)
+               padapter->pwrctrlpriv.smart_ps = 0;
+       else
+               padapter->pwrctrlpriv.smart_ps =
+                       padapter->registrypriv.smart_ps;
+
+       DBG_8723A("%s: smart_ps =%d\n", __func__,
+                 padapter->pwrctrlpriv.smart_ps);
+
+       /* get cmdsz before endian conversion */
+       pcmd->cmdsz = get_wlan_bssid_ex_sz(psecnetwork);
+
+       INIT_LIST_HEAD(&pcmd->list);
+       pcmd->cmdcode = _JoinBss_CMD_;/* GEN_CMD_CODE(_JoinBss) */
+       pcmd->parmbuf = (unsigned char *)psecnetwork;
+       pcmd->rsp = NULL;
+       pcmd->rspsz = 0;
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, pcmd);
+exit:
+
+       return res;
+}
+
+u8 rtw_disassoc_cmd23a(struct rtw_adapter*padapter, u32 deauth_timeout_ms,
+                      bool enqueue)
+{
+       struct cmd_obj *cmdobj = NULL;
+       struct disconnect_parm *param = NULL;
+       struct cmd_priv *cmdpriv = &padapter->cmdpriv;
+       u8 res = _SUCCESS;
+
+       RT_TRACE(_module_rtl871x_cmd_c_, _drv_notice_,
+                ("+rtw_disassoc_cmd23a\n"));
+
+       /* prepare cmd parameter */
+       param = kzalloc(sizeof(*param), GFP_ATOMIC);
+       if (param == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+       param->deauth_timeout_ms = deauth_timeout_ms;
+
+       if (enqueue) {
+               /* need enqueue, prepare cmd_obj and enqueue */
+               cmdobj = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+               if (!cmdobj) {
+                       res = _FAIL;
+                       kfree(param);
+                       goto exit;
+               }
+               init_h2fwcmd_w_parm_no_rsp(cmdobj, param, _DisConnect_CMD_);
+               res = rtw_enqueue_cmd23a(cmdpriv, cmdobj);
+       } else {
+               /* no need to enqueue, do the cmd hdl directly and
+                  free cmd parameter */
+               if (H2C_SUCCESS != disconnect_hdl23a(padapter, (u8 *)param))
+                       res = _FAIL;
+               kfree(param);
+       }
+
+exit:
+       return res;
+}
+
+u8 rtw_setopmode_cmd23a(struct rtw_adapter *padapter,
+                       enum ndis_802_11_net_infra networktype)
+{
+       struct  cmd_obj *ph2c;
+       struct  setopmode_parm *psetop;
+       struct  cmd_priv   *pcmdpriv = &padapter->cmdpriv;
+       u8 res = _SUCCESS;
+
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       if (!ph2c) {
+               res = false;
+               goto exit;
+       }
+       psetop = kzalloc(sizeof(struct setopmode_parm), GFP_KERNEL);
+
+       if (!psetop) {
+               kfree(ph2c);
+               res = false;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psetop, _SetOpMode_CMD_);
+       psetop->mode = (u8)networktype;
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+exit:
+       return res;
+}
+
+u8 rtw_setstakey_cmd23a(struct rtw_adapter *padapter, u8 *psta, u8 unicast_key)
+{
+       struct cmd_obj *ph2c;
+       struct set_stakey_parm *psetstakey_para;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct set_stakey_rsp *psetstakey_rsp = NULL;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct sta_info *sta = (struct sta_info*)psta;
+       u8 res = _SUCCESS;
+
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       if (!ph2c) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL);
+       if (!psetstakey_para) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp), GFP_KERNEL);
+       if (!psetstakey_rsp) {
+               kfree(ph2c);
+               kfree(psetstakey_para);
+               res = _FAIL;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+       ph2c->rsp = (u8 *) psetstakey_rsp;
+       ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+       ether_addr_copy(psetstakey_para->addr, sta->hwaddr);
+
+       if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+               psetstakey_para->algorithm =
+                       (unsigned char)psecuritypriv->dot11PrivacyAlgrthm;
+       } else {
+               GET_ENCRY_ALGO(psecuritypriv, sta, psetstakey_para->algorithm,
+                              false);
+       }
+
+       if (unicast_key == true) {
+               memcpy(&psetstakey_para->key, &sta->dot118021x_UncstKey, 16);
+        } else {
+               int idx = psecuritypriv->dot118021XGrpKeyid;
+               memcpy(&psetstakey_para->key,
+                      &psecuritypriv->dot118021XGrpKey[idx].skey, 16);
+        }
+
+       /* jeff: set this becasue at least sw key is ready */
+       padapter->securitypriv.busetkipkey = true;
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+
+exit:
+
+       return res;
+}
+
+u8 rtw_clearstakey_cmd23a(struct rtw_adapter *padapter, u8 *psta, u8 entry,
+                         u8 enqueue)
+{
+       struct cmd_obj *ph2c;
+       struct set_stakey_parm *psetstakey_para;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct set_stakey_rsp *psetstakey_rsp = NULL;
+       struct sta_info *sta = (struct sta_info *)psta;
+       u8 res = _SUCCESS;
+
+       if (!enqueue) {
+               clear_cam_entry23a(padapter, entry);
+       } else {
+               ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+               if (!ph2c) {
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               psetstakey_para = kzalloc(sizeof(struct set_stakey_parm),
+                                         GFP_KERNEL);
+               if (!psetstakey_para) {
+                       kfree(ph2c);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               psetstakey_rsp = kzalloc(sizeof(struct set_stakey_rsp),
+                                        GFP_KERNEL);
+               if (!psetstakey_rsp) {
+                       kfree(ph2c);
+                       kfree(psetstakey_para);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para,
+                                          _SetStaKey_CMD_);
+               ph2c->rsp = (u8 *) psetstakey_rsp;
+               ph2c->rspsz = sizeof(struct set_stakey_rsp);
+
+               ether_addr_copy(psetstakey_para->addr, sta->hwaddr);
+
+               psetstakey_para->algorithm = _NO_PRIVACY_;
+
+               psetstakey_para->id = entry;
+
+               res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+       }
+exit:
+       return res;
+}
+
+u8 rtw_addbareq_cmd23a(struct rtw_adapter*padapter, u8 tid, u8 *addr)
+{
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct cmd_obj *ph2c;
+       struct addBaReq_parm *paddbareq_parm;
+       u8 res = _SUCCESS;
+
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!ph2c) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       paddbareq_parm = kzalloc(sizeof(struct addBaReq_parm), GFP_ATOMIC);
+       if (!paddbareq_parm) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       paddbareq_parm->tid = tid;
+       ether_addr_copy(paddbareq_parm->addr, addr);
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, paddbareq_parm,
+                                  GEN_CMD_CODE(_AddBAReq));
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+exit:
+       return res;
+}
+
+u8 rtw_dynamic_chk_wk_cmd23a(struct rtw_adapter*padapter)
+{
+       struct cmd_obj *ph2c;
+       struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8 res = _SUCCESS;
+
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!ph2c) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm = kzalloc(sizeof(*pdrvextra_cmd_parm), GFP_ATOMIC);
+       if (!pdrvextra_cmd_parm) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = DYNAMIC_CHK_WK_CID;
+       pdrvextra_cmd_parm->type_size = 0;
+       pdrvextra_cmd_parm->pbuf = (u8 *)padapter;
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm,
+                                  GEN_CMD_CODE(_Set_Drv_Extra));
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+exit:
+
+       return res;
+}
+
+/*
+ * This is only ever called from on_action_spct23a_ch_switch () which isn't
+ * called from anywhere itself
+ */
+u8 rtw_set_ch_cmd23a(struct rtw_adapter*padapter, u8 ch, u8 bw, u8 ch_offset,
+                    u8 enqueue)
+{
+       struct cmd_obj *pcmdobj;
+       struct set_ch_parm *set_ch_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       u8 res = _SUCCESS;
+
+       DBG_8723A(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
+                 FUNC_NDEV_ARG(padapter->pnetdev), ch, bw, ch_offset);
+
+       /* check input parameter */
+
+       /* prepare cmd parameter */
+       set_ch_parm = kzalloc(sizeof(*set_ch_parm), GFP_KERNEL);
+       if (!set_ch_parm) {
+               res = _FAIL;
+               goto exit;
+       }
+       set_ch_parm->ch = ch;
+       set_ch_parm->bw = bw;
+       set_ch_parm->ch_offset = ch_offset;
+
+       if (enqueue) {
+               /* need enqueue, prepare cmd_obj and enqueue */
+               pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+               if (!pcmdobj) {
+                       kfree(set_ch_parm);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm,
+                                          GEN_CMD_CODE(_SetChannel));
+               res = rtw_enqueue_cmd23a(pcmdpriv, pcmdobj);
+       } else {
+               /* no need to enqueue, do the cmd hdl directly and
+                  free cmd parameter */
+               if (H2C_SUCCESS != set_ch_hdl23a(padapter, (u8 *)set_ch_parm))
+                       res = _FAIL;
+
+               kfree(set_ch_parm);
+       }
+
+       /* do something based on res... */
+exit:
+
+       DBG_8723A(FUNC_NDEV_FMT" res:%u\n", FUNC_NDEV_ARG(padapter->pnetdev),
+                 res);
+
+       return res;
+}
+
+static void traffic_status_watchdog(struct rtw_adapter *padapter)
+{
+       u8 bEnterPS;
+       u8 bBusyTraffic = false, bTxBusyTraffic = false, bRxBusyTraffic = false;
+       u8 bHigherBusyTraffic = false, bHigherBusyRxTraffic = false;
+       u8 bHigherBusyTxTraffic = false;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#ifndef CONFIG_8723AU_BT_COEXIST
+       int BusyThreshold = 100;
+#endif
+       /*  */
+       /*  Determine if our traffic is busy now */
+       /*  */
+       if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+#ifdef CONFIG_8723AU_BT_COEXIST
+               if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 50 ||
+                   pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 50)
+#else /*  !CONFIG_8723AU_BT_COEXIST */
+               /*  if we raise bBusyTraffic in last watchdog, using
+                   lower threshold. */
+               if (pmlmepriv->LinkDetectInfo.bBusyTraffic)
+                       BusyThreshold = 75;
+               if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > BusyThreshold ||
+                   pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > BusyThreshold)
+#endif /*  !CONFIG_8723AU_BT_COEXIST */
+               {
+                       bBusyTraffic = true;
+
+                       if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod >
+                           pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+                               bRxBusyTraffic = true;
+                       else
+                               bTxBusyTraffic = true;
+               }
+
+               /*  Higher Tx/Rx data. */
+               if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod > 4000 ||
+                   pmlmepriv->LinkDetectInfo.NumTxOkInPeriod > 4000) {
+                       bHigherBusyTraffic = true;
+
+                       if (pmlmepriv->LinkDetectInfo.NumRxOkInPeriod >
+                           pmlmepriv->LinkDetectInfo.NumTxOkInPeriod)
+                               bHigherBusyRxTraffic = true;
+                       else
+                               bHigherBusyTxTraffic = true;
+               }
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+               if (BT_1Ant(padapter) == false)
+#endif
+               {
+               /*  check traffic for  powersaving. */
+               if (((pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod +
+                     pmlmepriv->LinkDetectInfo.NumTxOkInPeriod) > 8) ||
+                   (pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod > 2))
+                       bEnterPS = false;
+               else
+                       bEnterPS = true;
+
+               /*  LeisurePS only work in infra mode. */
+               if (bEnterPS)
+                       LPS_Enter23a(padapter);
+               else
+                       LPS_Leave23a(padapter);
+               }
+       } else
+               LPS_Leave23a(padapter);
+
+       pmlmepriv->LinkDetectInfo.NumRxOkInPeriod = 0;
+       pmlmepriv->LinkDetectInfo.NumTxOkInPeriod = 0;
+       pmlmepriv->LinkDetectInfo.NumRxUnicastOkInPeriod = 0;
+       pmlmepriv->LinkDetectInfo.bBusyTraffic = bBusyTraffic;
+       pmlmepriv->LinkDetectInfo.bTxBusyTraffic = bTxBusyTraffic;
+       pmlmepriv->LinkDetectInfo.bRxBusyTraffic = bRxBusyTraffic;
+       pmlmepriv->LinkDetectInfo.bHigherBusyTraffic = bHigherBusyTraffic;
+       pmlmepriv->LinkDetectInfo.bHigherBusyRxTraffic = bHigherBusyRxTraffic;
+       pmlmepriv->LinkDetectInfo.bHigherBusyTxTraffic = bHigherBusyTxTraffic;
+}
+
+void dynamic_chk_wk_hdl(struct rtw_adapter *padapter, u8 *pbuf, int sz)
+{
+       struct mlme_priv *pmlmepriv;
+
+       padapter = (struct rtw_adapter *)pbuf;
+       pmlmepriv = &padapter->mlmepriv;
+
+#ifdef CONFIG_8723AU_AP_MODE
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
+               expire_timeout_chk23a(padapter);
+#endif
+
+       rtw_hal_sreset_xmit_status_check23a(padapter);
+
+       linked_status_chk23a(padapter);
+       traffic_status_watchdog(padapter);
+
+       rtw_hal_dm_watchdog23a(padapter);
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       /*  */
+       /*  BT-Coexist */
+       /*  */
+       BT_CoexistMechanism(padapter);
+#endif
+}
+
+void lps_ctrl_wk_hdl(struct rtw_adapter *padapter, u8 lps_ctrl_type)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       u8 mstatus;
+
+       if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
+           (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
+               return;
+
+       switch (lps_ctrl_type)
+       {
+               case LPS_CTRL_SCAN:
+#ifdef CONFIG_8723AU_BT_COEXIST
+                       BT_WifiScanNotify(padapter, true);
+                       if (BT_1Ant(padapter) == false)
+#endif
+                       {
+                               if (check_fwstate(pmlmepriv, _FW_LINKED))
+                                       LPS_Leave23a(padapter);
+                       }
+                       break;
+               case LPS_CTRL_JOINBSS:
+                       LPS_Leave23a(padapter);
+                       break;
+               case LPS_CTRL_CONNECT:
+                       mstatus = 1;/* connect */
+                       /*  Reset LPS Setting */
+                       padapter->pwrctrlpriv.LpsIdleCount = 0;
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_JOINBSSRPT,
+                                            (u8 *)&mstatus);
+#ifdef CONFIG_8723AU_BT_COEXIST
+                       BT_WifiMediaStatusNotify(padapter, mstatus);
+#endif
+                       break;
+               case LPS_CTRL_DISCONNECT:
+                       mstatus = 0;/* disconnect */
+#ifdef CONFIG_8723AU_BT_COEXIST
+                       BT_WifiMediaStatusNotify(padapter, mstatus);
+                       if (BT_1Ant(padapter) == false)
+#endif
+                       {
+                               LPS_Leave23a(padapter);
+                       }
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_JOINBSSRPT,
+                                            (u8 *)&mstatus);
+                       break;
+               case LPS_CTRL_SPECIAL_PACKET:
+                       pwrpriv->DelayLPSLastTimeStamp = jiffies;
+#ifdef CONFIG_8723AU_BT_COEXIST
+                       BT_SpecialPacketNotify(padapter);
+                       if (BT_1Ant(padapter) == false)
+#endif
+                       {
+                               LPS_Leave23a(padapter);
+                       }
+                       break;
+               case LPS_CTRL_LEAVE:
+#ifdef CONFIG_8723AU_BT_COEXIST
+                       BT_LpsLeave(padapter);
+                       if (BT_1Ant(padapter) == false)
+#endif
+                       {
+                               LPS_Leave23a(padapter);
+                       }
+                       break;
+
+               default:
+                       break;
+       }
+}
+
+u8 rtw_lps_ctrl_wk_cmd23a(struct rtw_adapter *padapter,
+                         u8 lps_ctrl_type, u8 enqueue)
+{
+       struct cmd_obj *ph2c;
+       struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8 res = _SUCCESS;
+
+       if (enqueue) {
+               ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+               if (!ph2c) {
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
+                                            GFP_ATOMIC);
+               if (!pdrvextra_cmd_parm) {
+                       kfree(ph2c);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               pdrvextra_cmd_parm->ec_id = LPS_CTRL_WK_CID;
+               pdrvextra_cmd_parm->type_size = lps_ctrl_type;
+               pdrvextra_cmd_parm->pbuf = NULL;
+
+               init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm,
+                                          GEN_CMD_CODE(_Set_Drv_Extra));
+
+               res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+       } else
+               lps_ctrl_wk_hdl(padapter, lps_ctrl_type);
+exit:
+
+       return res;
+}
+
+static void power_saving_wk_hdl(struct rtw_adapter *padapter, u8 *pbuf, int sz)
+{
+        rtw_ps_processor23a(padapter);
+}
+
+#ifdef CONFIG_8723AU_P2P
+u8 p2p_protocol_wk_cmd23a(struct rtw_adapter*padapter, int intCmdType)
+{
+       struct cmd_obj *ph2c;
+       struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8 res = _SUCCESS;
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+       {
+               return res;
+       }
+
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!ph2c) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
+                                    GFP_ATOMIC);
+       if (!pdrvextra_cmd_parm) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = P2P_PROTO_WK_CID;
+       pdrvextra_cmd_parm->type_size = intCmdType; /* As the command tppe. */
+       pdrvextra_cmd_parm->pbuf = NULL;            /* Must be NULL here */
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm,
+                                  GEN_CMD_CODE(_Set_Drv_Extra));
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+exit:
+
+       return res;
+}
+#endif /* CONFIG_8723AU_P2P */
+
+u8 rtw_ps_cmd23a(struct rtw_adapter*padapter)
+{
+       struct cmd_obj *ppscmd;
+       struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       u8 res = _SUCCESS;
+
+       ppscmd = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!ppscmd) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
+                                    GFP_ATOMIC);
+       if (!pdrvextra_cmd_parm) {
+               kfree(ppscmd);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = POWER_SAVING_CTRL_WK_CID;
+       pdrvextra_cmd_parm->pbuf = NULL;
+       init_h2fwcmd_w_parm_no_rsp(ppscmd, pdrvextra_cmd_parm,
+                                  GEN_CMD_CODE(_Set_Drv_Extra));
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ppscmd);
+exit:
+
+       return res;
+}
+
+#ifdef CONFIG_8723AU_AP_MODE
+
+static void rtw_chk_hi_queue_hdl(struct rtw_adapter *padapter)
+{
+       int cnt = 0;
+       struct sta_info *psta_bmc;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+
+       psta_bmc = rtw_get_bcmc_stainfo23a(padapter);
+       if (!psta_bmc)
+               return;
+
+       if (psta_bmc->sleepq_len == 0) {
+               u8 val = 0;
+
+               rtw23a_hal_get_hwreg(padapter, HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+
+               while(val == false) {
+                       msleep(100);
+
+                       cnt++;
+
+                       if (cnt>10)
+                               break;
+
+                       rtw23a_hal_get_hwreg(padapter,
+                                            HW_VAR_CHK_HI_QUEUE_EMPTY, &val);
+               }
+
+               if (cnt <= 10) {
+                       pstapriv->tim_bitmap &= ~BIT(0);
+                       pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+                       update_beacon23a(padapter, _TIM_IE_, NULL, false);
+               } else /* re check again */
+                       rtw_chk_hi_queue_cmd23a(padapter);
+       }
+}
+
+u8 rtw_chk_hi_queue_cmd23a(struct rtw_adapter*padapter)
+{
+       struct cmd_obj *ph2c;
+       struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8 res = _SUCCESS;
+
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!ph2c) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
+                                    GFP_ATOMIC);
+       if (!pdrvextra_cmd_parm) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = CHECK_HIQ_WK_CID;
+       pdrvextra_cmd_parm->type_size = 0;
+       pdrvextra_cmd_parm->pbuf = NULL;
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm,
+                                  GEN_CMD_CODE(_Set_Drv_Extra));
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+exit:
+
+       return res;
+}
+#endif
+
+u8 rtw_c2h_wk_cmd23a(struct rtw_adapter *padapter, u8 *c2h_evt)
+{
+       struct cmd_obj *ph2c;
+       struct drvextra_cmd_parm *pdrvextra_cmd_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8 res = _SUCCESS;
+
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!ph2c) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm = kzalloc(sizeof(struct drvextra_cmd_parm),
+                                    GFP_ATOMIC);
+       if (!pdrvextra_cmd_parm) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       pdrvextra_cmd_parm->ec_id = C2H_WK_CID;
+       pdrvextra_cmd_parm->type_size = c2h_evt?16:0;
+       pdrvextra_cmd_parm->pbuf = c2h_evt;
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm,
+                                  GEN_CMD_CODE(_Set_Drv_Extra));
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+
+exit:
+
+       return res;
+}
+
+s32 c2h_evt_hdl(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt,
+               c2h_id_filter filter)
+{
+       s32 ret = _FAIL;
+       u8 buf[16];
+
+       if (!c2h_evt) {
+               /* No c2h event in cmd_obj, read c2h event before handling*/
+               if (c2h_evt_read23a(adapter, buf) == _SUCCESS) {
+                       c2h_evt = (struct c2h_evt_hdr *)buf;
+
+                       if (filter && filter(c2h_evt->id) == false)
+                               goto exit;
+
+                       ret = rtw_hal_c2h_handler23a(adapter, c2h_evt);
+               }
+       } else {
+
+               if (filter && filter(c2h_evt->id) == false)
+                       goto exit;
+
+               ret = rtw_hal_c2h_handler23a(adapter, c2h_evt);
+       }
+exit:
+       return ret;
+}
+
+static void c2h_wk_callback(struct work_struct *work)
+{
+       struct evt_priv *evtpriv;
+       struct rtw_adapter *adapter;
+       struct c2h_evt_hdr *c2h_evt;
+       c2h_id_filter ccx_id_filter;
+
+       evtpriv = container_of(work, struct evt_priv, c2h_wk);
+       adapter = container_of(evtpriv, struct rtw_adapter, evtpriv);
+       ccx_id_filter = rtw_hal_c2h_id_filter_ccx23a(adapter);
+
+       evtpriv->c2h_wk_alive = true;
+
+       while (!rtw_cbuf_empty23a(evtpriv->c2h_queue)) {
+               c2h_evt = (struct c2h_evt_hdr *)
+                       rtw_cbuf_pop23a(evtpriv->c2h_queue);
+               if (c2h_evt) {
+                       /* This C2H event is read, clear it */
+                       c2h_evt_clear23a(adapter);
+               } else if ((c2h_evt = (struct c2h_evt_hdr *)
+                           kmalloc(16, GFP_ATOMIC))) {
+                       /* This C2H event is not read, read & clear now */
+                       if (c2h_evt_read23a(adapter, (u8*)c2h_evt) != _SUCCESS)
+                               continue;
+               }
+
+               /* Special pointer to trigger c2h_evt_clear23a only */
+               if ((void *)c2h_evt == (void *)evtpriv)
+                       continue;
+
+               if (!c2h_evt_exist(c2h_evt)) {
+                       kfree(c2h_evt);
+                       continue;
+               }
+
+               if (ccx_id_filter(c2h_evt->id) == true) {
+                       /* Handle CCX report here */
+                       rtw_hal_c2h_handler23a(adapter, c2h_evt);
+                       kfree(c2h_evt);
+               } else {
+                       /* Enqueue into cmd_thread for others */
+                       rtw_c2h_wk_cmd23a(adapter, (u8 *)c2h_evt);
+               }
+       }
+
+       evtpriv->c2h_wk_alive = false;
+}
+
+u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       struct drvextra_cmd_parm *pdrvextra_cmd;
+
+       if (!pbuf)
+               return H2C_PARAMETERS_ERROR;
+
+       pdrvextra_cmd = (struct drvextra_cmd_parm *)pbuf;
+
+       switch (pdrvextra_cmd->ec_id)
+       {
+       case DYNAMIC_CHK_WK_CID:
+               dynamic_chk_wk_hdl(padapter, pdrvextra_cmd->pbuf,
+                                  pdrvextra_cmd->type_size);
+               break;
+       case POWER_SAVING_CTRL_WK_CID:
+               power_saving_wk_hdl(padapter, pdrvextra_cmd->pbuf,
+                                   pdrvextra_cmd->type_size);
+               break;
+       case LPS_CTRL_WK_CID:
+               lps_ctrl_wk_hdl(padapter, (u8)pdrvextra_cmd->type_size);
+               break;
+#ifdef CONFIG_8723AU_P2P
+       case P2P_PS_WK_CID:
+               p2p_ps_wk_hdl23a(padapter, pdrvextra_cmd->type_size);
+               break;
+       case P2P_PROTO_WK_CID:
+               /*      Commented by Albert 2011/07/01 */
+               /*      I used the type_size as the type command */
+               p2p_protocol_wk_hdl23a(padapter, pdrvextra_cmd->type_size);
+               break;
+#endif /*  CONFIG_8723AU_P2P */
+#ifdef CONFIG_8723AU_AP_MODE
+       case CHECK_HIQ_WK_CID:
+               rtw_chk_hi_queue_hdl(padapter);
+               break;
+#endif /* CONFIG_8723AU_AP_MODE */
+       case C2H_WK_CID:
+               c2h_evt_hdl(padapter,
+                           (struct c2h_evt_hdr *)pdrvextra_cmd->pbuf, NULL);
+               break;
+
+       default:
+               break;
+       }
+
+       if (pdrvextra_cmd->pbuf && (pdrvextra_cmd->type_size > 0)) {
+               kfree(pdrvextra_cmd->pbuf);
+               pdrvextra_cmd->pbuf = NULL;
+       }
+
+       return H2C_SUCCESS;
+}
+
+void rtw_survey_cmd_callback23a(struct rtw_adapter *padapter,
+                            struct cmd_obj *pcmd)
+{
+       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       if (pcmd->res == H2C_DROPPED) {
+               /* TODO: cancel timer and do timeout handler directly... */
+               /* need to make timeout handlerOS independent */
+               mod_timer(&pmlmepriv->scan_to_timer,
+                         jiffies + msecs_to_jiffies(1));
+       } else if (pcmd->res != H2C_SUCCESS) {
+               mod_timer(&pmlmepriv->scan_to_timer,
+                         jiffies + msecs_to_jiffies(1));
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                        ("\n ********Error: MgntActrtw_set_802_11_bssid23a_"
+                         "LIST_SCAN Fail ************\n\n."));
+       }
+
+       /*  free cmd */
+       rtw_free_cmd_obj23a(pcmd);
+}
+
+void rtw_disassoc_cmd23a_callback(struct rtw_adapter *padapter,
+                                 struct cmd_obj *pcmd)
+{
+       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       if (pcmd->res != H2C_SUCCESS) {
+               spin_lock_bh(&pmlmepriv->lock);
+               set_fwstate(pmlmepriv, _FW_LINKED);
+               spin_unlock_bh(&pmlmepriv->lock);
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                        ("\n ***Error: disconnect_cmd_callback Fail ***\n."));
+               return;
+       }
+
+       /*  free cmd */
+       rtw_free_cmd_obj23a(pcmd);
+}
+
+void rtw_joinbss_cmd23a_callback(struct rtw_adapter *padapter,
+                                struct cmd_obj *pcmd)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       if (pcmd->res == H2C_DROPPED) {
+               /* TODO: cancel timer and do timeout handler directly... */
+               /* need to make timeout handlerOS independent */
+               mod_timer(&pmlmepriv->assoc_timer,
+                         jiffies + msecs_to_jiffies(1));
+       } else if (pcmd->res != H2C_SUCCESS) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                        ("********Error:rtw_select_and_join_from_scanned_"
+                         "queue Wait Sema  Fail ************\n"));
+               mod_timer(&pmlmepriv->assoc_timer,
+                         jiffies + msecs_to_jiffies(1));
+       }
+
+       rtw_free_cmd_obj23a(pcmd);
+}
+
+void rtw_createbss_cmd23a_callback(struct rtw_adapter *padapter,
+                                  struct cmd_obj *pcmd)
+{
+       struct sta_info *psta;
+       struct wlan_network *pwlan;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_bssid_ex *pnetwork = (struct wlan_bssid_ex *)pcmd->parmbuf;
+       struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+
+       if (pcmd->res != H2C_SUCCESS) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                        ("\n ********Error: rtw_createbss_cmd23a_callback  "
+                         "Fail ************\n\n."));
+               mod_timer(&pmlmepriv->assoc_timer,
+                         jiffies + msecs_to_jiffies(1));
+       }
+
+       del_timer_sync(&pmlmepriv->assoc_timer);
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+               psta = rtw_get_stainfo23a(&padapter->stapriv,
+                                         pnetwork->MacAddress);
+               if (!psta) {
+                       psta = rtw_alloc_stainfo23a(&padapter->stapriv,
+                                                pnetwork->MacAddress);
+                       if (!psta) {
+                               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                                        ("\nCan't alloc sta_info when "
+                                         "createbss_cmd_callback\n"));
+                               goto createbss_cmd_fail ;
+                       }
+               }
+
+               rtw_indicate_connect23a(padapter);
+       } else {
+               pwlan = rtw_alloc_network(pmlmepriv);
+               spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+               if (!pwlan) {
+                       pwlan = rtw_get_oldest_wlan_network23a(&pmlmepriv->scanned_queue);
+                       if (!pwlan) {
+                               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                                        ("\n Error:  can't get pwlan in "
+                                         "rtw23a_joinbss_event_cb\n"));
+                               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+                               goto createbss_cmd_fail;
+                       }
+                       pwlan->last_scanned = jiffies;
+               } else {
+                       list_add_tail(&pwlan->list,
+                                     &pmlmepriv->scanned_queue.queue);
+               }
+
+               pnetwork->Length = get_wlan_bssid_ex_sz(pnetwork);
+               memcpy(&pwlan->network, pnetwork, pnetwork->Length);
+               /* pwlan->fixed = true; */
+
+               /* list_add_tail(&pwlan->list,
+                  &pmlmepriv->scanned_queue.queue); */
+
+               /*  copy pdev_network information to
+                   pmlmepriv->cur_network */
+               memcpy(&tgt_network->network, pnetwork,
+                      get_wlan_bssid_ex_sz(pnetwork));
+
+               /*  reset DSConfig */
+
+               _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+               /*  we will set _FW_LINKED when there is one more sat to
+                   join us (rtw_stassoc_event_callback23a) */
+       }
+
+createbss_cmd_fail:
+
+       spin_unlock_bh(&pmlmepriv->lock);
+
+       rtw_free_cmd_obj23a(pcmd);
+}
+
+void rtw_setstaKey_cmdrsp_callback23a(struct rtw_adapter *padapter,
+                                     struct cmd_obj *pcmd)
+{
+       struct sta_priv *pstapriv;
+       struct set_stakey_rsp *psetstakey_rsp;
+       struct sta_info *psta;
+
+       pstapriv = &padapter->stapriv;
+       psetstakey_rsp = (struct set_stakey_rsp*) (pcmd->rsp);
+       psta = rtw_get_stainfo23a(pstapriv, psetstakey_rsp->addr);
+
+       if (!psta) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                        ("\nERROR: rtw_setstaKey_cmdrsp_callback23a => "
+                         "can't get sta_info\n\n"));
+               goto exit;
+       }
+
+exit:
+
+       rtw_free_cmd_obj23a(pcmd);
+}
+
+void rtw_setassocsta_cmdrsp_callback23a(struct rtw_adapter *padapter,
+                                       struct cmd_obj *pcmd)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct set_assocsta_parm* passocsta_parm;
+       struct set_assocsta_rsp* passocsta_rsp;
+       struct sta_info *psta;
+
+       passocsta_parm = (struct set_assocsta_parm *)(pcmd->parmbuf);
+       passocsta_rsp = (struct set_assocsta_rsp*) (pcmd->rsp);
+       psta = rtw_get_stainfo23a(pstapriv, passocsta_parm->addr);
+
+       if (psta == NULL) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_,
+                        ("\nERROR: setassocsta_cmdrsp_callbac => can't "
+                         "get sta_info\n\n"));
+               goto exit;
+       }
+
+       psta->aid = psta->mac_id = passocsta_rsp->cam_id;
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) &&
+           (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true))
+               _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+       set_fwstate(pmlmepriv, _FW_LINKED);
+       spin_unlock_bh(&pmlmepriv->lock);
+
+exit:
+       rtw_free_cmd_obj23a(pcmd);
+}
+
+void rtw_getrttbl_cmd_cmdrsp_callback(struct rtw_adapter *padapter,
+                                     struct cmd_obj *pcmd)
+{
+       rtw_free_cmd_obj23a(pcmd);
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_efuse.c b/drivers/staging/rtl8723au/core/rtw_efuse.c
new file mode 100644 (file)
index 0000000..35b177f
--- /dev/null
@@ -0,0 +1,716 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_EFUSE_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <rtw_efuse.h>
+
+/*------------------------Define local variable------------------------------*/
+
+/*  */
+#define REG_EFUSE_CTRL         0x0030
+#define EFUSE_CTRL                     REG_EFUSE_CTRL          /*  E-Fuse Control. */
+/*  */
+
+/*-----------------------------------------------------------------------------
+ * Function:   Efuse_PowerSwitch23a
+ *
+ * Overview:   When we want to enable write operation, we should change to
+ *                             pwr on state. When we stop write, we should switch to 500k mode
+ *                             and disable LDO 2.5V.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 11/17/2008  MHC             Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void
+Efuse_PowerSwitch23a(
+       struct rtw_adapter *    pAdapter,
+       u8              bWrite,
+       u8              PwrState)
+{
+       pAdapter->HalFunc.EfusePowerSwitch(pAdapter, bWrite, PwrState);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:   efuse_GetCurrentSize23a
+ *
+ * Overview:   Get current efuse size!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 11/16/2008  MHC             Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+u16
+Efuse_GetCurrentSize23a(struct rtw_adapter *pAdapter, u8 efuseType)
+{
+       u16 ret = 0;
+
+       ret = pAdapter->HalFunc.EfuseGetCurrentSize(pAdapter, efuseType);
+
+       return ret;
+}
+
+/*  11/16/2008 MH Add description. Get current efuse area enabled word!!. */
+u8
+Efuse_CalculateWordCnts23a(u8 word_en)
+{
+       u8 word_cnts = 0;
+       if (!(word_en & BIT(0)))        word_cnts++; /*  0 : write enable */
+       if (!(word_en & BIT(1)))        word_cnts++;
+       if (!(word_en & BIT(2)))        word_cnts++;
+       if (!(word_en & BIT(3)))        word_cnts++;
+       return word_cnts;
+}
+
+/*  */
+/*     Description: */
+/*             Execute E-Fuse read byte operation. */
+/*             Refered from SD1 Richard. */
+/*  */
+/*     Assumption: */
+/*             1. Boot from E-Fuse and successfully auto-load. */
+/*             2. PASSIVE_LEVEL (USB interface) */
+/*  */
+/*     Created by Roger, 2008.10.21. */
+/*  */
+void
+ReadEFuseByte23a(struct rtw_adapter *Adapter, u16 _offset, u8 *pbuf)
+{
+       u32     value32;
+       u8      readbyte;
+       u16     retry;
+
+       /* Write Address */
+       rtw_write8(Adapter, EFUSE_CTRL+1, (_offset & 0xff));
+       readbyte = rtw_read8(Adapter, EFUSE_CTRL+2);
+       rtw_write8(Adapter, EFUSE_CTRL+2, ((_offset >> 8) & 0x03) | (readbyte & 0xfc));
+
+       /* Write bit 32 0 */
+       readbyte = rtw_read8(Adapter, EFUSE_CTRL+3);
+       rtw_write8(Adapter, EFUSE_CTRL+3, (readbyte & 0x7f));
+
+       /* Check bit 32 read-ready */
+       retry = 0;
+       value32 = rtw_read32(Adapter, EFUSE_CTRL);
+       /* while(!(((value32 >> 24) & 0xff) & 0x80)  && (retry<10)) */
+       while(!(((value32 >> 24) & 0xff) & 0x80)  && (retry<10000))
+       {
+               value32 = rtw_read32(Adapter, EFUSE_CTRL);
+               retry++;
+       }
+
+       /*  20100205 Joseph: Add delay suggested by SD1 Victor. */
+       /*  This fix the problem that Efuse read error in high temperature condition. */
+       /*  Designer says that there shall be some delay after ready bit is set, or the */
+       /*  result will always stay on last data we read. */
+       udelay(50);
+       value32 = rtw_read32(Adapter, EFUSE_CTRL);
+
+       *pbuf = (u8)(value32 & 0xff);
+}
+
+/*  */
+/*     Description: */
+/*             1. Execute E-Fuse read byte operation according as map offset and */
+/*                 save to E-Fuse table. */
+/*             2. Refered from SD1 Richard. */
+/*  */
+/*     Assumption: */
+/*             1. Boot from E-Fuse and successfully auto-load. */
+/*             2. PASSIVE_LEVEL (USB interface) */
+/*  */
+/*     Created by Roger, 2008.10.21. */
+/*  */
+/*     2008/12/12 MH   1. Reorganize code flow and reserve bytes. and add description. */
+/*                                     2. Add efuse utilization collect. */
+/*     2008/12/22 MH   Read Efuse must check if we write section 1 data again!!! Sec1 */
+/*                                     write addr must be after sec5. */
+/*  */
+
+void
+efuse_ReadEFuse(struct rtw_adapter *Adapter, u8 efuseType,
+               u16 _offset, u16 _size_byte, u8 *pbuf);
+void
+efuse_ReadEFuse(struct rtw_adapter *Adapter, u8 efuseType,
+               u16 _offset, u16 _size_byte, u8 *pbuf)
+{
+       Adapter->HalFunc.ReadEFuse(Adapter, efuseType, _offset,
+                                  _size_byte, pbuf);
+}
+
+void
+EFUSE_GetEfuseDefinition23a(struct rtw_adapter *pAdapter, u8 efuseType,
+                        u8 type, void *pOut)
+{
+       pAdapter->HalFunc.EFUSEGetEfuseDefinition(pAdapter, efuseType,
+                                                 type, pOut);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:   EFUSE_Read1Byte23a
+ *
+ * Overview:   Copy from WMAC fot EFUSE read 1 byte.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 09/23/2008  MHC             Copy from WMAC.
+ *
+ *---------------------------------------------------------------------------*/
+u8
+EFUSE_Read1Byte23a(struct rtw_adapter *Adapter, u16 Address)
+{
+       u8      data;
+       u8      Bytetemp = {0x00};
+       u8      temp = {0x00};
+       u32     k = 0;
+       u16     contentLen = 0;
+
+       EFUSE_GetEfuseDefinition23a(Adapter, EFUSE_WIFI,
+                                TYPE_EFUSE_REAL_CONTENT_LEN,
+                                (void *)&contentLen);
+
+       if (Address < contentLen)       /* E-fuse 512Byte */
+       {
+               /* Write E-fuse Register address bit0~7 */
+               temp = Address & 0xFF;
+               rtw_write8(Adapter, EFUSE_CTRL+1, temp);
+               Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2);
+               /* Write E-fuse Register address bit8~9 */
+               temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);
+               rtw_write8(Adapter, EFUSE_CTRL+2, temp);
+
+               /* Write 0x30[31]= 0 */
+               Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+               temp = Bytetemp & 0x7F;
+               rtw_write8(Adapter, EFUSE_CTRL+3, temp);
+
+               /* Wait Write-ready (0x30[31]= 1) */
+               Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+               while(!(Bytetemp & 0x80))
+               {
+                       Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+                       k++;
+                       if (k == 1000)
+                       {
+                               k = 0;
+                               break;
+                       }
+               }
+               data = rtw_read8(Adapter, EFUSE_CTRL);
+               return data;
+       }
+       else
+               return 0xFF;
+}/* EFUSE_Read1Byte23a */
+
+/*-----------------------------------------------------------------------------
+ * Function:   EFUSE_Write1Byte
+ *
+ * Overview:   Copy from WMAC fot EFUSE write 1 byte.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 09/23/2008  MHC             Copy from WMAC.
+ *
+ *---------------------------------------------------------------------------*/
+
+void
+EFUSE_Write1Byte(
+       struct rtw_adapter *    Adapter,
+       u16             Address,
+       u8              Value);
+void
+EFUSE_Write1Byte(
+       struct rtw_adapter *    Adapter,
+       u16             Address,
+       u8              Value)
+{
+       u8      Bytetemp = {0x00};
+       u8      temp = {0x00};
+       u32     k = 0;
+       u16     contentLen = 0;
+
+       /* RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr =%x Data =%x\n", Address, Value)); */
+       EFUSE_GetEfuseDefinition23a(Adapter, EFUSE_WIFI,
+                                TYPE_EFUSE_REAL_CONTENT_LEN,
+                                (void *)&contentLen);
+
+       if (Address < contentLen)       /* E-fuse 512Byte */
+       {
+               rtw_write8(Adapter, EFUSE_CTRL, Value);
+
+               /* Write E-fuse Register address bit0~7 */
+               temp = Address & 0xFF;
+               rtw_write8(Adapter, EFUSE_CTRL+1, temp);
+               Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+2);
+
+               /* Write E-fuse Register address bit8~9 */
+               temp = ((Address >> 8) & 0x03) | (Bytetemp & 0xFC);
+               rtw_write8(Adapter, EFUSE_CTRL+2, temp);
+
+               /* Write 0x30[31]= 1 */
+               Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+               temp = Bytetemp | 0x80;
+               rtw_write8(Adapter, EFUSE_CTRL+3, temp);
+
+               /* Wait Write-ready (0x30[31]= 0) */
+               Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+               while(Bytetemp & 0x80)
+               {
+                       Bytetemp = rtw_read8(Adapter, EFUSE_CTRL+3);
+                       k++;
+                       if (k == 100)
+                       {
+                               k = 0;
+                               break;
+                       }
+               }
+       }
+}/* EFUSE_Write1Byte */
+
+/*  11/16/2008 MH Read one byte from real Efuse. */
+u8
+efuse_OneByteRead23a(struct rtw_adapter *pAdapter, u16 addr, u8 *data)
+{
+       u8      tmpidx = 0;
+       u8      bResult;
+
+       /*  -----------------e-fuse reg ctrl --------------------------------- */
+       /* address */
+       rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff));
+       rtw_write8(pAdapter, EFUSE_CTRL+2, ((u8)((addr>>8) &0x03)) |
+       (rtw_read8(pAdapter, EFUSE_CTRL+2)&0xFC));
+
+       rtw_write8(pAdapter, EFUSE_CTRL+3,  0x72);/* read cmd */
+
+       while(!(0x80 &rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx<100))
+               tmpidx++;
+       if (tmpidx < 100) {
+               *data = rtw_read8(pAdapter, EFUSE_CTRL);
+               bResult = true;
+       } else {
+               *data = 0xff;
+               bResult = false;
+       }
+       return bResult;
+}
+
+/*  11/16/2008 MH Write one byte to reald Efuse. */
+u8
+efuse_OneByteWrite23a(struct rtw_adapter *pAdapter, u16 addr, u8 data)
+{
+       u8      tmpidx = 0;
+       u8      bResult;
+
+       /* RT_TRACE(COMP_EFUSE, DBG_LOUD, ("Addr = %x Data =%x\n", addr, data)); */
+
+       /* return       0; */
+
+       /*  -----------------e-fuse reg ctrl --------------------------------- */
+       /* address */
+       rtw_write8(pAdapter, EFUSE_CTRL+1, (u8)(addr&0xff));
+       rtw_write8(pAdapter, EFUSE_CTRL+2,
+       (rtw_read8(pAdapter, EFUSE_CTRL+2)&0xFC)|(u8)((addr>>8)&0x03));
+       rtw_write8(pAdapter, EFUSE_CTRL, data);/* data */
+
+       rtw_write8(pAdapter, EFUSE_CTRL+3, 0xF2);/* write cmd */
+
+       while((0x80 &  rtw_read8(pAdapter, EFUSE_CTRL+3)) && (tmpidx<100)) {
+               tmpidx++;
+       }
+
+       if (tmpidx<100)
+       {
+               bResult = true;
+       }
+       else
+       {
+               bResult = false;
+       }
+
+       return bResult;
+}
+
+int
+Efuse_PgPacketRead23a(struct rtw_adapter *pAdapter, u8 offset, u8 *data)
+{
+       int     ret = 0;
+
+       ret =  pAdapter->HalFunc.Efuse_PgPacketRead23a(pAdapter, offset, data);
+
+       return ret;
+}
+
+int
+Efuse_PgPacketWrite23a(struct rtw_adapter *pAdapter, u8 offset,
+                   u8 word_en, u8 *data)
+{
+       int ret;
+
+       ret =  pAdapter->HalFunc.Efuse_PgPacketWrite23a(pAdapter, offset,
+                                                    word_en, data);
+
+       return ret;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:   efuse_WordEnableDataRead23a
+ *
+ * Overview:   Read allowed word in current efuse section data.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 11/16/2008  MHC             Create Version 0.
+ * 11/21/2008  MHC             Fix Write bug when we only enable late word.
+ *
+ *---------------------------------------------------------------------------*/
+void
+efuse_WordEnableDataRead23a(u8 word_en,
+                        u8     *sourdata,
+                        u8     *targetdata)
+{
+       if (!(word_en&BIT(0)))
+       {
+               targetdata[0] = sourdata[0];
+               targetdata[1] = sourdata[1];
+       }
+       if (!(word_en&BIT(1)))
+       {
+               targetdata[2] = sourdata[2];
+               targetdata[3] = sourdata[3];
+       }
+       if (!(word_en&BIT(2)))
+       {
+               targetdata[4] = sourdata[4];
+               targetdata[5] = sourdata[5];
+       }
+       if (!(word_en&BIT(3)))
+       {
+               targetdata[6] = sourdata[6];
+               targetdata[7] = sourdata[7];
+       }
+}
+
+u8
+Efuse_WordEnableDataWrite23a(struct rtw_adapter *pAdapter, u16 efuse_addr,
+                         u8 word_en, u8 *data)
+{
+       u8 ret = 0;
+
+       ret = pAdapter->HalFunc.Efuse_WordEnableDataWrite23a(pAdapter, efuse_addr,
+                                                         word_en, data);
+
+       return ret;
+}
+
+static u8 efuse_read8(struct rtw_adapter *padapter, u16 address, u8 *value)
+{
+       return efuse_OneByteRead23a(padapter, address, value);
+}
+
+static u8 efuse_write8(struct rtw_adapter *padapter, u16 address, u8 *value)
+{
+       return efuse_OneByteWrite23a(padapter, address, *value);
+}
+
+/*
+ * read/wirte raw efuse data
+ */
+u8 rtw_efuse_access23a(struct rtw_adapter *padapter, u8 bWrite, u16 start_addr,
+                   u16 cnts, u8 *data)
+{
+       int i = 0;
+       u16     real_content_len = 0, max_available_size = 0;
+       u8 res = _FAIL ;
+       u8 (*rw8)(struct rtw_adapter *, u16, u8*);
+
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI,
+                                TYPE_EFUSE_REAL_CONTENT_LEN,
+                                (void *)&real_content_len);
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI,
+                                TYPE_AVAILABLE_EFUSE_BYTES_TOTAL,
+                                (void *)&max_available_size);
+
+       if (start_addr > real_content_len)
+               return _FAIL;
+
+       if (true == bWrite) {
+               if ((start_addr + cnts) > max_available_size)
+                       return _FAIL;
+               rw8 = &efuse_write8;
+       } else
+               rw8 = &efuse_read8;
+
+       Efuse_PowerSwitch23a(padapter, bWrite, true);
+
+       /*  e-fuse one byte read / write */
+       for (i = 0; i < cnts; i++) {
+               if (start_addr >= real_content_len) {
+                       res = _FAIL;
+                       break;
+               }
+
+               res = rw8(padapter, start_addr++, data++);
+               if (_FAIL == res) break;
+       }
+
+       Efuse_PowerSwitch23a(padapter, bWrite, false);
+
+       return res;
+}
+/*  */
+u16 efuse_GetMaxSize23a(struct rtw_adapter *padapter)
+{
+       u16     max_size;
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI,
+                                TYPE_AVAILABLE_EFUSE_BYTES_TOTAL,
+                                (void *)&max_size);
+       return max_size;
+}
+/*  */
+u8 efuse_GetCurrentSize23a(struct rtw_adapter *padapter, u16 *size)
+{
+       Efuse_PowerSwitch23a(padapter, false, true);
+       *size = Efuse_GetCurrentSize23a(padapter, EFUSE_WIFI);
+       Efuse_PowerSwitch23a(padapter, false, false);
+
+       return _SUCCESS;
+}
+/*  */
+u8 rtw_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+       u16     mapLen = 0;
+
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI,
+                                TYPE_EFUSE_MAP_LEN, (void *)&mapLen);
+
+       if ((addr + cnts) > mapLen)
+               return _FAIL;
+
+       Efuse_PowerSwitch23a(padapter, false, true);
+
+       efuse_ReadEFuse(padapter, EFUSE_WIFI, addr, cnts, data);
+
+       Efuse_PowerSwitch23a(padapter, false, false);
+
+       return _SUCCESS;
+}
+
+u8 rtw_BT_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data)
+{
+       u16     mapLen = 0;
+
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT,
+                                TYPE_EFUSE_MAP_LEN, (void *)&mapLen);
+
+       if ((addr + cnts) > mapLen)
+               return _FAIL;
+
+       Efuse_PowerSwitch23a(padapter, false, true);
+
+       efuse_ReadEFuse(padapter, EFUSE_BT, addr, cnts, data);
+
+       Efuse_PowerSwitch23a(padapter, false, false);
+
+       return _SUCCESS;
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:   Efuse_ReadAllMap
+ *
+ * Overview:   Read All Efuse content
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 11/11/2008  MHC             Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void
+Efuse_ReadAllMap(struct rtw_adapter *pAdapter, u8 efuseType, u8 *Efuse);
+void
+Efuse_ReadAllMap(struct rtw_adapter *pAdapter, u8 efuseType, u8 *Efuse)
+{
+       u16     mapLen = 0;
+
+       Efuse_PowerSwitch23a(pAdapter, false, true);
+
+       EFUSE_GetEfuseDefinition23a(pAdapter, efuseType, TYPE_EFUSE_MAP_LEN,
+                                (void *)&mapLen);
+
+       efuse_ReadEFuse(pAdapter, efuseType, 0, mapLen, Efuse);
+
+       Efuse_PowerSwitch23a(pAdapter, false, false);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:   efuse_ShadowRead1Byte
+ *                     efuse_ShadowRead2Byte
+ *                     efuse_ShadowRead4Byte
+ *
+ * Overview:   Read from efuse init map by one/two/four bytes !!!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 11/12/2008  MHC             Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+static void
+efuse_ShadowRead1Byte(
+       struct rtw_adapter *    pAdapter,
+       u16             Offset,
+       u8              *Value)
+{
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+
+       *Value = pEEPROM->efuse_eeprom_data[Offset];
+}      /*  EFUSE_ShadowRead23a1Byte */
+
+/* Read Two Bytes */
+static void
+efuse_ShadowRead2Byte(
+       struct rtw_adapter *    pAdapter,
+       u16             Offset,
+       u16             *Value)
+{
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+
+       *Value = pEEPROM->efuse_eeprom_data[Offset];
+       *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8;
+}      /*  EFUSE_ShadowRead23a2Byte */
+
+/* Read Four Bytes */
+static void
+efuse_ShadowRead4Byte(
+       struct rtw_adapter *    pAdapter,
+       u16             Offset,
+       u32             *Value)
+{
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+
+       *Value = pEEPROM->efuse_eeprom_data[Offset];
+       *Value |= pEEPROM->efuse_eeprom_data[Offset+1]<<8;
+       *Value |= pEEPROM->efuse_eeprom_data[Offset+2]<<16;
+       *Value |= pEEPROM->efuse_eeprom_data[Offset+3]<<24;
+}      /*  efuse_ShadowRead4Byte */
+
+/*-----------------------------------------------------------------------------
+ * Function:   EFUSE_ShadowMapUpdate23a
+ *
+ * Overview:   Transfer current EFUSE content to shadow init and modify map.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 11/13/2008  MHC             Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void EFUSE_ShadowMapUpdate23a(struct rtw_adapter *pAdapter, u8 efuseType)
+{
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
+       u16     mapLen = 0;
+
+       EFUSE_GetEfuseDefinition23a(pAdapter, efuseType,
+                                TYPE_EFUSE_MAP_LEN, (void *)&mapLen);
+
+       if (pEEPROM->bautoload_fail_flag == true)
+               memset(pEEPROM->efuse_eeprom_data, 0xFF, mapLen);
+       else
+               Efuse_ReadAllMap(pAdapter, efuseType,
+                                pEEPROM->efuse_eeprom_data);
+
+}/*  EFUSE_ShadowMapUpdate23a */
+
+/*-----------------------------------------------------------------------------
+ * Function:   EFUSE_ShadowRead23a
+ *
+ * Overview:   Read from efuse init map !!!!!
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 11/12/2008  MHC             Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void
+EFUSE_ShadowRead23a(
+       struct rtw_adapter *    pAdapter,
+       u8              Type,
+       u16             Offset,
+       u32             *Value  )
+{
+       if (Type == 1)
+               efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value);
+       else if (Type == 2)
+               efuse_ShadowRead2Byte(pAdapter, Offset, (u16 *)Value);
+       else if (Type == 4)
+               efuse_ShadowRead4Byte(pAdapter, Offset, (u32 *)Value);
+}      /*  EFUSE_ShadowRead23a */
diff --git a/drivers/staging/rtl8723au/core/rtw_ieee80211.c b/drivers/staging/rtl8723au/core/rtw_ieee80211.c
new file mode 100644 (file)
index 0000000..780631f
--- /dev/null
@@ -0,0 +1,1861 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _IEEE80211_C
+
+#include <drv_types.h>
+#include <linux/ieee80211.h>
+#include <ieee80211.h>
+#include <wifi.h>
+#include <osdep_service.h>
+#include <wlan_bssdef.h>
+
+u8 RTW_WPA_OUI23A_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
+u16 RTW_WPA_VERSION23A = 1;
+u8 WPA_AUTH_KEY_MGMT_NONE23A[] = { 0x00, 0x50, 0xf2, 0 };
+u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X23A[] = { 0x00, 0x50, 0xf2, 1 };
+u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X23A[] = { 0x00, 0x50, 0xf2, 2 };
+u8 WPA_CIPHER_SUITE_NONE23A[] = { 0x00, 0x50, 0xf2, 0 };
+u8 WPA_CIPHER_SUITE_WEP4023A[] = { 0x00, 0x50, 0xf2, 1 };
+u8 WPA_CIPHER_SUITE_TKIP23A[] = { 0x00, 0x50, 0xf2, 2 };
+u8 WPA_CIPHER_SUITE_WRAP23A[] = { 0x00, 0x50, 0xf2, 3 };
+u8 WPA_CIPHER_SUITE_CCMP23A[] = { 0x00, 0x50, 0xf2, 4 };
+u8 WPA_CIPHER_SUITE_WEP10423A[] = { 0x00, 0x50, 0xf2, 5 };
+
+u16 RSN_VERSION_BSD23A = 1;
+u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X23A[] = { 0x00, 0x0f, 0xac, 1 };
+u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X23A[] = { 0x00, 0x0f, 0xac, 2 };
+u8 RSN_CIPHER_SUITE_NONE23A[] = { 0x00, 0x0f, 0xac, 0 };
+u8 RSN_CIPHER_SUITE_WEP4023A[] = { 0x00, 0x0f, 0xac, 1 };
+u8 RSN_CIPHER_SUITE_TKIP23A[] = { 0x00, 0x0f, 0xac, 2 };
+u8 RSN_CIPHER_SUITE_WRAP23A[] = { 0x00, 0x0f, 0xac, 3 };
+u8 RSN_CIPHER_SUITE_CCMP23A[] = { 0x00, 0x0f, 0xac, 4 };
+u8 RSN_CIPHER_SUITE_WEP10423A[] = { 0x00, 0x0f, 0xac, 5 };
+/*  */
+/*  for adhoc-master to generate ie and provide supported-rate to fw */
+/*  */
+
+static u8      WIFI_CCKRATES[] =
+{(IEEE80211_CCK_RATE_1MB | IEEE80211_BASIC_RATE_MASK),
+ (IEEE80211_CCK_RATE_2MB | IEEE80211_BASIC_RATE_MASK),
+ (IEEE80211_CCK_RATE_5MB | IEEE80211_BASIC_RATE_MASK),
+ (IEEE80211_CCK_RATE_11MB | IEEE80211_BASIC_RATE_MASK)};
+
+static u8      WIFI_OFDMRATES[] =
+{(IEEE80211_OFDM_RATE_6MB),
+ (IEEE80211_OFDM_RATE_9MB),
+ (IEEE80211_OFDM_RATE_12MB),
+ (IEEE80211_OFDM_RATE_18MB),
+ (IEEE80211_OFDM_RATE_24MB),
+ IEEE80211_OFDM_RATE_36MB,
+ IEEE80211_OFDM_RATE_48MB,
+ IEEE80211_OFDM_RATE_54MB};
+
+int rtw_get_bit_value_from_ieee_value23a(u8 val)
+{
+       unsigned char dot11_rate_table[]=
+               {2, 4, 11, 22, 12, 18, 24, 36, 48, 72, 96, 108, 0};
+
+       int i = 0;
+       while (dot11_rate_table[i] != 0) {
+               if (dot11_rate_table[i] == val)
+                       return BIT(i);
+               i++;
+       }
+       return 0;
+}
+
+uint rtw_is_cckrates_included23a(u8 *rate)
+{
+       u32 i = 0;
+
+       while (rate[i] != 0) {
+               if ((((rate[i]) & 0x7f) == 2) || (((rate[i]) & 0x7f) == 4) ||
+                   (((rate[i]) & 0x7f) == 11) || (((rate[i]) & 0x7f) == 22))
+                       return true;
+               i++;
+       }
+
+       return false;
+}
+
+uint rtw_is_cckratesonly_included23a(u8 *rate)
+{
+       u32 i = 0;
+
+       while (rate[i] != 0) {
+               if ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
+                   (((rate[i]) & 0x7f) != 11) && (((rate[i]) & 0x7f) != 22))
+                       return false;
+
+               i++;
+       }
+
+       return true;
+}
+
+int rtw_check_network_type23a(unsigned char *rate, int ratelen, int channel)
+{
+       if (channel > 14) {
+               if ((rtw_is_cckrates_included23a(rate)) == true)
+                       return WIRELESS_INVALID;
+               else
+                       return WIRELESS_11A;
+       } else {  /*  could be pure B, pure G, or B/G */
+               if ((rtw_is_cckratesonly_included23a(rate)) == true)
+                       return WIRELESS_11B;
+               else if ((rtw_is_cckrates_included23a(rate)) == true)
+                       return  WIRELESS_11BG;
+               else
+                       return WIRELESS_11G;
+       }
+}
+
+u8 *rtw_set_fixed_ie23a(unsigned char *pbuf, unsigned int len,
+                    unsigned char *source, unsigned int *frlen)
+{
+       memcpy((void *)pbuf, (void *)source, len);
+       *frlen = *frlen + len;
+       return pbuf + len;
+}
+
+/*  rtw_set_ie23a will update frame length */
+u8 *rtw_set_ie23a(u8 *pbuf, int index, uint len, u8 *source, uint *frlen)
+{
+
+       *pbuf = (u8)index;
+
+       *(pbuf + 1) = (u8)len;
+
+       if (len > 0)
+               memcpy((void *)(pbuf + 2), (void *)source, len);
+
+       *frlen = *frlen + (len + 2);
+
+
+       return pbuf + len + 2;
+}
+
+inline u8 *rtw_set_ie23a_ch_switch (u8 *buf, u32 *buf_len, u8 ch_switch_mode,
+                               u8 new_ch, u8 ch_switch_cnt)
+{
+       u8 ie_data[3];
+
+       ie_data[0] = ch_switch_mode;
+       ie_data[1] = new_ch;
+       ie_data[2] = ch_switch_cnt;
+       return rtw_set_ie23a(buf, WLAN_EID_CHANNEL_SWITCH,  3, ie_data, buf_len);
+}
+
+inline u8 secondary_ch_offset_to_hal_ch_offset23a(u8 ch_offset)
+{
+       if (ch_offset == SCN)
+               return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+       else if (ch_offset == SCA)
+               return HAL_PRIME_CHNL_OFFSET_UPPER;
+       else if (ch_offset == SCB)
+               return HAL_PRIME_CHNL_OFFSET_LOWER;
+
+       return HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+}
+
+inline u8 hal_ch_offset_to_secondary_ch_offset23a(u8 ch_offset)
+{
+       if (ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+               return SCN;
+       else if (ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+               return SCB;
+       else if (ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+               return SCA;
+
+       return SCN;
+}
+
+inline u8 *rtw_set_ie23a_secondary_ch_offset(u8 *buf, u32 *buf_len,
+                                         u8 secondary_ch_offset)
+{
+       return rtw_set_ie23a(buf, WLAN_EID_SECONDARY_CHANNEL_OFFSET,
+                         1, &secondary_ch_offset, buf_len);
+}
+
+inline u8 *rtw_set_ie23a_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl,
+                                         u8 flags, u16 reason, u16 precedence)
+{
+       u8 ie_data[6];
+
+       ie_data[0] = ttl;
+       ie_data[1] = flags;
+       put_unaligned_le16(reason, (u8*)&ie_data[2]);
+       put_unaligned_le16(precedence, (u8*)&ie_data[4]);
+
+       return rtw_set_ie23a(buf, 0x118,  6, ie_data, buf_len);
+}
+
+/*----------------------------------------------------------------------------
+index: the information element id index, limit is the limit for search
+-----------------------------------------------------------------------------*/
+u8 *rtw_get_ie23a(u8 *pbuf, int index, int *len, int limit)
+{
+       int tmp, i;
+       u8 *p;
+
+       if (limit < 1) {
+
+               return NULL;
+       }
+
+       p = pbuf;
+       i = 0;
+       *len = 0;
+       while (1) {
+               if (*p == index) {
+                       *len = *(p + 1);
+                       return p;
+               } else {
+                       tmp = *(p + 1);
+                       p += (tmp + 2);
+                       i += (tmp + 2);
+               }
+               if (i >= limit)
+                       break;
+       }
+
+       return NULL;
+}
+
+/**
+ * rtw_get_ie23a_ex - Search specific IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @eid: Element ID to match
+ * @oui: OUI to match
+ * @oui_len: OUI length
+ * @ie: If not NULL and the specific IE is found, the IE will be copied
+ *      to the buf starting from the specific IE
+ * @ielen: If not NULL and the specific IE is found, will set to the length
+ *         of the entire IE
+ *
+ * Returns: The address of the specific IE found, or NULL
+ */
+u8 *rtw_get_ie23a_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len,
+                 u8 *ie, uint *ielen)
+{
+       uint cnt;
+       u8 *target_ie = NULL;
+
+       if (ielen)
+               *ielen = 0;
+
+       if (!in_ie || in_len <= 0)
+               return target_ie;
+
+       cnt = 0;
+
+       while (cnt < in_len) {
+               if (eid == in_ie[cnt] &&
+                   (!oui || !memcmp(&in_ie[cnt+2], oui, oui_len))) {
+                       target_ie = &in_ie[cnt];
+
+                       if (ie)
+                               memcpy(ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+                       if (ielen)
+                               *ielen = in_ie[cnt+1]+2;
+                       break;
+               } else {
+                       cnt += in_ie[cnt + 1] + 2; /* goto next */
+               }
+       }
+
+       return target_ie;
+}
+
+/**
+ * rtw_ies_remove_ie23a - Find matching IEs and remove
+ * @ies: Address of IEs to search
+ * @ies_len: Pointer of length of ies, will update to new length
+ * @offset: The offset to start scarch
+ * @eid: Element ID to match
+ * @oui: OUI to match
+ * @oui_len: OUI length
+ *
+ * Returns: _SUCCESS: ies is updated, _FAIL: not updated
+ */
+int rtw_ies_remove_ie23a(u8 *ies, uint *ies_len, uint offset, u8 eid,
+                     u8 *oui, u8 oui_len)
+{
+       int ret = _FAIL;
+       u8 *target_ie;
+       u32 target_ielen;
+       u8 *start;
+       uint search_len;
+
+       if (!ies || !ies_len || *ies_len <= offset)
+               goto exit;
+
+       start = ies + offset;
+       search_len = *ies_len - offset;
+
+       while (1) {
+               target_ie = rtw_get_ie23a_ex(start, search_len, eid, oui, oui_len,
+                                         NULL, &target_ielen);
+               if (target_ie && target_ielen) {
+                       u8 buf[MAX_IE_SZ] = {0};
+                       u8 *remain_ies = target_ie + target_ielen;
+                       uint remain_len = search_len - (remain_ies - start);
+
+                       memcpy(buf, remain_ies, remain_len);
+                       memcpy(target_ie, buf, remain_len);
+                       *ies_len = *ies_len - target_ielen;
+                       ret = _SUCCESS;
+
+                       start = target_ie;
+                       search_len = remain_len;
+               } else {
+                       break;
+               }
+       }
+exit:
+       return ret;
+}
+
+void rtw_set_supported_rate23a(u8* SupportedRates, uint mode)
+{
+
+
+       memset(SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+       switch (mode)
+       {
+       case WIRELESS_11B:
+               memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
+               break;
+
+       case WIRELESS_11G:
+       case WIRELESS_11A:
+       case WIRELESS_11_5N:
+       case WIRELESS_11A_5N:/* Todo: no basic rate for ofdm ? */
+               memcpy(SupportedRates, WIFI_OFDMRATES,
+                      IEEE80211_NUM_OFDM_RATESLEN);
+               break;
+
+       case WIRELESS_11BG:
+       case WIRELESS_11G_24N:
+       case WIRELESS_11_24N:
+       case WIRELESS_11BG_24N:
+               memcpy(SupportedRates, WIFI_CCKRATES, IEEE80211_CCK_RATE_LEN);
+               memcpy(SupportedRates + IEEE80211_CCK_RATE_LEN, WIFI_OFDMRATES,
+                      IEEE80211_NUM_OFDM_RATESLEN);
+               break;
+       }
+
+}
+
+uint rtw_get_rateset_len23a(u8 *rateset)
+{
+       uint i = 0;
+
+       while(1) {
+               if ((rateset[i]) == 0)
+                       break;
+
+               if (i > 12)
+                       break;
+
+               i++;
+       }
+
+       return i;
+}
+
+int rtw_generate_ie23a(struct registry_priv *pregistrypriv)
+{
+       u8      wireless_mode;
+       int     sz = 0, rateLen;
+       struct wlan_bssid_ex*   pdev_network = &pregistrypriv->dev_network;
+       u8*     ie = pdev_network->IEs;
+
+
+
+       /* timestamp will be inserted by hardware */
+       sz += 8;
+       ie += sz;
+
+       /* beacon interval : 2bytes */
+       /* BCN_INTERVAL; */
+       *(u16*)ie = cpu_to_le16((u16)pdev_network->Configuration.BeaconPeriod);
+       sz += 2;
+       ie += 2;
+
+       /* capability info */
+       *(u16*)ie = 0;
+
+       *(u16*)ie |= cpu_to_le16(cap_IBSS);
+
+       if (pregistrypriv->preamble == PREAMBLE_SHORT)
+               *(u16*)ie |= cpu_to_le16(cap_ShortPremble);
+
+       if (pdev_network->Privacy)
+               *(u16*)ie |= cpu_to_le16(cap_Privacy);
+
+       sz += 2;
+       ie += 2;
+
+       /* SSID */
+       ie = rtw_set_ie23a(ie, _SSID_IE_, pdev_network->Ssid.ssid_len,
+                       pdev_network->Ssid.ssid, &sz);
+
+       /* supported rates */
+       if (pregistrypriv->wireless_mode == WIRELESS_11ABGN) {
+               if (pdev_network->Configuration.DSConfig > 14)
+                       wireless_mode = WIRELESS_11A_5N;
+               else
+                       wireless_mode = WIRELESS_11BG_24N;
+       } else {
+               wireless_mode = pregistrypriv->wireless_mode;
+       }
+
+       rtw_set_supported_rate23a(pdev_network->SupportedRates, wireless_mode) ;
+
+       rateLen = rtw_get_rateset_len23a(pdev_network->SupportedRates);
+
+       if (rateLen > 8) {
+               ie = rtw_set_ie23a(ie, _SUPPORTEDRATES_IE_, 8,
+                               pdev_network->SupportedRates, &sz);
+               /* ie = rtw_set_ie23a(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8), (pdev_network->SupportedRates + 8), &sz); */
+       } else {
+               ie = rtw_set_ie23a(ie, _SUPPORTEDRATES_IE_, rateLen,
+                               pdev_network->SupportedRates, &sz);
+       }
+
+       /* DS parameter set */
+       ie = rtw_set_ie23a(ie, _DSSET_IE_, 1,
+                          (u8 *)&pdev_network->Configuration.DSConfig, &sz);
+
+       /* IBSS Parameter Set */
+
+       ie = rtw_set_ie23a(ie, _IBSS_PARA_IE_, 2,
+                          (u8 *)&pdev_network->Configuration.ATIMWindow, &sz);
+
+       if (rateLen > 8) {
+               ie = rtw_set_ie23a(ie, _EXT_SUPPORTEDRATES_IE_, (rateLen - 8),
+                               (pdev_network->SupportedRates + 8), &sz);
+       }
+
+
+
+       /* return _SUCCESS; */
+
+       return sz;
+}
+
+unsigned char *rtw_get_wpa_ie23a(unsigned char *pie, int *wpa_ie_len, int limit)
+{
+       int len;
+       u16 val16;
+       unsigned char wpa_oui_type[] = {0x00, 0x50, 0xf2, 0x01};
+       u8 *pbuf = pie;
+       int limit_new = limit;
+
+       while(1) {
+               pbuf = rtw_get_ie23a(pbuf, _WPA_IE_ID_, &len, limit_new);
+
+               if (pbuf) {
+                       /* check if oui matches... */
+                       if (memcmp((pbuf + 2), wpa_oui_type,
+                                  sizeof(wpa_oui_type))) {
+                               goto check_next_ie;
+                       }
+
+                       /* check version... */
+                       memcpy((u8 *)&val16, (pbuf + 6), sizeof(val16));
+
+                       val16 = le16_to_cpu(val16);
+                       if (val16 != 0x0001)
+                               goto check_next_ie;
+
+                       *wpa_ie_len = *(pbuf + 1);
+
+                       return pbuf;
+               } else {
+                       *wpa_ie_len = 0;
+                       return NULL;
+               }
+
+check_next_ie:
+
+               limit_new = limit - (pbuf - pie) - 2 - len;
+
+               if (limit_new <= 0)
+                       break;
+
+               pbuf += (2 + len);
+       }
+
+       *wpa_ie_len = 0;
+
+       return NULL;
+}
+
+unsigned char *rtw_get_wpa2_ie23a(unsigned char *pie, int *rsn_ie_len, int limit)
+{
+       return rtw_get_ie23a(pie, _WPA2_IE_ID_, rsn_ie_len, limit);
+}
+
+int rtw_get_wpa_cipher_suite23a(u8 *s)
+{
+       if (!memcmp(s, WPA_CIPHER_SUITE_NONE23A, WPA_SELECTOR_LEN))
+               return WPA_CIPHER_NONE;
+       if (!memcmp(s, WPA_CIPHER_SUITE_WEP4023A, WPA_SELECTOR_LEN))
+               return WPA_CIPHER_WEP40;
+       if (!memcmp(s, WPA_CIPHER_SUITE_TKIP23A, WPA_SELECTOR_LEN))
+               return WPA_CIPHER_TKIP;
+       if (!memcmp(s, WPA_CIPHER_SUITE_CCMP23A, WPA_SELECTOR_LEN))
+               return WPA_CIPHER_CCMP;
+       if (!memcmp(s, WPA_CIPHER_SUITE_WEP10423A, WPA_SELECTOR_LEN))
+               return WPA_CIPHER_WEP104;
+
+       return 0;
+}
+
+int rtw_get_wpa2_cipher_suite23a(u8 *s)
+{
+       if (!memcmp(s, RSN_CIPHER_SUITE_NONE23A, RSN_SELECTOR_LEN))
+               return WPA_CIPHER_NONE;
+       if (!memcmp(s, RSN_CIPHER_SUITE_WEP4023A, RSN_SELECTOR_LEN))
+               return WPA_CIPHER_WEP40;
+       if (!memcmp(s, RSN_CIPHER_SUITE_TKIP23A, RSN_SELECTOR_LEN))
+               return WPA_CIPHER_TKIP;
+       if (!memcmp(s, RSN_CIPHER_SUITE_CCMP23A, RSN_SELECTOR_LEN))
+               return WPA_CIPHER_CCMP;
+       if (!memcmp(s, RSN_CIPHER_SUITE_WEP10423A, RSN_SELECTOR_LEN))
+               return WPA_CIPHER_WEP104;
+
+       return 0;
+}
+
+int rtw_parse_wpa_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x)
+{
+       int i, ret = _SUCCESS;
+       int left, count;
+       u8 *pos;
+       u8 SUITE_1X[4] = {0x00, 0x50, 0xf2, 1};
+
+       if (wpa_ie_len <= 0) {
+               /* No WPA IE - fail silently */
+               return _FAIL;
+       }
+
+       if ((*wpa_ie != _WPA_IE_ID_) || (*(wpa_ie+1) != (u8)(wpa_ie_len - 2)) ||
+           memcmp(wpa_ie + 2, RTW_WPA_OUI23A_TYPE, WPA_SELECTOR_LEN)) {
+               return _FAIL;
+       }
+
+       pos = wpa_ie;
+
+       pos += 8;
+       left = wpa_ie_len - 8;
+
+       /* group_cipher */
+       if (left >= WPA_SELECTOR_LEN) {
+
+               *group_cipher = rtw_get_wpa_cipher_suite23a(pos);
+
+               pos += WPA_SELECTOR_LEN;
+               left -= WPA_SELECTOR_LEN;
+       } else if (left > 0) {
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                        ("%s: ie length mismatch, %u too much",
+                         __func__, left));
+
+               return _FAIL;
+       }
+
+       /* pairwise_cipher */
+       if (left >= 2) {
+                /* count = le16_to_cpu(*(u16*)pos); */
+               count = get_unaligned_le16(pos);
+               pos += 2;
+               left -= 2;
+
+               if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                                ("%s: ie count botch (pairwise), "
+                                 "count %u left %u", __func__,
+                                 count, left));
+                       return _FAIL;
+               }
+
+               for (i = 0; i < count; i++) {
+                       *pairwise_cipher |= rtw_get_wpa_cipher_suite23a(pos);
+
+                       pos += WPA_SELECTOR_LEN;
+                       left -= WPA_SELECTOR_LEN;
+               }
+       } else if (left == 1) {
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                        ("%s: ie too short (for key mgmt)", __func__));
+               return _FAIL;
+       }
+
+       if (is_8021x) {
+               if (left >= 6) {
+                       pos += 2;
+                       if (!memcmp(pos, SUITE_1X, 4)) {
+                               RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                        ("%s : there has 802.1x auth\n",
+                                         __func__));
+                               *is_8021x = 1;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+int rtw_parse_wpa2_ie23a(u8* rsn_ie, int rsn_ie_len, int *group_cipher,
+                     int *pairwise_cipher, int *is_8021x)
+{
+       int i, ret = _SUCCESS;
+       int left, count;
+       u8 *pos;
+       u8 SUITE_1X[4] = {0x00, 0x0f, 0xac, 0x01};
+
+       if (rsn_ie_len <= 0) {
+               /* No RSN IE - fail silently */
+               return _FAIL;
+       }
+
+       if ((*rsn_ie!= _WPA2_IE_ID_) || (*(rsn_ie+1) != (u8)(rsn_ie_len - 2))) {
+               return _FAIL;
+       }
+
+       pos = rsn_ie;
+       pos += 4;
+       left = rsn_ie_len - 4;
+
+       /* group_cipher */
+       if (left >= RSN_SELECTOR_LEN) {
+               *group_cipher = rtw_get_wpa2_cipher_suite23a(pos);
+
+               pos += RSN_SELECTOR_LEN;
+               left -= RSN_SELECTOR_LEN;
+       } else if (left > 0) {
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                        ("%s: ie length mismatch, %u too much",
+                         __func__, left));
+               return _FAIL;
+       }
+
+       /* pairwise_cipher */
+       if (left >= 2) {
+               /* count = le16_to_cpu(*(u16*)pos); */
+               count = get_unaligned_le16(pos);
+               pos += 2;
+               left -= 2;
+
+               if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                                ("%s: ie count botch (pairwise), "
+                                 "count %u left %u",
+                                 __func__, count, left));
+                       return _FAIL;
+               }
+
+               for (i = 0; i < count; i++) {
+                       *pairwise_cipher |= rtw_get_wpa2_cipher_suite23a(pos);
+
+                       pos += RSN_SELECTOR_LEN;
+                       left -= RSN_SELECTOR_LEN;
+               }
+       } else if (left == 1) {
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                        ("%s: ie too short (for key mgmt)",  __func__));
+
+               return _FAIL;
+       }
+
+       if (is_8021x) {
+               if (left >= 6) {
+                       pos += 2;
+                       if (!memcmp(pos, SUITE_1X, 4)) {
+                               RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                        ("%s (): there has 802.1x auth\n",
+                                         __func__));
+                               *is_8021x = 1;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+int rtw_get_sec_ie23a(u8 *in_ie, uint in_len, u8 *rsn_ie, u16 *rsn_len,
+                  u8 *wpa_ie, u16 *wpa_len)
+{
+       u8 authmode, sec_idx, i;
+       u8 wpa_oui[4] = {0x0, 0x50, 0xf2, 0x01};
+       uint cnt;
+
+
+
+       /* Search required WPA or WPA2 IE and copy to sec_ie[ ] */
+
+       cnt = (_TIMESTAMP_ + _BEACON_ITERVAL_ + _CAPABILITY_);
+
+       sec_idx = 0;
+
+       while(cnt < in_len) {
+               authmode = in_ie[cnt];
+
+               if ((authmode == _WPA_IE_ID_) &&
+                   !memcmp(&in_ie[cnt+2], &wpa_oui[0], 4)) {
+                               RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                        ("\n rtw_get_wpa_ie23a: sec_idx =%d "
+                                         "in_ie[cnt+1]+2 =%d\n",
+                                         sec_idx, in_ie[cnt + 1] + 2));
+
+                               if (wpa_ie) {
+                               memcpy(wpa_ie, &in_ie[cnt], in_ie[cnt+1]+2);
+
+                               for (i = 0; i < (in_ie[cnt + 1] + 2); i = i + 8) {
+                                       RT_TRACE(_module_rtl871x_mlme_c_,
+                                                _drv_info_,
+                                                ("\n %2x,%2x,%2x,%2x,%2x,%2x,"
+                                                 "%2x,%2x\n", wpa_ie[i],
+                                                 wpa_ie[i + 1], wpa_ie[i + 2],
+                                                 wpa_ie[i + 3], wpa_ie[i + 4],
+                                                 wpa_ie[i + 5], wpa_ie[i + 6],
+                                                 wpa_ie[i + 7]));
+                                       }
+                               }
+
+                               *wpa_len = in_ie[cnt + 1] + 2;
+                               cnt += in_ie[cnt + 1] + 2;  /* get next */
+               } else {
+                       if (authmode == _WPA2_IE_ID_) {
+                               RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                        ("\n get_rsn_ie: sec_idx =%d in_ie"
+                                         "[cnt+1]+2 =%d\n", sec_idx,
+                                         in_ie[cnt + 1] + 2));
+
+                               if (rsn_ie) {
+                               memcpy(rsn_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+
+                               for (i = 0; i < (in_ie[cnt + 1] + 2); i = i + 8) {
+                                       RT_TRACE(_module_rtl871x_mlme_c_,
+                                                _drv_info_,
+                                                ("\n %2x,%2x,%2x,%2x,%2x,%2x,"
+                                                 "%2x,%2x\n", rsn_ie[i],
+                                                 rsn_ie[i + 1], rsn_ie[i + 2],
+                                                 rsn_ie[i + 3], rsn_ie[i + 4],
+                                                 rsn_ie[i + 5], rsn_ie[i + 6],
+                                                 rsn_ie[i + 7]));
+                                       }
+                               }
+
+                               *rsn_len = in_ie[cnt + 1] + 2;
+                               cnt += in_ie[cnt + 1] + 2;  /* get next */
+                       } else {
+                               cnt += in_ie[cnt + 1] + 2;   /* get next */
+                       }
+               }
+       }
+
+
+
+       return *rsn_len + *wpa_len;
+}
+
+u8 rtw_is_wps_ie23a(u8 *ie_ptr, uint *wps_ielen)
+{
+       u8 match = false;
+       u8 eid, wps_oui[4]= {0x0, 0x50, 0xf2, 0x04};
+
+       if (!ie_ptr)
+               return match;
+
+       eid = ie_ptr[0];
+
+       if ((eid == _WPA_IE_ID_) && !memcmp(&ie_ptr[2], wps_oui, 4)) {
+               /* DBG_8723A("==> found WPS_IE.....\n"); */
+               *wps_ielen = ie_ptr[1] + 2;
+               match = true;
+       }
+       return match;
+}
+
+/**
+ * rtw_get_wps_ie23a - Search WPS IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @wps_ie: If not NULL and WPS IE is found, WPS IE will be copied to the
+ *          buf starting from wps_ie
+ * @wps_ielen: If not NULL and WPS IE is found, will set to the length of
+ *             the entire WPS IE
+ *
+ * Returns: The address of the WPS IE found, or NULL
+ */
+u8 *rtw_get_wps_ie23a(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen)
+{
+       uint cnt;
+       u8 *wpsie_ptr = NULL;
+       u8 eid, wps_oui[4] = {0x0, 0x50, 0xf2, 0x04};
+
+       if (wps_ielen)
+               *wps_ielen = 0;
+
+       if (!in_ie || in_len <= 0)
+               return wpsie_ptr;
+
+       cnt = 0;
+
+       while (cnt < in_len) {
+               eid = in_ie[cnt];
+
+               if ((eid == _WPA_IE_ID_) && !memcmp(&in_ie[cnt+2], wps_oui, 4)) {
+                       wpsie_ptr = &in_ie[cnt];
+
+                       if (wps_ie)
+                               memcpy(wps_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+
+                       if (wps_ielen)
+                               *wps_ielen = in_ie[cnt + 1] + 2;
+
+                       cnt += in_ie[cnt + 1] + 2;
+
+                       break;
+               } else {
+                       cnt += in_ie[cnt + 1] + 2; /* goto next */
+               }
+       }
+
+       return wpsie_ptr;
+}
+
+/**
+ * rtw_get_wps_attr23a - Search a specific WPS attribute from a given WPS IE
+ * @wps_ie: Address of WPS IE to search
+ * @wps_ielen: Length limit from wps_ie
+ * @target_attr_id: The attribute ID of WPS attribute to search
+ * @buf_attr: If not NULL and the WPS attribute is found, WPS attribute
+ *            will be copied to the buf starting from buf_attr
+ * @len_attr: If not NULL and the WPS attribute is found, will set to the
+ *            length of the entire WPS attribute
+ *
+ * Returns: the address of the specific WPS attribute found, or NULL
+ */
+u8 *rtw_get_wps_attr23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id,
+                    u8 *buf_attr, u32 *len_attr)
+{
+       u8 *attr_ptr = NULL;
+       u8 * target_attr_ptr = NULL;
+       u8 wps_oui[4] = {0x00, 0x50, 0xF2, 0x04};
+
+       if (len_attr)
+               *len_attr = 0;
+
+       if ((wps_ie[0] != _VENDOR_SPECIFIC_IE_) ||
+           memcmp(wps_ie + 2, wps_oui, 4)) {
+               return attr_ptr;
+       }
+
+       /*  6 = 1(Element ID) + 1(Length) + 4(WPS OUI) */
+       attr_ptr = wps_ie + 6; /* goto first attr */
+
+       while (attr_ptr - wps_ie < wps_ielen) {
+               /*  4 = 2(Attribute ID) + 2(Length) */
+               u16 attr_id = get_unaligned_be16(attr_ptr);
+               u16 attr_data_len = get_unaligned_be16(attr_ptr + 2);
+               u16 attr_len = attr_data_len + 4;
+
+               /* DBG_8723A("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); */
+               if (attr_id == target_attr_id) {
+                       target_attr_ptr = attr_ptr;
+
+                       if (buf_attr)
+                               memcpy(buf_attr, attr_ptr, attr_len);
+
+                       if (len_attr)
+                               *len_attr = attr_len;
+
+                       break;
+               } else {
+                       attr_ptr += attr_len; /* goto next */
+               }
+       }
+
+       return target_attr_ptr;
+}
+
+/**
+ * rtw_get_wps_attr_content23a - Search a specific WPS attribute content
+ * from a given WPS IE
+ * @wps_ie: Address of WPS IE to search
+ * @wps_ielen: Length limit from wps_ie
+ * @target_attr_id: The attribute ID of WPS attribute to search
+ * @buf_content: If not NULL and the WPS attribute is found, WPS attribute
+ *               content will be copied to the buf starting from buf_content
+ * @len_content: If not NULL and the WPS attribute is found, will set to the
+ *               length of the WPS attribute content
+ *
+ * Returns: the address of the specific WPS attribute content found, or NULL
+ */
+u8 *rtw_get_wps_attr_content23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id,
+                               u8 *buf_content, uint *len_content)
+{
+       u8 *attr_ptr;
+       u32 attr_len;
+
+       if (len_content)
+               *len_content = 0;
+
+       attr_ptr = rtw_get_wps_attr23a(wps_ie, wps_ielen, target_attr_id,
+                                   NULL, &attr_len);
+
+       if (attr_ptr && attr_len) {
+               if (buf_content)
+                       memcpy(buf_content, attr_ptr + 4, attr_len - 4);
+
+               if (len_content)
+                       *len_content = attr_len - 4;
+
+               return attr_ptr + 4;
+       }
+
+       return NULL;
+}
+
+static int
+rtw_ieee802_11_parse_vendor_specific(u8 *pos, uint elen,
+                                    struct rtw_ieee802_11_elems *elems,
+                                    int show_errors)
+{
+       unsigned int oui;
+
+       /* first 3 bytes in vendor specific information element are the IEEE
+        * OUI of the vendor. The following byte is used a vendor specific
+        * sub-type. */
+       if (elen < 4) {
+               if (show_errors) {
+                       DBG_8723A("short vendor specific "
+                                  "information element ignored (len =%lu)\n",
+                                  (unsigned long) elen);
+               }
+               return -1;
+       }
+
+       oui = RTW_GET_BE24(pos);
+       switch (oui) {
+       case WLAN_OUI_MICROSOFT:
+               /* Microsoft/Wi-Fi information elements are further typed and
+                * subtyped */
+               switch (pos[3]) {
+               case 1:
+                       /* Microsoft OUI (00:50:F2) with OUI Type 1:
+                        * real WPA information element */
+                       elems->wpa_ie = pos;
+                       elems->wpa_ie_len = elen;
+                       break;
+               case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
+                       if (elen < 5) {
+                               DBG_8723A("short WME "
+                                          "information element ignored "
+                                          "(len =%lu)\n",
+                                          (unsigned long) elen);
+                               return -1;
+                       }
+                       switch (pos[4]) {
+                       case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
+                       case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
+                               elems->wme = pos;
+                               elems->wme_len = elen;
+                               break;
+                       case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
+                               elems->wme_tspec = pos;
+                               elems->wme_tspec_len = elen;
+                               break;
+                       default:
+                               DBG_8723A("unknown WME "
+                                          "information element ignored "
+                                          "(subtype =%d len =%lu)\n",
+                                          pos[4], (unsigned long) elen);
+                               return -1;
+                       }
+                       break;
+               case 4:
+                       /* Wi-Fi Protected Setup (WPS) IE */
+                       elems->wps_ie = pos;
+                       elems->wps_ie_len = elen;
+                       break;
+               default:
+                       DBG_8723A("Unknown Microsoft "
+                                  "information element ignored "
+                                  "(type =%d len =%lu)\n",
+                                  pos[3], (unsigned long) elen);
+                       return -1;
+               }
+               break;
+
+       case OUI_BROADCOM:
+               switch (pos[3]) {
+               case VENDOR_HT_CAPAB_OUI_TYPE:
+                       elems->vendor_ht_cap = pos;
+                       elems->vendor_ht_cap_len = elen;
+                       break;
+               default:
+                       DBG_8723A("Unknown Broadcom "
+                                  "information element ignored "
+                                  "(type =%d len =%lu)\n",
+                                  pos[3], (unsigned long) elen);
+                       return -1;
+               }
+               break;
+
+       default:
+               DBG_8723A("unknown vendor specific information "
+                          "element ignored (vendor OUI %02x:%02x:%02x "
+                          "len =%lu)\n",
+                          pos[0], pos[1], pos[2], (unsigned long) elen);
+               return -1;
+       }
+
+       return 0;
+}
+
+/**
+ * ieee802_11_parse_elems - Parse information elements in management frames
+ * @start: Pointer to the start of IEs
+ * @len: Length of IE buffer in octets
+ * @elems: Data structure for parsed elements
+ * @show_errors: Whether to show parsing errors in debug log
+ * Returns: Parsing result
+ */
+enum parse_res rtw_ieee802_11_parse_elems23a(u8 *start, uint len,
+                               struct rtw_ieee802_11_elems *elems,
+                               int show_errors)
+{
+       uint left = len;
+       u8 *pos = start;
+       int unknown = 0;
+
+       memset(elems, 0, sizeof(*elems));
+
+       while (left >= 2) {
+               u8 id, elen;
+
+               id = *pos++;
+               elen = *pos++;
+               left -= 2;
+
+               if (elen > left) {
+                       if (show_errors) {
+                               DBG_8723A("IEEE 802.11 element "
+                                          "parse failed (id =%d elen =%d "
+                                          "left =%lu)\n",
+                                          id, elen, (unsigned long) left);
+                       }
+                       return ParseFailed;
+               }
+
+               switch (id) {
+               case WLAN_EID_SSID:
+                       elems->ssid = pos;
+                       elems->ssid_len = elen;
+                       break;
+               case WLAN_EID_SUPP_RATES:
+                       elems->supp_rates = pos;
+                       elems->supp_rates_len = elen;
+                       break;
+               case WLAN_EID_FH_PARAMS:
+                       elems->fh_params = pos;
+                       elems->fh_params_len = elen;
+                       break;
+               case WLAN_EID_DS_PARAMS:
+                       elems->ds_params = pos;
+                       elems->ds_params_len = elen;
+                       break;
+               case WLAN_EID_CF_PARAMS:
+                       elems->cf_params = pos;
+                       elems->cf_params_len = elen;
+                       break;
+               case WLAN_EID_TIM:
+                       elems->tim = pos;
+                       elems->tim_len = elen;
+                       break;
+               case WLAN_EID_IBSS_PARAMS:
+                       elems->ibss_params = pos;
+                       elems->ibss_params_len = elen;
+                       break;
+               case WLAN_EID_CHALLENGE:
+                       elems->challenge = pos;
+                       elems->challenge_len = elen;
+                       break;
+               case WLAN_EID_ERP_INFO:
+                       elems->erp_info = pos;
+                       elems->erp_info_len = elen;
+                       break;
+               case WLAN_EID_EXT_SUPP_RATES:
+                       elems->ext_supp_rates = pos;
+                       elems->ext_supp_rates_len = elen;
+                       break;
+               case WLAN_EID_VENDOR_SPECIFIC:
+                       if (rtw_ieee802_11_parse_vendor_specific(pos, elen,
+                                                                elems,
+                                                                show_errors))
+                               unknown++;
+                       break;
+               case WLAN_EID_RSN:
+                       elems->rsn_ie = pos;
+                       elems->rsn_ie_len = elen;
+                       break;
+               case WLAN_EID_PWR_CAPABILITY:
+                       elems->power_cap = pos;
+                       elems->power_cap_len = elen;
+                       break;
+               case WLAN_EID_SUPPORTED_CHANNELS:
+                       elems->supp_channels = pos;
+                       elems->supp_channels_len = elen;
+                       break;
+               case WLAN_EID_MOBILITY_DOMAIN:
+                       elems->mdie = pos;
+                       elems->mdie_len = elen;
+                       break;
+               case WLAN_EID_FAST_BSS_TRANSITION:
+                       elems->ftie = pos;
+                       elems->ftie_len = elen;
+                       break;
+               case WLAN_EID_TIMEOUT_INTERVAL:
+                       elems->timeout_int = pos;
+                       elems->timeout_int_len = elen;
+                       break;
+               case WLAN_EID_HT_CAPABILITY:
+                       elems->ht_capabilities = pos;
+                       elems->ht_capabilities_len = elen;
+                       break;
+               case WLAN_EID_HT_OPERATION:
+                       elems->ht_operation = pos;
+                       elems->ht_operation_len = elen;
+                       break;
+               default:
+                       unknown++;
+                       if (!show_errors)
+                               break;
+                       DBG_8723A("IEEE 802.11 element parse "
+                                  "ignored unknown element (id =%d elen =%d)\n",
+                                  id, elen);
+                       break;
+               }
+
+               left -= elen;
+               pos += elen;
+       }
+
+       if (left)
+               return ParseFailed;
+
+       return unknown ? ParseUnknown : ParseOK;
+}
+
+static u8 key_char2num(u8 ch)
+{
+       if ((ch >= '0') && (ch <= '9'))
+               return ch - '0';
+       else if ((ch >= 'a') && (ch <= 'f'))
+               return ch - 'a' + 10;
+       else if ((ch >= 'A') && (ch <= 'F'))
+               return ch - 'A' + 10;
+       else
+               return 0xff;
+}
+
+u8 str_2char2num23a(u8 hch, u8 lch)
+{
+       return (key_char2num(hch) * 10) + key_char2num(lch);
+}
+
+u8 key_2char2num23a(u8 hch, u8 lch)
+{
+       return (key_char2num(hch) << 4) | key_char2num(lch);
+}
+
+void rtw_macaddr_cfg23a(u8 *mac_addr)
+{
+       u8 mac[ETH_ALEN];
+       if (!mac_addr)
+               return;
+
+       memcpy(mac, mac_addr, ETH_ALEN);
+
+       if (is_broadcast_ether_addr(mac) || is_zero_ether_addr(mac)) {
+               mac[0] = 0x00;
+               mac[1] = 0xe0;
+               mac[2] = 0x4c;
+               mac[3] = 0x87;
+               mac[4] = 0x00;
+               mac[5] = 0x00;
+               /*  use default mac addresss */
+               memcpy(mac_addr, mac, ETH_ALEN);
+               DBG_8723A("MAC Address from efuse error, assign default "
+                         "one !!!\n");
+       }
+       DBG_8723A("rtw_macaddr_cfg23a MAC Address  = "MAC_FMT"\n",
+                 MAC_ARG(mac_addr));
+}
+
+void dump_ies23a(u8 *buf, u32 buf_len) {
+       u8* pos = (u8*)buf;
+       u8 id, len;
+
+       while (pos-buf <= buf_len) {
+               id = *pos;
+               len = *(pos + 1);
+
+               DBG_8723A("%s ID:%u, LEN:%u\n", __func__, id, len);
+#ifdef CONFIG_8723AU_P2P
+               dump_p2p_ie23a(pos, len);
+#endif
+               dump_wps_ie23a(pos, len);
+
+               pos += (2 + len);
+       }
+}
+
+void dump_wps_ie23a(u8 *ie, u32 ie_len) {
+       u8* pos = (u8*)ie;
+       u16 id;
+       u16 len;
+
+       u8 *wps_ie;
+       uint wps_ielen;
+
+       wps_ie = rtw_get_wps_ie23a(ie, ie_len, NULL, &wps_ielen);
+       if (wps_ie != ie || wps_ielen == 0)
+               return;
+
+       pos+= 6;
+       while (pos-ie < ie_len) {
+               id = get_unaligned_be16(pos);
+               len = get_unaligned_be16(pos + 2);
+
+               DBG_8723A("%s ID:0x%04x, LEN:%u\n", __func__, id, len);
+
+               pos += (4 + len);
+       }
+}
+
+#ifdef CONFIG_8723AU_P2P
+void dump_p2p_ie23a(u8 *ie, u32 ie_len) {
+       u8* pos = (u8*)ie;
+       u8 id;
+       u16 len;
+
+       u8 *p2p_ie;
+       uint p2p_ielen;
+
+       p2p_ie = rtw_get_p2p_ie23a(ie, ie_len, NULL, &p2p_ielen);
+       if (p2p_ie != ie || p2p_ielen == 0)
+               return;
+
+       pos += 6;
+       while (pos-ie < ie_len) {
+               id = *pos;
+               len = get_unaligned_le16(pos+1);
+
+               DBG_8723A("%s ID:%u, LEN:%u\n", __func__, id, len);
+
+               pos+= (3+len);
+       }
+}
+
+/**
+ * rtw_get_p2p_ie23a - Search P2P IE from a series of IEs
+ * @in_ie: Address of IEs to search
+ * @in_len: Length limit from in_ie
+ * @p2p_ie: If not NULL and P2P IE is found, P2P IE will be copied to the
+ *          buf starting from p2p_ie
+ * @p2p_ielen: If not NULL and P2P IE is found, will set to the length of
+ *             the entire P2P IE
+ *
+ * Returns: The address of the P2P IE found, or NULL
+ */
+u8 *rtw_get_p2p_ie23a(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen)
+{
+       uint cnt = 0;
+       u8 *p2p_ie_ptr;
+       u8 eid, p2p_oui[4]={0x50, 0x6F, 0x9A, 0x09};
+
+       if (p2p_ielen)
+               *p2p_ielen = 0;
+
+       while (cnt<in_len) {
+               eid = in_ie[cnt];
+               if ((in_len < 0) || (cnt > MAX_IE_SZ)) {
+                       dump_stack();
+                       return NULL;
+               }
+               if ((eid == _VENDOR_SPECIFIC_IE_) &&
+                   !memcmp(&in_ie[cnt + 2], p2p_oui, 4)) {
+                       p2p_ie_ptr = in_ie + cnt;
+
+                       if (p2p_ie != NULL) {
+                               memcpy(p2p_ie, &in_ie[cnt],
+                                      in_ie[cnt + 1] + 2);
+                       }
+
+                       if (p2p_ielen != NULL) {
+                               *p2p_ielen = in_ie[cnt + 1] + 2;
+                       }
+
+                       return p2p_ie_ptr;
+
+                       break;
+               } else {
+                       cnt += in_ie[cnt + 1] + 2; /* goto next */
+               }
+       }
+
+       return NULL;
+}
+
+/**
+ * rtw_get_p2p_attr23a - Search a specific P2P attribute from a given P2P IE
+ * @p2p_ie: Address of P2P IE to search
+ * @p2p_ielen: Length limit from p2p_ie
+ * @target_attr_id: The attribute ID of P2P attribute to search
+ * @buf_attr: If not NULL and the P2P attribute is found, P2P attribute will
+ *            be copied to the buf starting from buf_attr
+ * @len_attr: If not NULL and the P2P attribute is found, will set to the
+ *            length of the entire P2P attribute
+ *
+ * Returns: the address of the specific WPS attribute found, or NULL
+ */
+u8 *rtw_get_p2p_attr23a(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id,
+                    u8 *buf_attr, u32 *len_attr)
+{
+       u8 *attr_ptr = NULL;
+       u8 *target_attr_ptr = NULL;
+       u8 p2p_oui[4]={0x50, 0x6F, 0x9A, 0x09};
+
+       if (len_attr)
+               *len_attr = 0;
+
+       if (!p2p_ie || (p2p_ie[0] != _VENDOR_SPECIFIC_IE_) ||
+           memcmp(p2p_ie + 2, p2p_oui, 4)) {
+               return attr_ptr;
+       }
+
+       /*  6 = 1(Element ID) + 1(Length) + 3 (OUI) + 1(OUI Type) */
+       attr_ptr = p2p_ie + 6; /* goto first attr */
+
+       while (attr_ptr - p2p_ie < p2p_ielen) {
+               /*  3 = 1(Attribute ID) + 2(Length) */
+               u8 attr_id = *attr_ptr;
+               u16 attr_data_len = get_unaligned_le16(attr_ptr + 1);
+               u16 attr_len = attr_data_len + 3;
+
+               /* DBG_8723A("%s attr_ptr:%p, id:%u, length:%u\n", __func__, attr_ptr, attr_id, attr_data_len); */
+               if (attr_id == target_attr_id) {
+                       target_attr_ptr = attr_ptr;
+
+                       if (buf_attr)
+                               memcpy(buf_attr, attr_ptr, attr_len);
+
+                       if (len_attr)
+                               *len_attr = attr_len;
+
+                       break;
+               } else {
+                       attr_ptr += attr_len; /* goto next */
+               }
+       }
+
+       return target_attr_ptr;
+}
+
+/**
+ * rtw_get_p2p_attr23a_content - Search a specific P2P attribute content from
+ * a given P2P IE
+ * @p2p_ie: Address of P2P IE to search
+ * @p2p_ielen: Length limit from p2p_ie
+ * @target_attr_id: The attribute ID of P2P attribute to search
+ * @buf_content: If not NULL and the P2P attribute is found, P2P attribute
+ *               content will be copied to the buf starting from buf_content
+ * @len_content: If not NULL and the P2P attribute is found, will set to the
+ *               length of the P2P attribute content
+ *
+ * Returns: the address of the specific P2P attribute content found, or NULL
+ */
+u8 *rtw_get_p2p_attr23a_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id,
+                            u8 *buf_content, uint *len_content)
+{
+       u8 *attr_ptr;
+       u32 attr_len;
+
+       if (len_content)
+               *len_content = 0;
+
+       attr_ptr = rtw_get_p2p_attr23a(p2p_ie, p2p_ielen, target_attr_id,
+                                   NULL, &attr_len);
+
+       if (attr_ptr && attr_len) {
+               if (buf_content)
+                       memcpy(buf_content, attr_ptr + 3, attr_len - 3);
+
+               if (len_content)
+                       *len_content = attr_len - 3;
+
+               return attr_ptr+3;
+       }
+
+       return NULL;
+}
+
+u32 rtw_set_p2p_attr_content23a(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr)
+{
+       u32 a_len;
+
+       *pbuf = attr_id;
+
+       /* u16*)(pbuf + 1) = cpu_to_le16(attr_len); */
+       put_unaligned_le16(attr_len, pbuf + 1);
+
+       if (pdata_attr)
+               memcpy(pbuf + 3, pdata_attr, attr_len);
+
+       a_len = attr_len + 3;
+
+       return a_len;
+}
+
+static uint rtw_p2p_attr_remove(u8 *ie, uint ielen_ori, u8 attr_id)
+{
+       u8 *target_attr;
+       u32 target_attr_len;
+       uint ielen = ielen_ori;
+
+       while(1) {
+               target_attr = rtw_get_p2p_attr23a(ie, ielen, attr_id, NULL,
+                                            &target_attr_len);
+               if (target_attr && target_attr_len) {
+                       u8 *next_attr = target_attr+target_attr_len;
+                       uint remain_len = ielen-(next_attr-ie);
+                       /* dump_ies23a(ie, ielen); */
+
+                       memset(target_attr, 0, target_attr_len);
+                       memcpy(target_attr, next_attr, remain_len);
+                       memset(target_attr+remain_len, 0, target_attr_len);
+                       *(ie + 1) -= target_attr_len;
+                       ielen -= target_attr_len;
+               } else {
+                       /* if (index>0) */
+                       /*      dump_ies23a(ie, ielen); */
+                       break;
+               }
+       }
+
+       return ielen;
+}
+
+void rtw_wlan_bssid_ex_remove_p2p_attr23a(struct wlan_bssid_ex *bss_ex, u8 attr_id)
+{
+       u8 *p2p_ie;
+       uint p2p_ielen, p2p_ielen_ori;
+
+       if ((p2p_ie = rtw_get_p2p_ie23a(bss_ex->IEs + _FIXED_IE_LENGTH_,
+                                    bss_ex->IELength - _FIXED_IE_LENGTH_,
+                                    NULL, &p2p_ielen_ori))) {
+               p2p_ielen = rtw_p2p_attr_remove(p2p_ie, p2p_ielen_ori, attr_id);
+               if (p2p_ielen != p2p_ielen_ori) {
+                       u8 *next_ie_ori = p2p_ie+p2p_ielen_ori;
+                       u8 *next_ie = p2p_ie+p2p_ielen;
+                       uint remain_len;
+                       remain_len = bss_ex->IELength-(next_ie_ori-bss_ex->IEs);
+
+                       memcpy(next_ie, next_ie_ori, remain_len);
+                       memset(next_ie+remain_len, 0, p2p_ielen_ori-p2p_ielen);
+                       bss_ex->IELength -= p2p_ielen_ori-p2p_ielen;
+               }
+       }
+}
+
+#endif /* CONFIG_8723AU_P2P */
+
+#ifdef CONFIG_8723AU_P2P
+int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen)
+{
+       int match;
+       uint cnt = 0;
+       u8 eid, wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A};
+
+       match = false;
+
+       if (in_len < 0) {
+               return match;
+       }
+
+       while (cnt < in_len)
+       {
+               eid = in_ie[cnt];
+
+               if ((eid == _VENDOR_SPECIFIC_IE_) &&
+                   !memcmp(&in_ie[cnt+2], wfd_oui, 4)) {
+                       if (wfd_ie != NULL) {
+                               memcpy(wfd_ie, &in_ie[cnt], in_ie[cnt + 1] + 2);
+
+                       } else {
+                               if (wfd_ielen != NULL) {
+                                       *wfd_ielen = 0;
+                               }
+                       }
+
+                       if (wfd_ielen != NULL) {
+                               *wfd_ielen = in_ie[cnt + 1] + 2;
+                       }
+
+                       cnt += in_ie[cnt + 1] + 2;
+
+                       match = true;
+                       break;
+               } else {
+                       cnt += in_ie[cnt + 1] +2; /* goto next */
+               }
+       }
+
+       if (match == true) {
+               match = cnt;
+       }
+
+       return match;
+}
+
+/*     attr_content: The output buffer, contains the "body field" of
+       WFD attribute. */
+/*     attr_contentlen: The data length of the "body field" of WFD
+       attribute. */
+int rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id,
+                            u8 *attr_content, uint *attr_contentlen)
+{
+       int match;
+       uint cnt = 0;
+       u8 attr_id, wfd_oui[4] = {0x50, 0x6F, 0x9A, 0x0A};
+
+       match = false;
+
+       if ((wfd_ie[0] != _VENDOR_SPECIFIC_IE_) ||
+           memcmp(wfd_ie + 2, wfd_oui, 4)) {
+               return match;
+       }
+
+       /*      1 (WFD IE) + 1 (Length) + 3 (OUI) + 1 (OUI Type) */
+       cnt = 6;
+       while (cnt < wfd_ielen) {
+               u16 attrlen = get_unaligned_be16(wfd_ie + cnt + 1);
+
+               attr_id = wfd_ie[cnt];
+               if (attr_id == target_attr_id) {
+                       /*      3 -> 1 byte for attribute ID field, 2
+                               bytes for length field */
+                       if (attr_content)
+                               memcpy(attr_content, &wfd_ie[cnt + 3], attrlen);
+
+                       if (attr_contentlen)
+                               *attr_contentlen = attrlen;
+
+                       cnt += attrlen + 3;
+
+                       match = true;
+                       break;
+               } else {
+                       cnt += attrlen + 3; /* goto next */
+               }
+       }
+
+       return match;
+}
+#endif /*  CONFIG_8723AU_P2P */
+
+/* Baron adds to avoid FreeBSD warning */
+int ieee80211_is_empty_essid23a(const char *essid, int essid_len)
+{
+       /* Single white space is for Linksys APs */
+       if (essid_len == 1 && essid[0] == ' ')
+               return 1;
+
+       /* Otherwise, if the entire essid is 0, we assume it is hidden */
+       while (essid_len) {
+               essid_len--;
+               if (essid[essid_len] != '\0')
+                       return 0;
+       }
+
+       return 1;
+}
+
+static int rtw_get_cipher_info(struct wlan_network *pnetwork)
+{
+       u32 wpa_ielen;
+       unsigned char *pbuf;
+       int group_cipher = 0, pairwise_cipher = 0, is8021x = 0;
+       int ret = _FAIL;
+       int r;
+       pbuf = rtw_get_wpa_ie23a(&pnetwork->network.IEs[12], &wpa_ielen,
+                             pnetwork->network.IELength - 12);
+
+       if (pbuf && (wpa_ielen > 0)) {
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                        ("rtw_get_cipher_info: wpa_ielen: %d", wpa_ielen));
+               r = rtw_parse_wpa_ie23a(pbuf, wpa_ielen + 2, &group_cipher,
+                                    &pairwise_cipher, &is8021x);
+               if (r == _SUCCESS) {
+                       pnetwork->BcnInfo.pairwise_cipher = pairwise_cipher;
+                       pnetwork->BcnInfo.group_cipher = group_cipher;
+                       pnetwork->BcnInfo.is_8021x = is8021x;
+                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                ("%s: pnetwork->pairwise_cipher: %d, is_"
+                                 "8021x is %d", __func__,
+                                 pnetwork->BcnInfo.pairwise_cipher,
+                                 pnetwork->BcnInfo.is_8021x));
+                       ret = _SUCCESS;
+               }
+       } else {
+               pbuf = rtw_get_wpa2_ie23a(&pnetwork->network.IEs[12], &wpa_ielen,
+                                      pnetwork->network.IELength - 12);
+
+               if (pbuf && (wpa_ielen > 0)) {
+                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                ("get RSN IE\n"));
+                       r = rtw_parse_wpa2_ie23a(pbuf, wpa_ielen + 2,
+                                             &group_cipher, &pairwise_cipher,
+                                             &is8021x);
+                       if (r == _SUCCESS) {
+                               RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                        ("get RSN IE  OK!!!\n"));
+                               pnetwork->BcnInfo.pairwise_cipher =
+                                       pairwise_cipher;
+                               pnetwork->BcnInfo.group_cipher = group_cipher;
+                               pnetwork->BcnInfo.is_8021x = is8021x;
+                               RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                        ("%s: pnetwork->pairwise_cipher: %d,"
+                                         "pnetwork->group_cipher is %d, "
+                                         "is_8021x is %d", __func__,
+                                         pnetwork->BcnInfo.pairwise_cipher,
+                                         pnetwork->BcnInfo.group_cipher,
+                                         pnetwork->BcnInfo.is_8021x));
+                               ret = _SUCCESS;
+                       }
+               }
+       }
+
+       return ret;
+}
+
+void rtw_get_bcn_info23a(struct wlan_network *pnetwork)
+{
+       unsigned short cap = 0;
+       u8 bencrypt = 0;
+       /* u8 wpa_ie[255], rsn_ie[255]; */
+       u16 wpa_len = 0, rsn_len = 0;
+       struct HT_info_element *pht_info = NULL;
+       struct ieee80211_ht_cap *pht_cap = NULL;
+       unsigned int            len;
+       unsigned char           *p;
+
+       memcpy(&cap, rtw_get_capability23a_from_ie(pnetwork->network.IEs), 2);
+       cap = le16_to_cpu(cap);
+       if (cap & WLAN_CAPABILITY_PRIVACY) {
+               bencrypt = 1;
+               pnetwork->network.Privacy = 1;
+       } else {
+               pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_OPENSYS;
+       }
+       rtw_get_sec_ie23a(pnetwork->network.IEs, pnetwork->network.IELength,
+                      NULL, &rsn_len, NULL, &wpa_len);
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                ("rtw_get_bcn_info23a: ssid =%s\n", pnetwork->network.Ssid.ssid));
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                ("rtw_get_bcn_info23a: wpa_len =%d rsn_len =%d\n",
+                 wpa_len, rsn_len));
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                ("rtw_get_bcn_info23a: ssid =%s\n", pnetwork->network.Ssid.ssid));
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                ("rtw_get_bcn_info23a: wpa_len =%d rsn_len =%d\n",
+                 wpa_len, rsn_len));
+
+       if (rsn_len > 0) {
+               pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA2;
+       } else if (wpa_len > 0) {
+               pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WPA;
+       } else {
+               if (bencrypt)
+                       pnetwork->BcnInfo.encryp_protocol = ENCRYP_PROTOCOL_WEP;
+       }
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                ("rtw_get_bcn_info23a: pnetwork->encryp_protocol is %x\n",
+                 pnetwork->BcnInfo.encryp_protocol));
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                ("rtw_get_bcn_info23a: pnetwork->encryp_protocol is %x\n",
+                 pnetwork->BcnInfo.encryp_protocol));
+       rtw_get_cipher_info(pnetwork);
+
+       /* get bwmode and ch_offset */
+       /* parsing HT_CAP_IE */
+       p = rtw_get_ie23a(pnetwork->network.IEs + _FIXED_IE_LENGTH_,
+                      _HT_CAPABILITY_IE_, &len,
+                      pnetwork->network.IELength - _FIXED_IE_LENGTH_);
+       if (p && len > 0) {
+               pht_cap = (struct ieee80211_ht_cap *)(p + 2);
+               pnetwork->BcnInfo.ht_cap_info = pht_cap->cap_info;
+       } else {
+               pnetwork->BcnInfo.ht_cap_info = 0;
+       }
+       /* parsing HT_INFO_IE */
+       p = rtw_get_ie23a(pnetwork->network.IEs + _FIXED_IE_LENGTH_,
+                      _HT_ADD_INFO_IE_, &len,
+                      pnetwork->network.IELength - _FIXED_IE_LENGTH_);
+       if (p && len > 0) {
+               pht_info = (struct HT_info_element *)(p + 2);
+               pnetwork->BcnInfo.ht_info_infos_0 = pht_info->infos[0];
+       } else {
+               pnetwork->BcnInfo.ht_info_infos_0 = 0;
+       }
+}
+
+/* show MCS rate, unit: 100Kbps */
+u16 rtw_mcs_rate23a(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40,
+                unsigned char * MCS_rate)
+{
+       u16 max_rate = 0;
+
+       if (rf_type == RF_1T1R) {
+               if (MCS_rate[0] & BIT(7))
+                       max_rate = (bw_40MHz) ? ((short_GI_40)?1500:1350):
+                               ((short_GI_20)?722:650);
+               else if (MCS_rate[0] & BIT(6))
+                       max_rate = (bw_40MHz) ? ((short_GI_40)?1350:1215):
+                               ((short_GI_20)?650:585);
+               else if (MCS_rate[0] & BIT(5))
+                       max_rate = (bw_40MHz) ? ((short_GI_40)?1200:1080):
+                               ((short_GI_20)?578:520);
+               else if (MCS_rate[0] & BIT(4))
+                       max_rate = (bw_40MHz) ? ((short_GI_40)?900:810):
+                               ((short_GI_20)?433:390);
+               else if (MCS_rate[0] & BIT(3))
+                       max_rate = (bw_40MHz) ? ((short_GI_40)?600:540):
+                               ((short_GI_20)?289:260);
+               else if (MCS_rate[0] & BIT(2))
+                       max_rate = (bw_40MHz) ? ((short_GI_40)?450:405):
+                               ((short_GI_20)?217:195);
+               else if (MCS_rate[0] & BIT(1))
+                       max_rate = (bw_40MHz) ? ((short_GI_40)?300:270):
+                               ((short_GI_20)?144:130);
+               else if (MCS_rate[0] & BIT(0))
+                       max_rate = (bw_40MHz) ? ((short_GI_40)?150:135):
+                               ((short_GI_20)?72:65);
+       } else {
+               if (MCS_rate[1]) {
+                       if (MCS_rate[1] & BIT(7))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?3000:2700):((short_GI_20)?1444:1300);
+                       else if (MCS_rate[1] & BIT(6))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?2700:2430):((short_GI_20)?1300:1170);
+                       else if (MCS_rate[1] & BIT(5))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?2400:2160):((short_GI_20)?1156:1040);
+                       else if (MCS_rate[1] & BIT(4))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?1800:1620):((short_GI_20)?867:780);
+                       else if (MCS_rate[1] & BIT(3))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?1200:1080):((short_GI_20)?578:520);
+                       else if (MCS_rate[1] & BIT(2))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?900:810):((short_GI_20)?433:390);
+                       else if (MCS_rate[1] & BIT(1))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?600:540):((short_GI_20)?289:260);
+                       else if (MCS_rate[1] & BIT(0))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?300:270):((short_GI_20)?144:130);
+               } else {
+                       if (MCS_rate[0] & BIT(7))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?1500:1350):((short_GI_20)?722:650);
+                       else if (MCS_rate[0] & BIT(6))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?1350:1215):((short_GI_20)?650:585);
+                       else if (MCS_rate[0] & BIT(5))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?1200:1080):((short_GI_20)?578:520);
+                       else if (MCS_rate[0] & BIT(4))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?900:810):((short_GI_20)?433:390);
+                       else if (MCS_rate[0] & BIT(3))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?600:540):((short_GI_20)?289:260);
+                       else if (MCS_rate[0] & BIT(2))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?450:405):((short_GI_20)?217:195);
+                       else if (MCS_rate[0] & BIT(1))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?300:270):((short_GI_20)?144:130);
+                       else if (MCS_rate[0] & BIT(0))
+                               max_rate = (bw_40MHz) ? ((short_GI_40)?150:135):((short_GI_20)?72:65);
+               }
+       }
+       return max_rate;
+}
+
+int rtw_action_frame_parse23a(const u8 *frame, u32 frame_len, u8* category,
+                          u8 *action)
+{
+       const u8 *frame_body = frame + sizeof(struct ieee80211_hdr_3addr);
+       u16 fc;
+       u8 c, a = 0;
+
+       fc = le16_to_cpu(((struct ieee80211_hdr_3addr *)frame)->frame_control);
+
+       if ((fc & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE)) !=
+           (IEEE80211_FTYPE_MGMT|IEEE80211_STYPE_ACTION)) {
+               return false;
+       }
+
+       c = frame_body[0];
+
+       switch (c) {
+       case WLAN_CATEGORY_VENDOR_SPECIFIC: /* vendor-specific */
+               break;
+       default:
+               a = frame_body[1];
+       }
+
+       if (category)
+               *category = c;
+       if (action)
+               *action = a;
+
+       return true;
+}
+
+static const char *_action_public_str23a[] = {
+       "ACT_PUB_BSSCOEXIST",
+       "ACT_PUB_DSE_ENABLE",
+       "ACT_PUB_DSE_DEENABLE",
+       "ACT_PUB_DSE_REG_LOCATION",
+       "ACT_PUB_EXT_CHL_SWITCH",
+       "ACT_PUB_DSE_MSR_REQ",
+       "ACT_PUB_DSE_MSR_RPRT",
+       "ACT_PUB_MP",
+       "ACT_PUB_DSE_PWR_CONSTRAINT",
+       "ACT_PUB_VENDOR",
+       "ACT_PUB_GAS_INITIAL_REQ",
+       "ACT_PUB_GAS_INITIAL_RSP",
+       "ACT_PUB_GAS_COMEBACK_REQ",
+       "ACT_PUB_GAS_COMEBACK_RSP",
+       "ACT_PUB_TDLS_DISCOVERY_RSP",
+       "ACT_PUB_LOCATION_TRACK",
+       "ACT_PUB_RSVD",
+};
+
+const char *action_public_str23a(u8 action)
+{
+       action = (action >= ACT_PUBLIC_MAX) ? ACT_PUBLIC_MAX : action;
+       return _action_public_str23a[action];
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_io.c b/drivers/staging/rtl8723au/core/rtw_io.c
new file mode 100644 (file)
index 0000000..1cae8d7
--- /dev/null
@@ -0,0 +1,266 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+/*
+
+The purpose of rtw_io.c
+
+a. provides the API
+
+b. provides the protocol engine
+
+c. provides the software interface between caller and the hardware interface
+
+Compiler Flag Option:
+
+1. For USB:
+   a. USE_ASYNC_IRP: Both sync/async operations are provided.
+
+Only sync read/rtw_write_mem operations are provided.
+
+jackson@realtek.com.tw
+
+*/
+
+#define _RTW_IO_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_io.h>
+#include <osdep_intf.h>
+
+#include <usb_ops.h>
+
+u8 _rtw_read823a(struct rtw_adapter *adapter, u32 addr)
+{
+       u8 r_val;
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+
+       r_val = pintfhdl->io_ops._read8(pintfhdl, addr);
+
+       return r_val;
+}
+
+u16 _rtw_read1623a(struct rtw_adapter *adapter, u32 addr)
+{
+       u16 r_val;
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+
+       r_val = pintfhdl->io_ops._read16(pintfhdl, addr);
+
+       return le16_to_cpu(r_val);
+}
+
+u32 _rtw_read3223a(struct rtw_adapter *adapter, u32 addr)
+{
+       u32 r_val;
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+
+       r_val = pintfhdl->io_ops._read32(pintfhdl, addr);
+
+       return le32_to_cpu(r_val);
+}
+
+int _rtw_write823a(struct rtw_adapter *adapter, u32 addr, u8 val)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl         *pintfhdl = &pio_priv->intf;
+       int ret;
+
+       ret = pintfhdl->io_ops._write8(pintfhdl, addr, val);
+
+       return RTW_STATUS_CODE23a(ret);
+}
+
+int _rtw_write1623a(struct rtw_adapter *adapter, u32 addr, u16 val)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl         *pintfhdl = &pio_priv->intf;
+       int ret;
+
+       val = cpu_to_le16(val);
+       ret = pintfhdl->io_ops._write16(pintfhdl, addr, val);
+
+       return RTW_STATUS_CODE23a(ret);
+}
+int _rtw_write3223a(struct rtw_adapter *adapter, u32 addr, u32 val)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+       int ret;
+
+       val = cpu_to_le32(val);
+       ret = pintfhdl->io_ops._write32(pintfhdl, addr, val);
+
+       return RTW_STATUS_CODE23a(ret);
+}
+
+int _rtw_writeN23a(struct rtw_adapter *adapter, u32 addr , u32 length , u8 *pdata)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+        struct intf_hdl *pintfhdl = (struct intf_hdl*)&pio_priv->intf;
+       int ret;
+
+       ret = pintfhdl->io_ops._writeN(pintfhdl, addr, length, pdata);
+
+       return RTW_STATUS_CODE23a(ret);
+}
+int _rtw_write823a_async23a(struct rtw_adapter *adapter, u32 addr, u8 val)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+       int ret;
+
+       ret = pintfhdl->io_ops._write8_async(pintfhdl, addr, val);
+
+       return RTW_STATUS_CODE23a(ret);
+}
+int _rtw_write1623a_async(struct rtw_adapter *adapter, u32 addr, u16 val)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+       int ret;
+
+       val = cpu_to_le16(val);
+       ret = pintfhdl->io_ops._write16_async(pintfhdl, addr, val);
+
+       return RTW_STATUS_CODE23a(ret);
+}
+int _rtw_write3223a_async23a(struct rtw_adapter *adapter, u32 addr, u32 val)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+       int ret;
+
+       val = cpu_to_le32(val);
+       ret = pintfhdl->io_ops._write32_async(pintfhdl, addr, val);
+
+       return RTW_STATUS_CODE23a(ret);
+}
+
+void _rtw_read_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+
+       if ((adapter->bDriverStopped == true) ||
+           (adapter->bSurpriseRemoved == true)) {
+            RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
+                     ("rtw_read_mem:bDriverStopped(%d) OR "
+                      "bSurpriseRemoved(%d)", adapter->bDriverStopped,
+                      adapter->bSurpriseRemoved));
+            return;
+       }
+
+       pintfhdl->io_ops._read_mem(pintfhdl, addr, cnt, pmem);
+}
+
+void _rtw_write_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+
+       pintfhdl->io_ops._write_mem(pintfhdl, addr, cnt, pmem);
+}
+
+void _rtw_read_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt,
+                   struct recv_buf *rbuf)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+
+       if ((adapter->bDriverStopped == true) ||
+           (adapter->bSurpriseRemoved == true)) {
+            RT_TRACE(_module_rtl871x_io_c_, _drv_info_,
+                     ("rtw_read_port:bDriverStopped(%d) OR "
+                      "bSurpriseRemoved(%d)", adapter->bDriverStopped,
+                      adapter->bSurpriseRemoved));
+            return;
+       }
+
+       pintfhdl->io_ops._read_port(pintfhdl, addr, cnt, rbuf);
+}
+
+void _rtw_read_port23a_cancel(struct rtw_adapter *adapter)
+{
+       void (*_read_port_cancel)(struct intf_hdl *pintfhdl);
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+
+       _read_port_cancel = pintfhdl->io_ops._read_port_cancel;
+
+       if (_read_port_cancel)
+               _read_port_cancel(pintfhdl);
+}
+
+u32 _rtw_write_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt,
+                   struct xmit_buf *xbuf)
+{
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+       u32 ret = _SUCCESS;
+
+       ret = pintfhdl->io_ops._write_port(pintfhdl, addr, cnt, xbuf);
+
+       return ret;
+}
+
+u32 _rtw_write_port23a_and_wait23a(struct rtw_adapter *adapter, u32 addr, u32 cnt,
+                            struct xmit_buf *pxmitbuf, int timeout_ms)
+{
+       int ret = _SUCCESS;
+       struct submit_ctx sctx;
+
+       rtw_sctx_init23a(&sctx, timeout_ms);
+       pxmitbuf->sctx = &sctx;
+
+       ret = _rtw_write_port23a(adapter, addr, cnt, pxmitbuf);
+
+       if (ret == _SUCCESS)
+               ret = rtw_sctx_wait23a(&sctx);
+
+       return ret;
+}
+
+void _rtw_write_port23a_cancel(struct rtw_adapter *adapter)
+{
+       void (*_write_port_cancel)(struct intf_hdl *pintfhdl);
+       struct io_priv *pio_priv = &adapter->iopriv;
+       struct intf_hdl *pintfhdl = &pio_priv->intf;
+
+       _write_port_cancel = pintfhdl->io_ops._write_port_cancel;
+
+       if (_write_port_cancel)
+               _write_port_cancel(pintfhdl);
+}
+
+int rtw_init_io_priv23a(struct rtw_adapter *padapter,
+                    void (*set_intf_ops)(struct _io_ops *pops))
+{
+       struct io_priv  *piopriv = &padapter->iopriv;
+       struct intf_hdl *pintf = &piopriv->intf;
+
+       if (set_intf_ops == NULL)
+               return _FAIL;
+
+       piopriv->padapter = padapter;
+       pintf->padapter = padapter;
+       pintf->pintf_dev = adapter_to_dvobj(padapter);
+
+       set_intf_ops(&pintf->io_ops);
+
+       return _SUCCESS;
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_ioctl_set.c b/drivers/staging/rtl8723au/core/rtw_ioctl_set.c
new file mode 100644 (file)
index 0000000..30d7185
--- /dev/null
@@ -0,0 +1,601 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_IOCTL_SET_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_ioctl_set.h>
+#include <hal_intf.h>
+
+#include <usb_osintf.h>
+#include <usb_ops.h>
+#include <linux/ieee80211.h>
+
+u8 rtw_do_join23a(struct rtw_adapter *padapter)
+{
+       struct list_head *plist, *phead;
+       u8* pibss = NULL;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct rtw_queue *queue = &pmlmepriv->scanned_queue;
+       u8 ret = _SUCCESS;
+
+       spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+       phead = get_list_head(queue);
+       plist = phead->next;
+
+       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                ("\n rtw_do_join23a: phead = %p; plist = %p\n\n\n",
+                 phead, plist));
+
+       pmlmepriv->cur_network.join_res = -2;
+
+       set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+
+       pmlmepriv->to_join = true;
+
+       if (_rtw_queue_empty23a(queue) == true) {
+               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+               _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+               /* when set_ssid/set_bssid for rtw_do_join23a(), but
+                  scanning queue is empty */
+               /* we try to issue sitesurvey firstly */
+
+               if (pmlmepriv->LinkDetectInfo.bBusyTraffic == false ||
+                   rtw_to_roaming(padapter) > 0) {
+                       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                                ("rtw_do_join23a(): site survey if scanned_queue "
+                                 "is empty\n."));
+                       /*  submit site_survey23a_cmd */
+                       ret = rtw_sitesurvey_cmd23a(padapter,
+                                                &pmlmepriv->assoc_ssid, 1,
+                                                NULL, 0);
+                       if (ret != _SUCCESS) {
+                               pmlmepriv->to_join = false;
+                               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+                                        ("rtw_do_join23a(): site survey return "
+                                         "error\n."));
+                       }
+               } else {
+                       pmlmepriv->to_join = false;
+                       ret = _FAIL;
+               }
+
+               goto exit;
+       } else {
+               int select_ret;
+               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+               select_ret = rtw_select_and_join_from_scanned_queue23a(pmlmepriv);
+               if (select_ret == _SUCCESS) {
+                       pmlmepriv->to_join = false;
+                       mod_timer(&pmlmepriv->assoc_timer,
+                                 jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT));
+               } else {
+                       if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) {
+                               struct wlan_bssid_ex *pdev_network;
+                               /*  submit createbss_cmd to change to a
+                                   ADHOC_MASTER */
+
+                               /* pmlmepriv->lock has been acquired by
+                                  caller... */
+                               pdev_network =
+                                       &padapter->registrypriv.dev_network;
+
+                               pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
+
+                               pibss = padapter->registrypriv.dev_network.MacAddress;
+
+                               memcpy(&pdev_network->Ssid,
+                                      &pmlmepriv->assoc_ssid,
+                                      sizeof(struct cfg80211_ssid));
+
+                               rtw_update_registrypriv_dev_network23a(padapter);
+
+                               rtw_generate_random_ibss23a(pibss);
+
+                               if (rtw_createbss_cmd23a(padapter) != _SUCCESS) {
+                                       RT_TRACE(_module_rtl871x_ioctl_set_c_,
+                                                _drv_err_,
+                                                ("***Error =>do_goin: rtw_creat"
+                                                 "ebss_cmd status FAIL***\n"));
+                                       ret =  false;
+                                       goto exit;
+                               }
+
+                               pmlmepriv->to_join = false;
+
+                               RT_TRACE(_module_rtl871x_ioctl_set_c_,
+                                        _drv_info_,
+                                        ("***Error => rtw_select_and_join_from"
+                                         "_scanned_queue FAIL under STA_Mode"
+                                         "***\n "));
+                       } else {
+                               /*  can't associate ; reset under-linking */
+                               _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+
+                               /* when set_ssid/set_bssid for rtw_do_join23a(),
+                                  but there are no desired bss in scanning
+                                  queue */
+                               /* we try to issue sitesurvey firstly */
+                               if (pmlmepriv->LinkDetectInfo.bBusyTraffic ==
+                                   false || rtw_to_roaming(padapter) > 0) {
+                                       /* DBG_8723A("rtw_do_join23a() when   no "
+                                          "desired bss in scanning queue\n");
+                                       */
+                                       ret = rtw_sitesurvey_cmd23a(padapter, &pmlmepriv->assoc_ssid, 1, NULL, 0);
+                                       if (ret != _SUCCESS) {
+                                               pmlmepriv->to_join = false;
+                                               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("do_join(): site survey return error\n."));
+                                       }
+                               } else {
+                                       ret = _FAIL;
+                                       pmlmepriv->to_join = false;
+                               }
+                       }
+               }
+       }
+
+exit:
+
+       return ret;
+}
+
+u8 rtw_set_802_11_ssid23a(struct rtw_adapter* padapter, struct cfg80211_ssid *ssid)
+{
+       u8 status = _SUCCESS;
+       u32 cur_time = 0;
+
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_network *pnetwork = &pmlmepriv->cur_network;
+
+
+
+       DBG_8723A_LEVEL(_drv_always_, "set ssid [%s] fw_state = 0x%08x\n",
+                       ssid->ssid, get_fwstate(pmlmepriv));
+
+       if (padapter->hw_init_completed == false) {
+               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+                        ("set_ssid: hw_init_completed == false =>exit!!!\n"));
+               status = _FAIL;
+               goto exit;
+       }
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       DBG_8723A("Set SSID under fw_state = 0x%08x\n", get_fwstate(pmlmepriv));
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
+               goto handle_tkip_countermeasure;
+       } else if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true) {
+               goto release_mlme_lock;
+       }
+
+       if (check_fwstate(pmlmepriv, _FW_LINKED|WIFI_ADHOC_MASTER_STATE) == true)
+       {
+               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                        ("set_ssid: _FW_LINKED||WIFI_ADHOC_MASTER_STATE\n"));
+
+               if ((pmlmepriv->assoc_ssid.ssid_len == ssid->ssid_len) &&
+                   !memcmp(&pmlmepriv->assoc_ssid.ssid, ssid->ssid,
+                           ssid->ssid_len)) {
+                       if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == false))
+                       {
+                               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+                                        ("Set SSID is the same ssid, fw_state = 0x%08x\n",
+                                         get_fwstate(pmlmepriv)));
+
+                               if (rtw_is_same_ibss23a(padapter, pnetwork) == false)
+                               {
+                                       /* if in WIFI_ADHOC_MASTER_STATE | WIFI_ADHOC_STATE, create bss or rejoin again */
+                                       rtw_disassoc_cmd23a(padapter, 0, true);
+
+                                       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+                                               rtw_indicate_disconnect23a(padapter);
+
+                                       rtw_free_assoc_resources23a(padapter, 1);
+
+                                       if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
+                                               _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+                                               set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+                                       }
+                               } else {
+                                       goto release_mlme_lock;/* it means driver is in WIFI_ADHOC_MASTER_STATE, we needn't create bss again. */
+                               }
+                       } else {
+                               rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_JOINBSS, 1);
+                       }
+               } else {
+                       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                                ("Set SSID not the same ssid\n"));
+                       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                                ("set_ssid =[%s] len = 0x%x\n", ssid->ssid,
+                                 (unsigned int)ssid->ssid_len));
+                       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                                ("assoc_ssid =[%s] len = 0x%x\n",
+                                 pmlmepriv->assoc_ssid.ssid,
+                                 (unsigned int)pmlmepriv->assoc_ssid.ssid_len));
+
+                       rtw_disassoc_cmd23a(padapter, 0, true);
+
+                       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+                               rtw_indicate_disconnect23a(padapter);
+
+                       rtw_free_assoc_resources23a(padapter, 1);
+
+                       if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) {
+                               _clr_fwstate_(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+                               set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+                       }
+               }
+       }
+
+handle_tkip_countermeasure:
+
+       if (padapter->securitypriv.btkip_countermeasure == true) {
+               cur_time = jiffies;
+
+               if ((cur_time - padapter->securitypriv.btkip_countermeasure_time) > 60 * HZ)
+               {
+                       padapter->securitypriv.btkip_countermeasure = false;
+                       padapter->securitypriv.btkip_countermeasure_time = 0;
+               }
+               else
+               {
+                       status = _FAIL;
+                       goto release_mlme_lock;
+               }
+       }
+
+       memcpy(&pmlmepriv->assoc_ssid, ssid, sizeof(struct cfg80211_ssid));
+       pmlmepriv->assoc_by_bssid = false;
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) {
+               pmlmepriv->to_join = true;
+       }
+       else {
+               status = rtw_do_join23a(padapter);
+       }
+
+release_mlme_lock:
+       spin_unlock_bh(&pmlmepriv->lock);
+
+exit:
+       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+               ("-rtw_set_802_11_ssid23a: status =%d\n", status));
+
+
+
+       return status;
+}
+
+u8 rtw_set_802_11_infrastructure_mode23a(struct rtw_adapter* padapter,
+       enum ndis_802_11_net_infra networktype)
+{
+       struct  mlme_priv       *pmlmepriv = &padapter->mlmepriv;
+       struct  wlan_network    *cur_network = &pmlmepriv->cur_network;
+       enum ndis_802_11_net_infra* pold_state = &cur_network->network.InfrastructureMode;
+
+
+
+       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_notice_,
+                ("+rtw_set_802_11_infrastructure_mode23a: old =%d new =%d fw_state = 0x%08x\n",
+                 *pold_state, networktype, get_fwstate(pmlmepriv)));
+
+       if (*pold_state != networktype)
+       {
+               spin_lock_bh(&pmlmepriv->lock);
+
+               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_, (" change mode!"));
+               /* DBG_8723A("change mode, old_mode =%d, new_mode =%d, fw_state = 0x%x\n", *pold_state, networktype, get_fwstate(pmlmepriv)); */
+
+               if (*pold_state == Ndis802_11APMode)
+               {
+                       /* change to other mode from Ndis802_11APMode */
+                       cur_network->join_res = -1;
+
+#ifdef CONFIG_8723AU_AP_MODE
+                       stop_ap_mode23a(padapter);
+#endif
+               }
+
+               if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ||(*pold_state == Ndis802_11IBSS))
+                       rtw_disassoc_cmd23a(padapter, 0, true);
+
+               if ((check_fwstate(pmlmepriv, _FW_LINKED) == true) ||
+                       (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true))
+                       rtw_free_assoc_resources23a(padapter, 1);
+
+               if ((*pold_state == Ndis802_11Infrastructure) ||(*pold_state == Ndis802_11IBSS))
+              {
+                       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+                       {
+                               rtw_indicate_disconnect23a(padapter); /* will clr Linked_state; before this function, we must have chked whether  issue dis-assoc_cmd or not */
+                       }
+              }
+
+               *pold_state = networktype;
+
+               _clr_fwstate_(pmlmepriv, ~WIFI_NULL_STATE);
+
+               switch (networktype)
+               {
+                       case Ndis802_11IBSS:
+                               set_fwstate(pmlmepriv, WIFI_ADHOC_STATE);
+                               break;
+
+                       case Ndis802_11Infrastructure:
+                               set_fwstate(pmlmepriv, WIFI_STATION_STATE);
+                               break;
+
+                       case Ndis802_11APMode:
+                               set_fwstate(pmlmepriv, WIFI_AP_STATE);
+#ifdef CONFIG_8723AU_AP_MODE
+                               start_ap_mode23a(padapter);
+                               /* rtw_indicate_connect23a(padapter); */
+#endif
+
+                               break;
+
+                       case Ndis802_11AutoUnknown:
+                       case Ndis802_11InfrastructureMax:
+                               break;
+               }
+
+               /* SecClearAllKeys(adapter); */
+
+               /* RT_TRACE(COMP_OID_SET, DBG_LOUD, ("set_infrastructure: fw_state:%x after changing mode\n", */
+               /*                                                                      get_fwstate(pmlmepriv))); */
+
+               spin_unlock_bh(&pmlmepriv->lock);
+       }
+
+
+
+       return true;
+}
+
+u8 rtw_set_802_11_bssid23a_list_scan(struct rtw_adapter *padapter,
+                                 struct cfg80211_ssid *pssid, int ssid_max_num)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       u8 res = true;
+
+       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+                ("+rtw_set_802_11_bssid23a_list_scan(), fw_state =%x\n",
+                 get_fwstate(pmlmepriv)));
+
+       if (!padapter) {
+               res = false;
+               goto exit;
+       }
+       if (padapter->hw_init_completed == false) {
+               res = false;
+               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+                        ("\n === rtw_set_802_11_bssid23a_list_scan:"
+                         "hw_init_completed == false ===\n"));
+               goto exit;
+       }
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ||
+           (pmlmepriv->LinkDetectInfo.bBusyTraffic == true)) {
+               /*  Scan or linking is in progress, do nothing. */
+               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+                        ("rtw_set_802_11_bssid23a_list_scan fail since fw_state "
+                         "= %x\n", get_fwstate(pmlmepriv)));
+               res = true;
+
+               if (check_fwstate(pmlmepriv,
+                                 (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) {
+                       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+                                ("\n###_FW_UNDER_SURVEY|_FW_UNDER_LINKING\n"));
+               } else {
+                       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+                                ("\n###pmlmepriv->sitesurveyctrl.traffic_"
+                                 "busy == true\n"));
+               }
+       } else {
+               if (rtw_is_scan_deny(padapter)) {
+                       DBG_8723A(FUNC_ADPT_FMT": scan deny\n",
+                                 FUNC_ADPT_ARG(padapter));
+                       return _SUCCESS;
+               }
+
+               spin_lock_bh(&pmlmepriv->lock);
+
+               res = rtw_sitesurvey_cmd23a(padapter, pssid, ssid_max_num,
+                                        NULL, 0);
+
+               spin_unlock_bh(&pmlmepriv->lock);
+       }
+exit:
+       return res;
+}
+
+u8 rtw_set_802_11_authentication_mode23a(struct rtw_adapter* padapter,
+                                     enum ndis_802_11_auth_mode authmode)
+{
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       int res;
+       u8 ret;
+
+       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                ("set_802_11_auth.mode(): mode =%x\n", authmode));
+
+       psecuritypriv->ndisauthtype = authmode;
+
+       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                ("rtw_set_802_11_authentication_mode23a:"
+                 "psecuritypriv->ndisauthtype =%d",
+                 psecuritypriv->ndisauthtype));
+
+       if (psecuritypriv->ndisauthtype > 3)
+               psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+
+       res = rtw_set_auth23a(padapter, psecuritypriv);
+
+       if (res == _SUCCESS)
+               ret = true;
+       else
+               ret = false;
+
+       return ret;
+}
+
+u8 rtw_set_802_11_add_wep23a(struct rtw_adapter* padapter,
+                         struct ndis_802_11_wep *wep)
+{
+       u8 bdefaultkey;
+       u8 btransmitkey;
+       int keyid, res;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       u8 ret = _SUCCESS;
+
+       bdefaultkey = (wep->KeyIndex & 0x40000000) > 0 ? false : true;
+       btransmitkey = (wep->KeyIndex & 0x80000000) > 0 ? true  : false;
+       keyid = wep->KeyIndex & 0x3fffffff;
+
+       if (keyid >= 4) {
+               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_,
+                        ("MgntActrtw_set_802_11_add_wep23a:keyid>4 =>fail\n"));
+               ret = false;
+               goto exit;
+       }
+
+       switch (wep->KeyLength)
+       {
+       case 5:
+               psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                        ("MgntActrtw_set_802_11_add_wep23a:wep->KeyLength = 5\n"));
+               break;
+       case 13:
+               psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                        ("MgntActrtw_set_802_11_add_wep23a:wep->KeyLength = 13\n"));
+               break;
+       default:
+               psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                        ("MgntActrtw_set_802_11_add_wep23a:wep->KeyLength!= 5 "
+                         "or 13\n"));
+                       break;
+       }
+
+       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                ("rtw_set_802_11_add_wep23a:befor memcpy, wep->KeyLength = 0x%x "
+                 "wep->KeyIndex = 0x%x  keyid =%x\n",
+                 wep->KeyLength, wep->KeyIndex, keyid));
+
+       memcpy(&psecuritypriv->dot11DefKey[keyid].skey[0],
+              &wep->KeyMaterial, wep->KeyLength);
+
+       psecuritypriv->dot11DefKeylen[keyid] = wep->KeyLength;
+
+       psecuritypriv->dot11PrivacyKeyIndex = keyid;
+
+       RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_info_,
+                ("rtw_set_802_11_add_wep23a:security key material : %x %x %x %x "
+                 "%x %x %x %x %x %x %x %x %x\n",
+                 psecuritypriv->dot11DefKey[keyid].skey[0],
+                 psecuritypriv->dot11DefKey[keyid].skey[1],
+                 psecuritypriv->dot11DefKey[keyid].skey[2],
+                 psecuritypriv->dot11DefKey[keyid].skey[3],
+                 psecuritypriv->dot11DefKey[keyid].skey[4],
+                 psecuritypriv->dot11DefKey[keyid].skey[5],
+                 psecuritypriv->dot11DefKey[keyid].skey[6],
+                 psecuritypriv->dot11DefKey[keyid].skey[7],
+                 psecuritypriv->dot11DefKey[keyid].skey[8],
+                 psecuritypriv->dot11DefKey[keyid].skey[9],
+                 psecuritypriv->dot11DefKey[keyid].skey[10],
+                 psecuritypriv->dot11DefKey[keyid].skey[11],
+                 psecuritypriv->dot11DefKey[keyid].skey[12]));
+
+       res = rtw_set_key23a(padapter, psecuritypriv, keyid, 1);
+
+       if (res == _FAIL)
+               ret = false;
+exit:
+
+       return ret;
+}
+
+/*
+* rtw_get_cur_max_rate23a -
+* @adapter: pointer to _adapter structure
+*
+* Return 0 or 100Kbps
+*/
+u16 rtw_get_cur_max_rate23a(struct rtw_adapter *adapter)
+{
+       int i = 0;
+       u8 *p;
+       u16 rate = 0, max_rate = 0;
+       struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct registry_priv *pregistrypriv = &adapter->registrypriv;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct wlan_bssid_ex  *pcur_bss = &pmlmepriv->cur_network.network;
+       struct ieee80211_ht_cap *pht_capie;
+       u8 rf_type = 0;
+       u8 bw_40MHz = 0, short_GI_20 = 0, short_GI_40 = 0;
+       u16 mcs_rate = 0;
+       u32 ht_ielen = 0;
+
+       if (!check_fwstate(pmlmepriv, _FW_LINKED) &&
+           !check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE))
+               return 0;
+
+       if (pmlmeext->cur_wireless_mode & (WIRELESS_11_24N|WIRELESS_11_5N)) {
+               p = rtw_get_ie23a(&pcur_bss->IEs[12], _HT_CAPABILITY_IE_,
+                              &ht_ielen, pcur_bss->IELength - 12);
+               if (p && ht_ielen > 0) {
+                       pht_capie = (struct ieee80211_ht_cap *)(p + 2);
+
+                       memcpy(&mcs_rate, &pht_capie->mcs, 2);
+
+                       /* bw_40MHz = (pht_capie->cap_info&
+                          IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1:0; */
+                       /* cur_bwmod is updated by beacon, pmlmeinfo is
+                          updated by association response */
+                       bw_40MHz = (pmlmeext->cur_bwmode &&
+                                   (HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH &
+                                    pmlmeinfo->HT_info.infos[0])) ? 1:0;
+
+                       /* short_GI = (pht_capie->cap_info & (IEEE80211_HT_CAP
+                          _SGI_20|IEEE80211_HT_CAP_SGI_40)) ? 1 : 0; */
+                       short_GI_20 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_20) ? 1:0;
+                       short_GI_40 = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info&IEEE80211_HT_CAP_SGI_40) ? 1:0;
+
+                       rtw23a_hal_get_hwreg(adapter, HW_VAR_RF_TYPE,
+                                         (u8 *)(&rf_type));
+                       max_rate = rtw_mcs_rate23a(rf_type, bw_40MHz &
+                                               pregistrypriv->cbw40_enable,
+                                               short_GI_20, short_GI_40,
+                                               pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate
+                       );
+               }
+       } else {
+               while ((pcur_bss->SupportedRates[i] != 0) &&
+                      (pcur_bss->SupportedRates[i] != 0xFF)) {
+                       rate = pcur_bss->SupportedRates[i] & 0x7F;
+                       if (rate>max_rate)
+                               max_rate = rate;
+                       i++;
+               }
+
+               max_rate = max_rate * 10 / 2;
+       }
+
+       return max_rate;
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_led.c b/drivers/staging/rtl8723au/core/rtw_led.c
new file mode 100644 (file)
index 0000000..68532a3
--- /dev/null
@@ -0,0 +1,1899 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 <drv_types.h>
+#include <rtl8723a_led.h>
+
+/*  */
+/*     Description: */
+/*             Callback function of LED BlinkTimer, */
+/*             it just schedules to corresponding BlinkWorkItem/led_blink_hdl23a */
+/*  */
+static void BlinkTimerCallback(unsigned long data)
+{
+       struct led_8723a *pLed = (struct led_8723a *)data;
+       struct rtw_adapter *padapter = pLed->padapter;
+
+       /* DBG_8723A("%s\n", __func__); */
+
+       if ((padapter->bSurpriseRemoved == true) || (padapter->bDriverStopped == true))
+       {
+               /* DBG_8723A("%s bSurpriseRemoved:%d, bDriverStopped:%d\n", __func__, padapter->bSurpriseRemoved, padapter->bDriverStopped); */
+               return;
+       }
+       schedule_work(&pLed->BlinkWorkItem);
+}
+
+/*  */
+/*     Description: */
+/*             Callback function of LED BlinkWorkItem. */
+/*             We dispatch acture LED blink action according to LedStrategy. */
+/*  */
+void BlinkWorkItemCallback23a(struct work_struct *work)
+{
+       struct led_8723a *pLed = container_of(work, struct led_8723a, BlinkWorkItem);
+       BlinkHandler23a(pLed);
+}
+
+/*  */
+/*     Description: */
+/*             Reset status of led_8723a object. */
+/*  */
+void ResetLedStatus23a(struct led_8723a * pLed) {
+
+       pLed->CurrLedState = RTW_LED_OFF; /*  Current LED state. */
+       pLed->bLedOn = false; /*  true if LED is ON, false if LED is OFF. */
+
+       pLed->bLedBlinkInProgress = false; /*  true if it is blinking, false o.w.. */
+       pLed->bLedWPSBlinkInProgress = false;
+
+       pLed->BlinkTimes = 0; /*  Number of times to toggle led state for blinking. */
+       pLed->BlinkingLedState = LED_UNKNOWN; /*  Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */
+
+       pLed->bLedNoLinkBlinkInProgress = false;
+       pLed->bLedLinkBlinkInProgress = false;
+       pLed->bLedStartToLinkBlinkInProgress = false;
+       pLed->bLedScanBlinkInProgress = false;
+}
+
+ /*  */
+/*     Description: */
+/*             Initialize an led_8723a object. */
+/*  */
+void
+InitLed871x23a(struct rtw_adapter *padapter, struct led_8723a *pLed, enum led_pin_8723a LedPin)
+{
+       pLed->padapter = padapter;
+       pLed->LedPin = LedPin;
+
+       ResetLedStatus23a(pLed);
+
+       setup_timer(&pLed->BlinkTimer, BlinkTimerCallback, (unsigned long)pLed);
+
+       INIT_WORK(&pLed->BlinkWorkItem, BlinkWorkItemCallback23a);
+}
+
+/*  */
+/*     Description: */
+/*             DeInitialize an led_8723a object. */
+/*  */
+void
+DeInitLed871x23a(struct led_8723a *pLed)
+{
+       cancel_work_sync(&pLed->BlinkWorkItem);
+       del_timer_sync(&pLed->BlinkTimer);
+       ResetLedStatus23a(pLed);
+}
+
+/*     Description: */
+/*             Implementation of LED blinking behavior. */
+/*             It toggle off LED and schedule corresponding timer if necessary. */
+
+static void SwLedBlink(struct led_8723a *pLed)
+{
+       struct rtw_adapter *padapter = pLed->padapter;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       u8 bStopBlinking = false;
+
+       /*  Change LED according to BlinkingLedState specified. */
+       if (pLed->BlinkingLedState == RTW_LED_ON) {
+               SwLedOn23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+       } else {
+               SwLedOff23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+       }
+
+       /*  Determine if we shall change LED state again. */
+       pLed->BlinkTimes--;
+       switch (pLed->CurrLedState) {
+
+       case LED_BLINK_NORMAL:
+               if (pLed->BlinkTimes == 0)
+                       bStopBlinking = true;
+               break;
+       case LED_BLINK_StartToBlink:
+               if (check_fwstate(pmlmepriv, _FW_LINKED) &&
+                   check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+                       bStopBlinking = true;
+               if (check_fwstate(pmlmepriv, _FW_LINKED) &&
+                   (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
+                   check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)))
+                       bStopBlinking = true;
+               else if (pLed->BlinkTimes == 0)
+                       bStopBlinking = true;
+               break;
+       case LED_BLINK_WPS:
+               if (pLed->BlinkTimes == 0)
+                       bStopBlinking = true;
+               break;
+       default:
+               bStopBlinking = true;
+               break;
+       }
+
+       if (bStopBlinking) {
+               if ((check_fwstate(pmlmepriv, _FW_LINKED)) && !pLed->bLedOn)
+                       SwLedOn23a(padapter, pLed);
+               else if ((check_fwstate(pmlmepriv, _FW_LINKED)) &&  pLed->bLedOn)
+                       SwLedOff23a(padapter, pLed);
+
+               pLed->BlinkTimes = 0;
+               pLed->bLedBlinkInProgress = false;
+       } else {
+               /*  Assign LED state to toggle. */
+               if (pLed->BlinkingLedState == RTW_LED_ON)
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+               else
+                       pLed->BlinkingLedState = RTW_LED_ON;
+
+               /*  Schedule a timer to toggle LED state. */
+               switch (pLed->CurrLedState) {
+               case LED_BLINK_NORMAL:
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL));
+                       break;
+               case LED_BLINK_SLOWLY:
+               case LED_BLINK_StartToBlink:
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL));
+                       break;
+               case LED_BLINK_WPS:
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_LONG_INTERVAL));
+                       break;
+               default:
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL));
+                       break;
+               }
+       }
+}
+
+static void SwLedBlink1(struct led_8723a *pLed)
+{
+       struct rtw_adapter *padapter = pLed->padapter;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       unsigned long delay = 0;
+       u8 bStopBlinking = false;
+
+       /*  Change LED according to BlinkingLedState specified. */
+       if (pLed->BlinkingLedState == RTW_LED_ON) {
+               SwLedOn23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+                        ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+       } else {
+               SwLedOff23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+                        ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+       }
+
+       if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+               SwLedOff23a(padapter, pLed);
+               ResetLedStatus23a(pLed);
+               return;
+       }
+       switch (pLed->CurrLedState) {
+       case LED_BLINK_SLOWLY:
+               if (pLed->bLedOn)
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+               else
+                       pLed->BlinkingLedState = RTW_LED_ON;
+               delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA;
+               break;
+       case LED_BLINK_NORMAL:
+               if (pLed->bLedOn)
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+               else
+                       pLed->BlinkingLedState = RTW_LED_ON;
+               delay = LED_BLINK_LINK_INTERVAL_ALPHA;
+               break;
+       case LED_BLINK_SCAN:
+               pLed->BlinkTimes--;
+               if (pLed->BlinkTimes == 0)
+                       bStopBlinking = true;
+               if (bStopBlinking) {
+                       if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+                               pLed->bLedLinkBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_NORMAL;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_LINK_INTERVAL_ALPHA;
+                               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+                       } else if (check_fwstate(pmlmepriv, _FW_LINKED) == false) {
+                               pLed->bLedNoLinkBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_SLOWLY;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA;
+                               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+                       }
+                       pLed->bLedScanBlinkInProgress = false;
+               } else {
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       delay = LED_BLINK_SCAN_INTERVAL_ALPHA;
+               }
+               break;
+       case LED_BLINK_TXRX:
+               pLed->BlinkTimes--;
+               if (pLed->BlinkTimes == 0)
+                       bStopBlinking = true;
+               if (bStopBlinking) {
+                       if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+                               pLed->bLedLinkBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_NORMAL;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_LINK_INTERVAL_ALPHA;
+                               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+                       } else if (check_fwstate(pmlmepriv,
+                                                _FW_LINKED) == false) {
+                               pLed->bLedNoLinkBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_SLOWLY;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA;
+                               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+                       }
+                       pLed->BlinkTimes = 0;
+                       pLed->bLedBlinkInProgress = false;
+               } else {
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       delay = LED_BLINK_FASTER_INTERVAL_ALPHA;
+               }
+               break;
+       case LED_BLINK_WPS:
+               if (pLed->bLedOn)
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+               else
+                       pLed->BlinkingLedState = RTW_LED_ON;
+               delay = LED_BLINK_SCAN_INTERVAL_ALPHA;
+               break;
+       case LED_BLINK_WPS_STOP:        /* WPS success */
+               if (pLed->BlinkingLedState == RTW_LED_ON)
+                       bStopBlinking = false;
+               else
+                       bStopBlinking = true;
+               if (bStopBlinking) {
+                       pLed->bLedLinkBlinkInProgress = true;
+                       pLed->CurrLedState = LED_BLINK_NORMAL;
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       delay = LED_BLINK_LINK_INTERVAL_ALPHA;
+                       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+
+                       pLed->bLedWPSBlinkInProgress = false;
+               } else {
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+                       delay = LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA;
+               }
+               break;
+       default:
+               break;
+       }
+       if (delay)
+               mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay));
+}
+
+static void SwLedBlink2(struct led_8723a *pLed)
+{
+       struct rtw_adapter *padapter = pLed->padapter;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       u8 bStopBlinking = false;
+
+       /*  Change LED according to BlinkingLedState specified. */
+       if (pLed->BlinkingLedState == RTW_LED_ON) {
+               SwLedOn23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+                        ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+       } else {
+               SwLedOff23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+                        ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+       }
+       switch (pLed->CurrLedState) {
+       case LED_BLINK_SCAN:
+               pLed->BlinkTimes--;
+               if (pLed->BlinkTimes == 0)
+                       bStopBlinking = true;
+               if (bStopBlinking) {
+                       if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+                               SwLedOff23a(padapter, pLed);
+                       } else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+                               pLed->CurrLedState = RTW_LED_ON;
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                               SwLedOn23a(padapter, pLed);
+                               RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+                                        ("stop scan blink CurrLedState %d\n",
+                                        pLed->CurrLedState));
+                       } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+                               pLed->CurrLedState = RTW_LED_OFF;
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                               SwLedOff23a(padapter, pLed);
+                               RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+                                        ("stop scan blink CurrLedState %d\n",
+                                        pLed->CurrLedState));
+                       }
+                       pLed->bLedScanBlinkInProgress = false;
+               } else {
+                       if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+                               SwLedOff23a(padapter, pLed);
+                       } else {
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               mod_timer(&pLed->BlinkTimer,
+                                         jiffies + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
+                       }
+               }
+               break;
+       case LED_BLINK_TXRX:
+               pLed->BlinkTimes--;
+               if (pLed->BlinkTimes == 0)
+                       bStopBlinking = true;
+               if (bStopBlinking) {
+                       if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+                               SwLedOff23a(padapter, pLed);
+                       } else if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+                               pLed->CurrLedState = RTW_LED_ON;
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                               SwLedOn23a(padapter, pLed);
+                               RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+                                        ("stop CurrLedState %d\n", pLed->CurrLedState));
+
+                       } else if (!check_fwstate(pmlmepriv, _FW_LINKED)) {
+                               pLed->CurrLedState = RTW_LED_OFF;
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                               SwLedOff23a(padapter, pLed);
+                               RT_TRACE(_module_rtl8712_led_c_, _drv_info_,
+                                        ("stop CurrLedState %d\n", pLed->CurrLedState));
+                       }
+                       pLed->bLedBlinkInProgress = false;
+               } else {
+                       if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+                               SwLedOff23a(padapter, pLed);
+                       } else {
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               mod_timer(&pLed->BlinkTimer,
+                                         jiffies + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
+                       }
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void SwLedBlink3(struct led_8723a *pLed)
+{
+       struct rtw_adapter *padapter = pLed->padapter;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       u8 bStopBlinking = false;
+
+       /*  Change LED according to BlinkingLedState specified. */
+       if (pLed->BlinkingLedState == RTW_LED_ON)
+       {
+               SwLedOn23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+       }
+       else
+       {
+               if (pLed->CurrLedState != LED_BLINK_WPS_STOP)
+                       SwLedOff23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+       }
+
+       switch (pLed->CurrLedState)
+       {
+               case LED_BLINK_SCAN:
+                       pLed->BlinkTimes--;
+                       if (pLed->BlinkTimes == 0)
+                       {
+                               bStopBlinking = true;
+                       }
+
+                       if (bStopBlinking)
+                       {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on)
+                               {
+                                       SwLedOff23a(padapter, pLed);
+                               }
+                               else if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+                               {
+                                       pLed->CurrLedState = RTW_LED_ON;
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                                       if (!pLed->bLedOn)
+                                               SwLedOn23a(padapter, pLed);
+
+                                       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+                               }
+                               else if (check_fwstate(pmlmepriv, _FW_LINKED) == false)
+                               {
+                                       pLed->CurrLedState = RTW_LED_OFF;
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                                       if (pLed->bLedOn)
+                                               SwLedOff23a(padapter, pLed);
+
+                                       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+                               }
+                               pLed->bLedScanBlinkInProgress = false;
+                       }
+                       else
+                       {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on)
+                               {
+                                       SwLedOff23a(padapter, pLed);
+                               }
+                               else
+                               {
+                                       if (pLed->bLedOn)
+                                               pLed->BlinkingLedState = RTW_LED_OFF;
+                                       else
+                                               pLed->BlinkingLedState = RTW_LED_ON;
+                                       mod_timer(&pLed->BlinkTimer,
+                                                 jiffies + msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
+                               }
+                       }
+                       break;
+
+               case LED_BLINK_TXRX:
+                       pLed->BlinkTimes--;
+                       if (pLed->BlinkTimes == 0)
+                       {
+                               bStopBlinking = true;
+                       }
+                       if (bStopBlinking)
+                       {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on)
+                               {
+                                       SwLedOff23a(padapter, pLed);
+                               }
+                               else if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+                               {
+                                       pLed->CurrLedState = RTW_LED_ON;
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+
+                                       if (!pLed->bLedOn)
+                                               SwLedOn23a(padapter, pLed);
+
+                                       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+                               }
+                               else if (check_fwstate(pmlmepriv, _FW_LINKED) == false)
+                               {
+                                       pLed->CurrLedState = RTW_LED_OFF;
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+
+                                       if (pLed->bLedOn)
+                                               SwLedOff23a(padapter, pLed);
+
+                                       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+                               }
+                               pLed->bLedBlinkInProgress = false;
+                       }
+                       else
+                       {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on)
+                               {
+                                       SwLedOff23a(padapter, pLed);
+                               }
+                               else
+                               {
+                                       if (pLed->bLedOn)
+                                               pLed->BlinkingLedState = RTW_LED_OFF;
+                                       else
+                                               pLed->BlinkingLedState = RTW_LED_ON;
+                                       mod_timer(&pLed->BlinkTimer,
+                                                 jiffies + msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
+                               }
+                       }
+                       break;
+
+               case LED_BLINK_WPS:
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
+                       break;
+
+               case LED_BLINK_WPS_STOP:        /* WPS success */
+                       if (pLed->BlinkingLedState == RTW_LED_ON)
+                       {
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                               mod_timer(&pLed->BlinkTimer, jiffies +
+                                         msecs_to_jiffies(LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA));
+                               bStopBlinking = false;
+                       } else {
+                               bStopBlinking = true;
+                       }
+
+                       if (bStopBlinking)
+                       {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on)
+                               {
+                                       SwLedOff23a(padapter, pLed);
+                               }
+                               else
+                               {
+                                       pLed->CurrLedState = RTW_LED_ON;
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                                       SwLedOn23a(padapter, pLed);
+                                       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+                               }
+                               pLed->bLedWPSBlinkInProgress = false;
+                       }
+                       break;
+
+               default:
+                       break;
+       }
+}
+
+static void SwLedBlink4(struct led_8723a *pLed)
+{
+       struct rtw_adapter *padapter = pLed->padapter;
+       struct led_priv *ledpriv = &padapter->ledpriv;
+       struct led_8723a *pLed1 = &ledpriv->SwLed1;
+       u8 bStopBlinking = false;
+       unsigned long delay = 0;
+
+       /*  Change LED according to BlinkingLedState specified. */
+       if (pLed->BlinkingLedState == RTW_LED_ON)
+       {
+               SwLedOn23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+       } else {
+               SwLedOff23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+       }
+
+       if (!pLed1->bLedWPSBlinkInProgress && pLed1->BlinkingLedState == LED_UNKNOWN)
+       {
+               pLed1->BlinkingLedState = RTW_LED_OFF;
+               pLed1->CurrLedState = RTW_LED_OFF;
+               SwLedOff23a(padapter, pLed1);
+       }
+
+       switch (pLed->CurrLedState)
+       {
+               case LED_BLINK_SLOWLY:
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA;
+                       break;
+
+               case LED_BLINK_StartToBlink:
+                       if (pLed->bLedOn) {
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                               delay = LED_BLINK_SLOWLY_INTERVAL;
+                       } else {
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_NORMAL_INTERVAL;
+                       }
+                       break;
+
+               case LED_BLINK_SCAN:
+                       pLed->BlinkTimes--;
+                       if (pLed->BlinkTimes == 0) {
+                               bStopBlinking = false;
+                       }
+
+                       if (bStopBlinking) {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+                                       SwLedOff23a(padapter, pLed);
+                               } else {
+                                       pLed->bLedNoLinkBlinkInProgress = false;
+                                       pLed->CurrLedState = LED_BLINK_SLOWLY;
+                                       if (pLed->bLedOn)
+                                               pLed->BlinkingLedState = RTW_LED_OFF;
+                                       else
+                                               pLed->BlinkingLedState = RTW_LED_ON;
+                                       delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA;
+                               }
+                               pLed->bLedScanBlinkInProgress = false;
+                       } else {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+                                       SwLedOff23a(padapter, pLed);
+                               } else {
+                                       if (pLed->bLedOn)
+                                               pLed->BlinkingLedState = RTW_LED_OFF;
+                                       else
+                                               pLed->BlinkingLedState = RTW_LED_ON;
+                                       delay = LED_BLINK_SCAN_INTERVAL_ALPHA;
+                               }
+                       }
+                       break;
+
+               case LED_BLINK_TXRX:
+                       pLed->BlinkTimes--;
+                       if (pLed->BlinkTimes == 0) {
+                               bStopBlinking = true;
+                       }
+                       if (bStopBlinking) {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+                                       SwLedOff23a(padapter, pLed);
+                               } else {
+                                       pLed->bLedNoLinkBlinkInProgress = true;
+                                       pLed->CurrLedState = LED_BLINK_SLOWLY;
+                                       if (pLed->bLedOn)
+                                               pLed->BlinkingLedState = RTW_LED_OFF;
+                                       else
+                                               pLed->BlinkingLedState = RTW_LED_ON;
+                                       delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA;
+                               }
+                               pLed->bLedBlinkInProgress = false;
+                       } else {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+                                       SwLedOff23a(padapter, pLed);
+                               } else {
+                                       if (pLed->bLedOn)
+                                               pLed->BlinkingLedState = RTW_LED_OFF;
+                                       else
+                                               pLed->BlinkingLedState = RTW_LED_ON;
+                                       delay = LED_BLINK_FASTER_INTERVAL_ALPHA;
+                               }
+                       }
+                       break;
+
+               case LED_BLINK_WPS:
+                       if (pLed->bLedOn) {
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                               delay = LED_BLINK_SLOWLY_INTERVAL;
+                       } else {
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_NORMAL_INTERVAL;
+                       }
+                       break;
+
+               case LED_BLINK_WPS_STOP:        /* WPS authentication fail */
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+
+                       delay = LED_BLINK_NORMAL_INTERVAL;
+                       break;
+
+               case LED_BLINK_WPS_STOP_OVERLAP:        /* WPS session overlap */
+                       pLed->BlinkTimes--;
+                       if (pLed->BlinkTimes == 0) {
+                               if (pLed->bLedOn) {
+                                       pLed->BlinkTimes = 1;
+                               } else {
+                                       bStopBlinking = true;
+                               }
+                       }
+
+                       if (bStopBlinking) {
+                               pLed->BlinkTimes = 10;
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_LINK_INTERVAL_ALPHA;
+                       } else {
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+
+                               delay = LED_BLINK_NORMAL_INTERVAL;
+                       }
+                       break;
+
+               default:
+                       break;
+       }
+       if (delay)
+               mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay));
+
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink4 CurrLedState %d\n", pLed->CurrLedState));
+}
+
+static void SwLedBlink5(struct led_8723a *pLed)
+{
+       struct rtw_adapter *padapter = pLed->padapter;
+       u8 bStopBlinking = false;
+       unsigned long delay = 0;
+
+       /*  Change LED according to BlinkingLedState specified. */
+       if (pLed->BlinkingLedState == RTW_LED_ON) {
+               SwLedOn23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+       } else {
+               SwLedOff23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+       }
+
+       switch (pLed->CurrLedState)
+       {
+               case LED_BLINK_SCAN:
+                       pLed->BlinkTimes--;
+                       if (pLed->BlinkTimes == 0) {
+                               bStopBlinking = true;
+                       }
+
+                       if (bStopBlinking) {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+                                       pLed->CurrLedState = RTW_LED_OFF;
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                                       if (pLed->bLedOn)
+                                               SwLedOff23a(padapter, pLed);
+                               } else {
+                                       pLed->CurrLedState = RTW_LED_ON;
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                                       if (!pLed->bLedOn)
+                                               delay = LED_BLINK_FASTER_INTERVAL_ALPHA;
+                               }
+
+                               pLed->bLedScanBlinkInProgress = false;
+                       } else {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+                                       SwLedOff23a(padapter, pLed);
+                               } else {
+                                       if (pLed->bLedOn)
+                                               pLed->BlinkingLedState = RTW_LED_OFF;
+                                       else
+                                               pLed->BlinkingLedState = RTW_LED_ON;
+                                       delay = LED_BLINK_SCAN_INTERVAL_ALPHA;
+                               }
+                       }
+                       break;
+
+               case LED_BLINK_TXRX:
+                       pLed->BlinkTimes--;
+                       if (pLed->BlinkTimes == 0) {
+                               bStopBlinking = true;
+                       }
+
+                       if (bStopBlinking) {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+                                       pLed->CurrLedState = RTW_LED_OFF;
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                                       if (pLed->bLedOn)
+                                               SwLedOff23a(padapter, pLed);
+                               } else {
+                                       pLed->CurrLedState = RTW_LED_ON;
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                                       if (!pLed->bLedOn)
+                                               delay = LED_BLINK_FASTER_INTERVAL_ALPHA;
+                               }
+
+                               pLed->bLedBlinkInProgress = false;
+                       } else {
+                               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on && padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) {
+                                       SwLedOff23a(padapter, pLed);
+                               } else {
+                                       if (pLed->bLedOn)
+                                               pLed->BlinkingLedState = RTW_LED_OFF;
+                                       else
+                                               pLed->BlinkingLedState = RTW_LED_ON;
+                                       delay = LED_BLINK_FASTER_INTERVAL_ALPHA;
+                               }
+                       }
+                       break;
+
+               default:
+                       break;
+       }
+
+       if (delay)
+               mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay));
+
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("SwLedBlink5 CurrLedState %d\n", pLed->CurrLedState));
+}
+
+static void SwLedBlink6(struct led_8723a *pLed)
+{
+       struct rtw_adapter *padapter = pLed->padapter;
+
+       /*  Change LED according to BlinkingLedState specified. */
+       if (pLed->BlinkingLedState == RTW_LED_ON) {
+               SwLedOn23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn on\n", pLed->BlinkTimes));
+       } else {
+               SwLedOff23a(padapter, pLed);
+               RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Blinktimes (%d): turn off\n", pLed->BlinkTimes));
+       }
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("<==== blink6\n"));
+}
+
+/* ALPHA, added by chiyoko, 20090106 */
+static void
+SwLedControlMode1(struct rtw_adapter *padapter, enum led_ctl_mode LedAction)
+{
+       struct led_priv *ledpriv = &padapter->ledpriv;
+       struct led_8723a *pLed = &ledpriv->SwLed0;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       long delay = -1;
+
+       switch (LedAction)
+       {
+               case LED_CTL_POWER_ON:
+               case LED_CTL_START_TO_LINK:
+               case LED_CTL_NO_LINK:
+                       if (pLed->bLedNoLinkBlinkInProgress == false) {
+                               if (pLed->CurrLedState == LED_BLINK_SCAN ||
+                                   IS_LED_WPS_BLINKING(pLed)) {
+                                       return;
+                               }
+                               if (pLed->bLedLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedLinkBlinkInProgress = false;
+                               }
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+
+                               pLed->bLedNoLinkBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_SLOWLY;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA;
+                       }
+                       break;
+
+               case LED_CTL_LINK:
+                       if (pLed->bLedLinkBlinkInProgress == false) {
+                               if (pLed->CurrLedState == LED_BLINK_SCAN ||
+                                   IS_LED_WPS_BLINKING(pLed)) {
+                                       return;
+                               }
+                               if (pLed->bLedNoLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedNoLinkBlinkInProgress = false;
+                               }
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+                               pLed->bLedLinkBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_NORMAL;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_LINK_INTERVAL_ALPHA;
+                       }
+                       break;
+
+               case LED_CTL_SITE_SURVEY:
+                        if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) &&
+                            (check_fwstate(pmlmepriv, _FW_LINKED) == true))
+                               ;
+                        else if (pLed->bLedScanBlinkInProgress == false) {
+                               if (IS_LED_WPS_BLINKING(pLed))
+                                       return;
+
+                               if (pLed->bLedNoLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedNoLinkBlinkInProgress = false;
+                               }
+                               if (pLed->bLedLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedLinkBlinkInProgress = false;
+                               }
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+                               pLed->bLedScanBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_SCAN;
+                               pLed->BlinkTimes = 24;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_SCAN_INTERVAL_ALPHA;
+                        }
+                       break;
+
+               case LED_CTL_TX:
+               case LED_CTL_RX:
+                       if (pLed->bLedBlinkInProgress == false) {
+                               if (pLed->CurrLedState == LED_BLINK_SCAN ||
+                                   IS_LED_WPS_BLINKING(pLed)) {
+                                       return;
+                               }
+                               if (pLed->bLedNoLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedNoLinkBlinkInProgress = false;
+                               }
+                               if (pLed->bLedLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedLinkBlinkInProgress = false;
+                               }
+                               pLed->bLedBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_TXRX;
+                               pLed->BlinkTimes = 2;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_FASTER_INTERVAL_ALPHA;
+                       }
+                       break;
+
+               case LED_CTL_START_WPS: /* wait until xinpin finish */
+               case LED_CTL_START_WPS_BOTTON:
+                       if (pLed->bLedWPSBlinkInProgress == false) {
+                               if (pLed->bLedNoLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedNoLinkBlinkInProgress = false;
+                               }
+                               if (pLed->bLedLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedLinkBlinkInProgress = false;
+                               }
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+                               if (pLed->bLedScanBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedScanBlinkInProgress = false;
+                               }
+                               pLed->bLedWPSBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_WPS;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_SCAN_INTERVAL_ALPHA;
+                        }
+                       break;
+
+               case LED_CTL_STOP_WPS:
+                       if (pLed->bLedNoLinkBlinkInProgress == true) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedNoLinkBlinkInProgress = false;
+                       }
+                       if (pLed->bLedLinkBlinkInProgress == true) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedLinkBlinkInProgress = false;
+                       }
+                       if (pLed->bLedBlinkInProgress == true) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedBlinkInProgress = false;
+                       }
+                       if (pLed->bLedScanBlinkInProgress == true) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedScanBlinkInProgress = false;
+                       }
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                       } else {
+                               pLed->bLedWPSBlinkInProgress = true;
+                       }
+
+                       pLed->CurrLedState = LED_BLINK_WPS_STOP;
+                       if (pLed->bLedOn) {
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                               delay = LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA;
+                       } else {
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = 0;
+                       }
+                       break;
+
+               case LED_CTL_STOP_WPS_FAIL:
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedWPSBlinkInProgress = false;
+                       }
+
+                       pLed->bLedNoLinkBlinkInProgress = true;
+                       pLed->CurrLedState = LED_BLINK_SLOWLY;
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       delay = LED_BLINK_NO_LINK_INTERVAL_ALPHA;
+                       break;
+
+               case LED_CTL_POWER_OFF:
+                       pLed->CurrLedState = RTW_LED_OFF;
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+                       if (pLed->bLedNoLinkBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedNoLinkBlinkInProgress = false;
+                       }
+                       if (pLed->bLedLinkBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedLinkBlinkInProgress = false;
+                       }
+                       if (pLed->bLedBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedBlinkInProgress = false;
+                       }
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedWPSBlinkInProgress = false;
+                       }
+                       if (pLed->bLedScanBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedScanBlinkInProgress = false;
+                       }
+
+                       SwLedOff23a(padapter, pLed);
+                       break;
+
+               default:
+                       break;
+
+       }
+
+       if (delay != -1)
+               mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay));
+
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+}
+
+ /* Arcadyan/Sitecom , added by chiyoko, 20090216 */
+static void
+SwLedControlMode2(struct rtw_adapter *padapter, enum led_ctl_mode LedAction)
+{
+       struct led_priv *ledpriv = &padapter->ledpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct led_8723a *pLed = &ledpriv->SwLed0;
+       long delay = -1;
+
+       switch (LedAction) {
+       case LED_CTL_SITE_SURVEY:
+                if (pmlmepriv->LinkDetectInfo.bBusyTraffic)
+                       ;
+                else if (pLed->bLedScanBlinkInProgress == false) {
+                       if (IS_LED_WPS_BLINKING(pLed))
+                               return;
+
+                       if (pLed->bLedBlinkInProgress == true) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedBlinkInProgress = false;
+                       }
+                       pLed->bLedScanBlinkInProgress = true;
+                       pLed->CurrLedState = LED_BLINK_SCAN;
+                       pLed->BlinkTimes = 24;
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       delay = LED_BLINK_SCAN_INTERVAL_ALPHA;
+                }
+                break;
+       case LED_CTL_TX:
+       case LED_CTL_RX:
+               if ((pLed->bLedBlinkInProgress == false) &&
+                   (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
+                       if (pLed->CurrLedState == LED_BLINK_SCAN ||
+                           IS_LED_WPS_BLINKING(pLed)) {
+                               return;
+                       }
+
+                       pLed->bLedBlinkInProgress = true;
+                       pLed->CurrLedState = LED_BLINK_TXRX;
+                       pLed->BlinkTimes = 2;
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       delay = LED_BLINK_FASTER_INTERVAL_ALPHA;
+               }
+               break;
+       case LED_CTL_LINK:
+               pLed->CurrLedState = RTW_LED_ON;
+               pLed->BlinkingLedState = RTW_LED_ON;
+               if (pLed->bLedBlinkInProgress) {
+                       del_timer_sync(&pLed->BlinkTimer);
+                       pLed->bLedBlinkInProgress = false;
+               }
+               if (pLed->bLedScanBlinkInProgress) {
+                       del_timer_sync(&pLed->BlinkTimer);
+                       pLed->bLedScanBlinkInProgress = false;
+               }
+
+               delay = 0;
+               break;
+       case LED_CTL_START_WPS: /* wait until xinpin finish */
+       case LED_CTL_START_WPS_BOTTON:
+               if (pLed->bLedWPSBlinkInProgress == false) {
+                       if (pLed->bLedBlinkInProgress == true) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedBlinkInProgress = false;
+                       }
+                       if (pLed->bLedScanBlinkInProgress == true) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedScanBlinkInProgress = false;
+                       }
+                       pLed->bLedWPSBlinkInProgress = true;
+                       pLed->CurrLedState = RTW_LED_ON;
+                       pLed->BlinkingLedState = RTW_LED_ON;
+                       delay = 0;
+                }
+               break;
+       case LED_CTL_STOP_WPS:
+               pLed->bLedWPSBlinkInProgress = false;
+               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+                       SwLedOff23a(padapter, pLed);
+               } else {
+                       pLed->CurrLedState = RTW_LED_ON;
+                       pLed->BlinkingLedState = RTW_LED_ON;
+                       delay = 0;
+                       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+               }
+               break;
+       case LED_CTL_STOP_WPS_FAIL:
+               pLed->bLedWPSBlinkInProgress = false;
+               if (padapter->pwrctrlpriv.rf_pwrstate != rf_on) {
+                       SwLedOff23a(padapter, pLed);
+               } else {
+                       pLed->CurrLedState = RTW_LED_OFF;
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+                       delay = 0;
+                       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+               }
+               break;
+       case LED_CTL_START_TO_LINK:
+       case LED_CTL_NO_LINK:
+               if (!IS_LED_BLINKING(pLed))
+               {
+                       pLed->CurrLedState = RTW_LED_OFF;
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+                       delay = 0;
+               }
+               break;
+       case LED_CTL_POWER_OFF:
+               pLed->CurrLedState = RTW_LED_OFF;
+               pLed->BlinkingLedState = RTW_LED_OFF;
+               if (pLed->bLedBlinkInProgress) {
+                       del_timer_sync(&pLed->BlinkTimer);
+                       pLed->bLedBlinkInProgress = false;
+               }
+               if (pLed->bLedScanBlinkInProgress) {
+                       del_timer_sync(&pLed->BlinkTimer);
+                       pLed->bLedScanBlinkInProgress = false;
+               }
+               if (pLed->bLedWPSBlinkInProgress) {
+                       del_timer_sync(&pLed->BlinkTimer);
+                       pLed->bLedWPSBlinkInProgress = false;
+               }
+
+               delay = 0;
+               break;
+       default:
+               break;
+
+       }
+
+       if (delay != -1)
+               mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay));
+
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+}
+
+  /* COREGA, added by chiyoko, 20090316 */
+static void
+SwLedControlMode3(struct rtw_adapter *padapter, enum led_ctl_mode LedAction)
+{
+       struct led_priv *ledpriv = &padapter->ledpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct led_8723a *pLed = &ledpriv->SwLed0;
+       long delay = -1;
+
+       switch (LedAction)
+       {
+               case LED_CTL_SITE_SURVEY:
+                       if (pmlmepriv->LinkDetectInfo.bBusyTraffic)
+                               ;
+                       else if (pLed->bLedScanBlinkInProgress == false) {
+                               if (IS_LED_WPS_BLINKING(pLed))
+                                       return;
+
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+                               pLed->bLedScanBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_SCAN;
+                               pLed->BlinkTimes = 24;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_SCAN_INTERVAL_ALPHA;
+                       }
+                       break;
+
+               case LED_CTL_TX:
+               case LED_CTL_RX:
+                       if ((pLed->bLedBlinkInProgress == false) &&
+                           (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
+                               if (pLed->CurrLedState == LED_BLINK_SCAN ||
+                                   IS_LED_WPS_BLINKING(pLed)) {
+                                       return;
+                               }
+
+                               pLed->bLedBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_TXRX;
+                               pLed->BlinkTimes = 2;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay =  LED_BLINK_FASTER_INTERVAL_ALPHA;
+                       }
+                       break;
+
+               case LED_CTL_LINK:
+                       if (IS_LED_WPS_BLINKING(pLed))
+                               return;
+
+                       pLed->CurrLedState = RTW_LED_ON;
+                       pLed->BlinkingLedState = RTW_LED_ON;
+                       if (pLed->bLedBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedBlinkInProgress = false;
+                       }
+                       if (pLed->bLedScanBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedScanBlinkInProgress = false;
+                       }
+
+                       delay = 0;
+                       break;
+
+               case LED_CTL_START_WPS: /* wait until xinpin finish */
+               case LED_CTL_START_WPS_BOTTON:
+                       if (pLed->bLedWPSBlinkInProgress == false) {
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+                               if (pLed->bLedScanBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedScanBlinkInProgress = false;
+                               }
+                               pLed->bLedWPSBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_WPS;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = LED_BLINK_SCAN_INTERVAL_ALPHA;
+                       }
+                       break;
+
+               case LED_CTL_STOP_WPS:
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedWPSBlinkInProgress = false;
+                       } else {
+                               pLed->bLedWPSBlinkInProgress = true;
+                       }
+
+                       pLed->CurrLedState = LED_BLINK_WPS_STOP;
+                       if (pLed->bLedOn) {
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                               delay = LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA;
+                       } else {
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                               delay = 0;
+                       }
+
+                       break;
+
+               case LED_CTL_STOP_WPS_FAIL:
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedWPSBlinkInProgress = false;
+                       }
+
+                       pLed->CurrLedState = RTW_LED_OFF;
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+                       delay = 0;
+                       break;
+
+               case LED_CTL_START_TO_LINK:
+               case LED_CTL_NO_LINK:
+                       if (!IS_LED_BLINKING(pLed))
+                       {
+                               pLed->CurrLedState = RTW_LED_OFF;
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                               delay = 0;
+                       }
+                       break;
+
+               case LED_CTL_POWER_OFF:
+                       pLed->CurrLedState = RTW_LED_OFF;
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+                       if (pLed->bLedBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedBlinkInProgress = false;
+                       }
+                       if (pLed->bLedScanBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedScanBlinkInProgress = false;
+                       }
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedWPSBlinkInProgress = false;
+                       }
+
+                       delay = 0;
+                       break;
+
+               default:
+                       break;
+
+       }
+
+       if (delay != -1)
+               mod_timer(&pLed->BlinkTimer, jiffies + msecs_to_jiffies(delay));
+
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("CurrLedState %d\n", pLed->CurrLedState));
+}
+
+ /* Edimax-Belkin, added by chiyoko, 20090413 */
+static void
+SwLedControlMode4(struct rtw_adapter *padapter, enum led_ctl_mode LedAction)
+{
+       struct led_priv *ledpriv = &padapter->ledpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct led_8723a *pLed = &ledpriv->SwLed0;
+       struct led_8723a *pLed1 = &ledpriv->SwLed1;
+
+       switch (LedAction)
+       {
+               case LED_CTL_START_TO_LINK:
+                       if (pLed1->bLedWPSBlinkInProgress) {
+                               pLed1->bLedWPSBlinkInProgress = false;
+                               del_timer_sync(&pLed1->BlinkTimer);
+
+                               pLed1->BlinkingLedState = RTW_LED_OFF;
+                               pLed1->CurrLedState = RTW_LED_OFF;
+
+                               if (pLed1->bLedOn)
+                                       mod_timer(&pLed->BlinkTimer, jiffies);
+                       }
+
+                       if (pLed->bLedStartToLinkBlinkInProgress == false) {
+                               if (pLed->CurrLedState == LED_BLINK_SCAN ||
+                                   IS_LED_WPS_BLINKING(pLed)) {
+                                       return;
+                               }
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+                               if (pLed->bLedNoLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedNoLinkBlinkInProgress = false;
+                               }
+
+                               pLed->bLedStartToLinkBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_StartToBlink;
+                               if (pLed->bLedOn) {
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                                       mod_timer(&pLed->BlinkTimer,
+                                                 jiffies + msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL));
+                               } else {
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                                       mod_timer(&pLed->BlinkTimer,
+                                                 jiffies + msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL));
+                               }
+                       }
+                       break;
+
+               case LED_CTL_LINK:
+               case LED_CTL_NO_LINK:
+                       /* LED1 settings */
+                       if (LedAction == LED_CTL_LINK) {
+                               if (pLed1->bLedWPSBlinkInProgress) {
+                                       pLed1->bLedWPSBlinkInProgress = false;
+                                       del_timer_sync(&pLed1->BlinkTimer);
+
+                                       pLed1->BlinkingLedState = RTW_LED_OFF;
+                                       pLed1->CurrLedState = RTW_LED_OFF;
+
+                                       if (pLed1->bLedOn)
+                                               mod_timer(&pLed->BlinkTimer, jiffies);
+                               }
+                       }
+
+                       if (pLed->bLedNoLinkBlinkInProgress == false) {
+                               if (pLed->CurrLedState == LED_BLINK_SCAN ||
+                                   IS_LED_WPS_BLINKING(pLed)) {
+                                       return;
+                               }
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+
+                               pLed->bLedNoLinkBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_SLOWLY;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               mod_timer(&pLed->BlinkTimer, jiffies +
+                                         msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
+                       }
+                       break;
+
+               case LED_CTL_SITE_SURVEY:
+                       if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) &&
+                           (check_fwstate(pmlmepriv, _FW_LINKED) == true))
+                               ;
+                       else if (pLed->bLedScanBlinkInProgress == false) {
+                               if (IS_LED_WPS_BLINKING(pLed))
+                                       return;
+
+                               if (pLed->bLedNoLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedNoLinkBlinkInProgress = false;
+                               }
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+                               pLed->bLedScanBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_SCAN;
+                               pLed->BlinkTimes = 24;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               mod_timer(&pLed->BlinkTimer, jiffies +
+                                         msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
+                       }
+                       break;
+
+               case LED_CTL_TX:
+               case LED_CTL_RX:
+                       if (pLed->bLedBlinkInProgress == false) {
+                               if (pLed->CurrLedState == LED_BLINK_SCAN ||
+                                   IS_LED_WPS_BLINKING(pLed)) {
+                                       return;
+                               }
+                               if (pLed->bLedNoLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedNoLinkBlinkInProgress = false;
+                               }
+                               pLed->bLedBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_TXRX;
+                               pLed->BlinkTimes = 2;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               mod_timer(&pLed->BlinkTimer, jiffies +
+                                         msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
+                       }
+                       break;
+
+               case LED_CTL_START_WPS: /* wait until xinpin finish */
+               case LED_CTL_START_WPS_BOTTON:
+                       if (pLed1->bLedWPSBlinkInProgress) {
+                               pLed1->bLedWPSBlinkInProgress = false;
+                               del_timer_sync(&pLed1->BlinkTimer);
+
+                               pLed1->BlinkingLedState = RTW_LED_OFF;
+                               pLed1->CurrLedState = RTW_LED_OFF;
+
+                               if (pLed1->bLedOn)
+                                       mod_timer(&pLed->BlinkTimer, jiffies);
+                       }
+
+                       if (pLed->bLedWPSBlinkInProgress == false) {
+                               if (pLed->bLedNoLinkBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedNoLinkBlinkInProgress = false;
+                               }
+                               if (pLed->bLedBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+                               if (pLed->bLedScanBlinkInProgress == true) {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedScanBlinkInProgress = false;
+                               }
+                               pLed->bLedWPSBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_WPS;
+                               if (pLed->bLedOn)
+                               {
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                                 msecs_to_jiffies(LED_BLINK_SLOWLY_INTERVAL));
+                               } else {
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                                 msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL));
+                               }
+                       }
+                       break;
+
+               case LED_CTL_STOP_WPS:  /* WPS connect success */
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedWPSBlinkInProgress = false;
+                       }
+
+                       pLed->bLedNoLinkBlinkInProgress = true;
+                       pLed->CurrLedState = LED_BLINK_SLOWLY;
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
+                       break;
+
+               case LED_CTL_STOP_WPS_FAIL:             /* WPS authentication fail */
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedWPSBlinkInProgress = false;
+                       }
+
+                       pLed->bLedNoLinkBlinkInProgress = true;
+                       pLed->CurrLedState = LED_BLINK_SLOWLY;
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
+
+                       /* LED1 settings */
+                       if (pLed1->bLedWPSBlinkInProgress)
+                               del_timer_sync(&pLed1->BlinkTimer);
+                       else
+                               pLed1->bLedWPSBlinkInProgress = true;
+
+                       pLed1->CurrLedState = LED_BLINK_WPS_STOP;
+                       if (pLed1->bLedOn)
+                               pLed1->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed1->BlinkingLedState = RTW_LED_ON;
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL));
+
+                       break;
+
+               case LED_CTL_STOP_WPS_FAIL_OVERLAP:     /* WPS session overlap */
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedWPSBlinkInProgress = false;
+                       }
+
+                       pLed->bLedNoLinkBlinkInProgress = true;
+                       pLed->CurrLedState = LED_BLINK_SLOWLY;
+                       if (pLed->bLedOn)
+                               pLed->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed->BlinkingLedState = RTW_LED_ON;
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_NO_LINK_INTERVAL_ALPHA));
+
+                       /* LED1 settings */
+                       if (pLed1->bLedWPSBlinkInProgress)
+                               del_timer_sync(&pLed1->BlinkTimer);
+                       else
+                               pLed1->bLedWPSBlinkInProgress = true;
+
+                       pLed1->CurrLedState = LED_BLINK_WPS_STOP_OVERLAP;
+                       pLed1->BlinkTimes = 10;
+                       if (pLed1->bLedOn)
+                               pLed1->BlinkingLedState = RTW_LED_OFF;
+                       else
+                               pLed1->BlinkingLedState = RTW_LED_ON;
+                       mod_timer(&pLed->BlinkTimer, jiffies +
+                                 msecs_to_jiffies(LED_BLINK_NORMAL_INTERVAL));
+
+                       break;
+
+               case LED_CTL_POWER_OFF:
+                       pLed->CurrLedState = RTW_LED_OFF;
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+
+                       if (pLed->bLedNoLinkBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedNoLinkBlinkInProgress = false;
+                       }
+                       if (pLed->bLedLinkBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedLinkBlinkInProgress = false;
+                       }
+                       if (pLed->bLedBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedBlinkInProgress = false;
+                       }
+                       if (pLed->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedWPSBlinkInProgress = false;
+                       }
+                       if (pLed->bLedScanBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedScanBlinkInProgress = false;
+                       }
+                       if (pLed->bLedStartToLinkBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedStartToLinkBlinkInProgress = false;
+                       }
+
+                       if (pLed1->bLedWPSBlinkInProgress) {
+                               del_timer_sync(&pLed1->BlinkTimer);
+                               pLed1->bLedWPSBlinkInProgress = false;
+                       }
+
+                       pLed1->BlinkingLedState = LED_UNKNOWN;
+                       SwLedOff23a(padapter, pLed);
+                       SwLedOff23a(padapter, pLed1);
+                       break;
+
+               default:
+                       break;
+
+       }
+
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+}
+
+ /* Sercomm-Belkin, added by chiyoko, 20090415 */
+static void
+SwLedControlMode5(struct rtw_adapter *padapter, enum led_ctl_mode LedAction)
+{
+       struct led_priv *ledpriv = &padapter->ledpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct led_8723a *pLed = &ledpriv->SwLed0;
+
+       switch (LedAction)
+       {
+               case LED_CTL_POWER_ON:
+               case LED_CTL_NO_LINK:
+               case LED_CTL_LINK:      /* solid blue */
+                       pLed->CurrLedState = RTW_LED_ON;
+                       pLed->BlinkingLedState = RTW_LED_ON;
+
+                       mod_timer(&pLed->BlinkTimer, jiffies);
+                       break;
+
+               case LED_CTL_SITE_SURVEY:
+                       if ((pmlmepriv->LinkDetectInfo.bBusyTraffic) && (check_fwstate(pmlmepriv, _FW_LINKED) == true))
+                               ;
+                       else if (pLed->bLedScanBlinkInProgress == false)
+                       {
+                               if (pLed->bLedBlinkInProgress == true)
+                               {
+                                       del_timer_sync(&pLed->BlinkTimer);
+                                       pLed->bLedBlinkInProgress = false;
+                               }
+                               pLed->bLedScanBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_SCAN;
+                               pLed->BlinkTimes = 24;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               mod_timer(&pLed->BlinkTimer, jiffies +
+                                         msecs_to_jiffies(LED_BLINK_SCAN_INTERVAL_ALPHA));
+                       }
+                       break;
+
+               case LED_CTL_TX:
+               case LED_CTL_RX:
+                       if (pLed->bLedBlinkInProgress == false) {
+                               if (pLed->CurrLedState == LED_BLINK_SCAN) {
+                                       return;
+                               }
+                               pLed->bLedBlinkInProgress = true;
+                               pLed->CurrLedState = LED_BLINK_TXRX;
+                               pLed->BlinkTimes = 2;
+                               if (pLed->bLedOn)
+                                       pLed->BlinkingLedState = RTW_LED_OFF;
+                               else
+                                       pLed->BlinkingLedState = RTW_LED_ON;
+                               mod_timer(&pLed->BlinkTimer, jiffies +
+                                         msecs_to_jiffies(LED_BLINK_FASTER_INTERVAL_ALPHA));
+                       }
+                       break;
+
+               case LED_CTL_POWER_OFF:
+                       pLed->CurrLedState = RTW_LED_OFF;
+                       pLed->BlinkingLedState = RTW_LED_OFF;
+
+                       if (pLed->bLedBlinkInProgress) {
+                               del_timer_sync(&pLed->BlinkTimer);
+                               pLed->bLedBlinkInProgress = false;
+                       }
+
+                       SwLedOff23a(padapter, pLed);
+                       break;
+
+               default:
+                       break;
+
+       }
+
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("Led %d\n", pLed->CurrLedState));
+}
+
+ /* WNC-Corega, added by chiyoko, 20090902 */
+static void SwLedControlMode6(struct rtw_adapter *padapter,
+                             enum led_ctl_mode LedAction)
+{
+       struct led_priv *ledpriv = &padapter->ledpriv;
+       struct led_8723a *pLed0 = &ledpriv->SwLed0;
+
+       switch (LedAction) {
+       case LED_CTL_POWER_ON:
+       case LED_CTL_LINK:
+       case LED_CTL_NO_LINK:
+               del_timer_sync(&pLed0->BlinkTimer);
+               pLed0->CurrLedState = RTW_LED_ON;
+               pLed0->BlinkingLedState = RTW_LED_ON;
+               mod_timer(&pLed0->BlinkTimer, jiffies);
+               break;
+       case LED_CTL_POWER_OFF:
+               SwLedOff23a(padapter, pLed0);
+               break;
+       default:
+               break;
+       }
+
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("ledcontrol 6 Led %d\n", pLed0->CurrLedState));
+}
+
+/*  */
+/*     Description: */
+/*             Handler function of LED Blinking. */
+/*             We dispatch acture LED blink action according to LedStrategy. */
+/*  */
+void BlinkHandler23a(struct led_8723a *pLed)
+{
+       struct rtw_adapter *padapter = pLed->padapter;
+       struct led_priv *ledpriv = &padapter->ledpriv;
+
+       /* DBG_8723A("%s (%s:%d)\n", __func__, current->comm, current->pid); */
+
+       if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
+               return;
+
+       switch (ledpriv->LedStrategy) {
+       case SW_LED_MODE0:
+               SwLedBlink(pLed);
+               break;
+       case SW_LED_MODE1:
+               SwLedBlink1(pLed);
+               break;
+       case SW_LED_MODE2:
+               SwLedBlink2(pLed);
+               break;
+       case SW_LED_MODE3:
+               SwLedBlink3(pLed);
+               break;
+       case SW_LED_MODE4:
+               SwLedBlink4(pLed);
+               break;
+       case SW_LED_MODE5:
+               SwLedBlink5(pLed);
+               break;
+       case SW_LED_MODE6:
+               SwLedBlink6(pLed);
+               break;
+       default:
+               break;
+       }
+}
+
+void
+LedControl871x23a(struct rtw_adapter *padapter, enum led_ctl_mode LedAction) {
+       struct led_priv *ledpriv = &padapter->ledpriv;
+
+       if ((padapter->bSurpriseRemoved == true) ||
+           (padapter->bDriverStopped == true) ||
+           (padapter->hw_init_completed == false)) {
+             return;
+       }
+
+       if (ledpriv->bRegUseLed == false)
+               return;
+
+       /* if (!priv->up) */
+       /*      return; */
+
+       /* if (priv->bInHctTest) */
+       /*      return; */
+
+       if ((padapter->pwrctrlpriv.rf_pwrstate != rf_on &&
+            padapter->pwrctrlpriv.rfoff_reason > RF_CHANGE_BY_PS) &&
+           (LedAction == LED_CTL_TX || LedAction == LED_CTL_RX ||
+            LedAction == LED_CTL_SITE_SURVEY ||
+            LedAction == LED_CTL_LINK ||
+            LedAction == LED_CTL_NO_LINK ||
+            LedAction == LED_CTL_POWER_ON)) {
+               return;
+       }
+
+       switch (ledpriv->LedStrategy) {
+       case SW_LED_MODE0:
+               break;
+       case SW_LED_MODE1:
+               SwLedControlMode1(padapter, LedAction);
+               break;
+       case SW_LED_MODE2:
+               SwLedControlMode2(padapter, LedAction);
+               break;
+       case SW_LED_MODE3:
+               SwLedControlMode3(padapter, LedAction);
+               break;
+       case SW_LED_MODE4:
+               SwLedControlMode4(padapter, LedAction);
+               break;
+       case SW_LED_MODE5:
+               SwLedControlMode5(padapter, LedAction);
+               break;
+       case SW_LED_MODE6:
+               SwLedControlMode6(padapter, LedAction);
+               break;
+       default:
+               break;
+       }
+
+       RT_TRACE(_module_rtl8712_led_c_, _drv_info_, ("LedStrategy:%d, LedAction %d\n", ledpriv->LedStrategy, LedAction));
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_mlme.c b/drivers/staging/rtl8723au/core/rtw_mlme.c
new file mode 100644 (file)
index 0000000..6cee787
--- /dev/null
@@ -0,0 +1,2500 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_MLME_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+#include <hal_intf.h>
+#include <mlme_osdep.h>
+#include <sta_info.h>
+#include <linux/ieee80211.h>
+#include <wifi.h>
+#include <wlan_bssdef.h>
+#include <rtw_ioctl_set.h>
+
+extern u8 rtw_do_join23a(struct rtw_adapter * padapter);
+
+static void rtw_init_mlme_timer(struct rtw_adapter *padapter)
+{
+       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       setup_timer(&pmlmepriv->assoc_timer, rtw23a_join_to_handler,
+                   (unsigned long)padapter);
+
+       setup_timer(&pmlmepriv->scan_to_timer, rtw_scan_timeout_handler23a,
+                   (unsigned long)padapter);
+
+       setup_timer(&pmlmepriv->dynamic_chk_timer,
+                   rtw_dynamic_check_timer_handler, (unsigned long)padapter);
+
+       setup_timer(&pmlmepriv->set_scan_deny_timer,
+                   rtw_set_scan_deny_timer_hdl, (unsigned long)padapter);
+}
+
+int _rtw_init_mlme_priv23a(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       int res = _SUCCESS;
+
+       pmlmepriv->nic_hdl = padapter;
+
+       pmlmepriv->fw_state = 0;
+       pmlmepriv->cur_network.network.InfrastructureMode = Ndis802_11AutoUnknown;
+       pmlmepriv->scan_mode=SCAN_ACTIVE;/*  1: active, 0: pasive. Maybe someday we should rename this varable to "active_mode" (Jeff) */
+
+       spin_lock_init(&pmlmepriv->lock);
+       _rtw_init_queue23a(&pmlmepriv->scanned_queue);
+
+       memset(&pmlmepriv->assoc_ssid, 0, sizeof(struct cfg80211_ssid));
+
+       /* allocate DMA-able/Non-Page memory for cmd_buf and rsp_buf */
+
+       rtw_clear_scan_deny(padapter);
+
+       rtw_init_mlme_timer(padapter);
+       return res;
+}
+
+#ifdef CONFIG_8723AU_AP_MODE
+static void rtw_free_mlme_ie_data(u8 **ppie, u32 *plen)
+{
+       if(*ppie)
+       {
+               kfree(*ppie);
+               *plen = 0;
+               *ppie=NULL;
+       }
+}
+#endif
+
+void rtw23a_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv)
+{
+#ifdef CONFIG_8723AU_AP_MODE
+       kfree(pmlmepriv->assoc_req);
+       kfree(pmlmepriv->assoc_rsp);
+       rtw_free_mlme_ie_data(&pmlmepriv->wps_beacon_ie, &pmlmepriv->wps_beacon_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_req_ie, &pmlmepriv->wps_probe_req_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->wps_probe_resp_ie, &pmlmepriv->wps_probe_resp_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->wps_assoc_resp_ie, &pmlmepriv->wps_assoc_resp_ie_len);
+
+       rtw_free_mlme_ie_data(&pmlmepriv->p2p_beacon_ie, &pmlmepriv->p2p_beacon_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_req_ie, &pmlmepriv->p2p_probe_req_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->p2p_probe_resp_ie, &pmlmepriv->p2p_probe_resp_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->p2p_go_probe_resp_ie, &pmlmepriv->p2p_go_probe_resp_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->p2p_assoc_req_ie, &pmlmepriv->p2p_assoc_req_ie_len);
+
+       rtw_free_mlme_ie_data(&pmlmepriv->wfd_beacon_ie, &pmlmepriv->wfd_beacon_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_req_ie, &pmlmepriv->wfd_probe_req_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->wfd_probe_resp_ie, &pmlmepriv->wfd_probe_resp_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->wfd_go_probe_resp_ie, &pmlmepriv->wfd_go_probe_resp_ie_len);
+       rtw_free_mlme_ie_data(&pmlmepriv->wfd_assoc_req_ie, &pmlmepriv->wfd_assoc_req_ie_len);
+#endif
+}
+
+void _rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv)
+{
+
+       rtw23a_free_mlme_priv_ie_data(pmlmepriv);
+
+}
+
+struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv)
+{
+       struct wlan_network *pnetwork;
+
+       pnetwork = kzalloc(sizeof(struct wlan_network), GFP_ATOMIC);
+       if (pnetwork) {
+               INIT_LIST_HEAD(&pnetwork->list);
+               pnetwork->network_type = 0;
+               pnetwork->fixed = false;
+               pnetwork->last_scanned = jiffies;
+               pnetwork->aid = 0;
+               pnetwork->join_res = 0;
+       }
+
+       return pnetwork;
+}
+
+void _rtw_free_network23a(struct mlme_priv *pmlmepriv,
+                      struct wlan_network *pnetwork, u8 isfreeall)
+{
+       u32 lifetime = SCANQUEUE_LIFETIME;
+
+       if (!pnetwork)
+               return;
+
+       if (pnetwork->fixed == true)
+               return;
+
+       if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
+           (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
+               lifetime = 1;
+
+       list_del_init(&pnetwork->list);
+
+       kfree(pnetwork);
+}
+
+void _rtw_free_network23a_nolock23a(struct mlme_priv *pmlmepriv,
+                             struct wlan_network *pnetwork)
+{
+
+       if (pnetwork == NULL)
+               return;
+
+       if (pnetwork->fixed == true)
+               return;
+
+       list_del_init(&pnetwork->list);
+
+       kfree(pnetwork);
+}
+
+/*
+       return the wlan_network with the matching addr
+
+       Shall be calle under atomic context... to avoid possible racing condition...
+*/
+struct wlan_network *
+_rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr)
+{
+       struct list_head *phead, *plist;
+       struct wlan_network *pnetwork = NULL;
+
+       if (is_zero_ether_addr(addr)) {
+               pnetwork = NULL;
+               goto exit;
+       }
+
+       /* spin_lock_bh(&scanned_queue->lock); */
+
+       phead = get_list_head(scanned_queue);
+       plist = phead->next;
+
+       while (plist != phead) {
+               pnetwork = container_of(plist, struct wlan_network, list);
+
+               if (ether_addr_equal(addr, pnetwork->network.MacAddress))
+                       break;
+
+               plist = plist->next;
+        }
+
+       if(plist == phead)
+               pnetwork = NULL;
+
+       /* spin_unlock_bh(&scanned_queue->lock); */
+
+exit:
+
+       return pnetwork;
+}
+
+void _rtw_free_network23a_queue23a(struct rtw_adapter *padapter, u8 isfreeall)
+{
+       struct list_head *phead, *plist, *ptmp;
+       struct wlan_network *pnetwork;
+       struct mlme_priv* pmlmepriv = &padapter->mlmepriv;
+       struct rtw_queue *scanned_queue = &pmlmepriv->scanned_queue;
+
+       spin_lock_bh(&scanned_queue->lock);
+
+       phead = get_list_head(scanned_queue);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               pnetwork = container_of(plist, struct wlan_network, list);
+
+               _rtw_free_network23a(pmlmepriv,pnetwork, isfreeall);
+       }
+
+       spin_unlock_bh(&scanned_queue->lock);
+
+}
+
+int rtw_if_up23a(struct rtw_adapter *padapter) {
+
+       int res;
+
+       if(padapter->bDriverStopped || padapter->bSurpriseRemoved ||
+               (check_fwstate(&padapter->mlmepriv, _FW_LINKED)== false)) {
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_if_up23a:bDriverStopped(%d) OR bSurpriseRemoved(%d)", padapter->bDriverStopped, padapter->bSurpriseRemoved));
+               res=false;
+       }
+       else
+               res=  true;
+
+       return res;
+}
+
+void rtw_generate_random_ibss23a(u8* pibss)
+{
+       unsigned long curtime = jiffies;
+
+       pibss[0] = 0x02;  /* in ad-hoc mode bit1 must set to 1 */
+       pibss[1] = 0x11;
+       pibss[2] = 0x87;
+       pibss[3] = (u8)(curtime & 0xff) ;/* p[0]; */
+       pibss[4] = (u8)((curtime>>8) & 0xff) ;/* p[1]; */
+       pibss[5] = (u8)((curtime>>16) & 0xff) ;/* p[2]; */
+
+       return;
+}
+
+u8 *rtw_get_capability23a_from_ie(u8 *ie)
+{
+       return ie + 8 + 2;
+}
+
+u16 rtw_get_capability23a(struct wlan_bssid_ex *bss)
+{
+       u16     val;
+
+       memcpy((u8 *)&val, rtw_get_capability23a_from_ie(bss->IEs), 2);
+
+       return le16_to_cpu(val);
+}
+
+u8 *rtw_get_timestampe_from_ie23a(u8 *ie)
+{
+       return ie + 0;
+}
+
+u8 *rtw_get_beacon_interval23a_from_ie(u8 *ie)
+{
+       return ie + 8;
+}
+
+int    rtw_init_mlme_priv23a (struct rtw_adapter *padapter)/* struct   mlme_priv *pmlmepriv) */
+{
+       int     res;
+
+       res = _rtw_init_mlme_priv23a(padapter);/*  (pmlmepriv); */
+
+       return res;
+}
+
+void rtw_free_mlme_priv23a (struct mlme_priv *pmlmepriv)
+{
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_mlme_priv23a\n"));
+       _rtw_free_mlme_priv23a(pmlmepriv);
+
+}
+
+void rtw_free_network(struct mlme_priv *pmlmepriv, struct      wlan_network *pnetwork, u8 is_freeall);
+void rtw_free_network(struct mlme_priv *pmlmepriv, struct      wlan_network *pnetwork, u8 is_freeall)/* struct wlan_network *pnetwork, _queue  *free_queue) */
+{
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                ("rtw_free_network ==> ssid = %s\n\n" ,
+                 pnetwork->network.Ssid.ssid));
+       _rtw_free_network23a(pmlmepriv, pnetwork, is_freeall);
+
+}
+
+void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork);
+void rtw_free_network_nolock(struct mlme_priv *pmlmepriv, struct wlan_network *pnetwork)
+{
+
+       /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("rtw_free_network ==> ssid = %s\n\n" , pnetwork->network.Ssid.ssid)); */
+       _rtw_free_network23a_nolock23a(pmlmepriv, pnetwork);
+
+}
+
+void rtw_free_network_queue23a(struct rtw_adapter* dev, u8 isfreeall)
+{
+
+       _rtw_free_network23a_queue23a(dev, isfreeall);
+
+}
+
+/*
+       return the wlan_network with the matching addr
+
+       Shall be calle under atomic context... to avoid possible racing condition...
+*/
+struct wlan_network *
+rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr)
+{
+       struct wlan_network *pnetwork;
+
+       pnetwork = _rtw_find_network23a(scanned_queue, addr);
+
+       return pnetwork;
+}
+
+int rtw_is_same_ibss23a(struct rtw_adapter *adapter, struct wlan_network *pnetwork)
+{
+       int ret = true;
+       struct security_priv *psecuritypriv = &adapter->securitypriv;
+
+       if ((psecuritypriv->dot11PrivacyAlgrthm != _NO_PRIVACY_) &&
+                   (pnetwork->network.Privacy == 0))
+       {
+               ret = false;
+       }
+       else if ((psecuritypriv->dot11PrivacyAlgrthm == _NO_PRIVACY_) &&
+                (pnetwork->network.Privacy == 1))
+       {
+               ret = false;
+       }
+       else
+       {
+               ret = true;
+       }
+
+       return ret;
+}
+
+inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b);
+inline int is_same_ess(struct wlan_bssid_ex *a, struct wlan_bssid_ex *b)
+{
+       /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("(%s,%d)(%s,%d)\n", */
+       /*              a->Ssid.Ssid, a->Ssid.SsidLength, b->Ssid.Ssid, b->Ssid.SsidLength)); */
+       return (a->Ssid.ssid_len == b->Ssid.ssid_len) &&
+               !memcmp(a->Ssid.ssid, b->Ssid.ssid, a->Ssid.ssid_len);
+}
+
+int is_same_network23a(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst)
+{
+        u16 s_cap, d_cap;
+
+       memcpy((u8 *)&s_cap, rtw_get_capability23a_from_ie(src->IEs), 2);
+       memcpy((u8 *)&d_cap, rtw_get_capability23a_from_ie(dst->IEs), 2);
+
+       s_cap = le16_to_cpu(s_cap);
+       d_cap = le16_to_cpu(d_cap);
+
+       return ((src->Ssid.ssid_len == dst->Ssid.ssid_len) &&
+               /*      (src->Configuration.DSConfig == dst->Configuration.DSConfig) && */
+               ether_addr_equal(src->MacAddress, dst->MacAddress) &&
+               ((!memcmp(src->Ssid.ssid, dst->Ssid.ssid, src->Ssid.ssid_len))) &&
+               ((s_cap & WLAN_CAPABILITY_IBSS) ==
+                (d_cap & WLAN_CAPABILITY_IBSS)) &&
+               ((s_cap & WLAN_CAPABILITY_ESS) ==
+                (d_cap & WLAN_CAPABILITY_ESS)));
+}
+
+struct wlan_network *rtw_get_oldest_wlan_network23a(struct rtw_queue *scanned_queue)
+{
+       struct list_head *plist, *phead;
+
+       struct wlan_network *pwlan;
+       struct wlan_network *oldest = NULL;
+
+       phead = get_list_head(scanned_queue);
+
+       list_for_each(plist, phead) {
+               pwlan = container_of(plist, struct wlan_network, list);
+
+               if (pwlan->fixed != true) {
+                       if (!oldest || time_after(oldest->last_scanned,
+                                                 pwlan->last_scanned))
+                               oldest = pwlan;
+               }
+       }
+
+       return oldest;
+}
+
+void update_network23a(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
+       struct rtw_adapter * padapter, bool update_ie)
+{
+       u8 ss_ori = dst->PhyInfo.SignalStrength;
+       u8 sq_ori = dst->PhyInfo.SignalQuality;
+       long rssi_ori = dst->Rssi;
+
+       u8 ss_smp = src->PhyInfo.SignalStrength;
+       u8 sq_smp = src->PhyInfo.SignalQuality;
+       long rssi_smp = src->Rssi;
+
+       u8 ss_final;
+       u8 sq_final;
+       long rssi_final;
+
+       DBG_8723A("%s %s(%pM, ch%u) ss_ori:%3u, sq_ori:%3u, rssi_ori:%3ld, ss_smp:%3u, sq_smp:%3u, rssi_smp:%3ld\n",
+                 __func__, src->Ssid.ssid, src->MacAddress,
+                 src->Configuration.DSConfig, ss_ori, sq_ori, rssi_ori,
+                 ss_smp, sq_smp, rssi_smp
+       );
+
+       /* The rule below is 1/5 for sample value, 4/5 for history value */
+       if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) && is_same_network23a(&padapter->mlmepriv.cur_network.network, src)) {
+               /* Take the recvpriv's value for the connected AP*/
+               ss_final = padapter->recvpriv.signal_strength;
+               sq_final = padapter->recvpriv.signal_qual;
+               /* the rssi value here is undecorated, and will be used for antenna diversity */
+               if (sq_smp != 101) /* from the right channel */
+                       rssi_final = (src->Rssi+dst->Rssi*4)/5;
+               else
+                       rssi_final = rssi_ori;
+       }
+       else {
+               if (sq_smp != 101) { /* from the right channel */
+                       ss_final = ((u32)(src->PhyInfo.SignalStrength)+(u32)(dst->PhyInfo.SignalStrength)*4)/5;
+                       sq_final = ((u32)(src->PhyInfo.SignalQuality)+(u32)(dst->PhyInfo.SignalQuality)*4)/5;
+                       rssi_final = (src->Rssi+dst->Rssi*4)/5;
+               } else {
+                       /* bss info not receving from the right channel, use the original RX signal infos */
+                       ss_final = dst->PhyInfo.SignalStrength;
+                       sq_final = dst->PhyInfo.SignalQuality;
+                       rssi_final = dst->Rssi;
+               }
+
+       }
+
+       if (update_ie)
+               memcpy((u8 *)dst, (u8 *)src, get_wlan_bssid_ex_sz(src));
+
+       dst->PhyInfo.SignalStrength = ss_final;
+       dst->PhyInfo.SignalQuality = sq_final;
+       dst->Rssi = rssi_final;
+
+       DBG_8723A("%s %s(%pM), SignalStrength:%u, SignalQuality:%u, RawRSSI:%ld\n",
+                 __func__, dst->Ssid.ssid, dst->MacAddress,
+                 dst->PhyInfo.SignalStrength,
+                 dst->PhyInfo.SignalQuality, dst->Rssi);
+
+}
+
+static void update_current_network(struct rtw_adapter *adapter, struct wlan_bssid_ex *pnetwork)
+{
+       struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+       if ((check_fwstate(pmlmepriv, _FW_LINKED)== true) && (is_same_network23a(&pmlmepriv->cur_network.network, pnetwork)))
+       {
+               /* RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,"Same Network\n"); */
+
+               /* if(pmlmepriv->cur_network.network.IELength<= pnetwork->IELength) */
+               {
+                       update_network23a(&pmlmepriv->cur_network.network, pnetwork,adapter, true);
+                       rtw_update_protection23a(adapter, (pmlmepriv->cur_network.network.IEs) + sizeof (struct ndis_802_11_fixed_ies),
+                                                                       pmlmepriv->cur_network.network.IELength);
+               }
+       }
+
+}
+
+/*
+
+Caller must hold pmlmepriv->lock first.
+
+*/
+void rtw_update_scanned_network23a(struct rtw_adapter *adapter, struct wlan_bssid_ex *target)
+{
+       struct list_head *plist, *phead;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct wlan_network *pnetwork = NULL;
+       struct wlan_network *oldest = NULL;
+       struct rtw_queue *queue = &pmlmepriv->scanned_queue;
+       u32 bssid_ex_sz;
+       int found = 0;
+
+       spin_lock_bh(&queue->lock);
+       phead = get_list_head(queue);
+
+       list_for_each(plist, phead) {
+               pnetwork = container_of(plist, struct wlan_network, list);
+
+               if (is_same_network23a(&pnetwork->network, target)) {
+                       found = 1;
+                       break;
+               }
+               if (!oldest || time_after(oldest->last_scanned,
+                                         pnetwork->last_scanned))
+                       oldest = pnetwork;
+       }
+
+       /* If we didn't find a match, then get a new network slot to initialize
+        * with this beacon's information */
+       if (!found) {
+               pnetwork = rtw_alloc_network(pmlmepriv);
+               if (!pnetwork) {
+                       if (!oldest) {
+                               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                                        ("\n\n\nsomething wrong here\n\n\n"));
+                               goto exit;
+                       }
+                       pnetwork = oldest;
+               } else
+                       list_add_tail(&pnetwork->list, &queue->queue);
+
+               bssid_ex_sz = get_wlan_bssid_ex_sz(target);
+               target->Length = bssid_ex_sz;
+               memcpy(&pnetwork->network, target, bssid_ex_sz);
+
+               /*  variable initialize */
+               pnetwork->fixed = false;
+               pnetwork->last_scanned = jiffies;
+
+               pnetwork->network_type = 0;
+               pnetwork->aid = 0;
+               pnetwork->join_res = 0;
+
+               /* bss info not receving from the right channel */
+               if (pnetwork->network.PhyInfo.SignalQuality == 101)
+                       pnetwork->network.PhyInfo.SignalQuality = 0;
+       } else {
+               /*
+                * we have an entry and we are going to update it. But
+                * this entry may be already expired. In this case we
+                * do the same as we found a new net and call the
+                * new_net handler
+                */
+               bool update_ie = true;
+
+               pnetwork->last_scanned = jiffies;
+
+               /* target.reserved == 1, means that scanned network is
+                * a bcn frame. */
+               if ((pnetwork->network.IELength>target->IELength) &&
+                   (target->reserved == 1))
+                       update_ie = false;
+
+               update_network23a(&pnetwork->network, target,adapter, update_ie);
+       }
+
+exit:
+       spin_unlock_bh(&queue->lock);
+
+}
+
+void rtw_add_network(struct rtw_adapter *adapter, struct wlan_bssid_ex *pnetwork)
+{
+       update_current_network(adapter, pnetwork);
+       rtw_update_scanned_network23a(adapter, pnetwork);
+}
+
+/* select the desired network based on the capability of the (i)bss. */
+/*  check items: (1) security */
+/*                        (2) network_type */
+/*                        (3) WMM */
+/*                        (4) HT */
+/*                      (5) others */
+int rtw_is_desired_network(struct rtw_adapter *adapter, struct wlan_network *pnetwork)
+{
+       struct security_priv *psecuritypriv = &adapter->securitypriv;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       u32 desired_encmode;
+       u32 privacy;
+
+       /* u8 wps_ie[512]; */
+       uint wps_ielen;
+
+       int bselected = true;
+
+       desired_encmode = psecuritypriv->ndisencryptstatus;
+       privacy = pnetwork->network.Privacy;
+
+       if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS))
+       {
+               if (rtw_get_wps_ie23a(pnetwork->network.IEs+_FIXED_IE_LENGTH_, pnetwork->network.IELength-_FIXED_IE_LENGTH_, NULL, &wps_ielen)!= NULL)
+               {
+                       return true;
+               }
+               else
+               {
+                       return false;
+               }
+       }
+       if (adapter->registrypriv.wifi_spec == 1) /* for  correct flow of 8021X  to do.... */
+       {
+               if ((desired_encmode == Ndis802_11EncryptionDisabled) && (privacy != 0))
+                   bselected = false;
+       }
+
+       if ((desired_encmode != Ndis802_11EncryptionDisabled) && (privacy == 0)) {
+               DBG_8723A("desired_encmode: %d, privacy: %d\n", desired_encmode, privacy);
+               bselected = false;
+       }
+
+       if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)
+       {
+               if (pnetwork->network.InfrastructureMode != pmlmepriv->cur_network.network.InfrastructureMode)
+                       bselected = false;
+       }
+
+       return bselected;
+}
+
+/* TODO: Perry : For Power Management */
+void rtw_atimdone_event_callback23a(struct rtw_adapter *adapter , u8 *pbuf)
+{
+
+       RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("receive atimdone_evet\n"));
+
+       return;
+}
+
+void rtw_survey_event_cb23a(struct rtw_adapter *adapter, u8 *pbuf)
+{
+       u32 len;
+       struct wlan_bssid_ex *pnetwork;
+       struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+       pnetwork = (struct wlan_bssid_ex *)pbuf;
+
+       RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("rtw_survey_event_cb23a, ssid=%s\n",  pnetwork->Ssid.ssid));
+
+       len = get_wlan_bssid_ex_sz(pnetwork);
+       if(len > (sizeof(struct wlan_bssid_ex)))
+       {
+               RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n ****rtw_survey_event_cb23a: return a wrong bss ***\n"));
+               return;
+       }
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       /*  update IBSS_network 's timestamp */
+       if ((check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)) == true)
+       {
+               /* RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,"rtw_survey_event_cb23a : WIFI_ADHOC_MASTER_STATE\n\n"); */
+               if (ether_addr_equal(pmlmepriv->cur_network.network.MacAddress,
+                                    pnetwork->MacAddress)) {
+                       struct wlan_network* ibss_wlan = NULL;
+
+                       memcpy(pmlmepriv->cur_network.network.IEs, pnetwork->IEs, 8);
+                       spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+                       ibss_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue,  pnetwork->MacAddress);
+                       if (ibss_wlan)
+                       {
+                               memcpy(ibss_wlan->network.IEs , pnetwork->IEs, 8);
+                               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+                               goto exit;
+                       }
+                       spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+               }
+       }
+
+       /*  lock pmlmepriv->lock when you accessing network_q */
+       if ((check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) == false)
+       {
+               if (pnetwork->Ssid.ssid[0] == 0)
+                       pnetwork->Ssid.ssid_len = 0;
+
+               rtw_add_network(adapter, pnetwork);
+       }
+
+exit:
+
+       spin_unlock_bh(&pmlmepriv->lock);
+
+       return;
+}
+
+void rtw_surveydone_event_callback23a(struct rtw_adapter       *adapter, u8 *pbuf)
+{
+       struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       if (pmlmepriv->wps_probe_req_ie) {
+               pmlmepriv->wps_probe_req_ie_len = 0;
+               kfree(pmlmepriv->wps_probe_req_ie);
+               pmlmepriv->wps_probe_req_ie = NULL;
+       }
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("rtw_surveydone_event_callback23a: fw_state:%x\n\n", get_fwstate(pmlmepriv)));
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+               del_timer_sync(&pmlmepriv->scan_to_timer);
+
+               _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+       } else {
+
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("nic status =%x, survey done event comes too late!\n", get_fwstate(pmlmepriv)));
+       }
+
+       rtw_set_signal_stat_timer(&adapter->recvpriv);
+
+       if (pmlmepriv->to_join == true) {
+               if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true)) {
+                       if (check_fwstate(pmlmepriv, _FW_LINKED) == false) {
+                               set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+
+                               if (rtw_select_and_join_from_scanned_queue23a(pmlmepriv) == _SUCCESS) {
+                                       mod_timer(&pmlmepriv->assoc_timer,
+                                                 jiffies + msecs_to_jiffies(MAX_JOIN_TIMEOUT));
+                               } else {
+                                       struct wlan_bssid_ex *pdev_network = &adapter->registrypriv.dev_network;
+                                       u8 *pibss = adapter->registrypriv.dev_network.MacAddress;
+
+                                       _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+
+                                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("switching to adhoc master\n"));
+
+                                       memset(&pdev_network->Ssid, 0, sizeof(struct cfg80211_ssid));
+                                       memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid, sizeof(struct cfg80211_ssid));
+
+                                       rtw_update_registrypriv_dev_network23a(adapter);
+                                       rtw_generate_random_ibss23a(pibss);
+
+                                       pmlmepriv->fw_state = WIFI_ADHOC_MASTER_STATE;
+
+                                       if (rtw_createbss_cmd23a(adapter)!= _SUCCESS)
+                                       {
+                                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Error =>rtw_createbss_cmd23a status FAIL\n"));
+                                       }
+
+                                       pmlmepriv->to_join = false;
+                               }
+                       }
+               } else {
+                       int ret;
+                       set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+                       pmlmepriv->to_join = false;
+                       ret = rtw_select_and_join_from_scanned_queue23a(pmlmepriv);
+                       if (ret == _SUCCESS) {
+                               unsigned long e;
+                               e = msecs_to_jiffies(MAX_JOIN_TIMEOUT);
+                               mod_timer(&pmlmepriv->assoc_timer, jiffies + e);
+                       } else if (ret == 2)/* there is no need to wait for join */
+                       {
+                               _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+                               rtw_indicate_connect23a(adapter);
+                       } else {
+                               DBG_8723A("try_to_join, but select scanning queue fail, to_roaming:%d\n", rtw_to_roaming(adapter));
+                               if (rtw_to_roaming(adapter) != 0) {
+                                       if (--pmlmepriv->to_roaming == 0
+                                               || _SUCCESS != rtw_sitesurvey_cmd23a(adapter, &pmlmepriv->assoc_ssid, 1, NULL, 0)
+                                       ) {
+                                               rtw_set_roaming(adapter, 0);
+                                               rtw_free_assoc_resources23a(adapter, 1);
+                                               rtw_indicate_disconnect23a(adapter);
+                                       } else {
+                                               pmlmepriv->to_join = true;
+                                       }
+                               }
+                               _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+                       }
+               }
+       }
+
+       spin_unlock_bh(&pmlmepriv->lock);
+
+#ifdef CONFIG_8723AU_P2P
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+               p2p_ps_wk_cmd23a(adapter, P2P_PS_SCAN_DONE, 0);
+#endif /*  CONFIG_8723AU_P2P */
+
+       rtw_os_xmit_schedule23a(adapter);
+
+       if(pmlmeext->sitesurvey_res.bss_cnt == 0)
+               rtw_hal_sreset_reset23a(adapter);
+
+       rtw_cfg80211_surveydone_event_callback(adapter);
+
+}
+
+void rtw_dummy_event_callback23a(struct rtw_adapter *adapter , u8 *pbuf)
+{
+}
+
+void rtw23a_fwdbg_event_callback(struct rtw_adapter *adapter , u8 *pbuf)
+{
+}
+
+static void free_scanqueue(struct      mlme_priv *pmlmepriv)
+{
+       struct wlan_network *pnetwork;
+       struct rtw_queue *scan_queue = &pmlmepriv->scanned_queue;
+       struct list_head *plist, *phead, *ptemp;
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+free_scanqueue\n"));
+       spin_lock_bh(&scan_queue->lock);
+
+       phead = get_list_head(scan_queue);
+
+       list_for_each_safe(plist, ptemp, phead) {
+               list_del_init(plist);
+               pnetwork = container_of(plist, struct wlan_network, list);
+               kfree(pnetwork);
+        }
+
+       spin_unlock_bh(&scan_queue->lock);
+
+}
+
+/*
+*rtw_free_assoc_resources23a: the caller has to lock pmlmepriv->lock
+*/
+void rtw_free_assoc_resources23a(struct rtw_adapter *adapter, int lock_scanned_queue)
+{
+       struct wlan_network* pwlan = NULL;
+       struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct  sta_priv *pstapriv = &adapter->stapriv;
+       struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_, ("+rtw_free_assoc_resources23a\n"));
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("tgt_network->network.MacAddress="MAC_FMT" ssid=%s\n",
+               MAC_ARG(tgt_network->network.MacAddress), tgt_network->network.Ssid.ssid));
+
+       if(check_fwstate(pmlmepriv, WIFI_STATION_STATE|WIFI_AP_STATE))
+       {
+               struct sta_info* psta;
+
+               psta = rtw_get_stainfo23a(&adapter->stapriv, tgt_network->network.MacAddress);
+
+               {
+                       spin_lock_bh(&pstapriv->sta_hash_lock);
+                       rtw_free_stainfo23a(adapter,  psta);
+               }
+
+               spin_unlock_bh(&pstapriv->sta_hash_lock);
+
+       }
+
+       if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE))
+       {
+               struct sta_info* psta;
+
+               rtw_free_all_stainfo23a(adapter);
+
+               psta = rtw_get_bcmc_stainfo23a(adapter);
+               spin_lock_bh(&pstapriv->sta_hash_lock);
+               rtw_free_stainfo23a(adapter, psta);
+               spin_unlock_bh(&pstapriv->sta_hash_lock);
+
+               rtw_init_bcmc_stainfo23a(adapter);
+       }
+
+       if(lock_scanned_queue)
+               spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+
+       pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+       if(pwlan)
+               pwlan->fixed = false;
+       else
+               RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("rtw_free_assoc_resources23a : pwlan== NULL\n\n"));
+
+       if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) && (adapter->stapriv.asoc_sta_count == 1))
+               rtw_free_network_nolock(pmlmepriv, pwlan);
+
+       if(lock_scanned_queue)
+               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+
+       pmlmepriv->key_mask = 0;
+
+}
+
+/*
+*rtw_indicate_connect23a: the caller has to lock pmlmepriv->lock
+*/
+void rtw_indicate_connect23a(struct rtw_adapter *padapter)
+{
+       struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_connect23a\n"));
+
+       pmlmepriv->to_join = false;
+
+       if(!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+               set_fwstate(pmlmepriv, _FW_LINKED);
+
+               rtw_led_control(padapter, LED_CTL_LINK);
+
+               rtw_os_indicate_connect23a(padapter);
+       }
+
+       rtw_set_roaming(padapter, 0);
+
+       rtw_set_scan_deny(padapter, 3000);
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("-rtw_indicate_connect23a: fw_state=0x%08x\n", get_fwstate(pmlmepriv)));
+
+}
+
+/*
+*rtw_indicate_disconnect23a: the caller has to lock pmlmepriv->lock
+*/
+void rtw_indicate_disconnect23a(struct rtw_adapter *padapter)
+{
+       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("+rtw_indicate_disconnect23a\n"));
+
+       _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING|WIFI_UNDER_WPS);
+
+        /* DBG_8723A("clear wps when %s\n", __func__); */
+
+       if (rtw_to_roaming(padapter) > 0)
+               _clr_fwstate_(pmlmepriv, _FW_LINKED);
+
+       if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) ||
+           (rtw_to_roaming(padapter) <= 0)) {
+               rtw_os_indicate_disconnect23a(padapter);
+
+               /* set ips_deny_time to avoid enter IPS before LPS leave */
+               padapter->pwrctrlpriv.ips_deny_time =
+                       jiffies + msecs_to_jiffies(3000);
+
+               _clr_fwstate_(pmlmepriv, _FW_LINKED);
+
+               rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+               rtw_clear_scan_deny(padapter);
+
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       p2p_ps_wk_cmd23a(padapter, P2P_PS_DISABLE, 1);
+#endif /*  CONFIG_8723AU_P2P */
+
+       rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_DISCONNECT, 1);
+
+}
+
+inline void rtw_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted)
+{
+       rtw_os_indicate_scan_done23a(padapter, aborted);
+}
+
+void rtw_scan_abort23a(struct rtw_adapter *adapter)
+{
+       unsigned long start;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+
+       start = jiffies;
+       pmlmeext->scan_abort = true;
+       while (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) &&
+              jiffies_to_msecs(jiffies - start) <= 200) {
+
+               if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
+                       break;
+
+               DBG_8723A(FUNC_NDEV_FMT"fw_state = _FW_UNDER_SURVEY!\n", FUNC_NDEV_ARG(adapter->pnetdev));
+               msleep(20);
+       }
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+               if (!adapter->bDriverStopped && !adapter->bSurpriseRemoved)
+                       DBG_8723A(FUNC_NDEV_FMT"waiting for scan_abort time out!\n", FUNC_NDEV_ARG(adapter->pnetdev));
+               rtw_indicate_scan_done23a(adapter, true);
+       }
+       pmlmeext->scan_abort = false;
+}
+
+static struct sta_info *rtw_joinbss_update_stainfo(struct rtw_adapter *padapter, struct wlan_network *pnetwork)
+{
+       int i;
+       struct sta_info *bmc_sta, *psta = NULL;
+       struct recv_reorder_ctrl *preorder_ctrl;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+
+       psta = rtw_get_stainfo23a(pstapriv, pnetwork->network.MacAddress);
+       if (psta == NULL) {
+               psta = rtw_alloc_stainfo23a(pstapriv, pnetwork->network.MacAddress);
+       }
+
+       if (psta) /* update ptarget_sta */
+       {
+               DBG_8723A("%s\n", __func__);
+
+               psta->aid  = pnetwork->join_res;
+                       psta->mac_id = 0;
+
+               /* sta mode */
+               rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, true);
+
+               /* security related */
+               if (padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X)
+               {
+                       padapter->securitypriv.binstallGrpkey = false;
+                       padapter->securitypriv.busetkipkey = false;
+                       padapter->securitypriv.bgrpkey_handshake = false;
+
+                       psta->ieee8021x_blocked = true;
+                       psta->dot118021XPrivacy = padapter->securitypriv.dot11PrivacyAlgrthm;
+
+                       memset((u8 *)&psta->dot118021x_UncstKey, 0, sizeof (union Keytype));
+
+                       memset((u8 *)&psta->dot11tkiprxmickey, 0, sizeof (union Keytype));
+                       memset((u8 *)&psta->dot11tkiptxmickey, 0, sizeof (union Keytype));
+
+                       memset((u8 *)&psta->dot11txpn, 0, sizeof (union pn48));
+                       memset((u8 *)&psta->dot11rxpn, 0, sizeof (union pn48));
+               }
+
+               /*      Commented by Albert 2012/07/21 */
+               /*      When doing the WPS, the wps_ie_len won't equal to 0 */
+               /*      And the Wi-Fi driver shouldn't allow the data packet to be tramsmitted. */
+               if (padapter->securitypriv.wps_ie_len != 0)
+               {
+                       psta->ieee8021x_blocked = true;
+                       padapter->securitypriv.wps_ie_len = 0;
+               }
+
+               /* for A-MPDU Rx reordering buffer control for bmc_sta & sta_info */
+               /* if A-MPDU Rx is enabled, reseting  rx_ordering_ctrl wstart_b(indicate_seq) to default value = 0xffff */
+               /* todo: check if AP can send A-MPDU packets */
+               for (i = 0; i < 16 ; i++)
+               {
+                       /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */
+                       preorder_ctrl = &psta->recvreorder_ctrl[i];
+                       preorder_ctrl->enable = false;
+                       preorder_ctrl->indicate_seq = 0xffff;
+                       preorder_ctrl->wend_b = 0xffff;
+                       preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */
+               }
+
+               bmc_sta = rtw_get_bcmc_stainfo23a(padapter);
+               if (bmc_sta)
+               {
+                       for (i = 0; i < 16 ; i++)
+                       {
+                               /* preorder_ctrl = &precvpriv->recvreorder_ctrl[i]; */
+                               preorder_ctrl = &bmc_sta->recvreorder_ctrl[i];
+                               preorder_ctrl->enable = false;
+                               preorder_ctrl->indicate_seq = 0xffff;
+                               preorder_ctrl->wend_b = 0xffff;
+                               preorder_ctrl->wsize_b = 64;/* max_ampdu_sz; ex. 32(kbytes) -> wsize_b = 32 */
+                       }
+               }
+
+               /* misc. */
+               update_sta_info23a(padapter, psta);
+
+       }
+
+       return psta;
+}
+
+/* pnetwork : returns from rtw23a_joinbss_event_cb */
+/* ptarget_wlan: found from scanned_queue */
+static void rtw_joinbss_update_network23a(struct rtw_adapter *padapter, struct wlan_network *ptarget_wlan, struct wlan_network  *pnetwork)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_network *cur_network = &pmlmepriv->cur_network;
+
+       DBG_8723A("%s\n", __func__);
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("\nfw_state:%x, BSSID:"MAC_FMT"\n"
+               , get_fwstate(pmlmepriv), MAC_ARG(pnetwork->network.MacAddress)));
+
+       /*  why not use ptarget_wlan?? */
+       memcpy(&cur_network->network, &pnetwork->network, pnetwork->network.Length);
+       /*  some IEs in pnetwork is wrong, so we should use ptarget_wlan IEs */
+       cur_network->network.IELength = ptarget_wlan->network.IELength;
+       memcpy(&cur_network->network.IEs[0], &ptarget_wlan->network.IEs[0], MAX_IE_SZ);
+
+       cur_network->aid = pnetwork->join_res;
+
+       rtw_set_signal_stat_timer(&padapter->recvpriv);
+       padapter->recvpriv.signal_strength = ptarget_wlan->network.PhyInfo.SignalStrength;
+       padapter->recvpriv.signal_qual = ptarget_wlan->network.PhyInfo.SignalQuality;
+       /* the ptarget_wlan->network.Rssi is raw data, we use ptarget_wlan->network.PhyInfo.SignalStrength instead (has scaled) */
+       padapter->recvpriv.rssi = translate_percentage_to_dbm(ptarget_wlan->network.PhyInfo.SignalStrength);
+       DBG_8723A("%s signal_strength:%3u, rssi:%3d, signal_qual:%3u\n",
+                 __func__, padapter->recvpriv.signal_strength,
+                 padapter->recvpriv.rssi, padapter->recvpriv.signal_qual);
+       rtw_set_signal_stat_timer(&padapter->recvpriv);
+
+       /* update fw_state will clr _FW_UNDER_LINKING here indirectly */
+       switch (pnetwork->network.InfrastructureMode) {
+       case Ndis802_11Infrastructure:
+               if (pmlmepriv->fw_state&WIFI_UNDER_WPS)
+                       pmlmepriv->fw_state = WIFI_STATION_STATE|WIFI_UNDER_WPS;
+               else
+                       pmlmepriv->fw_state = WIFI_STATION_STATE;
+               break;
+       case Ndis802_11IBSS:
+               pmlmepriv->fw_state = WIFI_ADHOC_STATE;
+               break;
+       default:
+               pmlmepriv->fw_state = WIFI_NULL_STATE;
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("Invalid network_mode\n"));
+               break;
+       }
+
+       rtw_update_protection23a(padapter, (cur_network->network.IEs) + sizeof (struct ndis_802_11_fixed_ies),
+                                                                       (cur_network->network.IELength));
+
+       rtw_update_ht_cap23a(padapter, cur_network->network.IEs, cur_network->network.IELength);
+}
+
+/* Notes: the fucntion could be > passive_level (the same context as Rx tasklet) */
+/* pnetwork : returns from rtw23a_joinbss_event_cb */
+/* ptarget_wlan: found from scanned_queue */
+/* if join_res > 0, for (fw_state==WIFI_STATION_STATE), we check if  "ptarget_sta" & "ptarget_wlan" exist. */
+/* if join_res > 0, for (fw_state==WIFI_ADHOC_STATE), we only check if "ptarget_wlan" exist. */
+/* if join_res > 0, update "cur_network->network" from "pnetwork->network" if (ptarget_wlan !=NULL). */
+
+void rtw_joinbss_event_prehandle23a(struct rtw_adapter *adapter, u8 *pbuf)
+{
+       static u8 retry=0;
+       struct sta_info *ptarget_sta= NULL, *pcur_sta = NULL;
+       struct  sta_priv *pstapriv = &adapter->stapriv;
+       struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct wlan_network     *pnetwork       = (struct wlan_network *)pbuf;
+       struct wlan_network *cur_network = &pmlmepriv->cur_network;
+       struct wlan_network     *pcur_wlan = NULL, *ptarget_wlan = NULL;
+       unsigned int            the_same_macaddr = false;
+
+       RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("joinbss event call back received with res=%d\n", pnetwork->join_res));
+
+       rtw_get_encrypt_decrypt_from_registrypriv23a(adapter);
+
+       if (pmlmepriv->assoc_ssid.ssid_len == 0) {
+               RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("@@@@@   joinbss event call back  for Any SSid\n"));
+       } else {
+               RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,
+                        ("@@@@@   rtw23a_joinbss_event_cb for SSid:%s\n",
+                         pmlmepriv->assoc_ssid.ssid));
+       }
+
+       if (ether_addr_equal(pnetwork->network.MacAddress,
+                            cur_network->network.MacAddress))
+               the_same_macaddr = true;
+       else
+               the_same_macaddr = false;
+
+       pnetwork->network.Length = get_wlan_bssid_ex_sz(&pnetwork->network);
+       if(pnetwork->network.Length > sizeof(struct wlan_bssid_ex))
+       {
+               RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("\n\n ***joinbss_evt_callback return a wrong bss ***\n\n"));
+               return;
+       }
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("\n rtw23a_joinbss_event_cb !! _enter_critical\n"));
+
+       if(pnetwork->join_res > 0)
+       {
+               spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+               retry = 0;
+               if (check_fwstate(pmlmepriv,_FW_UNDER_LINKING))
+               {
+                       /* s1. find ptarget_wlan */
+                       if(check_fwstate(pmlmepriv, _FW_LINKED))
+                       {
+                               if(the_same_macaddr == true)
+                               {
+                                       ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
+                               }
+                               else
+                               {
+                                       pcur_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
+                                       if(pcur_wlan)   pcur_wlan->fixed = false;
+
+                                       pcur_sta = rtw_get_stainfo23a(pstapriv, cur_network->network.MacAddress);
+                                       if(pcur_sta) {
+                                               spin_lock_bh(&pstapriv->sta_hash_lock);
+                                               rtw_free_stainfo23a(adapter,  pcur_sta);
+                                               spin_unlock_bh(&pstapriv->sta_hash_lock);
+                                       }
+
+                                       ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress);
+                                       if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+                                               if(ptarget_wlan)        ptarget_wlan->fixed = true;
+                                       }
+                               }
+
+                       }
+                       else
+                       {
+                               ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pnetwork->network.MacAddress);
+                               if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+                                       if(ptarget_wlan)        ptarget_wlan->fixed = true;
+                               }
+                       }
+
+                       /* s2. update cur_network */
+                       if(ptarget_wlan)
+                       {
+                               rtw_joinbss_update_network23a(adapter, ptarget_wlan, pnetwork);
+                       }
+                       else
+                       {
+                               RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't find ptarget_wlan when joinbss_event callback\n"));
+                               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+                               goto ignore_joinbss_callback;
+                       }
+
+                       /* s3. find ptarget_sta & update ptarget_sta after update cur_network only for station mode */
+                       if(check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)
+                       {
+                               ptarget_sta = rtw_joinbss_update_stainfo(adapter, pnetwork);
+                               if(ptarget_sta==NULL)
+                               {
+                                       RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't update stainfo when joinbss_event callback\n"));
+                                       spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+                                       goto ignore_joinbss_callback;
+                               }
+                       }
+
+                       /* s4. indicate connect */
+                       if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)
+                       {
+                               rtw_indicate_connect23a(adapter);
+                       } else {
+                                       /* adhoc mode will rtw_indicate_connect23a when rtw_stassoc_event_callback23a */
+                               RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("adhoc mode, fw_state:%x", get_fwstate(pmlmepriv)));
+                       }
+
+                       /* s5. Cancle assoc_timer */
+                       del_timer_sync(&pmlmepriv->assoc_timer);
+
+                       RT_TRACE(_module_rtl871x_mlme_c_,_drv_info_,("Cancle assoc_timer\n"));
+               } else {
+                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                                ("rtw23a_joinbss_event_cb err: fw_state:%x",
+                                get_fwstate(pmlmepriv)));
+                       spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+                       goto ignore_joinbss_callback;
+               }
+               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+       } else if(pnetwork->join_res == -4) {
+               rtw_reset_securitypriv23a(adapter);
+               mod_timer(&pmlmepriv->assoc_timer,
+                         jiffies + msecs_to_jiffies(1));
+
+               /* rtw_free_assoc_resources23a(adapter, 1); */
+
+               if((check_fwstate(pmlmepriv, _FW_UNDER_LINKING))) {
+                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                                ("fail! clear _FW_UNDER_LINKING ^^^fw_state=%x\n",
+                                get_fwstate(pmlmepriv)));
+                       _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+               }
+
+       } else {
+               /* if join_res < 0 (join fails), then try again */
+               mod_timer(&pmlmepriv->assoc_timer,
+                         jiffies + msecs_to_jiffies(1));
+               _clr_fwstate_(pmlmepriv, _FW_UNDER_LINKING);
+       }
+
+ignore_joinbss_callback:
+
+       spin_unlock_bh(&pmlmepriv->lock);
+}
+
+void rtw23a_joinbss_event_cb(struct rtw_adapter *adapter, u8 *pbuf)
+{
+       struct wlan_network     *pnetwork       = (struct wlan_network *)pbuf;
+
+       mlmeext_joinbss_event_callback23a(adapter, pnetwork->join_res);
+
+       rtw_os_xmit_schedule23a(adapter);
+
+}
+
+/* FOR AP , AD-HOC mode */
+void rtw_stassoc_hw_rpt23a(struct rtw_adapter *adapter, struct sta_info *psta)
+{
+       u16 media_status;
+
+       if (psta == NULL)       return;
+
+       media_status = (psta->mac_id<<8)|1; /*   MACID|OPMODE:1 connect */
+       rtw_hal_set_hwreg23a(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
+}
+
+void rtw_stassoc_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf)
+{
+       struct sta_info *psta;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct stassoc_event    *pstassoc       = (struct stassoc_event*)pbuf;
+       struct wlan_network *cur_network = &pmlmepriv->cur_network;
+       struct wlan_network     *ptarget_wlan = NULL;
+
+       if(rtw_access_ctrl23a(adapter, pstassoc->macaddr) == false)
+               return;
+
+#ifdef CONFIG_8723AU_AP_MODE
+       if(check_fwstate(pmlmepriv, WIFI_AP_STATE))
+       {
+               psta = rtw_get_stainfo23a(&adapter->stapriv, pstassoc->macaddr);
+               if (psta) {
+                       /* bss_cap_update_on_sta_join23a(adapter, psta); */
+                       /* sta_info_update23a(adapter, psta); */
+                       ap_sta_info_defer_update23a(adapter, psta);
+
+                       rtw_stassoc_hw_rpt23a(adapter,psta);
+               }
+               return;
+       }
+#endif
+       /* for AD-HOC mode */
+       psta = rtw_get_stainfo23a(&adapter->stapriv, pstassoc->macaddr);
+       if (psta != NULL) {
+               /* the sta have been in sta_info_queue => do nothing */
+               RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Error: rtw_stassoc_event_callback23a: sta has been in sta_hash_queue\n"));
+               return; /* between drv has received this event before and  fw have not yet to set key to CAM_ENTRY) */
+       }
+
+       psta = rtw_alloc_stainfo23a(&adapter->stapriv, pstassoc->macaddr);
+       if (psta == NULL) {
+               RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("Can't alloc sta_info when rtw_stassoc_event_callback23a\n"));
+               return;
+       }
+
+       /* to do : init sta_info variable */
+       psta->qos_option = 0;
+       psta->mac_id = (uint)pstassoc->cam_id;
+       /* psta->aid = (uint)pstassoc->cam_id; */
+       DBG_8723A("%s\n",__func__);
+       /* for ad-hoc mode */
+       rtw_hal_set_odm_var23a(adapter,HAL_ODM_STA_INFO,psta,true);
+
+       rtw_stassoc_hw_rpt23a(adapter,psta);
+
+       if(adapter->securitypriv.dot11AuthAlgrthm==dot11AuthAlgrthm_8021X)
+               psta->dot118021XPrivacy = adapter->securitypriv.dot11PrivacyAlgrthm;
+
+       psta->ieee8021x_blocked = false;
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       if ( (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE)==true ) ||
+               (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)==true ) )
+       {
+               if(adapter->stapriv.asoc_sta_count== 2)
+               {
+                       spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+                       ptarget_wlan = rtw_find_network23a(&pmlmepriv->scanned_queue, cur_network->network.MacAddress);
+                       if(ptarget_wlan)        ptarget_wlan->fixed = true;
+                       spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+                       /*  a sta + bc/mc_stainfo (not Ibss_stainfo) */
+                       rtw_indicate_connect23a(adapter);
+               }
+       }
+
+       spin_unlock_bh(&pmlmepriv->lock);
+
+       mlmeext_sta_add_event_callback23a(adapter, psta);
+}
+
+void rtw_stadel_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf)
+{
+       int mac_id=-1;
+       struct sta_info *psta;
+       struct wlan_network* pwlan = NULL;
+       struct wlan_bssid_ex    *pdev_network=NULL;
+       u8* pibss = NULL;
+       struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct  stadel_event *pstadel   = (struct stadel_event*)pbuf;
+       struct  sta_priv *pstapriv = &adapter->stapriv;
+       struct wlan_network *tgt_network = &pmlmepriv->cur_network;
+
+       psta = rtw_get_stainfo23a(&adapter->stapriv, pstadel->macaddr);
+       if(psta)
+               mac_id = psta->mac_id;
+       else
+               mac_id = pstadel->mac_id;
+
+       DBG_8723A("%s(mac_id=%d)=" MAC_FMT "\n", __func__, mac_id, MAC_ARG(pstadel->macaddr));
+
+       if(mac_id>=0) {
+               u16 media_status;
+               media_status = (mac_id<<8)|0; /*   MACID|OPMODE:0 means disconnect */
+               /* for STA,AP,ADHOC mode, report disconnect stauts to FW */
+               rtw_hal_set_hwreg23a(adapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
+       }
+
+        if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+        {
+               return;
+        }
+
+       mlmeext_sta_del_event_callback23a(adapter);
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       if (check_fwstate(pmlmepriv, WIFI_STATION_STATE))
+       {
+               if (rtw_to_roaming(adapter) > 0)
+                       pmlmepriv->to_roaming--; /* this stadel_event is caused by roaming, decrease to_roaming */
+               else if (rtw_to_roaming(adapter) == 0)
+                       rtw_set_roaming(adapter, adapter->registrypriv.max_roaming_times);
+               if (*((unsigned short *)(pstadel->rsvd)) != WLAN_REASON_EXPIRATION_CHK)
+                       rtw_set_roaming(adapter, 0); /* don't roam */
+
+               rtw_free_uc_swdec_pending_queue23a(adapter);
+
+               rtw_free_assoc_resources23a(adapter, 1);
+               rtw_indicate_disconnect23a(adapter);
+               spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+               /*  remove the network entry in scanned_queue */
+               pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+               if (pwlan) {
+                       pwlan->fixed = false;
+                       rtw_free_network_nolock(pmlmepriv, pwlan);
+               }
+               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+
+               _rtw23a_roaming(adapter, tgt_network);
+       }
+
+       if (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
+             check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))
+       {
+
+               spin_lock_bh(&pstapriv->sta_hash_lock);
+               rtw_free_stainfo23a(adapter,  psta);
+               spin_unlock_bh(&pstapriv->sta_hash_lock);
+
+               if (adapter->stapriv.asoc_sta_count == 1) /* a sta + bc/mc_stainfo (not Ibss_stainfo) */
+               {
+                       spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+                       /* free old ibss network */
+                       /* pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, pstadel->macaddr); */
+                       pwlan = rtw_find_network23a(&pmlmepriv->scanned_queue, tgt_network->network.MacAddress);
+                       if (pwlan)
+                       {
+                               pwlan->fixed = false;
+                               rtw_free_network_nolock(pmlmepriv, pwlan);
+                       }
+                       spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+                       /* re-create ibss */
+                       pdev_network = &adapter->registrypriv.dev_network;
+                       pibss = adapter->registrypriv.dev_network.MacAddress;
+
+                       memcpy(pdev_network, &tgt_network->network, get_wlan_bssid_ex_sz(&tgt_network->network));
+
+                       memset(&pdev_network->Ssid, 0,
+                              sizeof(struct cfg80211_ssid));
+                       memcpy(&pdev_network->Ssid, &pmlmepriv->assoc_ssid,
+                              sizeof(struct cfg80211_ssid));
+
+                       rtw_update_registrypriv_dev_network23a(adapter);
+
+                       rtw_generate_random_ibss23a(pibss);
+
+                       if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE))
+                       {
+                               set_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE);
+                               _clr_fwstate_(pmlmepriv, WIFI_ADHOC_STATE);
+                       }
+
+                       if (rtw_createbss_cmd23a(adapter)!= _SUCCESS)
+                       {
+
+                               RT_TRACE(_module_rtl871x_ioctl_set_c_, _drv_err_, ("***Error =>stadel_event_callback: rtw_createbss_cmd23a status FAIL***\n "));
+
+                       }
+
+               }
+
+       }
+
+       spin_unlock_bh(&pmlmepriv->lock);
+
+}
+
+void rtw_cpwm_event_callback23a(struct rtw_adapter *padapter, u8 *pbuf)
+{
+
+       RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,("+rtw_cpwm_event_callback23a !!!\n"));
+
+}
+
+/*
+* rtw23a_join_to_handler - Timeout/faliure handler for CMD JoinBss
+* @adapter: pointer to _adapter structure
+*/
+void rtw23a_join_to_handler (unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       int do_join_r;
+
+       DBG_8723A("%s, fw_state=%x\n", __func__, get_fwstate(pmlmepriv));
+
+       if(adapter->bDriverStopped ||adapter->bSurpriseRemoved)
+               return;
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       if (rtw_to_roaming(adapter) > 0) { /* join timeout caused by roaming */
+               while(1) {
+                       pmlmepriv->to_roaming--;
+                       if (rtw_to_roaming(adapter) != 0) { /* try another */
+                               DBG_8723A("%s try another roaming\n", __func__);
+                               if (_SUCCESS!= (do_join_r = rtw_do_join23a(adapter))) {
+                                       DBG_8723A("%s roaming do_join return %d\n", __func__ , do_join_r);
+                                       continue;
+                               }
+                               break;
+                       } else {
+                               DBG_8723A("%s We've try roaming but fail\n", __func__);
+                               rtw_indicate_disconnect23a(adapter);
+                               break;
+                       }
+               }
+       } else {
+               rtw_indicate_disconnect23a(adapter);
+               free_scanqueue(pmlmepriv);/*  */
+
+               /* indicate disconnect for the case that join_timeout and check_fwstate != FW_LINKED */
+               rtw_cfg80211_indicate_disconnect(adapter);
+       }
+
+       spin_unlock_bh(&pmlmepriv->lock);
+
+}
+
+/*
+* rtw_scan_timeout_handler23a - Timeout/Faliure handler for CMD SiteSurvey
+* @data: pointer to _adapter structure
+*/
+void rtw_scan_timeout_handler23a(unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       struct  mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+       DBG_8723A(FUNC_ADPT_FMT" fw_state =%x\n", FUNC_ADPT_ARG(adapter), get_fwstate(pmlmepriv));
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY);
+
+       spin_unlock_bh(&pmlmepriv->lock);
+
+       rtw_indicate_scan_done23a(adapter, true);
+}
+
+static void rtw_auto_scan_handler(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       /* auto site survey per 60sec */
+       if (pmlmepriv->scan_interval > 0) {
+               pmlmepriv->scan_interval--;
+               if (pmlmepriv->scan_interval == 0) {
+                       DBG_8723A("%s\n", __func__);
+                       rtw_set_802_11_bssid23a_list_scan(padapter, NULL, 0);
+                       pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
+               }
+       }
+}
+
+void rtw_dynamic_check_timer_handler(unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       struct registry_priv *pregistrypriv = &adapter->registrypriv;
+
+       if (adapter->hw_init_completed == false)
+               goto out;
+
+       if ((adapter->bDriverStopped == true)||(adapter->bSurpriseRemoved == true))
+               goto out;
+
+       if (adapter->net_closed == true)
+               goto out;
+
+       rtw_dynamic_chk_wk_cmd23a(adapter);
+
+       if (pregistrypriv->wifi_spec == 1)
+       {
+#ifdef CONFIG_8723AU_P2P
+               struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+               if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+#endif
+               {
+                       /* auto site survey */
+                       rtw_auto_scan_handler(adapter);
+               }
+       }
+out:
+       mod_timer(&adapter->mlmepriv.dynamic_chk_timer,
+                 jiffies + msecs_to_jiffies(2000));
+}
+
+inline bool rtw_is_scan_deny(struct rtw_adapter *adapter)
+{
+       struct mlme_priv *mlmepriv = &adapter->mlmepriv;
+       return (atomic_read(&mlmepriv->set_scan_deny) != 0) ? true : false;
+}
+
+void rtw_clear_scan_deny(struct rtw_adapter *adapter)
+{
+       struct mlme_priv *mlmepriv = &adapter->mlmepriv;
+       atomic_set(&mlmepriv->set_scan_deny, 0);
+       if (0)
+       DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter));
+}
+
+void rtw_set_scan_deny_timer_hdl(unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       rtw_clear_scan_deny(adapter);
+}
+
+void rtw_set_scan_deny(struct rtw_adapter *adapter, u32 ms)
+{
+       struct mlme_priv *mlmepriv = &adapter->mlmepriv;
+
+       if (0)
+       DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(adapter));
+       atomic_set(&mlmepriv->set_scan_deny, 1);
+       mod_timer(&mlmepriv->set_scan_deny_timer,
+                 jiffies + msecs_to_jiffies(ms));
+
+}
+
+#if defined(IEEE80211_SCAN_RESULT_EXPIRE)
+#define RTW_SCAN_RESULT_EXPIRE IEEE80211_SCAN_RESULT_EXPIRE/HZ*1000 -1000 /* 3000 -1000 */
+#else
+#define RTW_SCAN_RESULT_EXPIRE 2000
+#endif
+
+/*
+* Select a new join candidate from the original @param candidate and @param competitor
+* @return true: candidate is updated
+* @return false: candidate is not updated
+*/
+static int rtw_check_join_candidate(struct mlme_priv *pmlmepriv
+       , struct wlan_network **candidate, struct wlan_network *competitor)
+{
+       int updated = false;
+       struct rtw_adapter *adapter = container_of(pmlmepriv, struct rtw_adapter, mlmepriv);
+
+       /* check bssid, if needed */
+       if (pmlmepriv->assoc_by_bssid == true) {
+               if (!ether_addr_equal(competitor->network.MacAddress,
+                                     pmlmepriv->assoc_bssid))
+                       goto exit;
+       }
+
+       /* check ssid, if needed */
+       if (pmlmepriv->assoc_ssid.ssid_len) {
+               if (competitor->network.Ssid.ssid_len !=
+                   pmlmepriv->assoc_ssid.ssid_len ||
+                   memcmp(competitor->network.Ssid.ssid,
+                          pmlmepriv->assoc_ssid.ssid,
+                          pmlmepriv->assoc_ssid.ssid_len))
+                       goto exit;
+       }
+
+       if (rtw_is_desired_network(adapter, competitor)  == false)
+               goto exit;
+
+       if (rtw_to_roaming(adapter) > 0) {
+               unsigned int passed;
+
+               passed = jiffies_to_msecs(jiffies - competitor->last_scanned);
+               if (passed >= RTW_SCAN_RESULT_EXPIRE ||
+                   is_same_ess(&competitor->network,
+                               &pmlmepriv->cur_network.network) == false)
+                       goto exit;
+       }
+
+       if (*candidate == NULL ||(*candidate)->network.Rssi<competitor->network.Rssi) {
+               *candidate = competitor;
+               updated = true;
+       }
+
+       if (updated) {
+               DBG_8723A("[by_bssid:%u][assoc_ssid:%s][to_roaming:%u] new candidate: %s("MAC_FMT") rssi:%d\n",
+                       pmlmepriv->assoc_by_bssid,
+                       pmlmepriv->assoc_ssid.ssid,
+                       rtw_to_roaming(adapter),
+                       (*candidate)->network.Ssid.ssid,
+                       MAC_ARG((*candidate)->network.MacAddress),
+                       (int)(*candidate)->network.Rssi);
+       }
+
+exit:
+       return updated;
+}
+
+/*
+Calling context:
+The caller of the sub-routine will be in critical section...
+
+The caller must hold the following spinlock
+
+pmlmepriv->lock
+
+*/
+
+int rtw_select_and_join_from_scanned_queue23a(struct mlme_priv *pmlmepriv)
+{
+       int ret;
+       struct list_head *phead, *plist, *ptmp;
+       struct rtw_adapter *adapter;
+       struct rtw_queue *queue = &pmlmepriv->scanned_queue;
+       struct  wlan_network    *pnetwork = NULL;
+       struct  wlan_network    *candidate = NULL;
+
+       spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+       phead = get_list_head(queue);
+       adapter = pmlmepriv->nic_hdl;
+
+       list_for_each_safe(plist, ptmp, phead) {
+               pnetwork = container_of(plist, struct wlan_network, list);
+               if (!pnetwork) {
+                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                                ("%s return _FAIL:(pnetwork == NULL)\n",
+                                 __func__));
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               rtw_check_join_candidate(pmlmepriv, &candidate, pnetwork);
+       }
+
+       if (!candidate) {
+               DBG_8723A("%s: return _FAIL(candidate == NULL)\n", __func__);
+               ret = _FAIL;
+               goto exit;
+       } else {
+               DBG_8723A("%s: candidate: %s("MAC_FMT", ch:%u)\n", __func__,
+                         candidate->network.Ssid.ssid,
+                         MAC_ARG(candidate->network.MacAddress),
+                         candidate->network.Configuration.DSConfig);
+       }
+
+       /*  check for situation of  _FW_LINKED */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true) {
+               DBG_8723A("%s: _FW_LINKED while ask_for_joinbss!!!\n",
+                         __func__);
+
+               rtw_disassoc_cmd23a(adapter, 0, true);
+               rtw_indicate_disconnect23a(adapter);
+               rtw_free_assoc_resources23a(adapter, 0);
+       }
+       set_fwstate(pmlmepriv, _FW_UNDER_LINKING);
+       ret = rtw_joinbss_cmd23a(adapter, candidate);
+
+exit:
+       spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+
+       return ret;
+}
+
+int rtw_set_auth23a(struct rtw_adapter * adapter,
+                struct security_priv *psecuritypriv)
+{
+       struct cmd_obj* pcmd;
+       struct setauth_parm *psetauthparm;
+       struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+       int res = _SUCCESS;
+
+       pcmd = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       if (!pcmd) {
+               res = _FAIL;  /* try again */
+               goto exit;
+       }
+
+       psetauthparm = (struct setauth_parm*)
+               kzalloc(sizeof(struct setauth_parm), GFP_KERNEL);
+       if (!psetauthparm) {
+               kfree(pcmd);
+               res = _FAIL;
+               goto exit;
+       }
+
+       psetauthparm->mode = (unsigned char)psecuritypriv->dot11AuthAlgrthm;
+
+       pcmd->cmdcode = _SetAuth_CMD_;
+       pcmd->parmbuf = (unsigned char *)psetauthparm;
+       pcmd->cmdsz =  (sizeof(struct setauth_parm));
+       pcmd->rsp = NULL;
+       pcmd->rspsz = 0;
+
+       INIT_LIST_HEAD(&pcmd->list);
+
+       RT_TRACE(_module_rtl871x_mlme_c_,_drv_err_,
+                ("after enqueue set_auth_cmd, auth_mode=%x\n",
+                 psecuritypriv->dot11AuthAlgrthm));
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, pcmd);
+
+exit:
+
+       return res;
+}
+
+int rtw_set_key23a(struct rtw_adapter *adapter,
+               struct security_priv *psecuritypriv, int keyid, u8 set_tx)
+{
+       u8 keylen;
+       struct cmd_obj *pcmd;
+       struct setkey_parm *psetkeyparm;
+       struct cmd_priv *pcmdpriv = &adapter->cmdpriv;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       int res = _SUCCESS;
+
+       pcmd = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       if (!pcmd) {
+               res = _FAIL;  /* try again */
+               goto exit;
+       }
+       psetkeyparm = kzalloc(sizeof(struct setkey_parm), GFP_KERNEL);
+       if (!psetkeyparm) {
+               kfree(pcmd);
+               res = _FAIL;
+               goto exit;
+       }
+
+       if (psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) {
+               psetkeyparm->algorithm = (unsigned char)
+                       psecuritypriv->dot118021XGrpPrivacy;
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                        ("\n rtw_set_key23a: psetkeyparm->algorithm = (unsigned "
+                         "char)psecuritypriv->dot118021XGrpPrivacy =%d\n",
+                         psetkeyparm->algorithm));
+       } else {
+               psetkeyparm->algorithm = (u8)psecuritypriv->dot11PrivacyAlgrthm;
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                        ("\n rtw_set_key23a: psetkeyparm->algorithm = (u8)"
+                         "psecuritypriv->dot11PrivacyAlgrthm =%d\n",
+                         psetkeyparm->algorithm));
+       }
+       psetkeyparm->keyid = (u8)keyid;/* 0~3 */
+       psetkeyparm->set_tx = set_tx;
+       if (is_wep_enc(psetkeyparm->algorithm))
+               pmlmepriv->key_mask |= CHKBIT(psetkeyparm->keyid);
+
+       DBG_8723A("==> rtw_set_key23a algorithm(%x), keyid(%x), key_mask(%x)\n",
+                 psetkeyparm->algorithm, psetkeyparm->keyid,
+                 pmlmepriv->key_mask);
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                ("\n rtw_set_key23a: psetkeyparm->algorithm =%d psetkeyparm->"
+                 "keyid = (u8)keyid =%d\n", psetkeyparm->algorithm, keyid));
+
+       switch (psetkeyparm->algorithm) {
+       case _WEP40_:
+               keylen = 5;
+               memcpy(&psetkeyparm->key[0],
+                      &psecuritypriv->dot11DefKey[keyid].skey[0], keylen);
+               break;
+       case _WEP104_:
+               keylen = 13;
+               memcpy(&psetkeyparm->key[0],
+                      &psecuritypriv->dot11DefKey[keyid].skey[0], keylen);
+               break;
+       case _TKIP_:
+               keylen = 16;
+               memcpy(&psetkeyparm->key,
+                      &psecuritypriv->dot118021XGrpKey[keyid], keylen);
+               psetkeyparm->grpkey = 1;
+               break;
+       case _AES_:
+               keylen = 16;
+               memcpy(&psetkeyparm->key,
+                      &psecuritypriv->dot118021XGrpKey[keyid], keylen);
+               psetkeyparm->grpkey = 1;
+               break;
+       default:
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                        ("\n rtw_set_key23a:psecuritypriv->dot11PrivacyAlgrthm = "
+                         "%x (must be 1 or 2 or 4 or 5)\n",
+                         psecuritypriv->dot11PrivacyAlgrthm));
+               res = _FAIL;
+               kfree(pcmd);
+               kfree(psetkeyparm);
+               goto exit;
+       }
+
+       pcmd->cmdcode = _SetKey_CMD_;
+       pcmd->parmbuf = (u8 *)psetkeyparm;
+       pcmd->cmdsz =  (sizeof(struct setkey_parm));
+       pcmd->rsp = NULL;
+       pcmd->rspsz = 0;
+
+       INIT_LIST_HEAD(&pcmd->list);
+
+       /* sema_init(&pcmd->cmd_sem, 0); */
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, pcmd);
+
+exit:
+
+       return res;
+}
+
+/* adjust IEs for rtw_joinbss_cmd23a in WMM */
+int rtw_restruct_wmm_ie23a(struct rtw_adapter *adapter, u8 *in_ie,
+                       u8 *out_ie, uint in_len, uint initial_out_len)
+{
+       unsigned int ielength = 0;
+       unsigned int i, j;
+
+       i = 12; /* after the fixed IE */
+       while(i < in_len) {
+               ielength = initial_out_len;
+
+               /* WMM element ID and OUI */
+               if (in_ie[i] == 0xDD && in_ie[i + 2] == 0x00 &&
+                   in_ie[i + 3] == 0x50 && in_ie[i + 4] == 0xF2 &&
+                   in_ie[i + 5] == 0x02 && i+5 < in_len) {
+
+                       /* Append WMM IE to the last index of out_ie */
+                        for (j = i; j < i + 9; j++) {
+                               out_ie[ielength] = in_ie[j];
+                               ielength++;
+                        }
+                        out_ie[initial_out_len + 1] = 0x07;
+                        out_ie[initial_out_len + 6] = 0x00;
+                        out_ie[initial_out_len + 8] = 0x00;
+
+                       break;
+               }
+
+               i += (in_ie[i + 1] + 2); /*  to the next IE element */
+       }
+
+       return ielength;
+}
+
+/*  */
+/*  Ported from 8185: IsInPreAuthKeyList().
+    (Renamed from SecIsInPreAuthKeyList(), 2006-10-13.) */
+/*  Added by Annie, 2006-05-07. */
+/*  */
+/*  Search by BSSID, */
+/*  Return Value: */
+/*             -1      :if there is no pre-auth key in the  table */
+/*             >= 0    :if there is pre-auth key, and   return the entry id */
+/*  */
+/*  */
+
+static int SecIsInPMKIDList(struct rtw_adapter *Adapter, u8 *bssid)
+{
+       struct security_priv *psecuritypriv = &Adapter->securitypriv;
+       int i = 0;
+
+       do {
+               if (psecuritypriv->PMKIDList[i].bUsed &&
+                    ether_addr_equal(psecuritypriv->PMKIDList[i].Bssid, bssid)) {
+                       break;
+               } else {
+                       i++;
+                       /* continue; */
+               }
+       } while(i < NUM_PMKID_CACHE);
+
+       if (i == NUM_PMKID_CACHE) {
+               i = -1;/*  Could not find. */
+       } else {
+               /*  There is one Pre-Authentication Key for
+                   the specific BSSID. */
+       }
+
+       return i;
+}
+
+/*  */
+/*  Check the RSN IE length */
+/*  If the RSN IE length <= 20, the RSN IE didn't include
+    the PMKID information */
+/*  0-11th element in the array are the fixed IE */
+/*  12th element in the array is the IE */
+/*  13th element in the array is the IE length */
+/*  */
+
+static int rtw_append_pmkid(struct rtw_adapter *Adapter, int iEntry,
+                           u8 *ie, uint ie_len)
+{
+       struct security_priv *psecuritypriv = &Adapter->securitypriv;
+
+       if (ie[13] <= 20) {
+               /*  The RSN IE didn't include the PMK ID,
+                   append the PMK information */
+                       ie[ie_len] = 1;
+                       ie_len++;
+                       ie[ie_len] = 0; /* PMKID count = 0x0100 */
+                       ie_len++;
+                       memcpy(&ie[ie_len],
+                              &psecuritypriv->PMKIDList[iEntry].PMKID, 16);
+
+                       ie_len += 16;
+                       ie[13] += 18;/* PMKID length = 2+16 */
+       }
+       return ie_len;
+}
+int rtw_restruct_sec_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie,
+                       uint in_len)
+{
+       u8 authmode;
+       uint ielength;
+       int iEntry;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct security_priv *psecuritypriv = &adapter->securitypriv;
+       uint ndisauthmode = psecuritypriv->ndisauthtype;
+       uint ndissecuritytype = psecuritypriv->ndisencryptstatus;
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+                ("+rtw_restruct_sec_ie23a: ndisauthmode=%d ndissecuritytype=%d\n",
+                 ndisauthmode, ndissecuritytype));
+
+       /* copy fixed ie only */
+       memcpy(out_ie, in_ie, 12);
+       ielength = 12;
+       if ((ndisauthmode==Ndis802_11AuthModeWPA) ||
+           (ndisauthmode==Ndis802_11AuthModeWPAPSK))
+               authmode=_WPA_IE_ID_;
+       if ((ndisauthmode==Ndis802_11AuthModeWPA2) ||
+           (ndisauthmode==Ndis802_11AuthModeWPA2PSK))
+               authmode=_WPA2_IE_ID_;
+
+       if (check_fwstate(pmlmepriv, WIFI_UNDER_WPS)) {
+               memcpy(out_ie + ielength, psecuritypriv->wps_ie,
+                      psecuritypriv->wps_ie_len);
+
+               ielength += psecuritypriv->wps_ie_len;
+       } else if ((authmode==_WPA_IE_ID_) || (authmode==_WPA2_IE_ID_)) {
+               /* copy RSN or SSN */
+               memcpy(&out_ie[ielength], &psecuritypriv->supplicant_ie[0],
+                      psecuritypriv->supplicant_ie[1] + 2);
+               ielength += psecuritypriv->supplicant_ie[1] + 2;
+               rtw_report_sec_ie23a(adapter, authmode,
+                                 psecuritypriv->supplicant_ie);
+       }
+
+       iEntry = SecIsInPMKIDList(adapter, pmlmepriv->assoc_bssid);
+       if (iEntry < 0) {
+               return ielength;
+       } else {
+               if (authmode == _WPA2_IE_ID_) {
+                       ielength=rtw_append_pmkid(adapter, iEntry,
+                                                 out_ie, ielength);
+               }
+       }
+
+       return ielength;
+}
+
+void rtw_init_registrypriv_dev_network23a(struct rtw_adapter* adapter)
+{
+       struct registry_priv* pregistrypriv = &adapter->registrypriv;
+       struct eeprom_priv* peepriv = &adapter->eeprompriv;
+       struct wlan_bssid_ex    *pdev_network = &pregistrypriv->dev_network;
+       u8 *myhwaddr = myid(peepriv);
+
+       ether_addr_copy(pdev_network->MacAddress, myhwaddr);
+
+       memcpy(&pdev_network->Ssid, &pregistrypriv->ssid,
+              sizeof(struct cfg80211_ssid));
+
+       pdev_network->Configuration.Length=sizeof(struct ndis_802_11_config);
+       pdev_network->Configuration.BeaconPeriod = 100;
+       pdev_network->Configuration.FHConfig.Length = 0;
+       pdev_network->Configuration.FHConfig.HopPattern = 0;
+       pdev_network->Configuration.FHConfig.HopSet = 0;
+       pdev_network->Configuration.FHConfig.DwellTime = 0;
+
+}
+
+void rtw_update_registrypriv_dev_network23a(struct rtw_adapter* adapter)
+{
+       int sz = 0;
+       struct registry_priv* pregistrypriv = &adapter->registrypriv;
+       struct wlan_bssid_ex *pdev_network = &pregistrypriv->dev_network;
+       struct security_priv *psecuritypriv = &adapter->securitypriv;
+       struct wlan_network *cur_network = &adapter->mlmepriv.cur_network;
+       /* struct       xmit_priv       *pxmitpriv = &adapter->xmitpriv; */
+
+       pdev_network->Privacy =
+               (psecuritypriv->dot11PrivacyAlgrthm > 0 ? 1 : 0);
+
+       pdev_network->Rssi = 0;
+
+       switch (pregistrypriv->wireless_mode)
+       {
+       case WIRELESS_11B:
+               pdev_network->NetworkTypeInUse = Ndis802_11DS;
+               break;
+       case WIRELESS_11G:
+       case WIRELESS_11BG:
+       case WIRELESS_11_24N:
+       case WIRELESS_11G_24N:
+       case WIRELESS_11BG_24N:
+               pdev_network->NetworkTypeInUse = Ndis802_11OFDM24;
+               break;
+       case WIRELESS_11A:
+       case WIRELESS_11A_5N:
+               pdev_network->NetworkTypeInUse = Ndis802_11OFDM5;
+               break;
+       case WIRELESS_11ABGN:
+               if (pregistrypriv->channel > 14)
+                       pdev_network->NetworkTypeInUse = Ndis802_11OFDM5;
+               else
+                       pdev_network->NetworkTypeInUse = Ndis802_11OFDM24;
+               break;
+       default :
+               /*  TODO */
+               break;
+       }
+
+       pdev_network->Configuration.DSConfig = pregistrypriv->channel;
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                ("pregistrypriv->channel =%d, pdev_network->Configuration."
+                 "DSConfig = 0x%x\n", pregistrypriv->channel,
+                 pdev_network->Configuration.DSConfig));
+
+       if (cur_network->network.InfrastructureMode == Ndis802_11IBSS)
+               pdev_network->Configuration.ATIMWindow = 0;
+
+       pdev_network->InfrastructureMode =
+               cur_network->network.InfrastructureMode;
+
+       /*  1. Supported rates */
+       /*  2. IE */
+
+       sz = rtw_generate_ie23a(pregistrypriv);
+
+       pdev_network->IELength = sz;
+
+       pdev_network->Length =
+               get_wlan_bssid_ex_sz((struct wlan_bssid_ex *)pdev_network);
+
+       /* notes: translate IELength & Length after assign the
+          Length to cmdsz in createbss_cmd(); */
+       /* pdev_network->IELength = cpu_to_le32(sz); */
+
+}
+
+void rtw_get_encrypt_decrypt_from_registrypriv23a(struct rtw_adapter* adapter)
+{
+
+}
+
+/* the fucntion is at passive_level */
+void rtw_joinbss_reset23a(struct rtw_adapter *padapter)
+{
+       u8 threshold;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+
+       /* todo: if you want to do something io/reg/hw setting
+          before join_bss, please add code here */
+
+       pmlmepriv->num_FortyMHzIntolerant = 0;
+
+       pmlmepriv->num_sta_no_ht = 0;
+
+       phtpriv->ampdu_enable = false;/* reset to disabled */
+
+       /*  TH = 1 => means that invalidate usb rx aggregation */
+       /*  TH = 0 => means that validate usb rx aggregation, use init value. */
+       if (phtpriv->ht_option) {
+               if (padapter->registrypriv.wifi_spec == 1)
+                       threshold = 1;
+               else
+                       threshold = 0;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH,
+                                 (u8 *)(&threshold));
+       } else {
+               threshold = 1;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH,
+                                 (u8 *)(&threshold));
+       }
+}
+
+/* the fucntion is >= passive_level */
+unsigned int rtw_restructure_ht_ie23a(struct rtw_adapter *padapter, u8 *in_ie,
+                                  u8 *out_ie, uint in_len, uint *pout_len)
+{
+       u32 ielen, out_len;
+       int max_rx_ampdu_factor;
+       unsigned char *p, *pframe;
+       struct ieee80211_ht_cap ht_capie;
+       unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01, 0x00};
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+       struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+
+       phtpriv->ht_option = false;
+
+       p = rtw_get_ie23a(in_ie + 12, _HT_CAPABILITY_IE_, &ielen, in_len - 12);
+
+       if (p && ielen > 0) {
+               u32 rx_packet_offset, max_recvbuf_sz;
+               if (pqospriv->qos_option == 0) {
+                       out_len = *pout_len;
+                       pframe = rtw_set_ie23a(out_ie + out_len,
+                                           _VENDOR_SPECIFIC_IE_,
+                                           _WMM_IE_Length_, WMM_IE, pout_len);
+
+                       pqospriv->qos_option = 1;
+               }
+
+               out_len = *pout_len;
+
+               memset(&ht_capie, 0, sizeof(struct ieee80211_ht_cap));
+
+               ht_capie.cap_info = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                       IEEE80211_HT_CAP_SGI_20 | IEEE80211_HT_CAP_SGI_40 |
+                       IEEE80211_HT_CAP_TX_STBC | IEEE80211_HT_CAP_DSSSCCK40;
+
+               rtw_hal_get_def_var23a(padapter, HAL_DEF_RX_PACKET_OFFSET,
+                                   &rx_packet_offset);
+               rtw_hal_get_def_var23a(padapter, HAL_DEF_MAX_RECVBUF_SZ,
+                                   &max_recvbuf_sz);
+
+               rtw_hal_get_def_var23a(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR,
+                                   &max_rx_ampdu_factor);
+               ht_capie.ampdu_params_info = max_rx_ampdu_factor & 0x03;
+
+               if (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)
+                       ht_capie.ampdu_params_info |=
+                               (IEEE80211_HT_AMPDU_PARM_DENSITY& (0x07 << 2));
+               else
+                       ht_capie.ampdu_params_info |=
+                               (IEEE80211_HT_AMPDU_PARM_DENSITY & 0x00);
+
+               pframe = rtw_set_ie23a(out_ie + out_len, _HT_CAPABILITY_IE_,
+                                   sizeof(struct ieee80211_ht_cap),
+                                   (unsigned char*)&ht_capie, pout_len);
+
+               phtpriv->ht_option = true;
+
+               p = rtw_get_ie23a(in_ie + 12, _HT_ADD_INFO_IE_, &ielen, in_len-12);
+               if (p && (ielen == sizeof(struct ieee80211_ht_addt_info))) {
+                       out_len = *pout_len;
+                       pframe = rtw_set_ie23a(out_ie + out_len, _HT_ADD_INFO_IE_,
+                                           ielen, p + 2 , pout_len);
+               }
+       }
+
+       return phtpriv->ht_option;
+}
+
+/* the fucntion is > passive_level (in critical_section) */
+void rtw_update_ht_cap23a(struct rtw_adapter *padapter, u8 *pie, uint ie_len)
+{
+       u8 *p, max_ampdu_sz;
+       int len;
+       /* struct sta_info *bmc_sta, *psta; */
+       struct ieee80211_ht_cap *pht_capie;
+       struct ieee80211_ht_addt_info *pht_addtinfo;
+       /* struct recv_reorder_ctrl *preorder_ctrl; */
+       struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
+       struct ht_priv          *phtpriv = &pmlmepriv->htpriv;
+       /* struct recv_priv *precvpriv = &padapter->recvpriv; */
+       struct registry_priv *pregistrypriv = &padapter->registrypriv;
+       /* struct wlan_network *pcur_network = &pmlmepriv->cur_network;; */
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if (!phtpriv->ht_option)
+               return;
+
+       if ((!pmlmeinfo->HT_info_enable) || (!pmlmeinfo->HT_caps_enable))
+               return;
+
+       DBG_8723A("+rtw_update_ht_cap23a()\n");
+
+       /* maybe needs check if ap supports rx ampdu. */
+       if ((phtpriv->ampdu_enable == false) && (pregistrypriv->ampdu_enable == 1)) {
+               if (pregistrypriv->wifi_spec == 1)
+                       phtpriv->ampdu_enable = false;
+               else
+                       phtpriv->ampdu_enable = true;
+       } else if (pregistrypriv->ampdu_enable == 2) {
+               phtpriv->ampdu_enable = true;
+       }
+
+       /* check Max Rx A-MPDU Size */
+       len = 0;
+       p = rtw_get_ie23a(pie+sizeof (struct ndis_802_11_fixed_ies), _HT_CAPABILITY_IE_, &len, ie_len-sizeof (struct ndis_802_11_fixed_ies));
+       if (p && len > 0) {
+               pht_capie = (struct ieee80211_ht_cap *)(p+2);
+               max_ampdu_sz = (pht_capie->ampdu_params_info & IEEE80211_HT_AMPDU_PARM_FACTOR);
+               max_ampdu_sz = 1 << (max_ampdu_sz+3); /*  max_ampdu_sz (kbytes); */
+
+               /* DBG_8723A("rtw_update_ht_cap23a(): max_ampdu_sz =%d\n", max_ampdu_sz); */
+               phtpriv->rx_ampdu_maxlen = max_ampdu_sz;
+
+       }
+
+       len = 0;
+       p = rtw_get_ie23a(pie+sizeof (struct ndis_802_11_fixed_ies), _HT_ADD_INFO_IE_, &len, ie_len-sizeof (struct ndis_802_11_fixed_ies));
+       if (p && len>0)
+       {
+               pht_addtinfo = (struct ieee80211_ht_addt_info *)(p+2);
+               /* todo: */
+       }
+
+       /* update cur_bwmode & cur_ch_offset */
+       if ((pregistrypriv->cbw40_enable) &&
+               (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & BIT(1)) &&
+               (pmlmeinfo->HT_info.infos[0] & BIT(2)))
+       {
+               int i;
+               u8      rf_type;
+
+               padapter->HalFunc.GetHwRegHandler(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+               /* update the MCS rates */
+               for (i = 0; i < 16; i++)
+               {
+                       if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R))
+                               pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R23A[i];
+                       else
+                               pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R23A[i];
+               }
+               /* switch to the 40M Hz mode accoring to the AP */
+               pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40;
+               switch ((pmlmeinfo->HT_info.infos[0] & 0x3))
+               {
+                       case HT_EXTCHNL_OFFSET_UPPER:
+                               pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+                               break;
+
+                       case HT_EXTCHNL_OFFSET_LOWER:
+                               pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+                               break;
+
+                       default:
+                               pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+                               break;
+               }
+       }
+
+       /*  */
+       /*  Config SM Power Save setting */
+       /*  */
+       pmlmeinfo->SM_PS = (pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info & 0x0C) >> 2;
+       if (pmlmeinfo->SM_PS == WLAN_HT_CAP_SM_PS_STATIC)
+               DBG_8723A("%s(): WLAN_HT_CAP_SM_PS_STATIC\n", __func__);
+
+       /*  */
+       /*  Config current HT Protection mode. */
+       /*  */
+       pmlmeinfo->HT_protection = pmlmeinfo->HT_info.infos[1] & 0x3;
+}
+
+void rtw_issue_addbareq_cmd23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       u8 issued;
+       int priority;
+       struct sta_info *psta = NULL;
+       struct ht_priv  *phtpriv;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       s32 bmcst = is_multicast_ether_addr(pattrib->ra);
+
+       if (bmcst || (padapter->mlmepriv.LinkDetectInfo.NumTxOkInPeriod<100))
+               return;
+
+       priority = pattrib->priority;
+
+       if (pattrib->psta)
+               psta = pattrib->psta;
+       else
+       {
+               DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
+               psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra);
+       }
+
+       if (psta == NULL)
+       {
+               DBG_8723A("%s, psta == NUL\n", __func__);
+               return;
+       }
+
+       if (!(psta->state &_FW_LINKED))
+       {
+               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state);
+               return;
+       }
+
+       phtpriv = &psta->htpriv;
+
+       if ((phtpriv->ht_option == true) && (phtpriv->ampdu_enable == true))
+       {
+               issued = (phtpriv->agg_enable_bitmap>>priority)&0x1;
+               issued |= (phtpriv->candidate_tid_bitmap>>priority)&0x1;
+
+               if (0 == issued)
+               {
+                       DBG_8723A("rtw_issue_addbareq_cmd23a, p =%d\n", priority);
+                       psta->htpriv.candidate_tid_bitmap |= CHKBIT((u8)priority);
+                       rtw_addbareq_cmd23a(padapter, (u8) priority, pattrib->ra);
+               }
+       }
+}
+
+inline void rtw_set_roaming(struct rtw_adapter *adapter, u8 to_roaming)
+{
+       if (to_roaming == 0)
+               adapter->mlmepriv.to_join = false;
+       adapter->mlmepriv.to_roaming = to_roaming;
+}
+
+inline u8 rtw_to_roaming(struct rtw_adapter *adapter)
+{
+       return adapter->mlmepriv.to_roaming;
+}
+
+void rtw23a_roaming(struct rtw_adapter *padapter, struct wlan_network *tgt_network)
+{
+       struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
+
+       spin_lock_bh(&pmlmepriv->lock);
+       _rtw23a_roaming(padapter, tgt_network);
+       spin_unlock_bh(&pmlmepriv->lock);
+}
+void _rtw23a_roaming(struct rtw_adapter *padapter, struct wlan_network *tgt_network)
+{
+       struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_network *pnetwork;
+       int do_join_r;
+
+       if (tgt_network != NULL)
+               pnetwork = tgt_network;
+       else
+               pnetwork = &pmlmepriv->cur_network;
+
+       if (0 < rtw_to_roaming(padapter)) {
+               DBG_8723A("roaming from %s("MAC_FMT"), length:%d\n",
+                         pnetwork->network.Ssid.ssid,
+                         MAC_ARG(pnetwork->network.MacAddress),
+                         pnetwork->network.Ssid.ssid_len);
+               memcpy(&pmlmepriv->assoc_ssid, &pnetwork->network.Ssid,
+                      sizeof(struct cfg80211_ssid));
+
+               pmlmepriv->assoc_by_bssid = false;
+
+               while(1) {
+                       if (_SUCCESS == (do_join_r = rtw_do_join23a(padapter))) {
+                               break;
+                       } else {
+                               DBG_8723A("roaming do_join return %d\n", do_join_r);
+                               pmlmepriv->to_roaming--;
+
+                               if (0 < rtw_to_roaming(padapter)) {
+                                       continue;
+                               } else {
+                                       DBG_8723A("%s(%d) -to roaming fail, indicate_disconnect\n", __func__, __LINE__);
+                                       rtw_indicate_disconnect23a(padapter);
+                                       break;
+                               }
+                       }
+               }
+       }
+}
+
+int rtw_linked_check(struct rtw_adapter *padapter)
+{
+       if ((check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE)) ||
+           (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE))) {
+               if (padapter->stapriv.asoc_sta_count > 2)
+                       return true;
+       } else {        /* Station mode */
+               if (check_fwstate(&padapter->mlmepriv, _FW_LINKED) == true)
+                       return true;
+       }
+       return false;
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_mlme_ext.c b/drivers/staging/rtl8723au/core/rtw_mlme_ext.c
new file mode 100644 (file)
index 0000000..4c75363
--- /dev/null
@@ -0,0 +1,9990 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_MLME_EXT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <rtw_mlme_ext.h>
+#include <wlan_bssdef.h>
+#include <mlme_osdep.h>
+#include <recv_osdep.h>
+#include <ethernet.h>
+#include <linux/ieee80211.h>
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+#include <rtl8723a_hal.h>
+#endif
+
+static struct mlme_handler mlme_sta_tbl[]={
+       {"OnAssocReq23a",               &OnAssocReq23a},
+       {"OnAssocRsp23a",               &OnAssocRsp23a},
+       {"OnReAssocReq",        &OnAssocReq23a},
+       {"OnReAssocRsp",        &OnAssocRsp23a},
+       {"OnProbeReq23a",               &OnProbeReq23a},
+       {"OnProbeRsp23a",               &OnProbeRsp23a},
+
+       /*----------------------------------------------------------
+                                       below 2 are reserved
+       -----------------------------------------------------------*/
+       {"DoReserved23a",               &DoReserved23a},
+       {"DoReserved23a",               &DoReserved23a},
+       {"OnBeacon23a",         &OnBeacon23a},
+       {"OnATIM",              &OnAtim23a},
+       {"OnDisassoc23a",               &OnDisassoc23a},
+       {"OnAuth23a",           &OnAuth23aClient23a},
+       {"OnDeAuth23a",         &OnDeAuth23a},
+       {"OnAction23a",         &OnAction23a},
+};
+
+static struct action_handler OnAction23a_tbl[]={
+       {WLAN_CATEGORY_SPECTRUM_MGMT, "ACTION_SPECTRUM_MGMT", on_action_spct23a},
+       {WLAN_CATEGORY_QOS, "ACTION_QOS", &OnAction23a_qos},
+       {WLAN_CATEGORY_DLS, "ACTION_DLS", &OnAction23a_dls},
+       {WLAN_CATEGORY_BACK, "ACTION_BACK", &OnAction23a_back23a},
+       {WLAN_CATEGORY_PUBLIC, "ACTION_PUBLIC", on_action_public23a},
+       {WLAN_CATEGORY_HT, "ACTION_HT", &OnAction23a_ht},
+       {WLAN_CATEGORY_SA_QUERY, "ACTION_SA_QUERY", &DoReserved23a},
+       {WLAN_CATEGORY_WMM, "ACTION_WMM", &OnAction23a_wmm},
+       {WLAN_CATEGORY_VENDOR_SPECIFIC, "ACTION_P2P", &OnAction23a_p2p},
+};
+
+static u8      null_addr[ETH_ALEN]= {0, 0, 0, 0, 0, 0};
+
+/**************************************************
+OUI definitions for the vendor specific IE
+***************************************************/
+unsigned char  RTW_WPA_OUI23A[] = {0x00, 0x50, 0xf2, 0x01};
+unsigned char WMM_OUI23A[] = {0x00, 0x50, 0xf2, 0x02};
+unsigned char  WPS_OUI23A[] = {0x00, 0x50, 0xf2, 0x04};
+unsigned char  P2P_OUI23A[] = {0x50, 0x6F, 0x9A, 0x09};
+unsigned char  WFD_OUI23A[] = {0x50, 0x6F, 0x9A, 0x0A};
+
+unsigned char  WMM_INFO_OUI23A[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
+unsigned char  WMM_PARA_OUI23A[] = {0x00, 0x50, 0xf2, 0x02, 0x01, 0x01};
+
+unsigned char WPA_TKIP_CIPHER23A[4] = {0x00, 0x50, 0xf2, 0x02};
+unsigned char RSN_TKIP_CIPHER23A[4] = {0x00, 0x0f, 0xac, 0x02};
+
+
+/********************************************************
+MCS rate definitions
+*********************************************************/
+unsigned char MCS_rate_2R23A[16] = {
+       0xff, 0xff, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+unsigned char MCS_rate_1R23A[16] = {
+       0xff, 0x00, 0x0, 0x0, 0x01, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
+
+/********************************************************
+ChannelPlan definitions
+*********************************************************/
+
+static struct rt_channel_plan_2g       RTW_ChannelPlan2G[RT_CHANNEL_DOMAIN_2G_MAX] = {
+       {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},              /*  0x00, RT_CHANNEL_DOMAIN_2G_WORLD , Passive scan CH 12, 13 */
+       {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}, 13},              /*  0x01, RT_CHANNEL_DOMAIN_2G_ETSI1 */
+       {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}, 11},                      /*  0x02, RT_CHANNEL_DOMAIN_2G_FCC1 */
+       {{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, 14},  /*  0x03, RT_CHANNEL_DOMAIN_2G_MIKK1 */
+       {{10, 11, 12, 13}, 4},                                  /*  0x04, RT_CHANNEL_DOMAIN_2G_ETSI2 */
+       {{}, 0},                                                                        /*  0x05, RT_CHANNEL_DOMAIN_2G_NULL */
+};
+
+static struct rt_channel_plan_5g       RTW_ChannelPlan5G[RT_CHANNEL_DOMAIN_5G_MAX] = {
+       {{}, 0},                                                                                                                                                                        /*  0x00, RT_CHANNEL_DOMAIN_5G_NULL */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 19},                                          /*  0x01, RT_CHANNEL_DOMAIN_5G_ETSI1 */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24}, /*  0x02, RT_CHANNEL_DOMAIN_5G_ETSI2 */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 149, 153, 157, 161, 165}, 22},                   /*  0x03, RT_CHANNEL_DOMAIN_5G_ETSI3 */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140, 149, 153, 157, 161, 165}, 24}, /*  0x04, RT_CHANNEL_DOMAIN_5G_FCC1 */
+       {{36, 40, 44, 48, 149, 153, 157, 161, 165}, 9},                                                                                                         /*  0x05, RT_CHANNEL_DOMAIN_5G_FCC2 */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161, 165}, 13},                                                                                        /*  0x06, RT_CHANNEL_DOMAIN_5G_FCC3 */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 149, 153, 157, 161}, 12},                                                                                             /*  0x07, RT_CHANNEL_DOMAIN_5G_FCC4 */
+       {{149, 153, 157, 161, 165}, 5},                                                                                                                                 /*  0x08, RT_CHANNEL_DOMAIN_5G_FCC5 */
+       {{36, 40, 44, 48, 52, 56, 60, 64}, 8},                                                                                                                          /*  0x09, RT_CHANNEL_DOMAIN_5G_FCC6 */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 20},                                     /*  0x0A, RT_CHANNEL_DOMAIN_5G_FCC7_IC1 */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 149, 153, 157, 161, 165}, 20},                                     /*  0x0B, RT_CHANNEL_DOMAIN_5G_KCC1 */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 19},                                          /*  0x0C, RT_CHANNEL_DOMAIN_5G_MKK1 */
+       {{36, 40, 44, 48, 52, 56, 60, 64}, 8},                                                                                                                          /*  0x0D, RT_CHANNEL_DOMAIN_5G_MKK2 */
+       {{100, 104, 108, 112, 116, 120, 124, 128, 132, 136, 140}, 11},                                                                                  /*  0x0E, RT_CHANNEL_DOMAIN_5G_MKK3 */
+       {{56, 60, 64, 100, 104, 108, 112, 116, 136, 140, 149, 153, 157, 161, 165}, 15},                                                         /*  0x0F, RT_CHANNEL_DOMAIN_5G_NCC1 */
+       {{56, 60, 64, 149, 153, 157, 161, 165}, 8},                                                                                                                     /*  0x10, RT_CHANNEL_DOMAIN_5G_NCC2 */
+
+       /*  Driver self defined for old channel plan Compatible , Remember to modify if have new channel plan definition ===== */
+       {{36, 40, 44, 48, 52, 56, 60, 64, 100, 104, 108, 112, 116, 132, 136, 140, 149, 153, 157, 161, 165}, 21},                                /*  0x11, RT_CHANNEL_DOMAIN_5G_FCC */
+       {{36, 40, 44, 48}, 4},                                                                                                                                                  /*  0x12, RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS */
+       {{36, 40, 44, 48, 149, 153, 157, 161}, 8},                                                                                                                              /*  0x13, RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS */
+};
+
+static struct rt_channel_plan_map      RTW_ChannelPlanMap[RT_CHANNEL_DOMAIN_MAX] = {
+       /*  0x00 ~ 0x1F , Old Define ===== */
+       {0x02, 0x11},   /* 0x00, RT_CHANNEL_DOMAIN_FCC */
+       {0x02, 0x0A},   /* 0x01, RT_CHANNEL_DOMAIN_IC */
+       {0x01, 0x01},   /* 0x02, RT_CHANNEL_DOMAIN_ETSI */
+       {0x01, 0x00},   /* 0x03, RT_CHANNEL_DOMAIN_SPAIN */
+       {0x01, 0x00},   /* 0x04, RT_CHANNEL_DOMAIN_FRANCE */
+       {0x03, 0x00},   /* 0x05, RT_CHANNEL_DOMAIN_MKK */
+       {0x03, 0x00},   /* 0x06, RT_CHANNEL_DOMAIN_MKK1 */
+       {0x01, 0x09},   /* 0x07, RT_CHANNEL_DOMAIN_ISRAEL */
+       {0x03, 0x09},   /* 0x08, RT_CHANNEL_DOMAIN_TELEC */
+       {0x03, 0x00},   /* 0x09, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN */
+       {0x00, 0x00},   /* 0x0A, RT_CHANNEL_DOMAIN_WORLD_WIDE_13 */
+       {0x02, 0x0F},   /* 0x0B, RT_CHANNEL_DOMAIN_TAIWAN */
+       {0x01, 0x08},   /* 0x0C, RT_CHANNEL_DOMAIN_CHINA */
+       {0x02, 0x06},   /* 0x0D, RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO */
+       {0x02, 0x0B},   /* 0x0E, RT_CHANNEL_DOMAIN_KOREA */
+       {0x02, 0x09},   /* 0x0F, RT_CHANNEL_DOMAIN_TURKEY */
+       {0x01, 0x01},   /* 0x10, RT_CHANNEL_DOMAIN_JAPAN */
+       {0x02, 0x05},   /* 0x11, RT_CHANNEL_DOMAIN_FCC_NO_DFS */
+       {0x01, 0x12},   /* 0x12, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
+       {0x00, 0x04},   /* 0x13, RT_CHANNEL_DOMAIN_WORLD_WIDE_5G */
+       {0x02, 0x10},   /* 0x14, RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS */
+       {0x00, 0x12},   /* 0x15, RT_CHANNEL_DOMAIN_ETSI_NO_DFS */
+       {0x00, 0x13},   /* 0x16, RT_CHANNEL_DOMAIN_KOREA_NO_DFS */
+       {0x03, 0x12},   /* 0x17, RT_CHANNEL_DOMAIN_JAPAN_NO_DFS */
+       {0x05, 0x08},   /* 0x18, RT_CHANNEL_DOMAIN_PAKISTAN_NO_DFS */
+       {0x02, 0x08},   /* 0x19, RT_CHANNEL_DOMAIN_TAIWAN2_NO_DFS */
+       {0x00, 0x00},   /* 0x1A, */
+       {0x00, 0x00},   /* 0x1B, */
+       {0x00, 0x00},   /* 0x1C, */
+       {0x00, 0x00},   /* 0x1D, */
+       {0x00, 0x00},   /* 0x1E, */
+       {0x05, 0x04},   /* 0x1F, RT_CHANNEL_DOMAIN_WORLD_WIDE_ONLY_5G */
+       /*  0x20 ~ 0x7F , New Define ===== */
+       {0x00, 0x00},   /* 0x20, RT_CHANNEL_DOMAIN_WORLD_NULL */
+       {0x01, 0x00},   /* 0x21, RT_CHANNEL_DOMAIN_ETSI1_NULL */
+       {0x02, 0x00},   /* 0x22, RT_CHANNEL_DOMAIN_FCC1_NULL */
+       {0x03, 0x00},   /* 0x23, RT_CHANNEL_DOMAIN_MKK1_NULL */
+       {0x04, 0x00},   /* 0x24, RT_CHANNEL_DOMAIN_ETSI2_NULL */
+       {0x02, 0x04},   /* 0x25, RT_CHANNEL_DOMAIN_FCC1_FCC1 */
+       {0x00, 0x01},   /* 0x26, RT_CHANNEL_DOMAIN_WORLD_ETSI1 */
+       {0x03, 0x0C},   /* 0x27, RT_CHANNEL_DOMAIN_MKK1_MKK1 */
+       {0x00, 0x0B},   /* 0x28, RT_CHANNEL_DOMAIN_WORLD_KCC1 */
+       {0x00, 0x05},   /* 0x29, RT_CHANNEL_DOMAIN_WORLD_FCC2 */
+       {0x00, 0x00},   /* 0x2A, */
+       {0x00, 0x00},   /* 0x2B, */
+       {0x00, 0x00},   /* 0x2C, */
+       {0x00, 0x00},   /* 0x2D, */
+       {0x00, 0x00},   /* 0x2E, */
+       {0x00, 0x00},   /* 0x2F, */
+       {0x00, 0x06},   /* 0x30, RT_CHANNEL_DOMAIN_WORLD_FCC3 */
+       {0x00, 0x07},   /* 0x31, RT_CHANNEL_DOMAIN_WORLD_FCC4 */
+       {0x00, 0x08},   /* 0x32, RT_CHANNEL_DOMAIN_WORLD_FCC5 */
+       {0x00, 0x09},   /* 0x33, RT_CHANNEL_DOMAIN_WORLD_FCC6 */
+       {0x02, 0x0A},   /* 0x34, RT_CHANNEL_DOMAIN_FCC1_FCC7 */
+       {0x00, 0x02},   /* 0x35, RT_CHANNEL_DOMAIN_WORLD_ETSI2 */
+       {0x00, 0x03},   /* 0x36, RT_CHANNEL_DOMAIN_WORLD_ETSI3 */
+       {0x03, 0x0D},   /* 0x37, RT_CHANNEL_DOMAIN_MKK1_MKK2 */
+       {0x03, 0x0E},   /* 0x38, RT_CHANNEL_DOMAIN_MKK1_MKK3 */
+       {0x02, 0x0F},   /* 0x39, RT_CHANNEL_DOMAIN_FCC1_NCC1 */
+       {0x00, 0x00},   /* 0x3A, */
+       {0x00, 0x00},   /* 0x3B, */
+       {0x00, 0x00},   /* 0x3C, */
+       {0x00, 0x00},   /* 0x3D, */
+       {0x00, 0x00},   /* 0x3E, */
+       {0x00, 0x00},   /* 0x3F, */
+       {0x02, 0x10},   /* 0x40, RT_CHANNEL_DOMAIN_FCC1_NCC2 */
+       {0x03, 0x00},   /* 0x41, RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G */
+};
+
+static struct rt_channel_plan_map      RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE = {0x03, 0x02}; /* use the conbination for max channel numbers */
+
+static struct fwevent wlanevents[] =
+{
+       {0, rtw_dummy_event_callback23a},       /*0*/
+       {0, NULL},
+       {0, NULL},
+       {0, NULL},
+       {0, NULL},
+       {0, NULL},
+       {0, NULL},
+       {0, NULL},
+       {0, &rtw_survey_event_cb23a},           /*8*/
+       {sizeof (struct surveydone_event), &rtw_surveydone_event_callback23a},  /*9*/
+
+       {0, &rtw23a_joinbss_event_cb},          /*10*/
+       {sizeof(struct stassoc_event), &rtw_stassoc_event_callback23a},
+       {sizeof(struct stadel_event), &rtw_stadel_event_callback23a},
+       {0, &rtw_atimdone_event_callback23a},
+       {0, rtw_dummy_event_callback23a},
+       {0, NULL},      /*15*/
+       {0, NULL},
+       {0, NULL},
+       {0, NULL},
+       {0, rtw23a_fwdbg_event_callback},
+       {0, NULL},       /*20*/
+       {0, NULL},
+       {0, NULL},
+       {0, &rtw_cpwm_event_callback23a},
+       {0, NULL},
+};
+
+
+/*
+ * Search the @param channel_num in given @param channel_set
+ * @ch_set: the given channel set
+ * @ch: the given channel number
+ *
+ * return the index of channel_num in channel_set, -1 if not found
+ */
+int rtw_ch_set_search_ch23a(struct rt_channel_info *ch_set, const u32 ch)
+{
+       int i;
+       for (i = 0; ch_set[i]. ChannelNum != 0; i++) {
+               if (ch == ch_set[i].ChannelNum)
+                       break;
+       }
+
+       if (i >= ch_set[i].ChannelNum)
+               return -1;
+       return i;
+}
+
+/****************************************************************************
+
+Following are the initialization functions for WiFi MLME
+
+*****************************************************************************/
+
+int init_hw_mlme_ext23a(struct rtw_adapter *padapter)
+{
+       struct  mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       set_channel_bwmode23a(padapter, pmlmeext->cur_channel,
+                             pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+       return _SUCCESS;
+}
+
+static void init_mlme_ext_priv23a_value(struct rtw_adapter* padapter)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       unsigned char   mixed_datarate[NumRates] = {
+               _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_,
+               _9M_RATE_, _12M_RATE_, _18M_RATE_, _24M_RATE_, _36M_RATE_,
+               _48M_RATE_, _54M_RATE_, 0xff};
+       unsigned char   mixed_basicrate[NumRates] = {
+               _1M_RATE_, _2M_RATE_, _5M_RATE_, _11M_RATE_, _6M_RATE_,
+               _12M_RATE_, _24M_RATE_, 0xff,};
+
+       atomic_set(&pmlmeext->event_seq, 0);
+       /* reset to zero when disconnect at client mode */
+       pmlmeext->mgnt_seq = 0;
+
+       pmlmeext->cur_channel = padapter->registrypriv.channel;
+       pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+       pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+       pmlmeext->retry = 0;
+
+       pmlmeext->cur_wireless_mode = padapter->registrypriv.wireless_mode;
+
+       memcpy(pmlmeext->datarate, mixed_datarate, NumRates);
+       memcpy(pmlmeext->basicrate, mixed_basicrate, NumRates);
+
+       if (pmlmeext->cur_channel > 14)
+               pmlmeext->tx_rate = IEEE80211_OFDM_RATE_6MB;
+       else
+               pmlmeext->tx_rate = IEEE80211_CCK_RATE_1MB;
+
+       pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
+       pmlmeext->sitesurvey_res.channel_idx = 0;
+       pmlmeext->sitesurvey_res.bss_cnt = 0;
+       pmlmeext->scan_abort = false;
+
+       pmlmeinfo->state = WIFI_FW_NULL_STATE;
+       pmlmeinfo->reauth_count = 0;
+       pmlmeinfo->reassoc_count = 0;
+       pmlmeinfo->link_count = 0;
+       pmlmeinfo->auth_seq = 0;
+       pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open;
+       pmlmeinfo->key_index = 0;
+       pmlmeinfo->iv = 0;
+
+       pmlmeinfo->enc_algo = _NO_PRIVACY_;
+       pmlmeinfo->authModeToggle = 0;
+
+       memset(pmlmeinfo->chg_txt, 0, 128);
+
+       pmlmeinfo->slotTime = SHORT_SLOT_TIME;
+       pmlmeinfo->preamble_mode = PREAMBLE_AUTO;
+
+       pmlmeinfo->dialogToken = 0;
+
+       pmlmeext->action_public_rxseq = 0xffff;
+       pmlmeext->action_public_dialog_token = 0xff;
+}
+
+static int has_channel(struct rt_channel_info *channel_set,
+                      u8 chanset_size, u8 chan) {
+       int i;
+
+       for (i = 0; i < chanset_size; i++) {
+               if (channel_set[i].ChannelNum == chan)
+                       return 1;
+       }
+
+       return 0;
+}
+
+static void init_channel_list(struct rtw_adapter *padapter,
+                             struct rt_channel_info *channel_set,
+                             u8 chanset_size,
+                             struct p2p_channels *channel_list) {
+
+       struct p2p_oper_class_map op_class[] = {
+               { IEEE80211G,  81,   1,  13,  1, BW20 },
+               { IEEE80211G,  82,  14,  14,  1, BW20 },
+               { IEEE80211A, 115,  36,  48,  4, BW20 },
+               { IEEE80211A, 116,  36,  44,  8, BW40PLUS },
+               { IEEE80211A, 117,  40,  48,  8, BW40MINUS },
+               { IEEE80211A, 124, 149, 161,  4, BW20 },
+               { IEEE80211A, 125, 149, 169,  4, BW20 },
+               { IEEE80211A, 126, 149, 157,  8, BW40PLUS },
+               { IEEE80211A, 127, 153, 161,  8, BW40MINUS },
+               { -1, 0, 0, 0, 0, BW20 }
+       };
+
+       int cla, op;
+
+       cla = 0;
+
+       for (op = 0; op_class[op].op_class; op++) {
+               u8 ch;
+               struct p2p_oper_class_map *o = &op_class[op];
+               struct p2p_reg_class *reg = NULL;
+
+               for (ch = o->min_chan; ch <= o->max_chan; ch += o->inc) {
+                       if (!has_channel(channel_set, chanset_size, ch))
+                               continue;
+
+                       if ((0 == padapter->registrypriv.ht_enable) &&
+                           (o->inc == 8))
+                               continue;
+
+                       if ((0 == (padapter->registrypriv.cbw40_enable & BIT(1))) &&
+                               ((BW40MINUS == o->bw) || (BW40PLUS == o->bw)))
+                               continue;
+
+                       if (reg == NULL) {
+                               reg = &channel_list->reg_class[cla];
+                               cla++;
+                               reg->reg_class = o->op_class;
+                               reg->channels = 0;
+                       }
+                       reg->channel[reg->channels] = ch;
+                       reg->channels++;
+               }
+       }
+       channel_list->reg_classes = cla;
+}
+
+static u8 init_channel_set(struct rtw_adapter* padapter, u8 ChannelPlan,
+                          struct rt_channel_info *channel_set)
+{
+       u8      index, chanset_size = 0;
+       u8      b5GBand = false, b2_4GBand = false;
+       u8      Index2G = 0, Index5G = 0;
+
+       memset(channel_set, 0, sizeof(struct rt_channel_info)*MAX_CHANNEL_NUM);
+
+       if (ChannelPlan >= RT_CHANNEL_DOMAIN_MAX &&
+           ChannelPlan != RT_CHANNEL_DOMAIN_REALTEK_DEFINE) {
+               DBG_8723A("ChannelPlan ID %x error !!!!!\n", ChannelPlan);
+               return chanset_size;
+       }
+
+       if (padapter->registrypriv.wireless_mode & WIRELESS_11G) {
+               b2_4GBand = true;
+               if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan)
+                       Index2G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index2G;
+               else
+                       Index2G = RTW_ChannelPlanMap[ChannelPlan].Index2G;
+       }
+
+       if (padapter->registrypriv.wireless_mode & WIRELESS_11A) {
+               b5GBand = true;
+               if (RT_CHANNEL_DOMAIN_REALTEK_DEFINE == ChannelPlan)
+                       Index5G = RTW_CHANNEL_PLAN_MAP_REALTEK_DEFINE.Index5G;
+               else
+                       Index5G = RTW_ChannelPlanMap[ChannelPlan].Index5G;
+       }
+
+       if (b2_4GBand) {
+               for (index = 0; index<RTW_ChannelPlan2G[Index2G].Len; index++) {
+                       channel_set[chanset_size].ChannelNum =
+                               RTW_ChannelPlan2G[Index2G].Channel[index];
+
+                       if ((RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN == ChannelPlan) ||
+                           /* Channel 1~11 is active, and 12~14 is passive */
+                           (RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G == ChannelPlan)){
+                               if (channel_set[chanset_size].ChannelNum >= 1 &&
+                                   channel_set[chanset_size].ChannelNum <= 11)
+                                       channel_set[chanset_size].ScanType =
+                                               SCAN_ACTIVE;
+                               else if ((channel_set[chanset_size].ChannelNum >= 12 &&
+                                         channel_set[chanset_size].ChannelNum  <= 14))
+                                       channel_set[chanset_size].ScanType =
+                                               SCAN_PASSIVE;
+                       } else if (RT_CHANNEL_DOMAIN_WORLD_WIDE_13 ==
+                                  ChannelPlan ||
+                                  RT_CHANNEL_DOMAIN_WORLD_WIDE_5G ==
+                                  ChannelPlan ||
+                                  RT_CHANNEL_DOMAIN_2G_WORLD == Index2G) {
+                               /*  channel 12~13, passive scan */
+                               if (channel_set[chanset_size].ChannelNum <= 11)
+                                       channel_set[chanset_size].ScanType =
+                                               SCAN_ACTIVE;
+                               else
+                                       channel_set[chanset_size].ScanType =
+                                               SCAN_PASSIVE;
+                       } else
+                               channel_set[chanset_size].ScanType =
+                                       SCAN_ACTIVE;
+
+                       chanset_size++;
+               }
+       }
+
+       if (b5GBand) {
+               for (index = 0;index<RTW_ChannelPlan5G[Index5G].Len;index++) {
+                       if (RTW_ChannelPlan5G[Index5G].Channel[index] <= 48 ||
+                           RTW_ChannelPlan5G[Index5G].Channel[index] >= 149) {
+                               channel_set[chanset_size].ChannelNum =
+                                       RTW_ChannelPlan5G[Index5G].Channel[index];
+                               if (RT_CHANNEL_DOMAIN_WORLD_WIDE_5G ==
+                                   ChannelPlan) {
+                                       /* passive scan for all 5G channels */
+                                       channel_set[chanset_size].ScanType =
+                                               SCAN_PASSIVE;
+                               } else
+                                       channel_set[chanset_size].ScanType =
+                                               SCAN_ACTIVE;
+                               DBG_8723A("%s(): channel_set[%d].ChannelNum = "
+                                         "%d\n", __func__, chanset_size,
+                                         channel_set[chanset_size].ChannelNum);
+                               chanset_size++;
+                       }
+               }
+       }
+
+       return chanset_size;
+}
+
+int init_mlme_ext_priv23a(struct rtw_adapter* padapter)
+{
+       int     res = _SUCCESS;
+       struct registry_priv* pregistrypriv = &padapter->registrypriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       pmlmeext->padapter = padapter;
+
+       init_mlme_ext_priv23a_value(padapter);
+       pmlmeinfo->bAcceptAddbaReq = pregistrypriv->bAcceptAddbaReq;
+
+       init_mlme_ext_timer23a(padapter);
+
+#ifdef CONFIG_8723AU_AP_MODE
+       init_mlme_ap_info23a(padapter);
+#endif
+
+       pmlmeext->max_chan_nums = init_channel_set(padapter,
+                                                  pmlmepriv->ChannelPlan,
+                                                  pmlmeext->channel_set);
+       init_channel_list(padapter, pmlmeext->channel_set,
+                         pmlmeext->max_chan_nums, &pmlmeext->channel_list);
+
+       pmlmeext->chan_scan_time = SURVEY_TO;
+       pmlmeext->mlmeext_init = true;
+
+       pmlmeext->active_keep_alive_check = true;
+       return res;
+}
+
+void free_mlme_ext_priv23a (struct mlme_ext_priv *pmlmeext)
+{
+       struct rtw_adapter *padapter = pmlmeext->padapter;
+
+       if (!padapter)
+               return;
+
+       if (padapter->bDriverStopped == true) {
+               del_timer_sync(&pmlmeext->survey_timer);
+               del_timer_sync(&pmlmeext->link_timer);
+               /* del_timer_sync(&pmlmeext->ADDBA_timer); */
+       }
+}
+
+static void
+_mgt_dispatcher23a(struct rtw_adapter *padapter, struct mlme_handler *ptable,
+                  struct recv_frame *precv_frame)
+{
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+       if (ptable->func) {
+               /* receive the frames that ra(a1) is my address
+                  or ra(a1) is bc address. */
+               if (!ether_addr_equal(hdr->addr1, myid(&padapter->eeprompriv))&&
+                   !is_broadcast_ether_addr(hdr->addr1))
+                       return;
+
+               ptable->func(padapter, precv_frame);
+        }
+}
+
+void mgt_dispatcher23a(struct rtw_adapter *padapter,
+                   struct recv_frame *precv_frame)
+{
+       int index;
+       struct mlme_handler *ptable;
+#ifdef CONFIG_8723AU_AP_MODE
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#endif /* CONFIG_8723AU_AP_MODE */
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u16 stype;
+       struct sta_info *psta;
+
+       if (!ieee80211_is_mgmt(hdr->frame_control))
+               return;
+
+       /* receive the frames that ra(a1) is my address or ra(a1) is
+          bc address. */
+       if (!ether_addr_equal(hdr->addr1, myid(&padapter->eeprompriv)) &&
+           !is_broadcast_ether_addr(hdr->addr1))
+               return;
+
+       ptable = mlme_sta_tbl;
+
+       stype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE;
+       index = stype >> 4;
+
+       if (index > 13) {
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                        ("Currently we do not support reserved sub-fr-type ="
+                         "%d\n", index));
+               return;
+       }
+       ptable += index;
+
+       psta = rtw_get_stainfo23a(&padapter->stapriv, hdr->addr2);
+
+       if (psta) {
+               if (ieee80211_has_retry(hdr->frame_control)) {
+                       if (precv_frame->attrib.seq_num ==
+                           psta->RxMgmtFrameSeqNum) {
+                               /* drop the duplicate management frame */
+                               DBG_8723A("Drop duplicate management frame "
+                                         "with seq_num = %d.\n",
+                                         precv_frame->attrib.seq_num);
+                               return;
+                       }
+               }
+               psta->RxMgmtFrameSeqNum = precv_frame->attrib.seq_num;
+       }
+
+#ifdef CONFIG_8723AU_AP_MODE
+       switch (stype)
+       {
+       case IEEE80211_STYPE_AUTH:
+               if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
+                       ptable->func = &OnAuth23a;
+               else
+                       ptable->func = &OnAuth23aClient23a;
+               /* pass through */
+       case IEEE80211_STYPE_ASSOC_REQ:
+       case IEEE80211_STYPE_REASSOC_REQ:
+               _mgt_dispatcher23a(padapter, ptable, precv_frame);
+               break;
+       case IEEE80211_STYPE_PROBE_REQ:
+               if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
+                       _mgt_dispatcher23a(padapter, ptable, precv_frame);
+               else
+                       _mgt_dispatcher23a(padapter, ptable, precv_frame);
+               break;
+       case IEEE80211_STYPE_BEACON:
+               _mgt_dispatcher23a(padapter, ptable, precv_frame);
+               break;
+       case IEEE80211_STYPE_ACTION:
+               /* if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) */
+               _mgt_dispatcher23a(padapter, ptable, precv_frame);
+               break;
+       default:
+               _mgt_dispatcher23a(padapter, ptable, precv_frame);
+               if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true)
+                       rtw_hostapd_mlme_rx23a(padapter, precv_frame);
+               break;
+       }
+#else
+       _mgt_dispatcher23a(padapter, ptable, precv_frame);
+#endif
+}
+
+#ifdef CONFIG_8723AU_P2P
+static u32 p2p_listen_state_process(struct rtw_adapter *padapter,
+                                   unsigned char *da)
+{
+       bool response = true;
+
+       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled == false ||
+           padapter->mlmepriv.wps_probe_resp_ie == NULL ||
+           padapter->mlmepriv.p2p_probe_resp_ie == NULL) {
+               DBG_8723A("DON'T issue_probersp23a_p2p23a: p2p_enabled:%d, "
+                         "wps_probe_resp_ie:%p, p2p_probe_resp_ie:%p\n",
+                         wdev_to_priv(padapter->rtw_wdev)->p2p_enabled,
+                         padapter->mlmepriv.wps_probe_resp_ie,
+                         padapter->mlmepriv.p2p_probe_resp_ie);
+               response = false;
+       }
+
+       if (response == true)
+               issue_probersp23a_p2p23a(padapter, da);
+
+       return _SUCCESS;
+}
+#endif /* CONFIG_8723AU_P2P */
+
+/****************************************************************************
+
+Following are the callback functions for each subtype of the management frames
+
+*****************************************************************************/
+
+unsigned int OnProbeReq23a(struct rtw_adapter *padapter,
+                          struct recv_frame *precv_frame)
+{
+       unsigned int    ielen;
+       unsigned char   *p;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur = &pmlmeinfo->network;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+       uint len = skb->len;
+       u8 is_valid_p2p_probereq = false;
+
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       u8 wifi_test_chk_rate = 1;
+
+       if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) &&
+           !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE) &&
+           !rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT) &&
+           !rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH) &&
+           !rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN)) {
+               /*      mcs_rate = 0 -> CCK 1M rate */
+               /*      mcs_rate = 1 -> CCK 2M rate */
+               /*      mcs_rate = 2 -> CCK 5.5M rate */
+               /*      mcs_rate = 3 -> CCK 11M rate */
+               /*      In the P2P mode, the driver should not support
+                       the CCK rate */
+
+               /*      IOT issue: Google Nexus7 use 1M rate to send
+                       p2p_probe_req after GO nego completed and Nexus7
+                       is client */
+               if (wifi_test_chk_rate == 1) {
+                       if ((is_valid_p2p_probereq =
+                            process_probe_req_p2p_ie23a(pwdinfo, pframe,
+                                                        len)) == true) {
+                               if (rtw_p2p_chk_role(pwdinfo,
+                                                    P2P_ROLE_DEVICE)) {
+                                       u8 *sa = ieee80211_get_SA(hdr);
+                                       p2p_listen_state_process(padapter, sa);
+                                       return _SUCCESS;
+                               }
+
+                               if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+                                       goto _continue;
+                               }
+                       }
+               }
+       }
+
+_continue:
+#endif /* CONFIG_8723AU_P2P */
+
+       if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+               return _SUCCESS;
+       }
+
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == false &&
+               check_fwstate(pmlmepriv,
+                             WIFI_ADHOC_MASTER_STATE|WIFI_AP_STATE) == false) {
+               return _SUCCESS;
+       }
+
+       p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) +
+                         _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ielen,
+                         len - sizeof(struct ieee80211_hdr_3addr) -
+                         _PROBEREQ_IE_OFFSET_);
+
+       /* check (wildcard) SSID */
+       if (p) {
+               if (is_valid_p2p_probereq == true) {
+                       goto _issue_probersp23a;
+               }
+
+               if ((ielen != 0 &&
+                    memcmp((void *)(p+2), cur->Ssid.ssid,
+                           cur->Ssid.ssid_len)) ||
+                   (ielen == 0 && pmlmeinfo->hidden_ssid_mode)) {
+                       return _SUCCESS;
+               }
+
+_issue_probersp23a:
+
+               if (check_fwstate(pmlmepriv, _FW_LINKED) == true &&
+                   pmlmepriv->cur_network.join_res == true) {
+                       /* DBG_8723A("+issue_probersp23a during ap mode\n"); */
+                       issue_probersp23a(padapter, ieee80211_get_SA(hdr),
+                                         is_valid_p2p_probereq);
+               }
+       }
+
+       return _SUCCESS;
+}
+
+unsigned int OnProbeRsp23a(struct rtw_adapter *padapter,
+                          struct recv_frame *precv_frame)
+{
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+#ifdef CONFIG_8723AU_P2P
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+#endif
+
+#ifdef CONFIG_8723AU_P2P
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
+               if (pwdinfo->tx_prov_disc_info.benable == true) {
+                       if (ether_addr_equal(pwdinfo->tx_prov_disc_info.peerIFAddr,
+                                   hdr->addr2)) {
+                               if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+                                       pwdinfo->tx_prov_disc_info.benable = false;
+                                       issue_p2p_provision_request23a(padapter,
+                                                                                               pwdinfo->tx_prov_disc_info.ssid.ssid,
+                                                                                               pwdinfo->tx_prov_disc_info.ssid.ssid_len,
+                                                                                               pwdinfo->tx_prov_disc_info.peerDevAddr);
+                               }
+                               else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+                               {
+                                       pwdinfo->tx_prov_disc_info.benable = false;
+                                       issue_p2p_provision_request23a(padapter,
+                                                                                               NULL,
+                                                                                               0,
+                                                                                               pwdinfo->tx_prov_disc_info.peerDevAddr);
+                               }
+                       }
+               }
+               return _SUCCESS;
+       } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING)) {
+               if (pwdinfo->nego_req_info.benable == true) {
+                       DBG_8723A("[%s] P2P State is GONEGO ING!\n", __func__);
+                       if (ether_addr_equal(pwdinfo->nego_req_info.peerDevAddr,
+                                            hdr->addr2)) {
+                               pwdinfo->nego_req_info.benable = false;
+                               issue_p2p_GO_request23a(padapter, pwdinfo->nego_req_info.peerDevAddr);
+                       }
+               }
+       } else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ)) {
+               if (pwdinfo->invitereq_info.benable == true) {
+                       DBG_8723A("[%s] P2P_STATE_TX_INVITE_REQ!\n", __func__);
+                       if (ether_addr_equal(
+                                   pwdinfo->invitereq_info.peer_macaddr,
+                                   hdr->addr2)) {
+                               pwdinfo->invitereq_info.benable = false;
+                               issue_p2p_invitation_request23a(padapter, pwdinfo->invitereq_info.peer_macaddr);
+                       }
+               }
+       }
+#endif
+
+       if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+               report_survey_event23a(padapter, precv_frame);
+               return _SUCCESS;
+       }
+
+       return _SUCCESS;
+}
+
+unsigned int OnBeacon23a(struct rtw_adapter *padapter,
+                        struct recv_frame *precv_frame)
+{
+       int cam_idx;
+       struct sta_info *psta;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+       uint len = skb->len;
+       struct wlan_bssid_ex *pbss;
+       int ret = _SUCCESS;
+       u8 *p = NULL;
+       u32 ielen = 0;
+
+       p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) +
+                         _BEACON_IE_OFFSET_, _EXT_SUPPORTEDRATES_IE_, &ielen,
+                         len - sizeof(struct ieee80211_hdr_3addr) -
+                         _BEACON_IE_OFFSET_);
+       if ((p != NULL) && (ielen > 0)) {
+               if ((*(p + 1 + ielen) == 0x2D) && (*(p + 2 + ielen) != 0x2D)) {
+                       /* Invalid value 0x2D is detected in Extended Supported
+                        * Rates (ESR) IE. Try to fix the IE length to avoid
+                        * failed Beacon parsing.
+                        */
+                       DBG_8723A("[WIFIDBG] Error in ESR IE is detected in "
+                                 "Beacon of BSSID: %pM. Fix the length of "
+                                 "ESR IE to avoid failed Beacon parsing.\n",
+                                 hdr->addr3);
+                       *(p + 1) = ielen - 1;
+               }
+       }
+
+       if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+               report_survey_event23a(padapter, precv_frame);
+               return _SUCCESS;
+       }
+
+       if (ether_addr_equal(hdr->addr3, get_my_bssid23a(&pmlmeinfo->network))){
+               if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
+                       /* we should update current network before auth,
+                          or some IE is wrong */
+                       pbss = (struct wlan_bssid_ex *)
+                               kmalloc(sizeof(struct wlan_bssid_ex),
+                                       GFP_ATOMIC);
+                       if (pbss) {
+                               if (collect_bss_info23a(padapter, precv_frame,
+                                                       pbss) == _SUCCESS) {
+                                       update_network23a(&pmlmepriv->cur_network.network, pbss, padapter, true);
+                                       rtw_get_bcn_info23a(&pmlmepriv->cur_network);
+                               }
+                               kfree(pbss);
+                       }
+
+                       /* check the vendor of the assoc AP */
+                       pmlmeinfo->assoc_AP_vendor = check_assoc_AP23a(pframe + sizeof(struct ieee80211_hdr_3addr), len-sizeof(struct ieee80211_hdr_3addr));
+
+                       /* update TSF Value */
+                       update_TSF23a(pmlmeext, pframe, len);
+
+                       /* start auth */
+                       start_clnt_auth23a(padapter);
+
+                       return _SUCCESS;
+               }
+
+               if (((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE) &&
+                   (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)) {
+                       psta = rtw_get_stainfo23a(pstapriv, hdr->addr2);
+                       if (psta) {
+                               ret = rtw_check_bcn_info23a(padapter, pframe,
+                                                           len);
+                               if (!ret) {
+                                       DBG_8723A_LEVEL(_drv_always_,
+                                                       "ap has changed, "
+                                                       "disconnect now\n");
+                                       receive_disconnect23a(padapter, pmlmeinfo->network.MacAddress, 65535);
+                                       return _SUCCESS;
+                               }
+                               /* update WMM, ERP in the beacon */
+                               /* todo: the timer is used instead of
+                                  the number of the beacon received */
+                               if ((sta_rx_pkts(psta) & 0xf) == 0) {
+                                       /* DBG_8723A("update_bcn_info\n"); */
+                                       update_beacon23a_info(padapter, pframe,
+                                                             len, psta);
+                               }
+
+#ifdef CONFIG_8723AU_P2P
+                               process_p2p_ps_ie23a(padapter, (pframe + sizeof(struct ieee80211_hdr_3addr)), (len - sizeof(struct ieee80211_hdr_3addr)));
+#endif /* CONFIG_8723AU_P2P */
+                       }
+               } else if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+                       psta = rtw_get_stainfo23a(pstapriv, hdr->addr2);
+                       if (psta) {
+                               /* update WMM, ERP in the beacon */
+                               /* todo: the timer is used instead of the
+                                  number of the beacon received */
+                               if ((sta_rx_pkts(psta) & 0xf) == 0) {
+                                       /* DBG_8723A("update_bcn_info\n"); */
+                                       update_beacon23a_info(padapter, pframe,
+                                                             len, psta);
+                               }
+                       } else {
+                               /* allocate a new CAM entry for IBSS station */
+                               cam_idx = allocate_fw_sta_entry23a(padapter);
+                               if (cam_idx == NUM_STA)
+                                       goto _END_ONBEACON_;
+
+                               /* get supported rate */
+                               if (update_sta_support_rate23a(padapter, (pframe + sizeof(struct ieee80211_hdr_3addr) + _BEACON_IE_OFFSET_), (len - sizeof(struct ieee80211_hdr_3addr) - _BEACON_IE_OFFSET_), cam_idx) == _FAIL) {
+                                       pmlmeinfo->FW_sta_info[cam_idx].status = 0;
+                                       goto _END_ONBEACON_;
+                               }
+
+                               /* update TSF Value */
+                               update_TSF23a(pmlmeext, pframe, len);
+
+                               /* report sta add event */
+                               report_add_sta_event23a(padapter, hdr->addr2,
+                                                       cam_idx);
+                       }
+               }
+       }
+
+_END_ONBEACON_:
+
+       return _SUCCESS;
+}
+
+unsigned int OnAuth23a(struct rtw_adapter *padapter,
+                      struct recv_frame *precv_frame)
+{
+#ifdef CONFIG_8723AU_AP_MODE
+       unsigned int    auth_mode, seq, ie_len;
+       unsigned char   *sa, *p;
+       u16     algorithm;
+       int     status;
+       static struct sta_info stat;
+       struct  sta_info        *pstat = NULL;
+       struct  sta_priv *pstapriv = &padapter->stapriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+       uint len = skb->len;
+
+       if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+               return _FAIL;
+
+       DBG_8723A("+OnAuth23a\n");
+
+       sa = hdr->addr2;
+
+       auth_mode = psecuritypriv->dot11AuthAlgrthm;
+       seq = cpu_to_le16(*(u16*)((unsigned long)pframe +
+                                 sizeof(struct ieee80211_hdr_3addr) + 2));
+       algorithm = cpu_to_le16(*(u16*)((unsigned long)pframe +
+                                       sizeof(struct ieee80211_hdr_3addr)));
+
+       DBG_8723A("auth alg =%x, seq =%X\n", algorithm, seq);
+
+       if (auth_mode == 2 &&
+           psecuritypriv->dot11PrivacyAlgrthm != _WEP40_ &&
+           psecuritypriv->dot11PrivacyAlgrthm != _WEP104_)
+               auth_mode = 0;
+
+       /*  rx a shared-key auth but shared not enabled, or */
+       /*  rx a open-system auth but shared-key is enabled */
+       if ((algorithm > 0 && auth_mode == 0) ||
+           (algorithm == 0 && auth_mode == 1)) {
+               DBG_8723A("auth rejected due to bad alg [alg =%d, auth_mib "
+                         "=%d] %02X%02X%02X%02X%02X%02X\n",
+                         algorithm, auth_mode,
+                         sa[0], sa[1], sa[2], sa[3], sa[4], sa[5]);
+
+               status = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+
+               goto auth_fail;
+       }
+
+       if (rtw_access_ctrl23a(padapter, sa) == false) {
+               status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+               goto auth_fail;
+       }
+
+       pstat = rtw_get_stainfo23a(pstapriv, sa);
+       if (!pstat) {
+               /*  allocate a new one */
+               DBG_8723A("going to alloc stainfo for sa ="MAC_FMT"\n",
+                         MAC_ARG(sa));
+               pstat = rtw_alloc_stainfo23a(pstapriv, sa);
+               if (!pstat) {
+                       DBG_8723A(" Exceed the upper limit of supported "
+                                 "clients...\n");
+                       status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+                       goto auth_fail;
+               }
+
+               pstat->state = WIFI_FW_AUTH_NULL;
+               pstat->auth_seq = 0;
+
+               /* pstat->flags = 0; */
+               /* pstat->capability = 0; */
+       } else {
+               spin_lock_bh(&pstapriv->asoc_list_lock);
+               if (!list_empty(&pstat->asoc_list)) {
+                       list_del_init(&pstat->asoc_list);
+                       pstapriv->asoc_list_cnt--;
+                       if (pstat->expire_to > 0)
+                       {
+                               /* TODO: STA re_auth within expire_to */
+                       }
+               }
+               spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+               if (seq == 1) {
+                       /* TODO: STA re_auth and auth timeout */
+               }
+       }
+
+       spin_lock_bh(&pstapriv->auth_list_lock);
+       if (list_empty(&pstat->auth_list)) {
+               list_add_tail(&pstat->auth_list, &pstapriv->auth_list);
+               pstapriv->auth_list_cnt++;
+       }
+       spin_unlock_bh(&pstapriv->auth_list_lock);
+
+       if (pstat->auth_seq == 0)
+               pstat->expire_to = pstapriv->auth_to;
+
+       if ((pstat->auth_seq + 1) != seq) {
+               DBG_8723A("(1)auth rejected because out of seq [rx_seq =%d, "
+                         "exp_seq =%d]!\n", seq, pstat->auth_seq+1);
+               status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+               goto auth_fail;
+       }
+
+       if (algorithm == 0 && (auth_mode == 0 || auth_mode == 2)) {
+               if (seq == 1) {
+                       pstat->state &= ~WIFI_FW_AUTH_NULL;
+                       pstat->state |= WIFI_FW_AUTH_SUCCESS;
+                       pstat->expire_to = pstapriv->assoc_to;
+                       pstat->authalg = algorithm;
+               } else {
+                       DBG_8723A("(2)auth rejected because out of seq "
+                                 "[rx_seq =%d, exp_seq =%d]!\n",
+                                 seq, pstat->auth_seq+1);
+                       status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+                       goto auth_fail;
+               }
+       } else { /*  shared system or auto authentication */
+               if (seq == 1) {
+                       /* prepare for the challenging txt... */
+                       pstat->state &= ~WIFI_FW_AUTH_NULL;
+                       pstat->state |= WIFI_FW_AUTH_STATE;
+                       pstat->authalg = algorithm;
+                       pstat->auth_seq = 2;
+               } else if (seq == 3) {
+                       /* checking for challenging txt... */
+                       DBG_8723A("checking for challenging txt...\n");
+
+                       p = rtw_get_ie23a(pframe +
+                                         sizeof(struct ieee80211_hdr_3addr) +
+                                         4 + _AUTH_IE_OFFSET_, _CHLGETXT_IE_,
+                                         (int *)&ie_len, len -
+                                         sizeof(struct ieee80211_hdr_3addr) -
+                                         _AUTH_IE_OFFSET_ - 4);
+
+                       if ((p == NULL) || (ie_len<= 0)) {
+                               DBG_8723A("auth rejected because challenge "
+                                         "failure!(1)\n");
+                               status = WLAN_STATUS_CHALLENGE_FAIL;
+                               goto auth_fail;
+                       }
+
+                       if (!memcmp((void *)(p + 2), pstat->chg_txt, 128)) {
+                               pstat->state &= (~WIFI_FW_AUTH_STATE);
+                               pstat->state |= WIFI_FW_AUTH_SUCCESS;
+                               /*  challenging txt is correct... */
+                               pstat->expire_to =  pstapriv->assoc_to;
+                       } else {
+                               DBG_8723A("auth rejected because challenge "
+                                         "failure!\n");
+                               status = WLAN_STATUS_CHALLENGE_FAIL;
+                               goto auth_fail;
+                       }
+               } else {
+                       DBG_8723A("(3)auth rejected because out of seq "
+                                 "[rx_seq =%d, exp_seq =%d]!\n",
+                                 seq, pstat->auth_seq+1);
+                       status = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+                       goto auth_fail;
+               }
+       }
+
+       /*  Now, we are going to issue_auth23a... */
+       pstat->auth_seq = seq + 1;
+
+       issue_auth23a(padapter, pstat, (unsigned short)WLAN_STATUS_SUCCESS);
+
+       if (pstat->state & WIFI_FW_AUTH_SUCCESS)
+               pstat->auth_seq = 0;
+
+       return _SUCCESS;
+
+auth_fail:
+
+       if (pstat)
+               rtw_free_stainfo23a(padapter, pstat);
+
+       pstat = &stat;
+       memset((char *)pstat, '\0', sizeof(stat));
+       pstat->auth_seq = 2;
+       memcpy(pstat->hwaddr, sa, 6);
+
+       issue_auth23a(padapter, pstat, (unsigned short)status);
+
+#endif
+       return _FAIL;
+}
+
+unsigned int OnAuth23aClient23a(struct rtw_adapter *padapter,
+                               struct recv_frame *precv_frame)
+{
+       unsigned int    seq, len, status, algthm, offset;
+       unsigned char   *p;
+       unsigned int    go2asoc = 0;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+       uint pkt_len = skb->len;
+
+       DBG_8723A("%s\n", __func__);
+
+       /* check A1 matches or not */
+       if (!ether_addr_equal(myid(&padapter->eeprompriv),
+                             ieee80211_get_DA(hdr)))
+               return _SUCCESS;
+
+       if (!(pmlmeinfo->state & WIFI_FW_AUTH_STATE))
+               return _SUCCESS;
+
+       offset = ieee80211_has_protected(hdr->frame_control) ? 4: 0;
+
+       algthm  = le16_to_cpu(*(unsigned short *)((unsigned long)pframe + sizeof(struct ieee80211_hdr_3addr) + offset));
+       seq     = le16_to_cpu(*(unsigned short *)((unsigned long)pframe + sizeof(struct ieee80211_hdr_3addr) + offset + 2));
+       status  = le16_to_cpu(*(unsigned short *)((unsigned long)pframe + sizeof(struct ieee80211_hdr_3addr) + offset + 4));
+
+       if (status != 0)
+       {
+               DBG_8723A("clnt auth fail, status: %d\n", status);
+               if (status == 13)/*  pmlmeinfo->auth_algo == dot11AuthAlgrthm_Auto) */
+               {
+                       if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
+                               pmlmeinfo->auth_algo = dot11AuthAlgrthm_Open;
+                       else
+                               pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared;
+                       /* pmlmeinfo->reauth_count = 0; */
+               }
+
+               set_link_timer(pmlmeext, 1);
+               goto authclnt_fail;
+       }
+
+       if (seq == 2)
+       {
+               if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
+               {
+                        /*  legendary shared system */
+                       p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _AUTH_IE_OFFSET_, _CHLGETXT_IE_, (int *)&len,
+                               pkt_len - sizeof(struct ieee80211_hdr_3addr) - _AUTH_IE_OFFSET_);
+
+                       if (p == NULL)
+                       {
+                               /* DBG_8723A("marc: no challenge text?\n"); */
+                               goto authclnt_fail;
+                       }
+
+                       memcpy((void *)(pmlmeinfo->chg_txt), (void *)(p + 2), len);
+                       pmlmeinfo->auth_seq = 3;
+                       issue_auth23a(padapter, NULL, 0);
+                       set_link_timer(pmlmeext, REAUTH_TO);
+
+                       return _SUCCESS;
+               }
+               else
+               {
+                       /*  open system */
+                       go2asoc = 1;
+               }
+       }
+       else if (seq == 4)
+       {
+               if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)
+               {
+                       go2asoc = 1;
+               }
+               else
+               {
+                       goto authclnt_fail;
+               }
+       }
+       else
+       {
+               /*  this is also illegal */
+               /* DBG_8723A("marc: clnt auth failed due to illegal seq =%x\n", seq); */
+               goto authclnt_fail;
+       }
+
+       if (go2asoc)
+       {
+               DBG_8723A_LEVEL(_drv_always_, "auth success, start assoc\n");
+               start_clnt_assoc23a(padapter);
+               return _SUCCESS;
+       }
+
+authclnt_fail:
+
+       /* pmlmeinfo->state &= ~(WIFI_FW_AUTH_STATE); */
+
+       return _FAIL;
+}
+
+unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
+{
+#ifdef CONFIG_8723AU_AP_MODE
+       u16 capab_info, listen_interval;
+       struct rtw_ieee802_11_elems elems;
+       struct sta_info *pstat;
+       unsigned char           reassoc, *p, *pos, *wpa_ie;
+       unsigned char WMM_IE[] = {0x00, 0x50, 0xf2, 0x02, 0x00, 0x01};
+       int             i, ie_len, wpa_ie_len, left;
+       unsigned char           supportRate[16];
+       int                                     supportRateNum;
+       unsigned short          status = WLAN_STATUS_SUCCESS;
+       unsigned short ie_offset;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur = &pmlmeinfo->network;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct sk_buff *skb = precv_frame->pkt;
+       u8 *pframe = skb->data;
+       uint pkt_len = skb->len;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u16 frame_control;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       u8 p2p_status_code = P2P_STATUS_SUCCESS;
+       u8 *p2pie;
+       u32 p2pielen = 0;
+       u8      wfd_ie[ 128 ] = { 0x00 };
+       u32     wfd_ielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+
+       if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+               return _FAIL;
+
+       frame_control = hdr->frame_control;
+       if (ieee80211_is_assoc_req(frame_control)) {
+               reassoc = 0;
+               ie_offset = _ASOCREQ_IE_OFFSET_;
+       } else { /*  WIFI_REASSOCREQ */
+               reassoc = 1;
+               ie_offset = _REASOCREQ_IE_OFFSET_;
+       }
+
+       if (pkt_len < sizeof(struct ieee80211_hdr_3addr) + ie_offset) {
+               DBG_8723A("handle_assoc(reassoc =%d) - too short payload (len =%lu)"
+                      "\n", reassoc, (unsigned long)pkt_len);
+               return _FAIL;
+       }
+
+       pstat = rtw_get_stainfo23a(pstapriv, hdr->addr2);
+       if (!pstat) {
+               status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA;
+               goto asoc_class2_error;
+       }
+
+       capab_info = get_unaligned_le16(pframe + sizeof(struct ieee80211_hdr_3addr));
+       /* capab_info = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr))); */
+       /* listen_interval = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr)+2)); */
+       listen_interval = get_unaligned_le16(pframe + sizeof(struct ieee80211_hdr_3addr)+2);
+
+       left = pkt_len - (sizeof(struct ieee80211_hdr_3addr) + ie_offset);
+       pos = pframe + (sizeof(struct ieee80211_hdr_3addr) + ie_offset);
+
+       DBG_8723A("%s\n", __func__);
+
+       /*  check if this stat has been successfully authenticated/assocated */
+       if (!((pstat->state) & WIFI_FW_AUTH_SUCCESS))
+       {
+               if (!((pstat->state) & WIFI_FW_ASSOC_SUCCESS))
+               {
+                       status = WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA;
+                       goto asoc_class2_error;
+               }
+               else
+               {
+                       pstat->state &= (~WIFI_FW_ASSOC_SUCCESS);
+                       pstat->state |= WIFI_FW_ASSOC_STATE;
+               }
+       }
+       else
+       {
+               pstat->state &= (~WIFI_FW_AUTH_SUCCESS);
+               pstat->state |= WIFI_FW_ASSOC_STATE;
+       }
+
+       pstat->capability = capab_info;
+
+       /* now parse all ieee802_11 ie to point to elems */
+       if (rtw_ieee802_11_parse_elems23a(pos, left, &elems, 1) == ParseFailed ||
+           !elems.ssid) {
+               DBG_8723A("STA " MAC_FMT " sent invalid association request\n",
+                      MAC_ARG(pstat->hwaddr));
+               status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               goto OnAssocReq23aFail;
+       }
+
+       /*  now we should check all the fields... */
+       /*  checking SSID */
+       p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, _SSID_IE_, &ie_len,
+               pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset);
+       if (p == NULL)
+       {
+               status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       if (ie_len == 0) /*  broadcast ssid, however it is not allowed in assocreq */
+               status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+       else {
+               /*  check if ssid match */
+               if (memcmp((void *)(p+2), cur->Ssid.ssid, cur->Ssid.ssid_len))
+                       status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+               if (ie_len != cur->Ssid.ssid_len)
+                       status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+       }
+
+       if (WLAN_STATUS_SUCCESS != status)
+               goto OnAssocReq23aFail;
+
+       /*  check if the supported rate is ok */
+       p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, _SUPPORTEDRATES_IE_, &ie_len, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset);
+       if (p == NULL) {
+               DBG_8723A("Rx a sta assoc-req which supported rate is empty!\n");
+               /*  use our own rate set as statoin used */
+               /* memcpy(supportRate, AP_BSSRATE, AP_BSSRATE_LEN); */
+               /* supportRateNum = AP_BSSRATE_LEN; */
+
+               status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               goto OnAssocReq23aFail;
+       } else {
+               memcpy(supportRate, p+2, ie_len);
+               supportRateNum = ie_len;
+
+               p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, _EXT_SUPPORTEDRATES_IE_, &ie_len,
+                               pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset);
+               if (p !=  NULL) {
+
+                       if (supportRateNum<= sizeof(supportRate))
+                       {
+                               memcpy(supportRate+supportRateNum, p+2, ie_len);
+                               supportRateNum += ie_len;
+                       }
+               }
+       }
+
+       /* todo: mask supportRate between AP & STA -> move to update raid */
+       /* get_matched_rate(pmlmeext, supportRate, &supportRateNum, 0); */
+
+       /* update station supportRate */
+       pstat->bssratelen = supportRateNum;
+       memcpy(pstat->bssrateset, supportRate, supportRateNum);
+       Update23aTblForSoftAP(pstat->bssrateset, pstat->bssratelen);
+
+       /* check RSN/WPA/WPS */
+       pstat->dot8021xalg = 0;
+       pstat->wpa_psk = 0;
+       pstat->wpa_group_cipher = 0;
+       pstat->wpa2_group_cipher = 0;
+       pstat->wpa_pairwise_cipher = 0;
+       pstat->wpa2_pairwise_cipher = 0;
+       memset(pstat->wpa_ie, 0, sizeof(pstat->wpa_ie));
+       if ((psecuritypriv->wpa_psk & BIT(1)) && elems.rsn_ie) {
+
+               int group_cipher = 0, pairwise_cipher = 0;
+
+               wpa_ie = elems.rsn_ie;
+               wpa_ie_len = elems.rsn_ie_len;
+
+               if (rtw_parse_wpa2_ie23a(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+                       pstat->dot8021xalg = 1;/* psk,  todo:802.1x */
+                       pstat->wpa_psk |= BIT(1);
+
+                       pstat->wpa2_group_cipher = group_cipher&psecuritypriv->wpa2_group_cipher;
+                       pstat->wpa2_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa2_pairwise_cipher;
+
+                       if (!pstat->wpa2_group_cipher)
+                               status = WLAN_REASON_INVALID_GROUP_CIPHER;
+
+                       if (!pstat->wpa2_pairwise_cipher)
+                               status = WLAN_REASON_INVALID_PAIRWISE_CIPHER;
+               } else {
+                       status = WLAN_STATUS_INVALID_IE;
+               }
+
+       } else if ((psecuritypriv->wpa_psk & BIT(0)) && elems.wpa_ie) {
+
+               int group_cipher = 0, pairwise_cipher = 0;
+
+               wpa_ie = elems.wpa_ie;
+               wpa_ie_len = elems.wpa_ie_len;
+
+               if (rtw_parse_wpa_ie23a(wpa_ie-2, wpa_ie_len+2, &group_cipher, &pairwise_cipher, NULL) == _SUCCESS) {
+                       pstat->dot8021xalg = 1;/* psk,  todo:802.1x */
+                       pstat->wpa_psk |= BIT(0);
+
+                       pstat->wpa_group_cipher = group_cipher&psecuritypriv->wpa_group_cipher;
+                       pstat->wpa_pairwise_cipher = pairwise_cipher&psecuritypriv->wpa_pairwise_cipher;
+
+                       if (!pstat->wpa_group_cipher)
+                               status = WLAN_STATUS_INVALID_GROUP_CIPHER;
+
+                       if (!pstat->wpa_pairwise_cipher)
+                               status = WLAN_STATUS_INVALID_PAIRWISE_CIPHER;
+
+               } else {
+                       status = WLAN_STATUS_INVALID_IE;
+               }
+
+       } else {
+               wpa_ie = NULL;
+               wpa_ie_len = 0;
+       }
+
+       if (WLAN_STATUS_SUCCESS != status)
+               goto OnAssocReq23aFail;
+
+       pstat->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+       if (wpa_ie == NULL) {
+               if (elems.wps_ie) {
+                       DBG_8723A("STA included WPS IE in "
+                                  "(Re)Association Request - assume WPS is "
+                                  "used\n");
+                       pstat->flags |= WLAN_STA_WPS;
+               } else {
+                       DBG_8723A("STA did not include WPA/RSN IE "
+                                  "in (Re)Association Request - possible WPS "
+                                  "use\n");
+                       pstat->flags |= WLAN_STA_MAYBE_WPS;
+               }
+
+               /*  AP support WPA/RSN, and sta is going to do WPS, but AP is not ready */
+               /*  that the selected registrar of AP is _FLASE */
+               if ((psecuritypriv->wpa_psk > 0) &&
+                   (pstat->flags & (WLAN_STA_WPS|WLAN_STA_MAYBE_WPS))) {
+                       if (pmlmepriv->wps_beacon_ie) {
+                               u8 selected_registrar = 0;
+
+                               rtw_get_wps_attr_content23a(pmlmepriv->wps_beacon_ie, pmlmepriv->wps_beacon_ie_len,
+                                                        WPS_ATTR_SELECTED_REGISTRAR, &selected_registrar, NULL);
+
+                               if (!selected_registrar) {
+                                       DBG_8723A("selected_registrar is false , or AP is not ready to do WPS\n");
+
+                                       status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+                                       goto OnAssocReq23aFail;
+                               }
+                       }
+               }
+       } else {
+               int copy_len;
+
+               if (psecuritypriv->wpa_psk == 0) {
+                       DBG_8723A("STA " MAC_FMT ": WPA/RSN IE in association "
+                       "request, but AP don't support WPA/RSN\n", MAC_ARG(pstat->hwaddr));
+
+                       status = WLAN_STATUS_INVALID_IE;
+
+                       goto OnAssocReq23aFail;
+               }
+
+               if (elems.wps_ie) {
+                       DBG_8723A("STA included WPS IE in "
+                                  "(Re)Association Request - WPS is "
+                                  "used\n");
+                       pstat->flags |= WLAN_STA_WPS;
+                       copy_len = 0;
+               } else {
+                       copy_len = ((wpa_ie_len+2) > sizeof(pstat->wpa_ie)) ? (sizeof(pstat->wpa_ie)):(wpa_ie_len+2);
+               }
+
+               if (copy_len>0)
+                       memcpy(pstat->wpa_ie, wpa_ie-2, copy_len);
+
+       }
+
+       /*  check if there is WMM IE & support WWM-PS */
+       pstat->flags &= ~WLAN_STA_WME;
+       pstat->qos_option = 0;
+       pstat->qos_info = 0;
+       pstat->has_legacy_ac = true;
+       pstat->uapsd_vo = 0;
+       pstat->uapsd_vi = 0;
+       pstat->uapsd_be = 0;
+       pstat->uapsd_bk = 0;
+       if (pmlmepriv->qospriv.qos_option)
+       {
+               p = pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset; ie_len = 0;
+               for (;;)
+               {
+                       p = rtw_get_ie23a(p, _VENDOR_SPECIFIC_IE_, &ie_len, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset);
+                       if (p != NULL) {
+                               if (!memcmp(p+2, WMM_IE, 6)) {
+
+                                       pstat->flags |= WLAN_STA_WME;
+
+                                       pstat->qos_option = 1;
+                                       pstat->qos_info = *(p+8);
+
+                                       pstat->max_sp_len = (pstat->qos_info>>5)&0x3;
+
+                                       if ((pstat->qos_info&0xf) != 0xf)
+                                               pstat->has_legacy_ac = true;
+                                       else
+                                               pstat->has_legacy_ac = false;
+
+                                       if (pstat->qos_info&0xf)
+                                       {
+                                               if (pstat->qos_info&BIT(0))
+                                                       pstat->uapsd_vo = BIT(0)|BIT(1);
+                                               else
+                                                       pstat->uapsd_vo = 0;
+
+                                               if (pstat->qos_info&BIT(1))
+                                                       pstat->uapsd_vi = BIT(0)|BIT(1);
+                                               else
+                                                       pstat->uapsd_vi = 0;
+
+                                               if (pstat->qos_info&BIT(2))
+                                                       pstat->uapsd_bk = BIT(0)|BIT(1);
+                                               else
+                                                       pstat->uapsd_bk = 0;
+
+                                               if (pstat->qos_info&BIT(3))
+                                                       pstat->uapsd_be = BIT(0)|BIT(1);
+                                               else
+                                                       pstat->uapsd_be = 0;
+
+                                       }
+
+                                       break;
+                               }
+                       }
+                       else {
+                               break;
+                       }
+                       p = p + ie_len + 2;
+               }
+       }
+
+       /* save HT capabilities in the sta object */
+       memset(&pstat->htpriv.ht_cap, 0, sizeof(struct ieee80211_ht_cap));
+       if (elems.ht_capabilities && elems.ht_capabilities_len >= sizeof(struct ieee80211_ht_cap))
+       {
+               pstat->flags |= WLAN_STA_HT;
+
+               pstat->flags |= WLAN_STA_WME;
+
+               memcpy(&pstat->htpriv.ht_cap, elems.ht_capabilities, sizeof(struct ieee80211_ht_cap));
+
+       } else
+               pstat->flags &= ~WLAN_STA_HT;
+
+       if ((pmlmepriv->htpriv.ht_option == false) && (pstat->flags&WLAN_STA_HT))
+       {
+               status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+               goto OnAssocReq23aFail;
+       }
+
+       if ((pstat->flags & WLAN_STA_HT) &&
+                   ((pstat->wpa2_pairwise_cipher&WPA_CIPHER_TKIP) ||
+                     (pstat->wpa_pairwise_cipher&WPA_CIPHER_TKIP)))
+       {
+               DBG_8723A("HT: " MAC_FMT " tried to "
+                                  "use TKIP with HT association\n", MAC_ARG(pstat->hwaddr));
+
+               /* status = WLAN_STATUS_CIPHER_REJECTED_PER_POLICY; */
+               /* goto OnAssocReq23aFail; */
+       }
+
+       /*  */
+       pstat->flags |= WLAN_STA_NONERP;
+       for (i = 0; i < pstat->bssratelen; i++) {
+               if ((pstat->bssrateset[i] & 0x7f) > 22) {
+                       pstat->flags &= ~WLAN_STA_NONERP;
+                       break;
+               }
+       }
+
+       if (pstat->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+               pstat->flags |= WLAN_STA_SHORT_PREAMBLE;
+       else
+               pstat->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+
+       if (status != WLAN_STATUS_SUCCESS)
+               goto OnAssocReq23aFail;
+
+#ifdef CONFIG_8723AU_P2P
+       pstat->is_p2p_device = false;
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+       {
+               if ((p2pie = rtw_get_p2p_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset, NULL, &p2pielen)))
+               {
+                       pstat->is_p2p_device = true;
+                       if ((p2p_status_code = (u8)process_assoc_req_p2p_ie23a(pwdinfo, pframe, pkt_len, pstat))>0)
+                       {
+                               pstat->p2p_status_code = p2p_status_code;
+                               status = WLAN_STATUS_CAPS_UNSUPPORTED;
+                               goto OnAssocReq23aFail;
+                       }
+               }
+#ifdef CONFIG_8723AU_P2P
+               if (rtw_get_wfd_ie(pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset, pkt_len - sizeof(struct ieee80211_hdr_3addr) - ie_offset, wfd_ie, &wfd_ielen))
+               {
+                       u8      attr_content[ 10 ] = { 0x00 };
+                       u32     attr_contentlen = 0;
+
+                       DBG_8723A("[%s] WFD IE Found!!\n", __func__);
+                       rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen);
+                       if (attr_contentlen)
+                       {
+                               pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2);
+                               DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport);
+                       }
+               }
+#endif
+       }
+       pstat->p2p_status_code = p2p_status_code;
+#endif /* CONFIG_8723AU_P2P */
+
+       /* TODO: identify_proprietary_vendor_ie(); */
+       /*  Realtek proprietary IE */
+       /*  identify if this is Broadcom sta */
+       /*  identify if this is ralink sta */
+       /*  Customer proprietary IE */
+
+       /* get a unique AID */
+       if (pstat->aid > 0) {
+               DBG_8723A("  old AID %d\n", pstat->aid);
+       } else {
+               for (pstat->aid = 1; pstat->aid <= NUM_STA; pstat->aid++)
+                       if (pstapriv->sta_aid[pstat->aid - 1] == NULL)
+                               break;
+
+               if (pstat->aid > NUM_STA)
+                       pstat->aid = NUM_STA;
+               if (pstat->aid > pstapriv->max_num_sta) {
+
+                       pstat->aid = 0;
+
+                       DBG_8723A("  no room for more AIDs\n");
+
+                       status = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+
+                       goto OnAssocReq23aFail;
+
+               } else {
+                       pstapriv->sta_aid[pstat->aid - 1] = pstat;
+                       DBG_8723A("allocate new AID = (%d)\n", pstat->aid);
+               }
+       }
+
+       pstat->state &= (~WIFI_FW_ASSOC_STATE);
+       pstat->state |= WIFI_FW_ASSOC_SUCCESS;
+
+       spin_lock_bh(&pstapriv->auth_list_lock);
+       if (!list_empty(&pstat->auth_list)) {
+               list_del_init(&pstat->auth_list);
+               pstapriv->auth_list_cnt--;
+       }
+       spin_unlock_bh(&pstapriv->auth_list_lock);
+
+       spin_lock_bh(&pstapriv->asoc_list_lock);
+       if (list_empty(&pstat->asoc_list)) {
+               pstat->expire_to = pstapriv->expire_to;
+               list_add_tail(&pstat->asoc_list, &pstapriv->asoc_list);
+               pstapriv->asoc_list_cnt++;
+       }
+       spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+       /*  now the station is qualified to join our BSS... */
+       if (pstat && (pstat->state & WIFI_FW_ASSOC_SUCCESS) &&
+           (WLAN_STATUS_SUCCESS == status)) {
+#ifdef CONFIG_8723AU_AP_MODE
+               /* 1 bss_cap_update & sta_info_update23a */
+               bss_cap_update_on_sta_join23a(padapter, pstat);
+               sta_info_update23a(padapter, pstat);
+
+               /* issue assoc rsp before notify station join event. */
+               if (ieee80211_is_assoc_req(frame_control))
+                       issue_asocrsp23a(padapter, status, pstat, WIFI_ASSOCRSP);
+               else
+                       issue_asocrsp23a(padapter, status, pstat, WIFI_REASSOCRSP);
+
+               /* 2 - report to upper layer */
+               DBG_8723A("indicate_sta_join_event to upper layer - hostapd\n");
+               rtw_cfg80211_indicate_sta_assoc(padapter, pframe, pkt_len);
+
+               /* 3-(1) report sta add event */
+               report_add_sta_event23a(padapter, pstat->hwaddr, pstat->aid);
+#endif
+       }
+
+       return _SUCCESS;
+
+asoc_class2_error:
+
+#ifdef CONFIG_8723AU_AP_MODE
+       issue_deauth23a(padapter, hdr->addr2, status);
+#endif
+
+       return _FAIL;
+
+OnAssocReq23aFail:
+
+#ifdef CONFIG_8723AU_AP_MODE
+       pstat->aid = 0;
+       if (ieee80211_is_assoc_req(frame_control))
+               issue_asocrsp23a(padapter, status, pstat, WIFI_ASSOCRSP);
+       else
+               issue_asocrsp23a(padapter, status, pstat, WIFI_REASSOCRSP);
+#endif
+
+#endif /* CONFIG_8723AU_AP_MODE */
+
+       return _FAIL;
+}
+
+unsigned int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
+{
+       uint i;
+       int res;
+       unsigned short  status;
+       struct ndis_802_11_var_ies *pIE;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+       uint pkt_len = skb->len;
+
+       DBG_8723A("%s\n", __func__);
+
+       /* check A1 matches or not */
+       if (!ether_addr_equal(myid(&padapter->eeprompriv),
+                             ieee80211_get_DA(hdr)))
+               return _SUCCESS;
+
+       if (!(pmlmeinfo->state & (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE)))
+               return _SUCCESS;
+
+       if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
+               return _SUCCESS;
+
+       del_timer_sync(&pmlmeext->link_timer);
+
+       /* status */
+       if ((status = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr) + 2))) > 0)
+       {
+               DBG_8723A("assoc reject, status code: %d\n", status);
+               pmlmeinfo->state = WIFI_FW_NULL_STATE;
+               res = -4;
+               goto report_assoc_result;
+       }
+
+       /* get capabilities */
+       pmlmeinfo->capability = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr)));
+
+       /* set slot time */
+       pmlmeinfo->slotTime = (pmlmeinfo->capability & BIT(10))? 9: 20;
+
+       /* AID */
+       res = pmlmeinfo->aid = (int)(le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr) + 4))&0x3fff);
+
+       /* following are moved to join event callback function */
+       /* to handle HT, WMM, rate adaptive, update MAC reg */
+       /* for not to handle the synchronous IO in the tasklet */
+       for (i = (6 + sizeof(struct ieee80211_hdr_3addr)); i < pkt_len;) {
+               pIE = (struct ndis_802_11_var_ies *)(pframe + i);
+
+               switch (pIE->ElementID)
+               {
+               case _VENDOR_SPECIFIC_IE_:
+                       if (!memcmp(pIE->data, WMM_PARA_OUI23A, 6))/* WMM */
+                                       WMM_param_handler23a(padapter, pIE);
+#if defined(CONFIG_8723AU_P2P)
+                       else if (!memcmp(pIE->data, WFD_OUI23A, 4)) { /* WFD */
+                               DBG_8723A("[%s] Found WFD IE\n", __func__);
+                               WFD_info_handler(padapter, pIE);
+                       }
+#endif
+                       break;
+
+               case _HT_CAPABILITY_IE_:        /* HT caps */
+                       HT_caps_handler23a(padapter, pIE);
+                       break;
+
+               case _HT_EXTRA_INFO_IE_:        /* HT info */
+                       HT_info_handler23a(padapter, pIE);
+                       break;
+
+               case _ERPINFO_IE_:
+                       ERP_IE_handler23a(padapter, pIE);
+
+               default:
+                       break;
+               }
+
+               i += (pIE->Length + 2);
+       }
+
+       pmlmeinfo->state &= (~WIFI_FW_ASSOC_STATE);
+       pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+
+       /* Update Basic Rate Table for spec, 2010-12-28 , by thomas */
+       UpdateBrateTbl23a(padapter, pmlmeinfo->network.SupportedRates);
+
+report_assoc_result:
+       pmlmepriv->assoc_rsp_len = 0;
+       if (res > 0) {
+               kfree(pmlmepriv->assoc_rsp);
+               pmlmepriv->assoc_rsp = kmalloc(pkt_len, GFP_ATOMIC);
+               if (pmlmepriv->assoc_rsp) {
+                       memcpy(pmlmepriv->assoc_rsp, pframe, pkt_len);
+                       pmlmepriv->assoc_rsp_len = pkt_len;
+               }
+       } else
+               kfree(pmlmepriv->assoc_rsp);
+
+       report_join_res23a(padapter, res);
+
+       return _SUCCESS;
+}
+
+unsigned int OnDeAuth23a(struct rtw_adapter *padapter,
+                        struct recv_frame *precv_frame)
+{
+       unsigned short  reason;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_8723AU_P2P */
+
+       /* check A3 */
+       if (!ether_addr_equal(hdr->addr3, get_my_bssid23a(&pmlmeinfo->network)))
+               return _SUCCESS;
+
+#ifdef CONFIG_8723AU_P2P
+       if (pwdinfo->rx_invitereq_info.scan_op_ch_only) {
+               mod_timer(&pwdinfo->reset_ch_sitesurvey,
+                         jiffies + msecs_to_jiffies(10));
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       reason = le16_to_cpu(*(unsigned short *)(pframe + sizeof(struct ieee80211_hdr_3addr)));
+
+       DBG_8723A("%s Reason code(%d)\n", __func__, reason);
+
+#ifdef CONFIG_8723AU_AP_MODE
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
+               struct sta_info *psta;
+               struct sta_priv *pstapriv = &padapter->stapriv;
+
+               DBG_8723A_LEVEL(_drv_always_, "ap recv deauth reason code(%d) "
+                               "sta:%pM\n", reason, hdr->addr2);
+
+               psta = rtw_get_stainfo23a(pstapriv, hdr->addr2);
+               if (psta) {
+                       u8 updated = 0;
+
+                       spin_lock_bh(&pstapriv->asoc_list_lock);
+                       if (!list_empty(&psta->asoc_list)) {
+                               list_del_init(&psta->asoc_list);
+                               pstapriv->asoc_list_cnt--;
+                               updated = ap_free_sta23a(padapter, psta,
+                                                     false, reason);
+                       }
+                       spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+                       associated_clients_update23a(padapter, updated);
+               }
+
+               return _SUCCESS;
+       }
+       else
+#endif
+       {
+               DBG_8723A_LEVEL(_drv_always_, "sta recv deauth reason code(%d) "
+                               "sta:%pM\n", reason, hdr->addr3);
+
+               receive_disconnect23a(padapter, hdr->addr3, reason);
+       }
+       pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+       return _SUCCESS;
+}
+
+unsigned int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
+{
+       unsigned short  reason;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_8723AU_P2P */
+
+       /* check A3 */
+       if (!ether_addr_equal(hdr->addr3, get_my_bssid23a(&pmlmeinfo->network)))
+               return _SUCCESS;
+
+#ifdef CONFIG_8723AU_P2P
+       if (pwdinfo->rx_invitereq_info.scan_op_ch_only)
+       {
+               mod_timer(&pwdinfo->reset_ch_sitesurvey,
+                         jiffies + msecs_to_jiffies(10));
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       reason = le16_to_cpu(*(unsigned short *)
+                            (pframe + sizeof(struct ieee80211_hdr_3addr)));
+
+        DBG_8723A("%s Reason code(%d)\n", __func__, reason);
+
+#ifdef CONFIG_8723AU_AP_MODE
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+               struct sta_info *psta;
+               struct sta_priv *pstapriv = &padapter->stapriv;
+
+               DBG_8723A_LEVEL(_drv_always_, "ap recv disassoc reason code(%d)"
+                               " sta:%pM\n", reason, hdr->addr2);
+
+               psta = rtw_get_stainfo23a(pstapriv, hdr->addr2);
+               if (psta) {
+                       u8 updated = 0;
+
+                       spin_lock_bh(&pstapriv->asoc_list_lock);
+                       if (!list_empty(&psta->asoc_list)) {
+                               list_del_init(&psta->asoc_list);
+                               pstapriv->asoc_list_cnt--;
+                               updated = ap_free_sta23a(padapter, psta,
+                                                     false, reason);
+                       }
+                       spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+                       associated_clients_update23a(padapter, updated);
+               }
+
+               return _SUCCESS;
+       }
+       else
+#endif
+       {
+               DBG_8723A_LEVEL(_drv_always_, "ap recv disassoc reason "
+                               "code(%d) sta:%pM\n", reason, hdr->addr3);
+
+               receive_disconnect23a(padapter, hdr->addr3, reason);
+       }
+       pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+       return _SUCCESS;
+}
+
+unsigned int OnAtim23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
+{
+       DBG_8723A("%s\n", __func__);
+       return _SUCCESS;
+}
+
+unsigned int on_action_spct23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
+{
+       return _FAIL;
+}
+
+unsigned int OnAction23a_qos(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
+{
+       return _SUCCESS;
+}
+
+unsigned int OnAction23a_dls(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
+{
+       return _SUCCESS;
+}
+
+unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
+{
+       u8 *addr;
+       struct sta_info *psta = NULL;
+       struct recv_reorder_ctrl *preorder_ctrl;
+       unsigned char           *frame_body;
+       unsigned char           category, action;
+       unsigned short  tid, status, reason_code = 0;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+
+       /* check RA matches or not */
+       if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1))
+               return _SUCCESS;
+
+       DBG_8723A("%s\n", __func__);
+
+       if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+               if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
+                       return _SUCCESS;
+
+       addr = hdr->addr2;
+       psta = rtw_get_stainfo23a(pstapriv, addr);
+
+       if (!psta)
+               return _SUCCESS;
+
+       frame_body = (unsigned char *)
+               (pframe + sizeof(struct ieee80211_hdr_3addr));
+
+       category = frame_body[0];
+       if (category == WLAN_CATEGORY_BACK) { /*  representing Block Ack */
+               if (!pmlmeinfo->HT_enable)
+                       return _SUCCESS;
+               action = frame_body[1];
+               DBG_8723A("%s, action =%d\n", __func__, action);
+               switch (action) {
+               case WLAN_ACTION_ADDBA_REQ: /* ADDBA request */
+                       memcpy(&pmlmeinfo->ADDBA_req, &frame_body[2],
+                              sizeof(struct ADDBA_request));
+                       process_addba_req23a(padapter,
+                                            (u8 *)&pmlmeinfo->ADDBA_req, addr);
+                       if (pmlmeinfo->bAcceptAddbaReq == true)
+                               issue_action_BA23a(padapter, addr,
+                                                  WLAN_ACTION_ADDBA_RESP, 0);
+                       else {
+                               /* reject ADDBA Req */
+                               issue_action_BA23a(padapter, addr,
+                                                  WLAN_ACTION_ADDBA_RESP, 37);
+                       }
+                       break;
+               case WLAN_ACTION_ADDBA_RESP: /* ADDBA response */
+                       status = get_unaligned_le16(&frame_body[3]);
+                       tid = ((frame_body[5] >> 2) & 0x7);
+                       if (status == 0) {      /* successful */
+                               DBG_8723A("agg_enable for TID =%d\n", tid);
+                               psta->htpriv.agg_enable_bitmap |= 1 << tid;
+                               psta->htpriv.candidate_tid_bitmap &=
+                                       ~CHKBIT(tid);
+                       } else
+                               psta->htpriv.agg_enable_bitmap &= ~CHKBIT(tid);
+                       break;
+
+               case WLAN_ACTION_DELBA: /* DELBA */
+                       if ((frame_body[3] & BIT(3)) == 0) {
+                               psta->htpriv.agg_enable_bitmap &=
+                                       ~(1 << ((frame_body[3] >> 4) & 0xf));
+                               psta->htpriv.candidate_tid_bitmap &=
+                                       ~(1 << ((frame_body[3] >> 4) & 0xf));
+
+                               /* reason_code = frame_body[4] | (frame_body[5] << 8); */
+                               reason_code = get_unaligned_le16(&frame_body[4]);
+                       } else if ((frame_body[3] & BIT(3)) == BIT(3)) {
+                               tid = (frame_body[3] >> 4) & 0x0F;
+
+                               preorder_ctrl =  &psta->recvreorder_ctrl[tid];
+                               preorder_ctrl->enable = false;
+                               preorder_ctrl->indicate_seq = 0xffff;
+                       }
+
+                       DBG_8723A("%s(): DELBA: %x(%x)\n", __func__,
+                                 pmlmeinfo->agg_enable_bitmap, reason_code);
+                       /* todo: how to notify the host while receiving
+                          DELETE BA */
+                       break;
+               default:
+                       break;
+               }
+       }
+       return _SUCCESS;
+}
+
+#ifdef CONFIG_8723AU_P2P
+
+static int get_reg_classes_full_count(struct p2p_channels channel_list) {
+       int cnt = 0;
+       int i;
+
+       for (i = 0; i < channel_list.reg_classes; i++)
+               cnt += channel_list.reg_class[i].channels;
+
+       return cnt;
+}
+
+void issue_p2p_GO_request23a(struct rtw_adapter *padapter, u8* raddr)
+{
+       unsigned char category = WLAN_CATEGORY_PUBLIC;
+       u8                      action = P2P_PUB_ACTION_ACTION;
+       u32                     p2poui = cpu_to_be32(P2POUI);
+       u8                      oui_subtype = P2P_GO_NEGO_REQ;
+       u8                      wpsie[ 255 ] = { 0x00 }, p2pie[ 255 ] = { 0x00 };
+       u8                      wpsielen = 0, p2pielen = 0;
+       u16                     len_channellist_attr = 0;
+#ifdef CONFIG_8723AU_P2P
+       u32                                     wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+
+       struct xmit_frame                       *pmgntframe;
+       struct pkt_attrib                       *pattrib;
+       unsigned char                                   *pframe;
+       struct ieee80211_hdr    *pwlanhdr;
+       unsigned short                          *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       DBG_8723A("[%s] In\n", __func__);
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, raddr);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui,
+                                    &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pwdinfo->negotiation_dialog_token = 1;  /*Initialize the dialog value*/
+       pframe = rtw_set_fixed_ie23a(pframe, 1,
+                                    &pwdinfo->negotiation_dialog_token,
+                                    &pattrib->pktlen);
+
+       /*      WPS Section */
+       wpsielen = 0;
+       /*      WPS OUI */
+       *(u32*) (wpsie) = cpu_to_be32(WPSOUI);
+       wpsielen += 4;
+
+       /*      WPS version */
+       /*      Type: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+       wpsielen += 2;
+
+       /*      Length: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001);
+       wpsielen += 2;
+
+       /*      Value: */
+       wpsie[wpsielen++] = WPS_VERSION_1;      /*      Version 1.0 */
+
+       /*      Device Password ID */
+       /*      Type: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+       wpsielen += 2;
+
+       /*      Length: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002);
+       wpsielen += 2;
+
+       /*      Value: */
+
+       if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PEER_DISPLAY_PIN)
+       {
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC);
+       }
+       else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_SELF_DISPLAY_PIN)
+       {
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
+       }
+       else if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC)
+       {
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC);
+       }
+
+       wpsielen += 2;
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen);
+
+       /*      P2P IE Section. */
+
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[p2pielen++] = 0x50;
+       p2pie[p2pielen++] = 0x6F;
+       p2pie[p2pielen++] = 0x9A;
+       p2pie[p2pielen++] = 0x09;       /*      WFA P2P v1.0 */
+
+       /*      Commented by Albert 20110306 */
+       /*      According to the P2P Specification, the group negoitation request frame should contain 9 P2P attributes */
+       /*      1. P2P Capability */
+       /*      2. Group Owner Intent */
+       /*      3. Configuration Timeout */
+       /*      4. Listen Channel */
+       /*      5. Extended Listen Timing */
+       /*      6. Intended P2P Interface Address */
+       /*      7. Channel List */
+       /*      8. P2P Device Info */
+       /*      9. Operating Channel */
+
+       /*      P2P Capability */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Device Capability Bitmap, 1 byte */
+       p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+       /*      Group Capability Bitmap, 1 byte */
+       if (pwdinfo->persistent_supported)
+       {
+               p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN | P2P_GRPCAP_PERSISTENT_GROUP;
+       }
+       else
+       {
+               p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
+       }
+
+       /*      Group Owner Intent */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_GO_INTENT;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Todo the tie breaker bit. */
+       p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0));
+
+       /*      Configuration Timeout */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002);
+       p2pielen += 2;
+
+       /*      Value: */
+       p2pie[p2pielen++] = 200;        /*      2 seconds needed to be the P2P GO */
+       p2pie[p2pielen++] = 200;        /*      2 seconds needed to be the P2P Client */
+
+       /*      Listen Channel */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Country String */
+       p2pie[p2pielen++] = 'X';
+       p2pie[p2pielen++] = 'X';
+
+       /*      The third byte should be set to 0x04. */
+       /*      Described in the "Operating Channel Attribute" section. */
+       p2pie[p2pielen++] = 0x04;
+
+       /*      Operating Class */
+       p2pie[p2pielen++] = 0x51;       /*      Copy from SD7 */
+
+       /*      Channel Number */
+       p2pie[p2pielen++] = pwdinfo->listen_channel;    /*      listening channel number */
+
+       /*      Extended Listen Timing ATTR */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Availability Period */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+       p2pielen += 2;
+
+       /*      Availability Interval */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+       p2pielen += 2;
+
+       /*      Intended P2P Interface Address */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+       p2pielen += 2;
+
+       /*      Value: */
+       memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+       p2pielen += ETH_ALEN;
+
+       /*      Channel List */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+       /*  Length: */
+       /*  Country String(3) */
+       /*  + (Operating Class (1) + Number of Channels(1)) * Operation Classes (?) */
+       /*  + number of channels in all classes */
+       len_channellist_attr = 3
+          + (1 + 1) * (u16)(pmlmeext->channel_list.reg_classes)
+          + get_reg_classes_full_count(pmlmeext->channel_list);
+
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Country String */
+       p2pie[p2pielen++] = 'X';
+       p2pie[p2pielen++] = 'X';
+
+       /*      The third byte should be set to 0x04. */
+       /*      Described in the "Operating Channel Attribute" section. */
+       p2pie[p2pielen++] = 0x04;
+
+       /*      Channel Entry List */
+
+       {
+               int i, j;
+               for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+                       /*      Operating Class */
+                       p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].reg_class;
+
+                       /*      Number of Channels */
+                       p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channels;
+
+                       /*      Channel List */
+                       for (i = 0; i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+                               p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+                       }
+               }
+       }
+
+       /*      Device Info */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+       /*      + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      P2P Device Address */
+       memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+       p2pielen += ETH_ALEN;
+
+       /*      Config Method */
+       /*      This field should be big endian. Noted by P2P specification. */
+
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+
+       p2pielen += 2;
+
+       /*      Primary Device Type */
+       /*      Category ID */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+       p2pielen += 2;
+
+       /*      OUI */
+       *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+       p2pielen += 4;
+
+       /*      Sub Category ID */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+       p2pielen += 2;
+
+       /*      Number of Secondary Device Types */
+       p2pie[p2pielen++] = 0x00;       /*      No Secondary Device Type List */
+
+       /*      Device Name */
+       /*      Type: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+       p2pielen += 2;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+       p2pielen += 2;
+
+       /*      Value: */
+       memcpy(p2pie + p2pielen, pwdinfo->device_name,
+              pwdinfo->device_name_len);
+       p2pielen += pwdinfo->device_name_len;
+
+       /*      Operating Channel */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Country String */
+       p2pie[p2pielen++] = 'X';
+       p2pie[p2pielen++] = 'X';
+
+       /*      The third byte should be set to 0x04. */
+       /*      Described in the "Operating Channel Attribute" section. */
+       p2pie[p2pielen++] = 0x04;
+
+       /*      Operating Class */
+       if (pwdinfo->operating_channel <= 14)
+       {
+               /*      Operating Class */
+               p2pie[p2pielen++] = 0x51;
+       }
+       else if ((pwdinfo->operating_channel >= 36) && (pwdinfo->operating_channel <= 48))
+       {
+               /*      Operating Class */
+               p2pie[p2pielen++] = 0x73;
+       }
+       else
+       {
+               /*      Operating Class */
+               p2pie[p2pielen++] = 0x7c;
+       }
+
+       /*      Channel Number */
+       p2pie[p2pielen++] = pwdinfo->operating_channel; /*      operating channel number */
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_P2P
+       wfdielen = build_nego_req_wfd_ie(pwdinfo, pframe);
+       pframe += wfdielen;
+       pattrib->pktlen += wfdielen;
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+static void issue_p2p_GO_response(struct rtw_adapter *padapter, u8* raddr, u8* frame_body, uint len, u8 result)
+{
+
+       unsigned char category = WLAN_CATEGORY_PUBLIC;
+       u8 action = P2P_PUB_ACTION_ACTION;
+       u32 p2poui = cpu_to_be32(P2POUI);
+       u8 oui_subtype = P2P_GO_NEGO_RESP;
+       u8 wpsie[255] = { 0x00 }, p2pie[255] = { 0x00 };
+       u8 p2pielen = 0;
+       uint wpsielen = 0;
+       u16 wps_devicepassword_id = 0x0000;
+       uint wps_devicepassword_id_len = 0;
+       u16 len_channellist_attr = 0;
+       int i, j;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#ifdef CONFIG_8723AU_P2P
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       DBG_8723A("[%s] In, result = %d\n", __func__,  result);
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, raddr);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui,
+                                    &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       /*      The Dialog Token of provisioning discovery request frame. */
+       pwdinfo->negotiation_dialog_token = frame_body[7];
+       pframe = rtw_set_fixed_ie23a(pframe, 1,
+                                    &pwdinfo->negotiation_dialog_token,
+                                    &pattrib->pktlen);
+
+       /*      Commented by Albert 20110328 */
+       /*      Try to get the device password ID from the WPS IE of group
+               negotiation request frame */
+       /*      WiFi Direct test plan 5.1.15 */
+       rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_,
+                         len - _PUBLIC_ACTION_IE_OFFSET_, wpsie, &wpsielen);
+       rtw_get_wps_attr_content23a(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID,
+                                   (u8 *)&wps_devicepassword_id,
+                                   &wps_devicepassword_id_len);
+       wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id);
+
+       memset(wpsie, 0x00, 255);
+       wpsielen = 0;
+
+       /*      WPS Section */
+       wpsielen = 0;
+       /*      WPS OUI */
+       *(u32*) (wpsie) = cpu_to_be32(WPSOUI);
+       wpsielen += 4;
+
+       /*      WPS version */
+       /*      Type: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+       wpsielen += 2;
+
+       /*      Length: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001);
+       wpsielen += 2;
+
+       /*      Value: */
+       wpsie[wpsielen++] = WPS_VERSION_1;      /*      Version 1.0 */
+
+       /*      Device Password ID */
+       /*      Type: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+       wpsielen += 2;
+
+       /*      Length: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002);
+       wpsielen += 2;
+
+       /*      Value: */
+       if (wps_devicepassword_id == WPS_DPID_USER_SPEC) {
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
+       } else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) {
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_USER_SPEC);
+       } else {
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_DPID_PBC);
+       }
+       wpsielen += 2;
+
+       /*      Commented by Kurt 20120113 */
+       /*      If some device wants to do p2p handshake without sending prov_disc_req */
+       /*      We have to get peer_req_cm from here. */
+       if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3)) {
+               if (wps_devicepassword_id == WPS_DPID_USER_SPEC) {
+                       memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
+               } else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC) {
+                       memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
+               } else {
+                       memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
+               }
+       }
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen,
+                              (unsigned char *) wpsie, &pattrib->pktlen);
+
+       /*      P2P IE Section. */
+
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[p2pielen++] = 0x50;
+       p2pie[p2pielen++] = 0x6F;
+       p2pie[p2pielen++] = 0x9A;
+       p2pie[p2pielen++] = 0x09;       /*      WFA P2P v1.0 */
+
+       /*      Commented by Albert 20100908 */
+       /*      According to the P2P Specification, the group negoitation
+               response frame should contain 9 P2P attributes */
+       /*      1. Status */
+       /*      2. P2P Capability */
+       /*      3. Group Owner Intent */
+       /*      4. Configuration Timeout */
+       /*      5. Operating Channel */
+       /*      6. Intended P2P Interface Address */
+       /*      7. Channel List */
+       /*      8. Device Info */
+       /*      9. Group ID     (Only GO) */
+
+       /*      ToDo: */
+
+       /*      P2P Status */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_STATUS;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001);
+       p2pielen += 2;
+
+       /*      Value: */
+       p2pie[p2pielen++] = result;
+
+       /*      P2P Capability */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Device Capability Bitmap, 1 byte */
+
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+               /*      Commented by Albert 2011/03/08 */
+               /*      According to the P2P specification */
+               /*      if the sending device will be client, the P2P
+                       Capability should be reserved of group negotation
+                       response frame */
+               p2pie[p2pielen++] = 0;
+       } else {
+               /*      Be group owner or meet the error case */
+               p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+       }
+
+       /*      Group Capability Bitmap, 1 byte */
+       if (pwdinfo->persistent_supported) {
+               p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN |
+                       P2P_GRPCAP_PERSISTENT_GROUP;
+       } else {
+               p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
+       }
+
+       /*      Group Owner Intent */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_GO_INTENT;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001);
+       p2pielen += 2;
+
+       /*      Value: */
+       if (pwdinfo->peer_intent & 0x01) {
+               /*      Peer's tie breaker bit is 1, our tie breaker
+                       bit should be 0 */
+               p2pie[p2pielen++] = (pwdinfo->intent << 1);
+       } else {
+               /* Peer's tie breaker bit is 0, our tie breaker bit
+                  should be 1 */
+               p2pie[p2pielen++] = ((pwdinfo->intent << 1) | BIT(0));
+       }
+
+       /*      Configuration Timeout */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      2 seconds needed to be the P2P GO */
+       p2pie[p2pielen++] = 200;
+       /*      2 seconds needed to be the P2P Client */
+       p2pie[p2pielen++] = 200;
+
+       /*      Operating Channel */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Country String */
+       p2pie[p2pielen++] = 'X';
+       p2pie[p2pielen++] = 'X';
+
+       /*      The third byte should be set to 0x04. */
+       /*      Described in the "Operating Channel Attribute" section. */
+       p2pie[p2pielen++] = 0x04;
+
+       /*      Operating Class */
+       if (pwdinfo->operating_channel <= 14) {
+               /*      Operating Class */
+               p2pie[p2pielen++] = 0x51;
+       } else if ((pwdinfo->operating_channel >= 36) &&
+                  (pwdinfo->operating_channel <= 48)) {
+               /*      Operating Class */
+               p2pie[p2pielen++] = 0x73;
+       } else {
+               /*      Operating Class */
+               p2pie[p2pielen++] = 0x7c;
+       }
+
+       /*      Channel Number */
+       /*      operating channel number */
+       p2pie[p2pielen++] = pwdinfo->operating_channel;
+
+       /*      Intended P2P Interface Address */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_INTENTED_IF_ADDR;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+       p2pielen += 2;
+
+       /*      Value: */
+       memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+       p2pielen += ETH_ALEN;
+
+       /*      Channel List */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+       /*  Country String(3) */
+       /*  + (Operating Class (1) + Number of Channels(1)) *
+           Operation Classes (?) */
+       /*  + number of channels in all classes */
+       len_channellist_attr = 3 +
+               (1 + 1) * (u16)pmlmeext->channel_list.reg_classes +
+               get_reg_classes_full_count(pmlmeext->channel_list);
+
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Country String */
+       p2pie[p2pielen++] = 'X';
+       p2pie[p2pielen++] = 'X';
+
+       /*      The third byte should be set to 0x04. */
+       /*      Described in the "Operating Channel Attribute" section. */
+       p2pie[p2pielen++] = 0x04;
+
+       /*      Channel Entry List */
+
+       for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+               /*      Operating Class */
+               p2pie[p2pielen++] =
+                       pmlmeext->channel_list.reg_class[j].reg_class;
+
+               /*      Number of Channels */
+               p2pie[p2pielen++] =
+                       pmlmeext->channel_list.reg_class[j].channels;
+
+               /*      Channel List */
+               for (i = 0;
+                    i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+                       p2pie[p2pielen++] =
+                               pmlmeext->channel_list.reg_class[j].channel[i];
+               }
+       }
+
+       /*      Device Info */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      21 -> P2P Device Address (6bytes) + Config Methods (2bytes) +
+               Primary Device Type (8bytes) */
+       /*      + NumofSecondDevType (1byte) + WPS Device Name ID field
+               (2bytes) + WPS Device Name Len field (2bytes) */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      P2P Device Address */
+       memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+       p2pielen += ETH_ALEN;
+
+       /*      Config Method */
+       /*      This field should be big endian. Noted by P2P specification. */
+
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm);
+
+       p2pielen += 2;
+
+       /*      Primary Device Type */
+       /*      Category ID */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+       p2pielen += 2;
+
+       /*      OUI */
+       *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+       p2pielen += 4;
+
+       /*      Sub Category ID */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+       p2pielen += 2;
+
+       /*      Number of Secondary Device Types */
+       p2pie[p2pielen++] = 0x00;       /*      No Secondary Device Type List */
+
+       /*      Device Name */
+       /*      Type: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+       p2pielen += 2;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+       p2pielen += 2;
+
+       /*      Value: */
+       memcpy(p2pie + p2pielen, pwdinfo->device_name,
+              pwdinfo->device_name_len);
+       p2pielen += pwdinfo->device_name_len;
+
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+       {
+               /*      Group ID Attribute */
+               /*      Type: */
+               p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+               /*      Length: */
+               *(u16*) (p2pie + p2pielen) =
+                       cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen);
+               p2pielen += 2;
+
+               /*      Value: */
+               /*      p2P Device Address */
+               memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
+               p2pielen += ETH_ALEN;
+
+               /*      SSID */
+               memcpy(p2pie + p2pielen, pwdinfo->nego_ssid,
+                      pwdinfo->nego_ssidlen);
+               p2pielen += pwdinfo->nego_ssidlen;
+
+       }
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen,
+                              (unsigned char *) p2pie, &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_P2P
+       wfdielen = build_nego_resp_wfd_ie(pwdinfo, pframe);
+       pframe += wfdielen;
+       pattrib->pktlen += wfdielen;
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+static void issue_p2p_GO_confirm(struct rtw_adapter *padapter, u8* raddr,
+                                u8 result)
+{
+
+       unsigned char category = WLAN_CATEGORY_PUBLIC;
+       u8 action = P2P_PUB_ACTION_ACTION;
+       u32 p2poui = cpu_to_be32(P2POUI);
+       u8 oui_subtype = P2P_GO_NEGO_CONF;
+       u8 p2pie[ 255 ] = { 0x00 };
+       u8 p2pielen = 0;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#ifdef CONFIG_8723AU_P2P
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       DBG_8723A("[%s] In\n", __func__);
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, raddr);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui,
+                                    &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1,
+                                    &pwdinfo->negotiation_dialog_token,
+                                 &pattrib->pktlen);
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[p2pielen++] = 0x50;
+       p2pie[p2pielen++] = 0x6F;
+       p2pie[p2pielen++] = 0x9A;
+       p2pie[p2pielen++] = 0x09;       /*      WFA P2P v1.0 */
+
+       /*      Commented by Albert 20110306 */
+       /*      According to the P2P Specification, the group negoitation
+               request frame should contain 5 P2P attributes */
+       /*      1. Status */
+       /*      2. P2P Capability */
+       /*      3. Operating Channel */
+       /*      4. Channel List */
+       /*      5. Group ID     (if this WiFi is GO) */
+
+       /*      P2P Status */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_STATUS;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001);
+       p2pielen += 2;
+
+       /*      Value: */
+       p2pie[p2pielen++] = result;
+
+       /*      P2P Capability */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Device Capability Bitmap, 1 byte */
+       p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+       /*      Group Capability Bitmap, 1 byte */
+       if (pwdinfo->persistent_supported) {
+               p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN |
+                       P2P_GRPCAP_PERSISTENT_GROUP;
+       } else {
+               p2pie[p2pielen++] = P2P_GRPCAP_CROSS_CONN;
+       }
+
+       /*      Operating Channel */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Country String */
+       p2pie[p2pielen++] = 'X';
+       p2pie[p2pielen++] = 'X';
+
+       /*      The third byte should be set to 0x04. */
+       /*      Described in the "Operating Channel Attribute" section. */
+       p2pie[p2pielen++] = 0x04;
+
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT)) {
+               if (pwdinfo->peer_operating_ch <= 14) {
+                       /*      Operating Class */
+                       p2pie[p2pielen++] = 0x51;
+               } else if ((pwdinfo->peer_operating_ch >= 36) &&
+                        (pwdinfo->peer_operating_ch <= 48)) {
+                       /*      Operating Class */
+                       p2pie[p2pielen++] = 0x73;
+               } else {
+                       /*      Operating Class */
+                       p2pie[p2pielen++] = 0x7c;
+               }
+
+               p2pie[p2pielen++] = pwdinfo->peer_operating_ch;
+       } else {
+               if (pwdinfo->operating_channel <= 14) {
+                       /*      Operating Class */
+                       p2pie[p2pielen++] = 0x51;
+               }
+               else if ((pwdinfo->operating_channel >= 36) &&
+                        (pwdinfo->operating_channel <= 48)) {
+                       /*      Operating Class */
+                       p2pie[p2pielen++] = 0x73;
+               } else {
+                       /*      Operating Class */
+                       p2pie[p2pielen++] = 0x7c;
+               }
+
+               /*      Channel Number */
+               /*      Use the listen channel as the operating channel */
+               p2pie[p2pielen++] = pwdinfo->operating_channel;
+       }
+
+       /*      Channel List */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) =
+               cpu_to_le16(pwdinfo->channel_list_attr_len);
+       p2pielen += 2;
+
+       /*      Value: */
+       memcpy(p2pie + p2pielen, pwdinfo->channel_list_attr,
+              pwdinfo->channel_list_attr_len);
+       p2pielen += pwdinfo->channel_list_attr_len;
+
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+               /*      Group ID Attribute */
+               /*      Type: */
+               p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+               /*      Length: */
+               *(u16*) (p2pie + p2pielen) =
+                       cpu_to_le16(ETH_ALEN + pwdinfo->nego_ssidlen);
+               p2pielen += 2;
+
+               /*      Value: */
+               /*      p2P Device Address */
+               memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
+               p2pielen += ETH_ALEN;
+
+               /*      SSID */
+               memcpy(p2pie + p2pielen, pwdinfo->nego_ssid,
+                      pwdinfo->nego_ssidlen);
+               p2pielen += pwdinfo->nego_ssidlen;
+       }
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen,
+                              (unsigned char *)p2pie, &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_P2P
+       wfdielen = build_nego_confirm_wfd_ie(pwdinfo, pframe);
+       pframe += wfdielen;
+       pattrib->pktlen += wfdielen;
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+void issue_p2p_invitation_request23a(struct rtw_adapter *padapter, u8* raddr)
+{
+       unsigned char category = WLAN_CATEGORY_PUBLIC;
+       u8 action = P2P_PUB_ACTION_ACTION;
+       u32 p2poui = cpu_to_be32(P2POUI);
+       u8 oui_subtype = P2P_INVIT_REQ;
+       u8 p2pie[ 255 ] = { 0x00 };
+       u8 p2pielen = 0;
+       u8 dialogToken = 3;
+       u16 len_channellist_attr = 0;
+#ifdef CONFIG_8723AU_P2P
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+       int i, j;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, raddr);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, raddr);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui,
+                                    &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen);
+
+       /*      P2P IE Section. */
+
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[p2pielen++] = 0x50;
+       p2pie[p2pielen++] = 0x6F;
+       p2pie[p2pielen++] = 0x9A;
+       p2pie[p2pielen++] = 0x09;       /*      WFA P2P v1.0 */
+
+       /*      Commented by Albert 20101011 */
+       /*      According to the P2P Specification, the P2P Invitation
+               request frame should contain 7 P2P attributes */
+       /*      1. Configuration Timeout */
+       /*      2. Invitation Flags */
+       /*      3. Operating Channel    (Only GO) */
+       /*      4. P2P Group BSSID      (Should be included if I am the GO) */
+       /*      5. Channel List */
+       /*      6. P2P Group ID */
+       /*      7. P2P Device Info */
+
+       /*      Configuration Timeout */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      2 seconds needed to be the P2P GO */
+       p2pie[p2pielen++] = 200;
+       /*      2 seconds needed to be the P2P Client */
+       p2pie[p2pielen++] = 200;
+
+       /*      Invitation Flags */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_INVITATION_FLAGS;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001);
+       p2pielen += 2;
+
+       /*      Value: */
+       p2pie[p2pielen++] = P2P_INVITATION_FLAGS_PERSISTENT;
+
+       /*      Operating Channel */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Country String */
+       p2pie[p2pielen++] = 'X';
+       p2pie[p2pielen++] = 'X';
+
+       /*      The third byte should be set to 0x04. */
+       /*      Described in the "Operating Channel Attribute" section. */
+       p2pie[p2pielen++] = 0x04;
+
+       /*      Operating Class */
+       if (pwdinfo->invitereq_info.operating_ch <= 14)
+               p2pie[p2pielen++] = 0x51;
+       else if ((pwdinfo->invitereq_info.operating_ch >= 36) &&
+                (pwdinfo->invitereq_info.operating_ch <= 48))
+               p2pie[p2pielen++] = 0x73;
+       else
+               p2pie[p2pielen++] = 0x7c;
+
+       /*      Channel Number */
+       /*      operating channel number */
+       p2pie[p2pielen++] = pwdinfo->invitereq_info.operating_ch;
+
+       if (ether_addr_equal(myid(&padapter->eeprompriv),
+                            pwdinfo->invitereq_info.go_bssid)) {
+               /*      P2P Group BSSID */
+               /*      Type: */
+               p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID;
+
+               /*      Length: */
+               *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+               p2pielen += 2;
+
+               /*      Value: */
+               /*      P2P Device Address for GO */
+               memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid,
+                      ETH_ALEN);
+               p2pielen += ETH_ALEN;
+       }
+
+       /*      Channel List */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+       /*      Length: */
+       /*  Country String(3) */
+       /*  + (Operating Class (1) + Number of Channels(1)) *
+           Operation Classes (?) */
+       /*  + number of channels in all classes */
+       len_channellist_attr = 3 +
+               (1 + 1) * (u16)pmlmeext->channel_list.reg_classes +
+               get_reg_classes_full_count(pmlmeext->channel_list);
+
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Country String */
+       p2pie[p2pielen++] = 'X';
+       p2pie[p2pielen++] = 'X';
+
+       /*      The third byte should be set to 0x04. */
+       /*      Described in the "Operating Channel Attribute" section. */
+       p2pie[p2pielen++] = 0x04;
+
+       /*      Channel Entry List */
+       for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+               /*      Operating Class */
+               p2pie[p2pielen++] =
+                       pmlmeext->channel_list.reg_class[j].reg_class;
+
+               /*      Number of Channels */
+               p2pie[p2pielen++] =
+                       pmlmeext->channel_list.reg_class[j].channels;
+
+               /*      Channel List */
+               for (i = 0;
+                    i < pmlmeext->channel_list.reg_class[j].channels; i++) {
+                       p2pie[p2pielen++] =
+                               pmlmeext->channel_list.reg_class[j].channel[i];
+               }
+       }
+
+       /*      P2P Group ID */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_GROUP_ID;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) =
+               cpu_to_le16(6 + pwdinfo->invitereq_info.ssidlen);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      P2P Device Address for GO */
+       memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_bssid, ETH_ALEN);
+       p2pielen += ETH_ALEN;
+
+       /*      SSID */
+       memcpy(p2pie + p2pielen, pwdinfo->invitereq_info.go_ssid,
+              pwdinfo->invitereq_info.ssidlen);
+       p2pielen += pwdinfo->invitereq_info.ssidlen;
+
+       /*      Device Info */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      21 -> P2P Device Address (6bytes) + Config Methods (2bytes) +
+               Primary Device Type (8bytes) */
+       /*      + NumofSecondDevType (1byte) + WPS Device Name ID field
+               (2bytes) + WPS Device Name Len field (2bytes) */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      P2P Device Address */
+       memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv), ETH_ALEN);
+       p2pielen += ETH_ALEN;
+
+       /*      Config Method */
+       /*      This field should be big endian. Noted by P2P specification. */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY);
+       p2pielen += 2;
+
+       /*      Primary Device Type */
+       /*      Category ID */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+       p2pielen += 2;
+
+       /*      OUI */
+       *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+       p2pielen += 4;
+
+       /*      Sub Category ID */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+       p2pielen += 2;
+
+       /*      Number of Secondary Device Types */
+       p2pie[p2pielen++] = 0x00;       /*      No Secondary Device Type List */
+
+       /*      Device Name */
+       /*      Type: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+       p2pielen += 2;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len);
+       p2pielen += 2;
+
+       /*      Value: */
+       memcpy(p2pie + p2pielen, pwdinfo->device_name,
+              pwdinfo->device_name_len);
+       p2pielen += pwdinfo->device_name_len;
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen,
+                              (unsigned char *) p2pie, &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_P2P
+       wfdielen = build_invitation_req_wfd_ie(pwdinfo, pframe);
+       pframe += wfdielen;
+       pattrib->pktlen += wfdielen;
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+void issue_p2p_invitation_response23a(struct rtw_adapter *padapter, u8 *raddr,
+                                     u8 dialogToken, u8 status_code)
+{
+       unsigned char category = WLAN_CATEGORY_PUBLIC;
+       u8 action = P2P_PUB_ACTION_ACTION;
+       u32 p2poui = cpu_to_be32(P2POUI);
+       u8 oui_subtype = P2P_INVIT_RESP;
+       u8 p2pie[ 255 ] = { 0x00 };
+       u8 p2pielen = 0;
+       u16 len_channellist_attr = 0;
+#ifdef CONFIG_8723AU_P2P
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+       int i, j;
+
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, raddr);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, raddr);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui,
+                                    &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen);
+
+       /*      P2P IE Section. */
+
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[p2pielen++] = 0x50;
+       p2pie[p2pielen++] = 0x6F;
+       p2pie[p2pielen++] = 0x9A;
+       p2pie[p2pielen++] = 0x09;       /*      WFA P2P v1.0 */
+
+       /*      Commented by Albert 20101005 */
+       /*      According to the P2P Specification, the P2P Invitation
+               response frame should contain 5 P2P attributes */
+       /*      1. Status */
+       /*      2. Configuration Timeout */
+       /*      3. Operating Channel    (Only GO) */
+       /*      4. P2P Group BSSID      (Only GO) */
+       /*      5. Channel List */
+
+       /*      P2P Status */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_STATUS;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0001);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      When status code is P2P_STATUS_FAIL_INFO_UNAVAILABLE. */
+       /*      Sent the event receiving the P2P Invitation Req frame
+               to DMP UI. */
+       /*      DMP had to compare the MAC address to find out the profile. */
+       /*      So, the WiFi driver will send the
+               P2P_STATUS_FAIL_INFO_UNAVAILABLE to NB. */
+       /*      If the UI found the corresponding profile, the WiFi driver
+               sends the P2P Invitation Req */
+       /*      to NB to rebuild the persistent group. */
+       p2pie[p2pielen++] = status_code;
+
+       /*      Configuration Timeout */
+       /*      Type: */
+       p2pie[p2pielen++] = P2P_ATTR_CONF_TIMEOUT;
+
+       /*      Length: */
+       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      2 seconds needed to be the P2P GO */
+       p2pie[p2pielen++] = 200;
+       /*      2 seconds needed to be the P2P Client */
+       p2pie[p2pielen++] = 200;
+
+       if (status_code == P2P_STATUS_SUCCESS) {
+               if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+                       /* The P2P Invitation request frame asks this
+                          Wi-Fi device to be the P2P GO */
+                       /* In this case, the P2P Invitation response
+                          frame should carry the two more P2P attributes. */
+                       /* First one is operating channel attribute. */
+                       /* Second one is P2P Group BSSID attribute. */
+
+                       /* Operating Channel */
+                       /* Type: */
+                       p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+                       /* Length: */
+                       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005);
+                       p2pielen += 2;
+
+                       /* Value: */
+                       /* Country String */
+                       p2pie[p2pielen++] = 'X';
+                       p2pie[p2pielen++] = 'X';
+
+                       /* The third byte should be set to 0x04. */
+                       /* Described in the "Operating Channel Attribute"
+                          section. */
+                       p2pie[p2pielen++] = 0x04;
+
+                       /* Operating Class */
+                       /*      Copy from SD7 */
+                       p2pie[p2pielen++] = 0x51;
+
+                       /* Channel Number */
+                       /*      operating channel number */
+                       p2pie[p2pielen++] = pwdinfo->operating_channel;
+
+                       /*      P2P Group BSSID */
+                       /*      Type: */
+                       p2pie[p2pielen++] = P2P_ATTR_GROUP_BSSID;
+
+                       /*      Length: */
+                       *(u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN);
+                       p2pielen += 2;
+
+                       /*      Value: */
+                       /*      P2P Device Address for GO */
+                       memcpy(p2pie + p2pielen, myid(&padapter->eeprompriv),
+                              ETH_ALEN);
+                       p2pielen += ETH_ALEN;
+               }
+
+               /*      Channel List */
+               /*      Type: */
+               p2pie[p2pielen++] = P2P_ATTR_CH_LIST;
+
+               /*      Length: */
+               /*  Country String(3) */
+               /*  + (Operating Class (1) + Number of Channels(1)) *
+                   Operation Classes (?) */
+               /*  + number of channels in all classes */
+               len_channellist_attr = 3 +
+                       (1 + 1) * (u16)pmlmeext->channel_list.reg_classes +
+                       get_reg_classes_full_count(pmlmeext->channel_list);
+
+               *(u16*) (p2pie + p2pielen) = cpu_to_le16(len_channellist_attr);
+               p2pielen += 2;
+
+               /*      Value: */
+               /*      Country String */
+               p2pie[p2pielen++] = 'X';
+               p2pie[p2pielen++] = 'X';
+
+               /* The third byte should be set to 0x04. */
+               /* Described in the "Operating Channel Attribute" section. */
+               p2pie[p2pielen++] = 0x04;
+
+               /*      Channel Entry List */
+               for (j = 0; j < pmlmeext->channel_list.reg_classes; j++) {
+                       /*      Operating Class */
+                       p2pie[p2pielen++] =
+                               pmlmeext->channel_list.reg_class[j].reg_class;
+
+                       /*      Number of Channels */
+                       p2pie[p2pielen++] =
+                               pmlmeext->channel_list.reg_class[j].channels;
+
+                       /*      Channel List */
+                       for (i = 0;
+                            i < pmlmeext->channel_list.reg_class[j].channels;
+                            i++) {
+                               p2pie[p2pielen++] = pmlmeext->channel_list.reg_class[j].channel[i];
+                       }
+               }
+       }
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen,
+                              (unsigned char *)p2pie, &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_P2P
+       wfdielen = build_invitation_resp_wfd_ie(pwdinfo, pframe);
+       pframe += wfdielen;
+       pattrib->pktlen += wfdielen;
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+void issue_p2p_provision_request23a(struct rtw_adapter *padapter, u8 *pssid,
+                                   u8 ussidlen, u8 *pdev_raddr)
+{
+       unsigned char category = WLAN_CATEGORY_PUBLIC;
+       u8 action = P2P_PUB_ACTION_ACTION;
+       u8 dialogToken = 1;
+       u32 p2poui = cpu_to_be32(P2POUI);
+       u8 oui_subtype = P2P_PROVISION_DISC_REQ;
+       u8 wpsie[100] = { 0x00 };
+       u8 wpsielen = 0;
+       u32 p2pielen = 0;
+#ifdef CONFIG_8723AU_P2P
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       DBG_8723A("[%s] In\n", __func__);
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, pdev_raddr);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, pdev_raddr);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui,
+                                    &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen);
+
+       p2pielen = build_prov_disc_request_p2p_ie23a(pwdinfo, pframe, pssid,
+                                                    ussidlen, pdev_raddr);
+
+       pframe += p2pielen;
+       pattrib->pktlen += p2pielen;
+
+       wpsielen = 0;
+       /*      WPS OUI */
+       *(u32*) (wpsie) = cpu_to_be32(WPSOUI);
+       wpsielen += 4;
+
+       /*      WPS version */
+       /*      Type: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+       wpsielen += 2;
+
+       /*      Length: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001);
+       wpsielen += 2;
+
+       /*      Value: */
+       wpsie[wpsielen++] = WPS_VERSION_1;      /*      Version 1.0 */
+
+       /*      Config Method */
+       /*      Type: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+       wpsielen += 2;
+
+       /*      Length: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002);
+       wpsielen += 2;
+
+       /*      Value: */
+       *(u16*) (wpsie + wpsielen) = cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request);
+       wpsielen += 2;
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen,
+                              (unsigned char *) wpsie, &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_P2P
+       wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe);
+       pframe += wfdielen;
+       pattrib->pktlen += wfdielen;
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+static u8 is_matched_in_profilelist(u8 *peermacaddr,
+                                   struct profile_info *profileinfo)
+{
+       u8 i, match_result = 0;
+
+       DBG_8723A("[%s] peermac = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__,
+                 peermacaddr[0], peermacaddr[1], peermacaddr[2],
+                 peermacaddr[3], peermacaddr[4], peermacaddr[5]);
+
+       for (i = 0; i < P2P_MAX_PERSISTENT_GROUP_NUM; i++, profileinfo++) {
+              DBG_8723A("[%s] profileinfo_mac = %.2X %.2X %.2X %.2X %.2X "
+                        "%.2X\n", __func__, profileinfo->peermac[0],
+                        profileinfo->peermac[1], profileinfo->peermac[2],
+                        profileinfo->peermac[3], profileinfo->peermac[4],
+                        profileinfo->peermac[5]);
+               if (ether_addr_equal(peermacaddr, profileinfo->peermac)) {
+                       match_result = 1;
+                       DBG_8723A("[%s] Match!\n", __func__);
+                       break;
+               }
+       }
+
+       return match_result;
+}
+
+void issue_probersp23a_p2p23a(struct rtw_adapter *padapter, unsigned char *da)
+{
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       unsigned char *mac;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       u16 beacon_interval = 100;
+       u16 capInfo = 0;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       u8 wpsie[255] = { 0x00 };
+       u32 wpsielen = 0, p2pielen = 0;
+#ifdef CONFIG_8723AU_P2P
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+       struct cfg80211_wifidirect_info *pcfg80211_wdinfo =
+               &padapter->cfg80211_wdinfo;
+       struct ieee80211_channel *ieee_ch =
+               &pcfg80211_wdinfo->remain_on_ch_channel;
+       u8 listen_channel =
+               (u8)ieee80211_frequency_to_channel(ieee_ch->center_freq);
+
+       /* DBG_8723A("%s\n", __func__); */
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+       {
+               return;
+       }
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       mac = myid(&padapter->eeprompriv);
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+       ether_addr_copy(pwlanhdr->addr1, da);
+       ether_addr_copy(pwlanhdr->addr2, mac);
+
+       /*      Use the device address for BSSID field. */
+       ether_addr_copy(pwlanhdr->addr3, mac);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(fctrl, WIFI_PROBERSP);
+
+       pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = pattrib->hdrlen;
+       pframe += pattrib->hdrlen;
+
+       /* timestamp will be inserted by hardware */
+       pframe += 8;
+       pattrib->pktlen += 8;
+
+       /*  beacon interval: 2 bytes */
+       memcpy(pframe, (unsigned char *) &beacon_interval, 2);
+       pframe += 2;
+       pattrib->pktlen += 2;
+
+       /*      capability info: 2 bytes */
+       /*      ESS and IBSS bits must be 0 (defined in the 3.1.2.1.1 of
+               WiFi Direct Spec) */
+       capInfo |= cap_ShortPremble;
+       capInfo |= cap_ShortSlot;
+
+       memcpy(pframe, (unsigned char *) &capInfo, 2);
+       pframe += 2;
+       pattrib->pktlen += 2;
+
+       /*  SSID */
+       pframe = rtw_set_ie23a(pframe, _SSID_IE_, 7, pwdinfo->p2p_wildcard_ssid,
+                              &pattrib->pktlen);
+
+       /*  supported rates... */
+       /*      Use the OFDM rate in the P2P probe response frame.
+               (6(B), 9(B), 12, 18, 24, 36, 48, 54) */
+       pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8,
+                              pwdinfo->support_rate, &pattrib->pktlen);
+
+       /*  DS parameter set */
+       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled &&
+           listen_channel != 0) {
+               pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *)
+                                      &listen_channel, &pattrib->pktlen);
+       } else {
+               pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *)
+                                      &pwdinfo->listen_channel,
+                                      &pattrib->pktlen);
+       }
+
+       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) {
+               if (pmlmepriv->wps_probe_resp_ie &&
+                   pmlmepriv->p2p_probe_resp_ie) {
+                       /* WPS IE */
+                       memcpy(pframe, pmlmepriv->wps_probe_resp_ie,
+                              pmlmepriv->wps_probe_resp_ie_len);
+                       pattrib->pktlen += pmlmepriv->wps_probe_resp_ie_len;
+                       pframe += pmlmepriv->wps_probe_resp_ie_len;
+
+                       /* P2P IE */
+                       memcpy(pframe, pmlmepriv->p2p_probe_resp_ie,
+                              pmlmepriv->p2p_probe_resp_ie_len);
+                       pattrib->pktlen += pmlmepriv->p2p_probe_resp_ie_len;
+                       pframe += pmlmepriv->p2p_probe_resp_ie_len;
+               }
+       } else {
+
+               /*      Todo: WPS IE */
+               /*      Noted by Albert 20100907 */
+               /*      According to the WPS specification, all the WPS
+                       attribute is presented by Big Endian. */
+
+               wpsielen = 0;
+               /*      WPS OUI */
+               *(u32*) (wpsie) = cpu_to_be32(WPSOUI);
+               wpsielen += 4;
+
+               /*      WPS version */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001);
+               wpsielen += 2;
+
+               /*      Value: */
+               wpsie[wpsielen++] = WPS_VERSION_1;      /*      Version 1.0 */
+
+               /*      WiFi Simple Config State */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(WPS_ATTR_SIMPLE_CONF_STATE);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001);
+               wpsielen += 2;
+
+               /*      Value: */
+               wpsie[wpsielen++] = WPS_WSC_STATE_NOT_CONFIG;
+
+               /*      Response Type */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_RESP_TYPE);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001);
+               wpsielen += 2;
+
+               /*      Value: */
+               wpsie[wpsielen++] = WPS_RESPONSE_TYPE_8021X;
+
+               /*      UUID-E */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_UUID_E);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0010);
+               wpsielen += 2;
+
+               /*      Value: */
+               memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv), ETH_ALEN);
+               wpsielen += 0x10;
+
+               /*      Manufacturer */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MANUFACTURER);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0007);
+               wpsielen += 2;
+
+               /*      Value: */
+               memcpy(wpsie + wpsielen, "Realtek", 7);
+               wpsielen += 7;
+
+               /*      Model Name */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NAME);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0006);
+               wpsielen += 2;
+
+               /*      Value: */
+               memcpy(wpsie + wpsielen, "8192CU", 6);
+               wpsielen += 6;
+
+               /*      Model Number */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_MODEL_NUMBER);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001);
+               wpsielen += 2;
+
+               /*      Value: */
+               wpsie[ wpsielen++ ] = 0x31;             /*      character 1 */
+
+               /*      Serial Number */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(WPS_ATTR_SERIAL_NUMBER);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(ETH_ALEN);
+               wpsielen += 2;
+
+               /*      Value: */
+               memcpy(wpsie + wpsielen, "123456", ETH_ALEN);
+               wpsielen += ETH_ALEN;
+
+               /*      Primary Device Type */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0008);
+               wpsielen += 2;
+
+               /*      Value: */
+               /*      Category ID */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+               wpsielen += 2;
+
+               /*      OUI */
+               *(u32*) (wpsie + wpsielen) = cpu_to_be32(WPSOUI);
+               wpsielen += 4;
+
+               /*      Sub Category ID */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+               wpsielen += 2;
+
+               /*      Device Name */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(pwdinfo->device_name_len);
+               wpsielen += 2;
+
+               /*      Value: */
+               if (pwdinfo->device_name_len) {
+                       memcpy(wpsie + wpsielen, pwdinfo->device_name,
+                              pwdinfo->device_name_len);
+                       wpsielen += pwdinfo->device_name_len;
+               }
+
+               /*      Config Method */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002);
+               wpsielen += 2;
+
+               /*      Value: */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(pwdinfo->supported_wps_cm);
+               wpsielen += 2;
+
+               pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen,
+                                      (unsigned char *)wpsie,
+                                      &pattrib->pktlen);
+
+               p2pielen = build_probe_resp_p2p_ie23a(pwdinfo, pframe);
+               pframe += p2pielen;
+               pattrib->pktlen += p2pielen;
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       if (pwdinfo->wfd_info->wfd_enable) {
+               wfdielen = build_probe_resp_wfd_ie(pwdinfo, pframe, 0);
+               pframe += wfdielen;
+               pattrib->pktlen += wfdielen;
+       } else if (pmlmepriv->wfd_probe_resp_ie &&
+                pmlmepriv->wfd_probe_resp_ie_len > 0) {
+               /* WFD IE */
+               memcpy(pframe, pmlmepriv->wfd_probe_resp_ie,
+                      pmlmepriv->wfd_probe_resp_ie_len);
+               pattrib->pktlen += pmlmepriv->wfd_probe_resp_ie_len;
+               pframe += pmlmepriv->wfd_probe_resp_ie_len;
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+static int _issue23a_probereq_p2p(struct rtw_adapter *padapter, u8 *da,
+                                 int wait_ack)
+{
+       int ret = _FAIL;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       unsigned char *mac;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       u8      bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+       struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+       u8 wpsie[255] = {0x00}, p2pie[255] = {0x00};
+       u16 wpsielen = 0, p2pielen = 0;
+#ifdef CONFIG_8723AU_P2P
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               goto exit;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       mac = myid(&padapter->eeprompriv);
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       if (da) {
+               ether_addr_copy(pwlanhdr->addr1, da);
+               ether_addr_copy(pwlanhdr->addr3, da);
+       } else {
+               if ((pwdinfo->p2p_info.scan_op_ch_only) ||
+                   (pwdinfo->rx_invitereq_info.scan_op_ch_only)) {
+                       /*      This two flags will be set when this is
+                               only the P2P client mode. */
+                       ether_addr_copy(pwlanhdr->addr1,
+                                       pwdinfo->p2p_peer_interface_addr);
+                       ether_addr_copy(pwlanhdr->addr3,
+                                       pwdinfo->p2p_peer_interface_addr);
+               } else {
+                       /*      broadcast probe request frame */
+                       ether_addr_copy(pwlanhdr->addr1, bc_addr);
+                       ether_addr_copy(pwlanhdr->addr3, bc_addr);
+               }
+       }
+       ether_addr_copy(pwlanhdr->addr2, mac);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_PROBEREQ);
+
+       pframe += sizeof (struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof (struct ieee80211_hdr_3addr);
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ)) {
+               pframe = rtw_set_ie23a(pframe, _SSID_IE_,
+                                   pwdinfo->tx_prov_disc_info.ssid.ssid_len,
+                                   pwdinfo->tx_prov_disc_info.ssid.ssid,
+                                   &pattrib->pktlen);
+       } else {
+               pframe = rtw_set_ie23a(pframe, _SSID_IE_,
+                                      P2P_WILDCARD_SSID_LEN,
+                                      pwdinfo->p2p_wildcard_ssid,
+                                      &pattrib->pktlen);
+       }
+       /*      Use the OFDM rate in the P2P probe request frame.
+               (6(B), 9(B), 12(B), 24(B), 36, 48, 54) */
+       pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8,
+                              pwdinfo->support_rate, &pattrib->pktlen);
+
+       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) {
+               if (pmlmepriv->wps_probe_req_ie &&
+                   pmlmepriv->p2p_probe_req_ie) {
+                       /* WPS IE */
+                       memcpy(pframe, pmlmepriv->wps_probe_req_ie,
+                              pmlmepriv->wps_probe_req_ie_len);
+                       pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;
+                       pframe += pmlmepriv->wps_probe_req_ie_len;
+
+                       /* P2P IE */
+                       memcpy(pframe, pmlmepriv->p2p_probe_req_ie,
+                              pmlmepriv->p2p_probe_req_ie_len);
+                       pattrib->pktlen += pmlmepriv->p2p_probe_req_ie_len;
+                       pframe += pmlmepriv->p2p_probe_req_ie_len;
+               }
+       } else {
+
+               /*      WPS IE */
+               /*      Noted by Albert 20110221 */
+               /*      According to the WPS specification, all the WPS
+                       attribute is presented by Big Endian. */
+
+               wpsielen = 0;
+               /*      WPS OUI */
+               *(u32*) (wpsie) = cpu_to_be32(WPSOUI);
+               wpsielen += 4;
+
+               /*      WPS version */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0001);
+               wpsielen += 2;
+
+               /*      Value: */
+               wpsie[wpsielen++] = WPS_VERSION_1;      /*      Version 1.0 */
+
+               if (pmlmepriv->wps_probe_req_ie == NULL) {
+                       /*      UUID-E */
+                       /*      Type: */
+                       *(u16*) (wpsie + wpsielen) =
+                               cpu_to_be16(WPS_ATTR_UUID_E);
+                       wpsielen += 2;
+
+                       /*      Length: */
+                       *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0010);
+                       wpsielen += 2;
+
+                       /*      Value: */
+                       memcpy(wpsie + wpsielen, myid(&padapter->eeprompriv),
+                              ETH_ALEN);
+                       wpsielen += 0x10;
+
+                       /*      Config Method */
+                       /*      Type: */
+                       *(u16*) (wpsie + wpsielen) =
+                               cpu_to_be16(WPS_ATTR_CONF_METHOD);
+                       wpsielen += 2;
+
+                       /*      Length: */
+                       *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002);
+                       wpsielen += 2;
+
+                       /*      Value: */
+                       *(u16*) (wpsie + wpsielen) =
+                               cpu_to_be16(pwdinfo->supported_wps_cm);
+                       wpsielen += 2;
+               }
+
+               /*      Device Name */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(pwdinfo->device_name_len);
+               wpsielen += 2;
+
+               /*      Value: */
+               memcpy(wpsie + wpsielen, pwdinfo->device_name,
+                      pwdinfo->device_name_len);
+               wpsielen += pwdinfo->device_name_len;
+
+               /*      Primary Device Type */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0008);
+               wpsielen += 2;
+
+               /*      Value: */
+               /*      Category ID */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_PDT_CID_RTK_WIDI);
+               wpsielen += 2;
+
+               /*      OUI */
+               *(u32*) (wpsie + wpsielen) = cpu_to_be32(WPSOUI);
+               wpsielen += 4;
+
+               /*      Sub Category ID */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_PDT_SCID_RTK_DMP);
+               wpsielen += 2;
+
+               /*      Device Password ID */
+               /*      Type: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_DEVICE_PWID);
+               wpsielen += 2;
+
+               /*      Length: */
+               *(u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002);
+               wpsielen += 2;
+
+               /*      Value: */
+               /*      Registrar-specified */
+               *(u16*) (wpsie + wpsielen) =
+                       cpu_to_be16(WPS_DPID_REGISTRAR_SPEC);
+               wpsielen += 2;
+
+               pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen,
+                                      (unsigned char *)wpsie,
+                                      &pattrib->pktlen);
+
+               /*      P2P OUI */
+               p2pielen = 0;
+               p2pie[p2pielen++] = 0x50;
+               p2pie[p2pielen++] = 0x6F;
+               p2pie[p2pielen++] = 0x9A;
+               p2pie[p2pielen++] = 0x09;       /*      WFA P2P v1.0 */
+
+               /*      Commented by Albert 20110221 */
+               /*      According to the P2P Specification, the probe request
+                       frame should contain 5 P2P attributes */
+               /*      1. P2P Capability */
+               /*      2. P2P Device ID if this probe request wants to
+                       find the specific P2P device */
+               /*      3. Listen Channel */
+               /*      4. Extended Listen Timing */
+               /*      5. Operating Channel if this WiFi is working as
+                       the group owner now */
+
+               /*      P2P Capability */
+               /*      Type: */
+               p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+               /*      Length: */
+               *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002);
+               p2pielen += 2;
+
+               /*      Value: */
+               /*      Device Capability Bitmap, 1 byte */
+               p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+               /*      Group Capability Bitmap, 1 byte */
+               if (pwdinfo->persistent_supported)
+                       p2pie[p2pielen++] = P2P_GRPCAP_PERSISTENT_GROUP |
+                               DMP_P2P_GRPCAP_SUPPORT;
+               else
+                       p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+
+               /*      Listen Channel */
+               /*      Type: */
+               p2pie[p2pielen++] = P2P_ATTR_LISTEN_CH;
+
+               /*      Length: */
+               *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005);
+               p2pielen += 2;
+
+               /*      Value: */
+               /*      Country String */
+               p2pie[p2pielen++] = 'X';
+               p2pie[p2pielen++] = 'X';
+
+               /* The third byte should be set to 0x04. */
+               /* Described in the "Operating Channel Attribute" section. */
+               p2pie[p2pielen++] = 0x04;
+
+               /*      Operating Class */
+               p2pie[p2pielen++] = 0x51;       /*      Copy from SD7 */
+
+               /*      Channel Number */
+               /*      listen channel */
+               p2pie[p2pielen++] = pwdinfo->listen_channel;
+
+               /*      Extended Listen Timing */
+               /*      Type: */
+               p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+               /*      Length: */
+               *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004);
+               p2pielen += 2;
+
+               /*      Value: */
+               /*      Availability Period */
+               *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+               p2pielen += 2;
+
+               /*      Availability Interval */
+               *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+               p2pielen += 2;
+
+               if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+                       /* Operating Channel (if this WiFi is working as
+                          the group owner now) */
+                       /* Type: */
+                       p2pie[p2pielen++] = P2P_ATTR_OPERATING_CH;
+
+                       /*      Length: */
+                       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0005);
+                       p2pielen += 2;
+
+                       /*      Value: */
+                       /*      Country String */
+                       p2pie[p2pielen++] = 'X';
+                       p2pie[p2pielen++] = 'X';
+
+                       /* The third byte should be set to 0x04. */
+                       /* Described in the "Operating Channel Attribute"
+                          section. */
+                       p2pie[p2pielen++] = 0x04;
+
+                       /*      Operating Class */
+                       p2pie[p2pielen++] = 0x51;       /*      Copy from SD7 */
+
+                       /*      Channel Number */
+                       /*      operating channel number */
+                       p2pie[p2pielen++] = pwdinfo->operating_channel;
+               }
+
+               pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen,
+                                      (unsigned char *)p2pie,
+                                      &pattrib->pktlen);
+
+               if (pmlmepriv->wps_probe_req_ie) {
+                       /* WPS IE */
+                       memcpy(pframe, pmlmepriv->wps_probe_req_ie,
+                              pmlmepriv->wps_probe_req_ie_len);
+                       pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;
+                       pframe += pmlmepriv->wps_probe_req_ie_len;
+               }
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       if (pwdinfo->wfd_info->wfd_enable) {
+               wfdielen = build_probe_req_wfd_ie(pwdinfo, pframe);
+               pframe += wfdielen;
+               pattrib->pktlen += wfdielen;
+       } else if (pmlmepriv->wfd_probe_req_ie &&
+                  pmlmepriv->wfd_probe_req_ie_len>0) {
+               /* WFD IE */
+               memcpy(pframe, pmlmepriv->wfd_probe_req_ie,
+                      pmlmepriv->wfd_probe_req_ie_len);
+               pattrib->pktlen += pmlmepriv->wfd_probe_req_ie_len;
+               pframe += pmlmepriv->wfd_probe_req_ie_len;
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                ("issuing probe_req, tx_len =%d\n", pattrib->last_txcmdsz));
+
+       if (wait_ack) {
+               ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
+       } else {
+               dump_mgntframe23a(padapter, pmgntframe);
+               ret = _SUCCESS;
+       }
+
+exit:
+       return ret;
+}
+
+inline void issue23a_probereq_p2p(struct rtw_adapter *adapter, u8 *da)
+{
+       _issue23a_probereq_p2p(adapter, da, false);
+}
+
+int issue23a_probereq_p2p_ex(struct rtw_adapter *adapter, u8 *da,
+                            int try_cnt, int wait_ms)
+{
+       int ret;
+       int i = 0;
+       unsigned long start = jiffies;
+
+       do {
+               ret = _issue23a_probereq_p2p(adapter, da,
+                                            wait_ms > 0 ? true : false);
+
+               i++;
+
+               if (adapter->bDriverStopped || adapter->bSurpriseRemoved)
+                       break;
+
+               if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+                       msleep(wait_ms);
+
+       } while ((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+       if (ret != _FAIL) {
+               ret = _SUCCESS;
+               goto exit;
+       }
+
+       if (try_cnt && wait_ms) {
+               if (da)
+                       DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d "
+                                 "in %u ms\n", FUNC_ADPT_ARG(adapter),
+                                 MAC_ARG(da), rtw_get_oper_ch23a(adapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+               else
+                       DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+                                 FUNC_ADPT_ARG(adapter),
+                                 rtw_get_oper_ch23a(adapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+       }
+exit:
+       return ret;
+}
+
+#endif /* CONFIG_8723AU_P2P */
+
+static s32 rtw_action_public_decache(struct recv_frame *recv_frame, s32 token)
+{
+       struct rtw_adapter *adapter = recv_frame->adapter;
+       struct mlme_ext_priv *mlmeext = &adapter->mlmeextpriv;
+       struct sk_buff *skb = recv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u16 seq_ctrl;
+
+       seq_ctrl = ((recv_frame->attrib.seq_num&0xffff) << 4) |
+               (recv_frame->attrib.frag_num & 0xf);
+
+       if (ieee80211_has_retry(hdr->frame_control)) {
+               if (token >= 0) {
+                       if ((seq_ctrl == mlmeext->action_public_rxseq) &&
+                           (token == mlmeext->action_public_dialog_token)) {
+                               DBG_8723A(FUNC_ADPT_FMT" seq_ctrl = 0x%x, "
+                                         "rxseq = 0x%x, token:%d\n",
+                                         FUNC_ADPT_ARG(adapter), seq_ctrl,
+                                         mlmeext->action_public_rxseq, token);
+                               return _FAIL;
+                       }
+               } else {
+                       if (seq_ctrl == mlmeext->action_public_rxseq) {
+                               DBG_8723A(FUNC_ADPT_FMT" seq_ctrl = 0x%x, "
+                                         "rxseq = 0x%x\n",
+                                         FUNC_ADPT_ARG(adapter), seq_ctrl,
+                                         mlmeext->action_public_rxseq);
+                               return _FAIL;
+                       }
+               }
+       }
+
+       mlmeext->action_public_rxseq = seq_ctrl;
+
+       if (token >= 0)
+               mlmeext->action_public_dialog_token = token;
+
+       return _SUCCESS;
+}
+
+static unsigned int on_action_public23a_p2p(struct recv_frame *precv_frame)
+{
+       struct sk_buff *skb = precv_frame->pkt;
+       u8 *pframe = skb->data;
+       u8 *frame_body;
+       u8 dialogToken = 0;
+#ifdef CONFIG_8723AU_P2P
+       struct rtw_adapter *padapter = precv_frame->adapter;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       uint len = skb->len;
+       u8 *p2p_ie;
+       u32     p2p_ielen;
+       struct  wifidirect_info *pwdinfo = &padapter->wdinfo;
+       u8      result = P2P_STATUS_SUCCESS;
+#endif /* CONFIG_8723AU_P2P */
+
+       frame_body = (unsigned char *)
+               (pframe + sizeof(struct ieee80211_hdr_3addr));
+
+       dialogToken = frame_body[7];
+
+       if (rtw_action_public_decache(precv_frame, dialogToken) == _FAIL)
+               return _FAIL;
+
+#ifdef CONFIG_8723AU_P2P
+       del_timer_sync(&pwdinfo->reset_ch_sitesurvey);
+       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) {
+               rtw_cfg80211_rx_p2p_action_public(padapter, pframe, len);
+       } else {
+               /*      Do nothing if the driver doesn't enable the P2P function. */
+               if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE))
+                       return _SUCCESS;
+
+               len -= sizeof(struct ieee80211_hdr_3addr);
+
+               switch (frame_body[ 6 ])/* OUI Subtype */
+               {
+                       case P2P_GO_NEGO_REQ:
+                               DBG_8723A("[%s] Got GO Nego Req Frame\n", __func__);
+                               memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
+
+                               if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ))
+                               {
+                                       rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+                               }
+
+                               if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
+                               {
+                                       /*      Commented by Albert 20110526 */
+                                       /*      In this case, this means the previous nego fail doesn't be reset yet. */
+                                       del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+                                       /*      Restore the previous p2p state */
+                                       rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+                                       DBG_8723A("[%s] Restore the previous p2p state to %d\n", __func__, rtw_p2p_state(pwdinfo));
+                               }
+
+                               /*      Commented by Kurt 20110902 */
+                               /* Add if statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */
+                               if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING))
+                                       rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+
+                               /*      Commented by Kurt 20120113 */
+                               /*      Get peer_dev_addr here if peer doesn't issue prov_disc frame. */
+                               if (is_zero_ether_addr(pwdinfo->rx_prov_disc_info.peerDevAddr))
+                                       ether_addr_copy(pwdinfo->rx_prov_disc_info.peerDevAddr, hdr->addr2);
+
+                               result = process_p2p_group_negotation_req23a(pwdinfo, frame_body, len);
+                               issue_p2p_GO_response(padapter, hdr->addr2,
+                                                     frame_body, len, result);
+
+                               /*      Commented by Albert 20110718 */
+                               /*      No matter negotiating or negotiation failure, the driver should set up the restore P2P state timer. */
+                               mod_timer(&pwdinfo->restore_p2p_state_timer,
+                                         jiffies + msecs_to_jiffies(5000));
+                               break;
+
+                       case P2P_GO_NEGO_RESP:
+                               DBG_8723A("[%s] Got GO Nego Resp Frame\n", __func__);
+
+                               if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING))
+                               {
+                                       /*      Commented by Albert 20110425 */
+                                       /*      The restore timer is enabled when issuing the nego request frame of rtw_p2p_connect function. */
+                                       del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+                                       pwdinfo->nego_req_info.benable = false;
+                                       result = process_p2p_group_negotation_resp23a(pwdinfo, frame_body, len);
+                                       issue_p2p_GO_confirm(pwdinfo->padapter,
+                                                            hdr->addr2,
+                                                            result);
+                                       if (result == P2P_STATUS_SUCCESS) {
+                                               if (rtw_p2p_role(pwdinfo) ==
+                                                   P2P_ROLE_CLIENT) {
+                                                       pwdinfo->p2p_info.operation_ch[ 0 ] = pwdinfo->peer_operating_ch;
+                                                       pwdinfo->p2p_info.scan_op_ch_only = 1;
+                                                       mod_timer(&pwdinfo->reset_ch_sitesurvey2, jiffies + msecs_to_jiffies(P2P_RESET_SCAN_CH));
+                                               }
+                                       }
+
+                                       /*      Reset the dialog token for group negotiation frames. */
+                                       pwdinfo->negotiation_dialog_token = 1;
+
+                                       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
+                                       {
+                                               mod_timer(&pwdinfo->restore_p2p_state_timer, jiffies + msecs_to_jiffies(5000));
+                                       }
+                               } else {
+                                       DBG_8723A("[%s] Skipped GO Nego Resp Frame (p2p_state != P2P_STATE_GONEGO_ING)\n", __func__);
+                               }
+
+                               break;
+
+                       case P2P_GO_NEGO_CONF:
+
+                               DBG_8723A("[%s] Got GO Nego Confirm Frame\n", __func__);
+                               result = process_p2p_group_negotation_confirm23a(pwdinfo, frame_body, len);
+                               if (P2P_STATUS_SUCCESS == result)
+                               {
+                                       if (rtw_p2p_role(pwdinfo) == P2P_ROLE_CLIENT)
+                                       {
+                                               pwdinfo->p2p_info.operation_ch[ 0 ] = pwdinfo->peer_operating_ch;
+                                               pwdinfo->p2p_info.scan_op_ch_only = 1;
+                                               mod_timer(&pwdinfo->reset_ch_sitesurvey2, jiffies + msecs_to_jiffies(P2P_RESET_SCAN_CH));
+                                       }
+                               }
+                               break;
+
+                       case P2P_INVIT_REQ:
+                               /*      Added by Albert 2010/10/05 */
+                               /*      Received the P2P Invite Request frame. */
+
+                               DBG_8723A("[%s] Got invite request frame!\n", __func__);
+                               if ((p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen)))
+                               {
+                                       /*      Parse the necessary information from the P2P Invitation Request frame. */
+                                       /*      For example: The MAC address of sending this P2P Invitation Request frame. */
+                                       u32     attr_contentlen = 0;
+                                       u8      status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+                                       struct group_id_info group_id;
+                                       u8      invitation_flag = 0;
+
+                                       rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, &invitation_flag, &attr_contentlen);
+                                       if (attr_contentlen)
+                                       {
+
+                                               rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_BSSID, pwdinfo->p2p_peer_interface_addr, &attr_contentlen);
+                                               /*      Commented by Albert 20120510 */
+                                               /*      Copy to the pwdinfo->p2p_peer_interface_addr. */
+                                               /*      So that the WFD UI (or Sigma) can get the peer interface address by using the following command. */
+                                               /*      #> iwpriv wlan0 p2p_get peer_ifa */
+                                               /*      After having the peer interface address, the sigma can find the correct conf file for wpa_supplicant. */
+
+                                               if (attr_contentlen)
+                                               {
+                                                       DBG_8723A("[%s] GO's BSSID = %.2X %.2X %.2X %.2X %.2X %.2X\n", __func__,
+                                                                       pwdinfo->p2p_peer_interface_addr[0], pwdinfo->p2p_peer_interface_addr[1],
+                                                                       pwdinfo->p2p_peer_interface_addr[2], pwdinfo->p2p_peer_interface_addr[3],
+                                                                       pwdinfo->p2p_peer_interface_addr[4], pwdinfo->p2p_peer_interface_addr[5]);
+                                               }
+
+                                               if (invitation_flag & P2P_INVITATION_FLAGS_PERSISTENT)
+                                               {
+                                                       /*      Re-invoke the persistent group. */
+
+                                                       memset(&group_id, 0x00, sizeof(struct group_id_info));
+                                                       rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8*) &group_id, &attr_contentlen);
+                                                       if (attr_contentlen) {
+                                                               if (ether_addr_equal(group_id.go_device_addr, myid(&padapter->eeprompriv))) {
+                                                                       /*      The p2p device sending this p2p invitation request wants this Wi-Fi device to be the persistent GO. */
+                                                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_GO);
+                                                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+                                                                       status_code = P2P_STATUS_SUCCESS;
+                                                               }
+                                                               else
+                                                               {
+                                                                       /*      The p2p device sending this p2p invitation request wants to be the persistent GO. */
+                                                                       if (is_matched_in_profilelist(pwdinfo->p2p_peer_interface_addr, &pwdinfo->profileinfo[ 0 ]))
+                                                                       {
+                                                                               u8 operatingch_info[5] = { 0x00 };
+                                                                               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
+                                                                               {
+                                                                                       if (rtw_ch_set_search_ch23a(padapter->mlmeextpriv.channel_set, (u32)operatingch_info[4]))
+                                                                                       {
+                                                                                               /*      The operating channel is acceptable for this device. */
+                                                                                               pwdinfo->rx_invitereq_info.operation_ch[0]= operatingch_info[4];
+                                                                                               pwdinfo->rx_invitereq_info.scan_op_ch_only = 1;
+                                                                                               mod_timer(&pwdinfo->reset_ch_sitesurvey, jiffies + msecs_to_jiffies(P2P_RESET_SCAN_CH));
+                                                                                               rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH);
+                                                                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                                                                                               status_code = P2P_STATUS_SUCCESS;
+                                                                                               }
+                                                                                       else
+                                                                                       {
+                                                                                               /*      The operating channel isn't supported by this device. */
+                                                                                               rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
+                                                                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+                                                                                               status_code = P2P_STATUS_FAIL_NO_COMMON_CH;
+                                                                                               mod_timer(&pwdinfo->restore_p2p_state_timer, jiffies + msecs_to_jiffies(3000));
+                                                                                       }
+                                                                               }
+                                                                               else {
+                                                                                       /*      Commented by Albert 20121130 */
+                                                                                       /*      Intel will use the different P2P IE to store the operating channel information */
+                                                                                       /*      Workaround for Intel WiDi 3.5 */
+                                                                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_MATCH);
+                                                                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                                                                                       status_code = P2P_STATUS_SUCCESS;
+                                                                               }
+                                                                       }
+                                                                       else
+                                                                       {
+                                                                               rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
+
+                                                                               status_code = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP;
+                                                                       }
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               DBG_8723A("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__);
+                                                               status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       /*      Received the invitation to join a P2P group. */
+
+                                                       memset(&group_id, 0x00, sizeof(struct group_id_info));
+                                                       rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, (u8*) &group_id, &attr_contentlen);
+                                                       if (attr_contentlen)
+                                                       {
+                                                               if (ether_addr_equal(group_id.go_device_addr, myid(&padapter->eeprompriv))) {
+                                                                       /*      In this case, the GO can't be myself. */
+                                                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_DISMATCH);
+                                                                       status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+                                                               }
+                                                               else
+                                                               {
+                                                                       /*      The p2p device sending this p2p invitation request wants to join an existing P2P group */
+                                                                       /*      Commented by Albert 2012/06/28 */
+                                                                       /*      In this case, this Wi-Fi device should use the iwpriv command to get the peer device address. */
+                                                                       /*      The peer device address should be the destination address for the provisioning discovery request. */
+                                                                       /*      Then, this Wi-Fi device should use the iwpriv command to get the peer interface address. */
+                                                                       /*      The peer interface address should be the address for WPS mac address */
+                                                                       ether_addr_copy(pwdinfo->p2p_peer_device_addr, group_id.go_device_addr);
+                                                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                                                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_RECV_INVITE_REQ_JOIN);
+                                                                       status_code = P2P_STATUS_SUCCESS;
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               DBG_8723A("[%s] P2P Group ID Attribute NOT FOUND!\n", __func__);
+                                                               status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+                                                       }
+                                               }
+                                       }
+                                       else
+                                       {
+                                               DBG_8723A("[%s] P2P Invitation Flags Attribute NOT FOUND!\n", __func__);
+                                               status_code = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+                                       }
+
+                                       DBG_8723A("[%s] status_code = %d\n", __func__, status_code);
+
+                                       pwdinfo->inviteresp_info.token = frame_body[ 7 ];
+                                       issue_p2p_invitation_response23a(padapter, hdr->addr2, pwdinfo->inviteresp_info.token, status_code);
+                               }
+                               break;
+
+                       case P2P_INVIT_RESP:
+                       {
+                               u8      attr_content = 0x00;
+                               u32     attr_contentlen = 0;
+
+                               DBG_8723A("[%s] Got invite response frame!\n", __func__);
+                               del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+                               if ((p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &p2p_ielen)))
+                               {
+                                       rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
+
+                                       if (attr_contentlen == 1)
+                                       {
+                                               DBG_8723A("[%s] Status = %d\n", __func__, attr_content);
+                                               pwdinfo->invitereq_info.benable = false;
+
+                                               if (attr_content == P2P_STATUS_SUCCESS)
+                                               {
+                                                       if (ether_addr_equal(pwdinfo->invitereq_info.go_bssid, myid(&padapter->eeprompriv))) {
+                                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+                                                       }
+                                                       else
+                                                       {
+                                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                                                       }
+                                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_OK);
+                                               }
+                                               else
+                                               {
+                                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+                                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
+                                               }
+                                       }
+                                       else
+                                       {
+                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+                                               rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
+                                       }
+                               }
+                               else
+                               {
+                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL);
+                               }
+
+                               if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_INVITE_RESP_FAIL)) {
+                                       mod_timer(&pwdinfo->restore_p2p_state_timer, jiffies + msecs_to_jiffies(5000));
+                               }
+                               break;
+                       }
+                       case P2P_DEVDISC_REQ:
+
+                               process_p2p_devdisc_req23a(pwdinfo, pframe, len);
+
+                               break;
+
+                       case P2P_DEVDISC_RESP:
+
+                               process_p2p_devdisc_resp23a(pwdinfo, pframe, len);
+
+                               break;
+
+                       case P2P_PROVISION_DISC_REQ:
+                               DBG_8723A("[%s] Got Provisioning Discovery Request Frame\n", __func__);
+                               process_p2p_provdisc_req23a(pwdinfo, pframe, len);
+                               ether_addr_copy(pwdinfo->rx_prov_disc_info.peerDevAddr, hdr->addr2);
+
+                               /* 20110902 Kurt */
+                               /* Add the following statement to avoid receiving duplicate prov disc req. such that pre_p2p_state would be covered. */
+                               if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ))
+                                       rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+
+                               rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_REQ);
+                               mod_timer(&pwdinfo->restore_p2p_state_timer,
+                                         jiffies + msecs_to_jiffies(P2P_PROVISION_TIMEOUT));
+                               break;
+
+                       case P2P_PROVISION_DISC_RESP:
+                               /*      Commented by Albert 20110707 */
+                               /*      Should we check the pwdinfo->tx_prov_disc_info.bsent flag here?? */
+                               DBG_8723A("[%s] Got Provisioning Discovery Response Frame\n", __func__);
+                               /*      Commented by Albert 20110426 */
+                               /*      The restore timer is enabled when issuing the provisioing request frame in rtw_p2p_prov_disc function. */
+                               del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+                               rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_PROVISION_DIS_RSP);
+                               process_p2p_provdisc_resp23a(pwdinfo, pframe);
+                               mod_timer(&pwdinfo->restore_p2p_state_timer,
+                                         jiffies + msecs_to_jiffies(P2P_PROVISION_TIMEOUT));
+                               break;
+
+               }
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       return _SUCCESS;
+}
+
+static unsigned int on_action_public23a_vendor(struct recv_frame *precv_frame)
+{
+       unsigned int ret = _FAIL;
+       struct sk_buff *skb = precv_frame->pkt;
+       u8 *pframe = skb->data;
+       u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr);
+
+       if (!memcmp(frame_body + 2, P2P_OUI23A, 4)) {
+               ret = on_action_public23a_p2p(precv_frame);
+       }
+
+       return ret;
+}
+
+static unsigned int
+on_action_public23a_default(struct recv_frame *precv_frame, u8 action)
+{
+       unsigned int ret = _FAIL;
+       struct sk_buff *skb = precv_frame->pkt;
+       u8 *pframe = skb->data;
+       uint frame_len = skb->len;
+       u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr);
+       u8 token;
+       struct rtw_adapter *adapter = precv_frame->adapter;
+       int cnt = 0;
+       char msg[64];
+
+       token = frame_body[2];
+
+       if (rtw_action_public_decache(precv_frame, token) == _FAIL)
+               goto exit;
+
+       cnt += sprintf((msg+cnt), "%s(token:%u)",
+                      action_public_str23a(action), token);
+       rtw_cfg80211_rx_action(adapter, pframe, frame_len, msg);
+
+       ret = _SUCCESS;
+
+exit:
+       return ret;
+}
+
+unsigned int on_action_public23a(struct rtw_adapter *padapter,
+                                struct recv_frame *precv_frame)
+{
+       unsigned int ret = _FAIL;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+       u8 *frame_body = pframe + sizeof(struct ieee80211_hdr_3addr);
+       u8 category, action;
+
+       /* check RA matches or not */
+       if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1))
+               goto exit;
+
+       category = frame_body[0];
+       if (category != WLAN_CATEGORY_PUBLIC)
+               goto exit;
+
+       action = frame_body[1];
+       switch (action) {
+       case ACT_PUBLIC_VENDOR:
+               ret = on_action_public23a_vendor(precv_frame);
+               break;
+       default:
+               ret = on_action_public23a_default(precv_frame, action);
+               break;
+       }
+
+exit:
+       return ret;
+}
+
+unsigned int OnAction23a_ht(struct rtw_adapter *padapter,
+                           struct recv_frame *precv_frame)
+{
+       return _SUCCESS;
+}
+
+unsigned int OnAction23a_wmm(struct rtw_adapter *padapter,
+                            struct recv_frame *precv_frame)
+{
+       return _SUCCESS;
+}
+
+unsigned int OnAction23a_p2p(struct rtw_adapter *padapter,
+                            struct recv_frame *precv_frame)
+{
+#ifdef CONFIG_8723AU_P2P
+       u8 *frame_body;
+       u8 category, OUI_Subtype, dialogToken = 0;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+       uint len = skb->len;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+       DBG_8723A("%s\n", __func__);
+
+       /* check RA matches or not */
+       if (!ether_addr_equal(myid(&padapter->eeprompriv), hdr->addr1))
+               return _SUCCESS;
+
+       frame_body = (unsigned char *)
+               (pframe + sizeof(struct ieee80211_hdr_3addr));
+
+       category = frame_body[0];
+       if (category != WLAN_CATEGORY_VENDOR_SPECIFIC)
+               return _SUCCESS;
+
+       if (cpu_to_be32(*((u32*) (frame_body + 1))) != P2POUI)
+               return _SUCCESS;
+
+       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) {
+               rtw_cfg80211_rx_action_p2p(padapter, pframe, len);
+               return _SUCCESS;
+       } else {
+               len -= sizeof(struct ieee80211_hdr_3addr);
+               OUI_Subtype = frame_body[5];
+               dialogToken = frame_body[6];
+
+               switch (OUI_Subtype)
+               {
+               case P2P_NOTICE_OF_ABSENCE:
+                       break;
+
+               case P2P_PRESENCE_REQUEST:
+                       process_p2p_presence_req23a(pwdinfo, pframe, len);
+                       break;
+
+               case P2P_PRESENCE_RESPONSE:
+                       break;
+
+               case P2P_GO_DISC_REQUEST:
+                       break;
+
+               default:
+                       break;
+               }
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       return _SUCCESS;
+}
+
+unsigned int OnAction23a(struct rtw_adapter *padapter,
+                        struct recv_frame *precv_frame)
+{
+       int i;
+       unsigned char   category;
+       struct action_handler *ptable;
+       unsigned char   *frame_body;
+       struct sk_buff *skb = precv_frame->pkt;
+       u8 *pframe = skb->data;
+
+       frame_body = (unsigned char *)
+               (pframe + sizeof(struct ieee80211_hdr_3addr));
+
+       category = frame_body[0];
+
+       for (i = 0;
+            i < sizeof(OnAction23a_tbl) / sizeof(struct action_handler); i++) {
+               ptable = &OnAction23a_tbl[i];
+
+               if (category == ptable->num)
+                       ptable->func(padapter, precv_frame);
+       }
+
+       return _SUCCESS;
+}
+
+unsigned int DoReserved23a(struct rtw_adapter *padapter,
+                       struct recv_frame *precv_frame)
+{
+       return _SUCCESS;
+}
+
+struct xmit_frame *alloc_mgtxmitframe23a(struct xmit_priv *pxmitpriv)
+{
+       struct xmit_frame *pmgntframe;
+       struct xmit_buf *pxmitbuf;
+
+       pmgntframe = rtw_alloc_xmitframe23a_ext(pxmitpriv);
+
+       if (!pmgntframe) {
+               DBG_8723A(FUNC_ADPT_FMT" alloc xmitframe fail\n",
+                         FUNC_ADPT_ARG(pxmitpriv->adapter));
+               goto exit;
+       }
+
+       pxmitbuf = rtw_alloc_xmitbuf23a_ext(pxmitpriv);
+       if (!pxmitbuf) {
+               DBG_8723A(FUNC_ADPT_FMT" alloc xmitbuf fail\n",
+                         FUNC_ADPT_ARG(pxmitpriv->adapter));
+               rtw_free_xmitframe23a(pxmitpriv, pmgntframe);
+               pmgntframe = NULL;
+               goto exit;
+       }
+
+       pmgntframe->frame_tag = MGNT_FRAMETAG;
+       pmgntframe->pxmitbuf = pxmitbuf;
+       pmgntframe->buf_addr = pxmitbuf->pbuf;
+       pxmitbuf->priv_data = pmgntframe;
+
+exit:
+       return pmgntframe;
+}
+
+/****************************************************************************
+
+Following are some TX fuctions for WiFi MLME
+
+*****************************************************************************/
+
+void update_mgnt_tx_rate23a(struct rtw_adapter *padapter, u8 rate)
+{
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       pmlmeext->tx_rate = rate;
+       DBG_8723A("%s(): rate = %x\n", __func__, rate);
+}
+
+void update_mgntframe_attrib23a(struct rtw_adapter *padapter,
+                               struct pkt_attrib *pattrib)
+{
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       memset((u8 *)pattrib, 0, sizeof(struct pkt_attrib));
+
+       pattrib->hdrlen = 24;
+       pattrib->nr_frags = 1;
+       pattrib->priority = 7;
+       pattrib->mac_id = 0;
+       pattrib->qsel = 0x12;
+
+       pattrib->pktlen = 0;
+
+       if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
+               pattrib->raid = 6;/* b mode */
+       else
+               pattrib->raid = 5;/* a/g mode */
+
+       pattrib->encrypt = _NO_PRIVACY_;
+       pattrib->bswenc = false;
+
+       pattrib->qos_en = false;
+       pattrib->ht_en = false;
+       pattrib->bwmode = HT_CHANNEL_WIDTH_20;
+       pattrib->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+       pattrib->sgi = false;
+
+       pattrib->seqnum = pmlmeext->mgnt_seq;
+
+       pattrib->retry_ctrl = true;
+}
+
+void dump_mgntframe23a(struct rtw_adapter *padapter,
+                      struct xmit_frame *pmgntframe)
+{
+       if (padapter->bSurpriseRemoved == true ||
+           padapter->bDriverStopped == true)
+               return;
+
+       rtw_hal_mgnt_xmit23a(padapter, pmgntframe);
+}
+
+s32 dump_mgntframe23a_and_wait(struct rtw_adapter *padapter,
+                              struct xmit_frame *pmgntframe, int timeout_ms)
+{
+       s32 ret = _FAIL;
+       unsigned long irqL;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct xmit_buf *pxmitbuf = pmgntframe->pxmitbuf;
+       struct submit_ctx sctx;
+
+       if (padapter->bSurpriseRemoved == true ||
+           padapter->bDriverStopped == true)
+               return ret;
+
+       rtw_sctx_init23a(&sctx, timeout_ms);
+       pxmitbuf->sctx = &sctx;
+
+       ret = rtw_hal_mgnt_xmit23a(padapter, pmgntframe);
+
+       if (ret == _SUCCESS)
+               ret = rtw_sctx_wait23a(&sctx);
+
+       spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL);
+       pxmitbuf->sctx = NULL;
+       spin_unlock_irqrestore(&pxmitpriv->lock_sctx, irqL);
+
+       return ret;
+}
+
+s32 dump_mgntframe23a_and_wait_ack23a(struct rtw_adapter *padapter,
+                                     struct xmit_frame *pmgntframe)
+{
+       s32 ret = _FAIL;
+       u32 timeout_ms = 500;/*   500ms */
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+       if (padapter->bSurpriseRemoved == true ||
+           padapter->bDriverStopped == true)
+               return -1;
+
+       mutex_lock(&pxmitpriv->ack_tx_mutex);
+       pxmitpriv->ack_tx = true;
+
+       pmgntframe->ack_report = 1;
+       if (rtw_hal_mgnt_xmit23a(padapter, pmgntframe) == _SUCCESS) {
+               ret = rtw_ack_tx_wait23a(pxmitpriv, timeout_ms);
+       }
+
+       pxmitpriv->ack_tx = false;
+       mutex_unlock(&pxmitpriv->ack_tx_mutex);
+
+       return ret;
+}
+
+static int update_hidden_ssid(u8 *ies, u32 ies_len, u8 hidden_ssid_mode)
+{
+       u8 *ssid_ie;
+       int ssid_len_ori;
+       int len_diff = 0;
+       u8 *next_ie;
+       u32 remain_len;
+
+       ssid_ie = rtw_get_ie23a(ies,  WLAN_EID_SSID, &ssid_len_ori, ies_len);
+
+       /* DBG_8723A("%s hidden_ssid_mode:%u, ssid_ie:%p, ssid_len_ori:%d\n",
+          __func__, hidden_ssid_mode, ssid_ie, ssid_len_ori); */
+
+       if (ssid_ie && ssid_len_ori > 0) {
+               switch (hidden_ssid_mode)
+               {
+               case 1:
+                       next_ie = ssid_ie + 2 + ssid_len_ori;
+                       remain_len = 0;
+
+                       remain_len = ies_len -(next_ie-ies);
+
+                       ssid_ie[1] = 0;
+                       memcpy(ssid_ie+2, next_ie, remain_len);
+                       len_diff -= ssid_len_ori;
+
+                       break;
+               case 2:
+                       memset(&ssid_ie[2], 0, ssid_len_ori);
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       return len_diff;
+}
+
+void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms)
+{
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       unsigned int rate_len;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+       u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_8723AU_P2P */
+       u8 *wps_ie;
+       u32 wps_ielen;
+       u8 sr = 0;
+       int len_diff;
+
+       /* DBG_8723A("%s\n", __func__); */
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL) {
+               DBG_8723A("%s, alloc mgnt frame fail\n", __func__);
+               return;
+       }
+#ifdef CONFIG_8723AU_AP_MODE
+       spin_lock_bh(&pmlmepriv->bcn_update_lock);
+#endif
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+       pattrib->qsel = 0x10;
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, bc_addr);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(cur_network));
+
+       SetSeqNum(pwlanhdr, 0 /*pmlmeext->mgnt_seq*/);
+       /* pmlmeext->mgnt_seq++; */
+       SetFrameSubType(pframe, WIFI_BEACON);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+               /* DBG_8723A("ie len =%d\n", cur_network->IELength); */
+#ifdef CONFIG_8723AU_P2P
+               /*  for P2P : Primary Device Type & Device Name */
+               u32 insert_len = 0;
+               wps_ie = rtw_get_wps_ie23a(cur_network->IEs + _FIXED_IE_LENGTH_,
+                                          cur_network->IELength -
+                                          _FIXED_IE_LENGTH_, NULL, &wps_ielen);
+
+               if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && wps_ie &&
+                   wps_ielen > 0) {
+                       uint wps_offset, remainder_ielen;
+                       u8 *premainder_ie, *pframe_wscie;
+
+                       wps_offset = (uint)(wps_ie - cur_network->IEs);
+
+                       premainder_ie = wps_ie + wps_ielen;
+
+                       remainder_ielen = cur_network->IELength - wps_offset -
+                               wps_ielen;
+
+                       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) {
+                               if (pmlmepriv->wps_beacon_ie &&
+                                   pmlmepriv->wps_beacon_ie_len>0) {
+                                       memcpy(pframe, cur_network->IEs,
+                                              wps_offset);
+                                       pframe += wps_offset;
+                                       pattrib->pktlen += wps_offset;
+
+                                       memcpy(pframe, pmlmepriv->wps_beacon_ie,
+                                              pmlmepriv->wps_beacon_ie_len);
+                                       pframe += pmlmepriv->wps_beacon_ie_len;
+                                       pattrib->pktlen +=
+                                               pmlmepriv->wps_beacon_ie_len;
+
+                                       /* copy remainder_ie to pframe */
+                                       memcpy(pframe, premainder_ie,
+                                              remainder_ielen);
+                                       pframe += remainder_ielen;
+                                       pattrib->pktlen += remainder_ielen;
+                               } else {
+                                       memcpy(pframe, cur_network->IEs,
+                                              cur_network->IELength);
+                                       pframe += cur_network->IELength;
+                                       pattrib->pktlen +=
+                                               cur_network->IELength;
+                               }
+                       } else {
+                               pframe_wscie = pframe + wps_offset;
+                               memcpy(pframe, cur_network->IEs,
+                                      wps_offset + wps_ielen);
+                               pframe += (wps_offset + wps_ielen);
+                               pattrib->pktlen += (wps_offset + wps_ielen);
+
+                               /* now pframe is end of wsc ie, insert Primary
+                                  Device Type & Device Name */
+                               /*      Primary Device Type */
+                               /*      Type: */
+                               *(u16*) (pframe + insert_len) =
+                                       cpu_to_be16(WPS_ATTR_PRIMARY_DEV_TYPE);
+                               insert_len += 2;
+
+                               /*      Length: */
+                               *(u16*) (pframe + insert_len) =
+                                       cpu_to_be16(0x0008);
+                               insert_len += 2;
+
+                               /*      Value: */
+                               /*      Category ID */
+                               *(u16*) (pframe + insert_len) =
+                                       cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+                               insert_len += 2;
+
+                               /*      OUI */
+                               *(u32*) (pframe + insert_len) =
+                                       cpu_to_be32(WPSOUI);
+                               insert_len += 4;
+
+                               /*      Sub Category ID */
+                               *(u16*) (pframe + insert_len) =
+                                       cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+                               insert_len += 2;
+
+                               /*      Device Name */
+                               /*      Type: */
+                               *(u16*) (pframe + insert_len) =
+                                       cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+                               insert_len += 2;
+
+                               /*      Length: */
+                               *(u16*) (pframe + insert_len) =
+                                       cpu_to_be16(pwdinfo->device_name_len);
+                               insert_len += 2;
+
+                               /*      Value: */
+                               memcpy(pframe + insert_len,
+                                      pwdinfo->device_name,
+                                      pwdinfo->device_name_len);
+                               insert_len += pwdinfo->device_name_len;
+
+                               /* update wsc ie length */
+                               *(pframe_wscie+1) = (wps_ielen -2) + insert_len;
+
+                               /* pframe move to end */
+                               pframe+= insert_len;
+                               pattrib->pktlen += insert_len;
+
+                               /* copy remainder_ie to pframe */
+                               memcpy(pframe, premainder_ie, remainder_ielen);
+                               pframe += remainder_ielen;
+                               pattrib->pktlen += remainder_ielen;
+                       }
+               } else
+#endif /* CONFIG_8723AU_P2P */
+                       memcpy(pframe, cur_network->IEs, cur_network->IELength);
+               len_diff = update_hidden_ssid(pframe + _BEACON_IE_OFFSET_,
+                                             cur_network->IELength -
+                                             _BEACON_IE_OFFSET_,
+                                             pmlmeinfo->hidden_ssid_mode);
+               pframe += (cur_network->IELength+len_diff);
+               pattrib->pktlen += (cur_network->IELength+len_diff);
+
+               wps_ie = rtw_get_wps_ie23a(pmgntframe->buf_addr + TXDESC_OFFSET+
+                                          sizeof (struct ieee80211_hdr_3addr) +
+                                          _BEACON_IE_OFFSET_, pattrib->pktlen -
+                                          sizeof (struct ieee80211_hdr_3addr) -
+                                          _BEACON_IE_OFFSET_, NULL,
+                                          &wps_ielen);
+               if (wps_ie && wps_ielen > 0) {
+                       rtw_get_wps_attr_content23a(wps_ie, wps_ielen,
+                                                   WPS_ATTR_SELECTED_REGISTRAR,
+                                                   (u8*)&sr, NULL);
+               }
+               if (sr != 0)
+                       set_fwstate(pmlmepriv, WIFI_UNDER_WPS);
+               else
+                       _clr_fwstate_(pmlmepriv, WIFI_UNDER_WPS);
+
+#ifdef CONFIG_8723AU_P2P
+               if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+                       u32 len;
+                       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) {
+                               len = pmlmepriv->p2p_beacon_ie_len;
+                               if (pmlmepriv->p2p_beacon_ie && len > 0)
+                                       memcpy(pframe,
+                                              pmlmepriv->p2p_beacon_ie, len);
+                       } else
+                               len = build_beacon_p2p_ie23a(pwdinfo, pframe);
+
+                       pframe += len;
+                       pattrib->pktlen += len;
+
+                       if (true == pwdinfo->wfd_info->wfd_enable) {
+                               len = build_beacon_wfd_ie(pwdinfo, pframe);
+                       } else {
+                               len = 0;
+                               if (pmlmepriv->wfd_beacon_ie &&
+                                   pmlmepriv->wfd_beacon_ie_len>0) {
+                                       len = pmlmepriv->wfd_beacon_ie_len;
+                                       memcpy(pframe,
+                                              pmlmepriv->wfd_beacon_ie, len);
+                               }
+                       }
+                       pframe += len;
+                       pattrib->pktlen += len;
+               }
+#endif /* CONFIG_8723AU_P2P */
+
+               goto _issue_bcn;
+       }
+
+       /* below for ad-hoc mode */
+
+       /* timestamp will be inserted by hardware */
+       pframe += 8;
+       pattrib->pktlen += 8;
+
+       /*  beacon interval: 2 bytes */
+
+       memcpy(pframe, (unsigned char *)
+              rtw_get_beacon_interval23a_from_ie(cur_network->IEs), 2);
+
+       pframe += 2;
+       pattrib->pktlen += 2;
+
+       /*  capability info: 2 bytes */
+
+       memcpy(pframe, (unsigned char *)
+              rtw_get_capability23a_from_ie(cur_network->IEs), 2);
+
+       pframe += 2;
+       pattrib->pktlen += 2;
+
+       /*  SSID */
+       pframe = rtw_set_ie23a(pframe, _SSID_IE_, cur_network->Ssid.ssid_len,
+                              cur_network->Ssid.ssid, &pattrib->pktlen);
+
+       /*  supported rates... */
+       rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates);
+       pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_,
+                              ((rate_len > 8)? 8: rate_len),
+                              cur_network->SupportedRates, &pattrib->pktlen);
+
+       /*  DS parameter set */
+       pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *)
+                              &cur_network->Configuration.DSConfig,
+                              &pattrib->pktlen);
+
+       /* if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) */
+       {
+               u8 erpinfo = 0;
+               u32 ATIMWindow;
+               /*  IBSS Parameter Set... */
+               /* ATIMWindow = cur->Configuration.ATIMWindow; */
+               ATIMWindow = 0;
+               pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2,
+                                      (unsigned char *)&ATIMWindow,
+                                      &pattrib->pktlen);
+
+               /* ERP IE */
+               pframe = rtw_set_ie23a(pframe, _ERPINFO_IE_, 1,
+                                      &erpinfo, &pattrib->pktlen);
+       }
+
+       /*  EXTERNDED SUPPORTED RATE */
+       if (rate_len > 8)
+               pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_,
+                                      rate_len - 8,
+                                      cur_network->SupportedRates + 8,
+                                      &pattrib->pktlen);
+
+       /* todo:HT for adhoc */
+
+_issue_bcn:
+
+#ifdef CONFIG_8723AU_AP_MODE
+       pmlmepriv->update_bcn = false;
+
+       spin_unlock_bh(&pmlmepriv->bcn_update_lock);
+#endif
+
+       if ((pattrib->pktlen + TXDESC_SIZE) > 512) {
+               DBG_8723A("beacon frame too large\n");
+               return;
+       }
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       /* DBG_8723A("issue bcn_sz =%d\n", pattrib->last_txcmdsz); */
+       if (timeout_ms > 0)
+               dump_mgntframe23a_and_wait(padapter, pmgntframe, timeout_ms);
+       else
+               dump_mgntframe23a(padapter, pmgntframe);
+}
+
+void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da,
+                      u8 is_valid_p2p_probereq)
+{
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       unsigned char *mac, *bssid;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+#ifdef CONFIG_8723AU_AP_MODE
+       u8 *pwps_ie;
+       uint wps_ielen;
+       u8 *ssid_ie;
+       int ssid_ielen;
+       int ssid_ielen_diff;
+       u8 buf[MAX_IE_SZ];
+       u8 *ies;
+#endif
+#if defined(CONFIG_8723AU_AP_MODE) || defined(CONFIG_8723AU_P2P)
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#endif
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+       unsigned int rate_len;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_8723AU_P2P */
+
+       /* DBG_8723A("%s\n", __func__); */
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+       {
+               DBG_8723A("%s, alloc mgnt frame fail\n", __func__);
+               return;
+       }
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       mac = myid(&padapter->eeprompriv);
+       bssid = cur_network->MacAddress;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+       ether_addr_copy(pwlanhdr->addr1, da);
+       ether_addr_copy(pwlanhdr->addr2, mac);
+       ether_addr_copy(pwlanhdr->addr3, bssid);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(fctrl, WIFI_PROBERSP);
+
+       pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = pattrib->hdrlen;
+       pframe += pattrib->hdrlen;
+
+       if (cur_network->IELength > MAX_IE_SZ)
+               return;
+
+#ifdef CONFIG_8723AU_AP_MODE
+       if ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE) {
+               pwps_ie = rtw_get_wps_ie23a(cur_network->IEs +
+                                           _FIXED_IE_LENGTH_,
+                                           cur_network->IELength -
+                                           _FIXED_IE_LENGTH_, NULL,
+                                           &wps_ielen);
+
+               /* inerset & update wps_probe_resp_ie */
+               if ((pmlmepriv->wps_probe_resp_ie != NULL) && pwps_ie &&
+                   (wps_ielen > 0)) {
+                       uint wps_offset, remainder_ielen;
+                       u8 *premainder_ie;
+
+                       wps_offset = (uint)(pwps_ie - cur_network->IEs);
+
+                       premainder_ie = pwps_ie + wps_ielen;
+
+                       remainder_ielen = cur_network->IELength - wps_offset -
+                               wps_ielen;
+
+                       memcpy(pframe, cur_network->IEs, wps_offset);
+                       pframe += wps_offset;
+                       pattrib->pktlen += wps_offset;
+
+                       /* to get ie data len */
+                       wps_ielen = (uint)pmlmepriv->wps_probe_resp_ie[1];
+                       if ((wps_offset+wps_ielen+2)<= MAX_IE_SZ) {
+                               memcpy(pframe, pmlmepriv->wps_probe_resp_ie,
+                                      wps_ielen+2);
+                               pframe += wps_ielen+2;
+                               pattrib->pktlen += wps_ielen+2;
+                       }
+
+                       if ((wps_offset+wps_ielen+2+remainder_ielen) <=
+                           MAX_IE_SZ) {
+                               memcpy(pframe, premainder_ie, remainder_ielen);
+                               pframe += remainder_ielen;
+                               pattrib->pktlen += remainder_ielen;
+                       }
+               } else {
+                       memcpy(pframe, cur_network->IEs, cur_network->IELength);
+                       pframe += cur_network->IELength;
+                       pattrib->pktlen += cur_network->IELength;
+               }
+
+               /* retrieve SSID IE from cur_network->Ssid */
+               ies = pmgntframe->buf_addr + TXDESC_OFFSET +
+                       sizeof(struct ieee80211_hdr_3addr);
+
+               ssid_ie = rtw_get_ie23a(ies+_FIXED_IE_LENGTH_, _SSID_IE_,
+                                       &ssid_ielen,
+                                       (pframe-ies)-_FIXED_IE_LENGTH_);
+
+               ssid_ielen_diff = cur_network->Ssid.ssid_len - ssid_ielen;
+
+               if (ssid_ie && cur_network->Ssid.ssid_len) {
+                       uint remainder_ielen;
+                       u8 *remainder_ie;
+                       remainder_ie = ssid_ie + 2;
+                       remainder_ielen = (pframe-remainder_ie);
+
+                       DBG_8723A_LEVEL(_drv_warning_, FUNC_ADPT_FMT
+                                       " remainder_ielen > MAX_IE_SZ\n",
+                                       FUNC_ADPT_ARG(padapter));
+                       if (remainder_ielen > MAX_IE_SZ) {
+                               remainder_ielen = MAX_IE_SZ;
+                       }
+
+                       memcpy(buf, remainder_ie, remainder_ielen);
+                       memcpy(remainder_ie+ssid_ielen_diff, buf,
+                              remainder_ielen);
+                       *(ssid_ie+1) = cur_network->Ssid.ssid_len;
+                       memcpy(ssid_ie+2, cur_network->Ssid.ssid,
+                              cur_network->Ssid.ssid_len);
+
+                       pframe += ssid_ielen_diff;
+                       pattrib->pktlen += ssid_ielen_diff;
+               }
+       } else
+#endif
+       {
+
+               /* timestamp will be inserted by hardware */
+               pframe += 8;
+               pattrib->pktlen += 8;
+
+               /*  beacon interval: 2 bytes */
+
+               memcpy(pframe, (unsigned char *)
+                      rtw_get_beacon_interval23a_from_ie(cur_network->IEs), 2);
+
+               pframe += 2;
+               pattrib->pktlen += 2;
+
+               /*  capability info: 2 bytes */
+
+               memcpy(pframe, (unsigned char *)
+                      rtw_get_capability23a_from_ie(cur_network->IEs), 2);
+
+               pframe += 2;
+               pattrib->pktlen += 2;
+
+               /* below for ad-hoc mode */
+
+               /*  SSID */
+               pframe = rtw_set_ie23a(pframe, _SSID_IE_,
+                                   cur_network->Ssid.ssid_len,
+                                   cur_network->Ssid.ssid, &pattrib->pktlen);
+
+               /*  supported rates... */
+               rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates);
+               pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_,
+                                      ((rate_len > 8)? 8: rate_len),
+                                      cur_network->SupportedRates,
+                                      &pattrib->pktlen);
+
+               /*  DS parameter set */
+               pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *)
+                                      &cur_network->Configuration.DSConfig,
+                                      &pattrib->pktlen);
+
+               if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+                       u8 erpinfo = 0;
+                       u32 ATIMWindow;
+                       /*  IBSS Parameter Set... */
+                       /* ATIMWindow = cur->Configuration.ATIMWindow; */
+                       ATIMWindow = 0;
+                       pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2,
+                                              (unsigned char *)&ATIMWindow,
+                                              &pattrib->pktlen);
+
+                       /* ERP IE */
+                       pframe = rtw_set_ie23a(pframe, _ERPINFO_IE_, 1,
+                                              &erpinfo, &pattrib->pktlen);
+               }
+
+               /*  EXTERNDED SUPPORTED RATE */
+               if (rate_len > 8)
+                       pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_,
+                                              rate_len - 8,
+                                              cur_network->SupportedRates + 8,
+                                              &pattrib->pktlen);
+
+               /* todo:HT for adhoc */
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) && is_valid_p2p_probereq) {
+               u32 len;
+               if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) {
+                       /* if pwdinfo->role == P2P_ROLE_DEVICE will call
+                          issue_probersp23a_p2p23a() */
+                       len = pmlmepriv->p2p_go_probe_resp_ie_len;
+                       if (pmlmepriv->p2p_go_probe_resp_ie && len>0)
+                               memcpy(pframe, pmlmepriv->p2p_go_probe_resp_ie,
+                                      len);
+               } else
+                       len = build_probe_resp_p2p_ie23a(pwdinfo, pframe);
+
+               pframe += len;
+               pattrib->pktlen += len;
+
+               if (true == pwdinfo->wfd_info->wfd_enable) {
+                       len = build_probe_resp_wfd_ie(pwdinfo, pframe, 0);
+               } else {
+                       len = 0;
+                       if (pmlmepriv->wfd_probe_resp_ie &&
+                           pmlmepriv->wfd_probe_resp_ie_len > 0) {
+                               len = pmlmepriv->wfd_probe_resp_ie_len;
+                               memcpy(pframe, pmlmepriv->wfd_probe_resp_ie,
+                                      len);
+                       }
+               }
+               pframe += len;
+               pattrib->pktlen += len;
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+static int _issue_probereq23a(struct rtw_adapter *padapter,
+                             struct cfg80211_ssid *pssid, u8 *da, int wait_ack)
+{
+       int ret = _FAIL;
+       struct xmit_frame               *pmgntframe;
+       struct pkt_attrib               *pattrib;
+       unsigned char                   *pframe;
+       struct ieee80211_hdr    *pwlanhdr;
+       unsigned short          *fctrl;
+       unsigned char                   *mac;
+       unsigned char                   bssrate[NumRates];
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       int     bssrate_len = 0;
+       u8      bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+                ("+issue_probereq23a\n"));
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               goto exit;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       mac = myid(&padapter->eeprompriv);
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       if (da) {
+               /*      unicast probe request frame */
+               ether_addr_copy(pwlanhdr->addr1, da);
+               ether_addr_copy(pwlanhdr->addr3, da);
+       } else {
+               /*      broadcast probe request frame */
+               ether_addr_copy(pwlanhdr->addr1, bc_addr);
+               ether_addr_copy(pwlanhdr->addr3, bc_addr);
+       }
+
+       ether_addr_copy(pwlanhdr->addr2, mac);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_PROBEREQ);
+
+       pframe += sizeof (struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof (struct ieee80211_hdr_3addr);
+
+       if (pssid)
+               pframe = rtw_set_ie23a(pframe, _SSID_IE_, pssid->ssid_len,
+                                      pssid->ssid, &pattrib->pktlen);
+       else
+               pframe = rtw_set_ie23a(pframe, _SSID_IE_, 0, NULL,
+                                      &pattrib->pktlen);
+
+       get_rate_set23a(padapter, bssrate, &bssrate_len);
+
+       if (bssrate_len > 8) {
+               pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8,
+                                      bssrate, &pattrib->pktlen);
+               pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_,
+                                      (bssrate_len - 8), (bssrate + 8),
+                                      &pattrib->pktlen);
+       } else {
+               pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_,
+                                      bssrate_len, bssrate, &pattrib->pktlen);
+       }
+
+       /* add wps_ie for wps2.0 */
+       if (pmlmepriv->wps_probe_req_ie_len>0 && pmlmepriv->wps_probe_req_ie) {
+               memcpy(pframe, pmlmepriv->wps_probe_req_ie,
+                      pmlmepriv->wps_probe_req_ie_len);
+               pframe += pmlmepriv->wps_probe_req_ie_len;
+               pattrib->pktlen += pmlmepriv->wps_probe_req_ie_len;
+       }
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+                ("issuing probe_req, tx_len =%d\n", pattrib->last_txcmdsz));
+
+       if (wait_ack) {
+               ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
+       } else {
+               dump_mgntframe23a(padapter, pmgntframe);
+               ret = _SUCCESS;
+       }
+
+exit:
+       return ret;
+}
+
+inline void issue_probereq23a(struct rtw_adapter *padapter,
+                             struct cfg80211_ssid *pssid, u8 *da)
+{
+       _issue_probereq23a(padapter, pssid, da, false);
+}
+
+int issue_probereq23a_ex23a(struct rtw_adapter *padapter,
+                     struct cfg80211_ssid *pssid, u8 *da,
+                     int try_cnt, int wait_ms)
+{
+       int ret;
+       int i = 0;
+       unsigned long start = jiffies;
+
+       do {
+               ret = _issue_probereq23a(padapter, pssid, da,
+                                        wait_ms > 0 ? true : false);
+
+               i++;
+
+               if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+                       break;
+
+               if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+                       msleep(wait_ms);
+
+       } while((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+       if (ret != _FAIL) {
+               ret = _SUCCESS;
+               goto exit;
+       }
+
+       if (try_cnt && wait_ms) {
+               if (da)
+                       DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d "
+                                 "in %u ms\n", FUNC_ADPT_ARG(padapter),
+                                 MAC_ARG(da), rtw_get_oper_ch23a(padapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+               else
+                       DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+                                 FUNC_ADPT_ARG(padapter),
+                                 rtw_get_oper_ch23a(padapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+       }
+exit:
+       return ret;
+}
+
+/*  if psta == NULL, indiate we are station(client) now... */
+void issue_auth23a(struct rtw_adapter *padapter, struct sta_info *psta,
+                  unsigned short status)
+{
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       unsigned int val32;
+       unsigned short val16;
+       int use_shared_key = 0;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_AUTH);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       if (psta) { /*  for AP mode */
+#ifdef CONFIG_8723AU_AP_MODE
+
+               ether_addr_copy(pwlanhdr->addr1, psta->hwaddr);
+               ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+               ether_addr_copy(pwlanhdr->addr3, myid(&padapter->eeprompriv));
+
+               /*  setting auth algo number */
+               val16 = (u16)psta->authalg;
+
+               if (status != WLAN_STATUS_SUCCESS)
+                       val16 = 0;
+
+               if (val16) {
+                       val16 = cpu_to_le16(val16);
+                       use_shared_key = 1;
+               }
+
+               pframe = rtw_set_fixed_ie23a(pframe, _AUTH_ALGM_NUM_,
+                                            (unsigned char *)&val16,
+                                            &pattrib->pktlen);
+
+               /*  setting auth seq number */
+               val16 = (u16)psta->auth_seq;
+               val16 = cpu_to_le16(val16);
+               pframe = rtw_set_fixed_ie23a(pframe, _AUTH_SEQ_NUM_,
+                                            (unsigned char *)&val16,
+                                            &pattrib->pktlen);
+
+               /*  setting status code... */
+               val16 = status;
+               val16 = cpu_to_le16(val16);
+               pframe = rtw_set_fixed_ie23a(pframe, _STATUS_CODE_,
+                                            (unsigned char *)&val16,
+                                            &pattrib->pktlen);
+
+               /*  added challenging text... */
+               if ((psta->auth_seq == 2) &&
+                   (psta->state & WIFI_FW_AUTH_STATE) && (use_shared_key == 1))
+                       pframe = rtw_set_ie23a(pframe, _CHLGETXT_IE_, 128,
+                                              psta->chg_txt, &pattrib->pktlen);
+#endif
+       } else {
+               ether_addr_copy(pwlanhdr->addr1,
+                               get_my_bssid23a(&pmlmeinfo->network));
+               ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+               ether_addr_copy(pwlanhdr->addr3,
+                               get_my_bssid23a(&pmlmeinfo->network));
+
+               /*  setting auth algo number */
+               /*  0:OPEN System, 1:Shared key */
+               val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared)? 1: 0;
+               if (val16) {
+                       val16 = cpu_to_le16(val16);
+                       use_shared_key = 1;
+               }
+               /* DBG_8723A("%s auth_algo = %s auth_seq =%d\n", __func__,
+                  (pmlmeinfo->auth_algo == 0)?"OPEN":"SHARED",
+                  pmlmeinfo->auth_seq); */
+
+               /* setting IV for auth seq #3 */
+               if ((pmlmeinfo->auth_seq == 3) &&
+                   (pmlmeinfo->state & WIFI_FW_AUTH_STATE) &&
+                   (use_shared_key == 1)) {
+                       /* DBG_8723A("==> iv(%d), key_index(%d)\n",
+                          pmlmeinfo->iv, pmlmeinfo->key_index); */
+                       val32 = ((pmlmeinfo->iv++) |
+                                (pmlmeinfo->key_index << 30));
+                       val32 = cpu_to_le32(val32);
+                       pframe = rtw_set_fixed_ie23a(pframe, 4,
+                                                    (unsigned char *)&val32,
+                                                    &pattrib->pktlen);
+
+                       pattrib->iv_len = 4;
+               }
+
+               pframe = rtw_set_fixed_ie23a(pframe, _AUTH_ALGM_NUM_,
+                                            (unsigned char *)&val16,
+                                            &pattrib->pktlen);
+
+               /*  setting auth seq number */
+               val16 = pmlmeinfo->auth_seq;
+               val16 = cpu_to_le16(val16);
+               pframe = rtw_set_fixed_ie23a(pframe, _AUTH_SEQ_NUM_,
+                                            (unsigned char *)&val16,
+                                            &pattrib->pktlen);
+
+               /*  setting status code... */
+               val16 = status;
+               val16 = cpu_to_le16(val16);
+               pframe = rtw_set_fixed_ie23a(pframe, _STATUS_CODE_,
+                                            (unsigned char *)&val16,
+                                            &pattrib->pktlen);
+
+               /*  then checking to see if sending challenging text... */
+               if ((pmlmeinfo->auth_seq == 3) &&
+                   (pmlmeinfo->state & WIFI_FW_AUTH_STATE) &&
+                   (use_shared_key == 1)) {
+                       pframe = rtw_set_ie23a(pframe, _CHLGETXT_IE_, 128,
+                                              pmlmeinfo->chg_txt,
+                                              &pattrib->pktlen);
+
+                       SetPrivacy(fctrl);
+
+                       pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
+
+                       pattrib->encrypt = _WEP40_;
+
+                       pattrib->icv_len = 4;
+
+                       pattrib->pktlen += pattrib->icv_len;
+               }
+       }
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       rtw_wep_encrypt23a(padapter, pmgntframe);
+       DBG_8723A("%s\n", __func__);
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+void issue_asocrsp23a(struct rtw_adapter *padapter, unsigned short status,
+                     struct sta_info *pstat, int pkt_type)
+{
+#ifdef CONFIG_8723AU_AP_MODE
+       struct xmit_frame *pmgntframe;
+       struct ieee80211_hdr *pwlanhdr;
+       struct pkt_attrib *pattrib;
+       unsigned char *pbuf, *pframe;
+       unsigned short val;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
+       u8 *ie = pnetwork->IEs;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+
+       DBG_8723A("%s\n", __func__);
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       pwlanhdr->frame_control = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, pstat->hwaddr);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       if ((pkt_type == WIFI_ASSOCRSP) || (pkt_type == WIFI_REASSOCRSP))
+               SetFrameSubType(pwlanhdr, pkt_type);
+       else
+               return;
+
+       pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen += pattrib->hdrlen;
+       pframe += pattrib->hdrlen;
+
+       /* capability */
+       val = *(unsigned short *)rtw_get_capability23a_from_ie(ie);
+
+       pframe = rtw_set_fixed_ie23a(pframe, _CAPABILITY_,
+                                    (unsigned char *)&val, &pattrib->pktlen);
+
+       status = cpu_to_le16(status);
+       pframe = rtw_set_fixed_ie23a(pframe, _STATUS_CODE_,
+                                    (unsigned char *)&status,
+                                    &pattrib->pktlen);
+
+       val = cpu_to_le16(pstat->aid | BIT(14) | BIT(15));
+       pframe = rtw_set_fixed_ie23a(pframe, _ASOC_ID_, (unsigned char *)&val,
+                                    &pattrib->pktlen);
+
+       if (pstat->bssratelen <= 8) {
+               pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_,
+                                      pstat->bssratelen, pstat->bssrateset,
+                                      &pattrib->pktlen);
+       } else {
+               pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8,
+                                      pstat->bssrateset, &pattrib->pktlen);
+               pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_,
+                                      pstat->bssratelen - 8,
+                                      pstat->bssrateset + 8, &pattrib->pktlen);
+       }
+
+       if ((pstat->flags & WLAN_STA_HT) && (pmlmepriv->htpriv.ht_option)) {
+               uint ie_len = 0;
+
+               /* FILL HT CAP INFO IE */
+               /* p = hostapd_eid_ht_capabilities_info(hapd, p); */
+               pbuf = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_,
+                                    _HT_CAPABILITY_IE_, &ie_len,
+                                    pnetwork->IELength - _BEACON_IE_OFFSET_);
+               if (pbuf && ie_len>0) {
+                       memcpy(pframe, pbuf, ie_len + 2);
+                       pframe += (ie_len + 2);
+                       pattrib->pktlen += (ie_len + 2);
+               }
+
+               /* FILL HT ADD INFO IE */
+               /* p = hostapd_eid_ht_operation(hapd, p); */
+               pbuf = rtw_get_ie23a(ie + _BEACON_IE_OFFSET_, _HT_ADD_INFO_IE_,
+                                    &ie_len,
+                                    pnetwork->IELength - _BEACON_IE_OFFSET_);
+               if (pbuf && ie_len > 0) {
+                       memcpy(pframe, pbuf, ie_len + 2);
+                       pframe += (ie_len + 2);
+                       pattrib->pktlen += (ie_len + 2);
+               }
+       }
+
+       /* FILL WMM IE */
+       if ((pstat->flags & WLAN_STA_WME) && pmlmepriv->qospriv.qos_option) {
+               uint ie_len = 0;
+               unsigned char WMM_PARA_IE[] = {0x00, 0x50, 0xf2, 0x02,
+                                              0x01, 0x01};
+
+               for (pbuf = ie + _BEACON_IE_OFFSET_; ; pbuf += (ie_len + 2)) {
+                       pbuf = rtw_get_ie23a(pbuf, _VENDOR_SPECIFIC_IE_,
+                                            &ie_len, (pnetwork->IELength -
+                                                      _BEACON_IE_OFFSET_ -
+                                                      (ie_len + 2)));
+                       if (pbuf && !memcmp(pbuf + 2, WMM_PARA_IE, 6)) {
+                               memcpy(pframe, pbuf, ie_len + 2);
+                               pframe += (ie_len + 2);
+                               pattrib->pktlen += (ie_len + 2);
+
+                               break;
+                       }
+
+                       if ((!pbuf) || (ie_len == 0))
+                               break;
+               }
+       }
+
+       if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK) {
+               pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, 6,
+                                      REALTEK_96B_IE23A, &pattrib->pktlen);
+       }
+
+       /* add WPS IE ie for wps 2.0 */
+       if (pmlmepriv->wps_assoc_resp_ie &&
+           pmlmepriv->wps_assoc_resp_ie_len > 0) {
+               memcpy(pframe, pmlmepriv->wps_assoc_resp_ie,
+                      pmlmepriv->wps_assoc_resp_ie_len);
+
+               pframe += pmlmepriv->wps_assoc_resp_ie_len;
+               pattrib->pktlen += pmlmepriv->wps_assoc_resp_ie_len;
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO) &&
+           pwdinfo->wfd_info->wfd_enable) {
+               wfdielen = build_assoc_resp_wfd_ie(pwdinfo, pframe);
+               pframe += wfdielen;
+               pattrib->pktlen += wfdielen;
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+#endif
+}
+
+void issue_assocreq23a(struct rtw_adapter *padapter)
+{
+       int ret = _FAIL;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe, *p;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       unsigned short val16;
+       unsigned int i, j, ie_len, index = 0;
+       unsigned char rf_type, bssrate[NumRates], sta_bssrate[NumRates];
+       struct ndis_802_11_var_ies *pIE;
+       struct registry_priv *pregpriv = &padapter->registrypriv;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       int bssrate_len = 0, sta_bssrate_len = 0;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       u8 p2pie[255] = { 0x00 };
+       u16 p2pielen = 0;
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               goto exit;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+       ether_addr_copy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network));
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ASSOCREQ);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       /* caps */
+       memcpy(pframe, rtw_get_capability23a_from_ie(pmlmeinfo->network.IEs),
+              2);
+
+       pframe += 2;
+       pattrib->pktlen += 2;
+
+       /* listen interval */
+       /* todo: listen interval for power saving */
+       val16 = cpu_to_le16(3);
+       memcpy(pframe, (unsigned char *)&val16, 2);
+       pframe += 2;
+       pattrib->pktlen += 2;
+
+       /* SSID */
+       pframe = rtw_set_ie23a(pframe, _SSID_IE_,
+                              pmlmeinfo->network.Ssid.ssid_len,
+                              pmlmeinfo->network.Ssid.ssid, &pattrib->pktlen);
+
+       /* supported rate & extended supported rate */
+
+       get_rate_set23a(padapter, sta_bssrate, &sta_bssrate_len);
+       /* DBG_8723A("sta_bssrate_len =%d\n", sta_bssrate_len); */
+
+       /*  for JAPAN, channel 14 can only uses B Mode(CCK) */
+       if (pmlmeext->cur_channel == 14)
+               sta_bssrate_len = 4;
+
+       /* for (i = 0; i < sta_bssrate_len; i++) { */
+       /*      DBG_8723A("sta_bssrate[%d]=%02X\n", i, sta_bssrate[i]); */
+       /*  */
+
+       for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+               if (pmlmeinfo->network.SupportedRates[i] == 0)
+                       break;
+               DBG_8723A("network.SupportedRates[%d]=%02X\n", i,
+                         pmlmeinfo->network.SupportedRates[i]);
+       }
+
+       for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+               if (pmlmeinfo->network.SupportedRates[i] == 0)
+                       break;
+
+               /*  Check if the AP's supported rates are also
+                   supported by STA. */
+               for (j = 0; j < sta_bssrate_len; j++) {
+                        /*  Avoid the proprietary data rate (22Mbps) of
+                            Handlink WSG-4000 AP */
+                       if ((pmlmeinfo->network.SupportedRates[i] |
+                            IEEE80211_BASIC_RATE_MASK) ==
+                           (sta_bssrate[j]|IEEE80211_BASIC_RATE_MASK)) {
+                               /* DBG_8723A("match i = %d, j =%d\n", i, j); */
+                               break;
+                       }
+               }
+
+               if (j == sta_bssrate_len) {
+                       /*  the rate is not supported by STA */
+                       DBG_8723A("%s(): the rate[%d]=%02X is not supported by "
+                                 "STA!\n", __func__, i,
+                                 pmlmeinfo->network.SupportedRates[i]);
+               } else {
+                       /*  the rate is supported by STA */
+                       bssrate[index++] = pmlmeinfo->network.SupportedRates[i];
+               }
+       }
+
+       bssrate_len = index;
+       DBG_8723A("bssrate_len = %d\n", bssrate_len);
+
+       if (bssrate_len == 0) {
+               rtw_free_xmitbuf23a(pxmitpriv, pmgntframe->pxmitbuf);
+               rtw_free_xmitframe23a(pxmitpriv, pmgntframe);
+               goto exit; /* don't connect to AP if no joint supported rate */
+       }
+
+       if (bssrate_len > 8) {
+               pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, 8,
+                                      bssrate, &pattrib->pktlen);
+               pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_,
+                                      (bssrate_len - 8), (bssrate + 8),
+                                      &pattrib->pktlen);
+       } else
+               pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_,
+                                      bssrate_len, bssrate, &pattrib->pktlen);
+
+       /* RSN */
+       p = rtw_get_ie23a((pmlmeinfo->network.IEs +
+                          sizeof(struct ndis_802_11_fixed_ies)), _RSN_IE_2_,
+                         &ie_len, (pmlmeinfo->network.IELength -
+                                   sizeof(struct ndis_802_11_fixed_ies)));
+       if (p)
+               pframe = rtw_set_ie23a(pframe, _RSN_IE_2_, ie_len, (p + 2),
+                                      &pattrib->pktlen);
+
+       /* HT caps */
+       if (padapter->mlmepriv.htpriv.ht_option == true) {
+               p = rtw_get_ie23a((pmlmeinfo->network.IEs +
+                                  sizeof(struct ndis_802_11_fixed_ies)),
+                                 _HT_CAPABILITY_IE_, &ie_len,
+                                 (pmlmeinfo->network.IELength -
+                                  sizeof(struct ndis_802_11_fixed_ies)));
+               if ((p != NULL) && (!(is_ap_in_tkip23a(padapter)))) {
+                       memcpy(&pmlmeinfo->HT_caps, (p + 2),
+                              sizeof(struct HT_caps_element));
+
+                       /* to disable 40M Hz support while gd_bw_40MHz_en = 0 */
+                       if (pregpriv->cbw40_enable == 0) {
+                               pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info &= (~(BIT(6) | BIT(1)));
+                       } else {
+                               pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= BIT(1);
+                       }
+
+                       /* todo: disable SM power save mode */
+                       pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |=
+                               0x000c;
+
+                       rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE,
+                                            (u8 *)(&rf_type));
+                       /* switch (pregpriv->rf_config) */
+                       switch (rf_type)
+                       {
+                       case RF_1T1R:
+
+                               if (pregpriv->rx_stbc)
+                                       pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0100);/* RX STBC One spatial stream */
+
+                               memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_1R23A, 16);
+                               break;
+
+                       case RF_2T2R:
+                       case RF_1T2R:
+                       default:
+
+                               /* enable for 2.4/5 GHz */
+                               if ((pregpriv->rx_stbc == 0x3) ||
+                                   ((pmlmeext->cur_wireless_mode &
+                                     WIRELESS_11_24N) &&
+                                    /* enable for 2.4GHz */
+                                    (pregpriv->rx_stbc == 0x1)) ||
+                                   ((pmlmeext->cur_wireless_mode &
+                                     WIRELESS_11_5N) &&
+                                    (pregpriv->rx_stbc == 0x2)) ||
+                                   /* enable for 5GHz */
+                                   (pregpriv->wifi_spec == 1)) {
+                                       DBG_8723A("declare supporting RX "
+                                                 "STBC\n");
+                                       pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info |= cpu_to_le16(0x0200);/* RX STBC two spatial stream */
+                               }
+                               memcpy(pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate, MCS_rate_2R23A, 16);
+                               break;
+                       }
+                       pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info =
+                               cpu_to_le16(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info);
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+                       if (BT_1Ant(padapter) == true) {
+                               /*  set to 8K */
+                               pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para &= (u8)~IEEE80211_HT_AMPDU_PARM_FACTOR;
+/*                             pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para |= MAX_AMPDU_FACTOR_8K */
+                       }
+#endif
+
+                       pframe = rtw_set_ie23a(pframe, _HT_CAPABILITY_IE_,
+                                              ie_len,
+                                              (u8 *)&pmlmeinfo->HT_caps,
+                                              &pattrib->pktlen);
+               }
+       }
+
+       /* vendor specific IE, such as WPA, WMM, WPS */
+       for (i = sizeof(struct ndis_802_11_fixed_ies);
+            i < pmlmeinfo->network.IELength;) {
+               pIE = (struct ndis_802_11_var_ies *)
+                       (pmlmeinfo->network.IEs + i);
+
+               switch (pIE->ElementID)
+               {
+               case _VENDOR_SPECIFIC_IE_:
+                       if (!memcmp(pIE->data, RTW_WPA_OUI23A, 4) ||
+                           !memcmp(pIE->data, WMM_OUI23A, 4) ||
+                           !memcmp(pIE->data, WPS_OUI23A, 4)) {
+                               if (!padapter->registrypriv.wifi_spec) {
+                                       /* Commented by Kurt 20110629 */
+                                       /* In some older APs, WPS handshake */
+                                       /* would be fail if we append vender
+                                          extensions informations to AP */
+                                       if (!memcmp(pIE->data, WPS_OUI23A, 4))
+                                               pIE->Length = 14;
+                               }
+                               pframe = rtw_set_ie23a(pframe,
+                                                      _VENDOR_SPECIFIC_IE_,
+                                                      pIE->Length, pIE->data,
+                                                      &pattrib->pktlen);
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+
+               i += (pIE->Length + 2);
+       }
+
+       if (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_REALTEK)
+               pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, 6,
+                                      REALTEK_96B_IE23A, &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_P2P
+
+       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled) {
+               if (pmlmepriv->p2p_assoc_req_ie &&
+                   pmlmepriv->p2p_assoc_req_ie_len>0) {
+                       memcpy(pframe, pmlmepriv->p2p_assoc_req_ie,
+                              pmlmepriv->p2p_assoc_req_ie_len);
+                       pframe += pmlmepriv->p2p_assoc_req_ie_len;
+                       pattrib->pktlen += pmlmepriv->p2p_assoc_req_ie_len;
+               }
+       } else {
+               if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) &&
+                   !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
+                       /*      Should add the P2P IE in the association
+                               request frame. */
+                       /*      P2P OUI */
+
+                       p2pielen = 0;
+                       p2pie[p2pielen++] = 0x50;
+                       p2pie[p2pielen++] = 0x6F;
+                       p2pie[p2pielen++] = 0x9A;
+                       p2pie[p2pielen++] = 0x09;       /*      WFA P2P v1.0 */
+
+                       /*      Commented by Albert 20101109 */
+                       /*      According to the P2P Specification, the
+                               association request frame should contain
+                               3 P2P attributes */
+                       /*      1. P2P Capability */
+                       /*      2. Extended Listen Timing */
+                       /*      3. Device Info */
+                       /*      Commented by Albert 20110516 */
+                       /*      4. P2P Interface */
+
+                       /*      P2P Capability */
+                       /*      Type: */
+                       p2pie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+                       /*      Length: */
+                       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002);
+                       p2pielen += 2;
+
+                       /*      Value: */
+                       /*      Device Capability Bitmap, 1 byte */
+                       p2pie[p2pielen++] = DMP_P2P_DEVCAP_SUPPORT;
+
+                       /*      Group Capability Bitmap, 1 byte */
+                       if (pwdinfo->persistent_supported)
+                               p2pie[p2pielen++] =
+                                       P2P_GRPCAP_PERSISTENT_GROUP |
+                                       DMP_P2P_GRPCAP_SUPPORT;
+                       else
+                               p2pie[p2pielen++] = DMP_P2P_GRPCAP_SUPPORT;
+
+                       /*      Extended Listen Timing */
+                       /*      Type: */
+                       p2pie[p2pielen++] = P2P_ATTR_EX_LISTEN_TIMING;
+
+                       /*      Length: */
+                       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004);
+                       p2pielen += 2;
+
+                       /*      Value: */
+                       /*      Availability Period */
+                       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+                       p2pielen += 2;
+
+                       /*      Availability Interval */
+                       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF);
+                       p2pielen += 2;
+
+                       /*      Device Info */
+                       /*      Type: */
+                       p2pie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+                       /*      Length: */
+                       /*      21 -> P2P Device Address (6bytes) + Config
+                               Methods (2bytes) + Primary Device
+                               Type (8bytes) */
+                       /*      + NumofSecondDevType (1byte) + WPS Device
+                               Name ID field (2bytes) + WPS Device Name
+                               Len field (2bytes) */
+                       *(u16*) (p2pie + p2pielen) =
+                               cpu_to_le16(21 + pwdinfo->device_name_len);
+                       p2pielen += 2;
+
+                       /*      Value: */
+                       /*      P2P Device Address */
+                       memcpy(p2pie + p2pielen,
+                              myid(&padapter->eeprompriv), ETH_ALEN);
+                       p2pielen += ETH_ALEN;
+
+                       /*      Config Method */
+                       /*      This field should be big endian.
+                               Noted by P2P specification. */
+                       if ((pwdinfo->ui_got_wps_info ==
+                            P2P_GOT_WPSINFO_PEER_DISPLAY_PIN) ||
+                           (pwdinfo->ui_got_wps_info ==
+                            P2P_GOT_WPSINFO_SELF_DISPLAY_PIN))
+                               *(u16*) (p2pie + p2pielen) =
+                                       cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY);
+                       else
+                               *(u16*) (p2pie + p2pielen) =
+                                       cpu_to_be16(WPS_CONFIG_METHOD_PBC);
+
+                       p2pielen += 2;
+
+                       /*      Primary Device Type */
+                       /*      Category ID */
+                       *(u16*) (p2pie + p2pielen) =
+                               cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA);
+                       p2pielen += 2;
+
+                       /*      OUI */
+                       *(u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI);
+                       p2pielen += 4;
+
+                       /*      Sub Category ID */
+                       *(u16*) (p2pie + p2pielen) =
+                               cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER);
+                       p2pielen += 2;
+
+                       /*      Number of Secondary Device Types */
+                       /*      No Secondary Device Type List */
+                       p2pie[p2pielen++] = 0x00;
+
+                       /*      Device Name */
+                       /*      Type: */
+                       *(u16*) (p2pie + p2pielen) =
+                               cpu_to_be16(WPS_ATTR_DEVICE_NAME);
+                       p2pielen += 2;
+
+                       /*      Length: */
+                       *(u16*) (p2pie + p2pielen) =
+                               cpu_to_be16(pwdinfo->device_name_len);
+                       p2pielen += 2;
+
+                       /*      Value: */
+                       memcpy(p2pie + p2pielen, pwdinfo->device_name,
+                              pwdinfo->device_name_len);
+                       p2pielen += pwdinfo->device_name_len;
+
+                       /*      P2P Interface */
+                       /*      Type: */
+                       p2pie[p2pielen++] = P2P_ATTR_INTERFACE;
+
+                       /*      Length: */
+                       *(u16*) (p2pie + p2pielen) = cpu_to_le16(0x000D);
+                       p2pielen += 2;
+
+                       /*      Value: */
+                       memcpy(p2pie + p2pielen, pwdinfo->device_addr,
+                              ETH_ALEN);       /* P2P Device Address */
+                       p2pielen += ETH_ALEN;
+
+                       /* P2P Interface Address Count */
+                       p2pie[p2pielen++] = 1;
+
+                       memcpy(p2pie + p2pielen, pwdinfo->device_addr,
+                              ETH_ALEN);       /* P2P Interface Address List */
+                       p2pielen += ETH_ALEN;
+
+                       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_,
+                                              p2pielen, (unsigned char *)p2pie,
+                                              &pattrib->pktlen);
+
+                       /* wfdielen = build_assoc_req_wfd_ie(pwdinfo, pframe);*/
+                       /* pframe += wfdielen; */
+                       /* pattrib->pktlen += wfdielen; */
+               }
+       }
+
+       if (true == pwdinfo->wfd_info->wfd_enable) {
+               wfdielen = build_assoc_req_wfd_ie(pwdinfo, pframe);
+               pframe += wfdielen;
+               pattrib->pktlen += wfdielen;
+       } else if (pmlmepriv->wfd_assoc_req_ie != NULL &&
+                  pmlmepriv->wfd_assoc_req_ie_len > 0) {
+               /* WFD IE */
+               memcpy(pframe, pmlmepriv->wfd_assoc_req_ie,
+                      pmlmepriv->wfd_assoc_req_ie_len);
+               pattrib->pktlen += pmlmepriv->wfd_assoc_req_ie_len;
+               pframe += pmlmepriv->wfd_assoc_req_ie_len;
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       ret = _SUCCESS;
+
+exit:
+       pmlmepriv->assoc_req_len = 0;
+       if (ret == _SUCCESS) {
+               kfree(pmlmepriv->assoc_req);
+               pmlmepriv->assoc_req = kmalloc(pattrib->pktlen, GFP_ATOMIC);
+               if (pmlmepriv->assoc_req) {
+                       memcpy(pmlmepriv->assoc_req, pwlanhdr,
+                              pattrib->pktlen);
+                       pmlmepriv->assoc_req_len = pattrib->pktlen;
+               }
+       } else
+               kfree(pmlmepriv->assoc_req);
+
+       return;
+}
+
+/* when wait_ack is ture, this function shoule be called at process context */
+static int _issue_nulldata23a(struct rtw_adapter *padapter, unsigned char *da,
+                             unsigned int power_mode, int wait_ack)
+{
+       int ret = _FAIL;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       struct xmit_priv *pxmitpriv;
+       struct mlme_ext_priv *pmlmeext;
+       struct mlme_ext_info *pmlmeinfo;
+
+       /* DBG_8723A("%s:%d\n", __func__, power_mode); */
+
+       if (!padapter)
+               goto exit;
+
+       pxmitpriv = &padapter->xmitpriv;
+       pmlmeext = &padapter->mlmeextpriv;
+       pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               goto exit;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+       pattrib->retry_ctrl = false;
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)
+               SetFrDs(fctrl);
+       else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+               SetToDs(fctrl);
+
+       if (power_mode)
+               SetPwrMgt(fctrl);
+
+       ether_addr_copy(pwlanhdr->addr1, da);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_DATA_NULL);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       if (wait_ack)
+               ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
+       else {
+               dump_mgntframe23a(padapter, pmgntframe);
+               ret = _SUCCESS;
+       }
+
+exit:
+       return ret;
+}
+
+/* when wait_ms >0 , this function shoule be called at process context */
+/* da == NULL for station mode */
+int issue_nulldata23a(struct rtw_adapter *padapter, unsigned char *da,
+                     unsigned int power_mode, int try_cnt, int wait_ms)
+{
+       int ret;
+       int i = 0;
+       unsigned long start = jiffies;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       /* da == NULL, assum it's null data for sta to ap*/
+       if (da == NULL)
+               da = get_my_bssid23a(&pmlmeinfo->network);
+
+       do {
+               ret = _issue_nulldata23a(padapter, da, power_mode,
+                                        wait_ms > 0 ? true : false);
+
+               i++;
+
+               if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+                       break;
+
+               if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+                       msleep(wait_ms);
+
+       } while((i < try_cnt) && ((ret == _FAIL) || (wait_ms == 0)));
+
+       if (ret != _FAIL) {
+               ret = _SUCCESS;
+               goto exit;
+       }
+
+       if (try_cnt && wait_ms) {
+               if (da)
+                       DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d "
+                                 "in %u ms\n", FUNC_ADPT_ARG(padapter),
+                                 MAC_ARG(da), rtw_get_oper_ch23a(padapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+               else
+                       DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+                                 FUNC_ADPT_ARG(padapter),
+                                 rtw_get_oper_ch23a(padapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+       }
+exit:
+       return ret;
+}
+
+/* when wait_ack is ture, this function shoule be called at process context */
+static int _issue_qos_nulldata23a(struct rtw_adapter *padapter,
+                                 unsigned char *da, u16 tid, int wait_ack)
+{
+       int ret = _FAIL;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl, *qc;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       DBG_8723A("%s\n", __func__);
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               goto exit;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       pattrib->hdrlen += 2;
+       pattrib->qos_en = true;
+       pattrib->eosp = 1;
+       pattrib->ack_policy = 0;
+       pattrib->mdata = 0;
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)
+               SetFrDs(fctrl);
+       else if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+               SetToDs(fctrl);
+
+       if (pattrib->mdata)
+               SetMData(fctrl);
+
+       qc = (unsigned short *)(pframe + pattrib->hdrlen - 2);
+
+       SetPriority(qc, tid);
+
+       SetEOSP(qc, pattrib->eosp);
+
+       SetAckpolicy(qc, pattrib->ack_policy);
+
+       ether_addr_copy(pwlanhdr->addr1, da);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
+
+       pframe += sizeof(struct ieee80211_qos_hdr);
+       pattrib->pktlen = sizeof(struct ieee80211_qos_hdr);
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       if (wait_ack)
+               ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
+       else {
+               dump_mgntframe23a(padapter, pmgntframe);
+               ret = _SUCCESS;
+       }
+
+exit:
+       return ret;
+}
+
+/* when wait_ms >0 , this function shoule be called at process context */
+/* da == NULL for station mode */
+int issue_qos_nulldata23a(struct rtw_adapter *padapter, unsigned char *da,
+                         u16 tid, int try_cnt, int wait_ms)
+{
+       int ret;
+       int i = 0;
+       unsigned long start = jiffies;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       /* da == NULL, assum it's null data for sta to ap*/
+       if (da == NULL)
+               da = get_my_bssid23a(&pmlmeinfo->network);
+
+       do {
+               ret = _issue_qos_nulldata23a(padapter, da, tid,
+                                            wait_ms > 0 ? true : false);
+
+               i++;
+
+               if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+                       break;
+
+               if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+                       msleep(wait_ms);
+       } while((i < try_cnt) && ((ret == _FAIL)||(wait_ms == 0)));
+
+       if (ret != _FAIL) {
+               ret = _SUCCESS;
+               goto exit;
+       }
+
+       if (try_cnt && wait_ms) {
+               if (da)
+                       DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d "
+                                 "in %u ms\n", FUNC_ADPT_ARG(padapter),
+                                 MAC_ARG(da), rtw_get_oper_ch23a(padapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+               else
+                       DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+                                 FUNC_ADPT_ARG(padapter),
+                                 rtw_get_oper_ch23a(padapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+       }
+exit:
+       return ret;
+}
+
+static int _issue_deauth23a(struct rtw_adapter *padapter, unsigned char *da,
+                           unsigned short reason, u8 wait_ack)
+{
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       int ret = _FAIL;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_8723AU_P2P */
+
+       /* DBG_8723A("%s to "MAC_FMT"\n", __func__, MAC_ARG(da)); */
+
+#ifdef CONFIG_8723AU_P2P
+       if (!(rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) &&
+           (pwdinfo->rx_invitereq_info.scan_op_ch_only)) {
+               mod_timer(&pwdinfo->reset_ch_sitesurvey,
+                         jiffies + msecs_to_jiffies(10));
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               goto exit;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+       pattrib->retry_ctrl = false;
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, da);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_DEAUTH);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       reason = cpu_to_le16(reason);
+       pframe = rtw_set_fixed_ie23a(pframe, WLAN_REASON_PREV_AUTH_NOT_VALID,
+                                    (unsigned char *)&reason,
+                                    &pattrib->pktlen);
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       if (wait_ack)
+               ret = dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe);
+       else {
+               dump_mgntframe23a(padapter, pmgntframe);
+               ret = _SUCCESS;
+       }
+
+exit:
+       return ret;
+}
+
+int issue_deauth23a(struct rtw_adapter *padapter, unsigned char *da,
+                   unsigned short reason)
+{
+       DBG_8723A("%s to "MAC_FMT"\n", __func__, MAC_ARG(da));
+       return _issue_deauth23a(padapter, da, reason, false);
+}
+
+int issue_deauth23a_ex23a(struct rtw_adapter *padapter, u8 *da,
+                         unsigned short reason, int try_cnt, int wait_ms)
+{
+       int ret;
+       int i = 0;
+       unsigned long start = jiffies;
+
+       do {
+               ret = _issue_deauth23a(padapter, da, reason,
+                                      wait_ms >0 ? true : false);
+
+               i++;
+
+               if (padapter->bDriverStopped || padapter->bSurpriseRemoved)
+                       break;
+
+               if (i < try_cnt && wait_ms > 0 && ret == _FAIL)
+                       msleep(wait_ms);
+
+       } while((i < try_cnt) && ((ret == _FAIL)||(wait_ms == 0)));
+
+       if (ret != _FAIL) {
+               ret = _SUCCESS;
+               goto exit;
+       }
+
+       if (try_cnt && wait_ms) {
+               if (da)
+                       DBG_8723A(FUNC_ADPT_FMT" to "MAC_FMT", ch:%u%s, %d/%d "
+                                 "in %u ms\n", FUNC_ADPT_ARG(padapter),
+                                 MAC_ARG(da), rtw_get_oper_ch23a(padapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+               else
+                       DBG_8723A(FUNC_ADPT_FMT", ch:%u%s, %d/%d in %u ms\n",
+                                 FUNC_ADPT_ARG(padapter),
+                                 rtw_get_oper_ch23a(padapter),
+                                 ret == _SUCCESS?", acked":"", i, try_cnt,
+                                 jiffies_to_msecs(jiffies - start));
+       }
+exit:
+       return ret;
+}
+
+void issue_action_spct_ch_switch23a(struct rtw_adapter *padapter,
+                                   u8 *ra, u8 new_ch, u8 ch_offset)
+{
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       u8 category, action;
+
+       DBG_8723A(FUNC_NDEV_FMT" ra ="MAC_FMT", ch:%u, offset:%u\n",
+               FUNC_NDEV_ARG(padapter->pnetdev), MAC_ARG(ra),
+                 new_ch, ch_offset);
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, ra); /* RA */
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv)); /* TA */
+       ether_addr_copy(pwlanhdr->addr3, ra); /* DA = RA */
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       /* category, action */
+       category = WLAN_CATEGORY_SPECTRUM_MGMT;
+       action = WLAN_ACTION_SPCT_CHL_SWITCH;
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+
+       pframe = rtw_set_ie23a_ch_switch (pframe, &pattrib->pktlen, 0,
+                                         new_ch, 0);
+       pframe = rtw_set_ie23a_secondary_ch_offset(pframe, &pattrib->pktlen,
+               hal_ch_offset_to_secondary_ch_offset23a(ch_offset));
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+}
+
+void issue_action_BA23a(struct rtw_adapter *padapter, unsigned char *raddr,
+                       unsigned char action, unsigned short status)
+{
+       u8 category = WLAN_CATEGORY_BACK;
+       u16 start_seq;
+       u16 BA_para_set;
+       u16 reason_code;
+       u16 BA_timeout_value;
+       u16 BA_starting_seqctrl;
+       int max_rx_ampdu_factor;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       u8 *pframe;
+       struct ieee80211_hdr *pwlanhdr;
+       u16 *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct sta_info *psta;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct registry_priv *pregpriv = &padapter->registrypriv;
+#ifdef CONFIG_8723AU_BT_COEXIST
+       u8 tendaAPMac[] = {0xC8, 0x3A, 0x35};
+#endif
+
+       DBG_8723A("%s, category =%d, action =%d, status =%d\n",
+                 __func__, category, action, status);
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       /* memcpy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN); */
+       ether_addr_copy(pwlanhdr->addr1, raddr);
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+
+       status = cpu_to_le16(status);
+
+       if (category != 3)
+               goto out;
+
+       switch (action)
+       {
+       case 0: /* ADDBA req */
+               do {
+                       pmlmeinfo->dialogToken++;
+               } while (pmlmeinfo->dialogToken == 0);
+               pframe = rtw_set_fixed_ie23a(pframe, 1, &pmlmeinfo->dialogToken,
+                                            &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+               if ((BT_1Ant(padapter) == true) &&
+                   ((pmlmeinfo->assoc_AP_vendor != broadcomAP) ||
+                    memcmp(raddr, tendaAPMac, 3))) {
+                       /*  A-MSDU NOT Supported */
+                       BA_para_set = 0;
+                       /*  immediate Block Ack */
+                       BA_para_set |= (1 << 1) &
+                               IEEE80211_ADDBA_PARAM_POLICY_MASK;
+                       /*  TID */
+                       BA_para_set |= (status << 2) &
+                               IEEE80211_ADDBA_PARAM_TID_MASK;
+                       /*  max buffer size is 8 MSDU */
+                       BA_para_set |= (8 << 6) &
+                               IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
+               } else
+#endif
+               {
+                       /* immediate ack & 64 buffer size */
+                       BA_para_set = (0x1002 | ((status & 0xf) << 2));
+               }
+               BA_para_set = cpu_to_le16(BA_para_set);
+               pframe = rtw_set_fixed_ie23a(pframe, 2,
+                                            (unsigned char *)&BA_para_set,
+                                            &pattrib->pktlen);
+
+               BA_timeout_value = 5000;/*  5ms */
+               BA_timeout_value = cpu_to_le16(BA_timeout_value);
+               pframe = rtw_set_fixed_ie23a(pframe, 2, (unsigned char *)
+                                            &BA_timeout_value,
+                                            &pattrib->pktlen);
+
+               /* if ((psta = rtw_get_stainfo23a(pstapriv,
+                  pmlmeinfo->network.MacAddress)) != NULL) */
+               if ((psta = rtw_get_stainfo23a(pstapriv, raddr))) {
+                       start_seq = (psta->sta_xmitpriv.txseq_tid[status & 0x07]&0xfff) + 1;
+
+                       DBG_8723A("BA_starting_seqctrl = %d for TID =%d\n",
+                                 start_seq, status & 0x07);
+
+                       psta->BA_starting_seqctrl[status & 0x07] = start_seq;
+
+                       BA_starting_seqctrl = start_seq << 4;
+               }
+
+               BA_starting_seqctrl = cpu_to_le16(BA_starting_seqctrl);
+               pframe = rtw_set_fixed_ie23a(pframe, 2, (unsigned char *)&BA_starting_seqctrl, &pattrib->pktlen);
+               break;
+
+       case 1: /* ADDBA rsp */
+               pframe = rtw_set_fixed_ie23a(pframe, 1, &pmlmeinfo->ADDBA_req.dialog_token, &pattrib->pktlen);
+               pframe = rtw_set_fixed_ie23a(pframe, 2,
+                                            (unsigned char *)&status,
+                                            &pattrib->pktlen);
+               rtw_hal_get_def_var23a(padapter, HW_VAR_MAX_RX_AMPDU_FACTOR,
+                                      &max_rx_ampdu_factor);
+               if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_64K)
+                       BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
+               else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_32K)
+                       BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0800); /* 32 buffer size */
+               else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_16K)
+                       BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0400); /* 16 buffer size */
+               else if (max_rx_ampdu_factor == IEEE80211_HT_MAX_AMPDU_8K)
+                       BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x0200); /* 8 buffer size */
+               else
+                       BA_para_set = ((le16_to_cpu(pmlmeinfo->ADDBA_req.BA_para_set) & 0x3f) | 0x1000); /* 64 buffer size */
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+               if ((BT_1Ant(padapter) == true) &&
+                   ((pmlmeinfo->assoc_AP_vendor != broadcomAP) ||
+                    memcmp(raddr, tendaAPMac, 3))) {
+                       /*  max buffer size is 8 MSDU */
+                       BA_para_set &= ~IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
+                       BA_para_set |= (8 << 6) &
+                               IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK;
+               }
+#endif
+
+               if (pregpriv->ampdu_amsdu == 0)/* disabled */
+                       BA_para_set = cpu_to_le16(BA_para_set & ~BIT(0));
+               else if (pregpriv->ampdu_amsdu == 1)/* enabled */
+                       BA_para_set = cpu_to_le16(BA_para_set | BIT(0));
+               else /* auto */
+                       BA_para_set = cpu_to_le16(BA_para_set);
+
+               pframe = rtw_set_fixed_ie23a(pframe, 2,
+                                            (unsigned char *)&BA_para_set,
+                                            &pattrib->pktlen);
+               pframe = rtw_set_fixed_ie23a(pframe, 2, (unsigned char *)&pmlmeinfo->ADDBA_req.BA_timeout_value, &pattrib->pktlen);
+               break;
+       case 2:/* DELBA */
+               BA_para_set = (status & 0x1F) << 3;
+               BA_para_set = cpu_to_le16(BA_para_set);
+               pframe = rtw_set_fixed_ie23a(pframe, 2,
+                                            (unsigned char *)&BA_para_set,
+                                            &pattrib->pktlen);
+
+               reason_code = 37;/* Requested from peer STA as it does not
+                                   want to use the mechanism */
+               reason_code = cpu_to_le16(reason_code);
+               pframe = rtw_set_fixed_ie23a(pframe, 2,
+                                            (unsigned char *)&reason_code,
+                                            &pattrib->pktlen);
+               break;
+       default:
+               break;
+       }
+
+out:
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+}
+
+static void issue_action_BSSCoexistPacket(struct rtw_adapter *padapter)
+{
+       struct list_head *plist, *phead, *ptmp;
+       unsigned char category, action;
+       struct xmit_frame                       *pmgntframe;
+       struct pkt_attrib                       *pattrib;
+       unsigned char                           *pframe;
+       struct ieee80211_hdr    *pwlanhdr;
+       unsigned short                  *fctrl;
+       struct  wlan_network    *pnetwork = NULL;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct rtw_queue        *queue  = &pmlmepriv->scanned_queue;
+       u8 InfoContent[16] = {0};
+       u8 ICS[8][15];
+
+       if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0))
+               return;
+
+       if (true == pmlmeinfo->bwmode_updated)
+               return;
+
+       DBG_8723A("%s\n", __func__);
+
+       category = WLAN_CATEGORY_PUBLIC;
+       action = ACT_PUBLIC_BSSCOEXIST;
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+       {
+               return;
+       }
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       ether_addr_copy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network));
+       ether_addr_copy(pwlanhdr->addr2, myid(&padapter->eeprompriv));
+       ether_addr_copy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network));
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+
+       /*  */
+       if (pmlmepriv->num_FortyMHzIntolerant>0)
+       {
+               u8 iedata = 0;
+
+               iedata |= BIT(2);/* 20 MHz BSS Width Request */
+
+               pframe = rtw_set_ie23a(pframe, EID_BSSCoexistence,  1, &iedata, &pattrib->pktlen);
+
+       }
+
+       /*  */
+       memset(ICS, 0, sizeof(ICS));
+       if (pmlmepriv->num_sta_no_ht>0)
+       {
+               int i;
+
+               spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+
+               phead = get_list_head(queue);
+               plist = phead->next;
+
+               list_for_each_safe(plist, ptmp, phead) {
+                       int len;
+                       u8 *p;
+                       struct wlan_bssid_ex *pbss_network;
+
+                       pnetwork = container_of(plist, struct wlan_network,
+                                               list);
+
+                       pbss_network = &pnetwork->network;
+
+                       p = rtw_get_ie23a(pbss_network->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, pbss_network->IELength - _FIXED_IE_LENGTH_);
+                       if ((p == NULL) || (len == 0))/* non-HT */
+                       {
+                               if ((pbss_network->Configuration.DSConfig<= 0) || (pbss_network->Configuration.DSConfig>14))
+                                       continue;
+
+                               ICS[0][pbss_network->Configuration.DSConfig]= 1;
+
+                               if (ICS[0][0] == 0)
+                                       ICS[0][0] = 1;
+                       }
+
+               }
+
+               spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+
+               for (i = 0;i<8;i++)
+               {
+                       if (ICS[i][0] == 1)
+                       {
+                               int j, k = 0;
+
+                               InfoContent[k] = i;
+                               /* SET_BSS_INTOLERANT_ELE_REG_CLASS(InfoContent, i); */
+                               k++;
+
+                               for (j = 1;j<= 14;j++)
+                               {
+                                       if (ICS[i][j]== 1)
+                                       {
+                                               if (k<16)
+                                               {
+                                                       InfoContent[k] = j; /* channel number */
+                                                       /* SET_BSS_INTOLERANT_ELE_CHANNEL(InfoContent+k, j); */
+                                                       k++;
+                                               }
+                                       }
+                               }
+
+                               pframe = rtw_set_ie23a(pframe, EID_BSSIntolerantChlReport, k, InfoContent, &pattrib->pktlen);
+
+                       }
+
+               }
+
+       }
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+}
+
+unsigned int send_delba23a(struct rtw_adapter *padapter, u8 initiator, u8 *addr)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct sta_info *psta = NULL;
+       /* struct recv_reorder_ctrl *preorder_ctrl; */
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       u16 tid;
+
+       if ((pmlmeinfo->state&0x03) != WIFI_FW_AP_STATE)
+               if (!(pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS))
+                       return _SUCCESS;
+
+       psta = rtw_get_stainfo23a(pstapriv, addr);
+       if (psta == NULL)
+               return _SUCCESS;
+
+       if (initiator == 0) {  /*  recipient */
+               for (tid = 0; tid < MAXTID; tid++) {
+                       if (psta->recvreorder_ctrl[tid].enable == true) {
+                               DBG_8723A("rx agg disable tid(%d)\n", tid);
+                               issue_action_BA23a(padapter, addr, WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F));
+                               psta->recvreorder_ctrl[tid].enable = false;
+                               psta->recvreorder_ctrl[tid].indicate_seq = 0xffff;
+                       }
+               }
+       } else if (initiator == 1) { /*  originator */
+               for (tid = 0; tid < MAXTID; tid++) {
+                       if (psta->htpriv.agg_enable_bitmap & BIT(tid)) {
+                               DBG_8723A("tx agg disable tid(%d)\n", tid);
+                               issue_action_BA23a(padapter, addr, WLAN_ACTION_DELBA, (((tid <<1) |initiator)&0x1F));
+                               psta->htpriv.agg_enable_bitmap &= ~BIT(tid);
+                               psta->htpriv.candidate_tid_bitmap &= ~BIT(tid);
+
+                       }
+               }
+       }
+       return _SUCCESS;
+}
+
+unsigned int send_beacon23a(struct rtw_adapter *padapter)
+{
+       u8      bxmitok = false;
+       int     issue = 0;
+       int poll = 0;
+       unsigned long start = jiffies;
+       unsigned int passing_time;
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BCN_VALID, NULL);
+       do {
+               issue_beacon23a(padapter, 100);
+               issue++;
+               do {
+                       yield();
+                       rtw23a_hal_get_hwreg(padapter, HW_VAR_BCN_VALID, (u8 *)(&bxmitok));
+                       poll++;
+               } while ((poll%10)!= 0 && false == bxmitok &&
+                        !padapter->bSurpriseRemoved &&
+                        !padapter->bDriverStopped);
+
+       } while (!bxmitok && issue<100 && !padapter->bSurpriseRemoved &&
+                !padapter->bDriverStopped);
+
+       if (padapter->bSurpriseRemoved || padapter->bDriverStopped)
+               return _FAIL;
+
+       passing_time = jiffies_to_msecs(jiffies - start);
+
+       if (!bxmitok) {
+               DBG_8723A("%s fail! %u ms\n", __func__, passing_time);
+               return _FAIL;
+       } else {
+
+               if (passing_time > 100 || issue > 3)
+                       DBG_8723A("%s success, issue:%d, poll:%d, %u ms\n",
+                                 __func__, issue, poll, passing_time);
+               return _SUCCESS;
+       }
+}
+
+/****************************************************************************
+
+Following are some utitity fuctions for WiFi MLME
+
+*****************************************************************************/
+
+bool IsLegal5GChannel(struct rtw_adapter *Adapter, u8 channel)
+{
+
+       int i = 0;
+       u8 Channel_5G[45] = {36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58,
+               60, 62, 64, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122,
+               124, 126, 128, 130, 132, 134, 136, 138, 140, 149, 151, 153, 155, 157, 159,
+               161, 163, 165};
+       for (i = 0; i < sizeof(Channel_5G); i++)
+               if (channel == Channel_5G[i])
+                       return true;
+       return false;
+}
+
+void site_survey23a(struct rtw_adapter *padapter)
+{
+       unsigned char survey_channel = 0, val8;
+       enum rt_scan_type ScanType = SCAN_PASSIVE;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       u32 initialgain = 0;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+       if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) ||
+           (pwdinfo->p2p_info.scan_op_ch_only)) {
+               if (pwdinfo->rx_invitereq_info.scan_op_ch_only)
+                       survey_channel = pwdinfo->rx_invitereq_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx];
+               else
+                       survey_channel = pwdinfo->p2p_info.operation_ch[pmlmeext->sitesurvey_res.channel_idx];
+               ScanType = SCAN_ACTIVE;
+       } else if (rtw_p2p_findphase_ex_is_social(pwdinfo)) {
+               /* The driver is in the find phase, it should go through the social channel. */
+               int ch_set_idx;
+               survey_channel = pwdinfo->social_chan[pmlmeext->sitesurvey_res.channel_idx];
+               ch_set_idx = rtw_ch_set_search_ch23a(pmlmeext->channel_set, survey_channel);
+               if (ch_set_idx >= 0)
+                       ScanType = pmlmeext->channel_set[ch_set_idx].ScanType;
+               else
+                       ScanType = SCAN_ACTIVE;
+       } else
+#endif /* CONFIG_8723AU_P2P */
+       {
+               struct rtw_ieee80211_channel *ch;
+               if (pmlmeext->sitesurvey_res.channel_idx < pmlmeext->sitesurvey_res.ch_num) {
+                       ch = &pmlmeext->sitesurvey_res.ch[pmlmeext->sitesurvey_res.channel_idx];
+                       survey_channel = ch->hw_value;
+                       ScanType = (ch->flags & IEEE80211_CHAN_NO_IR) ? SCAN_PASSIVE : SCAN_ACTIVE;
+}
+       }
+
+       if (survey_channel != 0) {
+               /* PAUSE 4-AC Queue when site_survey23a */
+               /* rtw23a_hal_get_hwreg(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */
+               /* val8 |= 0x0f; */
+               /* rtw_hal_set_hwreg23a(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */
+               if (pmlmeext->sitesurvey_res.channel_idx == 0)
+                       set_channel_bwmode23a(padapter, survey_channel,
+                                             HAL_PRIME_CHNL_OFFSET_DONT_CARE,
+                                             HT_CHANNEL_WIDTH_20);
+               else
+                       SelectChannel23a(padapter, survey_channel);
+
+               if (ScanType == SCAN_ACTIVE) /* obey the channel plan setting... */
+               {
+#ifdef CONFIG_8723AU_P2P
+                       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) ||
+                               rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH)
+                       )
+                       {
+                               issue23a_probereq_p2p(padapter, NULL);
+                               issue23a_probereq_p2p(padapter, NULL);
+                               issue23a_probereq_p2p(padapter, NULL);
+                       }
+                       else
+#endif /* CONFIG_8723AU_P2P */
+                       {
+                               int i;
+                               for (i = 0;i<RTW_SSID_SCAN_AMOUNT;i++) {
+                                       if (pmlmeext->sitesurvey_res.ssid[i].ssid_len) {
+                                               /* todo: to issue two probe req??? */
+                                               issue_probereq23a(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL);
+                                               /* msleep(SURVEY_TO>>1); */
+                                               issue_probereq23a(padapter, &pmlmeext->sitesurvey_res.ssid[i], NULL);
+                                       }
+                               }
+
+                               if (pmlmeext->sitesurvey_res.scan_mode == SCAN_ACTIVE) {
+                                       /* todo: to issue two probe req??? */
+                                       issue_probereq23a(padapter, NULL, NULL);
+                                       /* msleep(SURVEY_TO>>1); */
+                                       issue_probereq23a(padapter, NULL, NULL);
+                               }
+                       }
+               }
+
+               set_survey_timer(pmlmeext, pmlmeext->chan_scan_time);
+       } else {
+
+               /*      channel number is 0 or this channel is not valid. */
+
+
+#ifdef CONFIG_8723AU_P2P
+               if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH))
+               {
+                       if ((pwdinfo->rx_invitereq_info.scan_op_ch_only) || (pwdinfo->p2p_info.scan_op_ch_only))
+                       {
+                               /*      Set the find_phase_state_exchange_cnt to P2P_FINDPHASE_EX_CNT. */
+                               /*      This will let the following flow to run the scanning end. */
+                               rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX);
+                       }
+               }
+
+               if (rtw_p2p_findphase_ex_is_needed(pwdinfo))
+               {
+                       /*      Set the P2P State to the listen state of find phase and set the current channel to the listen channel */
+                       set_channel_bwmode23a(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+                       rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_LISTEN);
+                       pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
+
+                       initialgain = 0xff; /* restore RX GAIN */
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain));
+                       /* turn on dynamic functions */
+                       Restore_DM_Func_Flag23a(padapter);
+                       /* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DIG|DYNAMIC_FUNC_HP|DYNAMIC_FUNC_SS, true); */
+
+                       mod_timer(&pwdinfo->find_phase_timer, jiffies +
+                                 msecs_to_jiffies(pwdinfo->listen_dwell * 100));
+               } else
+#endif /* CONFIG_8723AU_P2P */
+               {
+#ifdef CONFIG_8723AU_P2P
+                       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_SCAN) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH))
+                               rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+                       rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
+#endif /* CONFIG_8723AU_P2P */
+
+                       pmlmeext->sitesurvey_res.state = SCAN_COMPLETE;
+
+                       /* switch back to the original channel */
+
+                       set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+                       /* flush 4-AC Queue after site_survey23a */
+                       /* val8 = 0; */
+                       /* rtw_hal_set_hwreg23a(padapter, HW_VAR_TXPAUSE, (u8 *)(&val8)); */
+
+                       /* config MSR */
+                       Set_MSR23a(padapter, (pmlmeinfo->state & 0x3));
+
+                       initialgain = 0xff; /* restore RX GAIN */
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain));
+                       /* turn on dynamic functions */
+                       Restore_DM_Func_Flag23a(padapter);
+                       /* Switch_DM_Func23a(padapter, DYNAMIC_ALL_FUNC_ENABLE, true); */
+
+                       if (is_client_associated_to_ap23a(padapter) == true)
+                       {
+                               issue_nulldata23a(padapter, NULL, 0, 3, 500);
+
+                       }
+
+                       val8 = 0; /* survey done */
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+
+                       report_surveydone_event23a(padapter);
+
+                       pmlmeext->chan_scan_time = SURVEY_TO;
+                       pmlmeext->sitesurvey_res.state = SCAN_DISABLE;
+
+                       issue_action_BSSCoexistPacket(padapter);
+                       issue_action_BSSCoexistPacket(padapter);
+                       issue_action_BSSCoexistPacket(padapter);
+
+               }
+       }
+
+       return;
+}
+
+/* collect bss info from Beacon and Probe request/response frames. */
+u8 collect_bss_info23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame, struct wlan_bssid_ex *bssid)
+{
+       int     i;
+       u32     len;
+       u8      *p;
+       u16     val16;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8      *pframe = skb->data;
+       u32     packet_len = skb->len;
+       u8 ie_offset;
+       struct registry_priv    *pregistrypriv = &padapter->registrypriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       len = packet_len - sizeof(struct ieee80211_hdr_3addr);
+
+       if (len > MAX_IE_SZ)
+       {
+               /* DBG_8723A("IE too long for survey event\n"); */
+               return _FAIL;
+       }
+
+       memset(bssid, 0, sizeof(struct wlan_bssid_ex));
+
+       if (ieee80211_is_beacon(hdr->frame_control)) {
+               bssid->reserved = 1;
+               ie_offset = _BEACON_IE_OFFSET_;
+       } else {
+               /*  FIXME : more type */
+               if (ieee80211_is_probe_req(hdr->frame_control)) {
+                       ie_offset = _PROBEREQ_IE_OFFSET_;
+                       bssid->reserved = 2;
+               } else if (ieee80211_is_probe_resp(hdr->frame_control)) {
+                       ie_offset = _PROBERSP_IE_OFFSET_;
+                       bssid->reserved = 3;
+               } else {
+                       bssid->reserved = 0;
+                       ie_offset = _FIXED_IE_LENGTH_;
+               }
+       }
+
+       bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len;
+
+       /* below is to copy the information element */
+       bssid->IELength = len;
+       memcpy(bssid->IEs, (pframe + sizeof(struct ieee80211_hdr_3addr)), bssid->IELength);
+
+       /* get the signal strength */
+       bssid->Rssi = precv_frame->attrib.phy_info.RecvSignalPower; /*  in dBM.raw data */
+       bssid->PhyInfo.SignalQuality = precv_frame->attrib.phy_info.SignalQuality;/* in percentage */
+       bssid->PhyInfo.SignalStrength = precv_frame->attrib.phy_info.SignalStrength;/* in percentage */
+
+       /*  checking SSID */
+       if ((p = rtw_get_ie23a(bssid->IEs + ie_offset, _SSID_IE_, &len, bssid->IELength - ie_offset)) == NULL)
+       {
+               DBG_8723A("marc: cannot find SSID for survey event\n");
+               return _FAIL;
+       }
+
+       if (*(p + 1)) {
+               if (len > IEEE80211_MAX_SSID_LEN) {
+                       DBG_8723A("%s()-%d: IE too long (%d) for survey "
+                                 "event\n", __func__, __LINE__, len);
+                       return _FAIL;
+               }
+               memcpy(bssid->Ssid.ssid, (p + 2), *(p + 1));
+               bssid->Ssid.ssid_len = *(p + 1);
+       } else {
+               bssid->Ssid.ssid_len = 0;
+       }
+
+       memset(bssid->SupportedRates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+       /* checking rate info... */
+       i = 0;
+       p = rtw_get_ie23a(bssid->IEs + ie_offset, _SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset);
+       if (p != NULL)
+       {
+               if (len > NDIS_802_11_LENGTH_RATES_EX)
+               {
+                       DBG_8723A("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+                       return _FAIL;
+               }
+               memcpy(bssid->SupportedRates, (p + 2), len);
+               i = len;
+       }
+
+       p = rtw_get_ie23a(bssid->IEs + ie_offset, _EXT_SUPPORTEDRATES_IE_, &len, bssid->IELength - ie_offset);
+       if (p != NULL)
+       {
+               if (len > (NDIS_802_11_LENGTH_RATES_EX-i))
+               {
+                       DBG_8723A("%s()-%d: IE too long (%d) for survey event\n", __func__, __LINE__, len);
+                       return _FAIL;
+               }
+               memcpy(bssid->SupportedRates + i, (p + 2), len);
+       }
+
+       /* todo: */
+       {
+               bssid->NetworkTypeInUse = Ndis802_11OFDM24;
+       }
+
+       if (bssid->IELength < 12)
+               return _FAIL;
+
+       /*  Checking for DSConfig */
+       p = rtw_get_ie23a(bssid->IEs + ie_offset, _DSSET_IE_, &len, bssid->IELength - ie_offset);
+
+       bssid->Configuration.DSConfig = 0;
+       bssid->Configuration.Length = 0;
+
+       if (p)
+       {
+               bssid->Configuration.DSConfig = *(p + 2);
+       }
+       else
+       {/*  In 5G, some ap do not have DSSET IE */
+               /*  checking HT info for channel */
+               p = rtw_get_ie23a(bssid->IEs + ie_offset, _HT_ADD_INFO_IE_, &len, bssid->IELength - ie_offset);
+               if (p)
+               {
+                       struct HT_info_element *HT_info = (struct HT_info_element *)(p + 2);
+                       bssid->Configuration.DSConfig = HT_info->primary_channel;
+               }
+               else
+               { /*  use current channel */
+                       bssid->Configuration.DSConfig = rtw_get_oper_ch23a(padapter);
+               }
+       }
+
+       if (ieee80211_is_probe_req(hdr->frame_control)) {
+               /*  FIXME */
+               bssid->InfrastructureMode = Ndis802_11Infrastructure;
+               ether_addr_copy(bssid->MacAddress, hdr->addr2);
+               bssid->Privacy = 1;
+               return _SUCCESS;
+       }
+
+       memcpy(&bssid->Configuration.BeaconPeriod, rtw_get_beacon_interval23a_from_ie(bssid->IEs), 2);
+       bssid->Configuration.BeaconPeriod = le32_to_cpu(bssid->Configuration.BeaconPeriod);
+
+       val16 = rtw_get_capability23a(bssid);
+
+       if (val16 & BIT(0)) {
+               bssid->InfrastructureMode = Ndis802_11Infrastructure;
+               ether_addr_copy(bssid->MacAddress, hdr->addr2);
+       } else {
+               bssid->InfrastructureMode = Ndis802_11IBSS;
+               ether_addr_copy(bssid->MacAddress, hdr->addr3);
+       }
+
+       if (val16 & BIT(4))
+               bssid->Privacy = 1;
+       else
+               bssid->Privacy = 0;
+
+       bssid->Configuration.ATIMWindow = 0;
+
+       /* 20/40 BSS Coexistence check */
+       if ((pregistrypriv->wifi_spec == 1) && (false == pmlmeinfo->bwmode_updated))
+       {
+               struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+               p = rtw_get_ie23a(bssid->IEs + ie_offset, _HT_CAPABILITY_IE_, &len, bssid->IELength - ie_offset);
+               if (p && len > 0) {
+                       struct HT_caps_element  *pHT_caps;
+                       pHT_caps = (struct HT_caps_element      *)(p + 2);
+
+                       if (pHT_caps->u.HT_cap_element.HT_caps_info & BIT(14))
+                               pmlmepriv->num_FortyMHzIntolerant++;
+               } else
+               {
+                       pmlmepriv->num_sta_no_ht++;
+               }
+       }
+
+
+       /*  mark bss info receving from nearby channel as SignalQuality 101 */
+       if (bssid->Configuration.DSConfig != rtw_get_oper_ch23a(padapter))
+               bssid->PhyInfo.SignalQuality = 101;
+
+       return _SUCCESS;
+}
+
+void start_create_ibss23a(struct rtw_adapter* padapter)
+{
+       unsigned short  caps;
+       u8      val8;
+       u8      join_type;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
+       pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig;
+       pmlmeinfo->bcn_interval = get_beacon_interval23a(pnetwork);
+
+       /* update wireless mode */
+       update_wireless_mode23a(padapter);
+
+       /* udpate capability */
+       caps = rtw_get_capability23a(pnetwork);
+       update_capinfo23a(padapter, caps);
+       if (caps&cap_IBSS)/* adhoc master */
+       {
+               val8 = 0xcf;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+               /* switch channel */
+               /* SelectChannel23a(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE); */
+               set_channel_bwmode23a(padapter, pmlmeext->cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+
+               beacon_timing_control23a(padapter);
+
+               /* set msr to WIFI_FW_ADHOC_STATE */
+               pmlmeinfo->state = WIFI_FW_ADHOC_STATE;
+               Set_MSR23a(padapter, (pmlmeinfo->state & 0x3));
+
+               /* issue beacon */
+               if (send_beacon23a(padapter) == _FAIL)
+               {
+                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_, ("issuing beacon frame fail....\n"));
+
+                       report_join_res23a(padapter, -1);
+                       pmlmeinfo->state = WIFI_FW_NULL_STATE;
+               }
+               else
+               {
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, padapter->registrypriv.dev_network.MacAddress);
+                       join_type = 0;
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+
+                       report_join_res23a(padapter, 1);
+                       pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+               }
+       }
+       else
+       {
+               DBG_8723A("start_create_ibss23a, invalid cap:%x\n", caps);
+               return;
+       }
+}
+
+void start_clnt_join23a(struct rtw_adapter* padapter)
+{
+       unsigned short  caps;
+       u8      val8;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
+       int beacon_timeout;
+
+       pmlmeext->cur_channel = (u8)pnetwork->Configuration.DSConfig;
+       pmlmeinfo->bcn_interval = get_beacon_interval23a(pnetwork);
+
+       /* update wireless mode */
+       update_wireless_mode23a(padapter);
+
+       /* udpate capability */
+       caps = rtw_get_capability23a(pnetwork);
+       update_capinfo23a(padapter, caps);
+       if (caps&cap_ESS) {
+               /* switch channel */
+               set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+               Set_MSR23a(padapter, WIFI_FW_STATION_STATE);
+
+               val8 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X)? 0xcc: 0xcf;
+
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+               /* switch channel */
+               /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */
+
+               /* here wait for receiving the beacon to start auth */
+               /* and enable a timer */
+               beacon_timeout = decide_wait_for_beacon_timeout23a(pmlmeinfo->bcn_interval);
+               set_link_timer(pmlmeext, beacon_timeout);
+               mod_timer(&padapter->mlmepriv.assoc_timer, jiffies +
+                         msecs_to_jiffies((REAUTH_TO * REAUTH_LIMIT) + (REASSOC_TO*REASSOC_LIMIT) + beacon_timeout));
+               pmlmeinfo->state = WIFI_FW_AUTH_NULL | WIFI_FW_STATION_STATE;
+       }
+       else if (caps&cap_IBSS) /* adhoc client */
+       {
+               Set_MSR23a(padapter, WIFI_FW_ADHOC_STATE);
+
+               val8 = 0xcf;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+               /* switch channel */
+               set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+               beacon_timing_control23a(padapter);
+
+               pmlmeinfo->state = WIFI_FW_ADHOC_STATE;
+
+               report_join_res23a(padapter, 1);
+       }
+       else
+       {
+               /* DBG_8723A("marc: invalid cap:%x\n", caps); */
+               return;
+       }
+}
+
+void start_clnt_auth23a(struct rtw_adapter* padapter)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       del_timer_sync(&pmlmeext->link_timer);
+
+       pmlmeinfo->state &= (~WIFI_FW_AUTH_NULL);
+       pmlmeinfo->state |= WIFI_FW_AUTH_STATE;
+
+       pmlmeinfo->auth_seq = 1;
+       pmlmeinfo->reauth_count = 0;
+       pmlmeinfo->reassoc_count = 0;
+       pmlmeinfo->link_count = 0;
+       pmlmeext->retry = 0;
+
+       /*  Because of AP's not receiving deauth before */
+       /*  AP may: 1)not response auth or 2)deauth us after link is complete */
+       /*  issue deauth before issuing auth to deal with the situation */
+       /*      Commented by Albert 2012/07/21 */
+       /*      For the Win8 P2P connection, it will be hard to have a successful connection if this Wi-Fi doesn't connect to it. */
+       issue_deauth23a(padapter, (&pmlmeinfo->network)->MacAddress, WLAN_REASON_DEAUTH_LEAVING);
+
+       DBG_8723A_LEVEL(_drv_always_, "start auth\n");
+       issue_auth23a(padapter, NULL, 0);
+
+       set_link_timer(pmlmeext, REAUTH_TO);
+}
+
+void start_clnt_assoc23a(struct rtw_adapter* padapter)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       del_timer_sync(&pmlmeext->link_timer);
+
+       pmlmeinfo->state &= (~(WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE));
+       pmlmeinfo->state |= (WIFI_FW_AUTH_SUCCESS | WIFI_FW_ASSOC_STATE);
+
+       issue_assocreq23a(padapter);
+
+       set_link_timer(pmlmeext, REASSOC_TO);
+}
+
+unsigned int receive_disconnect23a(struct rtw_adapter *padapter, unsigned char *MacAddr, unsigned short reason)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       /* check A3 */
+       if (!ether_addr_equal(MacAddr, get_my_bssid23a(&pmlmeinfo->network)))
+               return _SUCCESS;
+
+       DBG_8723A("%s\n", __func__);
+
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+       {
+               if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
+               {
+                       pmlmeinfo->state = WIFI_FW_NULL_STATE;
+                       report_del_sta_event23a(padapter, MacAddr, reason);
+
+               }
+               else if (pmlmeinfo->state & WIFI_FW_LINKING_STATE)
+               {
+                       pmlmeinfo->state = WIFI_FW_NULL_STATE;
+                       report_join_res23a(padapter, -2);
+               }
+       }
+
+       return _SUCCESS;
+}
+
+static void process_80211d(struct rtw_adapter *padapter, struct wlan_bssid_ex *bssid)
+{
+       struct registry_priv *pregistrypriv;
+       struct mlme_ext_priv *pmlmeext;
+       struct rt_channel_info *chplan_new;
+       u8 channel;
+       u8 i;
+
+       pregistrypriv = &padapter->registrypriv;
+       pmlmeext = &padapter->mlmeextpriv;
+
+       /*  Adjust channel plan by AP Country IE */
+       if (pregistrypriv->enable80211d &&
+               (!pmlmeext->update_channel_plan_by_ap_done))
+       {
+               u8 *ie, *p;
+               u32 len;
+               struct rt_channel_plan chplan_ap;
+               struct rt_channel_info chplan_sta[MAX_CHANNEL_NUM];
+               u8 country[4];
+               u8 fcn; /*  first channel number */
+               u8 noc; /*  number of channel */
+               u8 j, k;
+
+               ie = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _COUNTRY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+               if (!ie) return;
+               if (len < 6) return;
+
+               ie += 2;
+               p = ie;
+               ie += len;
+
+               memset(country, 0, 4);
+               memcpy(country, p, 3);
+               p += 3;
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+                               ("%s: 802.11d country =%s\n", __func__, country));
+
+               i = 0;
+               while ((ie - p) >= 3)
+               {
+                       fcn = *(p++);
+                       noc = *(p++);
+                       p++;
+
+                       for (j = 0; j < noc; j++)
+                       {
+                               if (fcn <= 14) channel = fcn + j; /*  2.4 GHz */
+                               else channel = fcn + j*4; /*  5 GHz */
+
+                               chplan_ap.Channel[i++] = channel;
+                       }
+               }
+               chplan_ap.Len = i;
+
+               memcpy(chplan_sta, pmlmeext->channel_set, sizeof(chplan_sta));
+               memset(pmlmeext->channel_set, 0, sizeof(pmlmeext->channel_set));
+               chplan_new = pmlmeext->channel_set;
+
+               i = j = k = 0;
+               if (pregistrypriv->wireless_mode & WIRELESS_11G) {
+                       do {
+                               if ((i == MAX_CHANNEL_NUM) ||
+                                       (chplan_sta[i].ChannelNum == 0) ||
+                                       (chplan_sta[i].ChannelNum > 14))
+                                       break;
+
+                               if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] > 14))
+                                       break;
+
+                               if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j]) {
+                                       chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+                                       chplan_new[k].ScanType = SCAN_ACTIVE;
+                                       i++;
+                                       j++;
+                                       k++;
+                               } else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j]) {
+                                       chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+                                       chplan_new[k].ScanType = SCAN_PASSIVE;
+                                       i++;
+                                       k++;
+                               } else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j]) {
+                                       chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+                                       chplan_new[k].ScanType = SCAN_ACTIVE;
+                                       j++;
+                                       k++;
+                               }
+                       } while (1);
+
+                       /*  change AP not support channel to Passive scan */
+                       while ((i < MAX_CHANNEL_NUM) &&
+                               (chplan_sta[i].ChannelNum != 0) &&
+                               (chplan_sta[i].ChannelNum <= 14)) {
+                               chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+                               chplan_new[k].ScanType = SCAN_PASSIVE;
+                               i++;
+                               k++;
+                       }
+
+                       /*  add channel AP supported */
+                       while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) {
+                               chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+                               chplan_new[k].ScanType = SCAN_ACTIVE;
+                               j++;
+                               k++;
+                       }
+               } else {
+                       /*  keep original STA 2.4G channel plan */
+                       while ((i < MAX_CHANNEL_NUM) &&
+                               (chplan_sta[i].ChannelNum != 0) &&
+                               (chplan_sta[i].ChannelNum <= 14)) {
+                               chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+                               chplan_new[k].ScanType = chplan_sta[i].ScanType;
+                               i++;
+                               k++;
+                       }
+
+                       /*  skip AP 2.4G channel plan */
+                       while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] <= 14)) {
+                               j++;
+                       }
+               }
+
+               if (pregistrypriv->wireless_mode & WIRELESS_11A) {
+                       do {
+                               if ((i == MAX_CHANNEL_NUM) ||
+                                   (chplan_sta[i].ChannelNum == 0))
+                                       break;
+
+                               if ((j == chplan_ap.Len) || (chplan_ap.Channel[j] == 0))
+                                       break;
+
+                               if (chplan_sta[i].ChannelNum == chplan_ap.Channel[j])
+                               {
+                                       chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+                                       chplan_new[k].ScanType = SCAN_ACTIVE;
+                                       i++;
+                                       j++;
+                                       k++;
+                               }
+                               else if (chplan_sta[i].ChannelNum < chplan_ap.Channel[j])
+                               {
+                                       chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+/*                                     chplan_new[k].ScanType = chplan_sta[i].ScanType; */
+                                       chplan_new[k].ScanType = SCAN_PASSIVE;
+                                       i++;
+                                       k++;
+                               }
+                               else if (chplan_sta[i].ChannelNum > chplan_ap.Channel[j])
+                               {
+                                       chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+                                       chplan_new[k].ScanType = SCAN_ACTIVE;
+                                       j++;
+                                       k++;
+                               }
+                       } while (1);
+
+                       /*  change AP not support channel to Passive scan */
+                       while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) {
+                               chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+                               chplan_new[k].ScanType = SCAN_PASSIVE;
+                               i++;
+                               k++;
+                       }
+
+                       /*  add channel AP supported */
+                       while ((j < chplan_ap.Len) && (chplan_ap.Channel[j] != 0)) {
+                               chplan_new[k].ChannelNum = chplan_ap.Channel[j];
+                               chplan_new[k].ScanType = SCAN_ACTIVE;
+                               j++;
+                               k++;
+                       }
+               } else {
+                       /*  keep original STA 5G channel plan */
+                       while ((i < MAX_CHANNEL_NUM) && (chplan_sta[i].ChannelNum != 0)) {
+                               chplan_new[k].ChannelNum = chplan_sta[i].ChannelNum;
+                               chplan_new[k].ScanType = chplan_sta[i].ScanType;
+                               i++;
+                               k++;
+                       }
+               }
+               pmlmeext->update_channel_plan_by_ap_done = 1;
+       }
+
+       /*  If channel is used by AP, set channel scan type to active */
+       channel = bssid->Configuration.DSConfig;
+       chplan_new = pmlmeext->channel_set;
+       i = 0;
+       while ((i < MAX_CHANNEL_NUM) && (chplan_new[i].ChannelNum != 0)) {
+               if (chplan_new[i].ChannelNum == channel)
+               {
+                       if (chplan_new[i].ScanType == SCAN_PASSIVE) {
+                               /* 5G Bnad 2, 3 (DFS) doesn't change to active scan */
+                               if (channel >= 52 && channel <= 144)
+                                       break;
+
+                               chplan_new[i].ScanType = SCAN_ACTIVE;
+                               RT_TRACE(_module_rtl871x_mlme_c_, _drv_notice_,
+                                                ("%s: change channel %d scan type from passive to active\n",
+                                                 __func__, channel));
+                       }
+                       break;
+               }
+               i++;
+       }
+}
+
+/****************************************************************************
+
+Following are the functions to report events
+
+*****************************************************************************/
+
+void report_survey_event23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame)
+{
+       struct cmd_obj *pcmd_obj;
+       u8      *pevtcmd;
+       u32 cmdsz;
+       struct survey_event     *psurvey_evt;
+       struct C2HEvent_Header *pc2h_evt_hdr;
+       struct mlme_ext_priv *pmlmeext;
+       struct cmd_priv *pcmdpriv;
+
+       if (!padapter)
+               return;
+
+       pmlmeext = &padapter->mlmeextpriv;
+       pcmdpriv = &padapter->cmdpriv;
+
+       pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj),
+                                            GFP_ATOMIC);
+       if (!pcmd_obj)
+               return;
+
+       cmdsz = (sizeof(struct survey_event) + sizeof(struct C2HEvent_Header));
+       pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
+       if (!pevtcmd) {
+               kfree(pcmd_obj);
+               return;
+       }
+
+       INIT_LIST_HEAD(&pcmd_obj->list);
+
+       pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+       pcmd_obj->cmdsz = cmdsz;
+       pcmd_obj->parmbuf = pevtcmd;
+
+       pcmd_obj->rsp = NULL;
+       pcmd_obj->rspsz  = 0;
+
+       pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd);
+       pc2h_evt_hdr->len = sizeof(struct survey_event);
+       pc2h_evt_hdr->ID = GEN_EVT_CODE(_Survey);
+       pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
+
+       psurvey_evt = (struct survey_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
+
+       if (collect_bss_info23a(padapter, precv_frame, &psurvey_evt->bss) == _FAIL) {
+               kfree(pcmd_obj);
+               kfree(pevtcmd);
+               return;
+       }
+
+       process_80211d(padapter, &psurvey_evt->bss);
+
+       rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
+
+       pmlmeext->sitesurvey_res.bss_cnt++;
+
+       return;
+}
+
+void report_surveydone_event23a(struct rtw_adapter *padapter)
+{
+       struct cmd_obj *pcmd_obj;
+       u8      *pevtcmd;
+       u32 cmdsz;
+       struct surveydone_event *psurveydone_evt;
+       struct C2HEvent_Header  *pc2h_evt_hdr;
+       struct mlme_ext_priv            *pmlmeext = &padapter->mlmeextpriv;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj),
+                                            GFP_ATOMIC);
+       if (!pcmd_obj)
+               return;
+
+       cmdsz = (sizeof(struct surveydone_event) + sizeof(struct C2HEvent_Header));
+       pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
+       if (!pevtcmd) {
+               kfree(pcmd_obj);
+               return;
+       }
+
+       INIT_LIST_HEAD(&pcmd_obj->list);
+
+       pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+       pcmd_obj->cmdsz = cmdsz;
+       pcmd_obj->parmbuf = pevtcmd;
+
+       pcmd_obj->rsp = NULL;
+       pcmd_obj->rspsz  = 0;
+
+       pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd);
+       pc2h_evt_hdr->len = sizeof(struct surveydone_event);
+       pc2h_evt_hdr->ID = GEN_EVT_CODE(_SurveyDone);
+       pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
+
+       psurveydone_evt = (struct surveydone_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
+       psurveydone_evt->bss_cnt = pmlmeext->sitesurvey_res.bss_cnt;
+
+       DBG_8723A("survey done event(%x)\n", psurveydone_evt->bss_cnt);
+
+       rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
+
+       return;
+}
+
+void report_join_res23a(struct rtw_adapter *padapter, int res)
+{
+       struct cmd_obj *pcmd_obj;
+       u8      *pevtcmd;
+       u32 cmdsz;
+       struct joinbss_event            *pjoinbss_evt;
+       struct C2HEvent_Header  *pc2h_evt_hdr;
+       struct mlme_ext_priv            *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj),
+                                            GFP_ATOMIC);
+       if (!pcmd_obj)
+               return;
+
+       cmdsz = (sizeof(struct joinbss_event) + sizeof(struct C2HEvent_Header));
+       pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
+       if (!pevtcmd) {
+               kfree(pcmd_obj);
+               return;
+       }
+
+       INIT_LIST_HEAD(&pcmd_obj->list);
+
+       pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+       pcmd_obj->cmdsz = cmdsz;
+       pcmd_obj->parmbuf = pevtcmd;
+
+       pcmd_obj->rsp = NULL;
+       pcmd_obj->rspsz  = 0;
+
+       pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd);
+       pc2h_evt_hdr->len = sizeof(struct joinbss_event);
+       pc2h_evt_hdr->ID = GEN_EVT_CODE(_JoinBss);
+       pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
+
+       pjoinbss_evt = (struct joinbss_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
+       memcpy((unsigned char *)&pjoinbss_evt->network.network,
+              &pmlmeinfo->network, sizeof(struct wlan_bssid_ex));
+       pjoinbss_evt->network.join_res  = pjoinbss_evt->network.aid = res;
+
+       DBG_8723A("report_join_res23a(%d)\n", res);
+
+       rtw_joinbss_event_prehandle23a(padapter, (u8 *)&pjoinbss_evt->network);
+
+       rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
+
+       return;
+}
+
+void report_del_sta_event23a(struct rtw_adapter *padapter, unsigned char* MacAddr, unsigned short reason)
+{
+       struct cmd_obj *pcmd_obj;
+       u8      *pevtcmd;
+       u32 cmdsz;
+       struct sta_info *psta;
+       int     mac_id;
+       struct stadel_event                     *pdel_sta_evt;
+       struct C2HEvent_Header  *pc2h_evt_hdr;
+       struct mlme_ext_priv            *pmlmeext = &padapter->mlmeextpriv;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj),
+                                            GFP_ATOMIC);
+       if (!pcmd_obj)
+               return;
+
+       cmdsz = (sizeof(struct stadel_event) + sizeof(struct C2HEvent_Header));
+       pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
+       if (!pevtcmd) {
+               kfree(pcmd_obj);
+               return;
+       }
+
+       INIT_LIST_HEAD(&pcmd_obj->list);
+
+       pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+       pcmd_obj->cmdsz = cmdsz;
+       pcmd_obj->parmbuf = pevtcmd;
+
+       pcmd_obj->rsp = NULL;
+       pcmd_obj->rspsz  = 0;
+
+       pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd);
+       pc2h_evt_hdr->len = sizeof(struct stadel_event);
+       pc2h_evt_hdr->ID = GEN_EVT_CODE(_DelSTA);
+       pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
+
+       pdel_sta_evt = (struct stadel_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
+       ether_addr_copy((unsigned char *)&pdel_sta_evt->macaddr, MacAddr);
+       memcpy((unsigned char *)pdel_sta_evt->rsvd, (unsigned char *)&reason,
+              2);
+
+       psta = rtw_get_stainfo23a(&padapter->stapriv, MacAddr);
+       if (psta)
+               mac_id = (int)psta->mac_id;
+       else
+               mac_id = (-1);
+
+       pdel_sta_evt->mac_id = mac_id;
+
+       DBG_8723A("report_del_sta_event23a: delete STA, mac_id =%d\n", mac_id);
+
+       rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
+
+       return;
+}
+
+void report_add_sta_event23a(struct rtw_adapter *padapter, unsigned char* MacAddr, int cam_idx)
+{
+       struct cmd_obj *pcmd_obj;
+       u8      *pevtcmd;
+       u32 cmdsz;
+       struct stassoc_event            *padd_sta_evt;
+       struct C2HEvent_Header  *pc2h_evt_hdr;
+       struct mlme_ext_priv            *pmlmeext = &padapter->mlmeextpriv;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+
+       pcmd_obj = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj),
+                                            GFP_ATOMIC);
+       if (!pcmd_obj)
+               return;
+
+       cmdsz = (sizeof(struct stassoc_event) + sizeof(struct C2HEvent_Header));
+       pevtcmd = kzalloc(cmdsz, GFP_ATOMIC);
+       if (!pevtcmd) {
+               kfree(pcmd_obj);
+               return;
+       }
+
+       INIT_LIST_HEAD(&pcmd_obj->list);
+
+       pcmd_obj->cmdcode = GEN_CMD_CODE(_Set_MLME_EVT);
+       pcmd_obj->cmdsz = cmdsz;
+       pcmd_obj->parmbuf = pevtcmd;
+
+       pcmd_obj->rsp = NULL;
+       pcmd_obj->rspsz  = 0;
+
+       pc2h_evt_hdr = (struct C2HEvent_Header*)(pevtcmd);
+       pc2h_evt_hdr->len = sizeof(struct stassoc_event);
+       pc2h_evt_hdr->ID = GEN_EVT_CODE(_AddSTA);
+       pc2h_evt_hdr->seq = atomic_inc_return(&pmlmeext->event_seq);
+
+       padd_sta_evt = (struct stassoc_event*)(pevtcmd + sizeof(struct C2HEvent_Header));
+       ether_addr_copy((unsigned char *)&padd_sta_evt->macaddr, MacAddr);
+       padd_sta_evt->cam_id = cam_idx;
+
+       DBG_8723A("report_add_sta_event23a: add STA\n");
+
+       rtw_enqueue_cmd23a(pcmdpriv, pcmd_obj);
+
+       return;
+}
+
+/****************************************************************************
+
+Following are the event callback functions
+
+*****************************************************************************/
+
+/* for sta/adhoc mode */
+void update_sta_info23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info    *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       /* ERP */
+       VCS_update23a(padapter, psta);
+
+       /* HT */
+       if (pmlmepriv->htpriv.ht_option)
+       {
+               psta->htpriv.ht_option = true;
+
+               psta->htpriv.ampdu_enable = pmlmepriv->htpriv.ampdu_enable;
+
+               if (support_short_GI23a(padapter, &pmlmeinfo->HT_caps))
+                       psta->htpriv.sgi = true;
+
+               psta->qos_option = true;
+
+       }
+       else
+       {
+               psta->htpriv.ht_option = false;
+
+               psta->htpriv.ampdu_enable = false;
+
+               psta->htpriv.sgi = false;
+               psta->qos_option = false;
+
+       }
+       psta->htpriv.bwmode = pmlmeext->cur_bwmode;
+       psta->htpriv.ch_offset = pmlmeext->cur_ch_offset;
+
+       psta->htpriv.agg_enable_bitmap = 0x0;/* reset */
+       psta->htpriv.candidate_tid_bitmap = 0x0;/* reset */
+
+       /* QoS */
+       if (pmlmepriv->qospriv.qos_option)
+               psta->qos_option = true;
+
+       psta->state = _FW_LINKED;
+}
+
+void mlmeext_joinbss_event_callback23a(struct rtw_adapter *padapter, int join_res)
+{
+       struct sta_info         *psta, *psta_bmc;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+       struct sta_priv         *pstapriv = &padapter->stapriv;
+       u8      join_type;
+       u16 media_status;
+
+       if (join_res < 0)
+       {
+               join_type = 1;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, null_addr);
+
+               /* restore to initial setting. */
+               update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode);
+
+               goto exit_mlmeext_joinbss_event_callback23a;
+       }
+
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)
+       {
+               /* for bc/mc */
+               psta_bmc = rtw_get_bcmc_stainfo23a(padapter);
+               if (psta_bmc)
+               {
+                       pmlmeinfo->FW_sta_info[psta_bmc->mac_id].psta = psta_bmc;
+                       update_bmc_sta_support_rate23a(padapter, psta_bmc->mac_id);
+                       Update_RA_Entry23a(padapter, psta_bmc);
+               }
+       }
+
+       /* turn on dynamic functions */
+       Switch_DM_Func23a(padapter, DYNAMIC_ALL_FUNC_ENABLE, true);
+
+       /*  update IOT-releated issue */
+       update_IOT_info23a(padapter);
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, cur_network->SupportedRates);
+
+       /* BCN interval */
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BEACON_INTERVAL, (u8 *)(&pmlmeinfo->bcn_interval));
+
+       /* udpate capability */
+       update_capinfo23a(padapter, pmlmeinfo->capability);
+
+       /* WMM, Update EDCA param */
+       WMMOnAssocRsp23a(padapter);
+
+       /* HT */
+       HTOnAssocRsp23a(padapter);
+
+       /* Set cur_channel&cur_bwmode&cur_ch_offset */
+       set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+       psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress);
+       if (psta) /* only for infra. mode */
+       {
+               pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
+
+               /* DBG_8723A("set_sta_rate23a\n"); */
+
+               psta->wireless_mode = pmlmeext->cur_wireless_mode;
+
+               /* set per sta rate after updating HT cap. */
+               set_sta_rate23a(padapter, psta);
+
+               media_status = (psta->mac_id<<8)|1; /*   MACID|OPMODE: 1 means connect */
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_MEDIA_STATUS_RPT, (u8 *)&media_status);
+       }
+
+       join_type = 2;
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+       {
+               /*  correcting TSF */
+               correct_TSF23a(padapter, pmlmeext);
+
+               /* set_link_timer(pmlmeext, DISCONNECT_TO); */
+       }
+
+       rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_CONNECT, 0);
+
+exit_mlmeext_joinbss_event_callback23a:
+       DBG_8723A("=>%s\n", __func__);
+}
+
+void mlmeext_sta_add_event_callback23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       u8      join_type;
+
+       DBG_8723A("%s\n", __func__);
+
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE)
+       {
+               if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)/* adhoc master or sta_count>1 */
+               {
+                       /* nothing to do */
+               }
+               else/* adhoc client */
+               {
+                       /* update TSF Value */
+                       /* update_TSF23a(pmlmeext, pframe, len); */
+
+                       /*  correcting TSF */
+                       correct_TSF23a(padapter, pmlmeext);
+
+                       /* start beacon */
+                       if (send_beacon23a(padapter) == _FAIL)
+                       {
+                               pmlmeinfo->FW_sta_info[psta->mac_id].status = 0;
+
+                               pmlmeinfo->state ^= WIFI_FW_ADHOC_STATE;
+
+                               return;
+                       }
+
+                       pmlmeinfo->state |= WIFI_FW_ASSOC_SUCCESS;
+
+               }
+
+               join_type = 2;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+       }
+
+       pmlmeinfo->FW_sta_info[psta->mac_id].psta = psta;
+
+       /* rate radaptive */
+       Update_RA_Entry23a(padapter, psta);
+
+       /* update adhoc sta_info */
+       update_sta_info23a(padapter, psta);
+}
+
+void mlmeext_sta_del_event_callback23a(struct rtw_adapter *padapter)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if (is_client_associated_to_ap23a(padapter) || is_IBSS_empty23a(padapter))
+       {
+               /* set_opmode_cmd(padapter, infra_client_with_mlme); */
+
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_DISCONNECT, NULL);
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, null_addr);
+
+               /* restore to initial setting. */
+               update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode);
+
+               /* switch to the 20M Hz mode after disconnect */
+               pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+               pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+               /* SelectChannel23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset); */
+               set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+               flush_all_cam_entry23a(padapter);
+
+               pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+               /* set MSR to no link state -> infra. mode */
+               Set_MSR23a(padapter, _HW_STATE_STATION_);
+
+               del_timer_sync(&pmlmeext->link_timer);
+       }
+}
+
+/****************************************************************************
+
+Following are the functions for the timer handlers
+
+*****************************************************************************/
+void linked23a_rx_sig_stren_disp(struct rtw_adapter *padapter)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       u8 mac_id;
+       int UndecoratedSmoothedPWDB;
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE)
+               mac_id = 0;
+       else if ((pmlmeinfo->state&0x03) == _HW_STATE_AP_)
+               mac_id = 2;
+
+       rtw_hal_get_def_var23a(padapter, HW_DEF_RA_INFO_DUMP,&mac_id);
+
+       rtw_hal_get_def_var23a(padapter, HAL_DEF_UNDERCORATEDSMOOTHEDPWDB, &UndecoratedSmoothedPWDB);
+       DBG_8723A("UndecoratedSmoothedPWDB:%d\n", UndecoratedSmoothedPWDB);
+}
+
+static u8 chk_ap_is_alive(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       u8 ret = false;
+
+       if ((sta_rx_data_pkts(psta) == sta_last_rx_data_pkts(psta)) &&
+           sta_rx_beacon_pkts(psta) == sta_last_rx_beacon_pkts(psta) &&
+           sta_rx_probersp_pkts(psta) == sta_last_rx_probersp_pkts(psta))
+               ret = false;
+       else
+               ret = true;
+
+       sta_update_last_rx_pkts(psta);
+       return ret;
+}
+
+void linked_status_chk23a(struct rtw_adapter *padapter)
+{
+       u32     i;
+       struct sta_info         *psta;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct sta_priv         *pstapriv = &padapter->stapriv;
+
+       if (padapter->bRxRSSIDisplay)
+                linked23a_rx_sig_stren_disp(padapter);
+
+       rtw_hal_sreset_linked_status_check23a(padapter);
+
+       if (is_client_associated_to_ap23a(padapter))
+       {
+               /* linked infrastructure client mode */
+
+               int tx_chk = _SUCCESS, rx_chk = _SUCCESS;
+               int rx_chk_limit;
+
+               rx_chk_limit = 4;
+
+               if ((psta = rtw_get_stainfo23a(pstapriv, pmlmeinfo->network.MacAddress)) != NULL)
+               {
+                       bool is_p2p_enable = false;
+#ifdef CONFIG_8723AU_P2P
+                       is_p2p_enable = !rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE);
+#endif
+
+                       if (chk_ap_is_alive(padapter, psta) == false)
+                               rx_chk = _FAIL;
+
+                       if (pxmitpriv->last_tx_pkts == pxmitpriv->tx_pkts)
+                               tx_chk = _FAIL;
+
+                       if (pmlmeext->active_keep_alive_check && (rx_chk == _FAIL || tx_chk == _FAIL)) {
+                               u8 backup_oper_channel = 0;
+
+                               /* switch to correct channel of current network  before issue keep-alive frames */
+                               if (rtw_get_oper_ch23a(padapter) != pmlmeext->cur_channel) {
+                                       backup_oper_channel = rtw_get_oper_ch23a(padapter);
+                                       SelectChannel23a(padapter, pmlmeext->cur_channel);
+                               }
+
+                               if (rx_chk != _SUCCESS)
+                                       issue_probereq23a_ex23a(padapter, &pmlmeinfo->network.Ssid, psta->hwaddr, 3, 1);
+
+                               if ((tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf) || rx_chk != _SUCCESS) {
+                                       tx_chk = issue_nulldata23a(padapter, psta->hwaddr, 0, 3, 1);
+                                       /* if tx acked and p2p disabled, set rx_chk _SUCCESS to reset retry count */
+                                       if (tx_chk == _SUCCESS && !is_p2p_enable)
+                                               rx_chk = _SUCCESS;
+                               }
+
+                               /* back to the original operation channel */
+                               if (backup_oper_channel>0)
+                                       SelectChannel23a(padapter, backup_oper_channel);
+
+                       } else {
+                               if (rx_chk != _SUCCESS) {
+                                       if (pmlmeext->retry == 0) {
+                                               issue_probereq23a(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+                                               issue_probereq23a(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+                                               issue_probereq23a(padapter, &pmlmeinfo->network.Ssid, pmlmeinfo->network.MacAddress);
+                                       }
+                               }
+
+                               if (tx_chk != _SUCCESS && pmlmeinfo->link_count++ == 0xf)
+                                       tx_chk = issue_nulldata23a(padapter, NULL, 0, 1, 0);
+                       }
+
+                       if (rx_chk == _FAIL) {
+                               pmlmeext->retry++;
+                               if (pmlmeext->retry > rx_chk_limit) {
+                                       DBG_8723A_LEVEL(_drv_always_, FUNC_ADPT_FMT" disconnect or roaming\n",
+                                               FUNC_ADPT_ARG(padapter));
+                                       receive_disconnect23a(padapter, pmlmeinfo->network.MacAddress,
+                                               WLAN_REASON_EXPIRATION_CHK);
+                                       return;
+                               }
+                       } else {
+                               pmlmeext->retry = 0;
+                       }
+
+                       if (tx_chk == _FAIL) {
+                               pmlmeinfo->link_count &= 0xf;
+                       } else {
+                               pxmitpriv->last_tx_pkts = pxmitpriv->tx_pkts;
+                               pmlmeinfo->link_count = 0;
+                       }
+
+               } /* end of if ((psta = rtw_get_stainfo23a(pstapriv, passoc_res->network.MacAddress)) != NULL) */
+       }
+       else if (is_client_associated_to_ibss23a(padapter))
+       {
+               /* linked IBSS mode */
+               /* for each assoc list entry to check the rx pkt counter */
+               for (i = IBSS_START_MAC_ID; i < NUM_STA; i++)
+               {
+                       if (pmlmeinfo->FW_sta_info[i].status == 1)
+                       {
+                               psta = pmlmeinfo->FW_sta_info[i].psta;
+
+                               if (NULL == psta) continue;
+
+                               if (pmlmeinfo->FW_sta_info[i].rx_pkt == sta_rx_pkts(psta))
+                               {
+
+                                       if (pmlmeinfo->FW_sta_info[i].retry<3)
+                                       {
+                                               pmlmeinfo->FW_sta_info[i].retry++;
+                                       }
+                                       else
+                                       {
+                                               pmlmeinfo->FW_sta_info[i].retry = 0;
+                                               pmlmeinfo->FW_sta_info[i].status = 0;
+                                               report_del_sta_event23a(padapter, psta->hwaddr,
+                                                       65535/*  indicate disconnect caused by no rx */
+                                               );
+                                       }
+                               }
+                               else
+                               {
+                                       pmlmeinfo->FW_sta_info[i].retry = 0;
+                                       pmlmeinfo->FW_sta_info[i].rx_pkt = (u32)sta_rx_pkts(psta);
+                               }
+                       }
+               }
+
+               /* set_link_timer(pmlmeext, DISCONNECT_TO); */
+
+       }
+}
+
+static void survey_timer_hdl(unsigned long data)
+{
+       struct rtw_adapter *padapter = (struct rtw_adapter *)data;
+       struct cmd_obj *ph2c;
+       struct sitesurvey_parm *psurveyPara;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif
+
+       /* issue rtw_sitesurvey_cmd23a */
+       if (pmlmeext->sitesurvey_res.state > SCAN_START) {
+               if (pmlmeext->sitesurvey_res.state ==  SCAN_PROCESS)
+                       pmlmeext->sitesurvey_res.channel_idx++;
+
+               if (pmlmeext->scan_abort == true)
+               {
+#ifdef CONFIG_8723AU_P2P
+                       if (!rtw_p2p_chk_state(&padapter->wdinfo, P2P_STATE_NONE))
+                       {
+                               rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_MAX);
+                               pmlmeext->sitesurvey_res.channel_idx = 3;
+                               DBG_8723A("%s idx:%d, cnt:%u\n", __func__,
+                                         pmlmeext->sitesurvey_res.channel_idx,
+                                         pwdinfo->find_phase_state_exchange_cnt);
+                       } else
+                       #endif
+                       {
+                               pmlmeext->sitesurvey_res.channel_idx = pmlmeext->sitesurvey_res.ch_num;
+                               DBG_8723A("%s idx:%d\n", __func__,
+                                         pmlmeext->sitesurvey_res.channel_idx);
+                       }
+
+                       pmlmeext->scan_abort = false;/* reset */
+               }
+
+               ph2c = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj),
+                       GFP_ATOMIC);
+               if (!ph2c)
+                       goto exit_survey_timer_hdl;
+
+               psurveyPara = (struct sitesurvey_parm*)
+                       kzalloc(sizeof(struct sitesurvey_parm), GFP_ATOMIC);
+               if (!psurveyPara) {
+                       kfree(ph2c);
+                       goto exit_survey_timer_hdl;
+               }
+
+               init_h2fwcmd_w_parm_no_rsp(ph2c, psurveyPara, GEN_CMD_CODE(_SiteSurvey));
+               rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+       }
+
+exit_survey_timer_hdl:
+       return;
+}
+
+static void link_timer_hdl(unsigned long data)
+{
+       struct rtw_adapter *padapter = (struct rtw_adapter *)data;
+       /* static unsigned int          rx_pkt = 0; */
+       /* static u64                           tx_cnt = 0; */
+       /* struct xmit_priv *pxmitpriv = &padapter->xmitpriv; */
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       /* struct sta_priv              *pstapriv = &padapter->stapriv; */
+
+       if (pmlmeinfo->state & WIFI_FW_AUTH_NULL)
+       {
+               DBG_8723A("link_timer_hdl:no beacon while connecting\n");
+               pmlmeinfo->state = WIFI_FW_NULL_STATE;
+               report_join_res23a(padapter, -3);
+       }
+       else if (pmlmeinfo->state & WIFI_FW_AUTH_STATE)
+       {
+               /* re-auth timer */
+               if (++pmlmeinfo->reauth_count > REAUTH_LIMIT)
+               {
+                       /* if (pmlmeinfo->auth_algo != dot11AuthAlgrthm_Auto) */
+                       /*  */
+                               pmlmeinfo->state = 0;
+                               report_join_res23a(padapter, -1);
+                               return;
+                       /*  */
+                       /* else */
+                       /*  */
+                       /*      pmlmeinfo->auth_algo = dot11AuthAlgrthm_Shared; */
+                       /*      pmlmeinfo->reauth_count = 0; */
+                       /*  */
+               }
+
+               DBG_8723A("link_timer_hdl: auth timeout and try again\n");
+               pmlmeinfo->auth_seq = 1;
+               issue_auth23a(padapter, NULL, 0);
+               set_link_timer(pmlmeext, REAUTH_TO);
+       }
+       else if (pmlmeinfo->state & WIFI_FW_ASSOC_STATE)
+       {
+               /* re-assoc timer */
+               if (++pmlmeinfo->reassoc_count > REASSOC_LIMIT)
+               {
+                       pmlmeinfo->state = WIFI_FW_NULL_STATE;
+                       report_join_res23a(padapter, -2);
+                       return;
+               }
+
+               DBG_8723A("link_timer_hdl: assoc timeout and try again\n");
+               issue_assocreq23a(padapter);
+               set_link_timer(pmlmeext, REASSOC_TO);
+       }
+
+       return;
+}
+
+static void addba_timer_hdl(unsigned long data)
+{
+       struct sta_info *psta = (struct sta_info *)data;
+       struct ht_priv  *phtpriv;
+
+       if (!psta)
+               return;
+
+       phtpriv = &psta->htpriv;
+
+       if ((phtpriv->ht_option == true) && (phtpriv->ampdu_enable == true))
+       {
+               if (phtpriv->candidate_tid_bitmap)
+                       phtpriv->candidate_tid_bitmap = 0x0;
+
+       }
+}
+
+void init_addba_retry_timer23a(struct sta_info *psta)
+{
+       setup_timer(&psta->addba_retry_timer, addba_timer_hdl,
+                   (unsigned long)psta);
+}
+
+void init_mlme_ext_timer23a(struct rtw_adapter *padapter)
+{
+       struct  mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       setup_timer(&pmlmeext->survey_timer, survey_timer_hdl,
+                   (unsigned long)padapter);
+
+       setup_timer(&pmlmeext->link_timer, link_timer_hdl,
+                   (unsigned long)padapter);
+}
+
+u8 NULL_hdl23a(struct rtw_adapter *padapter, u8 *pbuf)
+{
+       return H2C_SUCCESS;
+}
+
+u8 setopmode_hdl23a(struct rtw_adapter *padapter, u8 *pbuf)
+{
+       u8      type;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct setopmode_parm *psetop = (struct setopmode_parm *)pbuf;
+
+       if (psetop->mode == Ndis802_11APMode)
+       {
+               pmlmeinfo->state = WIFI_FW_AP_STATE;
+               type = _HW_STATE_AP_;
+       }
+       else if (psetop->mode == Ndis802_11Infrastructure)
+       {
+               pmlmeinfo->state &= ~(BIT(0)|BIT(1));/*  clear state */
+               pmlmeinfo->state |= WIFI_FW_STATION_STATE;/* set to     STATION_STATE */
+               type = _HW_STATE_STATION_;
+       }
+       else if (psetop->mode == Ndis802_11IBSS)
+       {
+               type = _HW_STATE_ADHOC_;
+       }
+       else
+       {
+               type = _HW_STATE_NOLINK_;
+       }
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_SET_OPMODE, (u8 *)(&type));
+       /* Set_NETYPE0_MSR(padapter, type); */
+
+       return H2C_SUCCESS;
+}
+
+u8 createbss_hdl23a(struct rtw_adapter *padapter, u8 *pbuf)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
+       struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf;
+       /* u32  initialgain; */
+
+       if (pparm->InfrastructureMode == Ndis802_11APMode) {
+#ifdef CONFIG_8723AU_AP_MODE
+
+               if (pmlmeinfo->state == WIFI_FW_AP_STATE)
+               {
+                       /* todo: */
+                       return H2C_SUCCESS;
+               }
+#endif
+       }
+
+       /* below is for ad-hoc master */
+       if (pparm->InfrastructureMode == Ndis802_11IBSS) {
+               rtw_joinbss_reset23a(padapter);
+
+               pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+               pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+               pmlmeinfo->ERP_enable = 0;
+               pmlmeinfo->WMM_enable = 0;
+               pmlmeinfo->HT_enable = 0;
+               pmlmeinfo->HT_caps_enable = 0;
+               pmlmeinfo->HT_info_enable = 0;
+               pmlmeinfo->agg_enable_bitmap = 0;
+               pmlmeinfo->candidate_tid_bitmap = 0;
+
+               /* disable dynamic functions, such as high power, DIG */
+               Save_DM_Func_Flag23a(padapter);
+               Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false);
+
+               /* config the initial gain under linking, need to write the BB registers */
+               /* initialgain = 0x1E; */
+               /* rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN, (u8 *)(&initialgain)); */
+
+               /* cancel link timer */
+               del_timer_sync(&pmlmeext->link_timer);
+
+               /* clear CAM */
+               flush_all_cam_entry23a(padapter);
+
+               if (pparm->IELength > MAX_IE_SZ)/* Check pbuf->IELength */
+                       return H2C_PARAMETERS_ERROR;
+
+               memcpy(pnetwork, pparm, sizeof(struct wlan_bssid_ex));
+
+               start_create_ibss23a(padapter);
+       }
+
+       return H2C_SUCCESS;
+}
+
+u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf)
+{
+       u8      join_type;
+       struct ndis_802_11_var_ies *    pIE;
+       struct registry_priv    *pregpriv = &padapter->registrypriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
+       struct wlan_bssid_ex *pparm = (struct wlan_bssid_ex *)pbuf;
+       struct HT_info_element *pht_info;
+       u32 i;
+        /* u32 initialgain; */
+       /* u32  acparm; */
+
+       /* check already connecting to AP or not */
+       if (pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS)
+       {
+               if (pmlmeinfo->state & WIFI_FW_STATION_STATE)
+                       issue_deauth23a_ex23a(padapter, pnetwork->MacAddress,
+                                       WLAN_REASON_DEAUTH_LEAVING, 5, 100);
+
+               pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+               /* clear CAM */
+               flush_all_cam_entry23a(padapter);
+
+               del_timer_sync(&pmlmeext->link_timer);
+
+               /* set MSR to nolink -> infra. mode */
+               /* Set_MSR23a(padapter, _HW_STATE_NOLINK_); */
+               Set_MSR23a(padapter, _HW_STATE_STATION_);
+
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_DISCONNECT, NULL);
+       }
+
+       rtw_joinbss_reset23a(padapter);
+
+       pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+       pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+       pmlmeinfo->ERP_enable = 0;
+       pmlmeinfo->WMM_enable = 0;
+       pmlmeinfo->HT_enable = 0;
+       pmlmeinfo->HT_caps_enable = 0;
+       pmlmeinfo->HT_info_enable = 0;
+       pmlmeinfo->agg_enable_bitmap = 0;
+       pmlmeinfo->candidate_tid_bitmap = 0;
+       pmlmeinfo->bwmode_updated = false;
+       /* pmlmeinfo->assoc_AP_vendor = HT_IOT_PEER_MAX; */
+
+       if (pparm->IELength > MAX_IE_SZ)/* Check pbuf->IELength */
+               return H2C_PARAMETERS_ERROR;
+
+       memcpy(pnetwork, pbuf, sizeof(struct wlan_bssid_ex));
+
+       /* Check AP vendor to move rtw_joinbss_cmd23a() */
+       /* pmlmeinfo->assoc_AP_vendor = check_assoc_AP23a(pnetwork->IEs,
+          pnetwork->IELength); */
+
+       for (i = sizeof(struct ndis_802_11_fixed_ies); i < pnetwork->IELength;)
+       {
+               pIE = (struct ndis_802_11_var_ies *)(pnetwork->IEs + i);
+
+               switch (pIE->ElementID)
+               {
+               case _VENDOR_SPECIFIC_IE_:/* Get WMM IE. */
+                       if (!memcmp(pIE->data, WMM_OUI23A, 4))
+                               pmlmeinfo->WMM_enable = 1;
+                       break;
+
+               case _HT_CAPABILITY_IE_:        /* Get HT Cap IE. */
+                       pmlmeinfo->HT_caps_enable = 1;
+                       break;
+
+               case _HT_EXTRA_INFO_IE_:        /* Get HT Info IE. */
+                       pmlmeinfo->HT_info_enable = 1;
+
+                       /* spec case only for cisco's ap because cisco's ap
+                        * issue assoc rsp using mcs rate @40MHz or @20MHz */
+                       pht_info = (struct HT_info_element *)(pIE->data);
+
+                       if ((pregpriv->cbw40_enable) &&
+                           (pht_info->infos[0] & BIT(2))) {
+                               /* switch to the 40M Hz mode according to AP */
+                               pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_40;
+                               switch (pht_info->infos[0] & 0x3)
+                               {
+                               case 1:
+                                       pmlmeext->cur_ch_offset =
+                                               HAL_PRIME_CHNL_OFFSET_LOWER;
+                                       break;
+
+                               case 3:
+                                       pmlmeext->cur_ch_offset =
+                                               HAL_PRIME_CHNL_OFFSET_UPPER;
+                                       break;
+
+                               default:
+                                       pmlmeext->cur_ch_offset =
+                                               HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+                                       break;
+                               }
+
+                               DBG_8723A("set ch/bw before connected\n");
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+
+               i += (pIE->Length + 2);
+       }
+       /* disable dynamic functions, such as high power, DIG */
+       /* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); */
+
+       /* config the initial gain under linking, need to write the BB
+          registers */
+       /* initialgain = 0x1E; */
+       /* rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN,
+          (u8 *)(&initialgain)); */
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID,
+                         pmlmeinfo->network.MacAddress);
+       join_type = 0;
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+
+       /* cancel link timer */
+       del_timer_sync(&pmlmeext->link_timer);
+
+       start_clnt_join23a(padapter);
+
+       return H2C_SUCCESS;
+}
+
+u8 disconnect_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       struct disconnect_parm *param = (struct disconnect_parm *)pbuf;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *pnetwork = &pmlmeinfo->network;
+       u8      val8;
+
+       if (is_client_associated_to_ap23a(padapter))
+       {
+               issue_deauth23a_ex23a(padapter, pnetwork->MacAddress, WLAN_REASON_DEAUTH_LEAVING, param->deauth_timeout_ms/100, 100);
+       }
+
+       /* set_opmode_cmd(padapter, infra_client_with_mlme); */
+
+       /* pmlmeinfo->state = WIFI_FW_NULL_STATE; */
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_DISCONNECT, NULL);
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, null_addr);
+
+       /* restore to initial setting. */
+       update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode);
+
+       if (((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) || ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE))
+       {
+               /* Stop BCN */
+               val8 = 0;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_BCN_FUNC, (u8 *)(&val8));
+       }
+
+       /* set MSR to no link state -> infra. mode */
+       Set_MSR23a(padapter, _HW_STATE_STATION_);
+
+       pmlmeinfo->state = WIFI_FW_NULL_STATE;
+
+       /* switch to the 20M Hz mode after disconnect */
+       pmlmeext->cur_bwmode = HT_CHANNEL_WIDTH_20;
+       pmlmeext->cur_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+
+       set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+       flush_all_cam_entry23a(padapter);
+
+       del_timer_sync(&pmlmeext->link_timer);
+
+       rtw_free_uc_swdec_pending_queue23a(padapter);
+
+       return  H2C_SUCCESS;
+}
+
+static int rtw_scan_ch_decision(struct rtw_adapter *padapter, struct rtw_ieee80211_channel *out,
+       u32 out_num, struct rtw_ieee80211_channel *in, u32 in_num)
+{
+       int i, j;
+       int scan_ch_num = 0;
+       int set_idx;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+
+       /* clear out first */
+       memset(out, 0, sizeof(struct rtw_ieee80211_channel)*out_num);
+
+       /* acquire channels from in */
+       j = 0;
+       for (i = 0;i<in_num;i++) {
+               if (0)
+               DBG_8723A(FUNC_ADPT_FMT" "CHAN_FMT"\n", FUNC_ADPT_ARG(padapter), CHAN_ARG(&in[i]));
+               if (in[i].hw_value && !(in[i].flags & IEEE80211_CHAN_DISABLED)
+                       && (set_idx = rtw_ch_set_search_ch23a(pmlmeext->channel_set, in[i].hw_value)) >= 0
+               )
+               {
+                       memcpy(&out[j], &in[i], sizeof(struct rtw_ieee80211_channel));
+
+                       if (pmlmeext->channel_set[set_idx].ScanType == SCAN_PASSIVE)
+                               out[j].flags &= IEEE80211_CHAN_NO_IR;
+
+                       j++;
+               }
+               if (j>= out_num)
+                       break;
+       }
+
+       /* if out is empty, use channel_set as default */
+       if (j == 0) {
+               for (i = 0;i<pmlmeext->max_chan_nums;i++) {
+                       out[i].hw_value = pmlmeext->channel_set[i].ChannelNum;
+
+                       if (pmlmeext->channel_set[i].ScanType == SCAN_PASSIVE)
+                               out[i].flags &= IEEE80211_CHAN_NO_IR;
+
+                       j++;
+               }
+       }
+
+       if (padapter->setband == GHZ_24) {                              /*  2.4G */
+               for (i = 0; i < j ; i++) {
+                       if (out[i].hw_value > 35)
+                               memset(&out[i], 0,
+                                      sizeof(struct rtw_ieee80211_channel));
+                       else
+                               scan_ch_num++;
+               }
+               j = scan_ch_num;
+       } else if  (padapter->setband == GHZ_50) {                      /*  5G */
+               for (i = 0; i < j ; i++) {
+                       if (out[i].hw_value > 35) {
+                               memcpy(&out[scan_ch_num++], &out[i], sizeof(struct rtw_ieee80211_channel));
+                       }
+               }
+               j = scan_ch_num;
+       } else
+               {}
+
+       return j;
+}
+
+u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf)
+{
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct sitesurvey_parm *pparm = (struct sitesurvey_parm *)pbuf;
+       u8 bdelayscan = false;
+       u8 val8;
+       u32 initialgain;
+       u32 i;
+
+       if (pmlmeext->sitesurvey_res.state == SCAN_DISABLE) {
+               /* for first time sitesurvey_cmd */
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_CHECK_TXBUF, NULL);
+
+               pmlmeext->sitesurvey_res.state = SCAN_START;
+               pmlmeext->sitesurvey_res.bss_cnt = 0;
+               pmlmeext->sitesurvey_res.channel_idx = 0;
+
+               for (i = 0; i < RTW_SSID_SCAN_AMOUNT; i++) {
+                       if (pparm->ssid[i].ssid_len) {
+                               memcpy(pmlmeext->sitesurvey_res.ssid[i].ssid,
+                                      pparm->ssid[i].ssid, IW_ESSID_MAX_SIZE);
+                               pmlmeext->sitesurvey_res.ssid[i].ssid_len =
+                                       pparm->ssid[i].ssid_len;
+                       } else {
+                               pmlmeext->sitesurvey_res.ssid[i].ssid_len = 0;
+                       }
+               }
+
+               pmlmeext->sitesurvey_res.ch_num =
+                       rtw_scan_ch_decision(padapter,
+                                            pmlmeext->sitesurvey_res.ch,
+                                            RTW_CHANNEL_SCAN_AMOUNT,
+                                            pparm->ch, pparm->ch_num);
+
+               pmlmeext->sitesurvey_res.scan_mode = pparm->scan_mode;
+
+               /* issue null data if associating to the AP */
+               if (is_client_associated_to_ap23a(padapter)) {
+                       pmlmeext->sitesurvey_res.state = SCAN_TXNULL;
+
+                       /* switch to correct channel of current network
+                          before issue keep-alive frames */
+                       if (rtw_get_oper_ch23a(padapter) != pmlmeext->cur_channel)
+                               SelectChannel23a(padapter, pmlmeext->cur_channel);
+
+                       issue_nulldata23a(padapter, NULL, 1, 3, 500);
+
+                       bdelayscan = true;
+               }
+
+               if (bdelayscan) {
+                       /* delay 50ms to protect nulldata(1). */
+                       set_survey_timer(pmlmeext, 50);
+                       return H2C_SUCCESS;
+               }
+       }
+
+       if ((pmlmeext->sitesurvey_res.state == SCAN_START) ||
+           (pmlmeext->sitesurvey_res.state == SCAN_TXNULL)) {
+               /* disable dynamic functions, such as high power, DIG */
+               Save_DM_Func_Flag23a(padapter);
+               Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false);
+
+               /* config the initial gain under scaning, need to
+                  write the BB registers */
+               if ((wdev_to_priv(padapter->rtw_wdev))->p2p_enabled == true) {
+                       initialgain = 0x30;
+               } else
+                       initialgain = 0x1E;
+
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_INITIAL_GAIN,
+                                 (u8 *)(&initialgain));
+
+               /* set MSR to no link state */
+               Set_MSR23a(padapter, _HW_STATE_NOLINK_);
+
+               val8 = 1; /* under site survey */
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY,
+                                 (u8 *)(&val8));
+
+               pmlmeext->sitesurvey_res.state = SCAN_PROCESS;
+       }
+
+       site_survey23a(padapter);
+
+       return H2C_SUCCESS;
+}
+
+u8 setauth_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       struct setauth_parm             *pparm = (struct setauth_parm *)pbuf;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if (pparm->mode < 4)
+       {
+               pmlmeinfo->auth_algo = pparm->mode;
+       }
+
+       return  H2C_SUCCESS;
+}
+
+u8 setkey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf)
+{
+       unsigned short                          ctrl;
+       struct setkey_parm              *pparm = (struct setkey_parm *)pbuf;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       unsigned char                                   null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+       /* main tx key for wep. */
+       if (pparm->set_tx)
+               pmlmeinfo->key_index = pparm->keyid;
+
+       /* write cam */
+       ctrl = BIT(15) | ((pparm->algorithm) << 2) | pparm->keyid;
+
+       DBG_8723A_LEVEL(_drv_always_, "set group key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) "
+                       "keyid:%d\n", pparm->algorithm, pparm->keyid);
+       write_cam23a(padapter, pparm->keyid, ctrl, null_sta, pparm->key);
+
+       /* allow multicast packets to driver */
+        padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_ON_RCR_AM, null_addr);
+
+       return H2C_SUCCESS;
+}
+
+u8 set_stakey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf)
+{
+       u16 ctrl = 0;
+       u8 cam_id;/* cam_entry */
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct set_stakey_parm  *pparm = (struct set_stakey_parm *)pbuf;
+
+       /* cam_entry: */
+       /* 0~3 for default key */
+
+       /* for concurrent mode (ap+sta): */
+       /* default key is disable, using sw encrypt/decrypt */
+       /* cam_entry = 4  for sta mode (macid = 0) */
+       /* cam_entry(macid+3) = 5 ~ N for ap mode (aid = 1~N, macid = 2 ~N) */
+
+       /* for concurrent mode (sta+sta): */
+       /* default key is disable, using sw encrypt/decrypt */
+       /* cam_entry = 4 mapping to macid = 0 */
+       /* cam_entry = 5 mapping to macid = 2 */
+
+       cam_id = 4;
+
+       DBG_8723A_LEVEL(_drv_always_, "set pairwise key to hw: alg:%d(WEP40-1 WEP104-5 TKIP-2 AES-4) camid:%d\n",
+                       pparm->algorithm, cam_id);
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE)
+       {
+
+               struct sta_info *psta;
+               struct sta_priv *pstapriv = &padapter->stapriv;
+
+               if (pparm->algorithm == _NO_PRIVACY_)   /*  clear cam entry */
+               {
+                       clear_cam_entry23a(padapter, pparm->id);
+                       return H2C_SUCCESS_RSP;
+               }
+
+               psta = rtw_get_stainfo23a(pstapriv, pparm->addr);
+               if (psta)
+               {
+                       ctrl = (BIT(15) | ((pparm->algorithm) << 2));
+
+                       DBG_8723A("r871x_set_stakey_hdl23a(): enc_algorithm =%d\n", pparm->algorithm);
+
+                       if ((psta->mac_id<1) || (psta->mac_id>(NUM_STA-4)))
+                       {
+                               DBG_8723A("r871x_set_stakey_hdl23a():set_stakey failed, mac_id(aid) =%d\n", psta->mac_id);
+                               return H2C_REJECTED;
+                       }
+
+                       cam_id = (psta->mac_id + 3);/* 0~3 for default key, cmd_id = macid + 3, macid = aid+1; */
+
+                       DBG_8723A("Write CAM, mac_addr =%x:%x:%x:%x:%x:%x, cam_entry =%d\n", pparm->addr[0],
+                                               pparm->addr[1], pparm->addr[2], pparm->addr[3], pparm->addr[4],
+                                               pparm->addr[5], cam_id);
+
+                       write_cam23a(padapter, cam_id, ctrl, pparm->addr, pparm->key);
+
+                       return H2C_SUCCESS_RSP;
+
+               }
+               else
+               {
+                       DBG_8723A("r871x_set_stakey_hdl23a(): sta has been free\n");
+                       return H2C_REJECTED;
+               }
+
+       }
+
+       /* below for sta mode */
+
+       if (pparm->algorithm == _NO_PRIVACY_)   /*  clear cam entry */
+       {
+               clear_cam_entry23a(padapter, pparm->id);
+               return H2C_SUCCESS;
+       }
+
+       ctrl = BIT(15) | ((pparm->algorithm) << 2);
+
+       write_cam23a(padapter, cam_id, ctrl, pparm->addr, pparm->key);
+
+       pmlmeinfo->enc_algo = pparm->algorithm;
+
+       return H2C_SUCCESS;
+}
+
+u8 add_ba_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       struct addBaReq_parm    *pparm = (struct addBaReq_parm *)pbuf;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       struct sta_info *psta = rtw_get_stainfo23a(&padapter->stapriv, pparm->addr);
+
+       if (!psta)
+               return  H2C_SUCCESS;
+
+       if (((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) &&
+            (pmlmeinfo->HT_enable)) ||
+           ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) {
+               issue_action_BA23a(padapter, pparm->addr,
+                               WLAN_ACTION_ADDBA_REQ, (u16)pparm->tid);
+               mod_timer(&psta->addba_retry_timer,
+                         jiffies + msecs_to_jiffies(ADDBA_TO));
+       } else {
+               psta->htpriv.candidate_tid_bitmap &= ~CHKBIT(pparm->tid);
+       }
+       return  H2C_SUCCESS;
+}
+
+u8 set_tx_beacon_cmd23a(struct rtw_adapter* padapter)
+{
+       struct cmd_obj  *ph2c;
+       struct Tx_Beacon_param  *ptxBeacon_parm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       u8      res = _SUCCESS;
+       int len_diff = 0;
+
+
+
+       ph2c = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj), GFP_ATOMIC);
+       if (!ph2c) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       ptxBeacon_parm = (struct Tx_Beacon_param *)
+               kzalloc(sizeof(struct Tx_Beacon_param), GFP_ATOMIC);
+       if (!ptxBeacon_parm) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       memcpy(&ptxBeacon_parm->network, &pmlmeinfo->network,
+              sizeof(struct wlan_bssid_ex));
+
+       len_diff = update_hidden_ssid(
+               ptxBeacon_parm->network.IEs+_BEACON_IE_OFFSET_,
+               ptxBeacon_parm->network.IELength-_BEACON_IE_OFFSET_,
+               pmlmeinfo->hidden_ssid_mode);
+       ptxBeacon_parm->network.IELength += len_diff;
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, ptxBeacon_parm, GEN_CMD_CODE(_TX_Beacon));
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+
+exit:
+
+
+
+       return res;
+}
+
+u8 mlme_evt_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       u8 evt_code, evt_seq;
+       u16 evt_sz;
+       uint    *peventbuf;
+       void (*event_callback)(struct rtw_adapter *dev, u8 *pbuf);
+       struct evt_priv *pevt_priv = &padapter->evtpriv;
+
+       peventbuf = (uint*)pbuf;
+       evt_sz = (u16)(*peventbuf&0xffff);
+       evt_seq = (u8)((*peventbuf>>24)&0x7f);
+       evt_code = (u8)((*peventbuf>>16)&0xff);
+
+       /*  checking if event code is valid */
+       if (evt_code >= MAX_C2HEVT) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent Code(%d) mismatch!\n", evt_code));
+               goto _abort_event_;
+       }
+
+       /*  checking if event size match the event parm size */
+       if ((wlanevents[evt_code].parmsize != 0) &&
+           (wlanevents[evt_code].parmsize != evt_sz)) {
+               RT_TRACE(_module_rtl871x_cmd_c_, _drv_err_, ("\nEvent(%d) Parm Size mismatch (%d vs %d)!\n",
+                       evt_code, wlanevents[evt_code].parmsize, evt_sz));
+               goto _abort_event_;
+       }
+
+       atomic_inc(&pevt_priv->event_seq);
+
+       peventbuf += 2;
+
+       if (peventbuf) {
+               event_callback = wlanevents[evt_code].event_callback;
+               event_callback(padapter, (u8*)peventbuf);
+
+               pevt_priv->evt_done_cnt++;
+       }
+
+_abort_event_:
+
+       return H2C_SUCCESS;
+}
+
+u8 h2c_msg_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       if (!pbuf)
+               return H2C_PARAMETERS_ERROR;
+
+       return H2C_SUCCESS;
+}
+
+u8 tx_beacon_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       if (send_beacon23a(padapter) == _FAIL)
+       {
+               DBG_8723A("issue_beacon23a, fail!\n");
+               return H2C_PARAMETERS_ERROR;
+       }
+#ifdef CONFIG_8723AU_AP_MODE
+       else /* tx bc/mc frames after update TIM */
+       {
+               struct sta_info *psta_bmc;
+               struct list_head *plist, *phead, *ptmp;
+               struct xmit_frame *pxmitframe;
+               struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+               struct sta_priv  *pstapriv = &padapter->stapriv;
+
+               /* for BC/MC Frames */
+               psta_bmc = rtw_get_bcmc_stainfo23a(padapter);
+               if (!psta_bmc)
+                       return H2C_SUCCESS;
+
+               if ((pstapriv->tim_bitmap&BIT(0)) && (psta_bmc->sleepq_len>0))
+               {
+                       msleep(10);/*  10ms, ATIM(HIQ) Windows */
+                       /* spin_lock_bh(&psta_bmc->sleep_q.lock); */
+                       spin_lock_bh(&pxmitpriv->lock);
+
+                       phead = get_list_head(&psta_bmc->sleep_q);
+
+                       list_for_each_safe(plist, ptmp, phead) {
+                               pxmitframe = container_of(plist,
+                                                         struct xmit_frame,
+                                                         list);
+
+                               list_del_init(&pxmitframe->list);
+
+                               psta_bmc->sleepq_len--;
+                               if (psta_bmc->sleepq_len>0)
+                                       pxmitframe->attrib.mdata = 1;
+                               else
+                                       pxmitframe->attrib.mdata = 0;
+
+                               pxmitframe->attrib.triggered = 1;
+
+                               pxmitframe->attrib.qsel = 0x11;/* HIQ */
+
+                               rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe);
+                       }
+
+                       /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */
+                       spin_unlock_bh(&pxmitpriv->lock);
+               }
+
+       }
+#endif
+
+       return H2C_SUCCESS;
+}
+
+u8 set_ch_hdl23a(struct rtw_adapter *padapter, u8 *pbuf)
+{
+       struct set_ch_parm *set_ch_parm;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+
+       if (!pbuf)
+               return H2C_PARAMETERS_ERROR;
+
+       set_ch_parm = (struct set_ch_parm *)pbuf;
+
+       DBG_8723A(FUNC_NDEV_FMT" ch:%u, bw:%u, ch_offset:%u\n",
+               FUNC_NDEV_ARG(padapter->pnetdev),
+               set_ch_parm->ch, set_ch_parm->bw, set_ch_parm->ch_offset);
+
+       pmlmeext->cur_channel = set_ch_parm->ch;
+       pmlmeext->cur_ch_offset = set_ch_parm->ch_offset;
+       pmlmeext->cur_bwmode = set_ch_parm->bw;
+
+       set_channel_bwmode23a(padapter, set_ch_parm->ch, set_ch_parm->ch_offset, set_ch_parm->bw);
+
+       return  H2C_SUCCESS;
+}
+
+u8 set_chplan_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       struct SetChannelPlan_param *setChannelPlan_param;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+
+       if (!pbuf)
+               return H2C_PARAMETERS_ERROR;
+
+       setChannelPlan_param = (struct SetChannelPlan_param *)pbuf;
+
+       pmlmeext->max_chan_nums = init_channel_set(padapter, setChannelPlan_param->channel_plan, pmlmeext->channel_set);
+       init_channel_list(padapter, pmlmeext->channel_set, pmlmeext->max_chan_nums, &pmlmeext->channel_list);
+
+       return  H2C_SUCCESS;
+}
+
+u8 led_blink_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       struct LedBlink_param *ledBlink_param;
+
+       if (!pbuf)
+               return H2C_PARAMETERS_ERROR;
+
+       ledBlink_param = (struct LedBlink_param *)pbuf;
+
+       return  H2C_SUCCESS;
+}
+
+u8 set_csa_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       return  H2C_REJECTED;
+}
+
+/*  TDLS_WRCR          : write RCR DATA BIT */
+/*  TDLS_SD_PTI                : issue peer traffic indication */
+/*  TDLS_CS_OFF                : go back to the channel linked with AP, terminating channel switch procedure */
+/*  TDLS_INIT_CH_SEN   : init channel sensing, receive all data and mgnt frame */
+/*  TDLS_DONE_CH_SEN: channel sensing and report candidate channel */
+/*  TDLS_OFF_CH                : first time set channel to off channel */
+/*  TDLS_BASE_CH               : go back tp the channel linked with AP when set base channel as target channel */
+/*  TDLS_P_OFF_CH      : periodically go to off channel */
+/*  TDLS_P_BASE_CH     : periodically go back to base channel */
+/*  TDLS_RS_RCR                : restore RCR */
+/*  TDLS_CKALV_PH1     : check alive timer phase1 */
+/*  TDLS_CKALV_PH2     : check alive timer phase2 */
+/*  TDLS_FREE_STA      : free tdls sta */
+u8 tdls_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf)
+{
+       return H2C_REJECTED;
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_p2p.c b/drivers/staging/rtl8723au/core/rtw_p2p.c
new file mode 100644 (file)
index 0000000..27a6cc7
--- /dev/null
@@ -0,0 +1,4001 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_P2P_C_
+
+#include <drv_types.h>
+#include <rtw_p2p.h>
+#include <wifi.h>
+
+#ifdef CONFIG_8723AU_P2P
+
+static int rtw_p2p_is_channel_list_ok(u8 desired_ch, u8* ch_list, u8 ch_cnt)
+{
+       int found = 0, i = 0;
+
+       for (i = 0; i < ch_cnt; i++)
+       {
+               if (ch_list[ i ] == desired_ch)
+               {
+                       found = 1;
+                       break;
+               }
+       }
+       return found;
+}
+
+static int is_any_client_associated(struct rtw_adapter *padapter)
+{
+       return padapter->stapriv.asoc_list_cnt ? true : false;
+}
+
+static u32 go_add_group_info_attr(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       struct list_head *phead, *plist;
+       u32 len = 0;
+       u16 attr_len = 0;
+       u8 tmplen, *pdata_attr, *pstart, *pcur;
+       struct sta_info *psta;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+
+       DBG_8723A("%s\n", __func__);
+
+       pdata_attr = kzalloc(MAX_P2P_IE_LEN, GFP_ATOMIC);
+
+       pstart = pdata_attr;
+       pcur = pdata_attr;
+
+       spin_lock_bh(&pstapriv->asoc_list_lock);
+       phead = &pstapriv->asoc_list;
+
+       list_for_each(plist, phead) {
+               psta = container_of(plist, struct sta_info, asoc_list);
+
+               if (psta->is_p2p_device)
+               {
+                       tmplen = 0;
+
+                       pcur++;
+
+                       /* P2P device address */
+                       memcpy(pcur, psta->dev_addr, ETH_ALEN);
+                       pcur += ETH_ALEN;
+
+                       /* P2P interface address */
+                       memcpy(pcur, psta->hwaddr, ETH_ALEN);
+                       pcur += ETH_ALEN;
+
+                       *pcur = psta->dev_cap;
+                       pcur++;
+
+                       /* u16*)(pcur) = cpu_to_be16(psta->config_methods); */
+                       put_unaligned_be16(psta->config_methods, pcur);
+                       pcur += 2;
+
+                       memcpy(pcur, psta->primary_dev_type, 8);
+                       pcur += 8;
+
+                       *pcur = psta->num_of_secdev_type;
+                       pcur++;
+
+                       memcpy(pcur, psta->secdev_types_list, psta->num_of_secdev_type*8);
+                       pcur += psta->num_of_secdev_type*8;
+
+                       if (psta->dev_name_len>0)
+                       {
+                               /* u16*)(pcur) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */
+                               put_unaligned_be16(WPS_ATTR_DEVICE_NAME, pcur);
+                               pcur += 2;
+
+                               /* u16*)(pcur) = cpu_to_be16(psta->dev_name_len); */
+                               put_unaligned_be16(psta->dev_name_len, pcur);
+                               pcur += 2;
+
+                               memcpy(pcur, psta->dev_name, psta->dev_name_len);
+                               pcur += psta->dev_name_len;
+                       }
+
+                       tmplen = (u8)(pcur-pstart);
+
+                       *pstart = (tmplen-1);
+
+                       attr_len += tmplen;
+
+                       /* pstart += tmplen; */
+                       pstart = pcur;
+
+               }
+
+       }
+       spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+       if (attr_len>0)
+       {
+               len = rtw_set_p2p_attr_content23a(pbuf, P2P_ATTR_GROUP_INFO, attr_len, pdata_attr);
+       }
+
+       kfree(pdata_attr);
+
+       return len;
+}
+
+static void issue_group_disc_req(struct wifidirect_info *pwdinfo, u8 *da)
+{
+       struct xmit_frame                       *pmgntframe;
+       struct pkt_attrib                       *pattrib;
+       unsigned char                                   *pframe;
+       struct ieee80211_hdr    *pwlanhdr;
+       unsigned short                          *fctrl;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       unsigned char category = WLAN_CATEGORY_VENDOR_SPECIFIC;/* P2P action frame */
+       u32     p2poui = cpu_to_be32(P2POUI);
+       u8      oui_subtype = P2P_GO_DISC_REQUEST;
+       u8      dialogToken = 0;
+
+       DBG_8723A("[%s]\n", __func__);
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+       {
+               return;
+       }
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+       memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
+       memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       /* Build P2P action frame header */
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen);
+
+       /* there is no IE in this P2P action frame */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+}
+
+static void issue_p2p_devdisc_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken)
+{
+       struct xmit_frame                       *pmgntframe;
+       struct pkt_attrib                       *pattrib;
+       unsigned char                                   *pframe;
+       struct ieee80211_hdr    *pwlanhdr;
+       unsigned short                          *fctrl;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       unsigned char category = WLAN_CATEGORY_PUBLIC;
+       u8                      action = P2P_PUB_ACTION_ACTION;
+       u32                     p2poui = cpu_to_be32(P2POUI);
+       u8                      oui_subtype = P2P_DEVDISC_RESP;
+       u8 p2pie[8] = { 0x00 };
+       u32 p2pielen = 0;
+
+       DBG_8723A("[%s]\n", __func__);
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+       {
+               return;
+       }
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+       memcpy(pwlanhdr->addr2, pwdinfo->device_addr, ETH_ALEN);
+       memcpy(pwlanhdr->addr3, pwdinfo->device_addr, ETH_ALEN);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       /* Build P2P public action frame header */
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui,
+                                    &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen);
+
+       /* Build P2P IE */
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[ p2pielen++ ] = 0x50;
+       p2pie[ p2pielen++ ] = 0x6F;
+       p2pie[ p2pielen++ ] = 0x9A;
+       p2pie[ p2pielen++ ] = 0x09;     /*      WFA P2P v1.0 */
+
+       /*  P2P_ATTR_STATUS */
+       p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status);
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie, &pattrib->pktlen);
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+}
+
+static void issue_p2p_provision_resp(struct wifidirect_info *pwdinfo, u8* raddr, u8* frame_body, u16 config_method)
+{
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       unsigned char category = WLAN_CATEGORY_PUBLIC;
+       u8                      action = P2P_PUB_ACTION_ACTION;
+       u8                      dialogToken = frame_body[7];    /*      The Dialog Token of provisioning discovery request frame. */
+       u32                     p2poui = cpu_to_be32(P2POUI);
+       u8                      oui_subtype = P2P_PROVISION_DISC_RESP;
+       u8                      wpsie[ 100 ] = { 0x00 };
+       u8                      wpsielen = 0;
+#ifdef CONFIG_8723AU_P2P
+       u32                                     wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+
+       struct xmit_frame                       *pmgntframe;
+       struct pkt_attrib                       *pattrib;
+       unsigned char                                   *pframe;
+       struct ieee80211_hdr    *pwlanhdr;
+       unsigned short                          *fctrl;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+               return;
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
+       memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
+       memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv), ETH_ALEN);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui,
+                                    &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen);
+
+       wpsielen = 0;
+       /*      WPS OUI */
+       /* u32*) (wpsie) = cpu_to_be32(WPSOUI); */
+       put_unaligned_be32(WPSOUI, wpsie);
+       wpsielen += 4;
+
+       /*      Config Method */
+       /*      Type: */
+       /* u16*) (wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD); */
+       put_unaligned_be16(WPS_ATTR_CONF_METHOD, wpsie + wpsielen);
+       wpsielen += 2;
+
+       /*      Length: */
+       /* u16*) (wpsie + wpsielen) = cpu_to_be16(0x0002); */
+       put_unaligned_be16(0x0002, wpsie + wpsielen);
+       wpsielen += 2;
+
+       /*      Value: */
+       /* u16*) (wpsie + wpsielen) = cpu_to_be16(config_method); */
+       put_unaligned_be16(config_method, wpsie + wpsielen);
+       wpsielen += 2;
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen, (unsigned char *) wpsie, &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_P2P
+       wfdielen = build_provdisc_resp_wfd_ie(pwdinfo, pframe);
+       pframe += wfdielen;
+       pattrib->pktlen += wfdielen;
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+
+       return;
+}
+
+static void issue_p2p_presence_resp(struct wifidirect_info *pwdinfo, u8 *da, u8 status, u8 dialogToken)
+{
+       struct xmit_frame                       *pmgntframe;
+       struct pkt_attrib                       *pattrib;
+       unsigned char                                   *pframe;
+       struct ieee80211_hdr    *pwlanhdr;
+       unsigned short                          *fctrl;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       unsigned char category = WLAN_CATEGORY_VENDOR_SPECIFIC;/* P2P action frame */
+       u32     p2poui = cpu_to_be32(P2POUI);
+       u8      oui_subtype = P2P_PRESENCE_RESPONSE;
+       u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 };
+       u8 noa_attr_content[32] = { 0x00 };
+       u32 p2pielen = 0;
+
+       DBG_8723A("[%s]\n", __func__);
+
+       if ((pmgntframe = alloc_mgtxmitframe23a(pxmitpriv)) == NULL)
+       {
+               return;
+       }
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *fctrl = 0;
+
+       memcpy(pwlanhdr->addr1, da, ETH_ALEN);
+       memcpy(pwlanhdr->addr2, pwdinfo->interface_addr, ETH_ALEN);
+       memcpy(pwlanhdr->addr3, pwdinfo->interface_addr, ETH_ALEN);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       /* Build P2P action frame header */
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *) &p2poui,
+                                    &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen);
+
+       /* Add P2P IE header */
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[ p2pielen++ ] = 0x50;
+       p2pie[ p2pielen++ ] = 0x6F;
+       p2pie[ p2pielen++ ] = 0x9A;
+       p2pie[ p2pielen++ ] = 0x09;     /*      WFA P2P v1.0 */
+
+       /* Add Status attribute in P2P IE */
+       p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status);
+
+       /* Add NoA attribute in P2P IE */
+       noa_attr_content[0] = 0x1;/* index */
+       noa_attr_content[1] = 0x0;/* CTWindow and OppPS Parameters */
+
+       /* todo: Notice of Absence Descriptor(s) */
+
+       p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_NOA, 2, noa_attr_content);
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen, p2pie,
+                              &pattrib->pktlen);
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       dump_mgntframe23a(padapter, pmgntframe);
+}
+
+u32 build_beacon_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 };
+       u16 capability = 0;
+       u32 len = 0, p2pielen = 0;
+
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[ p2pielen++ ] = 0x50;
+       p2pie[ p2pielen++ ] = 0x6F;
+       p2pie[ p2pielen++ ] = 0x9A;
+       p2pie[ p2pielen++ ] = 0x09;     /*      WFA P2P v1.0 */
+
+       /*      According to the P2P Specification, the beacon frame should contain 3 P2P attributes */
+       /*      1. P2P Capability */
+       /*      2. P2P Device ID */
+       /*      3. Notice of Absence (NOA) */
+
+       /*      P2P Capability ATTR */
+       /*      Type: */
+       /*      Length: */
+       /*      Value: */
+       /*      Device Capability Bitmap, 1 byte */
+       /*      Be able to participate in additional P2P Groups and */
+       /*      support the P2P Invitation Procedure */
+       /*      Group Capability Bitmap, 1 byte */
+       capability = P2P_DEVCAP_INVITATION_PROC|P2P_DEVCAP_CLIENT_DISCOVERABILITY;
+       capability |=  ((P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS) << 8);
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+               capability |= (P2P_GRPCAP_GROUP_FORMATION<<8);
+
+       capability = cpu_to_le16(capability);
+
+       p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_CAPABILITY, 2, (u8*)&capability);
+
+       /*  P2P Device ID ATTR */
+       p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_DEVICE_ID, ETH_ALEN, pwdinfo->device_addr);
+
+       /*  Notice of Absence ATTR */
+       /*      Type: */
+       /*      Length: */
+       /*      Value: */
+
+       /* go_add_noa_attr(pwdinfo); */
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len);
+
+       return len;
+}
+
+#ifdef CONFIG_8723AU_P2P
+u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110812 */
+       /*      According to the WFD Specification, the beacon frame should contain 4 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID */
+       /*      3. Coupled Sink Information */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+
+       if (P2P_ROLE_GO == pwdinfo->role)
+       {
+               if (is_any_client_associated(pwdinfo->padapter))
+               {
+                       /*      WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) */
+                       put_unaligned_be16(pwfd_info->wfd_device_type |
+                                          WFD_DEVINFO_WSD, wfdie + wfdielen);
+               }
+               else
+               {
+                       /*      WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+                       put_unaligned_be16(pwfd_info->wfd_device_type |
+                                          WFD_DEVINFO_SESSION_AVAIL |
+                                          WFD_DEVINFO_WSD, wfdie + wfdielen);
+               }
+
+       }
+       else
+       {
+               /*      WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+               put_unaligned_be16(pwfd_info->wfd_device_type |
+                                  WFD_DEVINFO_SESSION_AVAIL |
+                                  WFD_DEVINFO_WSD, wfdie + wfdielen);
+       }
+
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110812 */
+       /*      According to the WFD Specification, the probe request frame should contain 4 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID */
+       /*      3. Coupled Sink Information */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+
+       if (1 == pwdinfo->wfd_tdls_enable)
+       {
+               /*      WFD primary sink + available for WFD session + WiFi TDLS mode + WSC (WFD Service Discovery) */
+               put_unaligned_be16(pwfd_info->wfd_device_type |
+                                  WFD_DEVINFO_SESSION_AVAIL |
+                                  WFD_DEVINFO_WSD |
+                                  WFD_DEVINFO_PC_TDLS, wfdie + wfdielen);
+       }
+       else
+       {
+               /*      WFD primary sink + available for WFD session + WiFi Direct mode + WSC (WFD Service Discovery) */
+               put_unaligned_be16(pwfd_info->wfd_device_type |
+                                  WFD_DEVINFO_SESSION_AVAIL |
+                                  WFD_DEVINFO_WSD, wfdie + wfdielen);
+       }
+
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 tunneled)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110812 */
+       /*      According to the WFD Specification, the probe response frame should contain 4 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID */
+       /*      3. Coupled Sink Information */
+       /*      4. WFD Session Information */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + available for WFD session + WiFi Direct mode */
+
+       if (true == pwdinfo->session_available)
+       {
+               if (P2P_ROLE_GO == pwdinfo->role)
+               {
+                       if (is_any_client_associated(pwdinfo->padapter))
+                       {
+                               if (pwdinfo->wfd_tdls_enable)
+                               {
+                                       /*      TDLS mode + WSD (WFD Service Discovery) */
+                                       put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen);
+                               }
+                               else
+                               {
+                                       /*      WiFi Direct mode + WSD (WFD Service Discovery) */
+                                       put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen);
+                               }
+                       }
+                       else
+                       {
+                               if (pwdinfo->wfd_tdls_enable)
+                               {
+                                       /*      available for WFD session + TDLS mode + WSD (WFD Service Discovery) */
+                                       put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_PC_TDLS | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen);
+                               }
+                               else
+                               {
+                                       /*      available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+                                       put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD | WFD_DEVINFO_HDCP_SUPPORT, wfdie + wfdielen);
+                               }
+                       }
+               }
+               else
+               {
+                       if (pwdinfo->wfd_tdls_enable)
+                       {
+                               /*      available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+                               put_unaligned_be16(pwfd_info->wfd_device_type |
+                                                  WFD_DEVINFO_SESSION_AVAIL |
+                                                  WFD_DEVINFO_WSD |
+                                                  WFD_DEVINFO_PC_TDLS |
+                                                  WFD_DEVINFO_HDCP_SUPPORT,
+                                                  wfdie + wfdielen);
+                       }
+                       else
+                       {
+
+                               /*      available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+                               put_unaligned_be16(pwfd_info->wfd_device_type |
+                                                  WFD_DEVINFO_SESSION_AVAIL |
+                                                  WFD_DEVINFO_WSD |
+                                                  WFD_DEVINFO_HDCP_SUPPORT,
+                                                  wfdie + wfdielen);
+                       }
+               }
+       }
+       else
+       {
+               if (pwdinfo->wfd_tdls_enable)
+               {
+                       put_unaligned_be16(pwfd_info->wfd_device_type |
+                                          WFD_DEVINFO_WSD |
+                                          WFD_DEVINFO_PC_TDLS |
+                                          WFD_DEVINFO_HDCP_SUPPORT,
+                                          wfdie + wfdielen);
+               }
+               else
+               {
+                       put_unaligned_be16(pwfd_info->wfd_device_type |
+                                          WFD_DEVINFO_WSD |
+                                          WFD_DEVINFO_HDCP_SUPPORT,
+                                          wfdie + wfdielen);
+               }
+
+       }
+
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+       {
+               /*      WFD Session Information ATTR */
+               /*      Type: */
+               wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO;
+
+               /*      Length: */
+               /*      Note: In the WFD specification, the size of length field is 2. */
+               put_unaligned_be16(0x0000, wfdie + wfdielen);
+               wfdielen += 2;
+
+               /*      Todo: to add the list of WFD device info descriptor in WFD group. */
+
+       }
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter                                      *padapter = NULL;
+       struct mlme_priv                        *pmlmepriv = NULL;
+       struct wifi_display_info                *pwfd_info = NULL;
+
+       /*      WFD OUI */
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE))
+       {
+               return 0;
+       }
+
+       padapter = pwdinfo->padapter;
+       pmlmepriv = &padapter->mlmepriv;
+       pwfd_info = padapter->wdinfo.wfd_info;
+
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110812 */
+       /*      According to the WFD Specification, the probe request frame should contain 4 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID */
+       /*      3. Coupled Sink Information */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+       put_unaligned_be16(pwfd_info->wfd_device_type |
+                          WFD_DEVINFO_SESSION_AVAIL |
+                          WFD_DEVINFO_WSD, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110812 */
+       /*      According to the WFD Specification, the probe request frame should contain 4 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID */
+       /*      3. Coupled Sink Information */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+       put_unaligned_be16(pwfd_info->wfd_device_type |
+                          WFD_DEVINFO_SESSION_AVAIL |
+                          WFD_DEVINFO_WSD, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110825 */
+       /*      According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID (Optional) */
+       /*      3. Local IP Adress (Optional) */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */
+       put_unaligned_be16(pwfd_info->wfd_device_type |
+                          WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL,
+                          wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110825 */
+       /*      According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID (Optional) */
+       /*      3. Local IP Adress (Optional) */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */
+       put_unaligned_be16(pwfd_info->wfd_device_type |
+                          WFD_DEVINFO_WSD | WFD_DEVINFO_SESSION_AVAIL,
+                          wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110825 */
+       /*      According to the WFD Specification, the negotiation request frame should contain 3 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID (Optional) */
+       /*      3. Local IP Adress (Optional) */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + WiFi Direct mode + WSD (WFD Service Discovery) + WFD Session Available */
+       put_unaligned_be16(pwfd_info->wfd_device_type | WFD_DEVINFO_WSD |
+                          WFD_DEVINFO_SESSION_AVAIL, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110825 */
+       /*      According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID (Optional) */
+       /*      3. Local IP Adress (Optional) */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+       put_unaligned_be16(pwfd_info->wfd_device_type |
+                          WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD,
+                          wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       if (P2P_ROLE_GO == pwdinfo->role)
+       {
+               /*      WFD Session Information ATTR */
+               /*      Type: */
+               wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO;
+
+               /*      Length: */
+               /*      Note: In the WFD specification, the size of length field is 2. */
+               put_unaligned_be16(0x0000, wfdie + wfdielen);
+               wfdielen += 2;
+
+               /*      Todo: to add the list of WFD device info descriptor in WFD group. */
+
+       }
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110825 */
+       /*      According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID (Optional) */
+       /*      3. Local IP Adress (Optional) */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+       put_unaligned_be16(pwfd_info->wfd_device_type |
+                          WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD,
+                          wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       if (P2P_ROLE_GO == pwdinfo->role)
+       {
+               /*      WFD Session Information ATTR */
+               /*      Type: */
+               wfdie[ wfdielen++ ] = WFD_ATTR_SESSION_INFO;
+
+               /*      Length: */
+               /*      Note: In the WFD specification, the size of length field is 2. */
+               put_unaligned_be16(0x0000, wfdie + wfdielen);
+               wfdielen += 2;
+
+               /*      Todo: to add the list of WFD device info descriptor in WFD group. */
+
+       }
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110825 */
+       /*      According to the WFD Specification, the provision discovery request frame should contain 3 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID (Optional) */
+       /*      3. Local IP Adress (Optional) */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+       put_unaligned_be16(pwfd_info->wfd_device_type |
+                          WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD,
+                          wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 wfdie[ MAX_WFD_IE_LEN] = { 0x00 };
+       u32 len = 0, wfdielen = 0;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct wifi_display_info*       pwfd_info = padapter->wdinfo.wfd_info;
+
+       /*      WFD OUI */
+       wfdielen = 0;
+       wfdie[ wfdielen++ ] = 0x50;
+       wfdie[ wfdielen++ ] = 0x6F;
+       wfdie[ wfdielen++ ] = 0x9A;
+       wfdie[ wfdielen++ ] = 0x0A;     /*      WFA WFD v1.0 */
+
+       /*      Commented by Albert 20110825 */
+       /*      According to the WFD Specification, the provision discovery response frame should contain 3 WFD attributes */
+       /*      1. WFD Device Information */
+       /*      2. Associated BSSID (Optional) */
+       /*      3. Local IP Adress (Optional) */
+
+       /*      WFD Device Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value1: */
+       /*      WFD device information */
+       /*      WFD primary sink + available for WFD session + WiFi Direct mode + WSD (WFD Service Discovery) */
+       put_unaligned_be16(pwfd_info->wfd_device_type |
+                          WFD_DEVINFO_SESSION_AVAIL | WFD_DEVINFO_WSD,
+                          wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value2: */
+       /*      Session Management Control Port */
+       /*      Default TCP port for RTSP messages is 554 */
+       put_unaligned_be16(pwfd_info->rtsp_ctrlport, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value3: */
+       /*      WFD Device Maximum Throughput */
+       /*      300Mbps is the maximum throughput */
+       put_unaligned_be16(300, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Associated BSSID ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_ASSOC_BSSID;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0006, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Associated BSSID */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               memcpy(wfdie + wfdielen, &pmlmepriv->assoc_bssid[ 0 ], ETH_ALEN);
+       }
+       else
+       {
+               memset(wfdie + wfdielen, 0x00, ETH_ALEN);
+       }
+
+       wfdielen += ETH_ALEN;
+
+       /*      Coupled Sink Information ATTR */
+       /*      Type: */
+       wfdie[ wfdielen++ ] = WFD_ATTR_COUPLED_SINK_INFO;
+
+       /*      Length: */
+       /*      Note: In the WFD specification, the size of length field is 2. */
+       put_unaligned_be16(0x0007, wfdie + wfdielen);
+       wfdielen += 2;
+
+       /*      Value: */
+       /*      Coupled Sink Status bitmap */
+       /*      Not coupled/available for Coupling */
+       wfdie[ wfdielen++ ] = 0;
+       /*   MAC Addr. */
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+       wfdie[ wfdielen++ ] = 0;
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, wfdielen, (unsigned char *) wfdie, &len);
+
+       return len;
+}
+
+#endif /* CONFIG_8723AU_P2P */
+
+u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 };
+       u32 len = 0, p2pielen = 0;
+
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[ p2pielen++ ] = 0x50;
+       p2pie[ p2pielen++ ] = 0x6F;
+       p2pie[ p2pielen++ ] = 0x9A;
+       p2pie[ p2pielen++ ] = 0x09;     /*      WFA P2P v1.0 */
+
+       /*      Commented by Albert 20100907 */
+       /*      According to the P2P Specification, the probe response frame should contain 5 P2P attributes */
+       /*      1. P2P Capability */
+       /*      2. Extended Listen Timing */
+       /*      3. Notice of Absence (NOA)      (Only GO needs this) */
+       /*      4. Device Info */
+       /*      5. Group Info   (Only GO need this) */
+
+       /*      P2P Capability ATTR */
+       /*      Type: */
+       p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY;
+
+       /*      Length: */
+       /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */
+       put_unaligned_le16(0x0002, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Device Capability Bitmap, 1 byte */
+       p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT;
+
+       /*      Group Capability Bitmap, 1 byte */
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+       {
+               p2pie[ p2pielen ] = (P2P_GRPCAP_GO | P2P_GRPCAP_INTRABSS);
+
+               if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_PROVISIONING_ING))
+                       p2pie[ p2pielen ] |= P2P_GRPCAP_GROUP_FORMATION;
+
+               p2pielen++;
+       }
+       else if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE))
+       {
+               /*      Group Capability Bitmap, 1 byte */
+               if (pwdinfo->persistent_supported)
+                       p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+               else
+                       p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT;
+       }
+
+       /*      Extended Listen Timing ATTR */
+       /*      Type: */
+       p2pie[ p2pielen++ ] = P2P_ATTR_EX_LISTEN_TIMING;
+
+       /*      Length: */
+       /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0004); */
+       put_unaligned_le16(0x0004, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Availability Period */
+       /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */
+       put_unaligned_le16(0xFFFF, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Availability Interval */
+       /* u16*) (p2pie + p2pielen) = cpu_to_le16(0xFFFF); */
+       put_unaligned_le16(0xFFFF, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*  Notice of Absence ATTR */
+       /*      Type: */
+       /*      Length: */
+       /*      Value: */
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+       {
+               /* go_add_noa_attr(pwdinfo); */
+       }
+
+       /*      Device Info ATTR */
+       /*      Type: */
+       p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+       /*      + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+       /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */
+       put_unaligned_le16(21 + pwdinfo->device_name_len, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      P2P Device Address */
+       memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
+       p2pielen += ETH_ALEN;
+
+       /*      Config Method */
+       /*      This field should be big endian. Noted by P2P specification. */
+       /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->supported_wps_cm); */
+       put_unaligned_be16(pwdinfo->supported_wps_cm, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Primary Device Type */
+       /*      Category ID */
+       /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */
+       put_unaligned_be16(WPS_PDT_CID_MULIT_MEDIA, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      OUI */
+       /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */
+       put_unaligned_be32(WPSOUI, p2pie + p2pielen);
+       p2pielen += 4;
+
+       /*      Sub Category ID */
+       /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */
+       put_unaligned_be16(WPS_PDT_SCID_MEDIA_SERVER, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Number of Secondary Device Types */
+       p2pie[ p2pielen++ ] = 0x00;     /*      No Secondary Device Type List */
+
+       /*      Device Name */
+       /*      Type: */
+       /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */
+       put_unaligned_be16(WPS_ATTR_DEVICE_NAME, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Length: */
+       /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */
+       put_unaligned_be16(pwdinfo->device_name_len, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Value: */
+       memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+       p2pielen += pwdinfo->device_name_len;
+
+       /*  Group Info ATTR */
+       /*      Type: */
+       /*      Length: */
+       /*      Value: */
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+       {
+               p2pielen += go_add_group_info_attr(pwdinfo, p2pie + p2pielen);
+       }
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len);
+
+       return len;
+}
+
+u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, u8* pssid, u8 ussidlen, u8* pdev_raddr)
+{
+       u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 };
+       u32 len = 0, p2pielen = 0;
+
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[ p2pielen++ ] = 0x50;
+       p2pie[ p2pielen++ ] = 0x6F;
+       p2pie[ p2pielen++ ] = 0x9A;
+       p2pie[ p2pielen++ ] = 0x09;     /*      WFA P2P v1.0 */
+
+       /*      Commented by Albert 20110301 */
+       /*      According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */
+       /*      1. P2P Capability */
+       /*      2. Device Info */
+       /*      3. Group ID (When joining an operating P2P Group) */
+
+       /*      P2P Capability ATTR */
+       /*      Type: */
+       p2pie[ p2pielen++ ] = P2P_ATTR_CAPABILITY;
+
+       /*      Length: */
+       /* u16*) (p2pie + p2pielen) = cpu_to_le16(0x0002); */
+       put_unaligned_le16(0x0002, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Device Capability Bitmap, 1 byte */
+       p2pie[ p2pielen++ ] = DMP_P2P_DEVCAP_SUPPORT;
+
+       /*      Group Capability Bitmap, 1 byte */
+       if (pwdinfo->persistent_supported)
+               p2pie[ p2pielen++ ] = P2P_GRPCAP_PERSISTENT_GROUP | DMP_P2P_GRPCAP_SUPPORT;
+       else
+               p2pie[ p2pielen++ ] = DMP_P2P_GRPCAP_SUPPORT;
+
+       /*      Device Info ATTR */
+       /*      Type: */
+       p2pie[ p2pielen++ ] = P2P_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       /*      21 -> P2P Device Address (6bytes) + Config Methods (2bytes) + Primary Device Type (8bytes) */
+       /*      + NumofSecondDevType (1byte) + WPS Device Name ID field (2bytes) + WPS Device Name Len field (2bytes) */
+       /* u16*) (p2pie + p2pielen) = cpu_to_le16(21 + pwdinfo->device_name_len); */
+       put_unaligned_le16(21 + pwdinfo->device_name_len, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      P2P Device Address */
+       memcpy(p2pie + p2pielen, pwdinfo->device_addr, ETH_ALEN);
+       p2pielen += ETH_ALEN;
+
+       /*      Config Method */
+       /*      This field should be big endian. Noted by P2P specification. */
+       if (pwdinfo->ui_got_wps_info == P2P_GOT_WPSINFO_PBC)
+       {
+               /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_PBC); */
+               put_unaligned_be16(WPS_CONFIG_METHOD_PBC, p2pie + p2pielen);
+       }
+       else
+       {
+               /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_CONFIG_METHOD_DISPLAY); */
+               put_unaligned_be16(WPS_CONFIG_METHOD_DISPLAY, p2pie + p2pielen);
+       }
+
+       p2pielen += 2;
+
+       /*      Primary Device Type */
+       /*      Category ID */
+       /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_CID_MULIT_MEDIA); */
+       put_unaligned_be16(WPS_PDT_CID_MULIT_MEDIA, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      OUI */
+       /* u32*) (p2pie + p2pielen) = cpu_to_be32(WPSOUI); */
+       put_unaligned_be32(WPSOUI, p2pie + p2pielen);
+       p2pielen += 4;
+
+       /*      Sub Category ID */
+       /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_PDT_SCID_MEDIA_SERVER); */
+       put_unaligned_be16(WPS_PDT_SCID_MEDIA_SERVER, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Number of Secondary Device Types */
+       p2pie[ p2pielen++ ] = 0x00;     /*      No Secondary Device Type List */
+
+       /*      Device Name */
+       /*      Type: */
+       /* u16*) (p2pie + p2pielen) = cpu_to_be16(WPS_ATTR_DEVICE_NAME); */
+       put_unaligned_be16(WPS_ATTR_DEVICE_NAME, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Length: */
+       /* u16*) (p2pie + p2pielen) = cpu_to_be16(pwdinfo->device_name_len); */
+       put_unaligned_be16(pwdinfo->device_name_len, p2pie + p2pielen);
+       p2pielen += 2;
+
+       /*      Value: */
+       memcpy(p2pie + p2pielen, pwdinfo->device_name, pwdinfo->device_name_len);
+       p2pielen += pwdinfo->device_name_len;
+
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_CLIENT))
+       {
+               /*      Added by Albert 2011/05/19 */
+               /*      In this case, the pdev_raddr is the device address of the group owner. */
+
+               /*      P2P Group ID ATTR */
+               /*      Type: */
+               p2pie[ p2pielen++ ] = P2P_ATTR_GROUP_ID;
+
+               /*      Length: */
+               /* u16*) (p2pie + p2pielen) = cpu_to_le16(ETH_ALEN + ussidlen); */
+               put_unaligned_le16(ETH_ALEN + ussidlen, p2pie + p2pielen);
+               p2pielen += 2;
+
+               /*      Value: */
+               memcpy(p2pie + p2pielen, pdev_raddr, ETH_ALEN);
+               p2pielen += ETH_ALEN;
+
+               memcpy(p2pie + p2pielen, pssid, ussidlen);
+               p2pielen += ussidlen;
+
+       }
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len);
+
+       return len;
+}
+
+u32 build_assoc_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf, u8 status_code)
+{
+       u8 p2pie[ MAX_P2P_IE_LEN] = { 0x00 };
+       u32 len = 0, p2pielen = 0;
+
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2pie[ p2pielen++ ] = 0x50;
+       p2pie[ p2pielen++ ] = 0x6F;
+       p2pie[ p2pielen++ ] = 0x9A;
+       p2pie[ p2pielen++ ] = 0x09;     /*      WFA P2P v1.0 */
+
+       /*  According to the P2P Specification, the Association response frame should contain 2 P2P attributes */
+       /*      1. Status */
+       /*      2. Extended Listen Timing (optional) */
+
+       /*      Status ATTR */
+       p2pielen += rtw_set_p2p_attr_content23a(&p2pie[p2pielen], P2P_ATTR_STATUS, 1, &status_code);
+
+       /*  Extended Listen Timing ATTR */
+       /*      Type: */
+       /*      Length: */
+       /*      Value: */
+
+       pbuf = rtw_set_ie23a(pbuf, _VENDOR_SPECIFIC_IE_, p2pielen, (unsigned char *) p2pie, &len);
+
+       return len;
+}
+
+u32 build_deauth_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf)
+{
+       u32 len = 0;
+
+       return len;
+}
+
+u32 process_probe_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+       u8 *p;
+       u32 ret = false;
+       u8 *p2pie;
+       u32     p2pielen = 0;
+       int ssid_len = 0, rate_cnt = 0;
+
+       p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _PROBEREQ_IE_OFFSET_, _SUPPORTEDRATES_IE_, (int *)&rate_cnt,
+                       len - sizeof(struct ieee80211_hdr_3addr) - _PROBEREQ_IE_OFFSET_);
+
+       if (rate_cnt <= 4)
+       {
+               int i, g_rate = 0;
+
+               for (i = 0; i < rate_cnt; i++)
+               {
+                       if (((*(p + 2 + i) & 0xff) != 0x02) &&
+                               ((*(p + 2 + i) & 0xff) != 0x04) &&
+                               ((*(p + 2 + i) & 0xff) != 0x0B) &&
+                               ((*(p + 2 + i) & 0xff) != 0x16))
+                       {
+                               g_rate = 1;
+                       }
+               }
+
+               if (g_rate == 0)
+               {
+                       /*      There is no OFDM rate included in SupportedRates IE of this probe request frame */
+                       /*      The driver should response this probe request. */
+                       return ret;
+               }
+       }
+       else
+       {
+               /*      rate_cnt > 4 means the SupportRates IE contains the OFDM rate because the count of CCK rates are 4. */
+               /*      We should proceed the following check for this probe request. */
+       }
+
+       /*      Added comments by Albert 20100906 */
+       /*      There are several items we should check here. */
+       /*      1. This probe request frame must contain the P2P IE. (Done) */
+       /*      2. This probe request frame must contain the wildcard SSID. (Done) */
+       /*      3. Wildcard BSSID. (Todo) */
+       /*      4. Destination Address. (Done in mgt_dispatcher23a function) */
+       /*      5. Requested Device Type in WSC IE. (Todo) */
+       /*      6. Device ID attribute in P2P IE. (Todo) */
+
+       p = rtw_get_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _PROBEREQ_IE_OFFSET_, _SSID_IE_, (int *)&ssid_len,
+                       len - sizeof(struct ieee80211_hdr_3addr) - _PROBEREQ_IE_OFFSET_);
+
+       ssid_len &= 0xff;       /*      Just last 1 byte is valid for ssid len of the probe request */
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE) || rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+       {
+               if ((p2pie = rtw_get_p2p_ie23a(pframe + sizeof(struct ieee80211_hdr_3addr) + _PROBEREQ_IE_OFFSET_, len - sizeof(struct ieee80211_hdr_3addr) - _PROBEREQ_IE_OFFSET_, NULL, &p2pielen)))
+               {
+                       if ((p) && !memcmp((void *)(p+2), (void *)pwdinfo->p2p_wildcard_ssid, 7))
+                       {
+                               /* todo: */
+                               /* Check Requested Device Type attributes in WSC IE. */
+                               /* Check Device ID attribute in P2P IE */
+
+                               ret = true;
+                       }
+                       else if ((p != NULL) && (ssid_len == 0))
+                       {
+                               ret = true;
+                       }
+               }
+               else
+               {
+                       /* non -p2p device */
+               }
+
+       }
+
+       return ret;
+}
+
+u32 process_assoc_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len, struct sta_info *psta)
+{
+       u8 status_code = P2P_STATUS_SUCCESS;
+       u8 *pbuf, *pattr_content = NULL;
+       u32 attr_contentlen = 0;
+       u16 cap_attr = 0;
+       unsigned short ie_offset;
+       u8 * ies;
+       u32 ies_len;
+       u8 * p2p_ie;
+       u32     p2p_ielen = 0;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe;
+
+       if (!rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+               return P2P_STATUS_FAIL_REQUEST_UNABLE;
+
+       if (ieee80211_is_assoc_req(hdr->frame_control))
+               ie_offset = _ASOCREQ_IE_OFFSET_;
+       else /*  WIFI_REASSOCREQ */
+               ie_offset = _REASOCREQ_IE_OFFSET_;
+
+       ies = pframe + sizeof(struct ieee80211_hdr_3addr) + ie_offset;
+       ies_len = len - sizeof(struct ieee80211_hdr_3addr) - ie_offset;
+
+       p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen);
+
+       if (!p2p_ie)
+       {
+               DBG_8723A("[%s] P2P IE not Found!!\n", __func__);
+               status_code =  P2P_STATUS_FAIL_INVALID_PARAM;
+       }
+       else
+       {
+               DBG_8723A("[%s] P2P IE Found!!\n", __func__);
+       }
+
+       while (p2p_ie)
+       {
+               /* Check P2P Capability ATTR */
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*) &attr_contentlen))
+               {
+                       DBG_8723A("[%s] Got P2P Capability Attr!!\n", __func__);
+                       cap_attr = le16_to_cpu(cap_attr);
+                       psta->dev_cap = cap_attr&0xff;
+               }
+
+               /* Check Extended Listen Timing ATTR */
+
+               /* Check P2P Device Info ATTR */
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, NULL, (uint*)&attr_contentlen))
+               {
+                       DBG_8723A("[%s] Got P2P DEVICE INFO Attr!!\n", __func__);
+                       pattr_content = pbuf = kzalloc(attr_contentlen,
+                                                      GFP_ATOMIC);
+                       if (pattr_content) {
+                               u8 num_of_secdev_type;
+                               u16 dev_name_len;
+
+                               rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_DEVICE_INFO, pattr_content, (uint*)&attr_contentlen);
+
+                               memcpy(psta->dev_addr,  pattr_content, ETH_ALEN);/* P2P Device Address */
+
+                               pattr_content += ETH_ALEN;
+
+                               memcpy(&psta->config_methods, pattr_content, 2);/* Config Methods */
+                               psta->config_methods = be16_to_cpu(psta->config_methods);
+
+                               pattr_content += 2;
+
+                               memcpy(psta->primary_dev_type, pattr_content, 8);
+
+                               pattr_content += 8;
+
+                               num_of_secdev_type = *pattr_content;
+                               pattr_content += 1;
+
+                               if (num_of_secdev_type == 0)
+                               {
+                                       psta->num_of_secdev_type = 0;
+                               }
+                               else
+                               {
+                                       u32 len;
+
+                                       psta->num_of_secdev_type = num_of_secdev_type;
+
+                                       len = (sizeof(psta->secdev_types_list)<(num_of_secdev_type*8)) ? (sizeof(psta->secdev_types_list)) : (num_of_secdev_type*8);
+
+                                       memcpy(psta->secdev_types_list, pattr_content, len);
+
+                                       pattr_content += (num_of_secdev_type*8);
+                               }
+
+                               /* dev_name_len = attr_contentlen - ETH_ALEN - 2 - 8 - 1 - (num_of_secdev_type*8); */
+                               psta->dev_name_len = 0;
+                               if (WPS_ATTR_DEVICE_NAME == be16_to_cpu(*(u16*)pattr_content))
+                               {
+                                       dev_name_len = be16_to_cpu(*(u16*)(pattr_content+2));
+
+                                       psta->dev_name_len = (sizeof(psta->dev_name)<dev_name_len) ? sizeof(psta->dev_name):dev_name_len;
+
+                                       memcpy(psta->dev_name, pattr_content+4, psta->dev_name_len);
+                               }
+
+                               kfree(pbuf);
+
+                       }
+
+               }
+
+               /* Get the next P2P IE */
+               p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen);
+
+       }
+
+       return status_code;
+}
+
+u32 process_p2p_devdisc_req23a(struct wifidirect_info *pwdinfo, u8 *pframe,
+                           uint len)
+{
+       u8 *frame_body;
+       u8 status, dialogToken;
+       struct sta_info *psta = NULL;
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       u8 *p2p_ie;
+       u32     p2p_ielen = 0;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe;
+
+       frame_body = (unsigned char *)
+               (pframe + sizeof(struct ieee80211_hdr_3addr));
+
+       dialogToken = frame_body[7];
+       status = P2P_STATUS_FAIL_UNKNOWN_P2PGROUP;
+
+       if ((p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_,
+                                    len - _PUBLIC_ACTION_IE_OFFSET_, NULL,
+                                    &p2p_ielen))) {
+               u8 groupid[38] = { 0x00 };
+               u8 dev_addr[ETH_ALEN] = { 0x00 };
+               u32 attr_contentlen = 0;
+
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen,
+                                            P2P_ATTR_GROUP_ID, groupid,
+                                            &attr_contentlen)) {
+                       if (!memcmp(pwdinfo->device_addr, groupid, ETH_ALEN) &&
+                           !memcmp(pwdinfo->p2p_group_ssid, groupid + ETH_ALEN,
+                                   pwdinfo->p2p_group_ssid_len)) {
+                               attr_contentlen = 0;
+
+                               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen,
+                                                            P2P_ATTR_DEVICE_ID,
+                                                            dev_addr,
+                                                            &attr_contentlen)) {
+                                       struct list_head *phead, *plist, *ptmp;
+
+                                       spin_lock_bh(&pstapriv->asoc_list_lock);
+                                       phead = &pstapriv->asoc_list;
+
+                                       list_for_each_safe(plist, ptmp, phead) {
+                                               psta = container_of(plist, struct sta_info, asoc_list);
+
+                                               if (psta->is_p2p_device && (psta->dev_cap&P2P_DEVCAP_CLIENT_DISCOVERABILITY) &&
+                                                  !memcmp(psta->dev_addr, dev_addr, ETH_ALEN))
+                                               {
+                                                       /* spin_unlock_bh(&pstapriv->asoc_list_lock); */
+                                                       /* issue GO Discoverability Request */
+                                                       issue_group_disc_req(pwdinfo, psta->hwaddr);
+                                                       /* spin_lock_bh(&pstapriv->asoc_list_lock); */
+                                                       status = P2P_STATUS_SUCCESS;
+                                                       break;
+                                               } else {
+                                                       status = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+                                               }
+                                       }
+                                       spin_unlock_bh(&pstapriv->asoc_list_lock);
+                               } else {
+                                       status = P2P_STATUS_FAIL_INVALID_PARAM;
+                               }
+                       } else {
+                               status = P2P_STATUS_FAIL_INVALID_PARAM;
+                       }
+               }
+       }
+
+       /* issue Device Discoverability Response */
+       issue_p2p_devdisc_resp(pwdinfo, hdr->addr2, status, dialogToken);
+
+       return (status == P2P_STATUS_SUCCESS) ? true:false;
+}
+
+u32 process_p2p_devdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+       return true;
+}
+
+u8 process_p2p_provdisc_req23a(struct wifidirect_info *pwdinfo,
+                           u8 *pframe, uint len)
+{
+       u8 *frame_body;
+       u8 *wpsie;
+       u8 *ptr = NULL;
+       uint    wps_ielen = 0, attr_contentlen = 0;
+       u16     uconfig_method = 0;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe;
+
+       frame_body = (pframe + sizeof(struct ieee80211_hdr_3addr));
+
+       wpsie = rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_,
+                              len - _PUBLIC_ACTION_IE_OFFSET_, NULL,
+                              &wps_ielen);
+       if (!wpsie)
+               goto out;
+
+       if (!rtw_get_wps_attr_content23a(wpsie, wps_ielen, WPS_ATTR_CONF_METHOD,
+                                    (u8 *)&uconfig_method, &attr_contentlen))
+               goto out;
+
+       uconfig_method = be16_to_cpu(uconfig_method);
+       ptr = pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req;
+
+       switch (uconfig_method)
+       {
+       case WPS_CM_DISPLYA:
+               memcpy(ptr, "dis", 3);
+               break;
+
+       case WPS_CM_LABEL:
+               memcpy(ptr, "lab", 3);
+               break;
+
+       case WPS_CM_PUSH_BUTTON:
+               memcpy(ptr, "pbc", 3);
+               break;
+
+       case WPS_CM_KEYPAD:
+               memcpy(ptr, "pad", 3);
+               break;
+       }
+       issue_p2p_provision_resp(pwdinfo, hdr->addr2, frame_body,
+                                uconfig_method);
+
+out:
+       DBG_8723A("[%s] config method = %s\n", __func__, ptr);
+
+       return true;
+}
+
+u8 process_p2p_provdisc_resp23a(struct wifidirect_info *pwdinfo,  u8 *pframe)
+{
+
+       return true;
+}
+
+static u8 rtw_p2p_get_peer_ch_list(struct wifidirect_info *pwdinfo, u8 *ch_content, u8 ch_cnt, u8 *peer_ch_list)
+{
+       u8 i = 0, j = 0;
+       u8 temp = 0;
+       u8 ch_no = 0;
+       ch_content += 3;
+       ch_cnt -= 3;
+
+       while(ch_cnt > 0)
+       {
+               ch_content += 1;
+               ch_cnt -= 1;
+               temp = *ch_content;
+               for (i = 0 ; i < temp ; i++, j++)
+               {
+                       peer_ch_list[j] = *(ch_content + 1 + i);
+               }
+               ch_content += (temp + 1);
+               ch_cnt -= (temp + 1);
+               ch_no += temp ;
+       }
+
+       return ch_no;
+}
+
+static u8 rtw_p2p_ch_inclusion(struct mlme_ext_priv *pmlmeext, u8 *peer_ch_list, u8 peer_ch_num, u8 *ch_list_inclusioned)
+{
+       int     i = 0, j = 0, temp = 0;
+       u8 ch_no = 0;
+
+       for (i = 0; i < peer_ch_num; i++)
+       {
+               for (j = temp; j < pmlmeext->max_chan_nums; j++)
+               {
+                       if (*(peer_ch_list + i) == pmlmeext->channel_set[ j ].ChannelNum)
+                       {
+                               ch_list_inclusioned[ ch_no++ ] = *(peer_ch_list + i);
+                               temp = j;
+                               break;
+                       }
+               }
+       }
+
+       return ch_no;
+}
+
+u8 process_p2p_group_negotation_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       u8      result = P2P_STATUS_SUCCESS;
+       u32     p2p_ielen = 0, wps_ielen = 0;
+       u8 * ies;
+       u32 ies_len;
+       u8 *p2p_ie;
+       u8 *wpsie;
+       u16             wps_devicepassword_id = 0x0000;
+       uint    wps_devicepassword_id_len = 0;
+#ifdef CONFIG_8723AU_P2P
+       u8      wfd_ie[ 128 ] = { 0x00 };
+       u32     wfd_ielen = 0;
+#endif /*  CONFIG_8723AU_P2P */
+
+       if ((wpsie = rtw_get_wps_ie23a(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, NULL, &wps_ielen)))
+       {
+               /*      Commented by Kurt 20120113 */
+               /*      If some device wants to do p2p handshake without sending prov_disc_req */
+               /*      We have to get peer_req_cm from here. */
+               if (!memcmp(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "000", 3))
+               {
+                       rtw_get_wps_attr_content23a(wpsie, wps_ielen, WPS_ATTR_DEVICE_PWID, (u8*) &wps_devicepassword_id, &wps_devicepassword_id_len);
+                       wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id);
+
+                       if (wps_devicepassword_id == WPS_DPID_USER_SPEC)
+                       {
+                               memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "dis", 3);
+                       }
+                       else if (wps_devicepassword_id == WPS_DPID_REGISTRAR_SPEC)
+                       {
+                               memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pad", 3);
+                       }
+                       else
+                       {
+                               memcpy(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, "pbc", 3);
+                       }
+               }
+       }
+       else
+       {
+               DBG_8723A("[%s] WPS IE not Found!!\n", __func__);
+               result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+               return result;
+       }
+
+       if (pwdinfo->ui_got_wps_info == P2P_NO_WPSINFO)
+       {
+               result = P2P_STATUS_FAIL_INFO_UNAVAILABLE;
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_TX_INFOR_NOREADY);
+               return result;
+       }
+
+       ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
+       ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
+
+       p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen);
+
+       if (!p2p_ie)
+       {
+               DBG_8723A("[%s] P2P IE not Found!!\n", __func__);
+               result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+       }
+
+       while (p2p_ie)
+       {
+               u8      attr_content = 0x00;
+               u32     attr_contentlen = 0;
+               u8      ch_content[50] = { 0x00 };
+               uint    ch_cnt = 0;
+               u8      peer_ch_list[50] = { 0x00 };
+               u8      peer_ch_num = 0;
+               u8      ch_list_inclusioned[50] = { 0x00 };
+               u8      ch_num_inclusioned = 0;
+               u16     cap_attr;
+
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_ING);
+
+               /* Check P2P Capability ATTR */
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*)&attr_contentlen))
+                       cap_attr = le16_to_cpu(cap_attr);
+
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, &attr_content, &attr_contentlen))
+               {
+                       DBG_8723A("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01);
+                       pwdinfo->peer_intent = attr_content;    /*      include both intent and tie breaker values. */
+
+                       if (pwdinfo->intent == (pwdinfo->peer_intent >> 1))
+                       {
+                               /*      Try to match the tie breaker value */
+                               if (pwdinfo->intent == P2P_MAX_INTENT)
+                               {
+                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+                                       result = P2P_STATUS_FAIL_BOTH_GOINTENT_15;
+                               }
+                               else
+                               {
+                                       if (attr_content & 0x01)
+                                       {
+                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                                       }
+                                       else
+                                       {
+                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+                                       }
+                               }
+                       }
+                       else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1))
+                       {
+                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+                       }
+                       else
+                       {
+                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                       }
+
+                       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+                       {
+                               /*      Store the group id information. */
+                               memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN);
+                               memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+                       }
+               }
+
+               attr_contentlen = 0;
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen))
+               {
+                       if (attr_contentlen != ETH_ALEN)
+                       {
+                               memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
+                       }
+               }
+
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, ch_content, &ch_cnt))
+               {
+                       peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, ch_content, ch_cnt, peer_ch_list);
+                       ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned);
+
+                       if (ch_num_inclusioned == 0)
+                       {
+                               DBG_8723A("[%s] No common channel in channel list!\n", __func__);
+                               result = P2P_STATUS_FAIL_NO_COMMON_CH;
+                               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+                               break;
+                       }
+
+                       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+                       {
+                               if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel,
+                                                                                               ch_list_inclusioned, ch_num_inclusioned))
+                               {
+                                       {
+                                               u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0;
+                                               attr_contentlen = 0;
+
+                                               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
+                                               {
+                                                       peer_operating_ch = operatingch_info[4];
+                                               }
+
+                                               if (rtw_p2p_is_channel_list_ok(peer_operating_ch,
+                                                                                                               ch_list_inclusioned, ch_num_inclusioned))
+                                               {
+                                                       /**
+                                                        *      Change our operating channel as peer's for compatibility.
+                                                        */
+                                                       pwdinfo->operating_channel = peer_operating_ch;
+                                                       DBG_8723A("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel);
+                                               }
+                                               else
+                                               {
+                                                       /*  Take first channel of ch_list_inclusioned as operating channel */
+                                                       pwdinfo->operating_channel = ch_list_inclusioned[0];
+                                                       DBG_8723A("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel);
+                                               }
+                                       }
+
+                               }
+                       }
+               }
+
+               /* Get the next P2P IE */
+               p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen);
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       /*      Added by Albert 20110823 */
+       /*      Try to get the TCP port information when receiving the negotiation request. */
+       if (rtw_get_wfd_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wfd_ie, &wfd_ielen))
+       {
+               u8      attr_content[ 10 ] = { 0x00 };
+               u32     attr_contentlen = 0;
+
+               DBG_8723A("[%s] WFD IE Found!!\n", __func__);
+               rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen);
+               if (attr_contentlen)
+               {
+                       pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2);
+                       DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport);
+               }
+       }
+#endif /*  CONFIG_8723AU_P2P */
+
+       return result;
+}
+
+u8 process_p2p_group_negotation_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+       struct rtw_adapter *padapter = pwdinfo->padapter;
+       u8      result = P2P_STATUS_SUCCESS;
+       u32     p2p_ielen, wps_ielen;
+       u8 * ies;
+       u32 ies_len;
+       u8 * p2p_ie;
+#ifdef CONFIG_8723AU_P2P
+       u8      wfd_ie[ 128 ] = { 0x00 };
+       u32     wfd_ielen = 0;
+#endif /*  CONFIG_8723AU_P2P */
+
+       ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
+       ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
+
+       /*      Be able to know which one is the P2P GO and which one is P2P client. */
+
+       if (rtw_get_wps_ie23a(ies, ies_len, NULL, &wps_ielen))
+       {
+
+       }
+       else
+       {
+               DBG_8723A("[%s] WPS IE not Found!!\n", __func__);
+               result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+       }
+
+       p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen);
+       if (!p2p_ie)
+       {
+               rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+               result = P2P_STATUS_FAIL_INCOMPATIBLE_PARAM;
+       }
+       else
+       {
+
+               u8      attr_content = 0x00;
+               u32     attr_contentlen = 0;
+               u8      operatingch_info[5] = { 0x00 };
+               u8      groupid[ 38 ];
+               u16     cap_attr;
+               u8      peer_ch_list[50] = { 0x00 };
+               u8      peer_ch_num = 0;
+               u8      ch_list_inclusioned[50] = { 0x00 };
+               u8      ch_num_inclusioned = 0;
+
+               while (p2p_ie)  /*      Found the P2P IE. */
+               {
+
+                       /* Check P2P Capability ATTR */
+                       if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY, (u8*)&cap_attr, (uint*)&attr_contentlen))
+                               cap_attr = le16_to_cpu(cap_attr);
+
+                       rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
+                       if (attr_contentlen == 1)
+                       {
+                               DBG_8723A("[%s] Status = %d\n", __func__, attr_content);
+                               if (attr_content == P2P_STATUS_SUCCESS)
+                               {
+                                       /*      Do nothing. */
+                               }
+                               else
+                               {
+                                       if (P2P_STATUS_FAIL_INFO_UNAVAILABLE == attr_content) {
+                                               rtw_p2p_set_state(pwdinfo, P2P_STATE_RX_INFOR_NOREADY);
+                                       } else {
+                                               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+                                       }
+                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+                                       result = attr_content;
+                                       break;
+                               }
+                       }
+
+                       /*      Try to get the peer's interface address */
+                       attr_contentlen = 0;
+                       if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INTENTED_IF_ADDR, pwdinfo->p2p_peer_interface_addr, &attr_contentlen))
+                       {
+                               if (attr_contentlen != ETH_ALEN)
+                               {
+                                       memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
+                               }
+                       }
+
+                       /*      Try to get the peer's intent and tie breaker value. */
+                       attr_content = 0x00;
+                       attr_contentlen = 0;
+                       if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GO_INTENT, &attr_content, &attr_contentlen))
+                       {
+                               DBG_8723A("[%s] GO Intent = %d, tie = %d\n", __func__, attr_content >> 1, attr_content & 0x01);
+                               pwdinfo->peer_intent = attr_content;    /*      include both intent and tie breaker values. */
+
+                               if (pwdinfo->intent == (pwdinfo->peer_intent >> 1))
+                               {
+                                       /*      Try to match the tie breaker value */
+                                       if (pwdinfo->intent == P2P_MAX_INTENT)
+                                       {
+                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+                                               result = P2P_STATUS_FAIL_BOTH_GOINTENT_15;
+                                               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+                                       }
+                                       else
+                                       {
+                                               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+                                               rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+                                               if (attr_content & 0x01)
+                                               {
+                                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                                               }
+                                               else
+                                               {
+                                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+                                               }
+                                       }
+                               }
+                               else if (pwdinfo->intent > (pwdinfo->peer_intent >> 1))
+                               {
+                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+                                       rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+                               }
+                               else
+                               {
+                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+                                       rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                               }
+
+                               if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+                               {
+                                       /*      Store the group id information. */
+                                       memcpy(pwdinfo->groupid_info.go_device_addr, pwdinfo->device_addr, ETH_ALEN);
+                                       memcpy(pwdinfo->groupid_info.ssid, pwdinfo->nego_ssid, pwdinfo->nego_ssidlen);
+
+                               }
+                       }
+
+                       /*      Try to get the operation channel information */
+
+                       attr_contentlen = 0;
+                       if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
+                       {
+                               DBG_8723A("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]);
+                               pwdinfo->peer_operating_ch = operatingch_info[4];
+                       }
+
+                       /*      Try to get the channel list information */
+                       if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CH_LIST, pwdinfo->channel_list_attr, &pwdinfo->channel_list_attr_len))
+                       {
+                               DBG_8723A("[%s] channel list attribute found, len = %d\n", __func__,  pwdinfo->channel_list_attr_len);
+
+                               peer_ch_num = rtw_p2p_get_peer_ch_list(pwdinfo, pwdinfo->channel_list_attr, pwdinfo->channel_list_attr_len, peer_ch_list);
+                               ch_num_inclusioned = rtw_p2p_ch_inclusion(&padapter->mlmeextpriv, peer_ch_list, peer_ch_num, ch_list_inclusioned);
+
+                               if (ch_num_inclusioned == 0)
+                               {
+                                       DBG_8723A("[%s] No common channel in channel list!\n", __func__);
+                                       result = P2P_STATUS_FAIL_NO_COMMON_CH;
+                                       rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+                                       break;
+                               }
+
+                               if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO))
+                               {
+                                       if (!rtw_p2p_is_channel_list_ok(pwdinfo->operating_channel,
+                                                                                                       ch_list_inclusioned, ch_num_inclusioned))
+                                       {
+                                               {
+                                                       u8 operatingch_info[5] = { 0x00 }, peer_operating_ch = 0;
+                                                       attr_contentlen = 0;
+
+                                                       if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
+                                                       {
+                                                               peer_operating_ch = operatingch_info[4];
+                                                       }
+
+                                                       if (rtw_p2p_is_channel_list_ok(peer_operating_ch,
+                                                                                                                       ch_list_inclusioned, ch_num_inclusioned))
+                                                       {
+                                                               /**
+                                                                *      Change our operating channel as peer's for compatibility.
+                                                                */
+                                                               pwdinfo->operating_channel = peer_operating_ch;
+                                                               DBG_8723A("[%s] Change op ch to %02x as peer's\n", __func__, pwdinfo->operating_channel);
+                                                       }
+                                                       else
+                                                       {
+                                                               /*  Take first channel of ch_list_inclusioned as operating channel */
+                                                               pwdinfo->operating_channel = ch_list_inclusioned[0];
+                                                               DBG_8723A("[%s] Change op ch to %02x\n", __func__, pwdinfo->operating_channel);
+                                                       }
+                                               }
+
+                                       }
+                               }
+
+                       }
+                       else
+                       {
+                               DBG_8723A("[%s] channel list attribute not found!\n", __func__);
+                       }
+
+                       /*      Try to get the group id information if peer is GO */
+                       attr_contentlen = 0;
+                       memset(groupid, 0x00, 38);
+                       if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen))
+                       {
+                               memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN);
+                               memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN);
+                       }
+
+                       /* Get the next P2P IE */
+                       p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen);
+               }
+
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       /*      Added by Albert 20111122 */
+       /*      Try to get the TCP port information when receiving the negotiation response. */
+       if (rtw_get_wfd_ie(pframe + _PUBLIC_ACTION_IE_OFFSET_, len - _PUBLIC_ACTION_IE_OFFSET_, wfd_ie, &wfd_ielen))
+       {
+               u8      attr_content[ 10 ] = { 0x00 };
+               u32     attr_contentlen = 0;
+
+               DBG_8723A("[%s] WFD IE Found!!\n", __func__);
+               rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen);
+               if (attr_contentlen)
+               {
+                       pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2);
+                       DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport);
+               }
+       }
+#endif /*  CONFIG_8723AU_P2P */
+
+       return result;
+}
+
+u8 process_p2p_group_negotation_confirm23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+       u8 * ies;
+       u32 ies_len;
+       u8 * p2p_ie;
+       u32     p2p_ielen = 0;
+       u8      result = P2P_STATUS_SUCCESS;
+       ies = pframe + _PUBLIC_ACTION_IE_OFFSET_;
+       ies_len = len - _PUBLIC_ACTION_IE_OFFSET_;
+
+       p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen);
+       while (p2p_ie)  /*      Found the P2P IE. */
+       {
+               u8      attr_content = 0x00, operatingch_info[5] = { 0x00 };
+               u8      groupid[ 38 ] = { 0x00 };
+               u32     attr_contentlen = 0;
+
+               pwdinfo->negotiation_dialog_token = 1;
+               rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, &attr_content, &attr_contentlen);
+               if (attr_contentlen == 1)
+               {
+                       DBG_8723A("[%s] Status = %d\n", __func__, attr_content);
+                       result = attr_content;
+
+                       if (attr_content == P2P_STATUS_SUCCESS)
+                       {
+                               del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+
+                               /*      Commented by Albert 20100911 */
+                               /*      Todo: Need to handle the case which both Intents are the same. */
+                               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+                               rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+                               if ((pwdinfo->intent) > (pwdinfo->peer_intent >> 1))
+                               {
+                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+                               }
+                               else if ((pwdinfo->intent) < (pwdinfo->peer_intent >> 1))
+                               {
+                                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                               }
+                               else
+                               {
+                                       /*      Have to compare the Tie Breaker */
+                                       if (pwdinfo->peer_intent & 0x01)
+                                       {
+                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+                                       }
+                                       else
+                                       {
+                                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+                                       }
+                               }
+                       }
+                       else
+                       {
+                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+                               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_FAIL);
+                               break;
+                       }
+               }
+
+               /*      Try to get the group id information */
+               attr_contentlen = 0;
+               memset(groupid, 0x00, 38);
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, groupid, &attr_contentlen))
+               {
+                       DBG_8723A("[%s] Ssid = %s, ssidlen = %zu\n", __func__, &groupid[ETH_ALEN], strlen(&groupid[ETH_ALEN]));
+                       memcpy(pwdinfo->groupid_info.go_device_addr, &groupid[0], ETH_ALEN);
+                       memcpy(pwdinfo->groupid_info.ssid, &groupid[6], attr_contentlen - ETH_ALEN);
+               }
+
+               attr_contentlen = 0;
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, operatingch_info, &attr_contentlen))
+               {
+                       DBG_8723A("[%s] Peer's operating channel = %d\n", __func__, operatingch_info[4]);
+                       pwdinfo->peer_operating_ch = operatingch_info[4];
+               }
+
+               /* Get the next P2P IE */
+               p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen);
+
+       }
+
+       return result;
+}
+
+u8 process_p2p_presence_req23a(struct wifidirect_info *pwdinfo, u8 *pframe, uint len)
+{
+       u8 *frame_body;
+       u8 dialogToken = 0;
+       u8 status = P2P_STATUS_SUCCESS;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe;
+
+       frame_body = (unsigned char *)(pframe + sizeof(struct ieee80211_hdr_3addr));
+
+       dialogToken = frame_body[6];
+
+       /* todo: check NoA attribute */
+
+       issue_p2p_presence_resp(pwdinfo, hdr->addr2, status, dialogToken);
+
+       return true;
+}
+
+static void find_phase_handler(struct rtw_adapter *padapter)
+{
+       struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct cfg80211_ssid ssid;
+       u8                                      _status = 0;
+
+
+
+       memset((unsigned char*)&ssid, 0, sizeof(struct cfg80211_ssid));
+       memcpy(ssid.ssid, pwdinfo->p2p_wildcard_ssid, P2P_WILDCARD_SSID_LEN);
+       ssid.ssid_len = P2P_WILDCARD_SSID_LEN;
+
+       rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+
+       spin_lock_bh(&pmlmepriv->lock);
+       _status = rtw_sitesurvey_cmd23a(padapter, &ssid, 1, NULL, 0);
+       spin_unlock_bh(&pmlmepriv->lock);
+
+
+}
+
+void p2p_concurrent_handler(struct rtw_adapter* padapter);
+
+static void restore_p2p_state_handler(struct rtw_adapter *padapter)
+{
+       struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING) || rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_FAIL))
+               rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+
+       rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+
+       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_DEVICE)) {
+               /*      In the P2P client mode, the driver should not switch back to its listen channel */
+               /*      because this P2P client should stay at the operating channel of P2P GO. */
+               set_channel_bwmode23a(padapter, pwdinfo->listen_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+       }
+}
+
+static void pre_tx_invitereq_handler(struct rtw_adapter *padapter)
+{
+       struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+       u8      val8 = 1;
+
+       set_channel_bwmode23a(padapter, pwdinfo->invitereq_info.peer_ch, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+       padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+       issue23a_probereq_p2p(padapter, NULL);
+       mod_timer(&pwdinfo->pre_tx_scan_timer,
+                 jiffies + msecs_to_jiffies(P2P_TX_PRESCAN_TIMEOUT));
+
+
+}
+
+static void pre_tx_provdisc_handler(struct rtw_adapter *padapter)
+{
+       struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+       u8      val8 = 1;
+
+
+       set_channel_bwmode23a(padapter, pwdinfo->tx_prov_disc_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+       issue23a_probereq_p2p(padapter, NULL);
+       mod_timer(&pwdinfo->pre_tx_scan_timer,
+                 jiffies + msecs_to_jiffies(P2P_TX_PRESCAN_TIMEOUT));
+
+
+}
+
+static void pre_tx_negoreq_handler(struct rtw_adapter *padapter)
+{
+       struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+       u8      val8 = 1;
+
+
+       set_channel_bwmode23a(padapter, pwdinfo->nego_req_info.peer_channel_num[0], HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_SITESURVEY, (u8 *)(&val8));
+       issue23a_probereq_p2p(padapter, NULL);
+       mod_timer(&pwdinfo->pre_tx_scan_timer,
+                 jiffies + msecs_to_jiffies(P2P_TX_PRESCAN_TIMEOUT));
+
+
+}
+
+static void ro_ch_handler(struct rtw_adapter *padapter)
+{
+       struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       if (pcfg80211_wdinfo->restore_channel != pmlmeext->cur_channel) {
+               if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED))
+                       pmlmeext->cur_channel = pcfg80211_wdinfo->restore_channel;
+
+               set_channel_bwmode23a(padapter, pmlmeext->cur_channel,
+                                     HAL_PRIME_CHNL_OFFSET_DONT_CARE,
+                                     HT_CHANNEL_WIDTH_20);
+       }
+
+       rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+
+       pcfg80211_wdinfo->is_ro_ch = false;
+
+       DBG_8723A("cfg80211_remain_on_channel_expired\n");
+
+       rtw_cfg80211_remain_on_channel_expired(padapter,
+               pcfg80211_wdinfo->remain_on_ch_cookie,
+               &pcfg80211_wdinfo->remain_on_ch_channel,
+               pcfg80211_wdinfo->remain_on_ch_type, GFP_KERNEL);
+}
+
+static void ro_ch_timer_process (unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+
+       p2p_protocol_wk_cmd23a(adapter, P2P_RO_CH_WK);
+}
+
+#ifdef CONFIG_8723AU_P2P
+void rtw_append_wfd_ie(struct rtw_adapter *padapter, u8 *buf, u32* len)
+{
+       unsigned char   *frame_body;
+       u8 category, action, OUI_Subtype, dialogToken = 0;
+       u32     wfdielen = 0;
+
+       frame_body = (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr));
+       category = frame_body[0];
+
+       if (category == WLAN_CATEGORY_PUBLIC) {
+               action = frame_body[1];
+               if (action == ACT_PUBLIC_VENDOR &&
+                   !memcmp(frame_body+2, P2P_OUI23A, 4)) {
+                       OUI_Subtype = frame_body[6];
+                       dialogToken = frame_body[7];
+                       switch (OUI_Subtype)/* OUI Subtype */ {
+                       case P2P_GO_NEGO_REQ:
+                               wfdielen = build_nego_req_wfd_ie(&padapter->wdinfo, buf + (*len));
+                               (*len) += wfdielen;
+                               break;
+                       case P2P_GO_NEGO_RESP:
+                               wfdielen = build_nego_resp_wfd_ie(&padapter->wdinfo, buf + (*len));
+                               (*len) += wfdielen;
+                               break;
+                       case P2P_GO_NEGO_CONF:
+                               wfdielen = build_nego_confirm_wfd_ie(&padapter->wdinfo, buf + (*len));
+                               (*len) += wfdielen;
+                               break;
+                       case P2P_INVIT_REQ:
+                               wfdielen = build_invitation_req_wfd_ie(&padapter->wdinfo, buf + (*len));
+                               (*len) += wfdielen;
+                               break;
+                       case P2P_INVIT_RESP:
+                               wfdielen = build_invitation_resp_wfd_ie(&padapter->wdinfo, buf + (*len));
+                               (*len) += wfdielen;
+                               break;
+                       case P2P_DEVDISC_REQ:
+                               break;
+                       case P2P_DEVDISC_RESP:
+                               break;
+                       case P2P_PROVISION_DISC_REQ:
+                               wfdielen = build_provdisc_req_wfd_ie(&padapter->wdinfo, buf + (*len));
+                               (*len) += wfdielen;
+                               break;
+                       case P2P_PROVISION_DISC_RESP:
+                               wfdielen = build_provdisc_resp_wfd_ie(&padapter->wdinfo, buf + (*len));
+                               (*len) += wfdielen;
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       } else if (category == WLAN_CATEGORY_VENDOR_SPECIFIC) {
+               OUI_Subtype = frame_body[5];
+               dialogToken = frame_body[6];
+       } else {
+               DBG_8723A("%s, action frame category =%d\n", __func__, category);
+       }
+}
+#endif
+
+int rtw_p2p_check_frames(struct rtw_adapter *padapter, const u8 *buf, u32 len, u8 tx)
+{
+       int is_p2p_frame = (-1);
+       unsigned char   *frame_body;
+       u8 category, action, OUI_Subtype, dialogToken = 0;
+       u8 *p2p_ie = NULL;
+       uint p2p_ielen = 0;
+       struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev);
+
+       frame_body = (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr));
+       category = frame_body[0];
+       /* just for check */
+       if (category == WLAN_CATEGORY_PUBLIC)
+       {
+               action = frame_body[1];
+               if (action == ACT_PUBLIC_VENDOR &&
+                   !memcmp(frame_body+2, P2P_OUI23A, 4)) {
+                       OUI_Subtype = frame_body[6];
+                       dialogToken = frame_body[7];
+                       is_p2p_frame = OUI_Subtype;
+                       p2p_ie = rtw_get_p2p_ie23a(
+                               (u8 *)buf+sizeof(struct ieee80211_hdr_3addr)+_PUBLIC_ACTION_IE_OFFSET_,
+                               len-sizeof(struct ieee80211_hdr_3addr)-_PUBLIC_ACTION_IE_OFFSET_,
+                               NULL, &p2p_ielen);
+
+                       switch (OUI_Subtype) {/* OUI Subtype */
+                       u8 *cont;
+                       uint cont_len;
+                       case P2P_GO_NEGO_REQ:
+                               DBG_8723A("RTW_%s:P2P_GO_NEGO_REQ, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken);
+                               break;
+                       case P2P_GO_NEGO_RESP:
+                               cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len);
+                               DBG_8723A("RTW_%s:P2P_GO_NEGO_RESP, dialogToken =%d, status:%d\n", (tx == true)?"Tx":"Rx", dialogToken, cont?*cont:-1);
+
+                               if (!tx)
+                                       pwdev_priv->provdisc_req_issued = false;
+                               break;
+                       case P2P_GO_NEGO_CONF:
+                               cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len);
+                               DBG_8723A("RTW_%s:P2P_GO_NEGO_CONF, dialogToken =%d, status:%d\n",
+                                         (tx == true)?"Tx":"Rx", dialogToken, cont?*cont:-1);
+                               break;
+                       case P2P_INVIT_REQ:
+                       {
+                               struct rtw_wdev_invit_info* invit_info = &pwdev_priv->invit_info;
+                               int flags = -1;
+                               int op_ch = 0;
+
+                               if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_INVITATION_FLAGS, NULL, &cont_len)))
+                                       flags = *cont;
+                               if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len)))
+                                       op_ch = *(cont+4);
+
+                               if (invit_info->token != dialogToken)
+                                       rtw_wdev_invit_info_init(invit_info);
+
+                               invit_info->token = dialogToken;
+                               invit_info->flags = (flags ==-1) ? 0x0 : flags;
+                               invit_info->req_op_ch = op_ch;
+
+                               DBG_8723A("RTW_%s:P2P_INVIT_REQ, dialogToken =%d, flags:0x%02x, op_ch:%d\n",
+                                         (tx) ? "Tx" : "Rx", dialogToken, flags, op_ch);
+                               break;
+                       }
+                       case P2P_INVIT_RESP:
+                       {
+                               struct rtw_wdev_invit_info* invit_info = &pwdev_priv->invit_info;
+                               int status = -1;
+                               int op_ch = 0;
+
+                               if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len)))
+                                       status = *cont;
+                               if ((cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_OPERATING_CH, NULL, &cont_len)))
+                                       op_ch = *(cont+4);
+
+                               if (invit_info->token != dialogToken) {
+                                       rtw_wdev_invit_info_init(invit_info);
+                               } else {
+                                       invit_info->token = 0;
+                                       invit_info->status = (status ==-1) ? 0xff : status;
+                                       invit_info->rsp_op_ch = op_ch;
+                               }
+
+                               DBG_8723A("RTW_%s:P2P_INVIT_RESP, dialogToken =%d, status:%d, op_ch:%d\n",
+                                         (tx == true)?"Tx":"Rx", dialogToken, status, op_ch);
+                               break;
+                       }
+                       case P2P_DEVDISC_REQ:
+                               DBG_8723A("RTW_%s:P2P_DEVDISC_REQ, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken);
+                               break;
+                       case P2P_DEVDISC_RESP:
+                               cont = rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_STATUS, NULL, &cont_len);
+                               DBG_8723A("RTW_%s:P2P_DEVDISC_RESP, dialogToken =%d, status:%d\n", (tx == true)?"Tx":"Rx", dialogToken, cont?*cont:-1);
+                               break;
+                       case P2P_PROVISION_DISC_REQ:
+                       {
+                               size_t frame_body_len = len - sizeof(struct ieee80211_hdr_3addr);
+                               u8 *p2p_ie;
+                               uint p2p_ielen = 0;
+                               uint contentlen = 0;
+
+                               DBG_8723A("RTW_%s:P2P_PROVISION_DISC_REQ, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken);
+
+                               pwdev_priv->provdisc_req_issued = false;
+
+                               p2p_ie = rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_,
+                                                          frame_body_len - _PUBLIC_ACTION_IE_OFFSET_,
+                                                          NULL, &p2p_ielen);
+                               if (p2p_ie) {
+                                       if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_GROUP_ID, NULL, &contentlen))
+                                               pwdev_priv->provdisc_req_issued = false;/* case: p2p_client join p2p GO */
+                                       else
+                                               pwdev_priv->provdisc_req_issued = true;/* case: p2p_devices connection before Nego req. */
+                               }
+                       }
+                               break;
+                       case P2P_PROVISION_DISC_RESP:
+                               DBG_8723A("RTW_%s:P2P_PROVISION_DISC_RESP, dialogToken =%d\n", (tx == true)?"Tx":"Rx", dialogToken);
+                               break;
+                       default:
+                               DBG_8723A("RTW_%s:OUI_Subtype =%d, dialogToken =%d\n", (tx == true)?"Tx":"Rx", OUI_Subtype, dialogToken);
+                               break;
+                       }
+
+               }
+
+       }
+       else if (category == WLAN_CATEGORY_VENDOR_SPECIFIC)
+       {
+               OUI_Subtype = frame_body[5];
+               dialogToken = frame_body[6];
+
+               is_p2p_frame = OUI_Subtype;
+
+               switch (OUI_Subtype) {
+               case P2P_NOTICE_OF_ABSENCE:
+                       DBG_8723A("RTW_%s:P2P_NOTICE_OF_ABSENCE, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken);
+                       break;
+               case P2P_PRESENCE_REQUEST:
+                       DBG_8723A("RTW_%s:P2P_PRESENCE_REQUEST, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken);
+                       break;
+               case P2P_PRESENCE_RESPONSE:
+                       DBG_8723A("RTW_%s:P2P_PRESENCE_RESPONSE, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken);
+                       break;
+               case P2P_GO_DISC_REQUEST:
+                       DBG_8723A("RTW_%s:P2P_GO_DISC_REQUEST, dialogToken =%d\n", (tx == true)?"TX":"RX", dialogToken);
+                       break;
+               default:
+                       DBG_8723A("RTW_%s:OUI_Subtype =%d, dialogToken =%d\n", (tx == true)?"TX":"RX", OUI_Subtype, dialogToken);
+                       break;
+               }
+
+       } else {
+               DBG_8723A("RTW_%s:action frame category =%d\n", (tx == true)?"TX":"RX", category);
+       }
+       return is_p2p_frame;
+}
+
+void rtw_init_cfg80211_wifidirect_info(struct rtw_adapter *padapter)
+{
+       struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo;
+
+       memset(pcfg80211_wdinfo, 0x00, sizeof(struct cfg80211_wifidirect_info));
+
+       setup_timer(&pcfg80211_wdinfo->remain_on_ch_timer,
+                   ro_ch_timer_process, (unsigned long)padapter);
+}
+
+void p2p_protocol_wk_hdl23a(struct rtw_adapter *padapter, int intCmdType)
+{
+       switch (intCmdType) {
+       case P2P_FIND_PHASE_WK:
+               find_phase_handler(padapter);
+               break;
+       case P2P_RESTORE_STATE_WK:
+               restore_p2p_state_handler(padapter);
+               break;
+       case P2P_PRE_TX_PROVDISC_PROCESS_WK:
+               pre_tx_provdisc_handler(padapter);
+               break;
+       case P2P_PRE_TX_INVITEREQ_PROCESS_WK:
+               pre_tx_invitereq_handler(padapter);
+               break;
+       case P2P_PRE_TX_NEGOREQ_PROCESS_WK:
+               pre_tx_negoreq_handler(padapter);
+               break;
+       case P2P_RO_CH_WK:
+               ro_ch_handler(padapter);
+               break;
+       }
+}
+
+#ifdef CONFIG_8723AU_P2P
+void process_p2p_ps_ie23a(struct rtw_adapter *padapter, u8 *IEs, u32 IELength)
+{
+       u8 * ies;
+       u32 ies_len;
+       u8 * p2p_ie;
+       u32     p2p_ielen = 0;
+       u8      noa_attr[MAX_P2P_IE_LEN] = { 0x00 };/*  NoA length should be n*(13) + 2 */
+       u32     attr_contentlen = 0;
+
+       struct wifidirect_info  *pwdinfo = &padapter->wdinfo;
+       u8      find_p2p = false, find_p2p_ps = false;
+       u8      noa_offset, noa_num, noa_index;
+
+
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+       {
+               return;
+       }
+       if (IELength <= _BEACON_IE_OFFSET_)
+               return;
+
+       ies = IEs + _BEACON_IE_OFFSET_;
+       ies_len = IELength - _BEACON_IE_OFFSET_;
+
+       p2p_ie = rtw_get_p2p_ie23a(ies, ies_len, NULL, &p2p_ielen);
+
+       while(p2p_ie)
+       {
+               find_p2p = true;
+               /*  Get Notice of Absence IE. */
+               if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_NOA, noa_attr, &attr_contentlen))
+               {
+                       find_p2p_ps = true;
+                       noa_index = noa_attr[0];
+
+                       if ((pwdinfo->p2p_ps_mode == P2P_PS_NONE) ||
+                               (noa_index != pwdinfo->noa_index))/*  if index change, driver should reconfigure related setting. */
+                       {
+                               pwdinfo->noa_index = noa_index;
+                               pwdinfo->opp_ps = noa_attr[1] >> 7;
+                               pwdinfo->ctwindow = noa_attr[1] & 0x7F;
+
+                               noa_offset = 2;
+                               noa_num = 0;
+                               /*  NoA length should be n*(13) + 2 */
+                               if (attr_contentlen > 2)
+                               {
+                                       while(noa_offset < attr_contentlen)
+                                       {
+                                               /* memcpy(&wifidirect_info->noa_count[noa_num], &noa_attr[noa_offset], 1); */
+                                               pwdinfo->noa_count[noa_num] = noa_attr[noa_offset];
+                                               noa_offset += 1;
+
+                                               memcpy(&pwdinfo->noa_duration[noa_num], &noa_attr[noa_offset], 4);
+                                               noa_offset += 4;
+
+                                               memcpy(&pwdinfo->noa_interval[noa_num], &noa_attr[noa_offset], 4);
+                                               noa_offset += 4;
+
+                                               memcpy(&pwdinfo->noa_start_time[noa_num], &noa_attr[noa_offset], 4);
+                                               noa_offset += 4;
+
+                                               noa_num++;
+                                       }
+                               }
+                               pwdinfo->noa_num = noa_num;
+
+                               if (pwdinfo->opp_ps == 1)
+                               {
+                                       pwdinfo->p2p_ps_mode = P2P_PS_CTWINDOW;
+                                       /*  driver should wait LPS for entering CTWindow */
+                                       if (padapter->pwrctrlpriv.bFwCurrentInPSMode == true)
+                                       {
+                                               p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 1);
+                                       }
+                               }
+                               else if (pwdinfo->noa_num > 0)
+                               {
+                                       pwdinfo->p2p_ps_mode = P2P_PS_NOA;
+                                       p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 1);
+                               }
+                               else if (pwdinfo->p2p_ps_mode > P2P_PS_NONE)
+                               {
+                                       p2p_ps_wk_cmd23a(padapter, P2P_PS_DISABLE, 1);
+                               }
+                       }
+
+                       break; /*  find target, just break. */
+               }
+
+               /* Get the next P2P IE */
+               p2p_ie = rtw_get_p2p_ie23a(p2p_ie+p2p_ielen, ies_len -(p2p_ie -ies + p2p_ielen), NULL, &p2p_ielen);
+
+       }
+
+       if (find_p2p == true)
+       {
+               if ((pwdinfo->p2p_ps_mode > P2P_PS_NONE) && (find_p2p_ps == false))
+               {
+                       p2p_ps_wk_cmd23a(padapter, P2P_PS_DISABLE, 1);
+               }
+       }
+
+
+}
+
+void p2p_ps_wk_hdl23a(struct rtw_adapter *padapter, u8 p2p_ps_state)
+{
+       struct pwrctrl_priv             *pwrpriv = &padapter->pwrctrlpriv;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+
+
+       /*  Pre action for p2p state */
+       switch (p2p_ps_state)
+       {
+               case P2P_PS_DISABLE:
+                       pwdinfo->p2p_ps_state = p2p_ps_state;
+
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
+
+                       pwdinfo->noa_index = 0;
+                       pwdinfo->ctwindow = 0;
+                       pwdinfo->opp_ps = 0;
+                       pwdinfo->noa_num = 0;
+                       pwdinfo->p2p_ps_mode = P2P_PS_NONE;
+                       if (padapter->pwrctrlpriv.bFwCurrentInPSMode == true)
+                       {
+                               if (pwrpriv->smart_ps == 0)
+                               {
+                                       pwrpriv->smart_ps = 2;
+                                       rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)&padapter->pwrctrlpriv.pwr_mode);
+                               }
+                       }
+                       break;
+               case P2P_PS_ENABLE:
+                       if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
+                               pwdinfo->p2p_ps_state = p2p_ps_state;
+
+                               if (pwdinfo->ctwindow > 0)
+                               {
+                                       if (pwrpriv->smart_ps != 0)
+                                       {
+                                               pwrpriv->smart_ps = 0;
+                                               DBG_8723A("%s(): Enter CTW, change SmartPS\n", __func__);
+                                               rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)&padapter->pwrctrlpriv.pwr_mode);
+                                       }
+                               }
+                               rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
+                       }
+                       break;
+               case P2P_PS_SCAN:
+               case P2P_PS_SCAN_DONE:
+               case P2P_PS_ALLSTASLEEP:
+                       if (pwdinfo->p2p_ps_mode > P2P_PS_NONE) {
+                               pwdinfo->p2p_ps_state = p2p_ps_state;
+                               rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_P2P_PS_OFFLOAD, (u8 *)(&p2p_ps_state));
+                       }
+                       break;
+               default:
+                       break;
+       }
+
+
+}
+
+u8 p2p_ps_wk_cmd23a(struct rtw_adapter*padapter, u8 p2p_ps_state, u8 enqueue)
+{
+       struct cmd_obj  *ph2c;
+       struct drvextra_cmd_parm        *pdrvextra_cmd_parm;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8      res = _SUCCESS;
+
+
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+               return res;
+
+       if (enqueue) {
+               ph2c = (struct cmd_obj *)kzalloc(sizeof(struct cmd_obj),
+                                                GFP_ATOMIC);
+               if (!ph2c) {
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               pdrvextra_cmd_parm = (struct drvextra_cmd_parm *)
+                       kzalloc(sizeof(struct drvextra_cmd_parm), GFP_ATOMIC);
+               if (pdrvextra_cmd_parm == NULL) {
+                       kfree(ph2c);
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               pdrvextra_cmd_parm->ec_id = P2P_PS_WK_CID;
+               pdrvextra_cmd_parm->type_size = p2p_ps_state;
+               pdrvextra_cmd_parm->pbuf = NULL;
+
+               init_h2fwcmd_w_parm_no_rsp(ph2c, pdrvextra_cmd_parm, GEN_CMD_CODE(_Set_Drv_Extra));
+
+               res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+       }
+       else
+       {
+               p2p_ps_wk_hdl23a(padapter, p2p_ps_state);
+       }
+
+exit:
+
+
+
+       return res;
+}
+#endif /*  CONFIG_8723AU_P2P */
+
+static void reset_ch_sitesurvey_timer_process(unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       struct  wifidirect_info *pwdinfo = &adapter->wdinfo;
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+               return;
+
+       DBG_8723A("[%s] In\n", __func__);
+       /*      Reset the operation channel information */
+       pwdinfo->rx_invitereq_info.operation_ch[0] = 0;
+       pwdinfo->rx_invitereq_info.scan_op_ch_only = 0;
+}
+
+static void reset_ch_sitesurvey_timer_process2(unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+               return;
+
+       DBG_8723A("[%s] In\n", __func__);
+       /*      Reset the operation channel information */
+       pwdinfo->p2p_info.operation_ch[0] = 0;
+       pwdinfo->p2p_info.scan_op_ch_only = 0;
+}
+
+static void restore_p2p_state_timer_process (unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       struct  wifidirect_info         *pwdinfo = &adapter->wdinfo;
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+               return;
+
+       p2p_protocol_wk_cmd23a(adapter, P2P_RESTORE_STATE_WK);
+}
+
+static void pre_tx_scan_timer_process (unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+               return;
+
+       spin_lock_bh(&pmlmepriv->lock);
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_PROVISION_DIS_REQ))
+       {
+               if (true == pwdinfo->tx_prov_disc_info.benable) /*      the provision discovery request frame is trigger to send or not */
+               {
+                       p2p_protocol_wk_cmd23a(adapter, P2P_PRE_TX_PROVDISC_PROCESS_WK);
+                       /* issue23a_probereq_p2p(adapter, NULL); */
+                       /* _set_timer(&pwdinfo->pre_tx_scan_timer, P2P_TX_PRESCAN_TIMEOUT); */
+               }
+       }
+       else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_GONEGO_ING))
+       {
+               if (true == pwdinfo->nego_req_info.benable)
+               {
+                       p2p_protocol_wk_cmd23a(adapter, P2P_PRE_TX_NEGOREQ_PROCESS_WK);
+               }
+       }
+       else if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_TX_INVITE_REQ))
+       {
+               if (true == pwdinfo->invitereq_info.benable)
+               {
+                       p2p_protocol_wk_cmd23a(adapter, P2P_PRE_TX_INVITEREQ_PROCESS_WK);
+               }
+       }
+       else
+       {
+               DBG_8723A("[%s] p2p_state is %d, ignore!!\n", __func__, rtw_p2p_state(pwdinfo));
+       }
+
+       spin_unlock_bh(&pmlmepriv->lock);
+}
+
+static void find_phase_timer_process (unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       struct  wifidirect_info         *pwdinfo = &adapter->wdinfo;
+
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+               return;
+
+       adapter->wdinfo.find_phase_state_exchange_cnt++;
+
+       p2p_protocol_wk_cmd23a(adapter, P2P_FIND_PHASE_WK);
+}
+
+void reset_global_wifidirect_info23a(struct rtw_adapter *padapter)
+{
+       struct wifidirect_info  *pwdinfo;
+
+       pwdinfo = &padapter->wdinfo;
+       pwdinfo->persistent_supported = 0;
+       pwdinfo->session_available = true;
+       pwdinfo->wfd_tdls_enable = 0;
+       pwdinfo->wfd_tdls_weaksec = 0;
+}
+
+#ifdef CONFIG_8723AU_P2P
+int rtw_init_wifi_display_info(struct rtw_adapter* padapter)
+{
+       int     res = _SUCCESS;
+       struct wifi_display_info *pwfd_info = &padapter->wfd_info;
+
+       /*  Used in P2P and TDLS */
+       pwfd_info->rtsp_ctrlport = 554;
+       pwfd_info->peer_rtsp_ctrlport = 0;      /*      Reset to 0 */
+       pwfd_info->wfd_enable = false;
+       pwfd_info->wfd_device_type = WFD_DEVINFO_PSINK;
+       pwfd_info->scan_result_type = SCAN_RESULT_P2P_ONLY;
+
+       /*  Used in P2P */
+       pwfd_info->peer_session_avail = true;
+       pwfd_info->wfd_pc = false;
+
+       /*  Used in TDLS */
+       memset(pwfd_info->ip_address, 0x00, 4);
+       memset(pwfd_info->peer_ip_address, 0x00, 4);
+       return res;
+}
+#endif /* CONFIG_8723AU_P2P */
+
+void rtw_init_wifidirect_timers23a(struct rtw_adapter* padapter)
+{
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+       setup_timer(&pwdinfo->find_phase_timer, find_phase_timer_process,
+                   (unsigned long)padapter);
+       setup_timer(&pwdinfo->restore_p2p_state_timer,
+                   restore_p2p_state_timer_process, (unsigned long)padapter);
+       setup_timer(&pwdinfo->pre_tx_scan_timer, pre_tx_scan_timer_process,
+                   (unsigned long)padapter);
+       setup_timer(&pwdinfo->reset_ch_sitesurvey,
+                   reset_ch_sitesurvey_timer_process, (unsigned long)padapter);
+       setup_timer(&pwdinfo->reset_ch_sitesurvey2,
+                   reset_ch_sitesurvey_timer_process2,
+                   (unsigned long)padapter);
+}
+
+void rtw_init_wifidirect_addrs23a(struct rtw_adapter* padapter, u8 *dev_addr, u8 *iface_addr)
+{
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+
+       /*init device&interface address */
+       if (dev_addr) {
+               memcpy(pwdinfo->device_addr, dev_addr, ETH_ALEN);
+       }
+       if (iface_addr) {
+               memcpy(pwdinfo->interface_addr, iface_addr, ETH_ALEN);
+       }
+#endif
+}
+
+void init_wifidirect_info23a(struct rtw_adapter *padapter, enum P2P_ROLE role)
+{
+       struct wifidirect_info  *pwdinfo;
+#ifdef CONFIG_8723AU_P2P
+       struct wifi_display_info        *pwfd_info = &padapter->wfd_info;
+#endif
+
+       pwdinfo = &padapter->wdinfo;
+
+       pwdinfo->padapter = padapter;
+
+       /*      1, 6, 11 are the social channel defined in the WiFi Direct specification. */
+       pwdinfo->social_chan[0] = 1;
+       pwdinfo->social_chan[1] = 6;
+       pwdinfo->social_chan[2] = 11;
+       pwdinfo->social_chan[3] = 0;    /*      channel 0 for scanning ending in site survey function. */
+
+       /*      Use the channel 11 as the listen channel */
+       pwdinfo->listen_channel = 11;
+
+       if (role == P2P_ROLE_DEVICE)
+       {
+               rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+               pwdinfo->intent = 1;
+               rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_LISTEN);
+       }
+       else if (role == P2P_ROLE_CLIENT)
+       {
+               rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+               pwdinfo->intent = 1;
+               rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+       }
+       else if (role == P2P_ROLE_GO)
+       {
+               rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+               pwdinfo->intent = 15;
+               rtw_p2p_set_pre_state(pwdinfo, P2P_STATE_GONEGO_OK);
+       }
+
+/*     Use the OFDM rate in the P2P probe response frame. (6(B), 9(B), 12, 18, 24, 36, 48, 54) */
+       pwdinfo->support_rate[0] = 0x8c;        /*      6(B) */
+       pwdinfo->support_rate[1] = 0x92;        /*      9(B) */
+       pwdinfo->support_rate[2] = 0x18;        /*      12 */
+       pwdinfo->support_rate[3] = 0x24;        /*      18 */
+       pwdinfo->support_rate[4] = 0x30;        /*      24 */
+       pwdinfo->support_rate[5] = 0x48;        /*      36 */
+       pwdinfo->support_rate[6] = 0x60;        /*      48 */
+       pwdinfo->support_rate[7] = 0x6c;        /*      54 */
+
+       memcpy((void*) pwdinfo->p2p_wildcard_ssid, "DIRECT-", 7);
+
+       memset(pwdinfo->device_name, 0x00, WPS_MAX_DEVICE_NAME_LEN);
+       pwdinfo->device_name_len = 0;
+
+       memset(&pwdinfo->invitereq_info, 0x00, sizeof(struct tx_invite_req_info));
+       pwdinfo->invitereq_info.token = 3;      /*      Token used for P2P invitation request frame. */
+
+       memset(&pwdinfo->inviteresp_info, 0x00, sizeof(struct tx_invite_resp_info));
+       pwdinfo->inviteresp_info.token = 0;
+
+       pwdinfo->profileindex = 0;
+       memset(&pwdinfo->profileinfo[ 0 ], 0x00, sizeof(struct profile_info) * P2P_MAX_PERSISTENT_GROUP_NUM);
+
+       rtw_p2p_findphase_ex_set(pwdinfo, P2P_FINDPHASE_EX_NONE);
+
+       pwdinfo->listen_dwell = (u8) ((jiffies % 3) + 1);
+       /* DBG_8723A("[%s] listen_dwell time is %d00ms\n", __func__, pwdinfo->listen_dwell); */
+
+       memset(&pwdinfo->tx_prov_disc_info, 0x00, sizeof(struct tx_provdisc_req_info));
+       pwdinfo->tx_prov_disc_info.wps_config_method_request = WPS_CM_NONE;
+
+       memset(&pwdinfo->nego_req_info, 0x00, sizeof(struct tx_nego_req_info));
+
+       pwdinfo->device_password_id_for_nego = WPS_DPID_PBC;
+       pwdinfo->negotiation_dialog_token = 1;
+
+       memset(pwdinfo->nego_ssid, 0x00, IEEE80211_MAX_SSID_LEN);
+       pwdinfo->nego_ssidlen = 0;
+
+       pwdinfo->ui_got_wps_info = P2P_NO_WPSINFO;
+#ifdef CONFIG_8723AU_P2P
+       pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY  | WPS_CONFIG_METHOD_PBC;
+       pwdinfo->wfd_info = pwfd_info;
+#else
+       pwdinfo->supported_wps_cm = WPS_CONFIG_METHOD_DISPLAY | WPS_CONFIG_METHOD_PBC | WPS_CONFIG_METHOD_KEYPAD;
+#endif /* CONFIG_8723AU_P2P */
+       pwdinfo->channel_list_attr_len = 0;
+       memset(pwdinfo->channel_list_attr, 0x00, 100);
+
+       memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, 0x00, 4);
+       memset(pwdinfo->rx_prov_disc_info.strconfig_method_desc_of_prov_disc_req, '0', 3);
+       memset(&pwdinfo->groupid_info, 0x00, sizeof(struct group_id_info));
+       pwdinfo->wfd_tdls_enable = 0;
+       memset(pwdinfo->p2p_peer_interface_addr, 0x00, ETH_ALEN);
+       memset(pwdinfo->p2p_peer_device_addr, 0x00, ETH_ALEN);
+
+       pwdinfo->rx_invitereq_info.operation_ch[0] = 0;
+       pwdinfo->rx_invitereq_info.operation_ch[1] = 0; /*      Used to indicate the scan end in site survey function */
+       pwdinfo->rx_invitereq_info.scan_op_ch_only = 0;
+       pwdinfo->p2p_info.operation_ch[0] = 0;
+       pwdinfo->p2p_info.operation_ch[1] = 0;                  /*      Used to indicate the scan end in site survey function */
+       pwdinfo->p2p_info.scan_op_ch_only = 0;
+}
+
+int rtw_p2p_enable23a(struct rtw_adapter *padapter, enum P2P_ROLE role)
+{
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       int ret = _SUCCESS;
+
+       if (role == P2P_ROLE_DEVICE || role == P2P_ROLE_CLIENT ||
+           role == P2P_ROLE_GO) {
+               /* leave IPS/Autosuspend */
+               if (_FAIL == rtw_pwr_wakeup(padapter)) {
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               /*      Added by Albert 2011/03/22 */
+               /*      In the P2P mode, the driver should not support the b mode. */
+               /*      So, the Tx packet shouldn't use the CCK rate */
+               update_tx_basic_rate23a(padapter, WIRELESS_11AGN);
+
+               /* Enable P2P function */
+               init_wifidirect_info23a(padapter, role);
+
+               rtw_hal_set_odm_var23a(padapter, HAL_ODM_P2P_STATE, NULL, true);
+               #ifdef CONFIG_8723AU_P2P
+               rtw_hal_set_odm_var23a(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, true);
+               #endif
+
+       }
+       else if (role == P2P_ROLE_DISABLE)
+       {
+               if (_FAIL == rtw_pwr_wakeup(padapter)) {
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               /* Disable P2P function */
+               if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+               {
+                       del_timer_sync(&pwdinfo->find_phase_timer);
+                       del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+                       del_timer_sync(&pwdinfo->pre_tx_scan_timer);
+                       del_timer_sync(&pwdinfo->reset_ch_sitesurvey);
+                       del_timer_sync(&pwdinfo->reset_ch_sitesurvey2);
+                       reset_ch_sitesurvey_timer_process((unsigned long)padapter);
+                       reset_ch_sitesurvey_timer_process2((unsigned long)padapter);
+                       rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE);
+                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_DISABLE);
+                       memset(&pwdinfo->rx_prov_disc_info, 0x00, sizeof(struct rx_provdisc_req_info));
+               }
+
+               rtw_hal_set_odm_var23a(padapter, HAL_ODM_P2P_STATE, NULL, false);
+               #ifdef CONFIG_8723AU_P2P
+               rtw_hal_set_odm_var23a(padapter, HAL_ODM_WIFI_DISPLAY_STATE, NULL, false);
+               #endif
+
+               /* Restore to initial setting. */
+               update_tx_basic_rate23a(padapter, padapter->registrypriv.wireless_mode);
+       }
+
+exit:
+       return ret;
+}
+
+#endif /* CONFIG_8723AU_P2P */
diff --git a/drivers/staging/rtl8723au/core/rtw_pwrctrl.c b/drivers/staging/rtl8723au/core/rtw_pwrctrl.c
new file mode 100644 (file)
index 0000000..8ddd67f
--- /dev/null
@@ -0,0 +1,689 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_PWRCTRL_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+#include <rtl8723a_hal.h>
+#endif
+
+void ips_enter23a(struct rtw_adapter * padapter)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
+       down(&pwrpriv->lock);
+
+       pwrpriv->bips_processing = true;
+
+       /*  syn ips_mode with request */
+       pwrpriv->ips_mode = pwrpriv->ips_mode_req;
+
+       pwrpriv->ips_enter23a_cnts++;
+       DBG_8723A("==>ips_enter23a cnts:%d\n", pwrpriv->ips_enter23a_cnts);
+#ifdef CONFIG_8723AU_BT_COEXIST
+       BTDM_TurnOffBtCoexistBeforeEnterIPS(padapter);
+#endif
+       if (rf_off == pwrpriv->change_rfpwrstate)
+       {
+               pwrpriv->bpower_saving = true;
+               DBG_8723A_LEVEL(_drv_always_, "nolinked power save enter\n");
+
+               if (pwrpriv->ips_mode == IPS_LEVEL_2)
+                       pwrpriv->bkeepfwalive = true;
+
+               rtw_ips_pwr_down23a(padapter);
+               pwrpriv->rf_pwrstate = rf_off;
+       }
+       pwrpriv->bips_processing = false;
+
+       up(&pwrpriv->lock);
+}
+
+int ips_leave23a(struct rtw_adapter * padapter)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       int result = _SUCCESS;
+       int keyid;
+
+       down(&pwrpriv->lock);
+
+       if ((pwrpriv->rf_pwrstate == rf_off) &&!pwrpriv->bips_processing)
+       {
+               pwrpriv->bips_processing = true;
+               pwrpriv->change_rfpwrstate = rf_on;
+               pwrpriv->ips_leave23a_cnts++;
+               DBG_8723A("==>ips_leave23a cnts:%d\n", pwrpriv->ips_leave23a_cnts);
+
+               if ((result = rtw_ips_pwr_up23a(padapter)) == _SUCCESS) {
+                       pwrpriv->rf_pwrstate = rf_on;
+               }
+               DBG_8723A_LEVEL(_drv_always_, "nolinked power save leave\n");
+
+               if ((_WEP40_ == psecuritypriv->dot11PrivacyAlgrthm) ||(_WEP104_ == psecuritypriv->dot11PrivacyAlgrthm))
+               {
+                       DBG_8723A("==>%s, channel(%d), processing(%x)\n", __func__, padapter->mlmeextpriv.cur_channel, pwrpriv->bips_processing);
+                       set_channel_bwmode23a(padapter, padapter->mlmeextpriv.cur_channel, HAL_PRIME_CHNL_OFFSET_DONT_CARE, HT_CHANNEL_WIDTH_20);
+                       for (keyid = 0;keyid<4;keyid++) {
+                               if (pmlmepriv->key_mask & CHKBIT(keyid)) {
+                                       if (keyid == psecuritypriv->dot11PrivacyKeyIndex)
+                                               result = rtw_set_key23a(padapter, psecuritypriv, keyid, 1);
+                                       else
+                                               result = rtw_set_key23a(padapter, psecuritypriv, keyid, 0);
+                               }
+                       }
+               }
+
+               DBG_8723A("==> ips_leave23a.....LED(0x%08x)...\n", rtw_read32(padapter, 0x4c));
+               pwrpriv->bips_processing = false;
+
+               pwrpriv->bkeepfwalive = false;
+               pwrpriv->bpower_saving = false;
+       }
+
+       up(&pwrpriv->lock);
+
+       return result;
+}
+
+
+static bool rtw_pwr_unassociated_idle(struct rtw_adapter *adapter)
+{
+       struct rtw_adapter *buddy = adapter->pbuddy_adapter;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       struct xmit_priv *pxmit_priv = &adapter->xmitpriv;
+       struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+
+       bool ret = false;
+
+       if (time_after_eq(adapter->pwrctrlpriv.ips_deny_time, jiffies))
+               goto exit;
+
+       if (check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)
+               || check_fwstate(pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS)
+               || check_fwstate(pmlmepriv, WIFI_AP_STATE)
+               || check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)
+               || !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)
+       ) {
+               goto exit;
+       }
+
+       /* consider buddy, if exist */
+       if (buddy) {
+               struct mlme_priv *b_pmlmepriv = &buddy->mlmepriv;
+               struct wifidirect_info *b_pwdinfo = &buddy->wdinfo;
+
+               if (check_fwstate(b_pmlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)
+                       || check_fwstate(b_pmlmepriv, WIFI_UNDER_LINKING|WIFI_UNDER_WPS)
+                       || check_fwstate(b_pmlmepriv, WIFI_AP_STATE)
+                       || check_fwstate(b_pmlmepriv, WIFI_ADHOC_MASTER_STATE|WIFI_ADHOC_STATE)
+                       || !rtw_p2p_chk_state(b_pwdinfo, P2P_STATE_NONE)
+               ) {
+                       goto exit;
+               }
+       }
+
+       if (pxmit_priv->free_xmitbuf_cnt != NR_XMITBUFF ||
+               pxmit_priv->free_xmit_extbuf_cnt != NR_XMIT_EXTBUFF) {
+               DBG_8723A_LEVEL(_drv_always_, "There are some pkts to transmit\n");
+               DBG_8723A_LEVEL(_drv_info_, "free_xmitbuf_cnt: %d, free_xmit_extbuf_cnt: %d\n",
+                       pxmit_priv->free_xmitbuf_cnt, pxmit_priv->free_xmit_extbuf_cnt);
+               goto exit;
+       }
+
+       ret = true;
+
+exit:
+       return ret;
+}
+
+void rtw_ps_processor23a(struct rtw_adapter*padapter)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       enum rt_rf_power_state rfpwrstate;
+
+       pwrpriv->ps_processing = true;
+
+       if (pwrpriv->bips_processing == true)
+               goto exit;
+
+       if (padapter->pwrctrlpriv.bHWPwrPindetect) {
+               rfpwrstate = RfOnOffDetect23a(padapter);
+               DBG_8723A("@@@@- #2  %s ==> rfstate:%s\n", __func__, (rfpwrstate == rf_on)?"rf_on":"rf_off");
+
+               if (rfpwrstate!= pwrpriv->rf_pwrstate) {
+                       if (rfpwrstate == rf_off) {
+                               pwrpriv->change_rfpwrstate = rf_off;
+                               pwrpriv->brfoffbyhw = true;
+                               padapter->bCardDisableWOHSM = true;
+                               rtw_hw_suspend23a(padapter);
+                       } else {
+                               pwrpriv->change_rfpwrstate = rf_on;
+                               rtw_hw_resume23a(padapter);
+                       }
+                       DBG_8723A("current rf_pwrstate(%s)\n", (pwrpriv->rf_pwrstate == rf_off)?"rf_off":"rf_on");
+               }
+               pwrpriv->pwr_state_check_cnts ++;
+       }
+
+       if (pwrpriv->ips_mode_req == IPS_NONE)
+               goto exit;
+
+       if (rtw_pwr_unassociated_idle(padapter) == false)
+               goto exit;
+
+       if ((pwrpriv->rf_pwrstate == rf_on) && ((pwrpriv->pwr_state_check_cnts%4) == 0))
+       {
+               DBG_8723A("==>%s .fw_state(%x)\n", __func__, get_fwstate(pmlmepriv));
+               pwrpriv->change_rfpwrstate = rf_off;
+               ips_enter23a(padapter);
+       }
+exit:
+       rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+       pwrpriv->ps_processing = false;
+       return;
+}
+
+static void pwr_state_check_handler(unsigned long data)
+{
+       struct rtw_adapter *padapter = (struct rtw_adapter *)data;
+       rtw_ps_cmd23a(padapter);
+}
+
+/*
+ *
+ * Parameters
+ *     padapter
+ *     pslv                    power state level, only could be PS_STATE_S0 ~ PS_STATE_S4
+ *
+ */
+void rtw_set_rpwm23a(struct rtw_adapter *padapter, u8 pslv)
+{
+       u8      rpwm;
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+
+
+
+       pslv = PS_STATE(pslv);
+
+       if (true == pwrpriv->btcoex_rfon)
+       {
+               if (pslv < PS_STATE_S4)
+                       pslv = PS_STATE_S3;
+       }
+
+       if (pwrpriv->rpwm == pslv) {
+               RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+                       ("%s: Already set rpwm[0x%02X], new = 0x%02X!\n", __func__, pwrpriv->rpwm, pslv));
+               return;
+       }
+
+       if ((padapter->bSurpriseRemoved == true) ||
+           (padapter->hw_init_completed == false)) {
+               RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+                                ("%s: SurpriseRemoved(%d) hw_init_completed(%d)\n",
+                                 __func__, padapter->bSurpriseRemoved, padapter->hw_init_completed));
+
+               pwrpriv->cpwm = PS_STATE_S4;
+
+               return;
+       }
+
+       if (padapter->bDriverStopped == true) {
+               RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+                                ("%s: change power state(0x%02X) when DriverStopped\n", __func__, pslv));
+
+               if (pslv < PS_STATE_S2) {
+                       RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_,
+                                        ("%s: Reject to enter PS_STATE(0x%02X) lower than S2 when DriverStopped!!\n", __func__, pslv));
+                       return;
+               }
+       }
+
+       rpwm = pslv | pwrpriv->tog;
+       RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+                        ("rtw_set_rpwm23a: rpwm = 0x%02x cpwm = 0x%02x\n", rpwm, pwrpriv->cpwm));
+
+       pwrpriv->rpwm = pslv;
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_SET_RPWM, (u8 *)(&rpwm));
+
+       pwrpriv->tog += 0x80;
+       pwrpriv->cpwm = pslv;
+
+
+}
+
+u8 PS_RDY_CHECK(struct rtw_adapter * padapter)
+{
+       unsigned long delta_time;
+       struct pwrctrl_priv     *pwrpriv = &padapter->pwrctrlpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       delta_time = jiffies - pwrpriv->DelayLPSLastTimeStamp;
+
+       if (delta_time < LPS_DELAY_TIME)
+       {
+               return false;
+       }
+
+       if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) ||
+               (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY) == true) ||
+               (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) ||
+               (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true) ||
+               (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true))
+               return false;
+       if (true == pwrpriv->bInSuspend)
+               return false;
+       if ((padapter->securitypriv.dot11AuthAlgrthm == dot11AuthAlgrthm_8021X) && (padapter->securitypriv.binstallGrpkey == false))
+       {
+               DBG_8723A("Group handshake still in progress !!!\n");
+               return false;
+       }
+       if (!rtw_cfg80211_pwr_mgmt(padapter))
+               return false;
+
+       return true;
+}
+
+void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode, u8 smart_ps, u8 bcn_ant_mode)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_8723AU_P2P */
+
+
+
+       RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_notice_,
+                        ("%s: PowerMode =%d Smart_PS =%d\n",
+                         __func__, ps_mode, smart_ps));
+
+       if (ps_mode > PM_Card_Disable) {
+               RT_TRACE(_module_rtl871x_pwrctrl_c_, _drv_err_, ("ps_mode:%d error\n", ps_mode));
+               return;
+       }
+
+       if (pwrpriv->pwr_mode == ps_mode)
+       {
+               if (PS_MODE_ACTIVE == ps_mode) return;
+
+               if ((pwrpriv->smart_ps == smart_ps) &&
+                       (pwrpriv->bcn_ant_mode == bcn_ant_mode))
+               {
+                       return;
+               }
+       }
+
+       if (ps_mode == PS_MODE_ACTIVE) {
+#ifdef CONFIG_8723AU_P2P
+               if (pwdinfo->opp_ps == 0)
+#endif /* CONFIG_8723AU_P2P */
+               {
+                       DBG_8723A("rtw_set_ps_mode23a: Leave 802.11 power save\n");
+
+                       pwrpriv->pwr_mode = ps_mode;
+                       rtw_set_rpwm23a(padapter, PS_STATE_S4);
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+                       pwrpriv->bFwCurrentInPSMode = false;
+               }
+       }
+       else
+       {
+               if (PS_RDY_CHECK(padapter)
+#ifdef CONFIG_8723AU_BT_COEXIST
+                       || (BT_1Ant(padapter) == true)
+#endif
+                       )
+               {
+                       DBG_8723A("%s: Enter 802.11 power save\n", __func__);
+
+                       pwrpriv->bFwCurrentInPSMode = true;
+                       pwrpriv->pwr_mode = ps_mode;
+                       pwrpriv->smart_ps = smart_ps;
+                       pwrpriv->bcn_ant_mode = bcn_ant_mode;
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_H2C_FW_PWRMODE, (u8 *)(&ps_mode));
+
+#ifdef CONFIG_8723AU_P2P
+                       /*  Set CTWindow after LPS */
+                       if (pwdinfo->opp_ps == 1)
+                               p2p_ps_wk_cmd23a(padapter, P2P_PS_ENABLE, 0);
+#endif /* CONFIG_8723AU_P2P */
+
+                       rtw_set_rpwm23a(padapter, PS_STATE_S2);
+               }
+       }
+
+
+}
+
+/*
+ * Return:
+ *     0:      Leave OK
+ *     -1:     Timeout
+ *     -2:     Other error
+ */
+s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms)
+{
+       unsigned long start_time, end_time;
+       u8 bAwake = false;
+       s32 err = 0;
+
+       start_time = jiffies;
+       end_time = start_time + msecs_to_jiffies(delay_ms);
+
+       while (1)
+       {
+               rtw23a_hal_get_hwreg(padapter, HW_VAR_FWLPS_RF_ON, &bAwake);
+               if (true == bAwake)
+                       break;
+
+               if (true == padapter->bSurpriseRemoved)
+               {
+                       err = -2;
+                       DBG_8723A("%s: device surprise removed!!\n", __func__);
+                       break;
+               }
+
+               if (time_after(jiffies, end_time)) {
+                       err = -1;
+                       DBG_8723A("%s: Wait for FW LPS leave more than %u ms!!!\n", __func__, delay_ms);
+                       break;
+               }
+               udelay(100);
+       }
+
+       return err;
+}
+
+/*     Description: */
+/*             Enter the leisure power save mode. */
+void LPS_Enter23a(struct rtw_adapter *padapter)
+{
+       struct pwrctrl_priv     *pwrpriv = &padapter->pwrctrlpriv;
+
+       if (!PS_RDY_CHECK(padapter))
+               return;
+
+       if (pwrpriv->bLeisurePs) {
+               /*  Idle for a while if we connect to AP a while ago. */
+               if (pwrpriv->LpsIdleCount >= 2) { /*   4 Sec */
+                       if (pwrpriv->pwr_mode == PS_MODE_ACTIVE) {
+                               pwrpriv->bpower_saving = true;
+                               DBG_8723A("%s smart_ps:%d\n", __func__, pwrpriv->smart_ps);
+                               /* For Tenda W311R IOT issue */
+                               rtw_set_ps_mode23a(padapter, pwrpriv->power_mgnt, pwrpriv->smart_ps, 0);
+                       }
+               } else {
+                       pwrpriv->LpsIdleCount++;
+               }
+       }
+}
+
+/*     Description: */
+/*             Leave the leisure power save mode. */
+void LPS_Leave23a(struct rtw_adapter *padapter)
+{
+#define LPS_LEAVE_TIMEOUT_MS 100
+
+       struct pwrctrl_priv     *pwrpriv = &padapter->pwrctrlpriv;
+
+       if (pwrpriv->bLeisurePs) {
+               if (pwrpriv->pwr_mode != PS_MODE_ACTIVE) {
+                       rtw_set_ps_mode23a(padapter, PS_MODE_ACTIVE, 0, 0);
+
+                       if (pwrpriv->pwr_mode == PS_MODE_ACTIVE)
+                               LPS_RF_ON_check23a(padapter, LPS_LEAVE_TIMEOUT_MS);
+               }
+       }
+
+       pwrpriv->bpower_saving = false;
+}
+
+/*  Description: Leave all power save mode: LPS, FwLPS, IPS if needed. */
+/*  Move code to function by tynli. 2010.03.26. */
+void LeaveAllPowerSaveMode23a(struct rtw_adapter *Adapter)
+{
+       struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
+       u8      enqueue = 0;
+
+
+
+       /* DBG_8723A("%s.....\n", __func__); */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       { /* connect */
+#ifdef CONFIG_8723AU_P2P
+               p2p_ps_wk_cmd23a(Adapter, P2P_PS_DISABLE, enqueue);
+#endif /* CONFIG_8723AU_P2P */
+
+               rtw_lps_ctrl_wk_cmd23a(Adapter, LPS_CTRL_LEAVE, enqueue);
+       }
+
+
+}
+
+void rtw_init_pwrctrl_priv23a(struct rtw_adapter *padapter)
+{
+       struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+       sema_init(&pwrctrlpriv->lock, 1);
+       pwrctrlpriv->rf_pwrstate = rf_on;
+       pwrctrlpriv->ips_enter23a_cnts = 0;
+       pwrctrlpriv->ips_leave23a_cnts = 0;
+       pwrctrlpriv->bips_processing = false;
+
+       pwrctrlpriv->ips_mode = padapter->registrypriv.ips_mode;
+       pwrctrlpriv->ips_mode_req = padapter->registrypriv.ips_mode;
+
+       pwrctrlpriv->pwr_state_check_interval = RTW_PWR_STATE_CHK_INTERVAL;
+       pwrctrlpriv->pwr_state_check_cnts = 0;
+       pwrctrlpriv->bInternalAutoSuspend = false;
+       pwrctrlpriv->bInSuspend = false;
+       pwrctrlpriv->bkeepfwalive = false;
+
+       pwrctrlpriv->LpsIdleCount = 0;
+       pwrctrlpriv->power_mgnt = padapter->registrypriv.power_mgnt;/*  PS_MODE_MIN; */
+       pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false;
+
+       pwrctrlpriv->bFwCurrentInPSMode = false;
+
+       pwrctrlpriv->rpwm = 0;
+       pwrctrlpriv->cpwm = PS_STATE_S4;
+
+       pwrctrlpriv->pwr_mode = PS_MODE_ACTIVE;
+       pwrctrlpriv->smart_ps = padapter->registrypriv.smart_ps;
+       pwrctrlpriv->bcn_ant_mode = 0;
+
+       pwrctrlpriv->tog = 0x80;
+
+       pwrctrlpriv->btcoex_rfon = false;
+
+       setup_timer(&pwrctrlpriv->pwr_state_check_timer,
+                   pwr_state_check_handler, (unsigned long)padapter);
+
+
+}
+
+void rtw_free_pwrctrl_priv(struct rtw_adapter *adapter)
+{
+}
+
+u8 rtw_interface_ps_func23a(struct rtw_adapter *padapter, enum hal_intf_ps_func efunc_id, u8* val)
+{
+       u8 bResult = true;
+       rtw_hal_intf_ps_func23a(padapter, efunc_id, val);
+
+       return bResult;
+}
+
+inline void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       pwrpriv->ips_deny_time = jiffies + msecs_to_jiffies(ms);
+}
+
+/*
+* rtw_pwr_wakeup - Wake the NIC up from: 1)IPS. 2)USB autosuspend
+* @adapter: pointer to _adapter structure
+* @ips_deffer_ms: the ms wiil prevent from falling into IPS after wakeup
+* Return _SUCCESS or _FAIL
+*/
+
+int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms, const char *caller)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       int ret = _SUCCESS;
+       unsigned long start = jiffies;
+       unsigned long new_deny_time;
+
+       new_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms);
+
+       if (time_before(pwrpriv->ips_deny_time, new_deny_time))
+               pwrpriv->ips_deny_time = new_deny_time;
+
+       if (pwrpriv->ps_processing) {
+               DBG_8723A("%s wait ps_processing...\n", __func__);
+               while (pwrpriv->ps_processing &&
+                      jiffies_to_msecs(jiffies - start) <= 3000)
+                       msleep(10);
+               if (pwrpriv->ps_processing)
+                       DBG_8723A("%s wait ps_processing timeout\n", __func__);
+               else
+                       DBG_8723A("%s wait ps_processing done\n", __func__);
+       }
+
+       if (rtw_hal_sreset_inprogress(padapter)) {
+               DBG_8723A("%s wait sreset_inprogress...\n", __func__);
+               while (rtw_hal_sreset_inprogress(padapter) &&
+                      jiffies_to_msecs(jiffies - start) <= 4000)
+                       msleep(10);
+               if (rtw_hal_sreset_inprogress(padapter))
+                       DBG_8723A("%s wait sreset_inprogress timeout\n", __func__);
+               else
+                       DBG_8723A("%s wait sreset_inprogress done\n", __func__);
+       }
+
+       if (pwrpriv->bInternalAutoSuspend == false && pwrpriv->bInSuspend) {
+               DBG_8723A("%s wait bInSuspend...\n", __func__);
+               while (pwrpriv->bInSuspend &&
+                      (jiffies_to_msecs(jiffies - start) <= 3000)) {
+                       msleep(10);
+               }
+               if (pwrpriv->bInSuspend)
+                       DBG_8723A("%s wait bInSuspend timeout\n", __func__);
+               else
+                       DBG_8723A("%s wait bInSuspend done\n", __func__);
+       }
+
+       /* System suspend is not allowed to wakeup */
+       if ((pwrpriv->bInternalAutoSuspend == false) && (true == pwrpriv->bInSuspend)) {
+               ret = _FAIL;
+               goto exit;
+       }
+
+       /* block??? */
+       if ((pwrpriv->bInternalAutoSuspend == true)  && (padapter->net_closed == true)) {
+               ret = _FAIL;
+               goto exit;
+       }
+
+       /* I think this should be check in IPS, LPS, autosuspend functions... */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) == true)
+       {
+               ret = _SUCCESS;
+               goto exit;
+       }
+
+       if (rf_off == pwrpriv->rf_pwrstate) {
+               DBG_8723A("%s call ips_leave23a....\n", __func__);
+               if (_FAIL ==  ips_leave23a(padapter)) {
+                       DBG_8723A("======> ips_leave23a fail.............\n");
+                       ret = _FAIL;
+                       goto exit;
+               }
+       }
+
+       /* TODO: the following checking need to be merged... */
+       if (padapter->bDriverStopped || !padapter->bup ||
+           !padapter->hw_init_completed) {
+               DBG_8723A("%s: bDriverStopped =%d, bup =%d, hw_init_completed "
+                         "=%u\n", caller, padapter->bDriverStopped,
+                         padapter->bup, padapter->hw_init_completed);
+               ret = false;
+               goto exit;
+       }
+
+exit:
+       new_deny_time = jiffies + msecs_to_jiffies(ips_deffer_ms);
+       if (time_before(pwrpriv->ips_deny_time, new_deny_time))
+               pwrpriv->ips_deny_time = new_deny_time;
+       return ret;
+}
+
+int rtw_pm_set_lps23a(struct rtw_adapter *padapter, u8 mode)
+{
+       int     ret = 0;
+       struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+       if (mode < PS_MODE_NUM)
+       {
+               if (pwrctrlpriv->power_mgnt != mode)
+               {
+                       if (PS_MODE_ACTIVE == mode)
+                       {
+                               LeaveAllPowerSaveMode23a(padapter);
+                       }
+                       else
+                       {
+                               pwrctrlpriv->LpsIdleCount = 2;
+                       }
+                       pwrctrlpriv->power_mgnt = mode;
+                       pwrctrlpriv->bLeisurePs = (PS_MODE_ACTIVE != pwrctrlpriv->power_mgnt)?true:false;
+               }
+       }
+       else
+       {
+               ret = -EINVAL;
+       }
+
+       return ret;
+}
+
+int rtw_pm_set_ips23a(struct rtw_adapter *padapter, u8 mode)
+{
+       struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+
+       if (mode == IPS_NORMAL || mode == IPS_LEVEL_2) {
+               rtw_ips_mode_req(pwrctrlpriv, mode);
+               DBG_8723A("%s %s\n", __func__, mode == IPS_NORMAL?"IPS_NORMAL":"IPS_LEVEL_2");
+               return 0;
+       }
+       else if (mode == IPS_NONE) {
+               rtw_ips_mode_req(pwrctrlpriv, mode);
+               DBG_8723A("%s %s\n", __func__, "IPS_NONE");
+               if ((padapter->bSurpriseRemoved == 0)&&_FAIL == rtw_pwr_wakeup(padapter))
+                       return -EFAULT;
+       }
+       else {
+               return -EINVAL;
+       }
+       return 0;
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_recv.c b/drivers/staging/rtl8723au/core/rtw_recv.c
new file mode 100644 (file)
index 0000000..0b2455e
--- /dev/null
@@ -0,0 +1,2471 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_RECV_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <mlme_osdep.h>
+#include <linux/ip.h>
+#include <linux/if_ether.h>
+#include <ethernet.h>
+#include <usb_ops.h>
+#include <linux/ieee80211.h>
+#include <wifi.h>
+
+void rtw_signal_stat_timer_hdl23a(unsigned long data);
+
+void _rtw_init_sta_recv_priv23a(struct sta_recv_priv *psta_recvpriv)
+{
+
+
+
+       spin_lock_init(&psta_recvpriv->lock);
+
+       /* for (i = 0; i<MAX_RX_NUMBLKS; i++) */
+       /*      _rtw_init_queue23a(&psta_recvpriv->blk_strms[i]); */
+
+       _rtw_init_queue23a(&psta_recvpriv->defrag_q);
+
+
+}
+
+int _rtw_init_recv_priv23a(struct recv_priv *precvpriv,
+                       struct rtw_adapter *padapter)
+{
+       struct recv_frame *precvframe;
+       int i;
+       int res = _SUCCESS;
+
+
+
+       /*  We don't need to memset padapter->XXX to zero, because
+           adapter is allocated by rtw_zvmalloc(). */
+       /* memset((unsigned char *)precvpriv, 0, sizeof (struct  recv_priv)); */
+
+       spin_lock_init(&precvpriv->lock);
+
+       _rtw_init_queue23a(&precvpriv->free_recv_queue);
+       _rtw_init_queue23a(&precvpriv->recv_pending_queue);
+       _rtw_init_queue23a(&precvpriv->uc_swdec_pending_queue);
+
+       precvpriv->adapter = padapter;
+
+       precvpriv->free_recvframe_cnt = NR_RECVFRAME;
+
+       precvpriv->pallocated_frame_buf =
+               rtw_zvmalloc(NR_RECVFRAME * sizeof(struct recv_frame));
+
+       if (precvpriv->pallocated_frame_buf == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       precvframe = precvpriv->pallocated_frame_buf;
+
+       for (i = 0; i < NR_RECVFRAME ; i++) {
+               INIT_LIST_HEAD(&precvframe->list);
+
+               list_add_tail(&precvframe->list,
+                             &precvpriv->free_recv_queue.queue);
+
+               res = rtw_os_recv_resource_alloc23a(padapter, precvframe);
+
+               precvframe->adapter = padapter;
+               precvframe++;
+       }
+
+       precvpriv->rx_pending_cnt = 1;
+
+       sema_init(&precvpriv->allrxreturnevt, 0);
+
+       res = rtw_hal_init23a_recv_priv(padapter);
+
+       setup_timer(&precvpriv->signal_stat_timer, rtw_signal_stat_timer_hdl23a,
+                   (unsigned long)padapter);
+
+       precvpriv->signal_stat_sampling_interval = 1000; /* ms */
+
+       rtw_set_signal_stat_timer(precvpriv);
+
+exit:
+
+
+
+       return res;
+}
+
+void _rtw_free_recv_priv23a (struct recv_priv *precvpriv)
+{
+       struct rtw_adapter *padapter = precvpriv->adapter;
+
+
+
+       rtw_free_uc_swdec_pending_queue23a(padapter);
+
+       if (precvpriv->pallocated_frame_buf) {
+               rtw_vmfree(precvpriv->pallocated_frame_buf,
+                          NR_RECVFRAME * sizeof(struct recv_frame));
+       }
+
+       rtw_hal_free_recv_priv23a(padapter);
+
+
+}
+
+struct recv_frame *rtw_alloc_recvframe23a(struct rtw_queue *pfree_recv_queue)
+{
+       struct recv_frame *pframe;
+       struct list_head *plist, *phead;
+       struct rtw_adapter *padapter;
+       struct recv_priv *precvpriv;
+
+       spin_lock_bh(&pfree_recv_queue->lock);
+
+       if (_rtw_queue_empty23a(pfree_recv_queue) == true)
+               pframe = NULL;
+       else {
+               phead = get_list_head(pfree_recv_queue);
+
+               plist = phead->next;
+
+               pframe = container_of(plist, struct recv_frame, list);
+
+               list_del_init(&pframe->list);
+               padapter = pframe->adapter;
+               if (padapter) {
+                       precvpriv = &padapter->recvpriv;
+                       if (pfree_recv_queue == &precvpriv->free_recv_queue)
+                               precvpriv->free_recvframe_cnt--;
+               }
+       }
+
+       spin_unlock_bh(&pfree_recv_queue->lock);
+
+       return pframe;
+}
+
+int rtw_free_recvframe23a(struct recv_frame *precvframe, struct rtw_queue *pfree_recv_queue)
+{
+       struct rtw_adapter *padapter = precvframe->adapter;
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+
+
+
+       if (precvframe->pkt) {
+               dev_kfree_skb_any(precvframe->pkt);/* free skb by driver */
+               precvframe->pkt = NULL;
+       }
+
+       spin_lock_bh(&pfree_recv_queue->lock);
+
+       list_del_init(&precvframe->list);
+
+       list_add_tail(&precvframe->list, get_list_head(pfree_recv_queue));
+
+       if (padapter) {
+               if (pfree_recv_queue == &precvpriv->free_recv_queue)
+                       precvpriv->free_recvframe_cnt++;
+       }
+
+       spin_unlock_bh(&pfree_recv_queue->lock);
+
+
+
+       return _SUCCESS;
+}
+
+int rtw_enqueue_recvframe23a(struct recv_frame *precvframe, struct rtw_queue *queue)
+{
+       struct rtw_adapter *padapter = precvframe->adapter;
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+
+       spin_lock_bh(&queue->lock);
+
+       list_del_init(&precvframe->list);
+
+       list_add_tail(&precvframe->list, get_list_head(queue));
+
+       if (padapter) {
+               if (queue == &precvpriv->free_recv_queue)
+                       precvpriv->free_recvframe_cnt++;
+       }
+
+       spin_unlock_bh(&queue->lock);
+
+       return _SUCCESS;
+}
+
+/*
+caller : defrag ; recvframe_chk_defrag23a in recv_thread  (passive)
+pframequeue: defrag_queue : will be accessed in recv_thread  (passive)
+
+using spinlock to protect
+
+*/
+
+void rtw_free_recvframe23a_queue(struct rtw_queue *pframequeue,  struct rtw_queue *pfree_recv_queue)
+{
+       struct recv_frame *hdr;
+       struct list_head *plist, *phead, *ptmp;
+
+
+       spin_lock(&pframequeue->lock);
+
+       phead = get_list_head(pframequeue);
+       plist = phead->next;
+
+       list_for_each_safe(plist, ptmp, phead) {
+               hdr = container_of(plist, struct recv_frame, list);
+               rtw_free_recvframe23a(hdr, pfree_recv_queue);
+       }
+
+       spin_unlock(&pframequeue->lock);
+
+
+}
+
+u32 rtw_free_uc_swdec_pending_queue23a(struct rtw_adapter *adapter)
+{
+       u32 cnt = 0;
+       struct recv_frame *pending_frame;
+       while ((pending_frame = rtw_alloc_recvframe23a(&adapter->recvpriv.uc_swdec_pending_queue))) {
+               rtw_free_recvframe23a(pending_frame,
+                                  &adapter->recvpriv.free_recv_queue);
+               DBG_8723A("%s: dequeue uc_swdec_pending_queue\n", __func__);
+               cnt++;
+       }
+
+       return cnt;
+}
+
+int rtw_enqueue_recvbuf23a_to_head(struct recv_buf *precvbuf, struct rtw_queue *queue)
+{
+       spin_lock_bh(&queue->lock);
+
+       list_del_init(&precvbuf->list);
+       list_add(&precvbuf->list, get_list_head(queue));
+
+       spin_unlock_bh(&queue->lock);
+
+       return _SUCCESS;
+}
+
+int rtw_enqueue_recvbuf23a(struct recv_buf *precvbuf, struct rtw_queue *queue)
+{
+       unsigned long irqL;
+       spin_lock_irqsave(&queue->lock, irqL);
+
+       list_del_init(&precvbuf->list);
+
+       list_add_tail(&precvbuf->list, get_list_head(queue));
+       spin_unlock_irqrestore(&queue->lock, irqL);
+       return _SUCCESS;
+}
+
+struct recv_buf *rtw_dequeue_recvbuf23a (struct rtw_queue *queue)
+{
+       unsigned long irqL;
+       struct recv_buf *precvbuf;
+       struct list_head *plist, *phead;
+
+       spin_lock_irqsave(&queue->lock, irqL);
+
+       if (_rtw_queue_empty23a(queue) == true) {
+               precvbuf = NULL;
+       } else {
+               phead = get_list_head(queue);
+
+               plist = phead->next;
+
+               precvbuf = container_of(plist, struct recv_buf, list);
+
+               list_del_init(&precvbuf->list);
+       }
+
+       spin_unlock_irqrestore(&queue->lock, irqL);
+
+       return precvbuf;
+}
+
+int recvframe_chkmic(struct rtw_adapter *adapter,
+                    struct recv_frame *precvframe);
+int recvframe_chkmic(struct rtw_adapter *adapter,
+                    struct recv_frame *precvframe) {
+
+       int     i, res = _SUCCESS;
+       u32     datalen;
+       u8      miccode[8];
+       u8      bmic_err = false, brpt_micerror = true;
+       u8      *pframe, *payload,*pframemic;
+       u8      *mickey;
+       /* u8   *iv, rxdata_key_idx = 0; */
+       struct  sta_info *stainfo;
+       struct  rx_pkt_attrib *prxattrib = &precvframe->attrib;
+       struct  security_priv *psecuritypriv = &adapter->securitypriv;
+
+       struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+
+       stainfo = rtw_get_stainfo23a(&adapter->stapriv, &prxattrib->ta[0]);
+
+       if (prxattrib->encrypt == _TKIP_) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                        ("\n recvframe_chkmic:prxattrib->encrypt == _TKIP_\n"));
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                        ("\n recvframe_chkmic:da = 0x%02x:0x%02x:0x%02x:0x%02x:"
+                         "0x%02x:0x%02x\n", prxattrib->ra[0],
+                         prxattrib->ra[1], prxattrib->ra[2], prxattrib->ra[3],
+                         prxattrib->ra[4], prxattrib->ra[5]));
+
+               /* calculate mic code */
+               if (stainfo != NULL) {
+                       if (is_multicast_ether_addr(prxattrib->ra)) {
+                               mickey = &psecuritypriv->dot118021XGrprxmickey[prxattrib->key_index].skey[0];
+
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                        ("\n recvframe_chkmic: bcmc key\n"));
+
+                               if (psecuritypriv->binstallGrpkey == false) {
+                                       res = _FAIL;
+                                       RT_TRACE(_module_rtl871x_recv_c_,
+                                                _drv_err_,
+                                                ("\n recvframe_chkmic:didn't "
+                                                 "install group key!!!!!!\n"));
+                                       DBG_8723A("\n recvframe_chkmic:didn't "
+                                                 "install group key!!!!!!\n");
+                                       goto exit;
+                               }
+                       } else {
+                               mickey = &stainfo->dot11tkiprxmickey.skey[0];
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                        ("\n recvframe_chkmic: unicast "
+                                         "key\n"));
+                       }
+
+                       /* icv_len included the mic code */
+                       datalen = precvframe->pkt->len-prxattrib->
+                               hdrlen-prxattrib->iv_len-prxattrib->icv_len - 8;
+                       pframe = precvframe->pkt->data;
+                       payload = pframe + prxattrib->hdrlen +
+                               prxattrib->iv_len;
+
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                ("\n prxattrib->iv_len =%d prxattrib->icv_len ="
+                                 "%d\n", prxattrib->iv_len,
+                                 prxattrib->icv_len));
+
+                       /* care the length of the data */
+                       rtw_seccalctkipmic23a(mickey, pframe, payload,
+                                          datalen, &miccode[0],
+                                          (unsigned char)prxattrib->priority);
+
+                       pframemic = payload + datalen;
+
+                       bmic_err = false;
+
+                       for (i = 0; i < 8; i++) {
+                               if (miccode[i] != *(pframemic + i)) {
+                                       RT_TRACE(_module_rtl871x_recv_c_,
+                                                _drv_err_,
+                                                ("recvframe_chkmic:miccode"
+                                                 "[%d](%02x) != *(pframemic+"
+                                                 "%d)(%02x) ", i, miccode[i],
+                                                 i, *(pframemic + i)));
+                                       bmic_err = true;
+                               }
+                       }
+
+                       if (bmic_err == true) {
+                               int i;
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                        ("\n *(pframemic-8)-*(pframemic-1) ="
+                                         "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:"
+                                         "0x%02x:0x%02x:0x%02x\n",
+                                         *(pframemic - 8), *(pframemic - 7),
+                                         *(pframemic - 6), *(pframemic - 5),
+                                         *(pframemic - 4), *(pframemic - 3),
+                                         *(pframemic - 2), *(pframemic - 1)));
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                        ("\n *(pframemic-16)-*(pframemic-9) ="
+                                         "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:"
+                                         "0x%02x:0x%02x:0x%02x\n",
+                                         *(pframemic - 16), *(pframemic - 15),
+                                         *(pframemic - 14), *(pframemic - 13),
+                                         *(pframemic - 12), *(pframemic - 11),
+                                         *(pframemic - 10), *(pframemic - 9)));
+
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                        ("\n ====== demp packet (len =%d) ======"
+                                         "\n", precvframe->pkt->len));
+                               for (i = 0; i < precvframe->pkt->len; i = i + 8) {
+                                       RT_TRACE(_module_rtl871x_recv_c_,
+                                                _drv_err_, ("0x%02x:0x%02x:0x"
+                                                           "%02x:0x%02x:0x%0"
+                                                           "2x:0x%02x:0x%02x"
+                                                           ":0x%02x",
+                                                           *(precvframe->pkt->data+i),*(precvframe->pkt->data+i+1),
+                                                           *(precvframe->pkt->data+i+2),*(precvframe->pkt->data+i+3),
+                                                           *(precvframe->pkt->data+i+4),*(precvframe->pkt->data+i+5),
+                                                           *(precvframe->pkt->data+i+6),*(precvframe->pkt->data+i+7)));
+                               }
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                        ("\n ====== demp packet end [len =%d]"
+                                         "======\n", precvframe->pkt->len));
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                        ("\n hrdlen =%d,\n",
+                                         prxattrib->hdrlen));
+
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                        ("ra = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%."
+                                         "2x 0x%.2x psecuritypriv->"
+                                         "binstallGrpkey =%d ",
+                                         prxattrib->ra[0], prxattrib->ra[1],
+                                         prxattrib->ra[2], prxattrib->ra[3],
+                                         prxattrib->ra[4], prxattrib->ra[5],
+                                         psecuritypriv->binstallGrpkey));
+
+                               /*  double check key_index for some timing
+                                   issue, cannot compare with
+                                   psecuritypriv->dot118021XGrpKeyid also
+                                   cause timing issue */
+                               if ((is_multicast_ether_addr(prxattrib->ra)) &&
+                                   (prxattrib->key_index !=
+                                    pmlmeinfo->key_index))
+                                       brpt_micerror = false;
+
+                               if ((prxattrib->bdecrypted == true) &&
+                                   (brpt_micerror == true)) {
+                                       rtw_handle_tkip_mic_err23a(adapter, (u8)is_multicast_ether_addr(prxattrib->ra));
+                                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" mic error :prxattrib->bdecrypted =%d ", prxattrib->bdecrypted));
+                                       DBG_8723A(" mic error :prxattrib->"
+                                                 "bdecrypted =%d\n",
+                                                 prxattrib->bdecrypted);
+                               } else {
+                                       RT_TRACE(_module_rtl871x_recv_c_,
+                                                _drv_err_,
+                                                (" mic error :prxattrib->"
+                                                 "bdecrypted =%d ",
+                                                 prxattrib->bdecrypted));
+                                       DBG_8723A(" mic error :prxattrib->"
+                                                 "bdecrypted =%d\n",
+                                                 prxattrib->bdecrypted);
+                               }
+
+                               res = _FAIL;
+                       } else {
+                               /* mic checked ok */
+                               if ((psecuritypriv->bcheck_grpkey == false) &&
+                                   (is_multicast_ether_addr(prxattrib->ra))) {
+                                       psecuritypriv->bcheck_grpkey = true;
+                                       RT_TRACE(_module_rtl871x_recv_c_,
+                                                _drv_err_,
+                                                ("psecuritypriv->bcheck_grp"
+                                                 "key = true"));
+                               }
+                       }
+               } else {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("recvframe_chkmic: rtw_get_stainfo23a =="
+                                 "NULL!!!\n"));
+               }
+
+               skb_trim(precvframe->pkt, precvframe->pkt->len - 8);
+       }
+
+exit:
+
+
+
+       return res;
+}
+
+/* decrypt and set the ivlen, icvlen of the recv_frame */
+struct recv_frame *decryptor(struct rtw_adapter *padapter,
+                            struct recv_frame *precv_frame);
+struct recv_frame *decryptor(struct rtw_adapter *padapter,
+                            struct recv_frame *precv_frame)
+{
+       struct rx_pkt_attrib *prxattrib = &precv_frame->attrib;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct recv_frame *return_packet = precv_frame;
+       u32 res = _SUCCESS;
+
+
+       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                ("prxstat->decrypted =%x prxattrib->encrypt = 0x%03x\n",
+                 prxattrib->bdecrypted, prxattrib->encrypt));
+
+       if (prxattrib->encrypt > 0) {
+               u8 *iv = precv_frame->pkt->data + prxattrib->hdrlen;
+               prxattrib->key_index = (((iv[3]) >> 6) & 0x3);
+
+               if (prxattrib->key_index > WEP_KEYS) {
+                       DBG_8723A("prxattrib->key_index(%d) > WEP_KEYS\n",
+                                 prxattrib->key_index);
+
+                       switch (prxattrib->encrypt) {
+                       case _WEP40_:
+                       case _WEP104_:
+                               prxattrib->key_index =
+                                       psecuritypriv->dot11PrivacyKeyIndex;
+                               break;
+                       case _TKIP_:
+                       case _AES_:
+                       default:
+                               prxattrib->key_index =
+                                       psecuritypriv->dot118021XGrpKeyid;
+                               break;
+                       }
+               }
+       }
+
+       if ((prxattrib->encrypt > 0) && ((prxattrib->bdecrypted == 0))) {
+               psecuritypriv->hw_decrypted = false;
+               switch (prxattrib->encrypt) {
+               case _WEP40_:
+               case _WEP104_:
+                       rtw_wep_decrypt23a(padapter, precv_frame);
+                       break;
+               case _TKIP_:
+                       res = rtw_tkip_decrypt23a(padapter, precv_frame);
+                       break;
+               case _AES_:
+                       res = rtw_aes_decrypt23a(padapter, precv_frame);
+                       break;
+               default:
+                       break;
+               }
+       } else if (prxattrib->bdecrypted == 1 && prxattrib->encrypt > 0 &&
+                  (psecuritypriv->busetkipkey == 1 ||
+                   prxattrib->encrypt != _TKIP_)) {
+                       psecuritypriv->hw_decrypted = true;
+       }
+
+       if (res == _FAIL) {
+               rtw_free_recvframe23a(return_packet,
+                                  &padapter->recvpriv.free_recv_queue);
+               return_packet = NULL;
+       }
+
+
+
+       return return_packet;
+}
+
+/* set the security information in the recv_frame */
+static struct recv_frame *portctrl(struct rtw_adapter *adapter,
+                                  struct recv_frame *precv_frame)
+{
+       u8 *psta_addr = NULL, *ptr;
+       uint auth_alg;
+       struct recv_frame *pfhdr;
+       struct sta_info *psta;
+       struct sta_priv *pstapriv ;
+       struct recv_frame *prtnframe;
+       u16 ether_type = 0;
+       u16 eapol_type = 0x888e;/* for Funia BD's WPA issue */
+       struct rx_pkt_attrib *pattrib;
+
+       pstapriv = &adapter->stapriv;
+       psta = rtw_get_stainfo23a(pstapriv, psta_addr);
+
+       auth_alg = adapter->securitypriv.dot11AuthAlgrthm;
+
+       ptr = precv_frame->pkt->data;
+       pfhdr = precv_frame;
+       pattrib = &pfhdr->attrib;
+       psta_addr = pattrib->ta;
+
+       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                ("########portctrl:adapter->securitypriv.dot11AuthAlgrthm ="
+                 "%d\n", adapter->securitypriv.dot11AuthAlgrthm));
+
+       if (auth_alg == 2) {
+               if ((psta != NULL) && (psta->ieee8021x_blocked)) {
+                       /* blocked */
+                       /* only accept EAPOL frame */
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                ("########portctrl:psta->ieee8021x_blocked =="
+                                 "1\n"));
+
+                       prtnframe = precv_frame;
+
+                       /* get ether_type */
+                       ptr = ptr + pfhdr->attrib.hdrlen + LLC_HEADER_SIZE;
+                       memcpy(&ether_type, ptr, 2);
+                       ether_type = ntohs((unsigned short)ether_type);
+
+                       if (ether_type == eapol_type) {
+                               prtnframe = precv_frame;
+                       } else {
+                               /* free this frame */
+                               rtw_free_recvframe23a(precv_frame,
+                                                  &adapter->recvpriv.free_recv_queue);
+                               prtnframe = NULL;
+                       }
+               } else {
+                       /* allowed */
+                       /* check decryption status, and decrypt the frame if needed */
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                ("########portctrl:psta->ieee8021x_blocked =="
+                                 "0\n"));
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                ("portctrl:precv_frame->hdr.attrib.privacy ="
+                                 "%x\n", precv_frame->attrib.privacy));
+
+                       if (pattrib->bdecrypted == 0) {
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                        ("portctrl:prxstat->decrypted =%x\n",
+                                         pattrib->bdecrypted));
+                       }
+
+                       prtnframe = precv_frame;
+                       /* check is the EAPOL frame or not (Rekey) */
+                       if (ether_type == eapol_type) {
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                                        ("########portctrl:ether_type == "
+                                         "0x888e\n"));
+                               /* check Rekey */
+
+                               prtnframe = precv_frame;
+                       } else {
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                        ("########portctrl:ether_type = 0x%04x"
+                                         "\n", ether_type));
+                       }
+               }
+       } else {
+               prtnframe = precv_frame;
+       }
+
+
+
+               return prtnframe;
+}
+
+int recv_decache(struct recv_frame *precv_frame, u8 bretry,
+                struct stainfo_rxcache *prxcache);
+int recv_decache(struct recv_frame *precv_frame, u8 bretry,
+                struct stainfo_rxcache *prxcache)
+{
+       int tid = precv_frame->attrib.priority;
+
+       u16 seq_ctrl = ((precv_frame->attrib.seq_num & 0xffff) << 4) |
+               (precv_frame->attrib.frag_num & 0xf);
+
+
+
+       if (tid > 15) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                        ("recv_decache, (tid>15)! seq_ctrl = 0x%x, tid = 0x%x\n",
+                         seq_ctrl, tid));
+
+               return _FAIL;
+       }
+
+       if (1) { /* if (bretry) */
+               if (seq_ctrl == prxcache->tid_rxseq[tid]) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                                ("recv_decache, seq_ctrl = 0x%x, tid = 0x%x, "
+                                 "tid_rxseq = 0x%x\n",
+                                 seq_ctrl, tid, prxcache->tid_rxseq[tid]));
+
+                       return _FAIL;
+               }
+       }
+
+       prxcache->tid_rxseq[tid] = seq_ctrl;
+
+
+
+       return _SUCCESS;
+}
+
+void process23a_pwrbit_data(struct rtw_adapter *padapter,
+                        struct recv_frame *precv_frame);
+void process23a_pwrbit_data(struct rtw_adapter *padapter,
+                        struct recv_frame *precv_frame)
+{
+#ifdef CONFIG_8723AU_AP_MODE
+       unsigned char pwrbit;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct sta_info *psta = NULL;
+
+       psta = rtw_get_stainfo23a(pstapriv, pattrib->src);
+
+       if (psta) {
+               pwrbit = ieee80211_has_pm(hdr->frame_control);
+
+               if (pwrbit) {
+                       if (!(psta->state & WIFI_SLEEP_STATE))
+                               stop_sta_xmit23a(padapter, psta);
+               } else {
+                       if (psta->state & WIFI_SLEEP_STATE)
+                               wakeup_sta_to_xmit23a(padapter, psta);
+               }
+       }
+
+#endif
+}
+
+void process_wmmps_data(struct rtw_adapter *padapter,
+                       struct recv_frame *precv_frame);
+void process_wmmps_data(struct rtw_adapter *padapter,
+                       struct recv_frame *precv_frame)
+{
+#ifdef CONFIG_8723AU_AP_MODE
+       struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct sta_info *psta = NULL;
+
+       psta = rtw_get_stainfo23a(pstapriv, pattrib->src);
+
+       if (!psta)
+               return;
+
+
+       if (!psta->qos_option)
+               return;
+
+       if (!(psta->qos_info & 0xf))
+               return;
+
+       if (psta->state & WIFI_SLEEP_STATE) {
+               u8 wmmps_ac = 0;
+
+               switch (pattrib->priority) {
+               case 1:
+               case 2:
+                       wmmps_ac = psta->uapsd_bk & BIT(1);
+                       break;
+               case 4:
+               case 5:
+                       wmmps_ac = psta->uapsd_vi & BIT(1);
+                       break;
+               case 6:
+               case 7:
+                       wmmps_ac = psta->uapsd_vo & BIT(1);
+                       break;
+               case 0:
+               case 3:
+               default:
+                       wmmps_ac = psta->uapsd_be & BIT(1);
+                       break;
+               }
+
+               if (wmmps_ac) {
+                       if (psta->sleepq_ac_len > 0) {
+                               /* process received triggered frame */
+                               xmit_delivery_enabled_frames23a(padapter, psta);
+                       } else {
+                               /* issue one qos null frame with More data bit = 0 and the EOSP bit set (= 1) */
+                               issue_qos_nulldata23a(padapter, psta->hwaddr,
+                                                  (u16)pattrib->priority,
+                                                  0, 0);
+                       }
+               }
+       }
+
+#endif
+}
+
+static void count_rx_stats(struct rtw_adapter *padapter,
+                          struct recv_frame *prframe, struct sta_info *sta)
+{
+       int sz;
+       struct sta_info *psta = NULL;
+       struct stainfo_stats *pstats = NULL;
+       struct rx_pkt_attrib *pattrib = & prframe->attrib;
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+
+       sz = prframe->pkt->len;
+       precvpriv->rx_bytes += sz;
+
+       padapter->mlmepriv.LinkDetectInfo.NumRxOkInPeriod++;
+
+       if ((!is_broadcast_ether_addr(pattrib->dst)) &&
+           (!is_multicast_ether_addr(pattrib->dst)))
+               padapter->mlmepriv.LinkDetectInfo.NumRxUnicastOkInPeriod++;
+
+       if (sta)
+               psta = sta;
+       else
+               psta = prframe->psta;
+
+       if (psta) {
+               pstats = &psta->sta_stats;
+
+               pstats->rx_data_pkts++;
+               pstats->rx_bytes += sz;
+       }
+}
+
+static int sta2sta_data_frame(struct rtw_adapter *adapter,
+                             struct recv_frame *precv_frame,
+                             struct sta_info**psta)
+{
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       int ret = _SUCCESS;
+       struct rx_pkt_attrib *pattrib = & precv_frame->attrib;
+       struct sta_priv *pstapriv = &adapter->stapriv;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       u8 *mybssid  = get_bssid(pmlmepriv);
+       u8 *myhwaddr = myid(&adapter->eeprompriv);
+       u8 *sta_addr = NULL;
+       int bmcast = is_multicast_ether_addr(pattrib->dst);
+
+
+
+       if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
+               (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
+
+               /*  filter packets that SA is myself or multicast or broadcast */
+               if (ether_addr_equal(myhwaddr, pattrib->src)) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                (" SA == myself\n"));
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               if (!ether_addr_equal(myhwaddr, pattrib->dst) && !bmcast) {
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               if (ether_addr_equal(pattrib->bssid, "\x0\x0\x0\x0\x0\x0") ||
+                   ether_addr_equal(mybssid, "\x0\x0\x0\x0\x0\x0") ||
+                   !ether_addr_equal(pattrib->bssid, mybssid)) {
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               sta_addr = pattrib->src;
+       } else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) {
+               /*  For Station mode, sa and bssid should always be BSSID,
+                   and DA is my mac-address */
+               if (!ether_addr_equal(pattrib->bssid, pattrib->src)) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("bssid != TA under STATION_MODE; drop "
+                                 "pkt\n"));
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               sta_addr = pattrib->bssid;
+
+       } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
+               if (bmcast) {
+                       /*  For AP mode, if DA == MCAST, then BSSID should be also MCAST */
+                       if (!is_multicast_ether_addr(pattrib->bssid)) {
+                               ret = _FAIL;
+                               goto exit;
+                       }
+               } else { /*  not mc-frame */
+                       /*  For AP mode, if DA is non-MCAST, then it must
+                           be BSSID, and bssid == BSSID */
+                       if (!ether_addr_equal(pattrib->bssid, pattrib->dst)) {
+                               ret = _FAIL;
+                               goto exit;
+                       }
+
+                       sta_addr = pattrib->src;
+               }
+       } else if (check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) {
+               ether_addr_copy(pattrib->dst, hdr->addr1);
+               ether_addr_copy(pattrib->src, hdr->addr2);
+               ether_addr_copy(pattrib->bssid, hdr->addr3);
+               ether_addr_copy(pattrib->ra, pattrib->dst);
+               ether_addr_copy(pattrib->ta, pattrib->src);
+
+               sta_addr = mybssid;
+       } else {
+               ret  = _FAIL;
+       }
+
+       if (bmcast)
+               *psta = rtw_get_bcmc_stainfo23a(adapter);
+       else
+               *psta = rtw_get_stainfo23a(pstapriv, sta_addr); /*  get ap_info */
+
+       if (*psta == NULL) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("can't get psta under sta2sta_data_frame ; drop pkt\n"));
+               ret = _FAIL;
+               goto exit;
+       }
+
+exit:
+
+       return ret;
+}
+
+int ap2sta_data_frame(struct rtw_adapter *adapter,
+                     struct recv_frame *precv_frame,
+                     struct sta_info **psta);
+int ap2sta_data_frame(struct rtw_adapter *adapter,
+                     struct recv_frame *precv_frame,
+                     struct sta_info **psta)
+{
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct rx_pkt_attrib *pattrib = & precv_frame->attrib;
+       int ret = _SUCCESS;
+       struct sta_priv *pstapriv = &adapter->stapriv;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       u8 *mybssid  = get_bssid(pmlmepriv);
+       u8 *myhwaddr = myid(&adapter->eeprompriv);
+       int bmcast = is_multicast_ether_addr(pattrib->dst);
+
+
+
+       if ((check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true) &&
+           (check_fwstate(pmlmepriv, _FW_LINKED) == true ||
+            check_fwstate(pmlmepriv, _FW_UNDER_LINKING) == true)) {
+
+               /* filter packets that SA is myself or multicast or broadcast */
+               if (ether_addr_equal(myhwaddr, pattrib->src)) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                (" SA == myself\n"));
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               /*  da should be for me */
+               if (!ether_addr_equal(myhwaddr, pattrib->dst) && !bmcast) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                               (" ap2sta_data_frame:  compare DA fail; DA ="
+                                MAC_FMT"\n", MAC_ARG(pattrib->dst)));
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               /*  check BSSID */
+               if (ether_addr_equal(pattrib->bssid, "\x0\x0\x0\x0\x0\x0") ||
+                   ether_addr_equal(mybssid, "\x0\x0\x0\x0\x0\x0") ||
+                   !ether_addr_equal(pattrib->bssid, mybssid)) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                               (" ap2sta_data_frame:  compare BSSID fail ; "
+                                "BSSID ="MAC_FMT"\n", MAC_ARG(pattrib->bssid)));
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                ("mybssid ="MAC_FMT"\n", MAC_ARG(mybssid)));
+
+                       if (!bmcast) {
+                               DBG_8723A("issue_deauth23a to the nonassociated "
+                                         "ap =" MAC_FMT " for the reason(7)\n",
+                                         MAC_ARG(pattrib->bssid));
+                               issue_deauth23a(adapter, pattrib->bssid,
+                                            WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+                       }
+
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               if (bmcast)
+                       *psta = rtw_get_bcmc_stainfo23a(adapter);
+               else
+                       /*  get ap_info */
+                       *psta = rtw_get_stainfo23a(pstapriv, pattrib->bssid);
+
+               if (*psta == NULL) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("ap2sta: can't get psta under STATION_MODE ;"
+                                 " drop pkt\n"));
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               if (ieee80211_is_nullfunc(hdr->frame_control)) {
+                       /* No data, will not indicate to upper layer,
+                          temporily count it here */
+                       count_rx_stats(adapter, precv_frame, *psta);
+                       ret = RTW_RX_HANDLED;
+                       goto exit;
+               }
+
+       } else if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true) &&
+                  (check_fwstate(pmlmepriv, _FW_LINKED) == true)) {
+               ether_addr_copy(pattrib->dst, hdr->addr1);
+               ether_addr_copy(pattrib->src, hdr->addr2);
+               ether_addr_copy(pattrib->bssid, hdr->addr3);
+               ether_addr_copy(pattrib->ra, pattrib->dst);
+               ether_addr_copy(pattrib->ta, pattrib->src);
+
+               /*  */
+               ether_addr_copy(pattrib->bssid,  mybssid);
+
+               /*  get sta_info */
+               *psta = rtw_get_stainfo23a(pstapriv, pattrib->bssid);
+               if (*psta == NULL) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("can't get psta under MP_MODE ; drop pkt\n"));
+                       ret = _FAIL;
+                       goto exit;
+               }
+       } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
+               /* Special case */
+               ret = RTW_RX_HANDLED;
+               goto exit;
+       } else {
+               if (ether_addr_equal(myhwaddr, pattrib->dst) && !bmcast) {
+                       *psta = rtw_get_stainfo23a(pstapriv, pattrib->bssid);
+                       if (*psta == NULL) {
+                               DBG_8723A("issue_deauth23a to the ap =" MAC_FMT
+                                         " for the reason(7)\n",
+                                         MAC_ARG(pattrib->bssid));
+
+                               issue_deauth23a(adapter, pattrib->bssid,
+                                            WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+                       }
+               }
+
+               ret = _FAIL;
+       }
+
+exit:
+
+
+
+       return ret;
+}
+
+int sta2ap_data_frame(struct rtw_adapter *adapter,
+                     struct recv_frame *precv_frame,
+                     struct sta_info **psta);
+int sta2ap_data_frame(struct rtw_adapter *adapter,
+                     struct recv_frame *precv_frame,
+                     struct sta_info **psta)
+{
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       struct rx_pkt_attrib *pattrib = & precv_frame->attrib;
+       struct sta_priv *pstapriv = &adapter->stapriv;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       unsigned char *mybssid = get_bssid(pmlmepriv);
+       int ret = _SUCCESS;
+
+
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
+               /* For AP mode, RA = BSSID, TX = STA(SRC_ADDR), A3 = DST_ADDR */
+               if (!ether_addr_equal(pattrib->bssid, mybssid)) {
+                       ret = _FAIL;
+                       goto exit;
+               }
+
+               *psta = rtw_get_stainfo23a(pstapriv, pattrib->src);
+               if (*psta == NULL) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("can't get psta under AP_MODE; drop pkt\n"));
+                       DBG_8723A("issue_deauth23a to sta =" MAC_FMT
+                                 " for the reason(7)\n",
+                                 MAC_ARG(pattrib->src));
+
+                       issue_deauth23a(adapter, pattrib->src,
+                                    WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+
+                       ret = RTW_RX_HANDLED;
+                       goto exit;
+               }
+
+               process23a_pwrbit_data(adapter, precv_frame);
+
+               /* We only get here if it's a data frame, so no need to
+                * confirm data frame type first */
+               if (ieee80211_is_data_qos(hdr->frame_control))
+                       process_wmmps_data(adapter, precv_frame);
+
+               if (ieee80211_is_nullfunc(hdr->frame_control)) {
+                       /* No data, will not indicate to upper layer,
+                          temporily count it here */
+                       count_rx_stats(adapter, precv_frame, *psta);
+                       ret = RTW_RX_HANDLED;
+                       goto exit;
+               }
+       } else {
+               u8 *myhwaddr = myid(&adapter->eeprompriv);
+               if (!ether_addr_equal(pattrib->ra, myhwaddr)) {
+                       ret = RTW_RX_HANDLED;
+                       goto exit;
+               }
+               DBG_8723A("issue_deauth23a to sta =" MAC_FMT " for the reason(7)\n",
+                         MAC_ARG(pattrib->src));
+               issue_deauth23a(adapter, pattrib->src,
+                            WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+               ret = RTW_RX_HANDLED;
+               goto exit;
+       }
+
+exit:
+
+
+
+       return ret;
+}
+
+int validate_recv_ctrl_frame(struct rtw_adapter *padapter,
+                            struct recv_frame *precv_frame);
+int validate_recv_ctrl_frame(struct rtw_adapter *padapter,
+                            struct recv_frame *precv_frame)
+{
+#ifdef CONFIG_8723AU_AP_MODE
+       struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *pframe = skb->data;
+
+       if (!ieee80211_is_ctl(hdr->frame_control))
+               return _FAIL;
+
+       /* receive the frames that ra(a1) is my address */
+       if (!ether_addr_equal(hdr->addr1, myid(&padapter->eeprompriv)))
+               return _FAIL;
+
+       /* only handle ps-poll */
+       if (ieee80211_is_pspoll(hdr->frame_control)) {
+               u16 aid;
+               u8 wmmps_ac = 0;
+               struct sta_info *psta = NULL;
+
+               aid = GetAid(pframe);
+               psta = rtw_get_stainfo23a(pstapriv, hdr->addr2);
+
+               if ((!psta) || (psta->aid != aid))
+                       return _FAIL;
+
+               /* for rx pkt statistics */
+               psta->sta_stats.rx_ctrl_pkts++;
+
+               switch (pattrib->priority) {
+               case 1:
+               case 2:
+                       wmmps_ac = psta->uapsd_bk & BIT(0);
+                       break;
+               case 4:
+               case 5:
+                       wmmps_ac = psta->uapsd_vi & BIT(0);
+                       break;
+               case 6:
+               case 7:
+                       wmmps_ac = psta->uapsd_vo & BIT(0);
+                       break;
+               case 0:
+               case 3:
+               default:
+                       wmmps_ac = psta->uapsd_be & BIT(0);
+                       break;
+               }
+
+               if (wmmps_ac)
+                       return _FAIL;
+
+               if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
+                       DBG_8723A("%s alive check-rx ps-poll\n", __func__);
+                       psta->expire_to = pstapriv->expire_to;
+                       psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+               }
+
+               if ((psta->state & WIFI_SLEEP_STATE) &&
+                   (pstapriv->sta_dz_bitmap & CHKBIT(psta->aid))) {
+                       struct list_head *xmitframe_plist, *xmitframe_phead;
+                       struct xmit_frame *pxmitframe;
+                       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+                       spin_lock_bh(&pxmitpriv->lock);
+
+                       xmitframe_phead = get_list_head(&psta->sleep_q);
+                       xmitframe_plist = xmitframe_phead->next;
+
+                       if (!list_empty(xmitframe_phead)) {
+                               pxmitframe = container_of(xmitframe_plist,
+                                                         struct xmit_frame,
+                                                         list);
+
+                               xmitframe_plist = xmitframe_plist->next;
+
+                               list_del_init(&pxmitframe->list);
+
+                               psta->sleepq_len--;
+
+                               if (psta->sleepq_len>0)
+                                       pxmitframe->attrib.mdata = 1;
+                                else
+                                       pxmitframe->attrib.mdata = 0;
+
+                               pxmitframe->attrib.triggered = 1;
+
+                               /* DBG_8723A("handling ps-poll, q_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */
+
+                               rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe);
+
+                               if (psta->sleepq_len == 0) {
+                                       pstapriv->tim_bitmap &= ~CHKBIT(psta->aid);
+
+                                       /* DBG_8723A("after handling ps-poll, tim =%x\n", pstapriv->tim_bitmap); */
+
+                                       /* upate BCN for TIM IE */
+                                       /* update_BCNTIM(padapter); */
+                                       update_beacon23a(padapter, _TIM_IE_,
+                                                     NULL, false);
+                               }
+
+                               /* spin_unlock_bh(&psta->sleep_q.lock); */
+                               spin_unlock_bh(&pxmitpriv->lock);
+
+                       } else {
+                               /* spin_unlock_bh(&psta->sleep_q.lock); */
+                               spin_unlock_bh(&pxmitpriv->lock);
+
+                               /* DBG_8723A("no buffered packets to xmit\n"); */
+                               if (pstapriv->tim_bitmap & CHKBIT(psta->aid)) {
+                                       if (psta->sleepq_len == 0) {
+                                               DBG_8723A("no buffered packets "
+                                                         "to xmit\n");
+
+                                               /* issue nulldata with More data bit = 0 to indicate we have no buffered packets */
+                                               issue_nulldata23a(padapter,
+                                                              psta->hwaddr,
+                                                              0, 0, 0);
+                                       } else {
+                                               DBG_8723A("error!psta->sleepq"
+                                                         "_len =%d\n",
+                                                         psta->sleepq_len);
+                                               psta->sleepq_len = 0;
+                                       }
+
+                                       pstapriv->tim_bitmap &= ~CHKBIT(psta->aid);
+
+                                       /* upate BCN for TIM IE */
+                                       /* update_BCNTIM(padapter); */
+                                       update_beacon23a(padapter, _TIM_IE_,
+                                                     NULL, false);
+                               }
+                       }
+               }
+       }
+
+#endif
+       return _FAIL;
+}
+
+struct recv_frame* recvframe_chk_defrag23a(struct rtw_adapter *padapter,
+                                       struct recv_frame *precv_frame);
+int validate_recv_mgnt_frame(struct rtw_adapter *padapter,
+                            struct recv_frame *precv_frame);
+int validate_recv_mgnt_frame(struct rtw_adapter *padapter,
+                            struct recv_frame *precv_frame)
+{
+       struct sta_info *psta;
+       struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
+       /* struct mlme_priv *pmlmepriv = &adapter->mlmepriv; */
+
+       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                ("+validate_recv_mgnt_frame\n"));
+
+       precv_frame = recvframe_chk_defrag23a(padapter, precv_frame);
+       if (precv_frame == NULL) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                        ("%s: fragment packet\n", __func__));
+               return _SUCCESS;
+       }
+
+       skb = precv_frame->pkt;
+       hdr = (struct ieee80211_hdr *) skb->data;
+
+               /* for rx pkt statistics */
+       psta = rtw_get_stainfo23a(&padapter->stapriv, hdr->addr2);
+       if (psta) {
+               psta->sta_stats.rx_mgnt_pkts++;
+
+               if (ieee80211_is_beacon(hdr->frame_control))
+                       psta->sta_stats.rx_beacon_pkts++;
+               else if (ieee80211_is_probe_req(hdr->frame_control))
+                       psta->sta_stats.rx_probereq_pkts++;
+               else if (ieee80211_is_probe_resp(hdr->frame_control)) {
+                       if (ether_addr_equal(padapter->eeprompriv.mac_addr,
+                                   hdr->addr1))
+                               psta->sta_stats.rx_probersp_pkts++;
+                       else if (is_broadcast_ether_addr(hdr->addr1) ||
+                                is_multicast_ether_addr(hdr->addr1))
+                               psta->sta_stats.rx_probersp_bm_pkts++;
+                       else
+                               psta->sta_stats.rx_probersp_uo_pkts++;
+               }
+       }
+
+       mgt_dispatcher23a(padapter, precv_frame);
+
+       return _SUCCESS;
+}
+
+int validate_recv_data_frame(struct rtw_adapter *adapter,
+                            struct recv_frame *precv_frame);
+int validate_recv_data_frame(struct rtw_adapter *adapter,
+                            struct recv_frame *precv_frame)
+{
+       u8 bretry;
+       u8 *psa, *pda, *pbssid;
+       struct sta_info *psta = NULL;
+       u8 *ptr = precv_frame->pkt->data;
+       struct rx_pkt_attrib *pattrib = & precv_frame->attrib;
+       struct security_priv *psecuritypriv = &adapter->securitypriv;
+       int ret = _SUCCESS;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+
+
+
+       bretry = ieee80211_has_retry(hdr->frame_control);
+       pda = ieee80211_get_DA(hdr);
+       psa = ieee80211_get_SA(hdr);
+       pbssid = get_hdr_bssid(ptr);
+
+       if (pbssid == NULL) {
+               ret = _FAIL;
+               goto exit;
+       }
+
+       ether_addr_copy(pattrib->dst, pda);
+       ether_addr_copy(pattrib->src, psa);
+
+       ether_addr_copy(pattrib->bssid, pbssid);
+
+       switch (pattrib->to_fr_ds)
+       {
+       case 0:
+               ether_addr_copy(pattrib->ra, pda);
+               ether_addr_copy(pattrib->ta, psa);
+               ret = sta2sta_data_frame(adapter, precv_frame, &psta);
+               break;
+
+       case 1:
+               ether_addr_copy(pattrib->ra, pda);
+               ether_addr_copy(pattrib->ta, pbssid);
+               ret = ap2sta_data_frame(adapter, precv_frame, &psta);
+               break;
+
+       case 2:
+               ether_addr_copy(pattrib->ra, pbssid);
+               ether_addr_copy(pattrib->ta, psa);
+               ret = sta2ap_data_frame(adapter, precv_frame, &psta);
+               break;
+
+       case 3:
+               ether_addr_copy(pattrib->ra, hdr->addr1);
+               ether_addr_copy(pattrib->ta, hdr->addr2);
+               ret = _FAIL;
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, (" case 3\n"));
+               break;
+
+       default:
+               ret = _FAIL;
+               break;
+       }
+
+       if ((ret == _FAIL) || (ret == RTW_RX_HANDLED))
+               goto exit;
+
+       if (!psta) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                        (" after to_fr_ds_chk; psta == NULL\n"));
+               ret = _FAIL;
+               goto exit;
+       }
+
+       /* psta->rssi = prxcmd->rssi; */
+       /* psta->signal_quality = prxcmd->sq; */
+       precv_frame->psta = psta;
+
+       pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
+       if (ieee80211_has_a4(hdr->frame_control))
+               pattrib->hdrlen += ETH_ALEN;
+
+       /* parsing QC field */
+       if (pattrib->qos == 1) {
+               __le16 *qptr = (__le16 *)ieee80211_get_qos_ctl(hdr);
+               u16 qos_ctrl = le16_to_cpu(*qptr);
+
+               pattrib->priority = qos_ctrl & IEEE80211_QOS_CTL_TID_MASK;
+               pattrib->ack_policy = (qos_ctrl >> 5) & 3;
+               pattrib->amsdu =
+                       (qos_ctrl & IEEE80211_QOS_CTL_A_MSDU_PRESENT) >> 7;
+               pattrib->hdrlen += IEEE80211_QOS_CTL_LEN;
+
+               if (pattrib->priority != 0 && pattrib->priority != 3) {
+                       adapter->recvpriv.bIsAnyNonBEPkts = true;
+               }
+       } else {
+               pattrib->priority = 0;
+               pattrib->ack_policy = 0;
+               pattrib->amsdu = 0;
+       }
+
+       if (pattrib->order) { /* HT-CTRL 11n */
+               pattrib->hdrlen += 4;
+       }
+
+       precv_frame->preorder_ctrl = &psta->recvreorder_ctrl[pattrib->priority];
+
+       /*  decache, drop duplicate recv packets */
+       if (recv_decache(precv_frame, bretry, &psta->sta_recvpriv.rxcache) ==
+           _FAIL) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                        ("decache : drop pkt\n"));
+               ret = _FAIL;
+               goto exit;
+       }
+
+       if (pattrib->privacy) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                        ("validate_recv_data_frame:pattrib->privacy =%x\n",
+                        pattrib->privacy));
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                        ("\n ^^^^^^^^^^^is_multicast_ether_addr"
+                         "(pattrib->ra(0x%02x)) =%d^^^^^^^^^^^^^^^6\n",
+                         pattrib->ra[0],
+                         is_multicast_ether_addr(pattrib->ra)));
+
+               GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt,
+                              is_multicast_ether_addr(pattrib->ra));
+
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                        ("\n pattrib->encrypt =%d\n", pattrib->encrypt));
+
+               switch (pattrib->encrypt)
+               {
+               case _WEP40_:
+               case _WEP104_:
+                       pattrib->iv_len = 4;
+                       pattrib->icv_len = 4;
+                       break;
+               case _TKIP_:
+                       pattrib->iv_len = 8;
+                       pattrib->icv_len = 4;
+                       break;
+               case _AES_:
+                       pattrib->iv_len = 8;
+                       pattrib->icv_len = 8;
+                       break;
+               case _SMS4_:
+                       pattrib->iv_len = 18;
+                       pattrib->icv_len = 16;
+                       break;
+               default:
+                       pattrib->iv_len = 0;
+                       pattrib->icv_len = 0;
+                       break;
+               }
+       } else {
+               pattrib->encrypt = 0;
+               pattrib->iv_len = 0;
+               pattrib->icv_len = 0;
+       }
+
+exit:
+
+
+
+       return ret;
+}
+
+static void dump_rx_pkt(struct sk_buff *skb, u16 type, int level)
+{
+       int i;
+       u8 *ptr;
+
+       if ((level == 1) ||
+           ((level == 2) && (type == IEEE80211_FTYPE_MGMT)) ||
+           ((level == 3) && (type == IEEE80211_FTYPE_DATA))) {
+
+               ptr = skb->data;
+
+               DBG_8723A("#############################\n");
+
+               for (i = 0; i < 64; i = i + 8)
+                       DBG_8723A("%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:\n",
+                                 *(ptr + i), *(ptr + i + 1), *(ptr + i + 2),
+                                 *(ptr + i + 3), *(ptr + i + 4),
+                                 *(ptr + i + 5), *(ptr + i + 6),
+                                 *(ptr + i + 7));
+               DBG_8723A("#############################\n");
+       }
+}
+
+static int validate_recv_frame(struct rtw_adapter *adapter,
+                              struct recv_frame *precv_frame)
+{
+       /* shall check frame subtype, to / from ds, da, bssid */
+
+       /* then call check if rx seq/frag. duplicated. */
+       u8 type;
+       u8 subtype;
+       int retval = _SUCCESS;
+       struct rx_pkt_attrib *pattrib = & precv_frame->attrib;
+       struct sk_buff *skb = precv_frame->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 ver;
+       u8 bDumpRxPkt;
+       u16 seq_ctrl, fctl;
+
+       fctl = le16_to_cpu(hdr->frame_control);
+       ver = fctl & IEEE80211_FCTL_VERS;
+       type = fctl & IEEE80211_FCTL_FTYPE;
+       subtype = fctl & IEEE80211_FCTL_STYPE;
+
+       /* add version chk */
+       if (ver != 0) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                        ("validate_recv_data_frame fail! (ver!= 0)\n"));
+               retval = _FAIL;
+               goto exit;
+       }
+
+       pattrib->to_fr_ds = get_tofr_ds(hdr->frame_control);
+
+       seq_ctrl = le16_to_cpu(hdr->seq_ctrl);
+       pattrib->frag_num = seq_ctrl & IEEE80211_SCTL_FRAG;
+       pattrib->seq_num = seq_ctrl >> 4;
+
+       pattrib->pw_save = ieee80211_has_pm(hdr->frame_control);
+       pattrib->mfrag = ieee80211_has_morefrags(hdr->frame_control);
+       pattrib->mdata = ieee80211_has_moredata(hdr->frame_control);
+       pattrib->privacy = ieee80211_has_protected(hdr->frame_control);
+       pattrib->order = ieee80211_has_order(hdr->frame_control);
+
+       rtw_hal_get_def_var23a(adapter, HAL_DEF_DBG_DUMP_RXPKT, &bDumpRxPkt);
+
+       if (unlikely(bDumpRxPkt == 1))
+               dump_rx_pkt(skb, type, bDumpRxPkt);
+
+       switch (type)
+       {
+       case IEEE80211_FTYPE_MGMT:
+               retval = validate_recv_mgnt_frame(adapter, precv_frame);
+               if (retval == _FAIL) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("validate_recv_mgnt_frame fail\n"));
+               }
+               retval = _FAIL; /*  only data frame return _SUCCESS */
+               break;
+       case IEEE80211_FTYPE_CTL:
+               retval = validate_recv_ctrl_frame(adapter, precv_frame);
+               if (retval == _FAIL) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("validate_recv_ctrl_frame fail\n"));
+               }
+               retval = _FAIL; /*  only data frame return _SUCCESS */
+               break;
+       case IEEE80211_FTYPE_DATA:
+               rtw_led_control(adapter, LED_CTL_RX);
+               pattrib->qos = (subtype & IEEE80211_STYPE_QOS_DATA) ? 1 : 0;
+               retval = validate_recv_data_frame(adapter, precv_frame);
+               if (retval == _FAIL) {
+                       struct recv_priv *precvpriv = &adapter->recvpriv;
+                       /* RT_TRACE(_module_rtl871x_recv_c_, _drv_err_, ("validate_recv_data_frame fail\n")); */
+                       precvpriv->rx_drop++;
+               }
+               break;
+       default:
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                        ("validate_recv_data_frame fail! type = 0x%x\n", type));
+               retval = _FAIL;
+               break;
+       }
+
+exit:
+       return retval;
+}
+
+/* remove the wlanhdr and add the eth_hdr */
+
+static int wlanhdr_to_ethhdr (struct recv_frame *precvframe)
+{
+       u16     eth_type, len, hdrlen;
+       u8      bsnaphdr;
+       u8      *psnap;
+
+       int ret = _SUCCESS;
+       struct rtw_adapter *adapter = precvframe->adapter;
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+
+       struct sk_buff *skb = precvframe->pkt;
+       u8 *ptr;
+       struct rx_pkt_attrib *pattrib = &precvframe->attrib;
+
+
+
+       ptr = skb->data;
+       hdrlen = pattrib->hdrlen;
+       psnap = ptr + hdrlen;
+       eth_type = (psnap[6] << 8) | psnap[7];
+       /* convert hdr + possible LLC headers into Ethernet header */
+       /* eth_type = (psnap_type[0] << 8) | psnap_type[1]; */
+       if ((ether_addr_equal(psnap, rfc1042_header) &&
+            eth_type != ETH_P_AARP && eth_type != ETH_P_IPX) ||
+           ether_addr_equal(psnap, bridge_tunnel_header)) {
+               /* remove RFC1042 or Bridge-Tunnel encapsulation
+                  and replace EtherType */
+               bsnaphdr = true;
+               hdrlen += SNAP_SIZE;
+       } else {
+               /* Leave Ethernet header part of hdr and full payload */
+               bsnaphdr = false;
+               eth_type = (psnap[0] << 8) | psnap[1];
+       }
+
+       len = skb->len - hdrlen;
+
+       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                ("\n === pattrib->hdrlen: %x,  pattrib->iv_len:%x ===\n\n",
+                 pattrib->hdrlen,  pattrib->iv_len));
+
+       pattrib->eth_type = eth_type;
+       if ((check_fwstate(pmlmepriv, WIFI_MP_STATE) == true)) {
+               ptr += hdrlen;
+               *ptr = 0x87;
+               *(ptr + 1) = 0x12;
+
+               eth_type = 0x8712;
+               /*  append rx status for mp test packets */
+
+               ptr = skb_pull(skb, (hdrlen - sizeof(struct ethhdr) + 2) - 24);
+               memcpy(ptr, skb->head, 24);
+               ptr += 24;
+       } else {
+               ptr = skb_pull(skb, (hdrlen - sizeof(struct ethhdr) +
+                                    (bsnaphdr ? 2:0)));
+       }
+
+       ether_addr_copy(ptr, pattrib->dst);
+       ether_addr_copy(ptr + ETH_ALEN, pattrib->src);
+
+       if (!bsnaphdr) {
+               len = htons(len);
+               memcpy(ptr + 12, &len, 2);
+       }
+
+
+       return ret;
+}
+
+/* perform defrag */
+struct recv_frame *recvframe_defrag(struct rtw_adapter *adapter,
+                                   struct rtw_queue *defrag_q);
+struct recv_frame *recvframe_defrag(struct rtw_adapter *adapter,
+                                   struct rtw_queue *defrag_q)
+{
+       struct list_head *plist, *phead, *ptmp;
+       u8      *data, wlanhdr_offset;
+       u8      curfragnum;
+       struct recv_frame *pnfhdr;
+       struct recv_frame *prframe, *pnextrframe;
+       struct rtw_queue        *pfree_recv_queue;
+       struct sk_buff *skb;
+
+
+
+       curfragnum = 0;
+       pfree_recv_queue = &adapter->recvpriv.free_recv_queue;
+
+       phead = get_list_head(defrag_q);
+       plist = phead->next;
+       prframe = container_of(plist, struct recv_frame, list);
+       list_del_init(&prframe->list);
+       skb = prframe->pkt;
+
+       if (curfragnum != prframe->attrib.frag_num) {
+               /* the first fragment number must be 0 */
+               /* free the whole queue */
+               rtw_free_recvframe23a(prframe, pfree_recv_queue);
+               rtw_free_recvframe23a_queue(defrag_q, pfree_recv_queue);
+
+               return NULL;
+       }
+
+       curfragnum++;
+
+       phead = get_list_head(defrag_q);
+
+       data = prframe->pkt->data;
+
+       list_for_each_safe(plist, ptmp, phead) {
+               pnfhdr = container_of(plist, struct recv_frame, list);
+               pnextrframe = (struct recv_frame *)pnfhdr;
+               /* check the fragment sequence  (2nd ~n fragment frame) */
+
+               if (curfragnum != pnfhdr->attrib.frag_num) {
+                       /* the fragment number must be increasing
+                          (after decache) */
+                       /* release the defrag_q & prframe */
+                       rtw_free_recvframe23a(prframe, pfree_recv_queue);
+                       rtw_free_recvframe23a_queue(defrag_q, pfree_recv_queue);
+                       return NULL;
+               }
+
+               curfragnum++;
+
+               /* copy the 2nd~n fragment frame's payload to the
+                  first fragment */
+               /* get the 2nd~last fragment frame's payload */
+
+               wlanhdr_offset = pnfhdr->attrib.hdrlen + pnfhdr->attrib.iv_len;
+
+               skb_pull(pnfhdr->pkt, wlanhdr_offset);
+
+               /* append  to first fragment frame's tail
+                  (if privacy frame, pull the ICV) */
+
+               skb_trim(skb, skb->len - prframe->attrib.icv_len);
+
+               memcpy(skb_tail_pointer(skb), pnfhdr->pkt->data,
+                      pnfhdr->pkt->len);
+
+               skb_put(skb, pnfhdr->pkt->len);
+
+               prframe->attrib.icv_len = pnfhdr->attrib.icv_len;
+       };
+
+       /* free the defrag_q queue and return the prframe */
+       rtw_free_recvframe23a_queue(defrag_q, pfree_recv_queue);
+
+       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                ("Performance defrag!!!!!\n"));
+
+
+
+       return prframe;
+}
+
+/* check if need to defrag, if needed queue the frame to defrag_q */
+struct recv_frame* recvframe_chk_defrag23a(struct rtw_adapter *padapter,
+                                       struct recv_frame *precv_frame)
+{
+       u8      ismfrag;
+       u8      fragnum;
+       u8      *psta_addr;
+       struct recv_frame *pfhdr;
+       struct sta_info *psta;
+       struct sta_priv *pstapriv;
+       struct list_head *phead;
+       struct recv_frame *prtnframe = NULL;
+       struct rtw_queue *pfree_recv_queue, *pdefrag_q;
+
+
+
+       pstapriv = &padapter->stapriv;
+
+       pfhdr = precv_frame;
+
+       pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+
+       /* need to define struct of wlan header frame ctrl */
+       ismfrag = pfhdr->attrib.mfrag;
+       fragnum = pfhdr->attrib.frag_num;
+
+       psta_addr = pfhdr->attrib.ta;
+       psta = rtw_get_stainfo23a(pstapriv, psta_addr);
+       if (!psta) {
+               struct ieee80211_hdr *hdr =
+                       (struct ieee80211_hdr *) pfhdr->pkt->data;
+               if (!ieee80211_is_data(hdr->frame_control)) {
+                       psta = rtw_get_bcmc_stainfo23a(padapter);
+                       pdefrag_q = &psta->sta_recvpriv.defrag_q;
+               } else
+                       pdefrag_q = NULL;
+       } else
+               pdefrag_q = &psta->sta_recvpriv.defrag_q;
+
+       if ((ismfrag == 0) && (fragnum == 0)) {
+               prtnframe = precv_frame;/* isn't a fragment frame */
+       }
+
+       if (ismfrag == 1) {
+               /* 0~(n-1) fragment frame */
+               /* enqueue to defraf_g */
+               if (pdefrag_q != NULL) {
+                       if (fragnum == 0) {
+                               /* the first fragment */
+                               if (_rtw_queue_empty23a(pdefrag_q) == false) {
+                                       /* free current defrag_q */
+                                       rtw_free_recvframe23a_queue(pdefrag_q, pfree_recv_queue);
+                               }
+                       }
+
+                       /* Then enqueue the 0~(n-1) fragment into the
+                          defrag_q */
+
+                       /* spin_lock(&pdefrag_q->lock); */
+                       phead = get_list_head(pdefrag_q);
+                       list_add_tail(&pfhdr->list, phead);
+                       /* spin_unlock(&pdefrag_q->lock); */
+
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                ("Enqueuq: ismfrag = %d, fragnum = %d\n",
+                                 ismfrag, fragnum));
+
+                       prtnframe = NULL;
+
+               } else {
+                       /* can't find this ta's defrag_queue,
+                          so free this recv_frame */
+                       rtw_free_recvframe23a(precv_frame, pfree_recv_queue);
+                       prtnframe = NULL;
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("Free because pdefrag_q == NULL: ismfrag = "
+                                 "%d, fragnum = %d\n", ismfrag, fragnum));
+               }
+       }
+
+       if ((ismfrag == 0) && (fragnum != 0)) {
+               /* the last fragment frame */
+               /* enqueue the last fragment */
+               if (pdefrag_q != NULL) {
+                       /* spin_lock(&pdefrag_q->lock); */
+                       phead = get_list_head(pdefrag_q);
+                       list_add_tail(&pfhdr->list, phead);
+                       /* spin_unlock(&pdefrag_q->lock); */
+
+                       /* call recvframe_defrag to defrag */
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                ("defrag: ismfrag = %d, fragnum = %d\n",
+                                 ismfrag, fragnum));
+                       precv_frame = recvframe_defrag(padapter, pdefrag_q);
+                       prtnframe = precv_frame;
+               } else {
+                       /* can't find this ta's defrag_queue,
+                          so free this recv_frame */
+                       rtw_free_recvframe23a(precv_frame, pfree_recv_queue);
+                       prtnframe = NULL;
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("Free because pdefrag_q == NULL: ismfrag = "
+                                 "%d, fragnum = %d\n", ismfrag, fragnum));
+               }
+
+       }
+
+       if ((prtnframe != NULL) && (prtnframe->attrib.privacy)) {
+               /* after defrag we must check tkip mic code */
+               if (recvframe_chkmic(padapter,  prtnframe) == _FAIL) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("recvframe_chkmic(padapter,  prtnframe) =="
+                                 "_FAIL\n"));
+                       rtw_free_recvframe23a(prtnframe, pfree_recv_queue);
+                       prtnframe = NULL;
+               }
+       }
+
+
+
+       return prtnframe;
+}
+
+int amsdu_to_msdu(struct rtw_adapter *padapter, struct recv_frame *prframe);
+int amsdu_to_msdu(struct rtw_adapter *padapter, struct recv_frame *prframe)
+{
+       struct rx_pkt_attrib *pattrib;
+       struct sk_buff *skb, *sub_skb;
+       struct sk_buff_head skb_list;
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+       struct rtw_queue *pfree_recv_queue = &precvpriv->free_recv_queue;
+
+       pattrib = &prframe->attrib;
+
+       skb = prframe->pkt;
+       skb_pull(skb, prframe->attrib.hdrlen);
+       __skb_queue_head_init(&skb_list);
+
+       ieee80211_amsdu_to_8023s(skb, &skb_list, NULL, 0, 0, false);
+
+       while (!skb_queue_empty(&skb_list)) {
+               sub_skb = __skb_dequeue(&skb_list);
+
+               sub_skb->protocol = eth_type_trans(sub_skb, padapter->pnetdev);
+               sub_skb->dev = padapter->pnetdev;
+
+               sub_skb->ip_summed = CHECKSUM_NONE;
+
+               netif_rx(sub_skb);
+       }
+
+       prframe->pkt = NULL;
+       rtw_free_recvframe23a(prframe, pfree_recv_queue);
+       return _SUCCESS;
+}
+
+int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num);
+int check_indicate_seq(struct recv_reorder_ctrl *preorder_ctrl, u16 seq_num)
+{
+       u8      wsize = preorder_ctrl->wsize_b;
+       u16     wend = (preorder_ctrl->indicate_seq + wsize -1) & 0xFFF;
+
+       /*  Rx Reorder initialize condition. */
+       if (preorder_ctrl->indicate_seq == 0xFFFF)
+               preorder_ctrl->indicate_seq = seq_num;
+
+       /*  Drop out the packet which SeqNum is smaller than WinStart */
+       if (SN_LESS(seq_num, preorder_ctrl->indicate_seq))
+               return false;
+
+       /*  */
+       /*  Sliding window manipulation. Conditions includes: */
+       /*  1. Incoming SeqNum is equal to WinStart =>Window shift 1 */
+       /*  2. Incoming SeqNum is larger than the WinEnd => Window shift N */
+       /*  */
+       if (SN_EQUAL(seq_num, preorder_ctrl->indicate_seq)) {
+               preorder_ctrl->indicate_seq =
+                       (preorder_ctrl->indicate_seq + 1) & 0xFFF;
+       } else if (SN_LESS(wend, seq_num)) {
+               /*  boundary situation, when seq_num cross 0xFFF */
+               if (seq_num >= (wsize - 1))
+                       preorder_ctrl->indicate_seq = seq_num + 1 -wsize;
+               else
+                       preorder_ctrl->indicate_seq = 0xFFF - (wsize - (seq_num + 1)) + 1;
+       }
+       return true;
+}
+
+int enqueue_reorder_recvframe23a(struct recv_reorder_ctrl *preorder_ctrl,
+                             struct recv_frame *prframe)
+{
+       struct rx_pkt_attrib *pattrib = &prframe->attrib;
+       struct rtw_queue *ppending_recvframe_queue;
+       struct list_head *phead, *plist, *ptmp;
+       struct recv_frame *hdr;
+       struct rx_pkt_attrib *pnextattrib;
+
+       ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+       /* DbgPrint("+enqueue_reorder_recvframe23a()\n"); */
+
+       /* spin_lock_irqsave(&ppending_recvframe_queue->lock); */
+       /* spin_lock_ex(&ppending_recvframe_queue->lock); */
+
+       phead = get_list_head(ppending_recvframe_queue);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               hdr = container_of(plist, struct recv_frame, list);
+               pnextattrib = &hdr->attrib;
+
+               if (SN_LESS(pnextattrib->seq_num, pattrib->seq_num)) {
+                       continue;
+               } else if (SN_EQUAL(pnextattrib->seq_num, pattrib->seq_num)) {
+                       /* Duplicate entry is found!! Do not insert current entry. */
+                       /* RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); */
+
+                       /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock); */
+                       return false;
+               } else {
+                       break;
+               }
+
+               /* DbgPrint("enqueue_reorder_recvframe23a():while\n"); */
+       }
+
+       /* spin_lock_irqsave(&ppending_recvframe_queue->lock); */
+       /* spin_lock_ex(&ppending_recvframe_queue->lock); */
+
+       list_del_init(&prframe->list);
+
+       list_add_tail(&prframe->list, plist);
+
+       /* spin_unlock_ex(&ppending_recvframe_queue->lock); */
+       /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock); */
+
+       /* RT_TRACE(COMP_RX_REORDER, DBG_TRACE, ("InsertRxReorderList(): Pkt insert into buffer!! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum)); */
+       return true;
+}
+
+int recv_indicatepkts_in_order(struct rtw_adapter *padapter,
+                              struct recv_reorder_ctrl *preorder_ctrl,
+                              int bforced);
+int recv_indicatepkts_in_order(struct rtw_adapter *padapter,
+                              struct recv_reorder_ctrl *preorder_ctrl,
+                              int bforced)
+{
+       /* u8 bcancelled; */
+       struct list_head *phead, *plist;
+       struct recv_frame *prframe;
+       struct rx_pkt_attrib *pattrib;
+       /* u8 index = 0; */
+       int bPktInBuf = false;
+       struct recv_priv *precvpriv;
+       struct rtw_queue *ppending_recvframe_queue;
+
+       precvpriv = &padapter->recvpriv;
+       ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+       /* DbgPrint("+recv_indicatepkts_in_order\n"); */
+
+       /* spin_lock_irqsave(&ppending_recvframe_queue->lock); */
+       /* spin_lock_ex(&ppending_recvframe_queue->lock); */
+
+       phead = get_list_head(ppending_recvframe_queue);
+       plist = phead->next;
+
+       /*  Handling some condition for forced indicate case. */
+       if (bforced) {
+               if (list_empty(phead)) {
+                       /*  spin_unlock_irqrestore(&ppending_recvframe_queue->lock); */
+                       /* spin_unlock_ex(&ppending_recvframe_queue->lock); */
+                       return true;
+               }
+
+               prframe = container_of(plist, struct recv_frame, list);
+               pattrib = &prframe->attrib;
+               preorder_ctrl->indicate_seq = pattrib->seq_num;
+       }
+
+       /*  Prepare indication list and indication. */
+       /*  Check if there is any packet need indicate. */
+       while (!list_empty(phead)) {
+
+               prframe = container_of(plist, struct recv_frame, list);
+               pattrib = &prframe->attrib;
+
+               if (!SN_LESS(preorder_ctrl->indicate_seq, pattrib->seq_num)) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                                ("recv_indicatepkts_in_order: indicate =%d "
+                                 "seq =%d amsdu =%d\n",
+                                 preorder_ctrl->indicate_seq,
+                                 pattrib->seq_num, pattrib->amsdu));
+
+                       plist = plist->next;
+                       list_del_init(&prframe->list);
+
+                       if (SN_EQUAL(preorder_ctrl->indicate_seq,
+                                    pattrib->seq_num)) {
+                               preorder_ctrl->indicate_seq =
+                                       (preorder_ctrl->indicate_seq + 1)&0xFFF;
+                       }
+
+                       if (!pattrib->amsdu) {
+                               if ((padapter->bDriverStopped == false) &&
+                                   (padapter->bSurpriseRemoved == false)) {
+                                       rtw_recv_indicatepkt23a(padapter, prframe);
+                               }
+                       } else {
+                               if (amsdu_to_msdu(padapter, prframe) !=
+                                   _SUCCESS) {
+                                       rtw_free_recvframe23a(prframe,
+                                                          &precvpriv->free_recv_queue);
+                               }
+                       }
+
+                       /* Update local variables. */
+                       bPktInBuf = false;
+
+               } else {
+                       bPktInBuf = true;
+                       break;
+               }
+
+               /* DbgPrint("recv_indicatepkts_in_order():while\n"); */
+       }
+
+       /* spin_unlock_ex(&ppending_recvframe_queue->lock); */
+       /* spin_unlock_irqrestore(&ppending_recvframe_queue->lock); */
+
+       return bPktInBuf;
+}
+
+int recv_indicatepkt_reorder(struct rtw_adapter *padapter,
+                            struct recv_frame *prframe);
+int recv_indicatepkt_reorder(struct rtw_adapter *padapter,
+                            struct recv_frame *prframe)
+{
+       int retval = _SUCCESS;
+       struct rx_pkt_attrib *pattrib;
+       struct recv_reorder_ctrl *preorder_ctrl;
+       struct rtw_queue *ppending_recvframe_queue;
+
+       pattrib = &prframe->attrib;
+       preorder_ctrl = prframe->preorder_ctrl;
+       ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+       if (!pattrib->amsdu) {
+               /* s1. */
+               wlanhdr_to_ethhdr(prframe);
+
+               if ((pattrib->qos!= 1) || (pattrib->eth_type == 0x0806) ||
+                   (pattrib->ack_policy != 0)) {
+                       if ((padapter->bDriverStopped == false) &&
+                           (padapter->bSurpriseRemoved == false)) {
+                               RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                                        ("@@@@  recv_indicatepkt_reorder -"
+                                         "recv_func recv_indicatepkt\n"));
+
+                               rtw_recv_indicatepkt23a(padapter, prframe);
+                               return _SUCCESS;
+                       }
+
+                       return _FAIL;
+               }
+
+               if (preorder_ctrl->enable == false) {
+                       /* indicate this recv_frame */
+                       preorder_ctrl->indicate_seq = pattrib->seq_num;
+                       rtw_recv_indicatepkt23a(padapter, prframe);
+
+                       preorder_ctrl->indicate_seq =
+                               (preorder_ctrl->indicate_seq + 1) % 4096;
+                       return _SUCCESS;
+               }
+       } else {
+                /* temp filter -> means didn't support A-MSDUs in a A-MPDU */
+               if (preorder_ctrl->enable == false) {
+                       preorder_ctrl->indicate_seq = pattrib->seq_num;
+                       retval = amsdu_to_msdu(padapter, prframe);
+
+                       preorder_ctrl->indicate_seq =
+                               (preorder_ctrl->indicate_seq + 1) % 4096;
+                       return retval;
+               }
+       }
+
+       spin_lock_bh(&ppending_recvframe_queue->lock);
+
+       RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                ("recv_indicatepkt_reorder: indicate =%d seq =%d\n",
+                 preorder_ctrl->indicate_seq, pattrib->seq_num));
+
+       /* s2. check if winstart_b(indicate_seq) needs to been updated */
+       if (!check_indicate_seq(preorder_ctrl, pattrib->seq_num)) {
+               goto _err_exit;
+       }
+
+       /* s3. Insert all packet into Reorder Queue to maintain its ordering. */
+       if (!enqueue_reorder_recvframe23a(preorder_ctrl, prframe)) {
+               goto _err_exit;
+       }
+
+       /* s4. */
+       /*  Indication process. */
+       /*  After Packet dropping and Sliding Window shifting as above,
+           we can now just indicate the packets */
+       /*  with the SeqNum smaller than latest WinStart and buffer
+           other packets. */
+       /*  */
+       /*  For Rx Reorder condition: */
+       /*  1. All packets with SeqNum smaller than WinStart => Indicate */
+       /*  2. All packets with SeqNum larger than or equal to WinStart =>
+           Buffer it. */
+       /*  */
+
+       if (recv_indicatepkts_in_order(padapter, preorder_ctrl, false) == true) {
+               mod_timer(&preorder_ctrl->reordering_ctrl_timer,
+                         jiffies + msecs_to_jiffies(REORDER_WAIT_TIME));
+               spin_unlock_bh(&ppending_recvframe_queue->lock);
+       } else {
+               spin_unlock_bh(&ppending_recvframe_queue->lock);
+               del_timer_sync(&preorder_ctrl->reordering_ctrl_timer);
+       }
+       return _SUCCESS;
+
+_err_exit:
+
+        spin_unlock_bh(&ppending_recvframe_queue->lock);
+       return _FAIL;
+}
+
+void rtw_reordering_ctrl_timeout_handler23a(unsigned long pcontext)
+{
+       struct recv_reorder_ctrl *preorder_ctrl;
+       struct rtw_adapter *padapter;
+       struct rtw_queue *ppending_recvframe_queue;
+
+       preorder_ctrl = (struct recv_reorder_ctrl *)pcontext;
+       padapter = preorder_ctrl->padapter;
+       ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+       if (padapter->bDriverStopped || padapter->bSurpriseRemoved) {
+               return;
+       }
+
+       /* DBG_8723A("+rtw_reordering_ctrl_timeout_handler23a() =>\n"); */
+
+       spin_lock_bh(&ppending_recvframe_queue->lock);
+
+       if (recv_indicatepkts_in_order(padapter, preorder_ctrl, true) == true) {
+               mod_timer(&preorder_ctrl->reordering_ctrl_timer,
+                         jiffies + msecs_to_jiffies(REORDER_WAIT_TIME));
+       }
+
+       spin_unlock_bh(&ppending_recvframe_queue->lock);
+}
+
+int process_recv_indicatepkts(struct rtw_adapter *padapter,
+                             struct recv_frame *prframe);
+int process_recv_indicatepkts(struct rtw_adapter *padapter,
+                             struct recv_frame *prframe)
+{
+       int retval = _SUCCESS;
+       /* struct recv_priv *precvpriv = &padapter->recvpriv; */
+       /* struct rx_pkt_attrib *pattrib = &prframe->attrib; */
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct ht_priv *phtpriv = &pmlmepriv->htpriv;
+
+       if (phtpriv->ht_option == true) { /* B/G/N Mode */
+               /* prframe->preorder_ctrl = &precvpriv->recvreorder_ctrl[pattrib->priority]; */
+
+               /*  including perform A-MPDU Rx Ordering Buffer Control */
+               if (recv_indicatepkt_reorder(padapter, prframe) != _SUCCESS) {
+                       if ((padapter->bDriverStopped == false) &&
+                           (padapter->bSurpriseRemoved == false)) {
+                               retval = _FAIL;
+                               return retval;
+                       }
+               }
+       } else /* B/G mode */
+       {
+               retval = wlanhdr_to_ethhdr(prframe);
+               if (retval != _SUCCESS) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("wlanhdr_to_ethhdr: drop pkt\n"));
+                       return retval;
+               }
+
+               if ((padapter->bDriverStopped == false) &&
+                   (padapter->bSurpriseRemoved == false)) {
+                       /* indicate this recv_frame */
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                                ("@@@@ process_recv_indicatepkts- "
+                                 "recv_func recv_indicatepkt\n"));
+                       rtw_recv_indicatepkt23a(padapter, prframe);
+               } else {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                                ("@@@@ process_recv_indicatepkts- "
+                                 "recv_func free_indicatepkt\n"));
+
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_notice_,
+                                ("recv_func:bDriverStopped(%d) OR "
+                                 "bSurpriseRemoved(%d)",
+                                 padapter->bDriverStopped,
+                                 padapter->bSurpriseRemoved));
+                       retval = _FAIL;
+                       return retval;
+               }
+
+       }
+
+       return retval;
+}
+
+static int recv_func_prehandle(struct rtw_adapter *padapter,
+                              struct recv_frame *rframe)
+{
+       struct rtw_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+       int ret = _SUCCESS;
+
+       /* check the frame crtl field and decache */
+       ret = validate_recv_frame(padapter, rframe);
+       if (ret != _SUCCESS) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                        ("recv_func: validate_recv_frame fail! drop pkt\n"));
+               rtw_free_recvframe23a(rframe, pfree_recv_queue);
+               goto exit;
+       }
+
+exit:
+       return ret;
+}
+
+static int recv_func_posthandle(struct rtw_adapter *padapter,
+                               struct recv_frame *prframe)
+{
+       int ret = _SUCCESS;
+       struct recv_frame *orig_prframe = prframe;
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+       struct rtw_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+
+       /*  DATA FRAME */
+       rtw_led_control(padapter, LED_CTL_RX);
+
+       prframe = decryptor(padapter, prframe);
+       if (prframe == NULL) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                        ("decryptor: drop pkt\n"));
+               ret = _FAIL;
+               goto _recv_data_drop;
+       }
+
+       prframe = recvframe_chk_defrag23a(padapter, prframe);
+       if (!prframe) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                        ("recvframe_chk_defrag23a: drop pkt\n"));
+               goto _recv_data_drop;
+       }
+
+       /*
+        * Pull off crypto headers
+        */
+       if (prframe->attrib.iv_len > 0) {
+               skb_pull(prframe->pkt, prframe->attrib.iv_len);
+       }
+
+       if (prframe->attrib.icv_len > 0) {
+               skb_trim(prframe->pkt,
+                        prframe->pkt->len - prframe->attrib.icv_len);
+       }
+
+       prframe = portctrl(padapter, prframe);
+       if (!prframe) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                        ("portctrl: drop pkt\n"));
+               ret = _FAIL;
+               goto _recv_data_drop;
+       }
+
+       count_rx_stats(padapter, prframe, NULL);
+
+       ret = process_recv_indicatepkts(padapter, prframe);
+       if (ret != _SUCCESS) {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                        ("recv_func: process_recv_indicatepkts fail!\n"));
+               rtw_free_recvframe23a(orig_prframe, pfree_recv_queue);/* free this recv_frame */
+               goto _recv_data_drop;
+       }
+       return ret;
+
+_recv_data_drop:
+       precvpriv->rx_drop++;
+       return ret;
+}
+
+int rtw_recv_entry23a(struct recv_frame *rframe)
+{
+       int ret, r;
+       struct rtw_adapter *padapter = rframe->adapter;
+       struct rx_pkt_attrib *prxattrib = &rframe->attrib;
+       struct recv_priv *recvpriv = &padapter->recvpriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+
+       /* check if need to handle uc_swdec_pending_queue*/
+       if (check_fwstate(mlmepriv, WIFI_STATION_STATE) &&
+           psecuritypriv->busetkipkey) {
+               struct recv_frame *pending_frame;
+
+               while ((pending_frame = rtw_alloc_recvframe23a(&padapter->recvpriv.uc_swdec_pending_queue))) {
+                       r = recv_func_posthandle(padapter, pending_frame);
+                       if (r == _SUCCESS)
+                               DBG_8723A("%s: dequeue uc_swdec_pending_queue\n", __func__);
+               }
+       }
+
+       ret = recv_func_prehandle(padapter, rframe);
+
+       if (ret == _SUCCESS) {
+               /* check if need to enqueue into uc_swdec_pending_queue*/
+               if (check_fwstate(mlmepriv, WIFI_STATION_STATE) &&
+                   !is_multicast_ether_addr(prxattrib->ra) &&
+                   prxattrib->encrypt > 0 &&
+                   (prxattrib->bdecrypted == 0) &&
+                   !is_wep_enc(psecuritypriv->dot11PrivacyAlgrthm) &&
+                   !psecuritypriv->busetkipkey) {
+                       rtw_enqueue_recvframe23a(rframe, &padapter->recvpriv.uc_swdec_pending_queue);
+                       DBG_8723A("%s: no key, enqueue uc_swdec_pending_queue\n", __func__);
+                       goto exit;
+               }
+
+               ret = recv_func_posthandle(padapter, rframe);
+
+               recvpriv->rx_pkts++;
+       }
+
+exit:
+       return ret;
+}
+
+void rtw_signal_stat_timer_hdl23a(unsigned long data)
+{
+       struct rtw_adapter *adapter = (struct rtw_adapter *)data;
+       struct recv_priv *recvpriv = &adapter->recvpriv;
+
+       u32 tmp_s, tmp_q;
+       u8 avg_signal_strength = 0;
+       u8 avg_signal_qual = 0;
+       u32 num_signal_strength = 0;
+       u32 num_signal_qual = 0;
+       u8 _alpha = 3;  /* this value is based on converging_constant = 5000 */
+                       /* and sampling_interval = 1000 */
+
+       if (adapter->recvpriv.is_signal_dbg) {
+               /* update the user specific value, signal_strength_dbg, */
+               /* to signal_strength, rssi */
+               adapter->recvpriv.signal_strength =
+                       adapter->recvpriv.signal_strength_dbg;
+               adapter->recvpriv.rssi =
+                       (s8)translate_percentage_to_dbm((u8)adapter->recvpriv.signal_strength_dbg);
+       } else {
+               if (recvpriv->signal_strength_data.update_req == 0) {
+                       /*  update_req is clear, means we got rx */
+                       avg_signal_strength =
+                               recvpriv->signal_strength_data.avg_val;
+                       num_signal_strength =
+                               recvpriv->signal_strength_data.total_num;
+                       /*  after avg_vals are accquired, we can re-stat */
+                       /* the signal values */
+                       recvpriv->signal_strength_data.update_req = 1;
+               }
+
+               if (recvpriv->signal_qual_data.update_req == 0) {
+                       /*  update_req is clear, means we got rx */
+                       avg_signal_qual = recvpriv->signal_qual_data.avg_val;
+                       num_signal_qual = recvpriv->signal_qual_data.total_num;
+                       /*  after avg_vals are accquired, we can re-stat */
+                       /*the signal values */
+                       recvpriv->signal_qual_data.update_req = 1;
+               }
+
+               /* update value of signal_strength, rssi, signal_qual */
+               if (check_fwstate(&adapter->mlmepriv, _FW_UNDER_SURVEY) ==
+                   false) {
+                       tmp_s = (avg_signal_strength + (_alpha - 1) *
+                                recvpriv->signal_strength);
+                       if (tmp_s %_alpha)
+                               tmp_s = tmp_s / _alpha + 1;
+                       else
+                               tmp_s = tmp_s / _alpha;
+                       if (tmp_s > 100)
+                               tmp_s = 100;
+
+                       tmp_q = (avg_signal_qual + (_alpha - 1) *
+                                recvpriv->signal_qual);
+                       if (tmp_q %_alpha)
+                               tmp_q = tmp_q / _alpha + 1;
+                       else
+                               tmp_q = tmp_q / _alpha;
+                       if (tmp_q > 100)
+                               tmp_q = 100;
+
+                       recvpriv->signal_strength = tmp_s;
+                       recvpriv->rssi = (s8)translate_percentage_to_dbm(tmp_s);
+                       recvpriv->signal_qual = tmp_q;
+
+                       DBG_8723A("%s signal_strength:%3u, rssi:%3d, "
+                                 "signal_qual:%3u, num_signal_strength:%u, "
+                                 "num_signal_qual:%u\n",
+                                 __func__, recvpriv->signal_strength,
+                                 recvpriv->rssi, recvpriv->signal_qual,
+                                 num_signal_strength, num_signal_qual
+                       );
+               }
+       }
+       rtw_set_signal_stat_timer(recvpriv);
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_security.c b/drivers/staging/rtl8723au/core/rtw_security.c
new file mode 100644 (file)
index 0000000..fd43e71
--- /dev/null
@@ -0,0 +1,1652 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define  _RTW_SECURITY_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <osdep_intf.h>
+
+/* WEP related ===== */
+
+#define CRC32_POLY 0x04c11db7
+
+struct arc4context
+{
+       u32 x;
+       u32 y;
+       u8 state[256];
+};
+
+static void arcfour_init(struct arc4context    *parc4ctx, u8 * key, u32        key_len)
+{
+       u32     t, u;
+       u32     keyindex;
+       u32     stateindex;
+       u8 * state;
+       u32     counter;
+
+       state = parc4ctx->state;
+       parc4ctx->x = 0;
+       parc4ctx->y = 0;
+       for (counter = 0; counter < 256; counter++)
+               state[counter] = (u8)counter;
+       keyindex = 0;
+       stateindex = 0;
+       for (counter = 0; counter < 256; counter++)
+       {
+               t = state[counter];
+               stateindex = (stateindex + key[keyindex] + t) & 0xff;
+               u = state[stateindex];
+               state[stateindex] = (u8)t;
+               state[counter] = (u8)u;
+               if (++keyindex >= key_len)
+                       keyindex = 0;
+       }
+
+}
+static u32 arcfour_byte(       struct arc4context      *parc4ctx)
+{
+       u32 x;
+       u32 y;
+       u32 sx, sy;
+       u8 * state;
+
+       state = parc4ctx->state;
+       x = (parc4ctx->x + 1) & 0xff;
+       sx = state[x];
+       y = (sx + parc4ctx->y) & 0xff;
+       sy = state[y];
+       parc4ctx->x = x;
+       parc4ctx->y = y;
+       state[y] = (u8)sx;
+       state[x] = (u8)sy;
+
+       return state[(sx + sy) & 0xff];
+}
+
+static void arcfour_encrypt(   struct arc4context      *parc4ctx,
+       u8 * dest,
+       u8 * src,
+       u32 len)
+{
+       u32     i;
+
+       for (i = 0; i < len; i++)
+               dest[i] = src[i] ^ (unsigned char)arcfour_byte(parc4ctx);
+
+}
+
+static int bcrc32initialized = 0;
+static u32 crc32_table[256];
+
+static u8 crc32_reverseBit(u8 data)
+{
+       u8 retval = ((data << 7) & 0x80) | ((data << 5) & 0x40) |
+               ((data << 3) & 0x20) | ((data << 1) & 0x10) |
+               ((data >> 1) & 0x08) | ((data >> 3) & 0x04) |
+               ((data >> 5) & 0x02) | ((data >> 7) & 0x01);
+       return retval;
+}
+
+static void crc32_init(void)
+{
+
+       if (bcrc32initialized == 1)
+               return;
+       else{
+               int i, j;
+               u32 c;
+               u8 *p = (u8 *)&c, *p1;
+               u8 k;
+
+               c = 0x12340000;
+
+               for (i = 0; i < 256; ++i)
+               {
+                       k = crc32_reverseBit((u8)i);
+                       for (c = ((u32)k) << 24, j = 8; j > 0; --j) {
+                               c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1);
+                       }
+                       p1 = (u8 *)&crc32_table[i];
+
+                       p1[0] = crc32_reverseBit(p[3]);
+                       p1[1] = crc32_reverseBit(p[2]);
+                       p1[2] = crc32_reverseBit(p[1]);
+                       p1[3] = crc32_reverseBit(p[0]);
+               }
+               bcrc32initialized = 1;
+       }
+}
+
+static u32 getcrc32(u8 *buf, int len)
+{
+       u8 *p;
+       u32  crc;
+
+       if (bcrc32initialized == 0) crc32_init();
+
+       crc = 0xffffffff;       /* preload shift register, per CRC-32 spec */
+
+       for (p = buf; len > 0; ++p, --len)
+               crc = crc32_table[ (crc ^ *p) & 0xff] ^ (crc >> 8);
+
+       return ~crc;    /* transmit complement, per CRC-32 spec */
+}
+
+/* Need to consider the fragment  situation */
+void rtw_wep_encrypt23a(struct rtw_adapter *padapter,
+                    struct xmit_frame *pxmitframe)
+{
+       /*  exclude ICV */
+       unsigned char crc[4];
+       struct arc4context mycontext;
+       int curfragnum, length, index;
+       u32 keylength;
+       u8 *pframe, *payload, *iv;    /* wepkey */
+       u8 wepkey[16];
+       u8 hw_hdr_offset = 0;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+       if (!pxmitframe->buf_addr)
+               return;
+
+       hw_hdr_offset = TXDESC_OFFSET;
+
+       pframe = pxmitframe->buf_addr + hw_hdr_offset;
+
+       /* start to encrypt each fragment */
+       if ((pattrib->encrypt != _WEP40_) && (pattrib->encrypt != _WEP104_))
+               return;
+
+       index = psecuritypriv->dot11PrivacyKeyIndex;
+       keylength = psecuritypriv->dot11DefKeylen[index];
+
+       for (curfragnum = 0; curfragnum < pattrib->nr_frags ; curfragnum++) {
+               iv = pframe + pattrib->hdrlen;
+               memcpy(&wepkey[0], iv, 3);
+               memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[index].skey[0],
+                      keylength);
+               payload = pframe + pattrib->iv_len + pattrib->hdrlen;
+
+               if ((curfragnum + 1) == pattrib->nr_frags) {
+                       /* the last fragment */
+                       length = pattrib->last_txcmdsz - pattrib->hdrlen -
+                               pattrib->iv_len- pattrib->icv_len;
+
+                       *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length));
+
+                       arcfour_init(&mycontext, wepkey, 3 + keylength);
+                       arcfour_encrypt(&mycontext, payload, payload, length);
+                       arcfour_encrypt(&mycontext, payload + length, crc, 4);
+               } else {
+                       length = pxmitpriv->frag_len - pattrib->hdrlen -
+                               pattrib->iv_len - pattrib->icv_len;
+                       *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length));
+                       arcfour_init(&mycontext, wepkey, 3 + keylength);
+                       arcfour_encrypt(&mycontext, payload, payload, length);
+                       arcfour_encrypt(&mycontext, payload + length, crc, 4);
+
+                       pframe += pxmitpriv->frag_len;
+                       pframe = PTR_ALIGN(pframe, 4);
+               }
+       }
+
+}
+
+void rtw_wep_decrypt23a(struct rtw_adapter *padapter,
+                    struct recv_frame *precvframe)
+{
+       /*  exclude ICV */
+       u8 crc[4];
+       struct arc4context mycontext;
+       int length;
+       u32 keylength;
+       u8 *pframe, *payload, *iv, wepkey[16];
+       u8 keyindex;
+       struct rx_pkt_attrib *prxattrib = &precvframe->attrib;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct sk_buff * skb = precvframe->pkt;
+
+       pframe = skb->data;
+
+       /* start to decrypt recvframe */
+       if ((prxattrib->encrypt != _WEP40_) && (prxattrib->encrypt != _WEP104_))
+               return;
+
+       iv = pframe + prxattrib->hdrlen;
+       /* keyindex = (iv[3]&0x3); */
+       keyindex = prxattrib->key_index;
+       keylength = psecuritypriv->dot11DefKeylen[keyindex];
+       memcpy(&wepkey[0], iv, 3);
+       /* memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[psecuritypriv->dot11PrivacyKeyIndex].skey[0], keylength); */
+       memcpy(&wepkey[3], &psecuritypriv->dot11DefKey[keyindex].skey[0],
+                  keylength);
+       length = skb->len - prxattrib->hdrlen - prxattrib->iv_len;
+
+       payload = pframe + prxattrib->iv_len + prxattrib->hdrlen;
+
+       /* decrypt payload include icv */
+       arcfour_init(&mycontext, wepkey, 3 + keylength);
+       arcfour_encrypt(&mycontext, payload, payload, length);
+
+       /* calculate icv and compare the icv */
+       *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length - 4));
+
+       if (crc[3] != payload[length - 1] || crc[2] != payload[length - 2] ||
+               crc[1] != payload[length - 3] || crc[0] != payload[length - 4]) {
+               RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+                        ("rtw_wep_decrypt23a:icv error crc[3](%x)!= payload"
+                         "[length-1](%x) || crc[2](%x)!= payload[length-2](%x)"
+                         " || crc[1](%x)!= payload[length-3](%x) || crc[0](%x)"
+                         "!= payload[length-4](%x)\n",
+                         crc[3], payload[length - 1],
+                         crc[2], payload[length - 2],
+                         crc[1], payload[length - 3],
+                         crc[0], payload[length - 4]));
+       }
+
+       return;
+}
+
+/* 3           ===== TKIP related ===== */
+
+static u32 secmicgetuint32(u8 * p)
+/*  Convert from Byte[] to u32 in a portable way */
+{
+       s32 i;
+       u32 res = 0;
+
+       for (i = 0; i<4; i++)
+       {
+               res |= ((u32)(*p++)) << (8*i);
+       }
+
+       return res;
+}
+
+static void secmicputuint32(u8 * p, u32 val)
+/*  Convert from long to Byte[] in a portable way */
+{
+       long i;
+
+       for (i = 0; i<4; i++)
+       {
+               *p++ = (u8) (val & 0xff);
+               val >>= 8;
+       }
+
+}
+
+static void secmicclear(struct mic_data *pmicdata)
+{
+/*  Reset the state to the empty message. */
+
+       pmicdata->L = pmicdata->K0;
+       pmicdata->R = pmicdata->K1;
+       pmicdata->nBytesInM = 0;
+       pmicdata->M = 0;
+
+}
+
+void rtw_secmicsetkey23a(struct mic_data *pmicdata, u8 * key)
+{
+       /*  Set the key */
+
+       pmicdata->K0 = secmicgetuint32(key);
+       pmicdata->K1 = secmicgetuint32(key + 4);
+       /*  and reset the message */
+       secmicclear(pmicdata);
+
+}
+
+void rtw_secmicappend23abyte23a(struct mic_data *pmicdata, u8 b)
+{
+
+       /*  Append the byte to our word-sized buffer */
+       pmicdata->M |= ((unsigned long)b) << (8*pmicdata->nBytesInM);
+       pmicdata->nBytesInM++;
+       /*  Process the word if it is full. */
+       if (pmicdata->nBytesInM >= 4)
+       {
+               pmicdata->L ^= pmicdata->M;
+               pmicdata->R ^= ROL32(pmicdata->L, 17);
+               pmicdata->L += pmicdata->R;
+               pmicdata->R ^= ((pmicdata->L & 0xff00ff00) >> 8) | ((pmicdata->L & 0x00ff00ff) << 8);
+               pmicdata->L += pmicdata->R;
+               pmicdata->R ^= ROL32(pmicdata->L, 3);
+               pmicdata->L += pmicdata->R;
+               pmicdata->R ^= ROR32(pmicdata->L, 2);
+               pmicdata->L += pmicdata->R;
+               /*  Clear the buffer */
+               pmicdata->M = 0;
+               pmicdata->nBytesInM = 0;
+       }
+
+}
+
+void rtw_secmicappend23a(struct mic_data *pmicdata, u8 * src, u32 nbytes)
+{
+
+       /*  This is simple */
+       while(nbytes > 0)
+       {
+               rtw_secmicappend23abyte23a(pmicdata, *src++);
+               nbytes--;
+       }
+
+}
+
+void rtw_secgetmic23a(struct mic_data *pmicdata, u8 * dst)
+{
+
+       /*  Append the minimum padding */
+       rtw_secmicappend23abyte23a(pmicdata, 0x5a);
+       rtw_secmicappend23abyte23a(pmicdata, 0);
+       rtw_secmicappend23abyte23a(pmicdata, 0);
+       rtw_secmicappend23abyte23a(pmicdata, 0);
+       rtw_secmicappend23abyte23a(pmicdata, 0);
+       /*  and then zeroes until the length is a multiple of 4 */
+       while(pmicdata->nBytesInM != 0)
+       {
+               rtw_secmicappend23abyte23a(pmicdata, 0);
+       }
+       /*  The appendByte function has already computed the result. */
+       secmicputuint32(dst, pmicdata->L);
+       secmicputuint32(dst+4, pmicdata->R);
+       /*  Reset to the empty message. */
+       secmicclear(pmicdata);
+
+}
+
+void rtw_seccalctkipmic23a(u8 * key, u8 *header, u8 *data, u32 data_len, u8 *mic_code, u8 pri)
+{
+
+       struct mic_data micdata;
+       u8 priority[4]={0x0, 0x0, 0x0, 0x0};
+
+       rtw_secmicsetkey23a(&micdata, key);
+       priority[0]= pri;
+
+       /* Michael MIC pseudo header: DA, SA, 3 x 0, Priority */
+       if (header[1]&1) {   /* ToDS == 1 */
+                       rtw_secmicappend23a(&micdata, &header[16], 6);  /* DA */
+               if (header[1]&2)  /* From Ds == 1 */
+                       rtw_secmicappend23a(&micdata, &header[24], 6);
+               else
+                       rtw_secmicappend23a(&micdata, &header[10], 6);
+       }
+       else{   /* ToDS == 0 */
+               rtw_secmicappend23a(&micdata, &header[4], 6);   /* DA */
+               if (header[1]&2)  /* From Ds == 1 */
+                       rtw_secmicappend23a(&micdata, &header[16], 6);
+               else
+                       rtw_secmicappend23a(&micdata, &header[10], 6);
+
+       }
+       rtw_secmicappend23a(&micdata, &priority[0], 4);
+
+       rtw_secmicappend23a(&micdata, data, data_len);
+
+       rtw_secgetmic23a(&micdata, mic_code);
+
+}
+
+/* macros for extraction/creation of unsigned char/unsigned short values  */
+#define RotR1(v16)   ((((v16) >> 1) & 0x7FFF) ^ (((v16) & 1) << 15))
+#define   Lo8(v16)   ((u8)((v16)       & 0x00FF))
+#define   Hi8(v16)   ((u8)(((v16) >> 8) & 0x00FF))
+#define  Lo16(v32)   ((u16)((v32)       & 0xFFFF))
+#define  Hi16(v32)   ((u16)(((v32) >>16) & 0xFFFF))
+#define  Mk16(hi, lo) ((lo) ^ (((u16)(hi)) << 8))
+
+/* select the Nth 16-bit word of the temporal key unsigned char array TK[]   */
+#define  TK16(N)     Mk16(tk[2*(N)+1], tk[2*(N)])
+
+/* S-box lookup: 16 bits --> 16 bits */
+#define _S_(v16)     (Sbox1[0][Lo8(v16)] ^ Sbox1[1][Hi8(v16)])
+
+/* fixed algorithm "parameters" */
+#define PHASE1_LOOP_CNT   8    /* this needs to be "big enough"     */
+#define TA_SIZE           6    /*  48-bit transmitter address       */
+#define TK_SIZE          16    /* 128-bit temporal key              */
+#define P1K_SIZE         10    /*  80-bit Phase1 key                */
+#define RC4_KEY_SIZE     16    /* 128-bit RC4KEY (104 bits unknown) */
+
+/* 2-unsigned char by 2-unsigned char subset of the full AES S-box table */
+static const unsigned short Sbox1[2][256]=       /* Sbox for hash (can be in ROM)     */
+{ {
+   0xC6A5, 0xF884, 0xEE99, 0xF68D, 0xFF0D, 0xD6BD, 0xDEB1, 0x9154,
+   0x6050, 0x0203, 0xCEA9, 0x567D, 0xE719, 0xB562, 0x4DE6, 0xEC9A,
+   0x8F45, 0x1F9D, 0x8940, 0xFA87, 0xEF15, 0xB2EB, 0x8EC9, 0xFB0B,
+   0x41EC, 0xB367, 0x5FFD, 0x45EA, 0x23BF, 0x53F7, 0xE496, 0x9B5B,
+   0x75C2, 0xE11C, 0x3DAE, 0x4C6A, 0x6C5A, 0x7E41, 0xF502, 0x834F,
+   0x685C, 0x51F4, 0xD134, 0xF908, 0xE293, 0xAB73, 0x6253, 0x2A3F,
+   0x080C, 0x9552, 0x4665, 0x9D5E, 0x3028, 0x37A1, 0x0A0F, 0x2FB5,
+   0x0E09, 0x2436, 0x1B9B, 0xDF3D, 0xCD26, 0x4E69, 0x7FCD, 0xEA9F,
+   0x121B, 0x1D9E, 0x5874, 0x342E, 0x362D, 0xDCB2, 0xB4EE, 0x5BFB,
+   0xA4F6, 0x764D, 0xB761, 0x7DCE, 0x527B, 0xDD3E, 0x5E71, 0x1397,
+   0xA6F5, 0xB968, 0x0000, 0xC12C, 0x4060, 0xE31F, 0x79C8, 0xB6ED,
+   0xD4BE, 0x8D46, 0x67D9, 0x724B, 0x94DE, 0x98D4, 0xB0E8, 0x854A,
+   0xBB6B, 0xC52A, 0x4FE5, 0xED16, 0x86C5, 0x9AD7, 0x6655, 0x1194,
+   0x8ACF, 0xE910, 0x0406, 0xFE81, 0xA0F0, 0x7844, 0x25BA, 0x4BE3,
+   0xA2F3, 0x5DFE, 0x80C0, 0x058A, 0x3FAD, 0x21BC, 0x7048, 0xF104,
+   0x63DF, 0x77C1, 0xAF75, 0x4263, 0x2030, 0xE51A, 0xFD0E, 0xBF6D,
+   0x814C, 0x1814, 0x2635, 0xC32F, 0xBEE1, 0x35A2, 0x88CC, 0x2E39,
+   0x9357, 0x55F2, 0xFC82, 0x7A47, 0xC8AC, 0xBAE7, 0x322B, 0xE695,
+   0xC0A0, 0x1998, 0x9ED1, 0xA37F, 0x4466, 0x547E, 0x3BAB, 0x0B83,
+   0x8CCA, 0xC729, 0x6BD3, 0x283C, 0xA779, 0xBCE2, 0x161D, 0xAD76,
+   0xDB3B, 0x6456, 0x744E, 0x141E, 0x92DB, 0x0C0A, 0x486C, 0xB8E4,
+   0x9F5D, 0xBD6E, 0x43EF, 0xC4A6, 0x39A8, 0x31A4, 0xD337, 0xF28B,
+   0xD532, 0x8B43, 0x6E59, 0xDAB7, 0x018C, 0xB164, 0x9CD2, 0x49E0,
+   0xD8B4, 0xACFA, 0xF307, 0xCF25, 0xCAAF, 0xF48E, 0x47E9, 0x1018,
+   0x6FD5, 0xF088, 0x4A6F, 0x5C72, 0x3824, 0x57F1, 0x73C7, 0x9751,
+   0xCB23, 0xA17C, 0xE89C, 0x3E21, 0x96DD, 0x61DC, 0x0D86, 0x0F85,
+   0xE090, 0x7C42, 0x71C4, 0xCCAA, 0x90D8, 0x0605, 0xF701, 0x1C12,
+   0xC2A3, 0x6A5F, 0xAEF9, 0x69D0, 0x1791, 0x9958, 0x3A27, 0x27B9,
+   0xD938, 0xEB13, 0x2BB3, 0x2233, 0xD2BB, 0xA970, 0x0789, 0x33A7,
+   0x2DB6, 0x3C22, 0x1592, 0xC920, 0x8749, 0xAAFF, 0x5078, 0xA57A,
+   0x038F, 0x59F8, 0x0980, 0x1A17, 0x65DA, 0xD731, 0x84C6, 0xD0B8,
+   0x82C3, 0x29B0, 0x5A77, 0x1E11, 0x7BCB, 0xA8FC, 0x6DD6, 0x2C3A,
+  },
+
+  {  /* second half of table is unsigned char-reversed version of first! */
+   0xA5C6, 0x84F8, 0x99EE, 0x8DF6, 0x0DFF, 0xBDD6, 0xB1DE, 0x5491,
+   0x5060, 0x0302, 0xA9CE, 0x7D56, 0x19E7, 0x62B5, 0xE64D, 0x9AEC,
+   0x458F, 0x9D1F, 0x4089, 0x87FA, 0x15EF, 0xEBB2, 0xC98E, 0x0BFB,
+   0xEC41, 0x67B3, 0xFD5F, 0xEA45, 0xBF23, 0xF753, 0x96E4, 0x5B9B,
+   0xC275, 0x1CE1, 0xAE3D, 0x6A4C, 0x5A6C, 0x417E, 0x02F5, 0x4F83,
+   0x5C68, 0xF451, 0x34D1, 0x08F9, 0x93E2, 0x73AB, 0x5362, 0x3F2A,
+   0x0C08, 0x5295, 0x6546, 0x5E9D, 0x2830, 0xA137, 0x0F0A, 0xB52F,
+   0x090E, 0x3624, 0x9B1B, 0x3DDF, 0x26CD, 0x694E, 0xCD7F, 0x9FEA,
+   0x1B12, 0x9E1D, 0x7458, 0x2E34, 0x2D36, 0xB2DC, 0xEEB4, 0xFB5B,
+   0xF6A4, 0x4D76, 0x61B7, 0xCE7D, 0x7B52, 0x3EDD, 0x715E, 0x9713,
+   0xF5A6, 0x68B9, 0x0000, 0x2CC1, 0x6040, 0x1FE3, 0xC879, 0xEDB6,
+   0xBED4, 0x468D, 0xD967, 0x4B72, 0xDE94, 0xD498, 0xE8B0, 0x4A85,
+   0x6BBB, 0x2AC5, 0xE54F, 0x16ED, 0xC586, 0xD79A, 0x5566, 0x9411,
+   0xCF8A, 0x10E9, 0x0604, 0x81FE, 0xF0A0, 0x4478, 0xBA25, 0xE34B,
+   0xF3A2, 0xFE5D, 0xC080, 0x8A05, 0xAD3F, 0xBC21, 0x4870, 0x04F1,
+   0xDF63, 0xC177, 0x75AF, 0x6342, 0x3020, 0x1AE5, 0x0EFD, 0x6DBF,
+   0x4C81, 0x1418, 0x3526, 0x2FC3, 0xE1BE, 0xA235, 0xCC88, 0x392E,
+   0x5793, 0xF255, 0x82FC, 0x477A, 0xACC8, 0xE7BA, 0x2B32, 0x95E6,
+   0xA0C0, 0x9819, 0xD19E, 0x7FA3, 0x6644, 0x7E54, 0xAB3B, 0x830B,
+   0xCA8C, 0x29C7, 0xD36B, 0x3C28, 0x79A7, 0xE2BC, 0x1D16, 0x76AD,
+   0x3BDB, 0x5664, 0x4E74, 0x1E14, 0xDB92, 0x0A0C, 0x6C48, 0xE4B8,
+   0x5D9F, 0x6EBD, 0xEF43, 0xA6C4, 0xA839, 0xA431, 0x37D3, 0x8BF2,
+   0x32D5, 0x438B, 0x596E, 0xB7DA, 0x8C01, 0x64B1, 0xD29C, 0xE049,
+   0xB4D8, 0xFAAC, 0x07F3, 0x25CF, 0xAFCA, 0x8EF4, 0xE947, 0x1810,
+   0xD56F, 0x88F0, 0x6F4A, 0x725C, 0x2438, 0xF157, 0xC773, 0x5197,
+   0x23CB, 0x7CA1, 0x9CE8, 0x213E, 0xDD96, 0xDC61, 0x860D, 0x850F,
+   0x90E0, 0x427C, 0xC471, 0xAACC, 0xD890, 0x0506, 0x01F7, 0x121C,
+   0xA3C2, 0x5F6A, 0xF9AE, 0xD069, 0x9117, 0x5899, 0x273A, 0xB927,
+   0x38D9, 0x13EB, 0xB32B, 0x3322, 0xBBD2, 0x70A9, 0x8907, 0xA733,
+   0xB62D, 0x223C, 0x9215, 0x20C9, 0x4987, 0xFFAA, 0x7850, 0x7AA5,
+   0x8F03, 0xF859, 0x8009, 0x171A, 0xDA65, 0x31D7, 0xC684, 0xB8D0,
+   0xC382, 0xB029, 0x775A, 0x111E, 0xCB7B, 0xFCA8, 0xD66D, 0x3A2C,
+  }
+};
+
+ /*
+**********************************************************************
+* Routine: Phase 1 -- generate P1K, given TA, TK, IV32
+*
+* Inputs:
+*     tk[]      = temporal key                         [128 bits]
+*     ta[]      = transmitter's MAC address            [ 48 bits]
+*     iv32      = upper 32 bits of IV                  [ 32 bits]
+* Output:
+*     p1k[]     = Phase 1 key                          [ 80 bits]
+*
+* Note:
+*     This function only needs to be called every 2**16 packets,
+*     although in theory it could be called every packet.
+*
+**********************************************************************
+*/
+static void phase1(u16 *p1k, const u8 *tk, const u8 *ta, u32 iv32)
+{
+       int  i;
+
+       /* Initialize the 80 bits of P1K[] from IV32 and TA[0..5]     */
+       p1k[0]      = Lo16(iv32);
+       p1k[1]      = Hi16(iv32);
+       p1k[2]      = Mk16(ta[1], ta[0]); /* use TA[] as little-endian */
+       p1k[3]      = Mk16(ta[3], ta[2]);
+       p1k[4]      = Mk16(ta[5], ta[4]);
+
+       /* Now compute an unbalanced Feistel cipher with 80-bit block */
+       /* size on the 80-bit block P1K[], using the 128-bit key TK[] */
+       for (i = 0; i < PHASE1_LOOP_CNT ;i++)
+       {                 /* Each add operation here is mod 2**16 */
+               p1k[0] += _S_(p1k[4] ^ TK16((i&1)+0));
+               p1k[1] += _S_(p1k[0] ^ TK16((i&1)+2));
+               p1k[2] += _S_(p1k[1] ^ TK16((i&1)+4));
+               p1k[3] += _S_(p1k[2] ^ TK16((i&1)+6));
+               p1k[4] += _S_(p1k[3] ^ TK16((i&1)+0));
+               p1k[4] +=  (unsigned short)i;                    /* avoid "slide attacks" */
+               }
+
+}
+
+/*
+**********************************************************************
+* Routine: Phase 2 -- generate RC4KEY, given TK, P1K, IV16
+*
+* Inputs:
+*     tk[]      = Temporal key                         [128 bits]
+*     p1k[]     = Phase 1 output key                   [ 80 bits]
+*     iv16      = low 16 bits of IV counter            [ 16 bits]
+* Output:
+*     rc4key[]  = the key used to encrypt the packet   [128 bits]
+*
+* Note:
+*     The value {TA, IV32, IV16} for Phase1/Phase2 must be unique
+*     across all packets using the same key TK value. Then, for a
+*     given value of TK[], this TKIP48 construction guarantees that
+*     the final RC4KEY value is unique across all packets.
+*
+* Suggested implementation optimization: if PPK[] is "overlaid"
+*     appropriately on RC4KEY[], there is no need for the final
+*     for loop below that copies the PPK[] result into RC4KEY[].
+*
+**********************************************************************
+*/
+static void phase2(u8 *rc4key, const u8 *tk, const u16 *p1k, u16 iv16)
+{
+       int  i;
+       u16 PPK[6];                          /* temporary key for mixing    */
+
+       /* Note: all adds in the PPK[] equations below are mod 2**16         */
+       for (i = 0;i<5;i++) PPK[i]= p1k[i];      /* first, copy P1K to PPK      */
+               PPK[5]  =  p1k[4] +iv16;             /* next,  add in IV16          */
+
+       /* Bijective non-linear mixing of the 96 bits of PPK[0..5]           */
+       PPK[0] +=    _S_(PPK[5] ^ TK16(0));   /* Mix key in each "round"     */
+       PPK[1] +=    _S_(PPK[0] ^ TK16(1));
+       PPK[2] +=    _S_(PPK[1] ^ TK16(2));
+       PPK[3] +=    _S_(PPK[2] ^ TK16(3));
+       PPK[4] +=    _S_(PPK[3] ^ TK16(4));
+       PPK[5] +=    _S_(PPK[4] ^ TK16(5));   /* Total # S-box lookups == 6  */
+
+       /* Final sweep: bijective, "linear". Rotates kill LSB correlations   */
+       PPK[0] +=  RotR1(PPK[5] ^ TK16(6));
+       PPK[1] +=  RotR1(PPK[0] ^ TK16(7));   /* Use all of TK[] in Phase2   */
+       PPK[2] +=  RotR1(PPK[1]);
+       PPK[3] +=  RotR1(PPK[2]);
+       PPK[4] +=  RotR1(PPK[3]);
+       PPK[5] +=  RotR1(PPK[4]);
+       /* Note: At this point, for a given key TK[0..15], the 96-bit output */
+       /*       value PPK[0..5] is guaranteed to be unique, as a function   */
+       /*       of the 96-bit "input" value   {TA, IV32, IV16}. That is, P1K  */
+       /*       is now a keyed permutation of {TA, IV32, IV16}.               */
+
+       /* Set RC4KEY[0..3], which includes "cleartext" portion of RC4 key   */
+       rc4key[0] = Hi8(iv16);                /* RC4KEY[0..2] is the WEP IV  */
+       rc4key[1] = (Hi8(iv16) | 0x20) & 0x7F; /* Help avoid weak (FMS) keys  */
+       rc4key[2] = Lo8(iv16);
+       rc4key[3] = Lo8((PPK[5] ^ TK16(0)) >> 1);
+
+       /* Copy 96 bits of PPK[0..5] to RC4KEY[4..15]  (little-endian)       */
+       for (i = 0;i<6;i++)
+       {
+               rc4key[4+2*i] = Lo8(PPK[i]);
+               rc4key[5+2*i] = Hi8(PPK[i]);
+       }
+
+}
+
+/* The hlen isn't include the IV */
+u32 rtw_tkip_encrypt23a(struct rtw_adapter *padapter,
+                    struct xmit_frame *pxmitframe)
+{                                                                                                                                      /*  exclude ICV */
+       u16     pnl;
+       u32     pnh;
+       u8      rc4key[16];
+       u8   ttkey[16];
+       u8      crc[4];
+       u8   hw_hdr_offset = 0;
+       struct arc4context mycontext;
+       int                     curfragnum, length;
+       u32     prwskeylen;
+
+       u8      *pframe, *payload,*iv,*prwskey;
+       union pn48 dot11txpn;
+       struct  sta_info                *stainfo;
+       struct  pkt_attrib       *pattrib = &pxmitframe->attrib;
+       struct  security_priv   *psecuritypriv = &padapter->securitypriv;
+       struct  xmit_priv               *pxmitpriv = &padapter->xmitpriv;
+       u32     res = _SUCCESS;
+
+       if (!pxmitframe->buf_addr)
+               return _FAIL;
+
+       hw_hdr_offset = TXDESC_OFFSET;
+
+       pframe = pxmitframe->buf_addr + hw_hdr_offset;
+       /* 4 start to encrypt each fragment */
+       if (pattrib->encrypt == _TKIP_) {
+
+               if (pattrib->psta)
+               {
+                       stainfo = pattrib->psta;
+               }
+               else
+               {
+                       DBG_8723A("%s, call rtw_get_stainfo()\n", __func__);
+                       stainfo = rtw_get_stainfo23a(&padapter->stapriv,
+                                                    &pattrib->ra[0]);
+               }
+
+               if (stainfo!= NULL) {
+
+                       if (!(stainfo->state &_FW_LINKED))
+                       {
+                               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, stainfo->state);
+                               return _FAIL;
+                       }
+
+                       RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt23a: stainfo!= NULL!!!\n"));
+
+                       if (is_multicast_ether_addr(pattrib->ra))
+                               prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
+                       else
+                               prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+
+                       prwskeylen = 16;
+
+                       for (curfragnum = 0;curfragnum<pattrib->nr_frags;curfragnum++) {
+                               iv = pframe+pattrib->hdrlen;
+                               payload = pframe+pattrib->iv_len+pattrib->hdrlen;
+
+                               GET_TKIP_PN(iv, dot11txpn);
+
+                               pnl = (u16)(dot11txpn.val);
+                               pnh = (u32)(dot11txpn.val>>16);
+
+                               phase1((u16 *)&ttkey[0], prwskey,&pattrib->ta[0], pnh);
+
+                               phase2(&rc4key[0], prwskey, (u16 *)&ttkey[0], pnl);
+
+                               if ((curfragnum+1) == pattrib->nr_frags) {      /* 4 the last fragment */
+                                       length = pattrib->last_txcmdsz-pattrib->hdrlen-pattrib->iv_len- pattrib->icv_len;
+                                       RT_TRACE(_module_rtl871x_security_c_, _drv_info_, ("pattrib->iv_len =%x, pattrib->icv_len =%x\n", pattrib->iv_len, pattrib->icv_len));
+                                       *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length));/* modified by Amy*/
+
+                                       arcfour_init(&mycontext, rc4key, 16);
+                                       arcfour_encrypt(&mycontext, payload, payload, length);
+                                       arcfour_encrypt(&mycontext, payload+length, crc, 4);
+
+                               }
+                               else{
+                                       length = pxmitpriv->frag_len-pattrib->hdrlen-pattrib->iv_len-pattrib->icv_len ;
+                                       *((u32 *)crc) = cpu_to_le32(getcrc32(payload, length));/* modified by Amy*/
+                                       arcfour_init(&mycontext, rc4key, 16);
+                                       arcfour_encrypt(&mycontext, payload, payload, length);
+                                       arcfour_encrypt(&mycontext, payload+length, crc, 4);
+
+                               pframe+= pxmitpriv->frag_len;
+                               pframe = PTR_ALIGN(pframe, 4);
+                               }
+                       }
+
+               }
+               else{
+                       RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_encrypt23a: stainfo == NULL!!!\n"));
+                               DBG_8723A("%s, psta == NUL\n", __func__);
+                       res = _FAIL;
+               }
+
+       }
+
+       return res;
+}
+
+/* The hlen isn't include the IV */
+u32 rtw_tkip_decrypt23a(struct rtw_adapter *padapter,
+                    struct recv_frame *precvframe)
+{
+       /*  exclude ICV */
+       u16 pnl;
+       u32 pnh;
+       u8   rc4key[16];
+       u8   ttkey[16];
+       u8      crc[4];
+       struct arc4context mycontext;
+       int     length;
+       u32     prwskeylen;
+       u8      *pframe, *payload,*iv,*prwskey;
+       union pn48 dot11txpn;
+       struct  sta_info                *stainfo;
+       struct  rx_pkt_attrib *prxattrib = &precvframe->attrib;
+       struct  security_priv *psecuritypriv = &padapter->securitypriv;
+       struct sk_buff * skb = precvframe->pkt;
+       u32     res = _SUCCESS;
+
+       pframe = skb->data;
+
+       /* 4 start to decrypt recvframe */
+       if (prxattrib->encrypt == _TKIP_) {
+
+               stainfo = rtw_get_stainfo23a(&padapter->stapriv,
+                                            &prxattrib->ta[0]);
+               if (stainfo!= NULL) {
+
+                       if (is_multicast_ether_addr(prxattrib->ra)) {
+                               if (psecuritypriv->binstallGrpkey == false) {
+                                       res = _FAIL;
+                                       DBG_8723A("%s:rx bc/mc packets, but didn't install group key!!!!!!!!!!\n", __func__);
+                                       goto exit;
+                               }
+                               prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
+                               prwskeylen = 16;
+                       } else {
+                               RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt23a: stainfo!= NULL!!!\n"));
+                               prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+                               prwskeylen = 16;
+                       }
+
+                       iv = pframe+prxattrib->hdrlen;
+                       payload = pframe+prxattrib->iv_len+prxattrib->hdrlen;
+                       length = skb->len - prxattrib->hdrlen-prxattrib->iv_len;
+
+                       GET_TKIP_PN(iv, dot11txpn);
+
+                       pnl = (u16)(dot11txpn.val);
+                       pnh = (u32)(dot11txpn.val>>16);
+
+                       phase1((u16 *)&ttkey[0], prwskey,&prxattrib->ta[0], pnh);
+                       phase2(&rc4key[0], prwskey, (unsigned short *)&ttkey[0], pnl);
+
+                       /* 4 decrypt payload include icv */
+                       arcfour_init(&mycontext, rc4key, 16);
+                       arcfour_encrypt(&mycontext, payload, payload, length);
+
+                       *((u32 *)crc) = le32_to_cpu(getcrc32(payload, length-4));
+
+                       if (crc[3]!= payload[length-1] || crc[2]!= payload[length-2] || crc[1]!= payload[length-3] || crc[0]!= payload[length-4])
+                       {
+                           RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_wep_decrypt23a:icv error crc[3](%x)!= payload[length-1](%x) || crc[2](%x)!= payload[length-2](%x) || crc[1](%x)!= payload[length-3](%x) || crc[0](%x)!= payload[length-4](%x)\n",
+                                               crc[3], payload[length-1], crc[2], payload[length-2], crc[1], payload[length-3], crc[0], payload[length-4]));
+                               res = _FAIL;
+                       }
+               } else {
+                       RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("rtw_tkip_decrypt23a: stainfo == NULL!!!\n"));
+                       res = _FAIL;
+               }
+       }
+exit:
+       return res;
+}
+
+/* 3                   ===== AES related ===== */
+
+#define MAX_MSG_SIZE   2048
+/*****************************/
+/******** SBOX Table *********/
+/*****************************/
+
+static  u8 sbox_table[256] = {
+       0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5,
+       0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+       0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+       0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+       0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc,
+       0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+       0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a,
+       0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+       0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+       0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+       0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b,
+       0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+       0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85,
+       0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+       0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+       0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+       0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17,
+       0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+       0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88,
+       0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+       0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+       0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+       0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9,
+       0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+       0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6,
+       0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+       0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+       0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+       0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94,
+       0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+       0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68,
+       0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
+};
+
+/*****************************/
+/**** Function Prototypes ****/
+/*****************************/
+
+static void construct_mic_header2(u8 *mic_header2, u8 *mpdu, int a4_exists,
+                                 int qc_exists);
+
+static void xor_128(u8 *a, u8 *b, u8 *out)
+{
+       int i;
+
+       for (i = 0;i<16; i++)
+               out[i] = a[i] ^ b[i];
+}
+
+static void xor_32(u8 *a, u8 *b, u8 *out)
+{
+       int i;
+
+       for (i = 0; i < 4; i++)
+               out[i] = a[i] ^ b[i];
+}
+
+static u8 sbox(u8 a)
+{
+       return sbox_table[(int)a];
+}
+
+static void next_key(u8 *key, int round)
+{
+       u8 rcon;
+       u8 sbox_key[4];
+       u8 rcon_table[12] =
+       {
+               0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80,
+               0x1b, 0x36, 0x36, 0x36
+       };
+
+       sbox_key[0] = sbox(key[13]);
+       sbox_key[1] = sbox(key[14]);
+       sbox_key[2] = sbox(key[15]);
+       sbox_key[3] = sbox(key[12]);
+
+       rcon = rcon_table[round];
+
+       xor_32(&key[0], sbox_key, &key[0]);
+       key[0] = key[0] ^ rcon;
+
+       xor_32(&key[4], &key[0], &key[4]);
+       xor_32(&key[8], &key[4], &key[8]);
+       xor_32(&key[12], &key[8], &key[12]);
+
+}
+
+static void byte_sub(u8 *in, u8 *out)
+{
+       int i;
+
+       for (i = 0; i< 16; i++)
+       {
+               out[i] = sbox(in[i]);
+       }
+
+}
+
+static void shift_row(u8 *in, u8 *out)
+{
+
+       out[0] =  in[0];
+       out[1] =  in[5];
+       out[2] =  in[10];
+       out[3] =  in[15];
+       out[4] =  in[4];
+       out[5] =  in[9];
+       out[6] =  in[14];
+       out[7] =  in[3];
+       out[8] =  in[8];
+       out[9] =  in[13];
+       out[10] = in[2];
+       out[11] = in[7];
+       out[12] = in[12];
+       out[13] = in[1];
+       out[14] = in[6];
+       out[15] = in[11];
+
+}
+
+static void mix_column(u8 *in, u8 *out)
+{
+       int i;
+       u8 add1b[4];
+       u8 add1bf7[4];
+       u8 rotl[4];
+       u8 swap_halfs[4];
+       u8 andf7[4];
+       u8 rotr[4];
+       u8 temp[4];
+       u8 tempb[4];
+
+       for (i = 0 ; i<4; i++)
+       {
+               if ((in[i] & 0x80) == 0x80)
+                   add1b[i] = 0x1b;
+               else
+                   add1b[i] = 0x00;
+       }
+
+       swap_halfs[0] = in[2];    /* Swap halfs */
+       swap_halfs[1] = in[3];
+       swap_halfs[2] = in[0];
+       swap_halfs[3] = in[1];
+
+       rotl[0] = in[3];        /* Rotate left 8 bits */
+       rotl[1] = in[0];
+       rotl[2] = in[1];
+       rotl[3] = in[2];
+
+       andf7[0] = in[0] & 0x7f;
+       andf7[1] = in[1] & 0x7f;
+       andf7[2] = in[2] & 0x7f;
+       andf7[3] = in[3] & 0x7f;
+
+       for (i = 3; i>0; i--)    /* logical shift left 1 bit */
+       {
+               andf7[i] = andf7[i] << 1;
+               if ((andf7[i-1] & 0x80) == 0x80)
+               {
+                   andf7[i] = (andf7[i] | 0x01);
+               }
+       }
+       andf7[0] = andf7[0] << 1;
+       andf7[0] = andf7[0] & 0xfe;
+
+       xor_32(add1b, andf7, add1bf7);
+
+       xor_32(in, add1bf7, rotr);
+
+       temp[0] = rotr[0];         /* Rotate right 8 bits */
+       rotr[0] = rotr[1];
+       rotr[1] = rotr[2];
+       rotr[2] = rotr[3];
+       rotr[3] = temp[0];
+
+       xor_32(add1bf7, rotr, temp);
+       xor_32(swap_halfs, rotl, tempb);
+       xor_32(temp, tempb, out);
+
+}
+
+static void aes128k128d(u8 *key, u8 *data, u8 *ciphertext)
+{
+       int round;
+       int i;
+       u8 intermediatea[16];
+       u8 intermediateb[16];
+       u8 round_key[16];
+
+       for (i = 0; i<16; i++) round_key[i] = key[i];
+
+       for (round = 0; round < 11; round++)
+       {
+               if (round == 0)
+               {
+                   xor_128(round_key, data, ciphertext);
+                   next_key(round_key, round);
+               }
+               else if (round == 10)
+               {
+                   byte_sub(ciphertext, intermediatea);
+                   shift_row(intermediatea, intermediateb);
+                   xor_128(intermediateb, round_key, ciphertext);
+               }
+               else    /* 1 - 9 */
+               {
+                   byte_sub(ciphertext, intermediatea);
+                   shift_row(intermediatea, intermediateb);
+                   mix_column(&intermediateb[0], &intermediatea[0]);
+                   mix_column(&intermediateb[4], &intermediatea[4]);
+                   mix_column(&intermediateb[8], &intermediatea[8]);
+                   mix_column(&intermediateb[12], &intermediatea[12]);
+                   xor_128(intermediatea, round_key, ciphertext);
+                   next_key(round_key, round);
+               }
+       }
+
+}
+
+/************************************************/
+/* construct_mic_iv()                           */
+/* Builds the MIC IV from header fields and PN  */
+/************************************************/
+static void construct_mic_iv(u8 *mic_iv, int qc_exists, int a4_exists, u8 *mpdu,
+                            uint payload_length, u8 *pn_vector)
+{
+       int i;
+
+       mic_iv[0] = 0x59;
+       if (qc_exists && a4_exists)
+               mic_iv[1] = mpdu[30] & 0x0f;    /* QoS_TC           */
+       if (qc_exists && !a4_exists)
+               mic_iv[1] = mpdu[24] & 0x0f;   /* mute bits 7-4    */
+       if (!qc_exists)
+               mic_iv[1] = 0x00;
+       for (i = 2; i < 8; i++)
+               mic_iv[i] = mpdu[i + 8]; /* mic_iv[2:7] = A2[0:5] = mpdu[10:15] */
+       for (i = 8; i < 14; i++)
+               mic_iv[i] = pn_vector[13 - i]; /* mic_iv[8:13] = PN[5:0] */
+       mic_iv[14] = (unsigned char)(payload_length / 256);
+       mic_iv[15] = (unsigned char)(payload_length % 256);
+}
+
+/************************************************/
+/* construct_mic_header1()                      */
+/* Builds the first MIC header block from       */
+/* header fields.                               */
+/************************************************/
+static void construct_mic_header1(u8 *mic_header1, int header_length, u8 *mpdu)
+{
+       mic_header1[0] = (u8)((header_length - 2) / 256);
+       mic_header1[1] = (u8)((header_length - 2) % 256);
+       mic_header1[2] = mpdu[0] & 0xcf;    /* Mute CF poll & CF ack bits */
+       mic_header1[3] = mpdu[1] & 0xc7;    /* Mute retry, more data and pwr mgt bits */
+       mic_header1[4] = mpdu[4];       /* A1 */
+       mic_header1[5] = mpdu[5];
+       mic_header1[6] = mpdu[6];
+       mic_header1[7] = mpdu[7];
+       mic_header1[8] = mpdu[8];
+       mic_header1[9] = mpdu[9];
+       mic_header1[10] = mpdu[10];     /* A2 */
+       mic_header1[11] = mpdu[11];
+       mic_header1[12] = mpdu[12];
+       mic_header1[13] = mpdu[13];
+       mic_header1[14] = mpdu[14];
+       mic_header1[15] = mpdu[15];
+
+}
+
+/************************************************/
+       /* construct_mic_header2()                      */
+/* Builds the last MIC header block from        */
+/* header fields.                               */
+/************************************************/
+static void construct_mic_header2(
+                       u8 *mic_header2,
+                       u8 *mpdu,
+                       int a4_exists,
+                       int qc_exists
+                     )
+{
+       int i;
+
+       for (i = 0; i<16; i++) mic_header2[i]= 0x00;
+
+       mic_header2[0] = mpdu[16];    /* A3 */
+       mic_header2[1] = mpdu[17];
+       mic_header2[2] = mpdu[18];
+       mic_header2[3] = mpdu[19];
+       mic_header2[4] = mpdu[20];
+       mic_header2[5] = mpdu[21];
+
+       mic_header2[6] = 0x00;
+       mic_header2[7] = 0x00; /* mpdu[23]; */
+
+       if (!qc_exists && a4_exists)
+       {
+               for (i = 0;i<6;i++) mic_header2[8+i] = mpdu[24+i];   /* A4 */
+
+       }
+
+       if (qc_exists && !a4_exists)
+       {
+               mic_header2[8] = mpdu[24] & 0x0f; /* mute bits 15 - 4 */
+               mic_header2[9] = mpdu[25] & 0x00;
+       }
+
+       if (qc_exists && a4_exists)
+       {
+               for (i = 0;i<6;i++) mic_header2[8+i] = mpdu[24+i];   /* A4 */
+
+               mic_header2[14] = mpdu[30] & 0x0f;
+               mic_header2[15] = mpdu[31] & 0x00;
+       }
+
+}
+
+/************************************************/
+/* construct_mic_header2()                      */
+/* Builds the last MIC header block from        */
+/* header fields.                               */
+/************************************************/
+static void construct_ctr_preload(u8 *ctr_preload, int a4_exists, int qc_exists,
+                                 u8 *mpdu, u8 *pn_vector, int c)
+{
+       int i = 0;
+
+       for (i = 0; i<16; i++) ctr_preload[i] = 0x00;
+       i = 0;
+
+       ctr_preload[0] = 0x01;                                  /* flag */
+       if (qc_exists && a4_exists)
+               ctr_preload[1] = mpdu[30] & 0x0f;   /* QoC_Control */
+       if (qc_exists && !a4_exists)
+               ctr_preload[1] = mpdu[24] & 0x0f;
+
+       for (i = 2; i < 8; i++)
+               ctr_preload[i] = mpdu[i + 8];                       /* ctr_preload[2:7] = A2[0:5] = mpdu[10:15] */
+       for (i = 8; i < 14; i++)
+               ctr_preload[i] =    pn_vector[13 - i];          /* ctr_preload[8:13] = PN[5:0] */
+       ctr_preload[14] =  (unsigned char) (c / 256); /* Ctr */
+       ctr_preload[15] =  (unsigned char) (c % 256);
+
+}
+
+/************************************/
+/* bitwise_xor()                    */
+/* A 128 bit, bitwise exclusive or  */
+/************************************/
+static void bitwise_xor(u8 *ina, u8 *inb, u8 *out)
+{
+       int i;
+
+       for (i = 0; i < 16; i++)
+               out[i] = ina[i] ^ inb[i];
+}
+
+static int aes_cipher(u8 *key, uint hdrlen, u8 *pframe, uint plen)
+{
+       uint    qc_exists, a4_exists, i, j, payload_remainder,
+               num_blocks, payload_index;
+       u8 pn_vector[6];
+       u8 mic_iv[16];
+       u8 mic_header1[16];
+       u8 mic_header2[16];
+       u8 ctr_preload[16];
+       /* Intermediate Buffers */
+       u8 chain_buffer[16];
+       u8 aes_out[16];
+       u8 padded_buffer[16];
+       u8 mic[8];
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe;
+       u16 frsubtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE;
+
+       memset((void *)mic_iv, 0, 16);
+       memset((void *)mic_header1, 0, 16);
+       memset((void *)mic_header2, 0, 16);
+       memset((void *)ctr_preload, 0, 16);
+       memset((void *)chain_buffer, 0, 16);
+       memset((void *)aes_out, 0, 16);
+       memset((void *)padded_buffer, 0, 16);
+
+       if ((hdrlen == sizeof(struct ieee80211_hdr_3addr) ||
+           (hdrlen == sizeof(struct ieee80211_qos_hdr))))
+               a4_exists = 0;
+       else
+               a4_exists = 1;
+
+       if (ieee80211_is_data(hdr->frame_control)) {
+               if ((frsubtype == IEEE80211_STYPE_DATA_CFACK) ||
+                   (frsubtype == IEEE80211_STYPE_DATA_CFPOLL) ||
+                   (frsubtype == IEEE80211_STYPE_DATA_CFACKPOLL)) {
+                       qc_exists = 1;
+                       if (hdrlen != sizeof(struct ieee80211_qos_hdr))
+                               hdrlen += 2;
+               } else if ((frsubtype == IEEE80211_STYPE_QOS_DATA) ||
+                          (frsubtype == IEEE80211_STYPE_QOS_DATA_CFACK) ||
+                          (frsubtype == IEEE80211_STYPE_QOS_DATA_CFPOLL) ||
+                          (frsubtype == IEEE80211_STYPE_QOS_DATA_CFACKPOLL)) {
+                       if (hdrlen != sizeof(struct ieee80211_qos_hdr))
+                               hdrlen += 2;
+                       qc_exists = 1;
+               } else {
+                       qc_exists = 0;
+               }
+       } else {
+               qc_exists = 0;
+       }
+       pn_vector[0]= pframe[hdrlen];
+       pn_vector[1]= pframe[hdrlen+1];
+       pn_vector[2]= pframe[hdrlen+4];
+       pn_vector[3]= pframe[hdrlen+5];
+       pn_vector[4]= pframe[hdrlen+6];
+       pn_vector[5]= pframe[hdrlen+7];
+
+       construct_mic_iv(mic_iv, qc_exists, a4_exists, pframe, plen, pn_vector);
+
+       construct_mic_header1(mic_header1, hdrlen, pframe);
+       construct_mic_header2(mic_header2, pframe, a4_exists, qc_exists);
+
+       payload_remainder = plen % 16;
+       num_blocks = plen / 16;
+
+       /* Find start of payload */
+       payload_index = (hdrlen + 8);
+
+       /* Calculate MIC */
+       aes128k128d(key, mic_iv, aes_out);
+       bitwise_xor(aes_out, mic_header1, chain_buffer);
+       aes128k128d(key, chain_buffer, aes_out);
+       bitwise_xor(aes_out, mic_header2, chain_buffer);
+       aes128k128d(key, chain_buffer, aes_out);
+
+       for (i = 0; i < num_blocks; i++) {
+               bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
+
+               payload_index += 16;
+               aes128k128d(key, chain_buffer, aes_out);
+       }
+
+       /* Add on the final payload block if it needs padding */
+       if (payload_remainder > 0) {
+               for (j = 0; j < 16; j++)
+                       padded_buffer[j] = 0x00;
+               for (j = 0; j < payload_remainder; j++)
+                       padded_buffer[j] = pframe[payload_index++];
+               bitwise_xor(aes_out, padded_buffer, chain_buffer);
+               aes128k128d(key, chain_buffer, aes_out);
+       }
+
+       for (j = 0; j < 8; j++)
+               mic[j] = aes_out[j];
+
+       /* Insert MIC into payload */
+       for (j = 0; j < 8; j++)
+               pframe[payload_index+j] = mic[j];
+
+       payload_index = hdrlen + 8;
+       for (i = 0; i < num_blocks; i++) {
+               construct_ctr_preload(ctr_preload, a4_exists, qc_exists,
+                                     pframe, pn_vector, i+1);
+               aes128k128d(key, ctr_preload, aes_out);
+               bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
+               for (j = 0; j < 16; j++)
+                       pframe[payload_index++] = chain_buffer[j];
+       }
+
+       if (payload_remainder > 0) {
+               /* If there is a short final block, then pad it,
+                * encrypt it and copy the unpadded part back
+                */
+               construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe,
+                                     pn_vector, num_blocks+1);
+
+               for (j = 0; j < 16; j++)
+                       padded_buffer[j] = 0x00;
+               for (j = 0; j < payload_remainder; j++)
+                       padded_buffer[j] = pframe[payload_index+j];
+               aes128k128d(key, ctr_preload, aes_out);
+               bitwise_xor(aes_out, padded_buffer, chain_buffer);
+               for (j = 0; j < payload_remainder;j++)
+                       pframe[payload_index++] = chain_buffer[j];
+       }
+
+       /* Encrypt the MIC */
+       construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe,
+                             pn_vector, 0);
+
+       for (j = 0; j < 16; j++)
+               padded_buffer[j] = 0x00;
+       for (j = 0; j < 8; j++)
+               padded_buffer[j] = pframe[j+hdrlen+8+plen];
+
+       aes128k128d(key, ctr_preload, aes_out);
+       bitwise_xor(aes_out, padded_buffer, chain_buffer);
+       for (j = 0; j < 8;j++)
+               pframe[payload_index++] = chain_buffer[j];
+
+       return _SUCCESS;
+}
+
+u32 rtw_aes_encrypt23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{      /*  exclude ICV */
+       /* Intermediate Buffers */
+       int curfragnum, length;
+       u32 prwskeylen;
+       u8 *pframe, *prwskey;   /*  *payload,*iv */
+       u8 hw_hdr_offset = 0;
+       struct sta_info *stainfo;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       u32 res = _SUCCESS;
+
+       if (!pxmitframe->buf_addr)
+               return _FAIL;
+
+       hw_hdr_offset = TXDESC_OFFSET;
+
+       pframe = pxmitframe->buf_addr + hw_hdr_offset;
+
+       /* 4 start to encrypt each fragment */
+       if (pattrib->encrypt != _AES_)
+               return _FAIL;
+
+       if (pattrib->psta) {
+               stainfo = pattrib->psta;
+       } else {
+               DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
+               stainfo = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]);
+       }
+
+       if (!stainfo) {
+               RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+                        ("rtw_aes_encrypt23a: stainfo == NULL!!!\n"));
+               DBG_8723A("%s, psta == NUL\n", __func__);
+               res = _FAIL;
+               goto out;
+       }
+       if (!(stainfo->state &_FW_LINKED)) {
+               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n",
+                         __func__, stainfo->state);
+               return _FAIL;
+       }
+       RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+                ("rtw_aes_encrypt23a: stainfo!= NULL!!!\n"));
+
+       if (is_multicast_ether_addr(pattrib->ra))
+               prwskey = psecuritypriv->dot118021XGrpKey[psecuritypriv->dot118021XGrpKeyid].skey;
+       else
+               prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+
+       prwskeylen = 16;
+
+       for (curfragnum = 0; curfragnum < pattrib->nr_frags; curfragnum++) {
+               /* 4 the last fragment */
+               if ((curfragnum + 1) == pattrib->nr_frags) {
+                       length = pattrib->last_txcmdsz -
+                               pattrib->hdrlen-pattrib->iv_len -
+                               pattrib->icv_len;
+
+                       aes_cipher(prwskey, pattrib->hdrlen, pframe, length);
+               } else {
+                       length = pxmitpriv->frag_len-pattrib->hdrlen -
+                               pattrib->iv_len - pattrib->icv_len;
+
+                       aes_cipher(prwskey, pattrib->hdrlen, pframe, length);
+                       pframe += pxmitpriv->frag_len;
+                       pframe = PTR_ALIGN(pframe, 4);
+               }
+       }
+out:
+       return res;
+}
+
+static int aes_decipher(u8 *key, uint  hdrlen,
+                       u8 *pframe, uint plen)
+{
+       static u8       message[MAX_MSG_SIZE];
+       uint    qc_exists, a4_exists, i, j, payload_remainder,
+                       num_blocks, payload_index;
+       int res = _SUCCESS;
+       u8 pn_vector[6];
+       u8 mic_iv[16];
+       u8 mic_header1[16];
+       u8 mic_header2[16];
+       u8 ctr_preload[16];
+       /* Intermediate Buffers */
+       u8 chain_buffer[16];
+       u8 aes_out[16];
+       u8 padded_buffer[16];
+       u8 mic[8];
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)pframe;
+       u16 frsubtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE;
+
+       memset((void *)mic_iv, 0, 16);
+       memset((void *)mic_header1, 0, 16);
+       memset((void *)mic_header2, 0, 16);
+       memset((void *)ctr_preload, 0, 16);
+       memset((void *)chain_buffer, 0, 16);
+       memset((void *)aes_out, 0, 16);
+       memset((void *)padded_buffer, 0, 16);
+
+       /* start to decrypt the payload */
+
+       num_blocks = (plen-8) / 16; /* plen including llc, payload_length and mic) */
+
+       payload_remainder = (plen-8) % 16;
+
+       pn_vector[0]  = pframe[hdrlen];
+       pn_vector[1]  = pframe[hdrlen+1];
+       pn_vector[2]  = pframe[hdrlen+4];
+       pn_vector[3]  = pframe[hdrlen+5];
+       pn_vector[4]  = pframe[hdrlen+6];
+       pn_vector[5]  = pframe[hdrlen+7];
+
+       if ((hdrlen == sizeof(struct ieee80211_hdr_3addr) ||
+           (hdrlen == sizeof(struct ieee80211_qos_hdr))))
+               a4_exists = 0;
+       else
+               a4_exists = 1;
+
+       if (ieee80211_is_data(hdr->frame_control)) {
+               if ((frsubtype == IEEE80211_STYPE_DATA_CFACK) ||
+                   (frsubtype == IEEE80211_STYPE_DATA_CFPOLL) ||
+                   (frsubtype == IEEE80211_STYPE_DATA_CFACKPOLL)) {
+                       qc_exists = 1;
+                       if (hdrlen != sizeof(struct ieee80211_hdr_3addr))
+                               hdrlen += 2;
+               } else if ((frsubtype == IEEE80211_STYPE_QOS_DATA) ||
+                          (frsubtype == IEEE80211_STYPE_QOS_DATA_CFACK) ||
+                          (frsubtype == IEEE80211_STYPE_QOS_DATA_CFPOLL) ||
+                          (frsubtype == IEEE80211_STYPE_QOS_DATA_CFACKPOLL)) {
+                       if (hdrlen != sizeof(struct ieee80211_hdr_3addr))
+                               hdrlen += 2;
+                       qc_exists = 1;
+               } else {
+                       qc_exists = 0;
+               }
+       } else {
+               qc_exists = 0;
+       }
+
+       /*  now, decrypt pframe with hdrlen offset and plen long */
+
+       payload_index = hdrlen + 8; /*  8 is for extiv */
+
+       for (i = 0; i < num_blocks; i++) {
+               construct_ctr_preload(ctr_preload, a4_exists, qc_exists,
+                                     pframe, pn_vector, i+1);
+
+               aes128k128d(key, ctr_preload, aes_out);
+               bitwise_xor(aes_out, &pframe[payload_index], chain_buffer);
+
+               for (j = 0; j < 16; j++)
+                       pframe[payload_index++] = chain_buffer[j];
+       }
+
+       if (payload_remainder > 0) {
+               /* If there is a short final block, then pad it,
+                * encrypt it and copy the unpadded part back
+                */
+               construct_ctr_preload(ctr_preload, a4_exists, qc_exists, pframe,
+                                     pn_vector, num_blocks+1);
+
+               for (j = 0; j < 16; j++)
+                       padded_buffer[j] = 0x00;
+               for (j = 0; j < payload_remainder; j++)
+                       padded_buffer[j] = pframe[payload_index+j];
+               aes128k128d(key, ctr_preload, aes_out);
+               bitwise_xor(aes_out, padded_buffer, chain_buffer);
+               for (j = 0; j < payload_remainder; j++)
+                       pframe[payload_index++] = chain_buffer[j];
+       }
+
+       /* start to calculate the mic */
+       if ((hdrlen +plen+8) <= MAX_MSG_SIZE)
+               memcpy(message, pframe, (hdrlen+plen+8)); /* 8 is for ext iv len */
+
+       pn_vector[0] = pframe[hdrlen];
+       pn_vector[1] = pframe[hdrlen+1];
+       pn_vector[2] = pframe[hdrlen+4];
+       pn_vector[3] = pframe[hdrlen+5];
+       pn_vector[4] = pframe[hdrlen+6];
+       pn_vector[5] = pframe[hdrlen+7];
+
+       construct_mic_iv(mic_iv, qc_exists, a4_exists, message,
+                        plen-8, pn_vector);
+
+       construct_mic_header1(mic_header1, hdrlen, message);
+       construct_mic_header2(mic_header2, message, a4_exists, qc_exists);
+
+       payload_remainder = (plen-8) % 16;
+       num_blocks = (plen-8) / 16;
+
+       /* Find start of payload */
+       payload_index = (hdrlen + 8);
+
+       /* Calculate MIC */
+       aes128k128d(key, mic_iv, aes_out);
+       bitwise_xor(aes_out, mic_header1, chain_buffer);
+       aes128k128d(key, chain_buffer, aes_out);
+       bitwise_xor(aes_out, mic_header2, chain_buffer);
+       aes128k128d(key, chain_buffer, aes_out);
+
+       for (i = 0; i < num_blocks; i++) {
+               bitwise_xor(aes_out, &message[payload_index], chain_buffer);
+
+               payload_index += 16;
+               aes128k128d(key, chain_buffer, aes_out);
+       }
+
+       /* Add on the final payload block if it needs padding */
+       if (payload_remainder > 0) {
+               for (j = 0; j < 16; j++)
+                       padded_buffer[j] = 0x00;
+               for (j = 0; j < payload_remainder; j++)
+                   padded_buffer[j] = message[payload_index++];
+               bitwise_xor(aes_out, padded_buffer, chain_buffer);
+               aes128k128d(key, chain_buffer, aes_out);
+       }
+
+       for (j = 0 ; j < 8; j++)
+               mic[j] = aes_out[j];
+
+       /* Insert MIC into payload */
+       for (j = 0; j < 8; j++)
+               message[payload_index+j] = mic[j];
+
+       payload_index = hdrlen + 8;
+       for (i = 0; i< num_blocks; i++) {
+               construct_ctr_preload(ctr_preload, a4_exists, qc_exists,
+                                     message, pn_vector, i+1);
+               aes128k128d(key, ctr_preload, aes_out);
+               bitwise_xor(aes_out, &message[payload_index], chain_buffer);
+               for (j = 0; j < 16; j++)
+                       message[payload_index++] = chain_buffer[j];
+       }
+
+       if (payload_remainder > 0) {
+               /* If there is a short final block, then pad it,
+                * encrypt it and copy the unpadded part back
+                */
+               construct_ctr_preload(ctr_preload, a4_exists, qc_exists,
+                                     message, pn_vector, num_blocks+1);
+
+               for (j = 0; j < 16; j++)
+                        padded_buffer[j] = 0x00;
+               for (j = 0; j < payload_remainder; j++)
+                       padded_buffer[j] = message[payload_index+j];
+               aes128k128d(key, ctr_preload, aes_out);
+               bitwise_xor(aes_out, padded_buffer, chain_buffer);
+               for (j = 0; j < payload_remainder; j++)
+                       message[payload_index++] = chain_buffer[j];
+       }
+
+       /* Encrypt the MIC */
+       construct_ctr_preload(ctr_preload, a4_exists, qc_exists, message,
+                             pn_vector, 0);
+
+       for (j = 0; j < 16; j++)
+               padded_buffer[j] = 0x00;
+       for (j = 0; j < 8; j++)
+               padded_buffer[j] = message[j+hdrlen+8+plen-8];
+
+       aes128k128d(key, ctr_preload, aes_out);
+       bitwise_xor(aes_out, padded_buffer, chain_buffer);
+       for (j = 0; j < 8; j++)
+               message[payload_index++] = chain_buffer[j];
+
+       /* compare the mic */
+       for (i = 0; i < 8; i++) {
+               if (pframe[hdrlen+8+plen-8+i] != message[hdrlen+8+plen-8+i]) {
+                       RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+                                ("aes_decipher:mic check error mic[%d]: pframe(%x) != message(%x)\n",
+                                i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]));
+                       DBG_8723A("aes_decipher:mic check error mic[%d]: pframe(%x) != message(%x)\n",
+                                 i, pframe[hdrlen+8+plen-8+i], message[hdrlen+8+plen-8+i]);
+                       res = _FAIL;
+               }
+       }
+       return res;
+}
+
+u32 rtw_aes_decrypt23a(struct rtw_adapter *padapter, struct recv_frame *precvframe)
+{      /*  exclude ICV */
+       struct sta_info *stainfo;
+       struct rx_pkt_attrib *prxattrib = &precvframe->attrib;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct sk_buff *skb = precvframe->pkt;
+       int length;
+       u8 *pframe, *prwskey;   /*  *payload,*iv */
+       u32 res = _SUCCESS;
+
+       pframe = skb->data;
+       /* 4 start to encrypt each fragment */
+       if (prxattrib->encrypt != _AES_)
+               return _FAIL;
+
+       stainfo = rtw_get_stainfo23a(&padapter->stapriv, &prxattrib->ta[0]);
+       if (!stainfo) {
+               RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+                        ("rtw_aes_encrypt23a: stainfo == NULL!!!\n"));
+               res = _FAIL;
+               goto exit;
+       }
+
+       RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+                ("rtw_aes_decrypt23a: stainfo!= NULL!!!\n"));
+
+       if (is_multicast_ether_addr(prxattrib->ra)) {
+               /* in concurrent we should use sw decrypt in group key,
+                  so we remove this message */
+               if (!psecuritypriv->binstallGrpkey) {
+                       res = _FAIL;
+                       DBG_8723A("%s:rx bc/mc packets, but didn't install "
+                                 "group key!!!!!!!!!!\n", __func__);
+                       goto exit;
+               }
+               prwskey = psecuritypriv->dot118021XGrpKey[prxattrib->key_index].skey;
+               if (psecuritypriv->dot118021XGrpKeyid != prxattrib->key_index) {
+                       DBG_8723A("not match packet_index =%d, install_index ="
+                                 "%d\n", prxattrib->key_index,
+                                 psecuritypriv->dot118021XGrpKeyid);
+                       res = _FAIL;
+                       goto exit;
+               }
+       } else {
+               prwskey = &stainfo->dot118021x_UncstKey.skey[0];
+       }
+
+       length = skb->len - prxattrib->hdrlen - prxattrib->iv_len;
+
+       res = aes_decipher(prwskey, prxattrib->hdrlen, pframe, length);
+exit:
+       return res;
+}
+
+void rtw_use_tkipkey_handler23a(void *FunctionContext)
+{
+       struct rtw_adapter *padapter = (struct rtw_adapter *)FunctionContext;
+
+       RT_TRACE(_module_rtl871x_security_c_, _drv_err_, ("^^^rtw_use_tkipkey_handler23a ^^^\n"));
+       padapter->securitypriv.busetkipkey = true;
+       RT_TRACE(_module_rtl871x_security_c_, _drv_err_,
+                ("^^^rtw_use_tkipkey_handler23a padapter->securitypriv.busetkipkey =%d^^^\n",
+                padapter->securitypriv.busetkipkey));
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_sreset.c b/drivers/staging/rtl8723au/core/rtw_sreset.c
new file mode 100644 (file)
index 0000000..4f74592
--- /dev/null
@@ -0,0 +1,255 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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<rtw_sreset.h>
+
+void sreset_init_value23a(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+       mutex_init(&psrtpriv->silentreset_mutex);
+       psrtpriv->silent_reset_inprogress = false;
+       psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+       psrtpriv->last_tx_time = 0;
+       psrtpriv->last_tx_complete_time = 0;
+}
+void sreset_reset_value23a(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+       psrtpriv->silent_reset_inprogress = false;
+       psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+       psrtpriv->last_tx_time = 0;
+       psrtpriv->last_tx_complete_time = 0;
+}
+
+u8 sreset_get_wifi_status23a(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+       u8 status = WIFI_STATUS_SUCCESS;
+       u32 val32 = 0;
+
+       if (psrtpriv->silent_reset_inprogress)
+               return status;
+       val32 = rtw_read32(padapter, REG_TXDMA_STATUS);
+       if (val32 == 0xeaeaeaea) {
+               psrtpriv->Wifi_Error_Status = WIFI_IF_NOT_EXIST;
+       } else if (val32 != 0) {
+               DBG_8723A("txdmastatu(%x)\n", val32);
+               psrtpriv->Wifi_Error_Status = WIFI_MAC_TXDMA_ERROR;
+       }
+
+       if (WIFI_STATUS_SUCCESS != psrtpriv->Wifi_Error_Status) {
+               DBG_8723A("==>%s error_status(0x%x)\n", __func__, psrtpriv->Wifi_Error_Status);
+               status = (psrtpriv->Wifi_Error_Status &~(USB_READ_PORT_FAIL|USB_WRITE_PORT_FAIL));
+       }
+       DBG_8723A("==> %s wifi_status(0x%x)\n", __func__, status);
+
+       /* status restore */
+       psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+
+       return status;
+}
+
+void sreset_set_wifi_error_status23a(struct rtw_adapter *padapter, u32 status)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+
+       pHalData->srestpriv.Wifi_Error_Status = status;
+}
+
+void sreset_set_trigger_point(struct rtw_adapter *padapter, s32 tgp)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+
+       pHalData->srestpriv.dbg_trigger_point = tgp;
+}
+
+bool sreset_inprogress(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+
+       return pHalData->srestpriv.silent_reset_inprogress;
+}
+
+static void sreset_restore_security_station(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct sta_info *psta;
+       struct mlme_ext_info *pmlmeinfo = &padapter->mlmeextpriv.mlmext_info;
+       u8 val8;
+
+       if (pmlmeinfo->auth_algo == dot11AuthAlgrthm_8021X)
+               val8 = 0xcc;
+       else
+               val8 = 0xcf;
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_SEC_CFG, (u8 *)(&val8));
+
+       if ((padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_) ||
+           (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
+               psta = rtw_get_stainfo23a(pstapriv, get_bssid(mlmepriv));
+               if (psta == NULL) {
+                       /* DEBUG_ERR(("Set wpa_set_encryption: Obtain Sta_info fail\n")); */
+               } else {
+                       /* pairwise key */
+                       rtw_setstakey_cmd23a(padapter, (unsigned char *)psta, true);
+                       /* group key */
+                       rtw_set_key23a(padapter,&padapter->securitypriv, padapter->securitypriv.dot118021XGrpKeyid, 0);
+               }
+       }
+}
+
+static void sreset_restore_network_station(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       u8 threshold;
+
+       rtw_setopmode_cmd23a(padapter, Ndis802_11Infrastructure);
+
+       /*  TH = 1 => means that invalidate usb rx aggregation */
+       /*  TH = 0 => means that validate usb rx aggregation, use init value. */
+       if (mlmepriv->htpriv.ht_option) {
+               if (padapter->registrypriv.wifi_spec == 1)
+                       threshold = 1;
+               else
+                       threshold = 0;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
+       } else {
+               threshold = 1;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_RXDMA_AGG_PG_TH, (u8 *)(&threshold));
+       }
+
+       set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode);
+
+       /* disable dynamic functions, such as high power, DIG */
+       /* Switch_DM_Func23a(padapter, DYNAMIC_FUNC_DISABLE, false); */
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BSSID, pmlmeinfo->network.MacAddress);
+
+       {
+               u8      join_type = 0;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_MLME_JOIN, (u8 *)(&join_type));
+       }
+
+       Set_MSR23a(padapter, (pmlmeinfo->state & 0x3));
+
+       mlmeext_joinbss_event_callback23a(padapter, 1);
+       /* restore Sequence No. */
+       rtw_write8(padapter, 0x4dc, padapter->xmitpriv.nqos_ssn);
+
+       sreset_restore_security_station(padapter);
+}
+
+static void sreset_restore_network_status(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *mlmepriv = &padapter->mlmepriv;
+
+       if (check_fwstate(mlmepriv, WIFI_STATION_STATE)) {
+               DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_STATION_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
+               sreset_restore_network_station(padapter);
+#ifdef CONFIG_8723AU_AP_MODE
+       } else if (check_fwstate(mlmepriv, WIFI_AP_STATE)) {
+               DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_AP_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
+               rtw_ap_restore_network(padapter);
+#endif
+       } else if (check_fwstate(mlmepriv, WIFI_ADHOC_STATE)) {
+               DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - WIFI_ADHOC_STATE\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
+       } else {
+               DBG_8723A(FUNC_ADPT_FMT" fwstate:0x%08x - ???\n", FUNC_ADPT_ARG(padapter), get_fwstate(mlmepriv));
+       }
+}
+
+static void sreset_stop_adapter(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
+
+       if (padapter == NULL)
+               return;
+
+       DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+       if (!rtw_netif_queue_stopped(padapter->pnetdev))
+               netif_tx_stop_all_queues(padapter->pnetdev);
+
+       rtw_cancel_all_timer23a(padapter);
+
+       /* TODO: OS and HCI independent */
+       tasklet_kill(&pxmitpriv->xmit_tasklet);
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
+               rtw_scan_abort23a(padapter);
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
+               rtw23a_join_to_handler((unsigned long)padapter);
+}
+
+static void sreset_start_adapter(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
+
+       if (padapter == NULL)
+               return;
+
+       DBG_8723A(FUNC_ADPT_FMT"\n", FUNC_ADPT_ARG(padapter));
+
+       if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+               sreset_restore_network_status(padapter);
+       }
+
+       /* TODO: OS and HCI independent */
+       tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+
+       mod_timer(&padapter->mlmepriv.dynamic_chk_timer,
+                 jiffies + msecs_to_jiffies(2000));
+
+       if (rtw_netif_queue_stopped(padapter->pnetdev))
+               netif_tx_wake_all_queues(padapter->pnetdev);
+}
+
+void sreset_reset(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       unsigned long start = jiffies;
+
+       DBG_8723A("%s\n", __func__);
+
+       psrtpriv->Wifi_Error_Status = WIFI_STATUS_SUCCESS;
+
+       mutex_lock(&psrtpriv->silentreset_mutex);
+       psrtpriv->silent_reset_inprogress = true;
+       pwrpriv->change_rfpwrstate = rf_off;
+
+       sreset_stop_adapter(padapter);
+
+       ips_enter23a(padapter);
+       ips_leave23a(padapter);
+
+       sreset_start_adapter(padapter);
+       psrtpriv->silent_reset_inprogress = false;
+       mutex_unlock(&psrtpriv->silentreset_mutex);
+
+       DBG_8723A("%s done in %d ms\n", __func__,
+                 jiffies_to_msecs(jiffies - start));
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_sta_mgt.c b/drivers/staging/rtl8723au/core/rtw_sta_mgt.c
new file mode 100644 (file)
index 0000000..451b58f
--- /dev/null
@@ -0,0 +1,509 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_STA_MGT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+#include <mlme_osdep.h>
+#include <sta_info.h>
+
+void _rtw_init_stainfo(struct sta_info *psta)
+{
+       memset((u8 *)psta, 0, sizeof (struct sta_info));
+       spin_lock_init(&psta->lock);
+       INIT_LIST_HEAD(&psta->list);
+       INIT_LIST_HEAD(&psta->hash_list);
+       _rtw_init_queue23a(&psta->sleep_q);
+       psta->sleepq_len = 0;
+       _rtw_init_sta_xmit_priv23a(&psta->sta_xmitpriv);
+       _rtw_init_sta_recv_priv23a(&psta->sta_recvpriv);
+#ifdef CONFIG_8723AU_AP_MODE
+       INIT_LIST_HEAD(&psta->asoc_list);
+       INIT_LIST_HEAD(&psta->auth_list);
+       psta->expire_to = 0;
+       psta->flags = 0;
+       psta->capability = 0;
+       psta->bpairwise_key_installed = false;
+       psta->nonerp_set = 0;
+       psta->no_short_slot_time_set = 0;
+       psta->no_short_preamble_set = 0;
+       psta->no_ht_gf_set = 0;
+       psta->no_ht_set = 0;
+       psta->ht_20mhz_set = 0;
+       psta->keep_alive_trycnt = 0;
+#endif /*  CONFIG_8723AU_AP_MODE */
+}
+
+u32 _rtw_init_sta_priv23a(struct sta_priv *pstapriv)
+{
+       struct sta_info *psta;
+       s32 i;
+
+       pstapriv->pallocated_stainfo_buf = rtw_zvmalloc(sizeof(struct sta_info) * NUM_STA+ 4);
+
+       if (!pstapriv->pallocated_stainfo_buf)
+               return _FAIL;
+
+       pstapriv->pstainfo_buf = pstapriv->pallocated_stainfo_buf + 4 -
+               ((unsigned long)(pstapriv->pallocated_stainfo_buf) & 3);
+       _rtw_init_queue23a(&pstapriv->free_sta_queue);
+       spin_lock_init(&pstapriv->sta_hash_lock);
+       pstapriv->asoc_sta_count = 0;
+       _rtw_init_queue23a(&pstapriv->sleep_q);
+       _rtw_init_queue23a(&pstapriv->wakeup_q);
+       psta = (struct sta_info *)(pstapriv->pstainfo_buf);
+
+       for (i = 0; i < NUM_STA; i++) {
+               _rtw_init_stainfo(psta);
+               INIT_LIST_HEAD(&pstapriv->sta_hash[i]);
+               list_add_tail(&psta->list, get_list_head(&pstapriv->free_sta_queue));
+               psta++;
+       }
+#ifdef CONFIG_8723AU_AP_MODE
+       pstapriv->sta_dz_bitmap = 0;
+       pstapriv->tim_bitmap = 0;
+       INIT_LIST_HEAD(&pstapriv->asoc_list);
+       INIT_LIST_HEAD(&pstapriv->auth_list);
+       spin_lock_init(&pstapriv->asoc_list_lock);
+       spin_lock_init(&pstapriv->auth_list_lock);
+       pstapriv->asoc_list_cnt = 0;
+       pstapriv->auth_list_cnt = 0;
+       pstapriv->auth_to = 3; /*  3*2 = 6 sec */
+       pstapriv->assoc_to = 3;
+       /* pstapriv->expire_to = 900;  900*2 = 1800 sec = 30 min, expire after no any traffic. */
+       /* pstapriv->expire_to = 30;  30*2 = 60 sec = 1 min, expire after no any traffic. */
+       pstapriv->expire_to = 3; /*  3*2 = 6 sec */
+       pstapriv->max_num_sta = NUM_STA;
+#endif
+       return _SUCCESS;
+}
+
+inline int rtw_stainfo_offset23a(struct sta_priv *stapriv, struct sta_info *sta)
+{
+       int offset = (((u8 *)sta) - stapriv->pstainfo_buf)/sizeof(struct sta_info);
+
+       if (!stainfo_offset_valid(offset))
+               DBG_8723A("%s invalid offset(%d), out of range!!!", __func__, offset);
+       return offset;
+}
+
+inline struct sta_info *rtw_get_stainfo23a_by_offset23a(struct sta_priv *stapriv, int offset)
+{
+       if (!stainfo_offset_valid(offset))
+               DBG_8723A("%s invalid offset(%d), out of range!!!", __func__, offset);
+       return (struct sta_info *)(stapriv->pstainfo_buf + offset * sizeof(struct sta_info));
+}
+
+/*  this function is used to free the memory of lock || sema for all stainfos */
+void rtw_mfree_all_stainfo(struct sta_priv *pstapriv)
+{
+       struct list_head *plist, *phead;
+       struct sta_info *psta;
+
+       spin_lock_bh(&pstapriv->sta_hash_lock);
+
+       phead = get_list_head(&pstapriv->free_sta_queue);
+
+       /* we really achieve a lot in this loop .... */
+       list_for_each(plist, phead)
+               psta = container_of(plist, struct sta_info, list);
+       spin_unlock_bh(&pstapriv->sta_hash_lock);
+}
+
+void rtw_mfree_sta_priv_lock(struct    sta_priv *pstapriv)
+{
+       rtw_mfree_all_stainfo(pstapriv); /* be done before free sta_hash_lock */
+}
+
+u32    _rtw_free_sta_priv23a(struct    sta_priv *pstapriv)
+{
+       struct list_head *phead, *plist, *ptmp;
+       struct sta_info *psta;
+       struct recv_reorder_ctrl *preorder_ctrl;
+       int     index;
+
+       if (pstapriv) {
+               /*      delete all reordering_ctrl_timer                */
+               spin_lock_bh(&pstapriv->sta_hash_lock);
+               for (index = 0; index < NUM_STA; index++) {
+                       phead = &pstapriv->sta_hash[index];
+
+                       list_for_each_safe(plist, ptmp, phead) {
+                               int i;
+                               psta = container_of(plist, struct sta_info,
+                                                   hash_list);
+                               for (i = 0; i < 16 ; i++) {
+                                       preorder_ctrl = &psta->recvreorder_ctrl[i];
+                                       del_timer_sync(&preorder_ctrl->reordering_ctrl_timer);
+                               }
+                       }
+               }
+               spin_unlock_bh(&pstapriv->sta_hash_lock);
+               /*===============================*/
+
+               rtw_mfree_sta_priv_lock(pstapriv);
+
+               if (pstapriv->pallocated_stainfo_buf)
+                       rtw_vmfree(pstapriv->pallocated_stainfo_buf, sizeof(struct sta_info)*NUM_STA+4);
+       }
+       return _SUCCESS;
+}
+
+struct sta_info *rtw_alloc_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr)
+{
+       struct list_head        *phash_list;
+       struct sta_info *psta;
+       struct rtw_queue *pfree_sta_queue;
+       struct recv_reorder_ctrl *preorder_ctrl;
+       uint tmp_aid;
+       s32     index;
+       int i = 0;
+       u16  wRxSeqInitialValue = 0xffff;
+
+       pfree_sta_queue = &pstapriv->free_sta_queue;
+
+       spin_lock_bh(&pstapriv->sta_hash_lock);
+
+       if (_rtw_queue_empty23a(pfree_sta_queue)) {
+               spin_unlock_bh(&pstapriv->sta_hash_lock);
+               return NULL;
+       }
+       psta = container_of((&pfree_sta_queue->queue)->next, struct sta_info, list);
+
+       list_del_init(&psta->list);
+
+       tmp_aid = psta->aid;
+
+       _rtw_init_stainfo(psta);
+
+       psta->padapter = pstapriv->padapter;
+
+       memcpy(psta->hwaddr, hwaddr, ETH_ALEN);
+
+       index = wifi_mac_hash(hwaddr);
+
+       RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_,
+                ("rtw_alloc_stainfo23a: index  = %x", index));
+       if (index >= NUM_STA) {
+               RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_,
+                        ("ERROR => rtw_alloc_stainfo23a: index >= NUM_STA"));
+               psta = NULL;
+               goto exit;
+       }
+       phash_list = &pstapriv->sta_hash[index];
+
+       list_add_tail(&psta->hash_list, phash_list);
+
+       pstapriv->asoc_sta_count ++ ;
+
+/*  For the SMC router, the sequence number of first packet of WPS handshake will be 0. */
+/*  In this case, this packet will be dropped by recv_decache function if we use the 0x00 as the default value for tid_rxseq variable. */
+/*  So, we initialize the tid_rxseq variable as the 0xffff. */
+
+       for (i = 0; i < 16; i++)
+               memcpy(&psta->sta_recvpriv.rxcache.tid_rxseq[i], &wRxSeqInitialValue, 2);
+
+       RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_info_,
+                ("alloc number_%d stainfo  with hwaddr = %pM\n",
+                pstapriv->asoc_sta_count, hwaddr));
+
+       init_addba_retry_timer23a(psta);
+
+       /* for A-MPDU Rx reordering buffer control */
+       for (i = 0; i < 16; i++) {
+               preorder_ctrl = &psta->recvreorder_ctrl[i];
+
+               preorder_ctrl->padapter = pstapriv->padapter;
+
+               preorder_ctrl->enable = false;
+
+               preorder_ctrl->indicate_seq = 0xffff;
+               preorder_ctrl->wend_b = 0xffff;
+               /* preorder_ctrl->wsize_b = (NR_RECVBUFF-2); */
+               preorder_ctrl->wsize_b = 64;/* 64; */
+
+               _rtw_init_queue23a(&preorder_ctrl->pending_recvframe_queue);
+
+               rtw_init_recv_timer23a(preorder_ctrl);
+       }
+       /* init for DM */
+       psta->rssi_stat.UndecoratedSmoothedPWDB = (-1);
+       psta->rssi_stat.UndecoratedSmoothedCCK = (-1);
+
+       /* init for the sequence number of received management frame */
+       psta->RxMgmtFrameSeqNum = 0xffff;
+exit:
+       spin_unlock_bh(&pstapriv->sta_hash_lock);
+       return psta;
+}
+
+/*  using pstapriv->sta_hash_lock to protect */
+u32    rtw_free_stainfo23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       struct rtw_queue *pfree_sta_queue;
+       struct recv_reorder_ctrl *preorder_ctrl;
+       struct  sta_xmit_priv   *pstaxmitpriv;
+       struct  xmit_priv       *pxmitpriv = &padapter->xmitpriv;
+       struct  sta_priv *pstapriv = &padapter->stapriv;
+       struct hw_xmit *phwxmit;
+       int i;
+
+       if (psta == NULL)
+               goto exit;
+
+       spin_lock_bh(&psta->lock);
+       psta->state &= ~_FW_LINKED;
+       spin_unlock_bh(&psta->lock);
+
+       pfree_sta_queue = &pstapriv->free_sta_queue;
+
+       pstaxmitpriv = &psta->sta_xmitpriv;
+
+       spin_lock_bh(&pxmitpriv->lock);
+
+       rtw_free_xmitframe_queue23a(pxmitpriv, &psta->sleep_q);
+       psta->sleepq_len = 0;
+
+       /* vo */
+       rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->vo_q.sta_pending);
+       list_del_init(&pstaxmitpriv->vo_q.tx_pending);
+       phwxmit = pxmitpriv->hwxmits;
+       phwxmit->accnt -= pstaxmitpriv->vo_q.qcnt;
+       pstaxmitpriv->vo_q.qcnt = 0;
+
+       /* vi */
+       rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->vi_q.sta_pending);
+       list_del_init(&pstaxmitpriv->vi_q.tx_pending);
+       phwxmit = pxmitpriv->hwxmits+1;
+       phwxmit->accnt -= pstaxmitpriv->vi_q.qcnt;
+       pstaxmitpriv->vi_q.qcnt = 0;
+
+       /* be */
+       rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->be_q.sta_pending);
+       list_del_init(&pstaxmitpriv->be_q.tx_pending);
+       phwxmit = pxmitpriv->hwxmits+2;
+       phwxmit->accnt -= pstaxmitpriv->be_q.qcnt;
+       pstaxmitpriv->be_q.qcnt = 0;
+
+       /* bk */
+       rtw_free_xmitframe_queue23a(pxmitpriv, &pstaxmitpriv->bk_q.sta_pending);
+       list_del_init(&pstaxmitpriv->bk_q.tx_pending);
+       phwxmit = pxmitpriv->hwxmits+3;
+       phwxmit->accnt -= pstaxmitpriv->bk_q.qcnt;
+       pstaxmitpriv->bk_q.qcnt = 0;
+
+       spin_unlock_bh(&pxmitpriv->lock);
+
+       list_del_init(&psta->hash_list);
+       RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_, ("\n free number_%d stainfo  with hwaddr = 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x \n", pstapriv->asoc_sta_count, psta->hwaddr[0], psta->hwaddr[1], psta->hwaddr[2], psta->hwaddr[3], psta->hwaddr[4], psta->hwaddr[5]));
+       pstapriv->asoc_sta_count --;
+
+       /*  re-init sta_info; 20061114  will be init in alloc_stainfo */
+       /* _rtw_init_sta_xmit_priv23a(&psta->sta_xmitpriv); */
+       /* _rtw_init_sta_recv_priv23a(&psta->sta_recvpriv); */
+
+       del_timer_sync(&psta->addba_retry_timer);
+
+       /* for A-MPDU Rx reordering buffer control, cancel reordering_ctrl_timer */
+       for (i = 0; i < 16; i++) {
+               struct list_head        *phead, *plist;
+               struct recv_frame *prframe;
+               struct rtw_queue *ppending_recvframe_queue;
+               struct rtw_queue *pfree_recv_queue = &padapter->recvpriv.free_recv_queue;
+
+               preorder_ctrl = &psta->recvreorder_ctrl[i];
+
+               del_timer_sync(&preorder_ctrl->reordering_ctrl_timer);
+
+               ppending_recvframe_queue = &preorder_ctrl->pending_recvframe_queue;
+
+               spin_lock_bh(&ppending_recvframe_queue->lock);
+               phead =         get_list_head(ppending_recvframe_queue);
+               plist = phead->next;
+
+               while (!list_empty(phead)) {
+                       prframe = container_of(plist, struct recv_frame, list);
+                       plist = plist->next;
+                       list_del_init(&prframe->list);
+                       rtw_free_recvframe23a(prframe, pfree_recv_queue);
+               }
+               spin_unlock_bh(&ppending_recvframe_queue->lock);
+       }
+       if (!(psta->state & WIFI_AP_STATE))
+               rtw_hal_set_odm_var23a(padapter, HAL_ODM_STA_INFO, psta, false);
+#ifdef CONFIG_8723AU_AP_MODE
+       spin_lock_bh(&pstapriv->auth_list_lock);
+       if (!list_empty(&psta->auth_list)) {
+               list_del_init(&psta->auth_list);
+               pstapriv->auth_list_cnt--;
+       }
+       spin_unlock_bh(&pstapriv->auth_list_lock);
+
+       psta->expire_to = 0;
+
+       psta->sleepq_ac_len = 0;
+       psta->qos_info = 0;
+
+       psta->max_sp_len = 0;
+       psta->uapsd_bk = 0;
+       psta->uapsd_be = 0;
+       psta->uapsd_vi = 0;
+       psta->uapsd_vo = 0;
+
+       psta->has_legacy_ac = 0;
+
+       pstapriv->sta_dz_bitmap &= ~CHKBIT(psta->aid);
+       pstapriv->tim_bitmap &= ~CHKBIT(psta->aid);
+
+       if ((psta->aid >0) && (pstapriv->sta_aid[psta->aid - 1] == psta)) {
+               pstapriv->sta_aid[psta->aid - 1] = NULL;
+               psta->aid = 0;
+       }
+#endif /*  CONFIG_8723AU_AP_MODE */
+       list_add_tail(&psta->list, get_list_head(pfree_sta_queue));
+exit:
+       return _SUCCESS;
+}
+
+/*  free all stainfo which in sta_hash[all] */
+void rtw_free_all_stainfo23a(struct rtw_adapter *padapter)
+{
+       struct list_head *plist, *phead, *ptmp;
+       struct sta_info *psta;
+       struct  sta_priv *pstapriv = &padapter->stapriv;
+       struct sta_info* pbcmc_stainfo = rtw_get_bcmc_stainfo23a(padapter);
+       s32     index;  if (pstapriv->asoc_sta_count == 1)
+               return;
+
+       spin_lock_bh(&pstapriv->sta_hash_lock);
+
+       for (index = 0; index < NUM_STA; index++) {
+               phead = &pstapriv->sta_hash[index];
+
+               list_for_each_safe(plist, ptmp, phead) {
+                       psta = container_of(plist, struct sta_info, hash_list);
+
+                       if (pbcmc_stainfo!= psta)
+                               rtw_free_stainfo23a(padapter, psta);
+               }
+       }
+       spin_unlock_bh(&pstapriv->sta_hash_lock);
+}
+
+/* any station allocated can be searched by hash list */
+struct sta_info *rtw_get_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr)
+{
+       struct list_head *plist, *phead;
+       struct sta_info *psta = NULL;
+       u32     index;
+       u8 *addr;
+       u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+       if (hwaddr == NULL)
+               return NULL;
+
+       if (is_multicast_ether_addr(hwaddr))
+               addr = bc_addr;
+       else
+               addr = hwaddr;
+
+       index = wifi_mac_hash(addr);
+
+       spin_lock_bh(&pstapriv->sta_hash_lock);
+
+       phead = &pstapriv->sta_hash[index];
+
+       list_for_each(plist, phead) {
+               psta = container_of(plist, struct sta_info, hash_list);
+
+               if (!memcmp(psta->hwaddr, addr, ETH_ALEN)) {
+                       /*  if found the matched address */
+                       break;
+               }
+               psta = NULL;
+       }
+       spin_unlock_bh(&pstapriv->sta_hash_lock);
+       return psta;
+}
+
+u32 rtw_init_bcmc_stainfo23a(struct rtw_adapter* padapter)
+{
+       struct  sta_priv *pstapriv = &padapter->stapriv;
+       struct sta_info         *psta;
+       struct tx_servq *ptxservq;
+       u32 res = _SUCCESS;
+       unsigned char bcast_addr[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+       psta = rtw_alloc_stainfo23a(pstapriv, bcast_addr);
+       if (psta == NULL) {
+               res = _FAIL;
+               RT_TRACE(_module_rtl871x_sta_mgt_c_, _drv_err_,
+                        ("rtw_alloc_stainfo23a fail"));
+               return res;
+       }
+       /*  default broadcast & multicast use macid 1 */
+       psta->mac_id = 1;
+
+       ptxservq = &psta->sta_xmitpriv.be_q;
+       return _SUCCESS;
+}
+
+struct sta_info *rtw_get_bcmc_stainfo23a(struct rtw_adapter *padapter)
+{
+       struct sta_info         *psta;
+       struct sta_priv         *pstapriv = &padapter->stapriv;
+       u8 bc_addr[ETH_ALEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+        psta = rtw_get_stainfo23a(pstapriv, bc_addr);
+       return psta;
+}
+
+u8 rtw_access_ctrl23a(struct rtw_adapter *padapter, u8 *mac_addr)
+{
+       u8 res = true;
+#ifdef CONFIG_8723AU_AP_MODE
+       struct list_head *plist, *phead;
+       struct rtw_wlan_acl_node *paclnode;
+       u8 match = false;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct wlan_acl_pool *pacl_list = &pstapriv->acl_list;
+       struct rtw_queue *pacl_node_q = &pacl_list->acl_node_q;
+
+       spin_lock_bh(&pacl_node_q->lock);
+       phead = get_list_head(pacl_node_q);
+
+       list_for_each(plist, phead) {
+               paclnode = container_of(plist, struct rtw_wlan_acl_node, list);
+
+               if (!memcmp(paclnode->addr, mac_addr, ETH_ALEN)) {
+                       if (paclnode->valid) {
+                               match = true;
+                               break;
+                       }
+               }
+       }
+       spin_unlock_bh(&pacl_node_q->lock);
+
+       if (pacl_list->mode == 1)/* accept unless in deny list */
+               res = (match) ?  false : true;
+       else if (pacl_list->mode == 2)/* deny unless in accept list */
+               res = (match) ?  true : false;
+       else
+                res = true;
+#endif
+       return res;
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_wlan_util.c b/drivers/staging/rtl8723au/core/rtw_wlan_util.c
new file mode 100644 (file)
index 0000000..0dfcfbc
--- /dev/null
@@ -0,0 +1,1760 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_WLAN_UTIL_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <linux/ieee80211.h>
+#include <wifi.h>
+
+static unsigned char ARTHEROS_OUI1[] = {0x00, 0x03, 0x7f};
+static unsigned char ARTHEROS_OUI2[] = {0x00, 0x13, 0x74};
+
+static unsigned char BROADCOM_OUI1[] = {0x00, 0x10, 0x18};
+static unsigned char BROADCOM_OUI2[] = {0x00, 0x0a, 0xf7};
+
+static unsigned char CISCO_OUI[] = {0x00, 0x40, 0x96};
+static unsigned char MARVELL_OUI[] = {0x00, 0x50, 0x43};
+static unsigned char RALINK_OUI[] = {0x00, 0x0c, 0x43};
+static unsigned char REALTEK_OUI[] = {0x00, 0xe0, 0x4c};
+static unsigned char AIRGOCAP_OUI[] = {0x00, 0x0a, 0xf5};
+static unsigned char EPIGRAM_OUI[] = {0x00, 0x90, 0x4c};
+
+unsigned char REALTEK_96B_IE23A[] = {0x00, 0xe0, 0x4c, 0x02, 0x01, 0x20};
+
+#define R2T_PHY_DELAY  (0)
+
+/* define WAIT_FOR_BCN_TO_MIN  (3000) */
+#define WAIT_FOR_BCN_TO_MIN    (6000)
+#define WAIT_FOR_BCN_TO_MAX    (20000)
+
+static u8 rtw_basic_rate_cck[4] = {
+       IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK,
+       IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK
+};
+
+static u8 rtw_basic_rate_ofdm[3] = {
+       IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK,
+       IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK
+};
+
+static u8 rtw_basic_rate_mix[7] = {
+       IEEE80211_CCK_RATE_1MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_2MB|IEEE80211_BASIC_RATE_MASK,
+       IEEE80211_CCK_RATE_5MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_CCK_RATE_11MB|IEEE80211_BASIC_RATE_MASK,
+       IEEE80211_OFDM_RATE_6MB|IEEE80211_BASIC_RATE_MASK, IEEE80211_OFDM_RATE_12MB|IEEE80211_BASIC_RATE_MASK,
+       IEEE80211_OFDM_RATE_24MB|IEEE80211_BASIC_RATE_MASK
+};
+
+int cckrates_included23a(unsigned char *rate, int ratelen)
+{
+       int     i;
+
+       for (i = 0; i < ratelen; i++) {
+               if  ((((rate[i]) & 0x7f) == 2)  || (((rate[i]) & 0x7f) == 4) ||
+                    (((rate[i]) & 0x7f) == 11)  || (((rate[i]) & 0x7f) == 22))
+                       return true;
+       }
+
+       return false;
+}
+
+int cckratesonly_included23a(unsigned char *rate, int ratelen)
+{
+       int     i;
+
+       for (i = 0; i < ratelen; i++) {
+               if  ((((rate[i]) & 0x7f) != 2) && (((rate[i]) & 0x7f) != 4) &&
+                          (((rate[i]) & 0x7f) != 11)  && (((rate[i]) & 0x7f) != 22))
+               return false;
+       }
+
+       return true;
+}
+
+unsigned char networktype_to_raid23a(unsigned char network_type)
+{
+       unsigned char raid;
+
+       switch (network_type) {
+       case WIRELESS_11B:
+               raid = RATR_INX_WIRELESS_B;
+               break;
+       case WIRELESS_11A:
+       case WIRELESS_11G:
+               raid = RATR_INX_WIRELESS_G;
+               break;
+       case WIRELESS_11BG:
+               raid = RATR_INX_WIRELESS_GB;
+               break;
+       case WIRELESS_11_24N:
+       case WIRELESS_11_5N:
+               raid = RATR_INX_WIRELESS_N;
+               break;
+       case WIRELESS_11A_5N:
+       case WIRELESS_11G_24N:
+               raid = RATR_INX_WIRELESS_NG;
+               break;
+       case WIRELESS_11BG_24N:
+               raid = RATR_INX_WIRELESS_NGB;
+               break;
+       default:
+               raid = RATR_INX_WIRELESS_GB;
+               break;
+       }
+       return raid;
+}
+
+u8 judge_network_type23a(struct rtw_adapter *padapter, unsigned char *rate, int ratelen)
+{
+       u8 network_type = 0;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if (pmlmeext->cur_channel > 14) {
+               if (pmlmeinfo->HT_enable)
+                       network_type = WIRELESS_11_5N;
+               network_type |= WIRELESS_11A;
+       } else {
+               if (pmlmeinfo->HT_enable)
+                       network_type = WIRELESS_11_24N;
+
+               if ((cckratesonly_included23a(rate, ratelen)) == true)
+                       network_type |= WIRELESS_11B;
+               else if ((cckrates_included23a(rate, ratelen)) == true)
+                       network_type |= WIRELESS_11BG;
+               else
+                       network_type |= WIRELESS_11G;
+       }
+       return  network_type;
+}
+
+unsigned char ratetbl_val_2wifirate(unsigned char rate)
+{
+       unsigned char val = 0;
+
+       switch (rate & 0x7f) {
+       case 0:
+               val = IEEE80211_CCK_RATE_1MB;
+               break;
+       case 1:
+               val = IEEE80211_CCK_RATE_2MB;
+               break;
+       case 2:
+               val = IEEE80211_CCK_RATE_5MB;
+               break;
+       case 3:
+               val = IEEE80211_CCK_RATE_11MB;
+               break;
+       case 4:
+               val = IEEE80211_OFDM_RATE_6MB;
+               break;
+       case 5:
+               val = IEEE80211_OFDM_RATE_9MB;
+               break;
+       case 6:
+               val = IEEE80211_OFDM_RATE_12MB;
+               break;
+       case 7:
+               val = IEEE80211_OFDM_RATE_18MB;
+               break;
+       case 8:
+               val = IEEE80211_OFDM_RATE_24MB;
+               break;
+       case 9:
+               val = IEEE80211_OFDM_RATE_36MB;
+               break;
+       case 10:
+               val = IEEE80211_OFDM_RATE_48MB;
+               break;
+       case 11:
+               val = IEEE80211_OFDM_RATE_54MB;
+               break;
+       }
+       return val;
+}
+
+int is_basicrate(struct rtw_adapter *padapter, unsigned char rate)
+{
+       int i;
+       unsigned char val;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       for (i = 0; i < NumRates; i++) {
+               val = pmlmeext->basicrate[i];
+
+               if ((val != 0xff) && (val != 0xfe)) {
+                       if (rate == ratetbl_val_2wifirate(val))
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+unsigned int ratetbl2rateset(struct rtw_adapter *padapter, unsigned char *rateset)
+{
+       int i;
+       unsigned char rate;
+       unsigned int    len = 0;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       for (i = 0; i < NumRates; i++) {
+               rate = pmlmeext->datarate[i];
+
+               switch (rate) {
+               case 0xff:
+                       return len;
+               case 0xfe:
+                       continue;
+               default:
+                       rate = ratetbl_val_2wifirate(rate);
+
+                       if (is_basicrate(padapter, rate) == true)
+                               rate |= IEEE80211_BASIC_RATE_MASK;
+
+                       rateset[len] = rate;
+                       len++;
+                       break;
+               }
+       }
+       return len;
+}
+
+void get_rate_set23a(struct rtw_adapter *padapter, unsigned char *pbssrate, int *bssrate_len)
+{
+       unsigned char supportedrates[NumRates];
+
+       memset(supportedrates, 0, NumRates);
+       *bssrate_len = ratetbl2rateset(padapter, supportedrates);
+       memcpy(pbssrate, supportedrates, *bssrate_len);
+}
+
+void UpdateBrateTbl23a(struct rtw_adapter *Adapter, u8 *mBratesOS)
+{
+       u8      i;
+       u8      rate;
+
+       /*  1M, 2M, 5.5M, 11M, 6M, 12M, 24M are mandatory. */
+       for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+               rate = mBratesOS[i] & 0x7f;
+               switch (rate) {
+               case IEEE80211_CCK_RATE_1MB:
+               case IEEE80211_CCK_RATE_2MB:
+               case IEEE80211_CCK_RATE_5MB:
+               case IEEE80211_CCK_RATE_11MB:
+               case IEEE80211_OFDM_RATE_6MB:
+               case IEEE80211_OFDM_RATE_12MB:
+               case IEEE80211_OFDM_RATE_24MB:
+                       mBratesOS[i] |= IEEE80211_BASIC_RATE_MASK;
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+void Update23aTblForSoftAP(u8 *bssrateset, u32 bssratelen)
+{
+       u8      i;
+       u8      rate;
+
+       for (i = 0; i < bssratelen; i++) {
+               rate = bssrateset[i] & 0x7f;
+               switch (rate) {
+               case IEEE80211_CCK_RATE_1MB:
+               case IEEE80211_CCK_RATE_2MB:
+               case IEEE80211_CCK_RATE_5MB:
+               case IEEE80211_CCK_RATE_11MB:
+                       bssrateset[i] |= IEEE80211_BASIC_RATE_MASK;
+                       break;
+               }
+       }
+}
+
+void Save_DM_Func_Flag23a(struct rtw_adapter *padapter)
+{
+       u8      bSaveFlag = true;
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&bSaveFlag));
+}
+
+void Restore_DM_Func_Flag23a(struct rtw_adapter *padapter)
+{
+       u8      bSaveFlag = false;
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_OP, (u8 *)(&bSaveFlag));
+}
+
+void Switch_DM_Func23a(struct rtw_adapter *padapter, unsigned long mode, u8 enable)
+{
+       if (enable == true)
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_SET, (u8 *)(&mode));
+       else
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_DM_FUNC_CLR, (u8 *)(&mode));
+}
+
+static void Set_NETYPE0_MSR(struct rtw_adapter *padapter, u8 type)
+{
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_MEDIA_STATUS, (u8 *)(&type));
+}
+
+void Set_MSR23a(struct rtw_adapter *padapter, u8 type)
+{
+               Set_NETYPE0_MSR(padapter, type);
+}
+
+inline u8 rtw_get_oper_ch23a(struct rtw_adapter *adapter)
+{
+       return adapter_to_dvobj(adapter)->oper_channel;
+}
+
+inline void rtw_set_oper_ch23a(struct rtw_adapter *adapter, u8 ch)
+{
+       adapter_to_dvobj(adapter)->oper_channel = ch;
+}
+
+inline u8 rtw_get_oper_bw23a(struct rtw_adapter *adapter)
+{
+       return adapter_to_dvobj(adapter)->oper_bwmode;
+}
+
+inline void rtw_set_oper_bw23a(struct rtw_adapter *adapter, u8 bw)
+{
+       adapter_to_dvobj(adapter)->oper_bwmode = bw;
+}
+
+inline u8 rtw_get_oper_ch23aoffset(struct rtw_adapter *adapter)
+{
+       return adapter_to_dvobj(adapter)->oper_ch_offset;
+}
+
+inline void rtw_set_oper_ch23aoffset23a(struct rtw_adapter *adapter, u8 offset)
+{
+       adapter_to_dvobj(adapter)->oper_ch_offset = offset;
+}
+
+void SelectChannel23a(struct rtw_adapter *padapter, unsigned char channel)
+{
+       mutex_lock(&adapter_to_dvobj(padapter)->setch_mutex);
+
+       /* saved channel info */
+       rtw_set_oper_ch23a(padapter, channel);
+
+       rtw_hal_set_chan23a(padapter, channel);
+
+       mutex_unlock(&adapter_to_dvobj(padapter)->setch_mutex);
+}
+
+void SetBWMode23a(struct rtw_adapter *padapter, unsigned short bwmode, unsigned char channel_offset)
+{
+       mutex_lock(&adapter_to_dvobj(padapter)->setbw_mutex);
+
+       /* saved bw info */
+       rtw_set_oper_bw23a(padapter, bwmode);
+       rtw_set_oper_ch23aoffset23a(padapter, channel_offset);
+
+       rtw_hal_set_bwmode23a(padapter, (enum ht_channel_width)bwmode,
+                          channel_offset);
+
+       mutex_unlock(&adapter_to_dvobj(padapter)->setbw_mutex);
+}
+
+void set_channel_bwmode23a(struct rtw_adapter *padapter, unsigned char channel,
+                       unsigned char channel_offset, unsigned short bwmode)
+{
+       u8 center_ch;
+
+       if (padapter->bNotifyChannelChange)
+               DBG_8723A("[%s] ch = %d, offset = %d, bwmode = %d\n", __func__, channel, channel_offset, bwmode);
+
+       if ((bwmode == HT_CHANNEL_WIDTH_20) ||
+           (channel_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)) {
+               /* SelectChannel23a(padapter, channel); */
+               center_ch = channel;
+       } else {
+               /* switch to the proper channel */
+               if (channel_offset == HAL_PRIME_CHNL_OFFSET_LOWER) {
+                       /* SelectChannel23a(padapter, channel + 2); */
+                       center_ch = channel + 2;
+               } else {
+                       /* SelectChannel23a(padapter, channel - 2); */
+                       center_ch = channel - 2;
+               }
+       }
+
+       /* set Channel */
+       mutex_lock(&adapter_to_dvobj(padapter)->setch_mutex);
+
+       /* saved channel/bw info */
+       rtw_set_oper_ch23a(padapter, channel);
+       rtw_set_oper_bw23a(padapter, bwmode);
+       rtw_set_oper_ch23aoffset23a(padapter, channel_offset);
+
+       rtw_hal_set_chan23a(padapter, center_ch); /*  set center channel */
+
+       mutex_unlock(&adapter_to_dvobj(padapter)->setch_mutex);
+
+       SetBWMode23a(padapter, bwmode, channel_offset);
+}
+
+int get_bsstype23a(unsigned short capability)
+{
+       if (capability & BIT(0))
+               return WIFI_FW_AP_STATE;
+       else if (capability & BIT(1))
+               return WIFI_FW_ADHOC_STATE;
+       return 0;
+}
+
+inline u8 *get_my_bssid23a(struct wlan_bssid_ex *pnetwork)
+{
+       return pnetwork->MacAddress;
+}
+
+u16 get_beacon_interval23a(struct wlan_bssid_ex *bss)
+{
+       unsigned short val;
+       memcpy((unsigned char *)&val, rtw_get_beacon_interval23a_from_ie(bss->IEs), 2);
+
+       return le16_to_cpu(val);
+}
+
+int is_client_associated_to_ap23a(struct rtw_adapter *padapter)
+{
+       struct mlme_ext_priv    *pmlmeext;
+       struct mlme_ext_info    *pmlmeinfo;
+
+       if (!padapter)
+               return _FAIL;
+
+       pmlmeext = &padapter->mlmeextpriv;
+       pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) && ((pmlmeinfo->state&0x03) == WIFI_FW_STATION_STATE))
+               return true;
+       else
+               return _FAIL;
+}
+
+int is_client_associated_to_ibss23a(struct rtw_adapter *padapter)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if ((pmlmeinfo->state & WIFI_FW_ASSOC_SUCCESS) &&
+           ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE))
+               return true;
+       else
+               return _FAIL;
+}
+
+int is_IBSS_empty23a(struct rtw_adapter *padapter)
+{
+       unsigned int i;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       for (i = IBSS_START_MAC_ID; i < NUM_STA; i++) {
+               if (pmlmeinfo->FW_sta_info[i].status == 1)
+                       return _FAIL;
+       }
+
+       return true;
+}
+
+unsigned int decide_wait_for_beacon_timeout23a(unsigned int bcn_interval)
+{
+       if ((bcn_interval << 2) < WAIT_FOR_BCN_TO_MIN)
+               return WAIT_FOR_BCN_TO_MIN;
+       else if ((bcn_interval << 2) > WAIT_FOR_BCN_TO_MAX)
+               return WAIT_FOR_BCN_TO_MAX;
+       else
+               return bcn_interval << 2;
+}
+
+void CAM_empty_entry23a(struct rtw_adapter *Adapter, u8 ucIndex)
+{
+       rtw_hal_set_hwreg23a(Adapter, HW_VAR_CAM_EMPTY_ENTRY, (u8 *)(&ucIndex));
+}
+
+void invalidate_cam_all23a(struct rtw_adapter *padapter)
+{
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_CAM_INVALID_ALL, NULL);
+}
+
+void write_cam23a(struct rtw_adapter *padapter, u8 entry, u16 ctrl, u8 *mac, u8 *key)
+{
+       unsigned int    i, val, addr;
+       int j;
+       u32     cam_val[2];
+
+       addr = entry << 3;
+
+       for (j = 5; j >= 0; j--) {
+               switch (j) {
+               case 0:
+                       val = (ctrl | (mac[0] << 16) | (mac[1] << 24));
+                       break;
+               case 1:
+                       val = (mac[2] | (mac[3] << 8) | (mac[4] << 16) | (mac[5] << 24));
+                       break;
+               default:
+                       i = (j - 2) << 2;
+                       val = (key[i] | (key[i+1] << 8) | (key[i+2] << 16) | (key[i+3] << 24));
+                       break;
+               }
+
+               cam_val[0] = val;
+               cam_val[1] = addr + (unsigned int)j;
+
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_CAM_WRITE, (u8 *)cam_val);
+
+               /* rtw_write32(padapter, WCAMI, val); */
+
+               /* cmd = CAM_POLLINIG | CAM_WRITE | (addr + j); */
+               /* rtw_write32(padapter, RWCAM, cmd); */
+
+               /* DBG_8723A("%s => cam write: %x, %x\n", __func__, cmd, val); */
+
+       }
+}
+
+void clear_cam_entry23a(struct rtw_adapter *padapter, u8 entry)
+{
+       unsigned char null_sta[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+       unsigned char null_key[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+       write_cam23a(padapter, entry, 0, null_sta, null_key);
+}
+
+int allocate_fw_sta_entry23a(struct rtw_adapter *padapter)
+{
+       unsigned int mac_id;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       for (mac_id = IBSS_START_MAC_ID; mac_id < NUM_STA; mac_id++) {
+               if (pmlmeinfo->FW_sta_info[mac_id].status == 0) {
+                       pmlmeinfo->FW_sta_info[mac_id].status = 1;
+                       pmlmeinfo->FW_sta_info[mac_id].retry = 0;
+                       break;
+               }
+       }
+
+       return mac_id;
+}
+
+void flush_all_cam_entry23a(struct rtw_adapter *padapter)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_CAM_INVALID_ALL, NULL);
+
+       memset((u8 *)(pmlmeinfo->FW_sta_info), 0, sizeof(pmlmeinfo->FW_sta_info));
+}
+
+#if defined(CONFIG_8723AU_P2P) && defined(CONFIG_8723AU_P2P)
+int WFD_info_handler(struct rtw_adapter *padapter, struct ndis_802_11_var_ies *        pIE)
+{
+       struct wifidirect_info  *pwdinfo;
+       u8      wfd_ie[128] = {0x00};
+       u32     wfd_ielen = 0;
+
+       pwdinfo = &padapter->wdinfo;
+       if (rtw_get_wfd_ie((u8 *) pIE, pIE->Length, wfd_ie, &wfd_ielen)) {
+               u8      attr_content[ 10 ] = { 0x00 };
+               u32     attr_contentlen = 0;
+
+               DBG_8723A("[%s] Found WFD IE\n", __func__);
+               rtw_get_wfd_attr_content(wfd_ie, wfd_ielen, WFD_ATTR_DEVICE_INFO, attr_content, &attr_contentlen);
+               if (attr_contentlen) {
+                       pwdinfo->wfd_info->peer_rtsp_ctrlport = get_unaligned_be16(attr_content + 2);
+                       DBG_8723A("[%s] Peer PORT NUM = %d\n", __func__, pwdinfo->wfd_info->peer_rtsp_ctrlport);
+                       return true;
+               }
+       } else {
+               DBG_8723A("[%s] NO WFD IE\n", __func__);
+       }
+       return _FAIL;
+}
+#endif
+
+int WMM_param_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies *    pIE)
+{
+       /* struct registry_priv *pregpriv = &padapter->registrypriv; */
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if (pmlmepriv->qospriv.qos_option == 0) {
+               pmlmeinfo->WMM_enable = 0;
+               return _FAIL;
+       }
+
+       pmlmeinfo->WMM_enable = 1;
+       memcpy(&pmlmeinfo->WMM_param, (pIE->data + 6),
+              sizeof(struct WMM_para_element));
+       return true;
+}
+
+void WMMOnAssocRsp23a(struct rtw_adapter *padapter)
+{
+       u8      ACI, ACM, AIFS, ECWMin, ECWMax, aSifsTime;
+       u8      acm_mask;
+       u16     TXOP;
+       u32     acParm, i;
+       u32     edca[4], inx[4];
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct xmit_priv                *pxmitpriv = &padapter->xmitpriv;
+       struct registry_priv    *pregpriv = &padapter->registrypriv;
+
+       if (pmlmeinfo->WMM_enable == 0) {
+               padapter->mlmepriv.acm_mask = 0;
+               return;
+       }
+
+       acm_mask = 0;
+
+       if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
+               aSifsTime = 10;
+       else
+               aSifsTime = 16;
+
+               for (i = 0; i < 4; i++) {
+               ACI = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 5) & 0x03;
+               ACM = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN >> 4) & 0x01;
+
+               /* AIFS = AIFSN * slot time + SIFS - r2t phy delay */
+               AIFS = (pmlmeinfo->WMM_param.ac_param[i].ACI_AIFSN & 0x0f) * pmlmeinfo->slotTime + aSifsTime;
+
+               ECWMin = (pmlmeinfo->WMM_param.ac_param[i].CW & 0x0f);
+               ECWMax = (pmlmeinfo->WMM_param.ac_param[i].CW & 0xf0) >> 4;
+               TXOP = le16_to_cpu(pmlmeinfo->WMM_param.ac_param[i].TXOP_limit);
+
+               acParm = AIFS | (ECWMin << 8) | (ECWMax << 12) | (TXOP << 16);
+
+               switch (ACI) {
+               case 0x0:
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BE, (u8 *)(&acParm));
+                       acm_mask |= (ACM? BIT(1):0);
+                       edca[XMIT_BE_QUEUE] = acParm;
+                       break;
+               case 0x1:
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_BK, (u8 *)(&acParm));
+                       /* acm_mask |= (ACM? BIT(0):0); */
+                       edca[XMIT_BK_QUEUE] = acParm;
+                       break;
+               case 0x2:
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VI, (u8 *)(&acParm));
+                       acm_mask |= (ACM? BIT(2):0);
+                       edca[XMIT_VI_QUEUE] = acParm;
+                       break;
+               case 0x3:
+                       rtw_hal_set_hwreg23a(padapter, HW_VAR_AC_PARAM_VO, (u8 *)(&acParm));
+                       acm_mask |= (ACM? BIT(3):0);
+                       edca[XMIT_VO_QUEUE] = acParm;
+                       break;
+               }
+
+               DBG_8723A("WMM(%x): %x, %x\n", ACI, ACM, acParm);
+       }
+
+       if (padapter->registrypriv.acm_method == 1)
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_ACM_CTRL, (u8 *)(&acm_mask));
+       else
+               padapter->mlmepriv.acm_mask = acm_mask;
+
+       inx[0] = 0; inx[1] = 1; inx[2] = 2; inx[3] = 3;
+
+       if (pregpriv->wifi_spec == 1) {
+               u32     j, tmp, change_inx;
+
+               /* entry indx: 0->vo, 1->vi, 2->be, 3->bk. */
+               for (i = 0; i < 4; i++) {
+                       for (j = i+1; j < 4; j++) {
+                               /* compare CW and AIFS */
+                               if ((edca[j] & 0xFFFF) < (edca[i] & 0xFFFF)) {
+                                       change_inx = true;
+                               } else if ((edca[j] & 0xFFFF) == (edca[i] & 0xFFFF)) {
+                                       /* compare TXOP */
+                                       if ((edca[j] >> 16) > (edca[i] >> 16))
+                                               change_inx = true;
+                               }
+
+                               if (change_inx) {
+                                       tmp = edca[i];
+                                       edca[i] = edca[j];
+                                       edca[j] = tmp;
+
+                                       tmp = inx[i];
+                                       inx[i] = inx[j];
+                                       inx[j] = tmp;
+
+                                       change_inx = false;
+                               }
+                       }
+               }
+       }
+
+       for (i = 0; i<4; i++) {
+               pxmitpriv->wmm_para_seq[i] = inx[i];
+               DBG_8723A("wmm_para_seq(%d): %d\n", i, pxmitpriv->wmm_para_seq[i]);
+       }
+
+       return;
+}
+
+static void bwmode_update_check(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE)
+{
+       struct HT_info_element   *pHT_info;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct registry_priv *pregistrypriv = &padapter->registrypriv;
+       struct ht_priv  *phtpriv = &pmlmepriv->htpriv;
+       unsigned char    new_bwmode;
+       unsigned char  new_ch_offset;
+
+       if (!pIE)
+               return;
+       if (!phtpriv->ht_option)
+               return;
+       if (pIE->Length > sizeof(struct HT_info_element))
+               return;
+
+       pHT_info = (struct HT_info_element *)pIE->data;
+
+       if ((pHT_info->infos[0] & BIT(2)) && pregistrypriv->cbw40_enable) {
+               new_bwmode = HT_CHANNEL_WIDTH_40;
+
+               switch (pHT_info->infos[0] & 0x3) {
+               case 1:
+                       new_ch_offset = HAL_PRIME_CHNL_OFFSET_LOWER;
+                       break;
+               case 3:
+                       new_ch_offset = HAL_PRIME_CHNL_OFFSET_UPPER;
+                       break;
+               default:
+                       new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+                       break;
+               }
+       } else {
+               new_bwmode = HT_CHANNEL_WIDTH_20;
+               new_ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+       }
+
+       if ((new_bwmode!= pmlmeext->cur_bwmode) ||
+           (new_ch_offset!= pmlmeext->cur_ch_offset)) {
+               pmlmeinfo->bwmode_updated = true;
+
+               pmlmeext->cur_bwmode = new_bwmode;
+               pmlmeext->cur_ch_offset = new_ch_offset;
+
+               /* update HT info also */
+               HT_info_handler23a(padapter, pIE);
+       } else {
+               pmlmeinfo->bwmode_updated = false;
+       }
+
+       if (pmlmeinfo->bwmode_updated) {
+               struct sta_info *psta;
+               struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+               struct sta_priv *pstapriv = &padapter->stapriv;
+
+               /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */
+
+               /* update ap's stainfo */
+               psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress);
+               if (psta) {
+                       struct ht_priv  *phtpriv_sta = &psta->htpriv;
+
+                       if (phtpriv_sta->ht_option) {
+                               /*  bwmode */
+                               phtpriv_sta->bwmode = pmlmeext->cur_bwmode;
+                               phtpriv_sta->ch_offset = pmlmeext->cur_ch_offset;
+                       } else {
+                               phtpriv_sta->bwmode = HT_CHANNEL_WIDTH_20;
+                               phtpriv_sta->ch_offset = HAL_PRIME_CHNL_OFFSET_DONT_CARE;
+                       }
+
+               }
+       }
+}
+
+void HT_caps_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE)
+{
+       unsigned int    i;
+       u8      rf_type;
+       u8      max_AMPDU_len, min_MPDU_spacing;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct ht_priv                  *phtpriv = &pmlmepriv->htpriv;
+
+       if (pIE == NULL) return;
+
+       if (phtpriv->ht_option == false)        return;
+
+       pmlmeinfo->HT_caps_enable = 1;
+
+       for (i = 0; i < (pIE->Length); i++) {
+               if (i != 2) {
+                       /*      Commented by Albert 2010/07/12 */
+                       /*      Got the endian issue here. */
+                       pmlmeinfo->HT_caps.u.HT_cap[i] &= (pIE->data[i]);
+               } else {
+                       /* modify from  fw by Thomas 2010/11/17 */
+                       if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3) > (pIE->data[i] & 0x3))
+                               max_AMPDU_len = (pIE->data[i] & 0x3);
+                       else
+                               max_AMPDU_len = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x3);
+
+                       if ((pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) > (pIE->data[i] & 0x1c))
+                               min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c);
+                       else
+                               min_MPDU_spacing = (pIE->data[i] & 0x1c);
+
+                       pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para = max_AMPDU_len | min_MPDU_spacing;
+               }
+       }
+
+       /*      Commented by Albert 2010/07/12 */
+       /*      Have to handle the endian issue after copying. */
+       /*      HT_ext_caps didn't be used yet. */
+       pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info = le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_caps_info);
+       pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps = le16_to_cpu(pmlmeinfo->HT_caps.u.HT_cap_element.HT_ext_caps);
+
+       rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+       /* update the MCS rates */
+       for (i = 0; i < 16; i++) {
+               if ((rf_type == RF_1T1R) || (rf_type == RF_1T2R))
+                       pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_1R23A[i];
+               else
+                       pmlmeinfo->HT_caps.u.HT_cap_element.MCS_rate[i] &= MCS_rate_2R23A[i];
+       }
+       return;
+}
+
+void HT_info_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct mlme_priv                *pmlmepriv = &padapter->mlmepriv;
+       struct ht_priv                  *phtpriv = &pmlmepriv->htpriv;
+
+       if (pIE == NULL) return;
+
+       if (phtpriv->ht_option == false)        return;
+
+       if (pIE->Length > sizeof(struct HT_info_element))
+               return;
+
+       pmlmeinfo->HT_info_enable = 1;
+       memcpy(&pmlmeinfo->HT_info, pIE->data, pIE->Length);
+       return;
+}
+
+void HTOnAssocRsp23a(struct rtw_adapter *padapter)
+{
+       unsigned char           max_AMPDU_len;
+       unsigned char           min_MPDU_spacing;
+       /* struct registry_priv  *pregpriv = &padapter->registrypriv; */
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       DBG_8723A("%s\n", __func__);
+
+       if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable)) {
+               pmlmeinfo->HT_enable = 1;
+       } else {
+               pmlmeinfo->HT_enable = 0;
+               /* set_channel_bwmode23a(padapter, pmlmeext->cur_channel, pmlmeext->cur_ch_offset, pmlmeext->cur_bwmode); */
+               return;
+       }
+
+       /* handle A-MPDU parameter field */
+       /*
+               AMPDU_para [1:0]:Max AMPDU Len => 0:8k , 1:16k, 2:32k, 3:64k
+               AMPDU_para [4:2]:Min MPDU Start Spacing
+       */
+       max_AMPDU_len = pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x03;
+
+       min_MPDU_spacing = (pmlmeinfo->HT_caps.u.HT_cap_element.AMPDU_para & 0x1c) >> 2;
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_MIN_SPACE, (u8 *)(&min_MPDU_spacing));
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_AMPDU_FACTOR, (u8 *)(&max_AMPDU_len));
+}
+
+void ERP_IE_handler23a(struct rtw_adapter *padapter, struct ndis_802_11_var_ies * pIE)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if (pIE->Length>1)
+               return;
+
+       pmlmeinfo->ERP_enable = 1;
+       memcpy(&pmlmeinfo->ERP_IE, pIE->data, pIE->Length);
+}
+
+void VCS_update23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       struct registry_priv     *pregpriv = &padapter->registrypriv;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       switch (pregpriv->vrtl_carrier_sense) { /* 0:off 1:on 2:auto */
+       case 0: /* off */
+               psta->rtsen = 0;
+               psta->cts2self = 0;
+               break;
+       case 1: /* on */
+               if (pregpriv->vcs_type == 1) { /* 1:RTS/CTS 2:CTS to self */
+                       psta->rtsen = 1;
+                       psta->cts2self = 0;
+               } else {
+                       psta->rtsen = 0;
+                       psta->cts2self = 1;
+               }
+               break;
+       case 2: /* auto */
+       default:
+               if ((pmlmeinfo->ERP_enable) && (pmlmeinfo->ERP_IE & BIT(1))) {
+                       if (pregpriv->vcs_type == 1) {
+                               psta->rtsen = 1;
+                               psta->cts2self = 0;
+                       } else {
+                               psta->rtsen = 0;
+                               psta->cts2self = 1;
+                       }
+               } else {
+                       psta->rtsen = 0;
+                       psta->cts2self = 0;
+               }
+               break;
+       }
+}
+
+int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, u8 *pframe, u32 packet_len)
+{
+       unsigned int            len;
+       unsigned char           *p;
+       unsigned short  val16;
+       struct wlan_network *cur_network = &Adapter->mlmepriv.cur_network;
+       u16 wpa_len = 0, rsn_len = 0;
+       u8 encryp_protocol = 0;
+       struct wlan_bssid_ex *bssid;
+       int group_cipher = 0, pairwise_cipher = 0, is_8021x = 0;
+       unsigned char *pbuf;
+       u32 wpa_ielen = 0;
+       u32 hidden_ssid = 0;
+       struct HT_info_element *pht_info = NULL;
+       struct ieee80211_ht_cap *pht_cap = NULL;
+       u32 bcn_channel;
+       unsigned short  ht_cap_info;
+       unsigned char   ht_info_infos_0;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe;
+       u8 *pbssid = hdr->addr3;
+
+       if (is_client_associated_to_ap23a(Adapter) == false)
+               return true;
+
+       len = packet_len - sizeof(struct ieee80211_hdr_3addr);
+
+       if (len > MAX_IE_SZ) {
+               DBG_8723A("%s IE too long for survey event\n", __func__);
+               return _FAIL;
+       }
+
+       if (memcmp(cur_network->network.MacAddress, pbssid, 6)) {
+               DBG_8723A("Oops: rtw_check_network_encrypt linked but recv other bssid bcn\n" MAC_FMT MAC_FMT,
+                               MAC_ARG(pbssid), MAC_ARG(cur_network->network.MacAddress));
+               return true;
+       }
+
+       bssid = (struct wlan_bssid_ex *)kzalloc(sizeof(struct wlan_bssid_ex),
+               GFP_ATOMIC);
+
+       if (ieee80211_is_beacon(hdr->frame_control))
+               bssid->reserved = 1;
+
+       bssid->Length = sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + len;
+
+       /* below is to copy the information element */
+       bssid->IELength = len;
+       memcpy(bssid->IEs, (pframe + sizeof(struct ieee80211_hdr_3addr)), bssid->IELength);
+
+       /* check bw and channel offset */
+       /* parsing HT_CAP_IE */
+       p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _HT_CAPABILITY_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+       if (p && len>0) {
+                       pht_cap = (struct ieee80211_ht_cap *)(p + 2);
+                       ht_cap_info = pht_cap->cap_info;
+       } else {
+                       ht_cap_info = 0;
+       }
+       /* parsing HT_INFO_IE */
+       p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+       if (p && len>0) {
+                       pht_info = (struct HT_info_element *)(p + 2);
+                       ht_info_infos_0 = pht_info->infos[0];
+       } else {
+                       ht_info_infos_0 = 0;
+       }
+       if (ht_cap_info != cur_network->BcnInfo.ht_cap_info ||
+               ((ht_info_infos_0&0x03) != (cur_network->BcnInfo.ht_info_infos_0&0x03))) {
+                       DBG_8723A("%s bcn now: ht_cap_info:%x ht_info_infos_0:%x\n", __func__,
+                                                       ht_cap_info, ht_info_infos_0);
+                       DBG_8723A("%s bcn link: ht_cap_info:%x ht_info_infos_0:%x\n", __func__,
+                                                       cur_network->BcnInfo.ht_cap_info, cur_network->BcnInfo.ht_info_infos_0);
+                       DBG_8723A("%s bw mode change, disconnect\n", __func__);
+                       /* bcn_info_update */
+                       cur_network->BcnInfo.ht_cap_info = ht_cap_info;
+                       cur_network->BcnInfo.ht_info_infos_0 = ht_info_infos_0;
+                       /* to do : need to check that whether modify related register of BB or not */
+       }
+
+       /* Checking for channel */
+       p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _DSSET_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+       if (p) {
+                       bcn_channel = *(p + 2);
+       } else {/* In 5G, some ap do not have DSSET IE checking HT info for channel */
+                       p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _HT_ADD_INFO_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_);
+                       if (pht_info) {
+                                       bcn_channel = pht_info->primary_channel;
+                       } else { /* we don't find channel IE, so don't check it */
+                                       DBG_8723A("Oops: %s we don't find channel IE, so don't check it\n", __func__);
+                                       bcn_channel = Adapter->mlmeextpriv.cur_channel;
+                       }
+       }
+       if (bcn_channel != Adapter->mlmeextpriv.cur_channel) {
+                       DBG_8723A("%s beacon channel:%d cur channel:%d disconnect\n", __func__,
+                                                  bcn_channel, Adapter->mlmeextpriv.cur_channel);
+                       goto _mismatch;
+       }
+
+       /* checking SSID */
+       if ((p = rtw_get_ie23a(bssid->IEs + _FIXED_IE_LENGTH_, _SSID_IE_, &len, bssid->IELength - _FIXED_IE_LENGTH_)) == NULL) {
+               DBG_8723A("%s marc: cannot find SSID for survey event\n", __func__);
+               hidden_ssid = true;
+       } else {
+               hidden_ssid = false;
+       }
+
+       if ((NULL != p) && (false == hidden_ssid && (*(p + 1)))) {
+               memcpy(bssid->Ssid.ssid, (p + 2), *(p + 1));
+               bssid->Ssid.ssid_len = *(p + 1);
+       } else {
+               bssid->Ssid.ssid_len = 0;
+               bssid->Ssid.ssid[0] = '\0';
+       }
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                ("%s bssid.Ssid.Ssid:%s bssid.Ssid.SsidLength:%d "
+                 "cur_network->network.Ssid.Ssid:%s len:%d\n", __func__,
+                 bssid->Ssid.ssid, bssid->Ssid.ssid_len,
+                 cur_network->network.Ssid.ssid,
+                 cur_network->network.Ssid.ssid_len));
+
+       if (memcmp(bssid->Ssid.ssid, cur_network->network.Ssid.ssid, 32) ||
+           bssid->Ssid.ssid_len != cur_network->network.Ssid.ssid_len) {
+               if (bssid->Ssid.ssid[0] != '\0' &&
+                   bssid->Ssid.ssid_len != 0) { /* not hidden ssid */
+                       DBG_8723A("%s(), SSID is not match return FAIL\n",
+                                 __func__);
+                       goto _mismatch;
+               }
+       }
+
+       /* check encryption info */
+       val16 = rtw_get_capability23a((struct wlan_bssid_ex *)bssid);
+
+       if (val16 & BIT(4))
+               bssid->Privacy = 1;
+       else
+               bssid->Privacy = 0;
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                       ("%s(): cur_network->network.Privacy is %d, bssid.Privacy is %d\n",
+                        __func__, cur_network->network.Privacy, bssid->Privacy));
+       if (cur_network->network.Privacy != bssid->Privacy) {
+               DBG_8723A("%s(), privacy is not match return FAIL\n", __func__);
+               goto _mismatch;
+       }
+
+       rtw_get_sec_ie23a(bssid->IEs, bssid->IELength, NULL,&rsn_len, NULL,&wpa_len);
+
+       if (rsn_len > 0) {
+               encryp_protocol = ENCRYP_PROTOCOL_WPA2;
+       } else if (wpa_len > 0) {
+               encryp_protocol = ENCRYP_PROTOCOL_WPA;
+       } else {
+               if (bssid->Privacy)
+                       encryp_protocol = ENCRYP_PROTOCOL_WEP;
+       }
+
+       if (cur_network->BcnInfo.encryp_protocol != encryp_protocol) {
+               DBG_8723A("%s(): enctyp is not match , return FAIL\n", __func__);
+               goto _mismatch;
+       }
+
+       if (encryp_protocol == ENCRYP_PROTOCOL_WPA || encryp_protocol == ENCRYP_PROTOCOL_WPA2) {
+               pbuf = rtw_get_wpa_ie23a(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12);
+               if (pbuf && (wpa_ielen>0)) {
+                       if (_SUCCESS == rtw_parse_wpa_ie23a(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) {
+                               RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                               ("%s pnetwork->pairwise_cipher: %d, group_cipher is %d, is_8021x is %d\n", __func__,
+                                                pairwise_cipher, group_cipher, is_8021x));
+                       }
+               } else {
+                       pbuf = rtw_get_wpa2_ie23a(&bssid->IEs[12], &wpa_ielen, bssid->IELength-12);
+
+                       if (pbuf && (wpa_ielen>0)) {
+                               if (_SUCCESS == rtw_parse_wpa2_ie23a(pbuf, wpa_ielen+2, &group_cipher, &pairwise_cipher, &is_8021x)) {
+                                       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_,
+                                                       ("%s pnetwork->pairwise_cipher: %d, pnetwork->group_cipher is %d, is_802x is %d\n",
+                                                        __func__, pairwise_cipher, group_cipher, is_8021x));
+                               }
+                       }
+               }
+
+               RT_TRACE(_module_rtl871x_mlme_c_, _drv_err_,
+                               ("%s cur_network->group_cipher is %d: %d\n", __func__, cur_network->BcnInfo.group_cipher, group_cipher));
+               if (pairwise_cipher != cur_network->BcnInfo.pairwise_cipher || group_cipher != cur_network->BcnInfo.group_cipher) {
+                       DBG_8723A("%s pairwise_cipher(%x:%x) or group_cipher(%x:%x) is not match , return FAIL\n", __func__,
+                                       pairwise_cipher, cur_network->BcnInfo.pairwise_cipher,
+                                       group_cipher, cur_network->BcnInfo.group_cipher);
+                       goto _mismatch;
+               }
+
+               if (is_8021x != cur_network->BcnInfo.is_8021x) {
+                       DBG_8723A("%s authentication is not match , return FAIL\n", __func__);
+                       goto _mismatch;
+               }
+       }
+
+       kfree(bssid);
+       return _SUCCESS;
+
+_mismatch:
+       kfree(bssid);
+
+       return _FAIL;
+}
+
+void update_beacon23a_info(struct rtw_adapter *padapter, u8 *pframe, uint pkt_len, struct sta_info *psta)
+{
+       unsigned int i;
+       unsigned int len;
+       struct ndis_802_11_var_ies *    pIE;
+
+       len = pkt_len -
+               (_BEACON_IE_OFFSET_ + sizeof(struct ieee80211_hdr_3addr));
+
+       for (i = 0; i < len;) {
+               pIE = (struct ndis_802_11_var_ies *)(pframe + (_BEACON_IE_OFFSET_ + sizeof(struct ieee80211_hdr_3addr)) + i);
+
+               switch (pIE->ElementID) {
+               case _HT_EXTRA_INFO_IE_:        /* HT info */
+                       /* HT_info_handler23a(padapter, pIE); */
+                       bwmode_update_check(padapter, pIE);
+                       break;
+               case _ERPINFO_IE_:
+                       ERP_IE_handler23a(padapter, pIE);
+                       VCS_update23a(padapter, psta);
+                       break;
+               default:
+                       break;
+               }
+               i += (pIE->Length + 2);
+       }
+}
+
+unsigned int is_ap_in_tkip23a(struct rtw_adapter *padapter)
+{
+       u32 i;
+       struct ndis_802_11_var_ies *    pIE;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+
+       if (rtw_get_capability23a((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
+               for (i = sizeof(struct ndis_802_11_fixed_ies); i < pmlmeinfo->network.IELength;) {
+                       pIE = (struct ndis_802_11_var_ies *)(pmlmeinfo->network.IEs + i);
+
+                       switch (pIE->ElementID) {
+                       case _VENDOR_SPECIFIC_IE_:
+                               if ((!memcmp(pIE->data, RTW_WPA_OUI23A, 4)) && (!memcmp((pIE->data + 12), WPA_TKIP_CIPHER23A, 4)))
+                                       return true;
+                               break;
+                       case _RSN_IE_2_:
+                               if (!memcmp((pIE->data + 8), RSN_TKIP_CIPHER23A, 4))
+                                       return true;
+                               break;
+                       default:
+                               break;
+                       }
+                       i += (pIE->Length + 2);
+               }
+               return false;
+       } else {
+               return false;
+       }
+}
+
+unsigned int should_forbid_n_rate23a(struct rtw_adapter * padapter)
+{
+       u32 i;
+       struct ndis_802_11_var_ies *    pIE;
+       struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_bssid_ex  *cur_network = &pmlmepriv->cur_network.network;
+
+       if (rtw_get_capability23a((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
+               for (i = sizeof(struct ndis_802_11_fixed_ies); i < cur_network->IELength;) {
+                       pIE = (struct ndis_802_11_var_ies *)(cur_network->IEs + i);
+
+                       switch (pIE->ElementID) {
+                       case _VENDOR_SPECIFIC_IE_:
+                               if (!memcmp(pIE->data, RTW_WPA_OUI23A, 4) &&
+                                       ((!memcmp((pIE->data + 12), WPA_CIPHER_SUITE_CCMP23A, 4)) ||
+                                         (!memcmp((pIE->data + 16), WPA_CIPHER_SUITE_CCMP23A, 4))))
+                                       return false;
+                               break;
+                       case _RSN_IE_2_:
+                               if  ((!memcmp((pIE->data + 8), RSN_CIPHER_SUITE_CCMP23A, 4))  ||
+                                      (!memcmp((pIE->data + 12), RSN_CIPHER_SUITE_CCMP23A, 4)))
+                               return false;
+                       default:
+                               break;
+                       }
+
+                       i += (pIE->Length + 2);
+               }
+               return true;
+       } else {
+               return false;
+       }
+}
+
+unsigned int is_ap_in_wep23a(struct rtw_adapter *padapter)
+{
+       u32 i;
+       struct ndis_802_11_var_ies *    pIE;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+
+       if (rtw_get_capability23a((struct wlan_bssid_ex *)cur_network) & WLAN_CAPABILITY_PRIVACY) {
+               for (i = sizeof(struct ndis_802_11_fixed_ies); i < pmlmeinfo->network.IELength;) {
+                       pIE = (struct ndis_802_11_var_ies *)(pmlmeinfo->network.IEs + i);
+
+                       switch (pIE->ElementID) {
+                       case _VENDOR_SPECIFIC_IE_:
+                               if (!memcmp(pIE->data, RTW_WPA_OUI23A, 4))
+                                       return false;
+                               break;
+                       case _RSN_IE_2_:
+                               return false;
+
+                       default:
+                               break;
+                       }
+
+                       i += (pIE->Length + 2);
+               }
+
+               return true;
+       } else {
+               return false;
+       }
+}
+
+int wifirate2_ratetbl_inx23a(unsigned char rate)
+{
+       int     inx = 0;
+       rate = rate & 0x7f;
+
+       switch (rate) {
+       case 54*2:
+               inx = 11;
+               break;
+       case 48*2:
+               inx = 10;
+               break;
+       case 36*2:
+               inx = 9;
+               break;
+       case 24*2:
+               inx = 8;
+               break;
+       case 18*2:
+               inx = 7;
+               break;
+       case 12*2:
+               inx = 6;
+               break;
+       case 9*2:
+               inx = 5;
+               break;
+       case 6*2:
+               inx = 4;
+               break;
+       case 11*2:
+               inx = 3;
+               break;
+       case 11:
+               inx = 2;
+               break;
+       case 2*2:
+               inx = 1;
+               break;
+       case 1*2:
+               inx = 0;
+               break;
+       }
+       return inx;
+}
+
+unsigned int update_basic_rate23a(unsigned char *ptn, unsigned int ptn_sz)
+{
+       unsigned int i, num_of_rate;
+       unsigned int mask = 0;
+
+       num_of_rate = (ptn_sz > NumRates)? NumRates: ptn_sz;
+
+       for (i = 0; i < num_of_rate; i++) {
+               if ((*(ptn + i)) & 0x80)
+                       mask |= 0x1 << wifirate2_ratetbl_inx23a(*(ptn + i));
+       }
+       return mask;
+}
+
+unsigned int update_supported_rate23a(unsigned char *ptn, unsigned int ptn_sz)
+{
+       unsigned int i, num_of_rate;
+       unsigned int mask = 0;
+
+       num_of_rate = (ptn_sz > NumRates)? NumRates: ptn_sz;
+
+       for (i = 0; i < num_of_rate; i++)
+               mask |= 0x1 << wifirate2_ratetbl_inx23a(*(ptn + i));
+       return mask;
+}
+
+unsigned int update_MSC_rate23a(struct HT_caps_element *pHT_caps)
+{
+       unsigned int mask = 0;
+
+       mask = ((pHT_caps->u.HT_cap_element.MCS_rate[0] << 12) | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 20));
+
+       return mask;
+}
+
+int support_short_GI23a(struct rtw_adapter *padapter,
+                    struct HT_caps_element *pHT_caps)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       unsigned char bit_offset;
+
+       if (!(pmlmeinfo->HT_enable))
+               return _FAIL;
+       if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK))
+               return _FAIL;
+       bit_offset = (pmlmeext->cur_bwmode & HT_CHANNEL_WIDTH_40)? 6: 5;
+
+       if (pHT_caps->u.HT_cap_element.HT_caps_info & (0x1 << bit_offset))
+               return _SUCCESS;
+       else
+               return _FAIL;
+}
+
+unsigned char get_highest_rate_idx23a(u32 mask)
+{
+       int i;
+       unsigned char rate_idx = 0;
+
+       for (i = 27; i >= 0; i--) {
+               if (mask & BIT(i)) {
+                       rate_idx = i;
+                       break;
+               }
+       }
+       return rate_idx;
+}
+
+unsigned char get_highest_mcs_rate(struct HT_caps_element *pHT_caps)
+{
+       int i, mcs_rate;
+
+       mcs_rate = (pHT_caps->u.HT_cap_element.MCS_rate[0] | (pHT_caps->u.HT_cap_element.MCS_rate[1] << 8));
+
+       for (i = 15; i >= 0; i--) {
+               if (mcs_rate & (0x1 << i))
+                       break;
+       }
+       return i;
+}
+
+void Update_RA_Entry23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       rtw_hal_update_ra_mask23a(psta, 0);
+}
+
+void enable_rate_adaptive(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       Update_RA_Entry23a(padapter, psta);
+}
+
+void set_sta_rate23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       /* rate adaptive */
+       enable_rate_adaptive(padapter, psta);
+}
+
+/*  Update RRSR and Rate for USERATE */
+void update_tx_basic_rate23a(struct rtw_adapter *padapter, u8 wirelessmode)
+{
+       unsigned char supported_rates[NDIS_802_11_LENGTH_RATES_EX];
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info* pwdinfo = &padapter->wdinfo;
+
+       /*      Added by Albert 2011/03/22 */
+       /*      In the P2P mode, the driver should not support the b mode. */
+       /*      So, the Tx packet shouldn't use the CCK rate */
+       if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE))
+               return;
+#endif /* CONFIG_8723AU_P2P */
+
+       memset(supported_rates, 0, NDIS_802_11_LENGTH_RATES_EX);
+
+       if ((wirelessmode & WIRELESS_11B) && (wirelessmode == WIRELESS_11B)) {
+               memcpy(supported_rates, rtw_basic_rate_cck, 4);
+       } else if (wirelessmode & WIRELESS_11B) {
+               memcpy(supported_rates, rtw_basic_rate_mix, 7);
+       } else {
+               memcpy(supported_rates, rtw_basic_rate_ofdm, 3);
+       }
+
+       if (wirelessmode & WIRELESS_11B)
+               update_mgnt_tx_rate23a(padapter, IEEE80211_CCK_RATE_1MB);
+       else
+               update_mgnt_tx_rate23a(padapter, IEEE80211_OFDM_RATE_6MB);
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, supported_rates);
+}
+
+unsigned char check_assoc_AP23a(u8 *pframe, uint len)
+{
+       unsigned int    i;
+       struct ndis_802_11_var_ies *    pIE;
+       u8      epigram_vendor_flag;
+       u8      ralink_vendor_flag;
+       epigram_vendor_flag = 0;
+       ralink_vendor_flag = 0;
+
+       for (i = sizeof(struct ndis_802_11_fixed_ies); i < len;) {
+               pIE = (struct ndis_802_11_var_ies *)(pframe + i);
+
+               switch (pIE->ElementID) {
+               case _VENDOR_SPECIFIC_IE_:
+                       if ((!memcmp(pIE->data, ARTHEROS_OUI1, 3)) ||
+                           (!memcmp(pIE->data, ARTHEROS_OUI2, 3))) {
+                               DBG_8723A("link to Artheros AP\n");
+                               return HT_IOT_PEER_ATHEROS;
+                       } else if ((!memcmp(pIE->data, BROADCOM_OUI1, 3)) ||
+                                  !memcmp(pIE->data, BROADCOM_OUI2, 3) ||
+                                  !memcmp(pIE->data, BROADCOM_OUI2, 3)) {
+                               DBG_8723A("link to Broadcom AP\n");
+                               return HT_IOT_PEER_BROADCOM;
+                       } else if (!memcmp(pIE->data, MARVELL_OUI, 3)) {
+                               DBG_8723A("link to Marvell AP\n");
+                               return HT_IOT_PEER_MARVELL;
+                       } else if (!memcmp(pIE->data, RALINK_OUI, 3)) {
+                               if (!ralink_vendor_flag) {
+                                       ralink_vendor_flag = 1;
+                               } else {
+                                       DBG_8723A("link to Ralink AP\n");
+                                       return HT_IOT_PEER_RALINK;
+                               }
+                       } else if (!memcmp(pIE->data, CISCO_OUI, 3)) {
+                               DBG_8723A("link to Cisco AP\n");
+                               return HT_IOT_PEER_CISCO;
+                       } else if (!memcmp(pIE->data, REALTEK_OUI, 3)) {
+                               DBG_8723A("link to Realtek 96B\n");
+                               return HT_IOT_PEER_REALTEK;
+                       } else if (!memcmp(pIE->data, AIRGOCAP_OUI, 3)) {
+                               DBG_8723A("link to Airgo Cap\n");
+                               return HT_IOT_PEER_AIRGO;
+                       } else if (!memcmp(pIE->data, EPIGRAM_OUI, 3)) {
+                               epigram_vendor_flag = 1;
+                               if (ralink_vendor_flag) {
+                                       DBG_8723A("link to Tenda W311R AP\n");
+                                       return HT_IOT_PEER_TENDA;
+                               } else {
+                                       DBG_8723A("Capture EPIGRAM_OUI\n");
+                               }
+                       } else {
+                               break;
+                       }
+               default:
+                       break;
+               }
+
+               i += (pIE->Length + 2);
+       }
+
+       if (ralink_vendor_flag && !epigram_vendor_flag) {
+               DBG_8723A("link to Ralink AP\n");
+               return HT_IOT_PEER_RALINK;
+       } else if (ralink_vendor_flag && epigram_vendor_flag) {
+               DBG_8723A("link to Tenda W311R AP\n");
+               return HT_IOT_PEER_TENDA;
+       } else {
+               DBG_8723A("link to new AP\n");
+               return HT_IOT_PEER_UNKNOWN;
+       }
+}
+
+void update_IOT_info23a(struct rtw_adapter *padapter)
+{
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       switch (pmlmeinfo->assoc_AP_vendor) {
+       case HT_IOT_PEER_MARVELL:
+               pmlmeinfo->turboMode_cts2self = 1;
+               pmlmeinfo->turboMode_rtsen = 0;
+               break;
+       case HT_IOT_PEER_RALINK:
+               pmlmeinfo->turboMode_cts2self = 0;
+               pmlmeinfo->turboMode_rtsen = 1;
+               /* disable high power */
+               Switch_DM_Func23a(padapter, ~DYNAMIC_BB_DYNAMIC_TXPWR,
+                              false);
+               break;
+       case HT_IOT_PEER_REALTEK:
+               /* rtw_write16(padapter, 0x4cc, 0xffff); */
+               /* rtw_write16(padapter, 0x546, 0x01c0); */
+               /* disable high power */
+               Switch_DM_Func23a(padapter, ~DYNAMIC_BB_DYNAMIC_TXPWR,
+                              false);
+               break;
+       default:
+               pmlmeinfo->turboMode_cts2self = 0;
+               pmlmeinfo->turboMode_rtsen = 1;
+               break;
+       }
+}
+
+void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap)
+{
+       struct mlme_ext_priv    *pmlmeext = &Adapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       bool            ShortPreamble;
+
+       if (updateCap & cShortPreamble) {
+               /*  Short Preamble */
+               if (pmlmeinfo->preamble_mode != PREAMBLE_SHORT) {
+                       /*  PREAMBLE_LONG or PREAMBLE_AUTO */
+                       ShortPreamble = true;
+                       pmlmeinfo->preamble_mode = PREAMBLE_SHORT;
+                       rtw_hal_set_hwreg23a(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble);
+               }
+       } else { /*  Long Preamble */
+               if (pmlmeinfo->preamble_mode != PREAMBLE_LONG) {
+                       /*  PREAMBLE_SHORT or PREAMBLE_AUTO */
+                       ShortPreamble = false;
+                       pmlmeinfo->preamble_mode = PREAMBLE_LONG;
+                       rtw_hal_set_hwreg23a(Adapter, HW_VAR_ACK_PREAMBLE, (u8 *)&ShortPreamble);
+               }
+       }
+       if (updateCap & cIBSS) {
+               /* Filen: See 802.11-2007 p.91 */
+               pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
+       } else {
+               /* Filen: See 802.11-2007 p.90 */
+               if (pmlmeext->cur_wireless_mode & (WIRELESS_11G | WIRELESS_11_24N)) {
+                       if (updateCap & cShortSlotTime) { /*  Short Slot Time */
+                               if (pmlmeinfo->slotTime != SHORT_SLOT_TIME)
+                                       pmlmeinfo->slotTime = SHORT_SLOT_TIME;
+                       } else { /*  Long Slot Time */
+                               if (pmlmeinfo->slotTime != NON_SHORT_SLOT_TIME)
+                                       pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
+                       }
+               } else if (pmlmeext->cur_wireless_mode & (WIRELESS_11A | WIRELESS_11_5N)) {
+                       pmlmeinfo->slotTime = SHORT_SLOT_TIME;
+               } else {
+                       /* B Mode */
+                       pmlmeinfo->slotTime = NON_SHORT_SLOT_TIME;
+               }
+       }
+       rtw_hal_set_hwreg23a(Adapter, HW_VAR_SLOT_TIME, &pmlmeinfo->slotTime);
+}
+
+void update_wireless_mode23a(struct rtw_adapter *padapter)
+{
+       int ratelen, network_type = 0;
+       u32 SIFS_Timer;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+       unsigned char                   *rate = cur_network->SupportedRates;
+
+       ratelen = rtw_get_rateset_len23a(cur_network->SupportedRates);
+
+       if ((pmlmeinfo->HT_info_enable) && (pmlmeinfo->HT_caps_enable))
+               pmlmeinfo->HT_enable = 1;
+
+       if (pmlmeext->cur_channel > 14) {
+               if (pmlmeinfo->HT_enable)
+                       network_type = WIRELESS_11_5N;
+               network_type |= WIRELESS_11A;
+       } else {
+               if (pmlmeinfo->HT_enable)
+                       network_type = WIRELESS_11_24N;
+
+               if ((cckratesonly_included23a(rate, ratelen)) == true)
+                       network_type |= WIRELESS_11B;
+               else if ((cckrates_included23a(rate, ratelen)) == true)
+                       network_type |= WIRELESS_11BG;
+               else
+                       network_type |= WIRELESS_11G;
+       }
+
+       pmlmeext->cur_wireless_mode = network_type & padapter->registrypriv.wireless_mode;
+
+       SIFS_Timer = 0x0a0a0808; /* 0x0808 -> for CCK, 0x0a0a -> for OFDM */
+                             /* change this value if having IOT issues. */
+
+       padapter->HalFunc.SetHwRegHandler(padapter, HW_VAR_RESP_SIFS,  (u8 *)&SIFS_Timer);
+
+       if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
+               update_mgnt_tx_rate23a(padapter, IEEE80211_CCK_RATE_1MB);
+        else
+               update_mgnt_tx_rate23a(padapter, IEEE80211_OFDM_RATE_6MB);
+}
+
+void update_bmc_sta_support_rate23a(struct rtw_adapter *padapter, u32 mac_id)
+{
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if (pmlmeext->cur_wireless_mode & WIRELESS_11B) {
+               /*  Only B, B/G, and B/G/N AP could use CCK rate */
+               memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_cck, 4);
+       } else {
+               memcpy((pmlmeinfo->FW_sta_info[mac_id].SupportedRates), rtw_basic_rate_ofdm, 4);
+       }
+}
+
+int update_sta_support_rate23a(struct rtw_adapter *padapter, u8 *pvar_ie, uint var_ie_len, int cam_idx)
+{
+       unsigned int    ie_len;
+       struct ndis_802_11_var_ies *pIE;
+       int     supportRateNum = 0;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       pIE = (struct ndis_802_11_var_ies *)rtw_get_ie23a(pvar_ie, _SUPPORTEDRATES_IE_, &ie_len, var_ie_len);
+       if (pIE == NULL)
+               return _FAIL;
+
+       memcpy(pmlmeinfo->FW_sta_info[cam_idx].SupportedRates, pIE->data, ie_len);
+       supportRateNum = ie_len;
+
+       pIE = (struct ndis_802_11_var_ies *)rtw_get_ie23a(pvar_ie, _EXT_SUPPORTEDRATES_IE_, &ie_len, var_ie_len);
+       if (pIE)
+               memcpy((pmlmeinfo->FW_sta_info[cam_idx].SupportedRates + supportRateNum), pIE->data, ie_len);
+       return _SUCCESS;
+}
+
+void process_addba_req23a(struct rtw_adapter *padapter, u8 *paddba_req, u8 *addr)
+{
+       struct sta_info *psta;
+       u16 tid, start_seq, param;
+       struct recv_reorder_ctrl *preorder_ctrl;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct ADDBA_request    *preq = (struct ADDBA_request*)paddba_req;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       psta = rtw_get_stainfo23a(pstapriv, addr);
+
+       if (psta) {
+               start_seq = le16_to_cpu(preq->BA_starting_seqctrl) >> 4;
+
+               param = le16_to_cpu(preq->BA_para_set);
+               tid = (param>>2)&0x0f;
+
+               preorder_ctrl = &psta->recvreorder_ctrl[tid];
+
+               preorder_ctrl->indicate_seq = 0xffff;
+
+               preorder_ctrl->enable = (pmlmeinfo->bAcceptAddbaReq == true)? true :false;
+       }
+}
+
+void update_TSF23a(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len)
+{
+       u8 *pIE;
+       u32 *pbuf;
+
+       pIE = pframe + sizeof(struct ieee80211_hdr_3addr);
+       pbuf = (u32 *)pIE;
+
+       pmlmeext->TSFValue = le32_to_cpu(*(pbuf+1));
+
+       pmlmeext->TSFValue = pmlmeext->TSFValue << 32;
+
+       pmlmeext->TSFValue |= le32_to_cpu(*pbuf);
+}
+
+void correct_TSF23a(struct rtw_adapter *padapter, struct mlme_ext_priv *pmlmeext)
+{
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_CORRECT_TSF, NULL);
+}
+
+void beacon_timing_control23a(struct rtw_adapter *padapter)
+{
+       rtw_hal_bcn_related_reg_setting23a(padapter);
+}
+
+static struct rtw_adapter *pbuddy_padapter;
+
+int rtw_handle_dualmac23a(struct rtw_adapter *adapter, bool init)
+{
+       int status = _SUCCESS;
+
+       if (init) {
+               if (pbuddy_padapter == NULL) {
+                       pbuddy_padapter = adapter;
+                       DBG_8723A("%s(): pbuddy_padapter == NULL, Set pbuddy_padapter\n", __func__);
+               } else {
+                       adapter->pbuddy_adapter = pbuddy_padapter;
+                       pbuddy_padapter->pbuddy_adapter = adapter;
+                       /*  clear global value */
+                       pbuddy_padapter = NULL;
+                       DBG_8723A("%s(): pbuddy_padapter exist, Exchange Information\n", __func__);
+               }
+         } else {
+               pbuddy_padapter = NULL;
+       }
+       return status;
+}
diff --git a/drivers/staging/rtl8723au/core/rtw_xmit.c b/drivers/staging/rtl8723au/core/rtw_xmit.c
new file mode 100644 (file)
index 0000000..0f10cfa
--- /dev/null
@@ -0,0 +1,2460 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTW_XMIT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <osdep_intf.h>
+#include <linux/ip.h>
+#include <usb_ops.h>
+
+static u8 P802_1H_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 };
+static u8 RFC1042_OUI[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 };
+
+static void _init_txservq(struct tx_servq *ptxservq)
+{
+
+       INIT_LIST_HEAD(&ptxservq->tx_pending);
+       _rtw_init_queue23a(&ptxservq->sta_pending);
+       ptxservq->qcnt = 0;
+
+}
+
+void   _rtw_init_sta_xmit_priv23a(struct sta_xmit_priv *psta_xmitpriv)
+{
+
+       spin_lock_init(&psta_xmitpriv->lock);
+
+       /* for (i = 0 ; i < MAX_NUMBLKS; i++) */
+       /*      _init_txservq(&psta_xmitpriv->blk_q[i]); */
+
+       _init_txservq(&psta_xmitpriv->be_q);
+       _init_txservq(&psta_xmitpriv->bk_q);
+       _init_txservq(&psta_xmitpriv->vi_q);
+       _init_txservq(&psta_xmitpriv->vo_q);
+       INIT_LIST_HEAD(&psta_xmitpriv->legacy_dz);
+       INIT_LIST_HEAD(&psta_xmitpriv->apsd);
+
+}
+
+s32    _rtw_init_xmit_priv23a(struct xmit_priv *pxmitpriv, struct rtw_adapter *padapter)
+{
+       int i;
+       struct xmit_buf *pxmitbuf;
+       struct xmit_frame *pxframe;
+       int     res = _SUCCESS;
+       u32 max_xmit_extbuf_size = MAX_XMIT_EXTBUF_SZ;
+       u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
+
+       /*  We don't need to memset padapter->XXX to zero, because adapter is allocated by rtw_zvmalloc(). */
+       /* memset((unsigned char *)pxmitpriv, 0, sizeof(struct xmit_priv)); */
+
+       spin_lock_init(&pxmitpriv->lock);
+       spin_lock_init(&pxmitpriv->lock_sctx);
+       sema_init(&pxmitpriv->xmit_sema, 0);
+       sema_init(&pxmitpriv->terminate_xmitthread_sema, 0);
+
+       /*
+       Please insert all the queue initializaiton using _rtw_init_queue23a below
+       */
+
+       pxmitpriv->adapter = padapter;
+
+       _rtw_init_queue23a(&pxmitpriv->be_pending);
+       _rtw_init_queue23a(&pxmitpriv->bk_pending);
+       _rtw_init_queue23a(&pxmitpriv->vi_pending);
+       _rtw_init_queue23a(&pxmitpriv->vo_pending);
+       _rtw_init_queue23a(&pxmitpriv->bm_pending);
+
+       _rtw_init_queue23a(&pxmitpriv->free_xmit_queue);
+
+       /*
+       Please allocate memory with the sz = (struct xmit_frame) * NR_XMITFRAME,
+       and initialize free_xmit_frame below.
+       Please also apply  free_txobj to link_up all the xmit_frames...
+       */
+
+       pxmitpriv->pallocated_frame_buf = rtw_zvmalloc(NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
+
+       if (pxmitpriv->pallocated_frame_buf  == NULL) {
+               pxmitpriv->pxmit_frame_buf = NULL;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xmit_frame fail!\n"));
+               res = _FAIL;
+               goto exit;
+       }
+       pxmitpriv->pxmit_frame_buf = PTR_ALIGN(pxmitpriv->pallocated_frame_buf, 4);
+
+       pxframe = (struct xmit_frame*) pxmitpriv->pxmit_frame_buf;
+
+       for (i = 0; i < NR_XMITFRAME; i++) {
+               INIT_LIST_HEAD(&pxframe->list);
+
+               pxframe->padapter = padapter;
+               pxframe->frame_tag = NULL_FRAMETAG;
+
+               pxframe->pkt = NULL;
+
+               pxframe->buf_addr = NULL;
+               pxframe->pxmitbuf = NULL;
+
+               list_add_tail(&pxframe->list,
+                             &pxmitpriv->free_xmit_queue.queue);
+
+               pxframe++;
+       }
+
+       pxmitpriv->free_xmitframe_cnt = NR_XMITFRAME;
+
+       pxmitpriv->frag_len = MAX_FRAG_THRESHOLD;
+
+       /* init xmit_buf */
+       _rtw_init_queue23a(&pxmitpriv->free_xmitbuf_queue);
+       INIT_LIST_HEAD(&pxmitpriv->xmitbuf_list);
+       _rtw_init_queue23a(&pxmitpriv->pending_xmitbuf_queue);
+
+       for (i = 0; i < NR_XMITBUFF; i++) {
+               pxmitbuf = kzalloc(sizeof(struct xmit_buf), GFP_KERNEL);
+               if (!pxmitbuf)
+                       goto fail;
+               INIT_LIST_HEAD(&pxmitbuf->list);
+               INIT_LIST_HEAD(&pxmitbuf->list2);
+
+               pxmitbuf->padapter = padapter;
+
+               /* Tx buf allocation may fail sometimes, so sleep and retry. */
+               res = rtw_os_xmit_resource_alloc23a(padapter, pxmitbuf,
+                                                (MAX_XMITBUF_SZ + XMITBUF_ALIGN_SZ));
+               if (res == _FAIL) {
+                       goto fail;
+               }
+
+               list_add_tail(&pxmitbuf->list,
+                             &pxmitpriv->free_xmitbuf_queue.queue);
+               list_add_tail(&pxmitbuf->list2,
+                             &pxmitpriv->xmitbuf_list);
+       }
+
+       pxmitpriv->free_xmitbuf_cnt = NR_XMITBUFF;
+
+       /* init xframe_ext queue,  the same count as extbuf  */
+       _rtw_init_queue23a(&pxmitpriv->free_xframe_ext_queue);
+
+       pxmitpriv->xframe_ext_alloc_addr = rtw_zvmalloc(num_xmit_extbuf * sizeof(struct xmit_frame) + 4);
+
+       if (pxmitpriv->xframe_ext_alloc_addr  == NULL) {
+               pxmitpriv->xframe_ext = NULL;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("alloc xframe_ext fail!\n"));
+               res = _FAIL;
+               goto exit;
+       }
+       pxmitpriv->xframe_ext = PTR_ALIGN(pxmitpriv->xframe_ext_alloc_addr, 4);
+       pxframe = (struct xmit_frame*)pxmitpriv->xframe_ext;
+
+       for (i = 0; i < num_xmit_extbuf; i++) {
+               INIT_LIST_HEAD(&pxframe->list);
+
+               pxframe->padapter = padapter;
+               pxframe->frame_tag = NULL_FRAMETAG;
+
+               pxframe->pkt = NULL;
+
+               pxframe->buf_addr = NULL;
+               pxframe->pxmitbuf = NULL;
+
+               pxframe->ext_tag = 1;
+
+               list_add_tail(&pxframe->list,
+                             &pxmitpriv->free_xframe_ext_queue.queue);
+
+               pxframe++;
+       }
+       pxmitpriv->free_xframe_ext_cnt = num_xmit_extbuf;
+
+       /*  Init xmit extension buff */
+       _rtw_init_queue23a(&pxmitpriv->free_xmit_extbuf_queue);
+       INIT_LIST_HEAD(&pxmitpriv->xmitextbuf_list);
+
+       for (i = 0; i < num_xmit_extbuf; i++) {
+               pxmitbuf = kzalloc(sizeof(struct xmit_buf), GFP_KERNEL);
+               if (!pxmitbuf)
+                       goto fail;
+               INIT_LIST_HEAD(&pxmitbuf->list);
+               INIT_LIST_HEAD(&pxmitbuf->list2);
+
+               pxmitbuf->padapter = padapter;
+
+               /* Tx buf allocation may fail sometimes, so sleep and retry. */
+               res = rtw_os_xmit_resource_alloc23a(padapter, pxmitbuf,
+                                                max_xmit_extbuf_size + XMITBUF_ALIGN_SZ);
+               if (res == _FAIL) {
+                       goto exit;
+               }
+
+               list_add_tail(&pxmitbuf->list,
+                             &pxmitpriv->free_xmit_extbuf_queue.queue);
+               list_add_tail(&pxmitbuf->list2,
+                             &pxmitpriv->xmitextbuf_list);
+       }
+
+       pxmitpriv->free_xmit_extbuf_cnt = num_xmit_extbuf;
+
+       rtw_alloc_hwxmits23a(padapter);
+       rtw_init_hwxmits23a(pxmitpriv->hwxmits, pxmitpriv->hwxmit_entry);
+
+       for (i = 0; i < 4; i ++)
+               pxmitpriv->wmm_para_seq[i] = i;
+
+       pxmitpriv->txirp_cnt = 1;
+
+       sema_init(&pxmitpriv->tx_retevt, 0);
+
+       /* per AC pending irp */
+       pxmitpriv->beq_cnt = 0;
+       pxmitpriv->bkq_cnt = 0;
+       pxmitpriv->viq_cnt = 0;
+       pxmitpriv->voq_cnt = 0;
+
+       pxmitpriv->ack_tx = false;
+       mutex_init(&pxmitpriv->ack_tx_mutex);
+       rtw_sctx_init23a(&pxmitpriv->ack_tx_ops, 0);
+       rtw_hal_init23a_xmit_priv(padapter);
+
+exit:
+
+       return res;
+fail:
+       goto exit;
+}
+
+void _rtw_free_xmit_priv23a (struct xmit_priv *pxmitpriv)
+{
+       struct rtw_adapter *padapter = pxmitpriv->adapter;
+       struct xmit_frame *pxmitframe = (struct xmit_frame*) pxmitpriv->pxmit_frame_buf;
+       struct xmit_buf *pxmitbuf;
+       struct list_head *plist, *ptmp;
+       u32 num_xmit_extbuf = NR_XMIT_EXTBUFF;
+       int i;
+
+       rtw_hal_free_xmit_priv23a(padapter);
+
+       if (pxmitpriv->pxmit_frame_buf == NULL)
+               return;
+       for (i = 0; i < NR_XMITFRAME; i++) {
+               rtw_os_xmit_complete23a(padapter, pxmitframe);
+               pxmitframe++;
+       }
+
+       list_for_each_safe(plist, ptmp, &pxmitpriv->xmitbuf_list) {
+               pxmitbuf = container_of(plist, struct xmit_buf, list2);
+               list_del_init(&pxmitbuf->list2);
+               rtw_os_xmit_resource_free23a(padapter, pxmitbuf);
+               kfree(pxmitbuf);
+       }
+
+       if (pxmitpriv->pallocated_frame_buf) {
+               rtw_vmfree(pxmitpriv->pallocated_frame_buf, NR_XMITFRAME * sizeof(struct xmit_frame) + 4);
+       }
+
+       /* free xframe_ext queue,  the same count as extbuf  */
+       if ((pxmitframe = (struct xmit_frame*)pxmitpriv->xframe_ext)) {
+               for (i = 0; i<num_xmit_extbuf; i++) {
+                       rtw_os_xmit_complete23a(padapter, pxmitframe);
+                       pxmitframe++;
+               }
+       }
+       if (pxmitpriv->xframe_ext_alloc_addr)
+               rtw_vmfree(pxmitpriv->xframe_ext_alloc_addr, num_xmit_extbuf * sizeof(struct xmit_frame) + 4);
+
+       /*  free xmit extension buff */
+       list_for_each_safe(plist, ptmp, &pxmitpriv->xmitextbuf_list) {
+               pxmitbuf = container_of(plist, struct xmit_buf, list2);
+               list_del_init(&pxmitbuf->list2);
+               rtw_os_xmit_resource_free23a(padapter, pxmitbuf);
+               kfree(pxmitbuf);
+       }
+
+       rtw_free_hwxmits23a(padapter);
+       mutex_destroy(&pxmitpriv->ack_tx_mutex);
+}
+
+static void update_attrib_vcs_info(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       u32     sz;
+       struct pkt_attrib       *pattrib = &pxmitframe->attrib;
+       struct sta_info *psta = pattrib->psta;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+        if (pattrib->psta) {
+               psta = pattrib->psta;
+       } else {
+               DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
+               psta = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]);
+       }
+
+        if (psta == NULL) {
+               DBG_8723A("%s, psta == NUL\n", __func__);
+               return;
+       }
+
+       if (!(psta->state &_FW_LINKED)) {
+               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state);
+               return;
+       }
+
+       if (pattrib->nr_frags != 1)
+               sz = padapter->xmitpriv.frag_len;
+       else /* no frag */
+               sz = pattrib->last_txcmdsz;
+
+       /*  (1) RTS_Threshold is compared to the MPDU, not MSDU. */
+       /*  (2) If there are more than one frag in  this MSDU, only the first frag uses protection frame. */
+       /*              Other fragments are protected by previous fragment. */
+       /*              So we only need to check the length of first fragment. */
+       if (pmlmeext->cur_wireless_mode < WIRELESS_11_24N  || padapter->registrypriv.wifi_spec) {
+               if (sz > padapter->registrypriv.rts_thresh) {
+                       pattrib->vcs_mode = RTS_CTS;
+               } else {
+                       if (psta->rtsen)
+                               pattrib->vcs_mode = RTS_CTS;
+                       else if (psta->cts2self)
+                               pattrib->vcs_mode = CTS_TO_SELF;
+                       else
+                               pattrib->vcs_mode = NONE_VCS;
+               }
+       } else {
+               while (true) {
+                       /* IOT action */
+                       if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS) &&
+                           (pattrib->ampdu_en) &&
+                           (padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)) {
+                               pattrib->vcs_mode = CTS_TO_SELF;
+                               break;
+                       }
+
+                       /* check ERP protection */
+                       if (psta->rtsen || psta->cts2self) {
+                               if (psta->rtsen)
+                                       pattrib->vcs_mode = RTS_CTS;
+                               else if (psta->cts2self)
+                                       pattrib->vcs_mode = CTS_TO_SELF;
+
+                               break;
+                       }
+
+                       /* check HT op mode */
+                       if (pattrib->ht_en) {
+                               u8 HTOpMode = pmlmeinfo->HT_protection;
+                               if ((pmlmeext->cur_bwmode && (HTOpMode == 2 || HTOpMode == 3)) ||
+                                   (!pmlmeext->cur_bwmode && HTOpMode == 3)) {
+                                       pattrib->vcs_mode = RTS_CTS;
+                                       break;
+                               }
+                       }
+
+                       /* check rts */
+                       if (sz > padapter->registrypriv.rts_thresh) {
+                               pattrib->vcs_mode = RTS_CTS;
+                               break;
+                       }
+
+                       /* to do list: check MIMO power save condition. */
+
+                       /* check AMPDU aggregation for TXOP */
+                       if (pattrib->ampdu_en) {
+                               pattrib->vcs_mode = RTS_CTS;
+                               break;
+                       }
+
+                       pattrib->vcs_mode = NONE_VCS;
+                       break;
+               }
+       }
+}
+
+static void update_attrib_phy_info(struct pkt_attrib *pattrib, struct sta_info *psta)
+{
+       /*if (psta->rtsen)
+               pattrib->vcs_mode = RTS_CTS;
+       else if (psta->cts2self)
+               pattrib->vcs_mode = CTS_TO_SELF;
+       else
+               pattrib->vcs_mode = NONE_VCS;*/
+
+       pattrib->mdata = 0;
+       pattrib->eosp = 0;
+       pattrib->triggered = 0;
+
+       /* qos_en, ht_en, init rate, , bw, ch_offset, sgi */
+       pattrib->qos_en = psta->qos_option;
+
+       pattrib->raid = psta->raid;
+       pattrib->ht_en = psta->htpriv.ht_option;
+       pattrib->bwmode = psta->htpriv.bwmode;
+       pattrib->ch_offset = psta->htpriv.ch_offset;
+       pattrib->sgi = psta->htpriv.sgi;
+       pattrib->ampdu_en = false;
+
+       pattrib->retry_ctrl = false;
+}
+
+u8 qos_acm23a(u8 acm_mask, u8 priority)
+{
+       u8 change_priority = priority;
+
+       switch (priority) {
+       case 0:
+       case 3:
+               if (acm_mask & BIT(1))
+                       change_priority = 1;
+               break;
+       case 1:
+       case 2:
+               break;
+       case 4:
+       case 5:
+               if (acm_mask & BIT(2))
+                       change_priority = 0;
+               break;
+       case 6:
+       case 7:
+               if (acm_mask & BIT(3))
+                       change_priority = 5;
+               break;
+       default:
+               DBG_8723A("qos_acm23a(): invalid pattrib->priority: %d!!!\n",
+                         priority);
+               break;
+       }
+
+       return change_priority;
+}
+
+static void set_qos(struct pkt_file *ppktfile, struct pkt_attrib *pattrib)
+{
+       struct ethhdr etherhdr;
+       struct iphdr ip_hdr;
+       s32 UserPriority = 0;
+
+       _rtw_open_pktfile23a(ppktfile->pkt, ppktfile);
+       _rtw_pktfile_read23a(ppktfile, (unsigned char*)&etherhdr, ETH_HLEN);
+
+       /*  get UserPriority from IP hdr */
+       if (pattrib->ether_type == 0x0800) {
+               _rtw_pktfile_read23a(ppktfile, (u8*)&ip_hdr, sizeof(ip_hdr));
+/*             UserPriority = (ntohs(ip_hdr.tos) >> 5) & 0x3; */
+               UserPriority = ip_hdr.tos >> 5;
+       } else if (pattrib->ether_type == 0x888e) {
+               /*  "When priority processing of data frames is supported, */
+               /*  a STA's SME should send EAPOL-Key frames at the highest
+                   priority." */
+               UserPriority = 7;
+       }
+
+       pattrib->priority = UserPriority;
+       pattrib->hdrlen = sizeof(struct ieee80211_qos_hdr);
+       pattrib->subtype = WIFI_QOS_DATA_TYPE;
+}
+
+static s32 update_attrib(struct rtw_adapter *padapter,
+                        struct sk_buff *pkt, struct pkt_attrib *pattrib)
+{
+       uint i;
+       struct pkt_file pktfile;
+       struct sta_info *psta = NULL;
+       struct ethhdr etherhdr;
+
+       int bmcast;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+       int res = _SUCCESS;
+
+       _rtw_open_pktfile23a(pkt, &pktfile);
+       i = _rtw_pktfile_read23a(&pktfile, (u8*)&etherhdr, ETH_HLEN);
+
+       pattrib->ether_type = ntohs(etherhdr.h_proto);
+
+       memcpy(pattrib->dst, &etherhdr.h_dest, ETH_ALEN);
+       memcpy(pattrib->src, &etherhdr.h_source, ETH_ALEN);
+
+       pattrib->pctrl = 0;
+
+       if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
+               (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
+               memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+               memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+       }
+       else if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+               memcpy(pattrib->ra, get_bssid(pmlmepriv), ETH_ALEN);
+               memcpy(pattrib->ta, pattrib->src, ETH_ALEN);
+       }
+       else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+               memcpy(pattrib->ra, pattrib->dst, ETH_ALEN);
+               memcpy(pattrib->ta, get_bssid(pmlmepriv), ETH_ALEN);
+       }
+
+       pattrib->pktlen = pktfile.pkt_len;
+
+       if (pattrib->ether_type == ETH_P_IP) {
+               /*  The following is for DHCP and ARP packet, we use cck1M
+                   to tx these packets and let LPS awake some time */
+               /*  to prevent DHCP protocol fail */
+               u8 tmp[24];
+               _rtw_pktfile_read23a(&pktfile, &tmp[0], 24);
+               pattrib->dhcp_pkt = 0;
+               if (pktfile.pkt_len > 282) {/* MINIMUM_DHCP_PACKET_SIZE) { */
+                       if (ETH_P_IP == pattrib->ether_type) {/*  IP header */
+                               if (((tmp[21] == 68) && (tmp[23] == 67)) ||
+                                   ((tmp[21] == 67) && (tmp[23] == 68))) {
+                                       /*  68 : UDP BOOTP client */
+                                       /*  67 : UDP BOOTP server */
+                                       RT_TRACE(_module_rtl871x_xmit_c_,
+                                                _drv_err_,
+                                                ("======================"
+                                                 "update_attrib: get DHCP "
+                                                 "Packet\n"));
+                                       pattrib->dhcp_pkt = 1;
+                               }
+                       }
+               }
+       } else if (0x888e == pattrib->ether_type) {
+               DBG_8723A_LEVEL(_drv_always_, "send eapol packet\n");
+       }
+
+       if ((pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) {
+               rtw_set_scan_deny(padapter, 3000);
+       }
+
+       /*  If EAPOL , ARP , OR DHCP packet, driver must be in active mode. */
+       if ((pattrib->ether_type == 0x0806) ||
+           (pattrib->ether_type == 0x888e) || (pattrib->dhcp_pkt == 1)) {
+               rtw_lps_ctrl_wk_cmd23a(padapter, LPS_CTRL_SPECIAL_PACKET, 1);
+       }
+
+       bmcast = is_multicast_ether_addr(pattrib->ra);
+
+       /*  get sta_info */
+       if (bmcast) {
+               psta = rtw_get_bcmc_stainfo23a(padapter);
+       } else {
+               psta = rtw_get_stainfo23a(pstapriv, pattrib->ra);
+               if (psta == NULL) { /*  if we cannot get psta => drrp the pkt */
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_,
+                                ("\nupdate_attrib => get sta_info fail, ra:"
+                                 MAC_FMT"\n", MAC_ARG(pattrib->ra)));
+                       res = _FAIL;
+                       goto exit;
+               } else if ((check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) &&
+                          (!(psta->state & _FW_LINKED))) {
+                       res = _FAIL;
+                       goto exit;
+               }
+       }
+
+       if (psta) {
+               pattrib->mac_id = psta->mac_id;
+               /* DBG_8723A("%s ==> mac_id(%d)\n", __func__, pattrib->mac_id); */
+               pattrib->psta = psta;
+       } else {
+               /*  if we cannot get psta => drop the pkt */
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_,
+                        ("\nupdate_attrib => get sta_info fail, ra:" MAC_FMT
+                         "\n", MAC_ARG(pattrib->ra)));
+               res = _FAIL;
+               goto exit;
+       }
+
+       pattrib->ack_policy = 0;
+       /*  get ether_hdr_len */
+
+       /* pattrib->ether_type == 0x8100) ? (14 + 4): 14; vlan tag */
+       pattrib->pkt_hdrlen = ETH_HLEN;
+
+       pattrib->hdrlen = sizeof(struct ieee80211_hdr_3addr);
+       pattrib->subtype = WIFI_DATA_TYPE;
+       pattrib->priority = 0;
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE | WIFI_ADHOC_STATE |
+                         WIFI_ADHOC_MASTER_STATE)) {
+               if (psta->qos_option)
+                       set_qos(&pktfile, pattrib);
+       } else {
+               if (pqospriv->qos_option) {
+                       set_qos(&pktfile, pattrib);
+
+                       if (pmlmepriv->acm_mask != 0) {
+                               pattrib->priority = qos_acm23a(pmlmepriv->acm_mask,
+                                                           pattrib->priority);
+                       }
+               }
+       }
+
+       if (psta->ieee8021x_blocked == true) {
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                        ("\n psta->ieee8021x_blocked == true\n"));
+
+               pattrib->encrypt = 0;
+
+               if ((pattrib->ether_type != 0x888e) &&
+                   (check_fwstate(pmlmepriv, WIFI_MP_STATE) == false)) {
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                ("\npsta->ieee8021x_blocked == true,  "
+                                 "pattrib->ether_type(%.4x) != 0x888e\n",
+                                 pattrib->ether_type));
+                       res = _FAIL;
+                       goto exit;
+               }
+       } else {
+               GET_ENCRY_ALGO(psecuritypriv, psta, pattrib->encrypt, bmcast);
+
+               switch (psecuritypriv->dot11AuthAlgrthm) {
+               case dot11AuthAlgrthm_Open:
+               case dot11AuthAlgrthm_Shared:
+               case dot11AuthAlgrthm_Auto:
+                       pattrib->key_idx =
+                               (u8)psecuritypriv->dot11PrivacyKeyIndex;
+                       break;
+               case dot11AuthAlgrthm_8021X:
+                       if (bmcast)
+                               pattrib->key_idx =
+                                       (u8)psecuritypriv->dot118021XGrpKeyid;
+                       else
+                               pattrib->key_idx = 0;
+                       break;
+               default:
+                       pattrib->key_idx = 0;
+                       break;
+               }
+
+       }
+
+       switch (pattrib->encrypt) {
+       case _WEP40_:
+       case _WEP104_:
+               pattrib->iv_len = 4;
+               pattrib->icv_len = 4;
+               break;
+
+       case _TKIP_:
+               pattrib->iv_len = 8;
+               pattrib->icv_len = 4;
+
+               if (padapter->securitypriv.busetkipkey == _FAIL) {
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                ("\npadapter->securitypriv.busetkip"
+                                 "key(%d) == _FAIL drop packet\n",
+                                 padapter->securitypriv.busetkipkey));
+                       res = _FAIL;
+                       goto exit;
+               }
+
+               break;
+       case _AES_:
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                        ("pattrib->encrypt =%d (_AES_)\n", pattrib->encrypt));
+               pattrib->iv_len = 8;
+               pattrib->icv_len = 8;
+               break;
+
+       default:
+               pattrib->iv_len = 0;
+               pattrib->icv_len = 0;
+               break;
+       }
+
+       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                ("update_attrib: encrypt =%d\n", pattrib->encrypt));
+
+       if (pattrib->encrypt && psecuritypriv->hw_decrypted == false) {
+               pattrib->bswenc = true;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                        ("update_attrib: encrypt =%d bswenc = true\n",
+                         pattrib->encrypt));
+       } else {
+               pattrib->bswenc = false;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                        ("update_attrib: bswenc = false\n"));
+       }
+       update_attrib_phy_info(pattrib, psta);
+
+exit:
+
+       return res;
+}
+
+static s32 xmitframe_addmic(struct rtw_adapter *padapter,
+                           struct xmit_frame *pxmitframe) {
+       struct mic_data micdata;
+       struct sta_info *stainfo;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       int curfragnum, length;
+       u8 *pframe, *payload, mic[8];
+       u8 priority[4]= {0x0, 0x0, 0x0, 0x0};
+       u8 hw_hdr_offset = 0;
+       int bmcst = is_multicast_ether_addr(pattrib->ra);
+
+       if (pattrib->psta) {
+               stainfo = pattrib->psta;
+       } else {
+               DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
+               stainfo = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]);
+       }
+
+       if (!stainfo) {
+               DBG_8723A("%s, psta == NUL\n", __func__);
+               return _FAIL;
+       }
+
+       if (!(stainfo->state &_FW_LINKED)) {
+               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n",
+                         __func__, stainfo->state);
+               return _FAIL;
+       }
+
+       hw_hdr_offset = TXDESC_OFFSET;
+
+       if (pattrib->encrypt == _TKIP_) {
+               /* encode mic code */
+               if (stainfo) {
+                       u8 null_key[16]={0x0, 0x0, 0x0, 0x0,
+                                        0x0, 0x0, 0x0, 0x0,
+                                        0x0, 0x0, 0x0, 0x0,
+                                        0x0, 0x0, 0x0, 0x0};
+
+                       pframe = pxmitframe->buf_addr + hw_hdr_offset;
+
+                       if (bmcst) {
+                               if (!memcmp(psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey, null_key, 16)) {
+                                       return _FAIL;
+                               }
+                               /* start to calculate the mic code */
+                               rtw_secmicsetkey23a(&micdata, psecuritypriv->dot118021XGrptxmickey[psecuritypriv->dot118021XGrpKeyid].skey);
+                       } else {
+                               if (!memcmp(&stainfo->dot11tkiptxmickey.skey[0],
+                                           null_key, 16)) {
+                                       return _FAIL;
+                               }
+                               /* start to calculate the mic code */
+                               rtw_secmicsetkey23a(&micdata, &stainfo->dot11tkiptxmickey.skey[0]);
+                       }
+
+                       if (pframe[1] & 1) {   /* ToDS == 1 */
+                               /* DA */
+                               rtw_secmicappend23a(&micdata, &pframe[16], 6);
+                               if (pframe[1] & 2)  /* From Ds == 1 */
+                                       rtw_secmicappend23a(&micdata,
+                                                        &pframe[24], 6);
+                               else
+                                       rtw_secmicappend23a(&micdata,
+                                                        &pframe[10], 6);
+                       } else {        /* ToDS == 0 */
+                               /* DA */
+                               rtw_secmicappend23a(&micdata, &pframe[4], 6);
+                               if (pframe[1] & 2)  /* From Ds == 1 */
+                                       rtw_secmicappend23a(&micdata,
+                                                        &pframe[16], 6);
+                               else
+                                       rtw_secmicappend23a(&micdata,
+                                                        &pframe[10], 6);
+                       }
+
+                       /* if (pqospriv->qos_option == 1) */
+                       if (pattrib->qos_en)
+                               priority[0] = (u8)pxmitframe->attrib.priority;
+
+                       rtw_secmicappend23a(&micdata, &priority[0], 4);
+
+                       payload = pframe;
+
+                       for (curfragnum = 0; curfragnum < pattrib->nr_frags;
+                            curfragnum++) {
+                               payload = PTR_ALIGN(payload, 4);
+                               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                        ("=== curfragnum =%d, pframe = 0x%.2x, "
+                                         "0x%.2x, 0x%.2x, 0x%.2x, 0x%.2x, 0x"
+                                         "%.2x, 0x%.2x, 0x%.2x,!!!\n",
+                                         curfragnum, *payload, *(payload + 1),
+                                         *(payload + 2), *(payload + 3),
+                                         *(payload + 4), *(payload + 5),
+                                         *(payload + 6), *(payload + 7)));
+
+                               payload = payload + pattrib->hdrlen +
+                                       pattrib->iv_len;
+                               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                        ("curfragnum =%d pattrib->hdrlen =%d "
+                                         "pattrib->iv_len =%d", curfragnum,
+                                         pattrib->hdrlen, pattrib->iv_len));
+                               if ((curfragnum + 1) == pattrib->nr_frags) {
+                                       length = pattrib->last_txcmdsz -
+                                               pattrib->hdrlen -
+                                               pattrib->iv_len -
+                                               ((pattrib->bswenc) ?
+                                                pattrib->icv_len : 0);
+                                       rtw_secmicappend23a(&micdata, payload,
+                                                        length);
+                                       payload = payload + length;
+                               } else {
+                                       length = pxmitpriv->frag_len -
+                                               pattrib->hdrlen -
+                                               pattrib->iv_len -
+                                               ((pattrib->bswenc) ?
+                                                pattrib->icv_len : 0);
+                                       rtw_secmicappend23a(&micdata, payload,
+                                                        length);
+                                       payload = payload + length +
+                                               pattrib->icv_len;
+                                       RT_TRACE(_module_rtl871x_xmit_c_,
+                                                _drv_err_,
+                                                ("curfragnum =%d length =%d "
+                                                 "pattrib->icv_len =%d",
+                                                 curfragnum, length,
+                                                 pattrib->icv_len));
+                               }
+                       }
+                       rtw_secgetmic23a(&micdata, &mic[0]);
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                ("xmitframe_addmic: before add mic code!!\n"));
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                ("xmitframe_addmic: pattrib->last_txcmdsz ="
+                                 "%d!!!\n", pattrib->last_txcmdsz));
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                ("xmitframe_addmic: mic[0]= 0x%.2x , mic[1]="
+                                 "0x%.2x , mic[2]= 0x%.2x , mic[3]= 0x%.2x\n"
+                                 "mic[4]= 0x%.2x , mic[5]= 0x%.2x , mic[6]= 0x%.2x "
+                                 ", mic[7]= 0x%.2x !!!!\n", mic[0], mic[1],
+                                 mic[2], mic[3], mic[4], mic[5], mic[6],
+                                 mic[7]));
+                       /* add mic code  and add the mic code length
+                          in last_txcmdsz */
+
+                       memcpy(payload, &mic[0], 8);
+                       pattrib->last_txcmdsz += 8;
+
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                                ("\n ======== last pkt ========\n"));
+                       payload = payload - pattrib->last_txcmdsz + 8;
+                       for (curfragnum = 0; curfragnum < pattrib->last_txcmdsz;
+                            curfragnum = curfragnum + 8)
+                               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                                        (" %.2x,  %.2x,  %.2x,  %.2x,  %.2x, "
+                                         " %.2x,  %.2x,  %.2x ",
+                                         *(payload + curfragnum),
+                                         *(payload + curfragnum + 1),
+                                         *(payload + curfragnum + 2),
+                                         *(payload + curfragnum + 3),
+                                         *(payload + curfragnum + 4),
+                                         *(payload + curfragnum + 5),
+                                         *(payload + curfragnum + 6),
+                                         *(payload + curfragnum + 7)));
+                       } else {
+                               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                        ("xmitframe_addmic: rtw_get_stainfo23a =="
+                                         "NULL!!!\n"));
+               }
+       }
+
+       return _SUCCESS;
+}
+
+static s32 xmitframe_swencrypt(struct rtw_adapter *padapter,
+                              struct xmit_frame *pxmitframe)
+{
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+
+       /* if ((psecuritypriv->sw_encrypt)||(pattrib->bswenc)) */
+       if (pattrib->bswenc) {
+               /* DBG_8723A("start xmitframe_swencrypt\n"); */
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_alert_,
+                        ("### xmitframe_swencrypt\n"));
+               switch (pattrib->encrypt) {
+               case _WEP40_:
+               case _WEP104_:
+                       rtw_wep_encrypt23a(padapter, pxmitframe);
+                       break;
+               case _TKIP_:
+                       rtw_tkip_encrypt23a(padapter, pxmitframe);
+                       break;
+               case _AES_:
+                       rtw_aes_encrypt23a(padapter, pxmitframe);
+                       break;
+               default:
+                               break;
+               }
+
+       } else {
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_,
+                        ("### xmitframe_hwencrypt\n"));
+       }
+
+       return _SUCCESS;
+}
+
+s32 rtw_make_wlanhdr23a(struct rtw_adapter *padapter, u8 *hdr,
+                       struct pkt_attrib *pattrib)
+{
+       u16 *qc;
+
+       struct ieee80211_hdr *pwlanhdr = (struct ieee80211_hdr *)hdr;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct qos_priv *pqospriv = &pmlmepriv->qospriv;
+       u8 qos_option = false;
+       int res = _SUCCESS;
+       u16 *fctrl = &pwlanhdr->frame_control;
+
+       struct sta_info *psta;
+
+       int bmcst = is_multicast_ether_addr(pattrib->ra);
+
+       if (pattrib->psta) {
+               psta = pattrib->psta;
+       } else {
+               DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
+               if (bmcst) {
+                       psta = rtw_get_bcmc_stainfo23a(padapter);
+               } else {
+                       psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra);
+               }
+       }
+
+       if (psta == NULL) {
+               DBG_8723A("%s, psta == NUL\n", __func__);
+               return _FAIL;
+       }
+
+       if (!(psta->state &_FW_LINKED)) {
+               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state);
+               return _FAIL;
+       }
+
+       memset(hdr, 0, WLANHDR_OFFSET);
+
+       SetFrameSubType(fctrl, pattrib->subtype);
+
+       if (pattrib->subtype & WIFI_DATA_TYPE) {
+               if ((check_fwstate(pmlmepriv,  WIFI_STATION_STATE) == true)) {
+                       /* to_ds = 1, fr_ds = 0; */
+                       /* Data transfer to AP */
+                       SetToDs(fctrl);
+                       memcpy(pwlanhdr->addr1, get_bssid(pmlmepriv), ETH_ALEN);
+                       memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
+                       memcpy(pwlanhdr->addr3, pattrib->dst, ETH_ALEN);
+
+                       if (pqospriv->qos_option)
+                               qos_option = true;
+
+               }
+               else if ((check_fwstate(pmlmepriv,  WIFI_AP_STATE) == true)) {
+                       /* to_ds = 0, fr_ds = 1; */
+                       SetFrDs(fctrl);
+                       memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
+                       memcpy(pwlanhdr->addr2, get_bssid(pmlmepriv), ETH_ALEN);
+                       memcpy(pwlanhdr->addr3, pattrib->src, ETH_ALEN);
+
+                       if (psta->qos_option)
+                               qos_option = true;
+               }
+               else if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) == true) ||
+               (check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) == true)) {
+                       memcpy(pwlanhdr->addr1, pattrib->dst, ETH_ALEN);
+                       memcpy(pwlanhdr->addr2, pattrib->src, ETH_ALEN);
+                       memcpy(pwlanhdr->addr3, get_bssid(pmlmepriv), ETH_ALEN);
+
+                       if (psta->qos_option)
+                               qos_option = true;
+               }
+               else {
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("fw_state:%x is not allowed to xmit frame\n", get_fwstate(pmlmepriv)));
+                       res = _FAIL;
+                       goto exit;
+               }
+               if (pattrib->mdata)
+                       SetMData(fctrl);
+               if (pattrib->encrypt)
+                       SetPrivacy(fctrl);
+               if (qos_option) {
+                       qc = (unsigned short *)(hdr + pattrib->hdrlen - 2);
+                       if (pattrib->priority)
+                               SetPriority(qc, pattrib->priority);
+                       SetEOSP(qc, pattrib->eosp);
+                       SetAckpolicy(qc, pattrib->ack_policy);
+               }
+               /* TODO: fill HT Control Field */
+
+               /* Update Seq Num will be handled by f/w */
+               if (psta) {
+                       psta->sta_xmitpriv.txseq_tid[pattrib->priority]++;
+                       psta->sta_xmitpriv.txseq_tid[pattrib->priority] &= 0xFFF;
+                       pattrib->seqnum = psta->sta_xmitpriv.txseq_tid[pattrib->priority];
+                       SetSeqNum(hdr, pattrib->seqnum);
+                       /* check if enable ampdu */
+                       if (pattrib->ht_en && psta->htpriv.ampdu_enable) {
+                               if (psta->htpriv.agg_enable_bitmap & CHKBIT(pattrib->priority))
+                               pattrib->ampdu_en = true;
+                       }
+                       /* re-check if enable ampdu by BA_starting_seqctrl */
+                       if (pattrib->ampdu_en) {
+                               u16 tx_seq;
+
+                               tx_seq = psta->BA_starting_seqctrl[pattrib->priority & 0x0f];
+
+                               /* check BA_starting_seqctrl */
+                               if (SN_LESS(pattrib->seqnum, tx_seq)) {
+                                       /* DBG_8723A("tx ampdu seqnum(%d) < tx_seq(%d)\n", pattrib->seqnum, tx_seq); */
+                                       pattrib->ampdu_en = false;/* AGG BK */
+                               } else if (SN_EQUAL(pattrib->seqnum, tx_seq)) {
+                                       psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (tx_seq+1)&0xfff;
+                                       pattrib->ampdu_en = true;/* AGG EN */
+                               } else {
+                                       /* DBG_8723A("tx ampdu over run\n"); */
+                                       psta->BA_starting_seqctrl[pattrib->priority & 0x0f] = (pattrib->seqnum+1)&0xfff;
+                                       pattrib->ampdu_en = true;/* AGG EN */
+                               }
+                       }
+               }
+       }
+exit:
+       return res;
+}
+
+s32 rtw_txframes_pending23a(struct rtw_adapter *padapter)
+{
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+       return (!_rtw_queue_empty23a(&pxmitpriv->be_pending)) ||
+              (!_rtw_queue_empty23a(&pxmitpriv->bk_pending)) ||
+              (!_rtw_queue_empty23a(&pxmitpriv->vi_pending)) ||
+              (!_rtw_queue_empty23a(&pxmitpriv->vo_pending));
+}
+
+s32 rtw_txframes_sta_ac_pending23a(struct rtw_adapter *padapter,
+                               struct pkt_attrib *pattrib)
+{
+       struct sta_info *psta;
+       struct tx_servq *ptxservq;
+       int priority = pattrib->priority;
+
+       if (pattrib->psta) {
+               psta = pattrib->psta;
+       } else {
+               DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
+               psta = rtw_get_stainfo23a(&padapter->stapriv, &pattrib->ra[0]);
+       }
+       if (psta == NULL) {
+               DBG_8723A("%s, psta == NUL\n", __func__);
+               return 0;
+       }
+       if (!(psta->state &_FW_LINKED)) {
+               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__,
+                         psta->state);
+               return 0;
+       }
+       switch (priority) {
+       case 1:
+       case 2:
+               ptxservq = &psta->sta_xmitpriv.bk_q;
+               break;
+       case 4:
+       case 5:
+               ptxservq = &psta->sta_xmitpriv.vi_q;
+               break;
+       case 6:
+       case 7:
+               ptxservq = &psta->sta_xmitpriv.vo_q;
+               break;
+       case 0:
+       case 3:
+       default:
+               ptxservq = &psta->sta_xmitpriv.be_q;
+               break;
+       }
+       return ptxservq->qcnt;
+}
+
+/*
+ * Calculate wlan 802.11 packet MAX size from pkt_attrib
+ * This function doesn't consider fragment case
+ */
+u32 rtw_calculate_wlan_pkt_size_by_attribue23a(struct pkt_attrib *pattrib)
+{
+       u32     len = 0;
+
+       len = pattrib->hdrlen + pattrib->iv_len; /*  WLAN Header and IV */
+       len += SNAP_SIZE + sizeof(u16); /*  LLC */
+       len += pattrib->pktlen;
+       if (pattrib->encrypt == _TKIP_) len += 8; /*  MIC */
+       len += ((pattrib->bswenc) ? pattrib->icv_len : 0); /*  ICV */
+
+       return len;
+}
+
+/*
+
+This sub-routine will perform all the following:
+
+1. remove 802.3 header.
+2. create wlan_header, based on the info in pxmitframe
+3. append sta's iv/ext-iv
+4. append LLC
+5. move frag chunk from pframe to pxmitframe->mem
+6. apply sw-encrypt, if necessary.
+
+*/
+s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt,
+                             struct xmit_frame *pxmitframe)
+{
+       struct pkt_file pktfile;
+       struct sta_info         *psta;
+       struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
+       struct pkt_attrib       *pattrib = &pxmitframe->attrib;
+       s32 frg_inx, frg_len, mpdu_len, llc_sz, mem_sz;
+       u8 *pframe, *mem_start;
+       u8 hw_hdr_offset;
+       u8 *pbuf_start;
+
+       s32 bmcst = is_multicast_ether_addr(pattrib->ra);
+       s32 res = _SUCCESS;
+
+       if (pattrib->psta) {
+               psta = pattrib->psta;
+       } else {
+               DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
+               psta = rtw_get_stainfo23a(&padapter->stapriv, pattrib->ra);
+       }
+
+       if (psta == NULL) {
+               DBG_8723A("%s, psta == NUL\n", __func__);
+               return _FAIL;
+       }
+
+       if (!(psta->state &_FW_LINKED)) {
+               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__, psta->state);
+               return _FAIL;
+       }
+
+       if (pxmitframe->buf_addr == NULL) {
+               DBG_8723A("==> %s buf_addr == NULL\n", __func__);
+               return _FAIL;
+       }
+
+       pbuf_start = pxmitframe->buf_addr;
+
+       hw_hdr_offset = TXDESC_OFFSET;
+
+       mem_start = pbuf_start +        hw_hdr_offset;
+
+       if (rtw_make_wlanhdr23a(padapter, mem_start, pattrib) == _FAIL) {
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                        ("rtw_xmitframe_coalesce23a: rtw_make_wlanhdr23a "
+                         "fail; drop pkt\n"));
+               res = _FAIL;
+               goto exit;
+       }
+
+       _rtw_open_pktfile23a(pkt, &pktfile);
+       _rtw_pktfile_read23a(&pktfile, NULL, pattrib->pkt_hdrlen);
+
+       frg_inx = 0;
+       frg_len = pxmitpriv->frag_len - 4;/* 2346-4 = 2342 */
+
+       while (1) {
+               llc_sz = 0;
+
+               mpdu_len = frg_len;
+
+               pframe = mem_start;
+
+               SetMFrag(mem_start);
+
+               pframe += pattrib->hdrlen;
+               mpdu_len -= pattrib->hdrlen;
+
+               /* adding icv, if necessary... */
+               if (pattrib->iv_len) {
+                       if (psta != NULL) {
+                               switch (pattrib->encrypt) {
+                               case _WEP40_:
+                               case _WEP104_:
+                                       WEP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+                                       break;
+                               case _TKIP_:
+                                       if (bmcst)
+                                               TKIP_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+                                       else
+                                               TKIP_IV(pattrib->iv, psta->dot11txpn, 0);
+                                       break;
+                               case _AES_:
+                                       if (bmcst)
+                                               AES_IV(pattrib->iv, psta->dot11txpn, pattrib->key_idx);
+                                       else
+                                               AES_IV(pattrib->iv, psta->dot11txpn, 0);
+                                       break;
+                               }
+                       }
+
+                       memcpy(pframe, pattrib->iv, pattrib->iv_len);
+
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_notice_,
+                                ("rtw_xmiaframe_coalesce23a: keyid =%d pattrib"
+                                 "->iv[3]=%.2x pframe =%.2x %.2x %.2x %.2x\n",
+                                 padapter->securitypriv.dot11PrivacyKeyIndex,
+                                 pattrib->iv[3], *pframe, *(pframe+1),
+                                 *(pframe+2), *(pframe+3)));
+                       pframe += pattrib->iv_len;
+                       mpdu_len -= pattrib->iv_len;
+               }
+               if (frg_inx == 0) {
+                       llc_sz = rtw_put_snap23a(pframe, pattrib->ether_type);
+                       pframe += llc_sz;
+                       mpdu_len -= llc_sz;
+               }
+
+               if ((pattrib->icv_len >0) && (pattrib->bswenc))
+                       mpdu_len -= pattrib->icv_len;
+
+               if (bmcst) {
+                       /*  don't do fragment to broadcat/multicast packets */
+                       mem_sz = _rtw_pktfile_read23a(&pktfile, pframe, pattrib->pktlen);
+               } else {
+                       mem_sz = _rtw_pktfile_read23a(&pktfile, pframe, mpdu_len);
+               }
+               pframe += mem_sz;
+
+               if ((pattrib->icv_len >0) && (pattrib->bswenc)) {
+                       memcpy(pframe, pattrib->icv, pattrib->icv_len);
+                       pframe += pattrib->icv_len;
+               }
+
+               frg_inx++;
+
+               if (bmcst || (rtw_endofpktfile23a(&pktfile))) {
+                       pattrib->nr_frags = frg_inx;
+
+                       pattrib->last_txcmdsz = pattrib->hdrlen +
+                                               pattrib->iv_len +
+                                               ((pattrib->nr_frags == 1) ?
+                                               llc_sz : 0) +
+                                               ((pattrib->bswenc) ?
+                                               pattrib->icv_len : 0) + mem_sz;
+
+                       ClearMFrag(mem_start);
+
+                       break;
+               } else {
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("%s: There're still something in packet!\n", __func__));
+               }
+
+               mem_start = PTR_ALIGN(pframe, 4) + hw_hdr_offset;
+               memcpy(mem_start, pbuf_start + hw_hdr_offset, pattrib->hdrlen);
+
+       }
+
+       if (xmitframe_addmic(padapter, pxmitframe) == _FAIL) {
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n"));
+               DBG_8723A("xmitframe_addmic(padapter, pxmitframe) == _FAIL\n");
+               res = _FAIL;
+               goto exit;
+       }
+
+       xmitframe_swencrypt(padapter, pxmitframe);
+
+       if (bmcst == false)
+               update_attrib_vcs_info(padapter, pxmitframe);
+       else
+               pattrib->vcs_mode = NONE_VCS;
+
+exit:
+       return res;
+}
+
+/* Logical Link Control(LLC) SubNetwork Attachment Point(SNAP) header
+ * IEEE LLC/SNAP header contains 8 octets
+ * First 3 octets comprise the LLC portion
+ * SNAP portion, 5 octets, is divided into two fields:
+ *     Organizationally Unique Identifier(OUI), 3 octets,
+ *     type, defined by that organization, 2 octets.
+ */
+s32 rtw_put_snap23a(u8 *data, u16 h_proto)
+{
+       struct ieee80211_snap_hdr *snap;
+       u8 *oui;
+
+       snap = (struct ieee80211_snap_hdr *)data;
+       snap->dsap = 0xaa;
+       snap->ssap = 0xaa;
+       snap->ctrl = 0x03;
+
+       if (h_proto == 0x8137 || h_proto == 0x80f3)
+               oui = P802_1H_OUI;
+       else
+               oui = RFC1042_OUI;
+       snap->oui[0] = oui[0];
+       snap->oui[1] = oui[1];
+       snap->oui[2] = oui[2];
+       *(u16 *)(data + SNAP_SIZE) = htons(h_proto);
+       return SNAP_SIZE + sizeof(u16);
+}
+
+void rtw_update_protection23a(struct rtw_adapter *padapter, u8 *ie, uint ie_len)
+{
+       struct  xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct  registry_priv *pregistrypriv = &padapter->registrypriv;
+       uint    protection;
+       u8      *perp;
+       int      erp_len;
+
+       switch (pxmitpriv->vcs_setting) {
+       case DISABLE_VCS:
+               pxmitpriv->vcs = NONE_VCS;
+               break;
+       case ENABLE_VCS:
+               break;
+       case AUTO_VCS:
+       default:
+               perp = rtw_get_ie23a(ie, _ERPINFO_IE_, &erp_len, ie_len);
+               if (perp == NULL) {
+                       pxmitpriv->vcs = NONE_VCS;
+               } else {
+                       protection = (*(perp + 2)) & BIT(1);
+                       if (protection) {
+                               if (pregistrypriv->vcs_type == RTS_CTS)
+                                       pxmitpriv->vcs = RTS_CTS;
+                               else
+                                       pxmitpriv->vcs = CTS_TO_SELF;
+                       } else {
+                               pxmitpriv->vcs = NONE_VCS;
+                       }
+               }
+               break;
+       }
+}
+
+void rtw_count_tx_stats23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe, int sz)
+{
+       struct sta_info *psta = NULL;
+       struct stainfo_stats *pstats = NULL;
+       struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_priv        *pmlmepriv = &padapter->mlmepriv;
+
+       if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) {
+               pxmitpriv->tx_bytes += sz;
+               pmlmepriv->LinkDetectInfo.NumTxOkInPeriod++;
+
+               psta = pxmitframe->attrib.psta;
+               if (psta) {
+                       pstats = &psta->sta_stats;
+                       pstats->tx_pkts++;
+                       pstats->tx_bytes += sz;
+               }
+       }
+}
+
+struct xmit_buf *rtw_alloc_xmitbuf23a_ext(struct xmit_priv *pxmitpriv)
+{
+       unsigned long irqL;
+       struct xmit_buf *pxmitbuf =  NULL;
+       struct list_head *phead;
+       struct rtw_queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
+
+       spin_lock_irqsave(&pfree_queue->lock, irqL);
+
+       phead = get_list_head(pfree_queue);
+
+       if (!list_empty(phead)) {
+               pxmitbuf = list_first_entry(phead, struct xmit_buf, list);
+
+               list_del_init(&pxmitbuf->list);
+
+               pxmitpriv->free_xmit_extbuf_cnt--;
+               pxmitbuf->priv_data = NULL;
+               pxmitbuf->ext_tag = true;
+
+               if (pxmitbuf->sctx) {
+                       DBG_8723A("%s pxmitbuf->sctx is not NULL\n", __func__);
+                       rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
+               }
+       }
+
+       spin_unlock_irqrestore(&pfree_queue->lock, irqL);
+
+       return pxmitbuf;
+}
+
+s32 rtw_free_xmitbuf_ext23a(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+{
+       unsigned long irqL;
+       struct rtw_queue *pfree_queue = &pxmitpriv->free_xmit_extbuf_queue;
+
+       if (pxmitbuf == NULL)
+               return _FAIL;
+
+       spin_lock_irqsave(&pfree_queue->lock, irqL);
+
+       list_del_init(&pxmitbuf->list);
+
+       list_add_tail(&pxmitbuf->list, get_list_head(pfree_queue));
+       pxmitpriv->free_xmit_extbuf_cnt++;
+
+       spin_unlock_irqrestore(&pfree_queue->lock, irqL);
+
+       return _SUCCESS;
+}
+
+struct xmit_buf *rtw_alloc_xmitbuf23a(struct xmit_priv *pxmitpriv)
+{
+       unsigned long irqL;
+       struct xmit_buf *pxmitbuf =  NULL;
+       struct list_head *phead;
+       struct rtw_queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
+
+       /* DBG_8723A("+rtw_alloc_xmitbuf23a\n"); */
+
+       spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL);
+
+       phead = get_list_head(pfree_xmitbuf_queue);
+
+       if (!list_empty(phead)) {
+               pxmitbuf = list_first_entry(phead, struct xmit_buf, list);
+
+               list_del_init(&pxmitbuf->list);
+
+               pxmitpriv->free_xmitbuf_cnt--;
+               pxmitbuf->priv_data = NULL;
+               pxmitbuf->ext_tag = false;
+               pxmitbuf->flags = XMIT_VO_QUEUE;
+
+               if (pxmitbuf->sctx) {
+                       DBG_8723A("%s pxmitbuf->sctx is not NULL\n", __func__);
+                       rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_ALLOC);
+               }
+       }
+
+       spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL);
+
+       return pxmitbuf;
+}
+
+s32 rtw_free_xmitbuf23a(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+{
+       unsigned long irqL;
+       struct rtw_queue *pfree_xmitbuf_queue = &pxmitpriv->free_xmitbuf_queue;
+
+       /* DBG_8723A("+rtw_free_xmitbuf23a\n"); */
+
+       if (pxmitbuf == NULL)
+               return _FAIL;
+
+       if (pxmitbuf->sctx) {
+               DBG_8723A("%s pxmitbuf->sctx is not NULL\n", __func__);
+               rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_BUF_FREE);
+       }
+
+       if (pxmitbuf->ext_tag) {
+               rtw_free_xmitbuf_ext23a(pxmitpriv, pxmitbuf);
+       } else {
+               spin_lock_irqsave(&pfree_xmitbuf_queue->lock, irqL);
+
+               list_del_init(&pxmitbuf->list);
+
+               list_add_tail(&pxmitbuf->list,
+                             get_list_head(pfree_xmitbuf_queue));
+
+               pxmitpriv->free_xmitbuf_cnt++;
+               spin_unlock_irqrestore(&pfree_xmitbuf_queue->lock, irqL);
+       }
+
+       return _SUCCESS;
+}
+
+static void rtw_init_xmitframe(struct xmit_frame *pxframe)
+{
+       if (pxframe !=  NULL) {
+               /* default value setting */
+               pxframe->buf_addr = NULL;
+               pxframe->pxmitbuf = NULL;
+
+               memset(&pxframe->attrib, 0, sizeof(struct pkt_attrib));
+               /* pxframe->attrib.psta = NULL; */
+
+               pxframe->frame_tag = DATA_FRAMETAG;
+
+               pxframe->pkt = NULL;
+               pxframe->pkt_offset = 1;/* default use pkt_offset to fill tx desc */
+
+               pxframe->ack_report = 0;
+       }
+}
+
+/*
+Calling context:
+1. OS_TXENTRY
+2. RXENTRY (rx_thread or RX_ISR/RX_CallBack)
+
+If we turn on USE_RXTHREAD, then, no need for critical section.
+Otherwise, we must use _enter/_exit critical to protect free_xmit_queue...
+
+Must be very very cautious...
+
+*/
+struct xmit_frame *rtw_alloc_xmitframe23a(struct xmit_priv *pxmitpriv)/* _queue *pfree_xmit_queue) */
+{
+       /*
+               Please remember to use all the osdep_service api,
+               and lock/unlock or _enter/_exit critical to protect
+               pfree_xmit_queue
+       */
+
+       struct xmit_frame *pxframe = NULL;
+       struct list_head *plist, *phead;
+       struct rtw_queue *pfree_xmit_queue = &pxmitpriv->free_xmit_queue;
+
+       spin_lock_bh(&pfree_xmit_queue->lock);
+
+       if (_rtw_queue_empty23a(pfree_xmit_queue) == true) {
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a:%d\n", pxmitpriv->free_xmitframe_cnt));
+               pxframe =  NULL;
+       } else {
+               phead = get_list_head(pfree_xmit_queue);
+
+               plist = phead->next;
+
+               pxframe = container_of(plist, struct xmit_frame, list);
+
+               list_del_init(&pxframe->list);
+               pxmitpriv->free_xmitframe_cnt--;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt));
+       }
+
+       spin_unlock_bh(&pfree_xmit_queue->lock);
+
+       rtw_init_xmitframe(pxframe);
+
+       return pxframe;
+}
+
+struct xmit_frame *rtw_alloc_xmitframe23a_ext(struct xmit_priv *pxmitpriv)
+{
+       struct xmit_frame *pxframe = NULL;
+       struct list_head *plist, *phead;
+       struct rtw_queue *queue = &pxmitpriv->free_xframe_ext_queue;
+
+       spin_lock_bh(&queue->lock);
+
+       if (_rtw_queue_empty23a(queue) == true) {
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a_ext:%d\n", pxmitpriv->free_xframe_ext_cnt));
+               pxframe =  NULL;
+       } else {
+               phead = get_list_head(queue);
+               plist = phead->next;
+               pxframe = container_of(plist, struct xmit_frame, list);
+
+               list_del_init(&pxframe->list);
+               pxmitpriv->free_xframe_ext_cnt--;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_alloc_xmitframe23a_ext():free_xmitframe_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt));
+       }
+
+       spin_unlock_bh(&queue->lock);
+
+       rtw_init_xmitframe(pxframe);
+
+       return pxframe;
+}
+
+s32 rtw_free_xmitframe23a(struct xmit_priv *pxmitpriv, struct xmit_frame *pxmitframe)
+{
+       struct rtw_queue *queue = NULL;
+       struct rtw_adapter *padapter = pxmitpriv->adapter;
+       struct sk_buff *pndis_pkt = NULL;
+
+       if (pxmitframe == NULL) {
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, ("====== rtw_free_xmitframe23a():pxmitframe == NULL!!!!!!!!!!\n"));
+               goto exit;
+       }
+
+       if (pxmitframe->pkt) {
+               pndis_pkt = pxmitframe->pkt;
+               pxmitframe->pkt = NULL;
+       }
+
+       if (pxmitframe->ext_tag == 0)
+               queue = &pxmitpriv->free_xmit_queue;
+       else if (pxmitframe->ext_tag == 1)
+               queue = &pxmitpriv->free_xframe_ext_queue;
+
+       if (!queue)
+               goto check_pkt_complete;
+       spin_lock_bh(&queue->lock);
+
+       list_del_init(&pxmitframe->list);
+       list_add_tail(&pxmitframe->list, get_list_head(queue));
+       if (pxmitframe->ext_tag == 0) {
+               pxmitpriv->free_xmitframe_cnt++;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe23a():free_xmitframe_cnt =%d\n", pxmitpriv->free_xmitframe_cnt));
+       } else if (pxmitframe->ext_tag == 1) {
+               pxmitpriv->free_xframe_ext_cnt++;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_debug_, ("rtw_free_xmitframe23a():free_xframe_ext_cnt =%d\n", pxmitpriv->free_xframe_ext_cnt));
+       }
+
+       spin_unlock_bh(&queue->lock);
+
+check_pkt_complete:
+
+       if (pndis_pkt)
+               rtw_os_pkt_complete23a(padapter, pndis_pkt);
+
+exit:
+
+       return _SUCCESS;
+}
+
+void rtw_free_xmitframe_queue23a(struct xmit_priv *pxmitpriv,
+                                struct rtw_queue *pframequeue)
+{
+       struct list_head *plist, *phead, *ptmp;
+       struct  xmit_frame *pxmitframe;
+
+       spin_lock_bh(&pframequeue->lock);
+
+       phead = get_list_head(pframequeue);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               pxmitframe = container_of(plist, struct xmit_frame, list);
+
+               rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
+       }
+       spin_unlock_bh(&pframequeue->lock);
+
+}
+
+s32 rtw_xmitframe_enqueue23a(struct rtw_adapter *padapter,
+                            struct xmit_frame *pxmitframe)
+{
+       if (rtw_xmit23a_classifier(padapter, pxmitframe) == _FAIL) {
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                        ("rtw_xmitframe_enqueue23a: drop xmit pkt for "
+                         "classifier fail\n"));
+               return _FAIL;
+       }
+
+       return _SUCCESS;
+}
+
+static struct xmit_frame *
+dequeue_one_xmitframe(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit,
+                     struct tx_servq *ptxservq, struct rtw_queue *pframe_queue)
+{
+       struct list_head *phead;
+       struct xmit_frame *pxmitframe = NULL;
+
+       phead = get_list_head(pframe_queue);
+
+       if (!list_empty(phead)) {
+               pxmitframe = list_first_entry(phead, struct xmit_frame, list);
+               list_del_init(&pxmitframe->list);
+               ptxservq->qcnt--;
+       }
+       return pxmitframe;
+}
+
+struct xmit_frame *
+rtw_dequeue_xframe23a(struct xmit_priv *pxmitpriv, struct hw_xmit *phwxmit_i,
+                  int entry)
+{
+       struct list_head *sta_plist, *sta_phead, *ptmp;
+       struct hw_xmit *phwxmit;
+       struct tx_servq *ptxservq = NULL;
+       struct rtw_queue *pframe_queue = NULL;
+       struct xmit_frame *pxmitframe = NULL;
+       struct rtw_adapter *padapter = pxmitpriv->adapter;
+       struct registry_priv    *pregpriv = &padapter->registrypriv;
+       int i, inx[4];
+
+       inx[0] = 0;
+       inx[1] = 1;
+       inx[2] = 2;
+       inx[3] = 3;
+       if (pregpriv->wifi_spec == 1) {
+               int j;
+
+               for (j = 0; j < 4; j++)
+                       inx[j] = pxmitpriv->wmm_para_seq[j];
+       }
+
+       spin_lock_bh(&pxmitpriv->lock);
+
+       for (i = 0; i < entry; i++) {
+               phwxmit = phwxmit_i + inx[i];
+
+               sta_phead = get_list_head(phwxmit->sta_queue);
+
+               list_for_each_safe(sta_plist, ptmp, sta_phead) {
+                       ptxservq = container_of(sta_plist, struct tx_servq,
+                                               tx_pending);
+
+                       pframe_queue = &ptxservq->sta_pending;
+
+                       pxmitframe = dequeue_one_xmitframe(pxmitpriv, phwxmit, ptxservq, pframe_queue);
+
+                       if (pxmitframe) {
+                               phwxmit->accnt--;
+
+                               /* Remove sta node when there is no pending packets. */
+                               if (_rtw_queue_empty23a(pframe_queue)) /* must be done after get_next and before break */
+                                       list_del_init(&ptxservq->tx_pending);
+                               goto exit;
+                       }
+               }
+       }
+exit:
+       spin_unlock_bh(&pxmitpriv->lock);
+       return pxmitframe;
+}
+
+struct tx_servq *rtw_get_sta_pending23a(struct rtw_adapter *padapter, struct sta_info *psta, int up, u8 *ac)
+{
+       struct tx_servq *ptxservq = NULL;
+
+       switch (up) {
+       case 1:
+       case 2:
+               ptxservq = &psta->sta_xmitpriv.bk_q;
+               *(ac) = 3;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : BK\n"));
+               break;
+       case 4:
+       case 5:
+               ptxservq = &psta->sta_xmitpriv.vi_q;
+               *(ac) = 1;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : VI\n"));
+               break;
+       case 6:
+       case 7:
+               ptxservq = &psta->sta_xmitpriv.vo_q;
+               *(ac) = 0;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : VO\n"));
+               break;
+       case 0:
+       case 3:
+       default:
+               ptxservq = &psta->sta_xmitpriv.be_q;
+               *(ac) = 2;
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_get_sta_pending23a : BE\n"));
+               break;
+       }
+       return ptxservq;
+}
+
+/*
+ * Will enqueue pxmitframe to the proper queue,
+ * and indicate it to xx_pending list.....
+ */
+s32 rtw_xmit23a_classifier(struct rtw_adapter *padapter,
+                       struct xmit_frame *pxmitframe)
+{
+       struct sta_info *psta;
+       struct tx_servq *ptxservq;
+       struct pkt_attrib       *pattrib = &pxmitframe->attrib;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct hw_xmit  *phwxmits =  padapter->xmitpriv.hwxmits;
+       u8      ac_index;
+       int res = _SUCCESS;
+
+       if (pattrib->psta) {
+               psta = pattrib->psta;
+       } else {
+               DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
+               psta = rtw_get_stainfo23a(pstapriv, pattrib->ra);
+       }
+       if (psta == NULL) {
+               res = _FAIL;
+               DBG_8723A("rtw_xmit23a_classifier: psta == NULL\n");
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                        ("rtw_xmit23a_classifier: psta == NULL\n"));
+               goto exit;
+       }
+       if (!(psta->state & _FW_LINKED)) {
+               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__,
+                         psta->state);
+               return _FAIL;
+       }
+       ptxservq = rtw_get_sta_pending23a(padapter, psta, pattrib->priority,
+                                      (u8 *)(&ac_index));
+
+       if (list_empty(&ptxservq->tx_pending)) {
+               list_add_tail(&ptxservq->tx_pending,
+                             get_list_head(phwxmits[ac_index].sta_queue));
+       }
+
+       list_add_tail(&pxmitframe->list, get_list_head(&ptxservq->sta_pending));
+       ptxservq->qcnt++;
+       phwxmits[ac_index].accnt++;
+exit:
+       return res;
+}
+
+void rtw_alloc_hwxmits23a(struct rtw_adapter *padapter)
+{
+       struct hw_xmit *hwxmits;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       int size;
+
+       pxmitpriv->hwxmit_entry = HWXMIT_ENTRY;
+
+       size = sizeof(struct hw_xmit) * (pxmitpriv->hwxmit_entry + 1);
+       pxmitpriv->hwxmits = kzalloc(size, GFP_KERNEL);
+
+       hwxmits = pxmitpriv->hwxmits;
+
+       if (pxmitpriv->hwxmit_entry == 5) {
+               /* pxmitpriv->bmc_txqueue.head = 0; */
+               /* hwxmits[0] .phwtxqueue = &pxmitpriv->bmc_txqueue; */
+               hwxmits[0] .sta_queue = &pxmitpriv->bm_pending;
+
+               /* pxmitpriv->vo_txqueue.head = 0; */
+               /* hwxmits[1] .phwtxqueue = &pxmitpriv->vo_txqueue; */
+               hwxmits[1] .sta_queue = &pxmitpriv->vo_pending;
+
+               /* pxmitpriv->vi_txqueue.head = 0; */
+               /* hwxmits[2] .phwtxqueue = &pxmitpriv->vi_txqueue; */
+               hwxmits[2] .sta_queue = &pxmitpriv->vi_pending;
+
+               /* pxmitpriv->bk_txqueue.head = 0; */
+               /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */
+               hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
+
+               /* pxmitpriv->be_txqueue.head = 0; */
+               /* hwxmits[4] .phwtxqueue = &pxmitpriv->be_txqueue; */
+               hwxmits[4] .sta_queue = &pxmitpriv->be_pending;
+
+       } else if (pxmitpriv->hwxmit_entry == 4) {
+
+               /* pxmitpriv->vo_txqueue.head = 0; */
+               /* hwxmits[0] .phwtxqueue = &pxmitpriv->vo_txqueue; */
+               hwxmits[0] .sta_queue = &pxmitpriv->vo_pending;
+
+               /* pxmitpriv->vi_txqueue.head = 0; */
+               /* hwxmits[1] .phwtxqueue = &pxmitpriv->vi_txqueue; */
+               hwxmits[1] .sta_queue = &pxmitpriv->vi_pending;
+
+               /* pxmitpriv->be_txqueue.head = 0; */
+               /* hwxmits[2] .phwtxqueue = &pxmitpriv->be_txqueue; */
+               hwxmits[2] .sta_queue = &pxmitpriv->be_pending;
+
+               /* pxmitpriv->bk_txqueue.head = 0; */
+               /* hwxmits[3] .phwtxqueue = &pxmitpriv->bk_txqueue; */
+               hwxmits[3] .sta_queue = &pxmitpriv->bk_pending;
+       } else {
+
+       }
+}
+
+void rtw_free_hwxmits23a(struct rtw_adapter *padapter)
+{
+       struct hw_xmit *hwxmits;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+       hwxmits = pxmitpriv->hwxmits;
+       kfree(hwxmits);
+}
+
+void rtw_init_hwxmits23a(struct hw_xmit *phwxmit, int entry)
+{
+       int i;
+
+       for (i = 0; i < entry; i++, phwxmit++)
+               phwxmit->accnt = 0;
+}
+
+u32 rtw_get_ff_hwaddr23a(struct xmit_frame *pxmitframe)
+{
+       u32 addr;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+
+       switch (pattrib->qsel) {
+       case 0:
+       case 3:
+               addr = BE_QUEUE_INX;
+               break;
+       case 1:
+       case 2:
+               addr = BK_QUEUE_INX;
+               break;
+       case 4:
+       case 5:
+               addr = VI_QUEUE_INX;
+               break;
+       case 6:
+       case 7:
+               addr = VO_QUEUE_INX;
+               break;
+       case 0x10:
+               addr = BCN_QUEUE_INX;
+               break;
+       case 0x11:/* BC/MC in PS (HIQ) */
+               addr = HIGH_QUEUE_INX;
+               break;
+       case 0x12:
+       default:
+               addr = MGT_QUEUE_INX;
+               break;
+       }
+
+       return addr;
+}
+
+static void do_queue_select(struct rtw_adapter *padapter, struct pkt_attrib *pattrib)
+{
+       u8 qsel;
+
+       qsel = pattrib->priority;
+       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                ("### do_queue_select priority =%d , qsel = %d\n",
+                 pattrib->priority, qsel));
+
+       pattrib->qsel = qsel;
+}
+
+/*
+ * The main transmit(tx) entry
+ *
+ * Return
+ *     1       enqueue
+ *     0       success, hardware will handle this xmit frame(packet)
+ *     <0      fail
+ */
+int rtw_xmit23a(struct rtw_adapter *padapter, struct sk_buff *skb)
+{
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct xmit_frame *pxmitframe = NULL;
+       s32 res;
+
+       pxmitframe = rtw_alloc_xmitframe23a(pxmitpriv);
+
+       if (pxmitframe == NULL) {
+               RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
+                        ("rtw_xmit23a: no more pxmitframe\n"));
+               return -1;
+       }
+
+       res = update_attrib(padapter, skb, &pxmitframe->attrib);
+
+       if (res == _FAIL) {
+               RT_TRACE(_module_xmit_osdep_c_, _drv_err_, ("rtw_xmit23a: update attrib fail\n"));
+               rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
+               return -1;
+       }
+       pxmitframe->pkt = skb;
+
+       rtw_led_control(padapter, LED_CTL_TX);
+
+       do_queue_select(padapter, &pxmitframe->attrib);
+
+#ifdef CONFIG_8723AU_AP_MODE
+       spin_lock_bh(&pxmitpriv->lock);
+       if (xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe)) {
+               spin_unlock_bh(&pxmitpriv->lock);
+               return 1;
+       }
+       spin_unlock_bh(&pxmitpriv->lock);
+#endif
+
+       if (rtw_hal_xmit23a(padapter, pxmitframe) == false)
+               return 1;
+
+       return 0;
+}
+
+#if defined(CONFIG_8723AU_AP_MODE)
+
+int xmitframe_enqueue_for_sleeping_sta23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       int ret = false;
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       int bmcst = is_multicast_ether_addr(pattrib->ra);
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == false)
+           return ret;
+
+       if (pattrib->psta) {
+               psta = pattrib->psta;
+       } else {
+               DBG_8723A("%s, call rtw_get_stainfo23a()\n", __func__);
+               psta = rtw_get_stainfo23a(pstapriv, pattrib->ra);
+       }
+
+       if (psta == NULL) {
+               DBG_8723A("%s, psta == NUL\n", __func__);
+               return false;
+       }
+
+       if (!(psta->state & _FW_LINKED)) {
+               DBG_8723A("%s, psta->state(0x%x) != _FW_LINKED\n", __func__,
+                         psta->state);
+               return false;
+       }
+
+       if (pattrib->triggered == 1) {
+               if (bmcst)
+                       pattrib->qsel = 0x11;/* HIQ */
+               return ret;
+       }
+
+       if (bmcst) {
+               spin_lock_bh(&psta->sleep_q.lock);
+
+               if (pstapriv->sta_dz_bitmap) {
+                       /* if anyone sta is in ps mode */
+                       list_del_init(&pxmitframe->list);
+
+                       /* spin_lock_bh(&psta->sleep_q.lock); */
+
+                       list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q));
+
+                       psta->sleepq_len++;
+
+                       pstapriv->tim_bitmap |= BIT(0);/*  */
+                       pstapriv->sta_dz_bitmap |= BIT(0);
+
+                       /* DBG_8723A("enqueue, sq_len =%d, tim =%x\n", psta->sleepq_len, pstapriv->tim_bitmap); */
+
+                       update_beacon23a(padapter, _TIM_IE_, NULL, false);/* tx bc/mc packets after upate bcn */
+
+                       /* spin_unlock_bh(&psta->sleep_q.lock); */
+
+                       ret = true;
+
+               }
+
+               spin_unlock_bh(&psta->sleep_q.lock);
+
+               return ret;
+
+       }
+
+       spin_lock_bh(&psta->sleep_q.lock);
+
+       if (psta->state&WIFI_SLEEP_STATE) {
+               u8 wmmps_ac = 0;
+
+               if (pstapriv->sta_dz_bitmap & CHKBIT(psta->aid)) {
+                       list_del_init(&pxmitframe->list);
+
+                       /* spin_lock_bh(&psta->sleep_q.lock); */
+
+                       list_add_tail(&pxmitframe->list, get_list_head(&psta->sleep_q));
+
+                       psta->sleepq_len++;
+
+                       switch (pattrib->priority) {
+                       case 1:
+                       case 2:
+                               wmmps_ac = psta->uapsd_bk & BIT(0);
+                               break;
+                       case 4:
+                       case 5:
+                               wmmps_ac = psta->uapsd_vi & BIT(0);
+                               break;
+                       case 6:
+                       case 7:
+                               wmmps_ac = psta->uapsd_vo & BIT(0);
+                               break;
+                       case 0:
+                       case 3:
+                       default:
+                               wmmps_ac = psta->uapsd_be & BIT(0);
+                               break;
+                       }
+
+                       if (wmmps_ac)
+                               psta->sleepq_ac_len++;
+
+                       if (((psta->has_legacy_ac) && (!wmmps_ac)) ||
+                          ((!psta->has_legacy_ac) && (wmmps_ac))) {
+                               pstapriv->tim_bitmap |= CHKBIT(psta->aid);
+
+                               if (psta->sleepq_len == 1) {
+                                       /* upate BCN for TIM IE */
+                                       update_beacon23a(padapter, _TIM_IE_, NULL, false);
+                               }
+                       }
+
+                       /* spin_unlock_bh(&psta->sleep_q.lock); */
+
+                       /* if (psta->sleepq_len > (NR_XMITFRAME>>3)) */
+                       /*  */
+                       /*      wakeup_sta_to_xmit23a(padapter, psta); */
+                       /*  */
+
+                       ret = true;
+
+               }
+
+       }
+
+       spin_unlock_bh(&psta->sleep_q.lock);
+
+       return ret;
+}
+
+static void
+dequeue_xmitframes_to_sleeping_queue(struct rtw_adapter *padapter,
+                                    struct sta_info *psta,
+                                    struct rtw_queue *pframequeue)
+{
+       int ret;
+       struct list_head *plist, *phead, *ptmp;
+       u8      ac_index;
+       struct tx_servq *ptxservq;
+       struct pkt_attrib       *pattrib;
+       struct xmit_frame       *pxmitframe;
+       struct hw_xmit *phwxmits =  padapter->xmitpriv.hwxmits;
+
+       phead = get_list_head(pframequeue);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               pxmitframe = container_of(plist, struct xmit_frame, list);
+
+               ret = xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe);
+
+               if (ret == true) {
+                       pattrib = &pxmitframe->attrib;
+
+                       ptxservq = rtw_get_sta_pending23a(padapter, psta, pattrib->priority, (u8 *)(&ac_index));
+
+                       ptxservq->qcnt--;
+                       phwxmits[ac_index].accnt--;
+               } else {
+                       /* DBG_8723A("xmitframe_enqueue_for_sleeping_sta23a return false\n"); */
+               }
+       }
+}
+
+void stop_sta_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       struct sta_info *psta_bmc;
+       struct sta_xmit_priv *pstaxmitpriv;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+       pstaxmitpriv = &psta->sta_xmitpriv;
+
+       /* for BC/MC Frames */
+       psta_bmc = rtw_get_bcmc_stainfo23a(padapter);
+
+       spin_lock_bh(&pxmitpriv->lock);
+
+       psta->state |= WIFI_SLEEP_STATE;
+
+       pstapriv->sta_dz_bitmap |= CHKBIT(psta->aid);
+
+       dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vo_q.sta_pending);
+       list_del_init(&pstaxmitpriv->vo_q.tx_pending);
+
+       dequeue_xmitframes_to_sleeping_queue(padapter, psta, &pstaxmitpriv->vi_q.sta_pending);
+       list_del_init(&pstaxmitpriv->vi_q.tx_pending);
+
+       dequeue_xmitframes_to_sleeping_queue(padapter, psta,
+                                            &pstaxmitpriv->be_q.sta_pending);
+       list_del_init(&pstaxmitpriv->be_q.tx_pending);
+
+       dequeue_xmitframes_to_sleeping_queue(padapter, psta,
+                                            &pstaxmitpriv->bk_q.sta_pending);
+       list_del_init(&pstaxmitpriv->bk_q.tx_pending);
+
+       /* for BC/MC Frames */
+       pstaxmitpriv = &psta_bmc->sta_xmitpriv;
+       dequeue_xmitframes_to_sleeping_queue(padapter, psta_bmc,
+                                            &pstaxmitpriv->be_q.sta_pending);
+       list_del_init(&pstaxmitpriv->be_q.tx_pending);
+
+       spin_unlock_bh(&pxmitpriv->lock);
+}
+
+void wakeup_sta_to_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       u8 update_mask = 0, wmmps_ac = 0;
+       struct sta_info *psta_bmc;
+       struct list_head *plist, *phead, *ptmp;
+       struct xmit_frame *pxmitframe = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+       spin_lock_bh(&pxmitpriv->lock);
+
+       phead = get_list_head(&psta->sleep_q);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               pxmitframe = container_of(plist, struct xmit_frame, list);
+               list_del_init(&pxmitframe->list);
+
+               switch (pxmitframe->attrib.priority) {
+               case 1:
+               case 2:
+                       wmmps_ac = psta->uapsd_bk & BIT(1);
+                       break;
+               case 4:
+               case 5:
+                       wmmps_ac = psta->uapsd_vi & BIT(1);
+                       break;
+               case 6:
+               case 7:
+                       wmmps_ac = psta->uapsd_vo & BIT(1);
+                       break;
+               case 0:
+               case 3:
+               default:
+                       wmmps_ac = psta->uapsd_be & BIT(1);
+                       break;
+               }
+
+               psta->sleepq_len--;
+               if (psta->sleepq_len > 0)
+                       pxmitframe->attrib.mdata = 1;
+               else
+                       pxmitframe->attrib.mdata = 0;
+
+               if (wmmps_ac) {
+                       psta->sleepq_ac_len--;
+                       if (psta->sleepq_ac_len > 0) {
+                               pxmitframe->attrib.mdata = 1;
+                               pxmitframe->attrib.eosp = 0;
+                       } else {
+                               pxmitframe->attrib.mdata = 0;
+                               pxmitframe->attrib.eosp = 1;
+                       }
+               }
+
+               pxmitframe->attrib.triggered = 1;
+               rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe);
+       }
+
+       if (psta->sleepq_len == 0) {
+               pstapriv->tim_bitmap &= ~CHKBIT(psta->aid);
+
+               /* upate BCN for TIM IE */
+               update_mask = BIT(0);
+
+               if (psta->state&WIFI_SLEEP_STATE)
+                       psta->state ^= WIFI_SLEEP_STATE;
+
+               if (psta->state & WIFI_STA_ALIVE_CHK_STATE) {
+                       psta->expire_to = pstapriv->expire_to;
+                       psta->state ^= WIFI_STA_ALIVE_CHK_STATE;
+               }
+
+               pstapriv->sta_dz_bitmap &= ~CHKBIT(psta->aid);
+       }
+
+       /* spin_unlock_bh(&psta->sleep_q.lock); */
+       spin_unlock_bh(&pxmitpriv->lock);
+
+       /* for BC/MC Frames */
+       psta_bmc = rtw_get_bcmc_stainfo23a(padapter);
+       if (!psta_bmc)
+               return;
+
+       if ((pstapriv->sta_dz_bitmap&0xfffe) == 0x0) {
+               /* no any sta in ps mode */
+               spin_lock_bh(&pxmitpriv->lock);
+
+               phead = get_list_head(&psta_bmc->sleep_q);
+
+               list_for_each_safe(plist, ptmp, phead) {
+                       pxmitframe = container_of(plist, struct xmit_frame,
+                                                 list);
+
+                       list_del_init(&pxmitframe->list);
+
+                       psta_bmc->sleepq_len--;
+                       if (psta_bmc->sleepq_len > 0)
+                               pxmitframe->attrib.mdata = 1;
+                       else
+                               pxmitframe->attrib.mdata = 0;
+
+                       pxmitframe->attrib.triggered = 1;
+                       rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe);
+               }
+               if (psta_bmc->sleepq_len == 0) {
+                       pstapriv->tim_bitmap &= ~BIT(0);
+                       pstapriv->sta_dz_bitmap &= ~BIT(0);
+
+                       /* upate BCN for TIM IE */
+                       /* update_BCNTIM(padapter); */
+                       update_mask |= BIT(1);
+               }
+
+               /* spin_unlock_bh(&psta_bmc->sleep_q.lock); */
+               spin_unlock_bh(&pxmitpriv->lock);
+       }
+
+       if (update_mask)
+               update_beacon23a(padapter, _TIM_IE_, NULL, false);
+}
+
+void xmit_delivery_enabled_frames23a(struct rtw_adapter *padapter,
+                                 struct sta_info *psta)
+{
+       u8 wmmps_ac = 0;
+       struct list_head *plist, *phead, *ptmp;
+       struct xmit_frame *pxmitframe;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+       /* spin_lock_bh(&psta->sleep_q.lock); */
+       spin_lock_bh(&pxmitpriv->lock);
+
+       phead = get_list_head(&psta->sleep_q);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               pxmitframe = container_of(plist, struct xmit_frame, list);
+
+               switch (pxmitframe->attrib.priority) {
+               case 1:
+               case 2:
+                       wmmps_ac = psta->uapsd_bk & BIT(1);
+                       break;
+               case 4:
+               case 5:
+                       wmmps_ac = psta->uapsd_vi & BIT(1);
+                       break;
+               case 6:
+               case 7:
+                       wmmps_ac = psta->uapsd_vo & BIT(1);
+                       break;
+               case 0:
+               case 3:
+               default:
+                       wmmps_ac = psta->uapsd_be & BIT(1);
+                       break;
+               }
+
+               if (!wmmps_ac)
+                       continue;
+
+               list_del_init(&pxmitframe->list);
+
+               psta->sleepq_len--;
+               psta->sleepq_ac_len--;
+
+               if (psta->sleepq_ac_len > 0) {
+                       pxmitframe->attrib.mdata = 1;
+                       pxmitframe->attrib.eosp = 0;
+               } else {
+                       pxmitframe->attrib.mdata = 0;
+                       pxmitframe->attrib.eosp = 1;
+               }
+
+               pxmitframe->attrib.triggered = 1;
+
+               rtw_hal_xmit23aframe_enqueue(padapter, pxmitframe);
+
+               if ((psta->sleepq_ac_len == 0) && (!psta->has_legacy_ac) &&
+                   (wmmps_ac)) {
+                       pstapriv->tim_bitmap &= ~CHKBIT(psta->aid);
+
+                       /* upate BCN for TIM IE */
+                       update_beacon23a(padapter, _TIM_IE_, NULL, false);
+               }
+       }
+       spin_unlock_bh(&pxmitpriv->lock);
+}
+
+#endif
+
+void rtw_sctx_init23a(struct submit_ctx *sctx, int timeout_ms)
+{
+       sctx->timeout_ms = timeout_ms;
+       init_completion(&sctx->done);
+       sctx->status = RTW_SCTX_SUBMITTED;
+}
+
+int rtw_sctx_wait23a(struct submit_ctx *sctx)
+{
+       int ret = _FAIL;
+       unsigned long expire;
+       int status = 0;
+
+       expire = sctx->timeout_ms ? msecs_to_jiffies(sctx->timeout_ms) :
+                MAX_SCHEDULE_TIMEOUT;
+       if (!wait_for_completion_timeout(&sctx->done, expire)) {
+               /* timeout, do something?? */
+               status = RTW_SCTX_DONE_TIMEOUT;
+               DBG_8723A("%s timeout\n", __func__);
+       } else {
+               status = sctx->status;
+       }
+
+       if (status == RTW_SCTX_DONE_SUCCESS)
+               ret = _SUCCESS;
+
+       return ret;
+}
+
+static bool rtw_sctx_chk_waring_status(int status)
+{
+       switch (status) {
+       case RTW_SCTX_DONE_UNKNOWN:
+       case RTW_SCTX_DONE_BUF_ALLOC:
+       case RTW_SCTX_DONE_BUF_FREE:
+       case RTW_SCTX_DONE_DRV_STOP:
+       case RTW_SCTX_DONE_DEV_REMOVE:
+               return true;
+       default:
+               return false;
+       }
+}
+
+void rtw23a_sctx_done_err(struct submit_ctx **sctx, int status)
+{
+       if (*sctx) {
+               if (rtw_sctx_chk_waring_status(status))
+                       DBG_8723A("%s status:%d\n", __func__, status);
+               (*sctx)->status = status;
+               complete(&(*sctx)->done);
+               *sctx = NULL;
+       }
+}
+
+void rtw_sctx_done23a(struct submit_ctx **sctx)
+{
+       rtw23a_sctx_done_err(sctx, RTW_SCTX_DONE_SUCCESS);
+}
+
+int rtw_ack_tx_wait23a(struct xmit_priv *pxmitpriv, u32 timeout_ms)
+{
+       struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
+
+       pack_tx_ops->timeout_ms = timeout_ms;
+       pack_tx_ops->status = RTW_SCTX_SUBMITTED;
+
+       return rtw_sctx_wait23a(pack_tx_ops);
+}
+
+void rtw_ack_tx_done23a(struct xmit_priv *pxmitpriv, int status)
+{
+       struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
+
+       if (pxmitpriv->ack_tx)
+               rtw23a_sctx_done_err(&pack_tx_ops, status);
+       else
+               DBG_8723A("%s ack_tx not set\n", __func__);
+}
diff --git a/drivers/staging/rtl8723au/hal/Hal8723PwrSeq.c b/drivers/staging/rtl8723au/hal/Hal8723PwrSeq.c
new file mode 100644 (file)
index 0000000..747f86c
--- /dev/null
@@ -0,0 +1,80 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 "Hal8723PwrSeq.h"
+
+/*
+    drivers should parse below arrays and do the corresponding actions
+*/
+/* 3 Power on  Array */
+struct wlan_pwr_cfg rtl8723AU_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS] = {
+       RTL8723A_TRANS_CARDEMU_TO_ACT
+       RTL8723A_TRANS_END
+};
+
+/* 3 Radio off GPIO Array */
+struct wlan_pwr_cfg rtl8723AU_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_END_STEPS] = {
+       RTL8723A_TRANS_ACT_TO_CARDEMU
+       RTL8723A_TRANS_END
+};
+
+/* 3 Card Disable Array */
+struct wlan_pwr_cfg rtl8723AU_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS] = {
+       RTL8723A_TRANS_ACT_TO_CARDEMU
+       RTL8723A_TRANS_CARDEMU_TO_CARDDIS
+       RTL8723A_TRANS_END
+};
+
+/* 3 Card Enable Array */
+struct wlan_pwr_cfg rtl8723AU_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS] = {
+       RTL8723A_TRANS_CARDDIS_TO_CARDEMU
+       RTL8723A_TRANS_CARDEMU_TO_ACT
+       RTL8723A_TRANS_END
+};
+
+/* 3 Suspend Array */
+struct wlan_pwr_cfg rtl8723AU_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS] = {
+       RTL8723A_TRANS_ACT_TO_CARDEMU
+       RTL8723A_TRANS_CARDEMU_TO_SUS
+       RTL8723A_TRANS_END
+};
+
+/* 3 Resume Array */
+struct wlan_pwr_cfg rtl8723AU_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS] = {
+       RTL8723A_TRANS_SUS_TO_CARDEMU
+       RTL8723A_TRANS_CARDEMU_TO_ACT
+       RTL8723A_TRANS_END
+};
+
+/* 3 HWPDN Array */
+struct wlan_pwr_cfg rtl8723AU_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS] = {
+       RTL8723A_TRANS_ACT_TO_CARDEMU
+       RTL8723A_TRANS_CARDEMU_TO_PDN
+       RTL8723A_TRANS_END
+};
+
+/* 3 Enter LPS */
+struct wlan_pwr_cfg rtl8723AU_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STEPS+RTL8723A_TRANS_END_STEPS] = {
+       /* FW behavior */
+       RTL8723A_TRANS_ACT_TO_LPS
+       RTL8723A_TRANS_END
+};
+
+/* 3 Leave LPS */
+struct wlan_pwr_cfg rtl8723AU_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS] = {
+       /* FW behavior */
+       RTL8723A_TRANS_LPS_TO_ACT
+       RTL8723A_TRANS_END
+};
diff --git a/drivers/staging/rtl8723au/hal/Hal8723UHWImg_CE.c b/drivers/staging/rtl8723au/hal/Hal8723UHWImg_CE.c
new file mode 100644 (file)
index 0000000..56833da
--- /dev/null
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+/*Created on  2013/01/14, 15:51*/
+#include "odm_precomp.h"
+
+u32 Rtl8723UPHY_REG_Array_PG[Rtl8723UPHY_REG_Array_PGLength] = {
+       0xe00, 0xffffffff, 0x0a0c0c0c,
+       0xe04, 0xffffffff, 0x02040608,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x0a0c0d0e,
+       0xe14, 0xffffffff, 0x02040608,
+       0xe18, 0xffffffff, 0x0a0c0d0e,
+       0xe1c, 0xffffffff, 0x02040608,
+       0x830, 0xffffffff, 0x0a0c0c0c,
+       0x834, 0xffffffff, 0x02040608,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x0a0c0d0e,
+       0x848, 0xffffffff, 0x02040608,
+       0x84c, 0xffffffff, 0x0a0c0d0e,
+       0x868, 0xffffffff, 0x02040608,
+       0xe00, 0xffffffff, 0x00000000,
+       0xe04, 0xffffffff, 0x00000000,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x00000000,
+       0x834, 0xffffffff, 0x00000000,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x04040404,
+       0xe04, 0xffffffff, 0x00020204,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x06060606,
+       0xe14, 0xffffffff, 0x00020406,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x04040404,
+       0x834, 0xffffffff, 0x00020204,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x06060606,
+       0x848, 0xffffffff, 0x00020406,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x00000000,
+       0xe04, 0xffffffff, 0x00000000,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x00000000,
+       0x834, 0xffffffff, 0x00000000,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x00000000,
+       0xe04, 0xffffffff, 0x00000000,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x00000000,
+       0x834, 0xffffffff, 0x00000000,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x04040404,
+       0xe04, 0xffffffff, 0x00020204,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x04040404,
+       0x834, 0xffffffff, 0x00020204,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x00000000,
+       0xe04, 0xffffffff, 0x00000000,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x00000000,
+       0x834, 0xffffffff, 0x00000000,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       };
+
+u32 Rtl8723UMACPHY_Array_PG[Rtl8723UMACPHY_Array_PGLength] = {
+       0x0,
+};
diff --git a/drivers/staging/rtl8723au/hal/HalDMOutSrc8723A_CE.c b/drivers/staging/rtl8723au/hal/HalDMOutSrc8723A_CE.c
new file mode 100644 (file)
index 0000000..9796f2e
--- /dev/null
@@ -0,0 +1,1063 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+/*  Description: */
+/*  This file is for 92CE/92CU dynamic mechanism only */
+
+/*  include files */
+
+#include "odm_precomp.h"
+
+#define                DPK_DELTA_MAPPING_NUM   13
+#define                index_mapping_HP_NUM    15
+/* 091212 chiyokolin */
+static void
+odm_TXPowerTrackingCallback_ThermalMeter_92C(
+       struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+       u8 ThermalValue = 0, delta, delta_LCK, delta_IQK, delta_HP;
+       int ele_A, ele_D, TempCCk, X, value32;
+       int Y, ele_C;
+       s8 OFDM_index[2], CCK_index = 0, OFDM_index_old[2] = {0};
+       s8 CCK_index_old = 0;
+       int i = 0;
+       bool is2T = IS_92C_SERIAL(pHalData->VersionID);
+       u8 OFDM_min_index = 6, rf; /* OFDM BB Swing should be less than +3.0dB*/
+       u8 ThermalValue_HP_count = 0;
+       u32 ThermalValue_HP = 0;
+       s32 index_mapping_HP[index_mapping_HP_NUM] = {
+               0, 1, 3, 4, 6,
+               7, 9, 10, 12, 13,
+               15, 16, 18, 19, 21
+       };
+       s8 index_HP;
+
+       pdmpriv->TXPowerTrackingCallbackCnt++;  /* cosa add for debug */
+       pdmpriv->bTXPowerTrackingInit = true;
+
+       if (pHalData->CurrentChannel == 14 && !pdmpriv->bCCKinCH14)
+               pdmpriv->bCCKinCH14 = true;
+       else if (pHalData->CurrentChannel != 14 && pdmpriv->bCCKinCH14)
+               pdmpriv->bCCKinCH14 = false;
+
+       ThermalValue = (u8)PHY_QueryRFReg(Adapter, RF_PATH_A, RF_T_METER,
+                                         0x1f);/*  0x24: RF Reg[4:0]    */
+
+       rtl8723a_phy_ap_calibrate(Adapter, (ThermalValue -
+                                 pHalData->EEPROMThermalMeter));
+
+       if (is2T)
+               rf = 2;
+       else
+               rf = 1;
+
+       if (ThermalValue) {
+               /* Query OFDM path A default setting     */
+               ele_D = PHY_QueryBBReg(Adapter, rOFDM0_XATxIQImbalance,
+                                      bMaskDWord)&bMaskOFDM_D;
+               for (i = 0; i < OFDM_TABLE_SIZE_92C; i++) {
+                       /* find the index */
+                       if (ele_D == (OFDMSwingTable23A[i]&bMaskOFDM_D)) {
+                               OFDM_index_old[0] = (u8)i;
+                               break;
+                       }
+               }
+
+               /* Query OFDM path B default setting  */
+               if (is2T) {
+                       ele_D = PHY_QueryBBReg(Adapter, rOFDM0_XBTxIQImbalance,
+                                              bMaskDWord)&bMaskOFDM_D;
+                       for (i = 0; i < OFDM_TABLE_SIZE_92C; i++) {     /* find the index  */
+                               if (ele_D == (OFDMSwingTable23A[i]&bMaskOFDM_D)) {
+                                       OFDM_index_old[1] = (u8)i;
+                                       break;
+                               }
+                       }
+               }
+
+               /* Query CCK default setting From 0xa24 */
+               TempCCk = PHY_QueryBBReg(Adapter, rCCK0_TxFilter2,
+                                        bMaskDWord)&bMaskCCK;
+               for (i = 0 ; i < CCK_TABLE_SIZE ; i++) {
+                       if (pdmpriv->bCCKinCH14) {
+                               if (!memcmp(&TempCCk,
+                                           &CCKSwingTable_Ch1423A[i][2], 4)) {
+                                       CCK_index_old = (u8)i;
+                                       break;
+                               }
+                       } else {
+                               if (!memcmp(&TempCCk,
+                                           &CCKSwingTable_Ch1_Ch1323A[i][2], 4)) {
+                                       CCK_index_old = (u8)i;
+                                       break;
+                               }
+                       }
+               }
+
+               if (!pdmpriv->ThermalValue) {
+                       pdmpriv->ThermalValue = pHalData->EEPROMThermalMeter;
+                       pdmpriv->ThermalValue_LCK = ThermalValue;
+                       pdmpriv->ThermalValue_IQK = ThermalValue;
+                       pdmpriv->ThermalValue_DPK = pHalData->EEPROMThermalMeter;
+
+                       for (i = 0; i < rf; i++) {
+                               pdmpriv->OFDM_index_HP[i] = OFDM_index_old[i];
+                               pdmpriv->OFDM_index[i] = OFDM_index_old[i];
+                       }
+                       pdmpriv->CCK_index_HP = CCK_index_old;
+                       pdmpriv->CCK_index = CCK_index_old;
+               }
+
+               if (pHalData->BoardType == BOARD_USB_High_PA) {
+                       pdmpriv->ThermalValue_HP[pdmpriv->ThermalValue_HP_index] = ThermalValue;
+                       pdmpriv->ThermalValue_HP_index++;
+                       if (pdmpriv->ThermalValue_HP_index == HP_THERMAL_NUM)
+                               pdmpriv->ThermalValue_HP_index = 0;
+
+                       for (i = 0; i < HP_THERMAL_NUM; i++) {
+                               if (pdmpriv->ThermalValue_HP[i]) {
+                                       ThermalValue_HP += pdmpriv->ThermalValue_HP[i];
+                                       ThermalValue_HP_count++;
+                               }
+                       }
+
+                       if (ThermalValue_HP_count)
+                               ThermalValue = (u8)(ThermalValue_HP / ThermalValue_HP_count);
+               }
+
+               delta = (ThermalValue > pdmpriv->ThermalValue) ?
+                       (ThermalValue - pdmpriv->ThermalValue) :
+                       (pdmpriv->ThermalValue - ThermalValue);
+               if (pHalData->BoardType == BOARD_USB_High_PA) {
+                       if (pdmpriv->bDoneTxpower)
+                               delta_HP = (ThermalValue > pdmpriv->ThermalValue) ?
+                                          (ThermalValue - pdmpriv->ThermalValue) :
+                                          (pdmpriv->ThermalValue - ThermalValue);
+                       else
+                               delta_HP = ThermalValue > pHalData->EEPROMThermalMeter ?
+                                          (ThermalValue - pHalData->EEPROMThermalMeter) :
+                                          (pHalData->EEPROMThermalMeter - ThermalValue);
+               } else {
+                       delta_HP = 0;
+               }
+               delta_LCK = (ThermalValue > pdmpriv->ThermalValue_LCK) ?
+                           (ThermalValue - pdmpriv->ThermalValue_LCK) :
+                           (pdmpriv->ThermalValue_LCK - ThermalValue);
+               delta_IQK = (ThermalValue > pdmpriv->ThermalValue_IQK) ?
+                           (ThermalValue - pdmpriv->ThermalValue_IQK) :
+                           (pdmpriv->ThermalValue_IQK - ThermalValue);
+
+               if (delta_LCK > 1) {
+                       pdmpriv->ThermalValue_LCK = ThermalValue;
+                       rtl8723a_phy_lc_calibrate(Adapter);
+               }
+
+               if ((delta > 0 || delta_HP > 0) && pdmpriv->TxPowerTrackControl) {
+                       if (pHalData->BoardType == BOARD_USB_High_PA) {
+                               pdmpriv->bDoneTxpower = true;
+                               delta_HP = ThermalValue > pHalData->EEPROMThermalMeter ?
+                                          (ThermalValue - pHalData->EEPROMThermalMeter) :
+                                          (pHalData->EEPROMThermalMeter - ThermalValue);
+
+                               if (delta_HP > index_mapping_HP_NUM-1)
+                                       index_HP = index_mapping_HP[index_mapping_HP_NUM-1];
+                               else
+                                       index_HP = index_mapping_HP[delta_HP];
+
+                               if (ThermalValue > pHalData->EEPROMThermalMeter) {
+                                       /* set larger Tx power */
+                                       for (i = 0; i < rf; i++)
+                                               OFDM_index[i] = pdmpriv->OFDM_index_HP[i] - index_HP;
+                                       CCK_index = pdmpriv->CCK_index_HP - index_HP;
+                               } else {
+                                       for (i = 0; i < rf; i++)
+                                               OFDM_index[i] = pdmpriv->OFDM_index_HP[i] + index_HP;
+                                       CCK_index = pdmpriv->CCK_index_HP + index_HP;
+                               }
+
+                               delta_HP = (ThermalValue > pdmpriv->ThermalValue) ?
+                                          (ThermalValue - pdmpriv->ThermalValue) :
+                                          (pdmpriv->ThermalValue - ThermalValue);
+                       } else {
+                               if (ThermalValue > pdmpriv->ThermalValue) {
+                                       for (i = 0; i < rf; i++)
+                                               pdmpriv->OFDM_index[i] -= delta;
+                                       pdmpriv->CCK_index -= delta;
+                               } else {
+                                       for (i = 0; i < rf; i++)
+                                               pdmpriv->OFDM_index[i] += delta;
+                                       pdmpriv->CCK_index += delta;
+                               }
+                       }
+
+                       /* no adjust */
+                       if (pHalData->BoardType != BOARD_USB_High_PA) {
+                               if (ThermalValue > pHalData->EEPROMThermalMeter) {
+                                       for (i = 0; i < rf; i++)
+                                               OFDM_index[i] = pdmpriv->OFDM_index[i]+1;
+                                       CCK_index = pdmpriv->CCK_index+1;
+                               } else {
+                                       for (i = 0; i < rf; i++)
+                                               OFDM_index[i] = pdmpriv->OFDM_index[i];
+                                       CCK_index = pdmpriv->CCK_index;
+                               }
+                       }
+                       for (i = 0; i < rf; i++) {
+                               if (OFDM_index[i] > (OFDM_TABLE_SIZE_92C-1))
+                                       OFDM_index[i] = (OFDM_TABLE_SIZE_92C-1);
+                               else if (OFDM_index[i] < OFDM_min_index)
+                                       OFDM_index[i] = OFDM_min_index;
+                       }
+
+                       if (CCK_index > (CCK_TABLE_SIZE-1))
+                               CCK_index = (CCK_TABLE_SIZE-1);
+                       else if (CCK_index < 0)
+                               CCK_index = 0;
+               }
+
+               if (pdmpriv->TxPowerTrackControl && (delta != 0 || delta_HP != 0)) {
+                       /* Adujst OFDM Ant_A according to IQK result */
+                       ele_D = (OFDMSwingTable23A[OFDM_index[0]] & 0xFFC00000)>>22;
+                       X = pdmpriv->RegE94;
+                       Y = pdmpriv->RegE9C;
+
+                       if (X != 0) {
+                               if ((X & 0x00000200) != 0)
+                                       X = X | 0xFFFFFC00;
+                               ele_A = ((X * ele_D)>>8)&0x000003FF;
+
+                               /* new element C = element D x Y */
+                               if ((Y & 0x00000200) != 0)
+                                       Y = Y | 0xFFFFFC00;
+                               ele_C = ((Y * ele_D)>>8)&0x000003FF;
+
+                               /* write new elements A, C, D to regC80 and regC94, element B is always 0 */
+                               value32 = (ele_D<<22)|((ele_C&0x3F)<<16)|ele_A;
+                               PHY_SetBBReg(Adapter, rOFDM0_XATxIQImbalance, bMaskDWord, value32);
+
+                               value32 = (ele_C&0x000003C0)>>6;
+                               PHY_SetBBReg(Adapter, rOFDM0_XCTxAFE, bMaskH4Bits, value32);
+
+                               value32 = ((X * ele_D)>>7)&0x01;
+                               PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT31, value32);
+
+                               value32 = ((Y * ele_D)>>7)&0x01;
+                               PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT29, value32);
+                       } else {
+                               PHY_SetBBReg(Adapter, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable23A[OFDM_index[0]]);
+                               PHY_SetBBReg(Adapter, rOFDM0_XCTxAFE, bMaskH4Bits, 0x00);
+                               PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT31|BIT29, 0x00);
+                       }
+
+                       /* Adjust CCK according to IQK result */
+                       if (!pdmpriv->bCCKinCH14) {
+                               rtw_write8(Adapter, 0xa22, CCKSwingTable_Ch1_Ch1323A[CCK_index][0]);
+                               rtw_write8(Adapter, 0xa23, CCKSwingTable_Ch1_Ch1323A[CCK_index][1]);
+                               rtw_write8(Adapter, 0xa24, CCKSwingTable_Ch1_Ch1323A[CCK_index][2]);
+                               rtw_write8(Adapter, 0xa25, CCKSwingTable_Ch1_Ch1323A[CCK_index][3]);
+                               rtw_write8(Adapter, 0xa26, CCKSwingTable_Ch1_Ch1323A[CCK_index][4]);
+                               rtw_write8(Adapter, 0xa27, CCKSwingTable_Ch1_Ch1323A[CCK_index][5]);
+                               rtw_write8(Adapter, 0xa28, CCKSwingTable_Ch1_Ch1323A[CCK_index][6]);
+                               rtw_write8(Adapter, 0xa29, CCKSwingTable_Ch1_Ch1323A[CCK_index][7]);
+                       } else {
+                               rtw_write8(Adapter, 0xa22, CCKSwingTable_Ch1423A[CCK_index][0]);
+                               rtw_write8(Adapter, 0xa23, CCKSwingTable_Ch1423A[CCK_index][1]);
+                               rtw_write8(Adapter, 0xa24, CCKSwingTable_Ch1423A[CCK_index][2]);
+                               rtw_write8(Adapter, 0xa25, CCKSwingTable_Ch1423A[CCK_index][3]);
+                               rtw_write8(Adapter, 0xa26, CCKSwingTable_Ch1423A[CCK_index][4]);
+                               rtw_write8(Adapter, 0xa27, CCKSwingTable_Ch1423A[CCK_index][5]);
+                               rtw_write8(Adapter, 0xa28, CCKSwingTable_Ch1423A[CCK_index][6]);
+                               rtw_write8(Adapter, 0xa29, CCKSwingTable_Ch1423A[CCK_index][7]);
+                       }
+
+                       if (is2T) {
+                               ele_D = (OFDMSwingTable23A[(u8)OFDM_index[1]] & 0xFFC00000)>>22;
+
+                               /* new element A = element D x X */
+                               X = pdmpriv->RegEB4;
+                               Y = pdmpriv->RegEBC;
+
+                               if (X != 0) {
+                                       if ((X & 0x00000200) != 0)      /* consider minus */
+                                               X = X | 0xFFFFFC00;
+                                       ele_A = ((X * ele_D)>>8)&0x000003FF;
+
+                                       /* new element C = element D x Y */
+                                       if ((Y & 0x00000200) != 0)
+                                               Y = Y | 0xFFFFFC00;
+                                       ele_C = ((Y * ele_D)>>8)&0x00003FF;
+
+                                       /* write new elements A, C, D to regC88 and regC9C, element B is always 0 */
+                                       value32 = (ele_D<<22)|((ele_C&0x3F)<<16) | ele_A;
+                                       PHY_SetBBReg(Adapter, rOFDM0_XBTxIQImbalance, bMaskDWord, value32);
+
+                                       value32 = (ele_C&0x000003C0)>>6;
+                                       PHY_SetBBReg(Adapter, rOFDM0_XDTxAFE, bMaskH4Bits, value32);
+
+                                       value32 = ((X * ele_D)>>7)&0x01;
+                                       PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT27, value32);
+
+                                       value32 = ((Y * ele_D)>>7)&0x01;
+                                       PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT25, value32);
+                               } else {
+                                       PHY_SetBBReg(Adapter, rOFDM0_XBTxIQImbalance, bMaskDWord, OFDMSwingTable23A[OFDM_index[1]]);
+                                       PHY_SetBBReg(Adapter, rOFDM0_XDTxAFE, bMaskH4Bits, 0x00);
+                                       PHY_SetBBReg(Adapter, rOFDM0_ECCAThreshold, BIT27|BIT25, 0x00);
+                               }
+                       }
+
+               }
+               if (delta_IQK > 3) {
+                       pdmpriv->ThermalValue_IQK = ThermalValue;
+                       rtl8723a_phy_iq_calibrate(Adapter, false);
+               }
+
+               /* update thermal meter value */
+               if (pdmpriv->TxPowerTrackControl)
+                       pdmpriv->ThermalValue = ThermalValue;
+       }
+       pdmpriv->TXPowercount = 0;
+}
+
+/*     Description: */
+/*             - Dispatch TxPower Tracking direct call ONLY for 92s. */
+/*             - We shall NOT schedule Workitem within PASSIVE LEVEL, which will cause system resource */
+/*                leakage under some platform. */
+/*     Assumption: */
+/*             PASSIVE_LEVEL when this routine is called. */
+static void ODM_TXPowerTracking92CDirectCall(struct rtw_adapter *Adapter)
+{
+       odm_TXPowerTrackingCallback_ThermalMeter_92C(Adapter);
+}
+
+static void odm_CheckTXPowerTracking_ThermalMeter(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+       struct dm_odm_t *podmpriv = &pHalData->odmpriv;
+
+       if (!(podmpriv->SupportAbility & ODM_RF_TX_PWR_TRACK))
+               return;
+
+       if (!pdmpriv->TM_Trigger) {             /* at least delay 1 sec */
+               PHY_SetRFReg(Adapter, RF_PATH_A, RF_T_METER, bRFRegOffsetMask, 0x60);
+
+               pdmpriv->TM_Trigger = 1;
+               return;
+       } else {
+               ODM_TXPowerTracking92CDirectCall(Adapter);
+               pdmpriv->TM_Trigger = 0;
+       }
+}
+
+void rtl8723a_odm_check_tx_power_tracking(struct rtw_adapter *Adapter)
+{
+       odm_CheckTXPowerTracking_ThermalMeter(Adapter);
+}
+
+/*     IQK */
+#define MAX_TOLERANCE          5
+#define IQK_DELAY_TIME         1       /* ms */
+
+static u8 _PHY_PathA_IQK(struct rtw_adapter *pAdapter, bool configPathB)
+{
+       u32 regEAC, regE94, regE9C, regEA4;
+       u8 result = 0x00;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+
+       /* path-A IQK setting */
+       PHY_SetBBReg(pAdapter, rTx_IQK_Tone_A, bMaskDWord, 0x10008c1f);
+       PHY_SetBBReg(pAdapter, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f);
+       PHY_SetBBReg(pAdapter, rTx_IQK_PI_A, bMaskDWord, 0x82140102);
+
+       PHY_SetBBReg(pAdapter, rRx_IQK_PI_A, bMaskDWord, configPathB ? 0x28160202 :
+               IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID)?0x28160202:0x28160502);
+
+       /* path-B IQK setting */
+       if (configPathB) {
+               PHY_SetBBReg(pAdapter, rTx_IQK_Tone_B, bMaskDWord, 0x10008c22);
+               PHY_SetBBReg(pAdapter, rRx_IQK_Tone_B, bMaskDWord, 0x10008c22);
+               PHY_SetBBReg(pAdapter, rTx_IQK_PI_B, bMaskDWord, 0x82140102);
+               PHY_SetBBReg(pAdapter, rRx_IQK_PI_B, bMaskDWord, 0x28160202);
+       }
+
+       /* LO calibration setting */
+       PHY_SetBBReg(pAdapter, rIQK_AGC_Rsp, bMaskDWord, 0x001028d1);
+
+       /* One shot, path A LOK & IQK */
+       PHY_SetBBReg(pAdapter, rIQK_AGC_Pts, bMaskDWord, 0xf9000000);
+       PHY_SetBBReg(pAdapter, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+
+       /*  delay x ms */
+       udelay(IQK_DELAY_TIME*1000);/* PlatformStallExecution(IQK_DELAY_TIME*1000); */
+
+       /*  Check failed */
+       regEAC = PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_A_2, bMaskDWord);
+       regE94 = PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_A, bMaskDWord);
+       regE9C = PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_A, bMaskDWord);
+       regEA4 = PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_A_2, bMaskDWord);
+
+       if (!(regEAC & BIT28) &&
+           (((regE94 & 0x03FF0000)>>16) != 0x142) &&
+           (((regE9C & 0x03FF0000)>>16) != 0x42))
+               result |= 0x01;
+       else                    /* if Tx not OK, ignore Rx */
+               return result;
+
+       if (!(regEAC & BIT27) &&                /* if Tx is OK, check whether Rx is OK */
+           (((regEA4 & 0x03FF0000)>>16) != 0x132) &&
+           (((regEAC & 0x03FF0000)>>16) != 0x36))
+               result |= 0x02;
+       else
+               DBG_8723A("Path A Rx IQK fail!!\n");
+       return result;
+}
+
+static u8 _PHY_PathB_IQK(struct rtw_adapter *pAdapter)
+{
+       u32 regEAC, regEB4, regEBC, regEC4, regECC;
+       u8 result = 0x00;
+
+       /* One shot, path B LOK & IQK */
+       PHY_SetBBReg(pAdapter, rIQK_AGC_Cont, bMaskDWord, 0x00000002);
+       PHY_SetBBReg(pAdapter, rIQK_AGC_Cont, bMaskDWord, 0x00000000);
+
+       /*  delay x ms */
+       udelay(IQK_DELAY_TIME*1000);
+
+       /*  Check failed */
+       regEAC = PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_A_2, bMaskDWord);
+       regEB4 = PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_B, bMaskDWord);
+       regEBC = PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_B, bMaskDWord);
+       regEC4 = PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_B_2, bMaskDWord);
+       regECC = PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_B_2, bMaskDWord);
+
+       if (!(regEAC & BIT31) &&
+           (((regEB4 & 0x03FF0000)>>16) != 0x142) &&
+           (((regEBC & 0x03FF0000)>>16) != 0x42))
+               result |= 0x01;
+       else
+               return result;
+
+       if (!(regEAC & BIT30) &&
+           (((regEC4 & 0x03FF0000)>>16) != 0x132) &&
+           (((regECC & 0x03FF0000)>>16) != 0x36))
+               result |= 0x02;
+       else
+               DBG_8723A("Path B Rx IQK fail!!\n");
+       return result;
+}
+
+static void _PHY_PathAFillIQKMatrix(struct rtw_adapter *pAdapter,
+       bool bIQKOK,
+       int result[][8],
+       u8 final_candidate,
+       bool bTxOnly
+       )
+{
+       u32 Oldval_0, X, TX0_A, reg;
+       s32 Y, TX0_C;
+
+       DBG_8723A("Path A IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed");
+
+       if (final_candidate == 0xFF) {
+               return;
+       } else if (bIQKOK) {
+               Oldval_0 = (PHY_QueryBBReg(pAdapter, rOFDM0_XATxIQImbalance, bMaskDWord) >> 22) & 0x3FF;
+
+               X = result[final_candidate][0];
+               if ((X & 0x00000200) != 0)
+                       X = X | 0xFFFFFC00;
+               TX0_A = (X * Oldval_0) >> 8;
+               PHY_SetBBReg(pAdapter, rOFDM0_XATxIQImbalance, 0x3FF, TX0_A);
+               PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(31), ((X * Oldval_0>>7) & 0x1));
+
+               Y = result[final_candidate][1];
+               if ((Y & 0x00000200) != 0)
+                       Y = Y | 0xFFFFFC00;
+               TX0_C = (Y * Oldval_0) >> 8;
+               PHY_SetBBReg(pAdapter, rOFDM0_XCTxAFE, 0xF0000000, ((TX0_C&0x3C0)>>6));
+               PHY_SetBBReg(pAdapter, rOFDM0_XATxIQImbalance, 0x003F0000, (TX0_C&0x3F));
+               PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(29), ((Y * Oldval_0>>7) & 0x1));
+
+               if (bTxOnly) {
+                       DBG_8723A("_PHY_PathAFillIQKMatrix only Tx OK\n");
+                       return;
+               }
+
+               reg = result[final_candidate][2];
+               PHY_SetBBReg(pAdapter, rOFDM0_XARxIQImbalance, 0x3FF, reg);
+
+               reg = result[final_candidate][3] & 0x3F;
+               PHY_SetBBReg(pAdapter, rOFDM0_XARxIQImbalance, 0xFC00, reg);
+
+               reg = (result[final_candidate][3] >> 6) & 0xF;
+               PHY_SetBBReg(pAdapter, rOFDM0_RxIQExtAnta, 0xF0000000, reg);
+       }
+}
+
+static void _PHY_PathBFillIQKMatrix(struct rtw_adapter *pAdapter, bool bIQKOK, int result[][8], u8 final_candidate, bool bTxOnly)
+{
+       u32 Oldval_1, X, TX1_A, reg;
+       s32 Y, TX1_C;
+
+       DBG_8723A("Path B IQ Calibration %s !\n", (bIQKOK)?"Success":"Failed");
+
+       if (final_candidate == 0xFF) {
+               return;
+       } else if (bIQKOK) {
+               Oldval_1 = (PHY_QueryBBReg(pAdapter, rOFDM0_XBTxIQImbalance, bMaskDWord) >> 22) & 0x3FF;
+
+               X = result[final_candidate][4];
+               if ((X & 0x00000200) != 0)
+                       X = X | 0xFFFFFC00;
+               TX1_A = (X * Oldval_1) >> 8;
+               PHY_SetBBReg(pAdapter, rOFDM0_XBTxIQImbalance, 0x3FF, TX1_A);
+               PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(27), ((X * Oldval_1>>7) & 0x1));
+
+               Y = result[final_candidate][5];
+               if ((Y & 0x00000200) != 0)
+                       Y = Y | 0xFFFFFC00;
+               TX1_C = (Y * Oldval_1) >> 8;
+               PHY_SetBBReg(pAdapter, rOFDM0_XDTxAFE, 0xF0000000, ((TX1_C&0x3C0)>>6));
+               PHY_SetBBReg(pAdapter, rOFDM0_XBTxIQImbalance, 0x003F0000, (TX1_C&0x3F));
+               PHY_SetBBReg(pAdapter, rOFDM0_ECCAThreshold, BIT(25), ((Y * Oldval_1>>7) & 0x1));
+
+               if (bTxOnly)
+                       return;
+
+               reg = result[final_candidate][6];
+               PHY_SetBBReg(pAdapter, rOFDM0_XBRxIQImbalance, 0x3FF, reg);
+
+               reg = result[final_candidate][7] & 0x3F;
+               PHY_SetBBReg(pAdapter, rOFDM0_XBRxIQImbalance, 0xFC00, reg);
+
+               reg = (result[final_candidate][7] >> 6) & 0xF;
+               PHY_SetBBReg(pAdapter, rOFDM0_AGCRSSITable, 0x0000F000, reg);
+       }
+}
+
+static void _PHY_SaveADDARegisters(struct rtw_adapter *pAdapter, u32 *ADDAReg, u32 *ADDABackup, u32 RegisterNum)
+{
+       u32 i;
+
+       for (i = 0 ; i < RegisterNum ; i++) {
+               ADDABackup[i] = PHY_QueryBBReg(pAdapter, ADDAReg[i], bMaskDWord);
+       }
+}
+
+static void _PHY_SaveMACRegisters(struct rtw_adapter *pAdapter, u32 *MACReg, u32 *MACBackup)
+{
+       u32 i;
+
+       for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++) {
+               MACBackup[i] = rtw_read8(pAdapter, MACReg[i]);
+       }
+       MACBackup[i] = rtw_read32(pAdapter, MACReg[i]);
+}
+
+static void _PHY_ReloadADDARegisters(struct rtw_adapter *pAdapter, u32 *ADDAReg, u32 *ADDABackup, u32 RegiesterNum)
+{
+       u32 i;
+
+       for (i = 0 ; i < RegiesterNum ; i++) {
+               PHY_SetBBReg(pAdapter, ADDAReg[i], bMaskDWord, ADDABackup[i]);
+       }
+}
+
+static void _PHY_ReloadMACRegisters(struct rtw_adapter *pAdapter, u32 *MACReg, u32 *MACBackup)
+{
+       u32 i;
+
+       for (i = 0 ; i < (IQK_MAC_REG_NUM - 1); i++) {
+               rtw_write8(pAdapter, MACReg[i], (u8)MACBackup[i]);
+       }
+       rtw_write32(pAdapter, MACReg[i], MACBackup[i]);
+}
+
+static void _PHY_PathADDAOn(struct rtw_adapter *pAdapter, u32 *ADDAReg, bool isPathAOn, bool is2T)
+{
+       u32 pathOn;
+       u32 i;
+
+       pathOn = isPathAOn ? 0x04db25a4 : 0x0b1b25a4;
+       if (false == is2T) {
+               pathOn = 0x0bdb25a0;
+               PHY_SetBBReg(pAdapter, ADDAReg[0], bMaskDWord, 0x0b1b25a0);
+       } else {
+               PHY_SetBBReg(pAdapter, ADDAReg[0], bMaskDWord, pathOn);
+       }
+
+       for (i = 1 ; i < IQK_ADDA_REG_NUM ; i++)
+               PHY_SetBBReg(pAdapter, ADDAReg[i], bMaskDWord, pathOn);
+}
+
+static void _PHY_MACSettingCalibration(struct rtw_adapter *pAdapter, u32 *MACReg, u32 *MACBackup)
+{
+       u32 i = 0;
+
+       rtw_write8(pAdapter, MACReg[i], 0x3F);
+
+       for (i = 1 ; i < (IQK_MAC_REG_NUM - 1); i++) {
+               rtw_write8(pAdapter, MACReg[i], (u8)(MACBackup[i]&(~BIT3)));
+       }
+       rtw_write8(pAdapter, MACReg[i], (u8)(MACBackup[i]&(~BIT5)));
+}
+
+static void _PHY_PathAStandBy(struct rtw_adapter *pAdapter)
+{
+       PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x0);
+       PHY_SetBBReg(pAdapter, 0x840, bMaskDWord, 0x00010000);
+       PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x80800000);
+}
+
+static void _PHY_PIModeSwitch(struct rtw_adapter *pAdapter, bool PIMode)
+{
+       u32 mode;
+
+       mode = PIMode ? 0x01000100 : 0x01000000;
+       PHY_SetBBReg(pAdapter, 0x820, bMaskDWord, mode);
+       PHY_SetBBReg(pAdapter, 0x828, bMaskDWord, mode);
+}
+
+/*
+return false => do IQK again
+*/
+static bool _PHY_SimularityCompare(struct rtw_adapter *pAdapter, int result[][8], u8 c1, u8 c2)
+{
+       u32 i, j, diff, SimularityBitMap, bound = 0;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+       u8 final_candidate[2] = {0xFF, 0xFF};   /* for path A and path B */
+       bool bResult = true, is2T = IS_92C_SERIAL(pHalData->VersionID);
+
+       if (is2T)
+               bound = 8;
+       else
+               bound = 4;
+
+       SimularityBitMap = 0;
+
+       for (i = 0; i < bound; i++) {
+               diff = (result[c1][i] > result[c2][i]) ? (result[c1][i] - result[c2][i]) : (result[c2][i] - result[c1][i]);
+               if (diff > MAX_TOLERANCE) {
+                       if ((i == 2 || i == 6) && !SimularityBitMap) {
+                               if (result[c1][i]+result[c1][i+1] == 0)
+                                       final_candidate[(i/4)] = c2;
+                               else if (result[c2][i]+result[c2][i+1] == 0)
+                                       final_candidate[(i/4)] = c1;
+                               else
+                                       SimularityBitMap = SimularityBitMap|(1<<i);
+                       } else {
+                               SimularityBitMap = SimularityBitMap|(1<<i);
+                       }
+               }
+       }
+
+       if (SimularityBitMap == 0) {
+               for (i = 0; i < (bound/4); i++) {
+                       if (final_candidate[i] != 0xFF) {
+                               for (j = i*4; j < (i+1)*4-2; j++)
+                                       result[3][j] = result[final_candidate[i]][j];
+                               bResult = false;
+                       }
+               }
+               return bResult;
+       } else if (!(SimularityBitMap & 0x0F)) {
+               /* path A OK */
+               for (i = 0; i < 4; i++)
+                       result[3][i] = result[c1][i];
+               return false;
+       } else if (!(SimularityBitMap & 0xF0) && is2T) {
+               /* path B OK */
+               for (i = 4; i < 8; i++)
+                       result[3][i] = result[c1][i];
+               return false;
+       } else {
+               return false;
+       }
+}
+
+static void _PHY_IQCalibrate(struct rtw_adapter *pAdapter, int result[][8], u8 t, bool is2T)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+       u32 i;
+       u8 PathAOK, PathBOK;
+       u32 ADDA_REG[IQK_ADDA_REG_NUM] = {
+               rFPGA0_XCD_SwitchControl, rBlue_Tooth,
+               rRx_Wait_CCA, rTx_CCK_RFON,
+               rTx_CCK_BBON, rTx_OFDM_RFON,
+               rTx_OFDM_BBON, rTx_To_Rx,
+               rTx_To_Tx, rRx_CCK,
+               rRx_OFDM, rRx_Wait_RIFS,
+               rRx_TO_Rx, rStandby,
+               rSleep, rPMPD_ANAEN
+       };
+
+       u32 IQK_MAC_REG[IQK_MAC_REG_NUM] = {
+               REG_TXPAUSE, REG_BCN_CTRL,
+               REG_BCN_CTRL_1, REG_GPIO_MUXCFG
+       };
+
+       u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = {
+               rOFDM0_TRxPathEnable, rOFDM0_TRMuxPar,
+               rFPGA0_XCD_RFInterfaceSW, rConfig_AntA, rConfig_AntB,
+               rFPGA0_XAB_RFInterfaceSW, rFPGA0_XA_RFInterfaceOE,
+               rFPGA0_XB_RFInterfaceOE, rFPGA0_RFMOD
+       };
+
+       const u32 retryCount = 2;
+
+       /*  Note: IQ calibration must be performed after loading  */
+       /*              PHY_REG.txt , and radio_a, radio_b.txt   */
+
+       u32 bbvalue;
+
+       if (t == 0) {
+               bbvalue = PHY_QueryBBReg(pAdapter, rFPGA0_RFMOD, bMaskDWord);
+
+               /*  Save ADDA parameters, turn Path A ADDA on */
+               _PHY_SaveADDARegisters(pAdapter, ADDA_REG, pdmpriv->ADDA_backup, IQK_ADDA_REG_NUM);
+               _PHY_SaveMACRegisters(pAdapter, IQK_MAC_REG, pdmpriv->IQK_MAC_backup);
+               _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup, IQK_BB_REG_NUM);
+       }
+       _PHY_PathADDAOn(pAdapter, ADDA_REG, true, is2T);
+
+       if (t == 0)
+               pdmpriv->bRfPiEnable = (u8)PHY_QueryBBReg(pAdapter, rFPGA0_XA_HSSIParameter1, BIT(8));
+
+       if (!pdmpriv->bRfPiEnable) {
+               /*  Switch BB to PI mode to do IQ Calibration. */
+               _PHY_PIModeSwitch(pAdapter, true);
+       }
+
+       PHY_SetBBReg(pAdapter, rFPGA0_RFMOD, BIT24, 0x00);
+       PHY_SetBBReg(pAdapter, rOFDM0_TRxPathEnable, bMaskDWord, 0x03a05600);
+       PHY_SetBBReg(pAdapter, rOFDM0_TRMuxPar, bMaskDWord, 0x000800e4);
+       PHY_SetBBReg(pAdapter, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22204000);
+       PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT10, 0x01);
+       PHY_SetBBReg(pAdapter, rFPGA0_XAB_RFInterfaceSW, BIT26, 0x01);
+       PHY_SetBBReg(pAdapter, rFPGA0_XA_RFInterfaceOE, BIT10, 0x00);
+       PHY_SetBBReg(pAdapter, rFPGA0_XB_RFInterfaceOE, BIT10, 0x00);
+
+       if (is2T) {
+               PHY_SetBBReg(pAdapter, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00010000);
+               PHY_SetBBReg(pAdapter, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00010000);
+       }
+
+       /* MAC settings */
+       _PHY_MACSettingCalibration(pAdapter, IQK_MAC_REG, pdmpriv->IQK_MAC_backup);
+
+       /* Page B init */
+       PHY_SetBBReg(pAdapter, rConfig_AntA, bMaskDWord, 0x00080000);
+
+       if (is2T)
+               PHY_SetBBReg(pAdapter, rConfig_AntB, bMaskDWord, 0x00080000);
+
+       /*  IQ calibration setting */
+       PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0x80800000);
+       PHY_SetBBReg(pAdapter, rTx_IQK, bMaskDWord, 0x01007c00);
+       PHY_SetBBReg(pAdapter, rRx_IQK, bMaskDWord, 0x01004800);
+
+       for (i = 0 ; i < retryCount ; i++) {
+               PathAOK = _PHY_PathA_IQK(pAdapter, is2T);
+               if (PathAOK == 0x03) {
+                               DBG_8723A("Path A IQK Success!!\n");
+                               result[t][0] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16;
+                               result[t][1] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16;
+                               result[t][2] = (PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
+                               result[t][3] = (PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_A_2, bMaskDWord)&0x3FF0000)>>16;
+                       break;
+               } else if (i == (retryCount-1) && PathAOK == 0x01) {
+                       /* Tx IQK OK */
+                       DBG_8723A("Path A IQK Only  Tx Success!!\n");
+
+                       result[t][0] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_A, bMaskDWord)&0x3FF0000)>>16;
+                       result[t][1] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_A, bMaskDWord)&0x3FF0000)>>16;
+               }
+       }
+
+       if (0x00 == PathAOK) {
+               DBG_8723A("Path A IQK failed!!\n");
+       }
+
+       if (is2T) {
+               _PHY_PathAStandBy(pAdapter);
+
+               /*  Turn Path B ADDA on */
+               _PHY_PathADDAOn(pAdapter, ADDA_REG, false, is2T);
+
+               for (i = 0 ; i < retryCount ; i++) {
+                       PathBOK = _PHY_PathB_IQK(pAdapter);
+                       if (PathBOK == 0x03) {
+                               DBG_8723A("Path B IQK Success!!\n");
+                               result[t][4] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+                               result[t][5] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+                               result[t][6] = (PHY_QueryBBReg(pAdapter, rRx_Power_Before_IQK_B_2, bMaskDWord)&0x3FF0000)>>16;
+                               result[t][7] = (PHY_QueryBBReg(pAdapter, rRx_Power_After_IQK_B_2, bMaskDWord)&0x3FF0000)>>16;
+                               break;
+                       } else if (i == (retryCount - 1) && PathBOK == 0x01) {
+                               /* Tx IQK OK */
+                               DBG_8723A("Path B Only Tx IQK Success!!\n");
+                               result[t][4] = (PHY_QueryBBReg(pAdapter, rTx_Power_Before_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+                               result[t][5] = (PHY_QueryBBReg(pAdapter, rTx_Power_After_IQK_B, bMaskDWord)&0x3FF0000)>>16;
+                       }
+               }
+
+               if (0x00 == PathBOK) {
+                       DBG_8723A("Path B IQK failed!!\n");
+               }
+       }
+
+       /* Back to BB mode, load original value */
+       PHY_SetBBReg(pAdapter, rFPGA0_IQK, bMaskDWord, 0);
+
+       if (t != 0) {
+               if (!pdmpriv->bRfPiEnable) {
+                       /*  Switch back BB to SI mode after finish IQ Calibration. */
+                       _PHY_PIModeSwitch(pAdapter, false);
+               }
+
+               /*  Reload ADDA power saving parameters */
+               _PHY_ReloadADDARegisters(pAdapter, ADDA_REG, pdmpriv->ADDA_backup, IQK_ADDA_REG_NUM);
+
+               /*  Reload MAC parameters */
+               _PHY_ReloadMACRegisters(pAdapter, IQK_MAC_REG, pdmpriv->IQK_MAC_backup);
+
+               /*  Reload BB parameters */
+               _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup, IQK_BB_REG_NUM);
+
+               /*  Restore RX initial gain */
+               PHY_SetBBReg(pAdapter, rFPGA0_XA_LSSIParameter, bMaskDWord, 0x00032ed3);
+               if (is2T) {
+                       PHY_SetBBReg(pAdapter, rFPGA0_XB_LSSIParameter, bMaskDWord, 0x00032ed3);
+               }
+
+               /* load 0xe30 IQC default value */
+               PHY_SetBBReg(pAdapter, rTx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+               PHY_SetBBReg(pAdapter, rRx_IQK_Tone_A, bMaskDWord, 0x01008c00);
+
+       }
+}
+
+static void _PHY_LCCalibrate(struct rtw_adapter *pAdapter, bool is2T)
+{
+       u8 tmpReg;
+       u32 RF_Amode = 0, RF_Bmode = 0, LC_Cal;
+
+       /* Check continuous TX and Packet TX */
+       tmpReg = rtw_read8(pAdapter, 0xd03);
+
+       if ((tmpReg&0x70) != 0)                 /* Deal with contisuous TX case */
+               rtw_write8(pAdapter, 0xd03, tmpReg&0x8F);       /* disable all continuous TX */
+       else                                                    /*  Deal with Packet TX case */
+               rtw_write8(pAdapter, REG_TXPAUSE, 0xFF);                        /*  block all queues */
+
+       if ((tmpReg&0x70) != 0) {
+               /* 1. Read original RF mode */
+               /* Path-A */
+               RF_Amode = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits);
+
+               /* Path-B */
+               if (is2T)
+                       RF_Bmode = PHY_QueryRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits);
+
+               /* 2. Set RF mode = standby mode */
+               /* Path-A */
+               PHY_SetRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits, (RF_Amode&0x8FFFF)|0x10000);
+
+               /* Path-B */
+               if (is2T)
+                       PHY_SetRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits, (RF_Bmode&0x8FFFF)|0x10000);
+       }
+
+       /* 3. Read RF reg18 */
+       LC_Cal = PHY_QueryRFReg(pAdapter, RF_PATH_A, RF_CHNLBW, bMask12Bits);
+
+       /* 4. Set LC calibration begin */
+       PHY_SetRFReg(pAdapter, RF_PATH_A, RF_CHNLBW, bMask12Bits, LC_Cal|0x08000);
+
+       msleep(100);
+
+       /* Restore original situation */
+       if ((tmpReg&0x70) != 0) {       /* Deal with contuous TX case  */
+               /* Path-A */
+               rtw_write8(pAdapter, 0xd03, tmpReg);
+               PHY_SetRFReg(pAdapter, RF_PATH_A, RF_AC, bMask12Bits, RF_Amode);
+
+               /* Path-B */
+               if (is2T)
+                       PHY_SetRFReg(pAdapter, RF_PATH_B, RF_AC, bMask12Bits, RF_Bmode);
+       } else { /*  Deal with Packet TX case */
+               rtw_write8(pAdapter, REG_TXPAUSE, 0x00);
+       }
+}
+
+/* Analog Pre-distortion calibration */
+#define                APK_BB_REG_NUM  8
+#define                APK_CURVE_REG_NUM 4
+#define                PATH_NUM                2
+
+void rtl8723a_phy_iq_calibrate(struct rtw_adapter *pAdapter, bool bReCovery)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+       s32 result[4][8];       /* last is final result */
+       u8 i, final_candidate;
+       bool bPathAOK, bPathBOK;
+       s32 RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4;
+       s32 RegECC, RegTmp = 0;
+       bool is12simular, is13simular, is23simular;
+       bool bStartContTx = false, bSingleTone = false;
+       bool bCarrierSuppression = false;
+       u32 IQK_BB_REG_92C[IQK_BB_REG_NUM] = {
+               rOFDM0_XARxIQImbalance, rOFDM0_XBRxIQImbalance,
+               rOFDM0_ECCAThreshold, rOFDM0_AGCRSSITable,
+               rOFDM0_XATxIQImbalance, rOFDM0_XBTxIQImbalance,
+               rOFDM0_XCTxAFE, rOFDM0_XDTxAFE,
+               rOFDM0_RxIQExtAnta
+       };
+
+       /* ignore IQK when continuous Tx */
+       if (bStartContTx || bSingleTone || bCarrierSuppression)
+               return;
+
+       if (bReCovery) {
+               _PHY_ReloadADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup_recover, 9);
+               return;
+       }
+       DBG_8723A("IQK:Start!!!\n");
+
+       for (i = 0; i < 8; i++) {
+               result[0][i] = 0;
+               result[1][i] = 0;
+               result[2][i] = 0;
+               result[3][i] = 0;
+       }
+       final_candidate = 0xff;
+       bPathAOK = false;
+       bPathBOK = false;
+       is12simular = false;
+       is23simular = false;
+       is13simular = false;
+
+       for (i = 0; i < 3; i++) {
+               if (IS_92C_SERIAL(pHalData->VersionID)) {
+                        _PHY_IQCalibrate(pAdapter, result, i, true);
+               } else {
+                       /*  For 88C 1T1R */
+                       _PHY_IQCalibrate(pAdapter, result, i, false);
+               }
+
+               if (i == 1) {
+                       is12simular = _PHY_SimularityCompare(pAdapter, result, 0, 1);
+                       if (is12simular) {
+                               final_candidate = 0;
+                               break;
+                       }
+               }
+
+               if (i == 2) {
+                       is13simular = _PHY_SimularityCompare(pAdapter, result, 0, 2);
+                       if (is13simular) {
+                               final_candidate = 0;
+                               break;
+                       }
+
+                       is23simular = _PHY_SimularityCompare(pAdapter, result, 1, 2);
+                       if (is23simular) {
+                               final_candidate = 1;
+                       } else {
+                               for (i = 0; i < 8; i++)
+                                       RegTmp += result[3][i];
+
+                               if (RegTmp != 0)
+                                       final_candidate = 3;
+                               else
+                                       final_candidate = 0xFF;
+                       }
+               }
+       }
+
+       for (i = 0; i < 4; i++) {
+               RegE94 = result[i][0];
+               RegE9C = result[i][1];
+               RegEA4 = result[i][2];
+               RegEAC = result[i][3];
+               RegEB4 = result[i][4];
+               RegEBC = result[i][5];
+               RegEC4 = result[i][6];
+               RegECC = result[i][7];
+       }
+
+       if (final_candidate != 0xff) {
+               RegE94 = result[final_candidate][0];
+               pdmpriv->RegE94 =  RegE94;
+               RegE9C = result[final_candidate][1];
+               pdmpriv->RegE9C = RegE9C;
+               RegEA4 = result[final_candidate][2];
+               RegEAC = result[final_candidate][3];
+               RegEB4 = result[final_candidate][4];
+               pdmpriv->RegEB4 = RegEB4;
+               RegEBC = result[final_candidate][5];
+               pdmpriv->RegEBC = RegEBC;
+               RegEC4 = result[final_candidate][6];
+               RegECC = result[final_candidate][7];
+               DBG_8723A("IQK: final_candidate is %x\n", final_candidate);
+               DBG_8723A("IQK: RegE94 =%x RegE9C =%x RegEA4 =%x RegEAC =%x RegEB4 =%x RegEBC =%x RegEC4 =%x RegECC =%x\n ",
+                         RegE94, RegE9C, RegEA4, RegEAC, RegEB4, RegEBC, RegEC4, RegECC);
+               bPathAOK = bPathBOK = true;
+       } else {
+               RegE94 = RegEB4 = pdmpriv->RegE94 = pdmpriv->RegEB4 = 0x100;    /* X default value */
+               RegE9C = RegEBC = pdmpriv->RegE9C = pdmpriv->RegEBC = 0x0;              /* Y default value */
+       }
+
+       if ((RegE94 != 0)/*&&(RegEA4 != 0)*/)
+               _PHY_PathAFillIQKMatrix(pAdapter, bPathAOK, result, final_candidate, (RegEA4 == 0));
+
+       if (IS_92C_SERIAL(pHalData->VersionID)) {
+               if ((RegEB4 != 0)/*&&(RegEC4 != 0)*/)
+               _PHY_PathBFillIQKMatrix(pAdapter, bPathBOK, result, final_candidate, (RegEC4 == 0));
+       }
+
+       _PHY_SaveADDARegisters(pAdapter, IQK_BB_REG_92C, pdmpriv->IQK_BB_backup_recover, 9);
+}
+
+void rtl8723a_phy_lc_calibrate(struct rtw_adapter *pAdapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+       struct mlme_ext_priv *pmlmeext = &pAdapter->mlmeextpriv;
+       bool bStartContTx = false, bSingleTone = false, bCarrierSuppression = false;
+
+       /* ignore IQK when continuous Tx */
+       if (bStartContTx || bSingleTone || bCarrierSuppression)
+               return;
+
+       if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS)
+               return;
+
+       if (IS_92C_SERIAL(pHalData->VersionID)) {
+               _PHY_LCCalibrate(pAdapter, true);
+       } else {
+               /*  For 88C 1T1R */
+               _PHY_LCCalibrate(pAdapter, false);
+       }
+}
+
+void
+rtl8723a_phy_ap_calibrate(struct rtw_adapter *pAdapter, char delta)
+{
+}
diff --git a/drivers/staging/rtl8723au/hal/HalHWImg8723A_BB.c b/drivers/staging/rtl8723au/hal/HalHWImg8723A_BB.c
new file mode 100644 (file)
index 0000000..294e6a6
--- /dev/null
@@ -0,0 +1,726 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License 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 "odm_precomp.h"
+
+static bool CheckCondition(const u32  Condition, const u32  Hex)
+{
+       u32 _board     = (Hex & 0x000000FF);
+       u32 _interface = (Hex & 0x0000FF00) >> 8;
+       u32 _platform  = (Hex & 0x00FF0000) >> 16;
+       u32 cond = Condition;
+
+       if (Condition == 0xCDCDCDCD)
+               return true;
+
+       cond = Condition & 0x000000FF;
+       if ((_board == cond) && cond != 0x00)
+               return false;
+
+       cond = Condition & 0x0000FF00;
+       cond = cond >> 8;
+       if ((_interface & cond) == 0 && cond != 0x07)
+               return false;
+
+       cond = Condition & 0x00FF0000;
+       cond = cond >> 16;
+       if ((_platform & cond) == 0 && cond != 0x0F)
+               return false;
+       return true;
+}
+
+/******************************************************************************
+*                           AGC_TAB_1T.TXT
+******************************************************************************/
+
+static u32 Array_AGC_TAB_1T_8723A[] = {
+       0xC78, 0x7B000001,
+       0xC78, 0x7B010001,
+       0xC78, 0x7B020001,
+       0xC78, 0x7B030001,
+       0xC78, 0x7B040001,
+       0xC78, 0x7B050001,
+       0xC78, 0x7A060001,
+       0xC78, 0x79070001,
+       0xC78, 0x78080001,
+       0xC78, 0x77090001,
+       0xC78, 0x760A0001,
+       0xC78, 0x750B0001,
+       0xC78, 0x740C0001,
+       0xC78, 0x730D0001,
+       0xC78, 0x720E0001,
+       0xC78, 0x710F0001,
+       0xC78, 0x70100001,
+       0xC78, 0x6F110001,
+       0xC78, 0x6E120001,
+       0xC78, 0x6D130001,
+       0xC78, 0x6C140001,
+       0xC78, 0x6B150001,
+       0xC78, 0x6A160001,
+       0xC78, 0x69170001,
+       0xC78, 0x68180001,
+       0xC78, 0x67190001,
+       0xC78, 0x661A0001,
+       0xC78, 0x651B0001,
+       0xC78, 0x641C0001,
+       0xC78, 0x631D0001,
+       0xC78, 0x621E0001,
+       0xC78, 0x611F0001,
+       0xC78, 0x60200001,
+       0xC78, 0x49210001,
+       0xC78, 0x48220001,
+       0xC78, 0x47230001,
+       0xC78, 0x46240001,
+       0xC78, 0x45250001,
+       0xC78, 0x44260001,
+       0xC78, 0x43270001,
+       0xC78, 0x42280001,
+       0xC78, 0x41290001,
+       0xC78, 0x402A0001,
+       0xC78, 0x262B0001,
+       0xC78, 0x252C0001,
+       0xC78, 0x242D0001,
+       0xC78, 0x232E0001,
+       0xC78, 0x222F0001,
+       0xC78, 0x21300001,
+       0xC78, 0x20310001,
+       0xC78, 0x06320001,
+       0xC78, 0x05330001,
+       0xC78, 0x04340001,
+       0xC78, 0x03350001,
+       0xC78, 0x02360001,
+       0xC78, 0x01370001,
+       0xC78, 0x00380001,
+       0xC78, 0x00390001,
+       0xC78, 0x003A0001,
+       0xC78, 0x003B0001,
+       0xC78, 0x003C0001,
+       0xC78, 0x003D0001,
+       0xC78, 0x003E0001,
+       0xC78, 0x003F0001,
+       0xC78, 0x7B400001,
+       0xC78, 0x7B410001,
+       0xC78, 0x7B420001,
+       0xC78, 0x7B430001,
+       0xC78, 0x7B440001,
+       0xC78, 0x7B450001,
+       0xC78, 0x7A460001,
+       0xC78, 0x79470001,
+       0xC78, 0x78480001,
+       0xC78, 0x77490001,
+       0xC78, 0x764A0001,
+       0xC78, 0x754B0001,
+       0xC78, 0x744C0001,
+       0xC78, 0x734D0001,
+       0xC78, 0x724E0001,
+       0xC78, 0x714F0001,
+       0xC78, 0x70500001,
+       0xC78, 0x6F510001,
+       0xC78, 0x6E520001,
+       0xC78, 0x6D530001,
+       0xC78, 0x6C540001,
+       0xC78, 0x6B550001,
+       0xC78, 0x6A560001,
+       0xC78, 0x69570001,
+       0xC78, 0x68580001,
+       0xC78, 0x67590001,
+       0xC78, 0x665A0001,
+       0xC78, 0x655B0001,
+       0xC78, 0x645C0001,
+       0xC78, 0x635D0001,
+       0xC78, 0x625E0001,
+       0xC78, 0x615F0001,
+       0xC78, 0x60600001,
+       0xC78, 0x49610001,
+       0xC78, 0x48620001,
+       0xC78, 0x47630001,
+       0xC78, 0x46640001,
+       0xC78, 0x45650001,
+       0xC78, 0x44660001,
+       0xC78, 0x43670001,
+       0xC78, 0x42680001,
+       0xC78, 0x41690001,
+       0xC78, 0x406A0001,
+       0xC78, 0x266B0001,
+       0xC78, 0x256C0001,
+       0xC78, 0x246D0001,
+       0xC78, 0x236E0001,
+       0xC78, 0x226F0001,
+       0xC78, 0x21700001,
+       0xC78, 0x20710001,
+       0xC78, 0x06720001,
+       0xC78, 0x05730001,
+       0xC78, 0x04740001,
+       0xC78, 0x03750001,
+       0xC78, 0x02760001,
+       0xC78, 0x01770001,
+       0xC78, 0x00780001,
+       0xC78, 0x00790001,
+       0xC78, 0x007A0001,
+       0xC78, 0x007B0001,
+       0xC78, 0x007C0001,
+       0xC78, 0x007D0001,
+       0xC78, 0x007E0001,
+       0xC78, 0x007F0001,
+       0xC78, 0x3800001E,
+       0xC78, 0x3801001E,
+       0xC78, 0x3802001E,
+       0xC78, 0x3803001E,
+       0xC78, 0x3804001E,
+       0xC78, 0x3805001E,
+       0xC78, 0x3806001E,
+       0xC78, 0x3807001E,
+       0xC78, 0x3808001E,
+       0xC78, 0x3C09001E,
+       0xC78, 0x3E0A001E,
+       0xC78, 0x400B001E,
+       0xC78, 0x440C001E,
+       0xC78, 0x480D001E,
+       0xC78, 0x4C0E001E,
+       0xC78, 0x500F001E,
+       0xC78, 0x5210001E,
+       0xC78, 0x5611001E,
+       0xC78, 0x5A12001E,
+       0xC78, 0x5E13001E,
+       0xC78, 0x6014001E,
+       0xC78, 0x6015001E,
+       0xC78, 0x6016001E,
+       0xC78, 0x6217001E,
+       0xC78, 0x6218001E,
+       0xC78, 0x6219001E,
+       0xC78, 0x621A001E,
+       0xC78, 0x621B001E,
+       0xC78, 0x621C001E,
+       0xC78, 0x621D001E,
+       0xC78, 0x621E001E,
+       0xC78, 0x621F001E,
+};
+
+#define READ_NEXT_PAIR(v1, v2, i)                      \
+       do {                                            \
+               i += 2; v1 = Array[i]; v2 = Array[i+1]; \
+       } while (0)
+
+void ODM_ReadAndConfig_AGC_TAB_1T_8723A(struct dm_odm_t *pDM_Odm)
+{
+
+       u32 hex;
+       u32 i;
+       u8 platform = 0x04;
+       u8 interfaceValue   = pDM_Odm->SupportInterface;
+       u8 board = pDM_Odm->BoardType;
+       u32 ArrayLen = sizeof(Array_AGC_TAB_1T_8723A)/sizeof(u32);
+       u32 *Array = Array_AGC_TAB_1T_8723A;
+
+       hex = board;
+       hex += interfaceValue << 8;
+       hex += platform << 16;
+       hex += 0xFF000000;
+       for (i = 0; i < ArrayLen; i += 2) {
+               u32 v1 = Array[i];
+               u32 v2 = Array[i+1];
+
+               /*  This (offset, data) pair meets the condition. */
+               if (v1 < 0xCDCDCDCD) {
+                       odm_ConfigBB_AGC_8723A(pDM_Odm, v1, bMaskDWord, v2);
+                       continue;
+               } else {
+                       if (!CheckCondition(Array[i], hex)) {
+                               /*  Discard the following (offset, data) pairs. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               i -= 2; /*  prevent from for-loop += 2 */
+                       } else {
+                               /*  Configure matched pairs and skip to end of if-else. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2) {
+                                       odm_ConfigBB_AGC_8723A(pDM_Odm, v1, bMaskDWord, v2);
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               }
+                               while (v2 != 0xDEAD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                       }
+               }
+       }
+}
+
+/******************************************************************************
+*                           PHY_REG_1T.TXT
+******************************************************************************/
+
+static u32 Array_PHY_REG_1T_8723A[] = {
+       0x800, 0x80040000,
+       0x804, 0x00000003,
+       0x808, 0x0000FC00,
+       0x80C, 0x0000000A,
+       0x810, 0x10001331,
+       0x814, 0x020C3D10,
+       0x818, 0x02200385,
+       0x81C, 0x00000000,
+       0x820, 0x01000100,
+       0x824, 0x00390004,
+       0x828, 0x00000000,
+       0x82C, 0x00000000,
+       0x830, 0x00000000,
+       0x834, 0x00000000,
+       0x838, 0x00000000,
+       0x83C, 0x00000000,
+       0x840, 0x00010000,
+       0x844, 0x00000000,
+       0x848, 0x00000000,
+       0x84C, 0x00000000,
+       0x850, 0x00000000,
+       0x854, 0x00000000,
+       0x858, 0x569A569A,
+       0x85C, 0x001B25A4,
+       0x860, 0x66F60110,
+       0x864, 0x061F0130,
+       0x868, 0x00000000,
+       0x86C, 0x32323200,
+       0x870, 0x07000760,
+       0x874, 0x22004000,
+       0x878, 0x00000808,
+       0x87C, 0x00000000,
+       0x880, 0xC0083070,
+       0x884, 0x000004D5,
+       0x888, 0x00000000,
+       0x88C, 0xCCC000C0,
+       0x890, 0x00000800,
+       0x894, 0xFFFFFFFE,
+       0x898, 0x40302010,
+       0x89C, 0x00706050,
+       0x900, 0x00000000,
+       0x904, 0x00000023,
+       0x908, 0x00000000,
+       0x90C, 0x81121111,
+       0xA00, 0x00D047C8,
+       0xA04, 0x80FF000C,
+       0xA08, 0x8C838300,
+       0xA0C, 0x2E68120F,
+       0xA10, 0x9500BB78,
+       0xA14, 0x11144028,
+       0xA18, 0x00881117,
+       0xA1C, 0x89140F00,
+       0xA20, 0x1A1B0000,
+       0xA24, 0x090E1317,
+       0xA28, 0x00000204,
+       0xA2C, 0x00D30000,
+       0xA70, 0x101FBF00,
+       0xA74, 0x00000007,
+       0xA78, 0x00000900,
+       0xC00, 0x48071D40,
+       0xC04, 0x03A05611,
+       0xC08, 0x000000E4,
+       0xC0C, 0x6C6C6C6C,
+       0xC10, 0x08800000,
+       0xC14, 0x40000100,
+       0xC18, 0x08800000,
+       0xC1C, 0x40000100,
+       0xC20, 0x00000000,
+       0xC24, 0x00000000,
+       0xC28, 0x00000000,
+       0xC2C, 0x00000000,
+       0xC30, 0x69E9AC44,
+       0xFF0F011F, 0xABCD,
+       0xC34, 0x469652CF,
+       0xCDCDCDCD, 0xCDCD,
+       0xC34, 0x469652AF,
+       0xFF0F011F, 0xDEAD,
+       0xC38, 0x49795994,
+       0xC3C, 0x0A97971C,
+       0xC40, 0x1F7C403F,
+       0xC44, 0x000100B7,
+       0xC48, 0xEC020107,
+       0xC4C, 0x007F037F,
+       0xC50, 0x69543420,
+       0xC54, 0x43BC0094,
+       0xC58, 0x69543420,
+       0xC5C, 0x433C0094,
+       0xC60, 0x00000000,
+       0xFF0F011F, 0xABCD,
+       0xC64, 0x7116848B,
+       0xCDCDCDCD, 0xCDCD,
+       0xC64, 0x7112848B,
+       0xFF0F011F, 0xDEAD,
+       0xC68, 0x47C00BFF,
+       0xC6C, 0x00000036,
+       0xC70, 0x2C7F000D,
+       0xC74, 0x018610DB,
+       0xC78, 0x0000001F,
+       0xC7C, 0x00B91612,
+       0xC80, 0x40000100,
+       0xC84, 0x20F60000,
+       0xC88, 0x40000100,
+       0xC8C, 0x20200000,
+       0xC90, 0x00121820,
+       0xC94, 0x00000000,
+       0xC98, 0x00121820,
+       0xC9C, 0x00007F7F,
+       0xCA0, 0x00000000,
+       0xCA4, 0x00000080,
+       0xCA8, 0x00000000,
+       0xCAC, 0x00000000,
+       0xCB0, 0x00000000,
+       0xCB4, 0x00000000,
+       0xCB8, 0x00000000,
+       0xCBC, 0x28000000,
+       0xCC0, 0x00000000,
+       0xCC4, 0x00000000,
+       0xCC8, 0x00000000,
+       0xCCC, 0x00000000,
+       0xCD0, 0x00000000,
+       0xCD4, 0x00000000,
+       0xCD8, 0x64B22427,
+       0xCDC, 0x00766932,
+       0xCE0, 0x00222222,
+       0xCE4, 0x00000000,
+       0xCE8, 0x37644302,
+       0xCEC, 0x2F97D40C,
+       0xD00, 0x00080740,
+       0xD04, 0x00020401,
+       0xD08, 0x0000907F,
+       0xD0C, 0x20010201,
+       0xD10, 0xA0633333,
+       0xD14, 0x3333BC43,
+       0xD18, 0x7A8F5B6B,
+       0xD2C, 0xCC979975,
+       0xD30, 0x00000000,
+       0xD34, 0x80608000,
+       0xD38, 0x00000000,
+       0xD3C, 0x00027293,
+       0xD40, 0x00000000,
+       0xD44, 0x00000000,
+       0xD48, 0x00000000,
+       0xD4C, 0x00000000,
+       0xD50, 0x6437140A,
+       0xD54, 0x00000000,
+       0xD58, 0x00000000,
+       0xD5C, 0x30032064,
+       0xD60, 0x4653DE68,
+       0xD64, 0x04518A3C,
+       0xD68, 0x00002101,
+       0xD6C, 0x2A201C16,
+       0xD70, 0x1812362E,
+       0xD74, 0x322C2220,
+       0xD78, 0x000E3C24,
+       0xE00, 0x2A2A2A2A,
+       0xE04, 0x2A2A2A2A,
+       0xE08, 0x03902A2A,
+       0xE10, 0x2A2A2A2A,
+       0xE14, 0x2A2A2A2A,
+       0xE18, 0x2A2A2A2A,
+       0xE1C, 0x2A2A2A2A,
+       0xE28, 0x00000000,
+       0xE30, 0x1000DC1F,
+       0xE34, 0x10008C1F,
+       0xE38, 0x02140102,
+       0xE3C, 0x681604C2,
+       0xE40, 0x01007C00,
+       0xE44, 0x01004800,
+       0xE48, 0xFB000000,
+       0xE4C, 0x000028D1,
+       0xE50, 0x1000DC1F,
+       0xE54, 0x10008C1F,
+       0xE58, 0x02140102,
+       0xE5C, 0x28160D05,
+       0xE60, 0x00000008,
+       0xE68, 0x001B25A4,
+       0xE6C, 0x631B25A0,
+       0xE70, 0x631B25A0,
+       0xE74, 0x081B25A0,
+       0xE78, 0x081B25A0,
+       0xE7C, 0x081B25A0,
+       0xE80, 0x081B25A0,
+       0xE84, 0x631B25A0,
+       0xE88, 0x081B25A0,
+       0xE8C, 0x631B25A0,
+       0xED0, 0x631B25A0,
+       0xED4, 0x631B25A0,
+       0xED8, 0x631B25A0,
+       0xEDC, 0x001B25A0,
+       0xEE0, 0x001B25A0,
+       0xEEC, 0x6B1B25A0,
+       0xF14, 0x00000003,
+       0xF4C, 0x00000000,
+       0xF00, 0x00000300,
+};
+
+void ODM_ReadAndConfig_PHY_REG_1T_8723A(struct dm_odm_t *pDM_Odm)
+{
+       u32 hex = 0;
+       u32 i = 0;
+       u8  platform = 0x04;
+       u8  interfaceValue = pDM_Odm->SupportInterface;
+       u8  board = pDM_Odm->BoardType;
+       u32 ArrayLen = sizeof(Array_PHY_REG_1T_8723A)/sizeof(u32);
+       u32 *Array = Array_PHY_REG_1T_8723A;
+
+       hex += board;
+       hex += interfaceValue << 8;
+       hex += platform << 16;
+       hex += 0xFF000000;
+       for (i = 0; i < ArrayLen; i += 2) {
+               u32 v1 = Array[i];
+               u32 v2 = Array[i+1];
+
+               /*  This (offset, data) pair meets the condition. */
+               if (v1 < 0xCDCDCDCD) {
+                       odm_ConfigBB_PHY_8723A(pDM_Odm, v1, bMaskDWord, v2);
+                       continue;
+               } else {
+                       if (!CheckCondition(Array[i], hex)) {
+                               /*  Discard the following (offset, data) pairs. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               i -= 2; /*  prevent from for-loop += 2 */
+                       } else {
+                               /*  Configure matched pairs and skip to end of if-else. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2) {
+                                       odm_ConfigBB_PHY_8723A(pDM_Odm, v1, bMaskDWord, v2);
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               }
+                               while (v2 != 0xDEAD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                       }
+               }
+       }
+}
+
+/******************************************************************************
+*                           PHY_REG_MP.TXT
+******************************************************************************/
+
+static u32 Array_PHY_REG_MP_8723A[] = {
+       0xC30, 0x69E9AC4A,
+       0xC3C, 0x0A979718,
+};
+
+void ODM_ReadAndConfig_PHY_REG_MP_8723A(struct dm_odm_t *pDM_Odm)
+{
+       u32     hex         = 0;
+       u32     i           = 0;
+       u8     platform    = 0x04;
+       u8     interfaceValue   = pDM_Odm->SupportInterface;
+       u8     board       = pDM_Odm->BoardType;
+       u32     ArrayLen    = sizeof(Array_PHY_REG_MP_8723A)/sizeof(u32);
+       u32 *Array       = Array_PHY_REG_MP_8723A;
+
+       hex += board;
+       hex += interfaceValue << 8;
+       hex += platform << 16;
+       hex += 0xFF000000;
+       for (i = 0; i < ArrayLen; i += 2) {
+               u32 v1 = Array[i];
+               u32 v2 = Array[i+1];
+
+               /*  This (offset, data) pair meets the condition. */
+               if (v1 < 0xCDCDCDCD) {
+                       odm_ConfigBB_PHY_8723A(pDM_Odm, v1, bMaskDWord, v2);
+                       continue;
+               } else {
+                       if (!CheckCondition(Array[i], hex)) {
+                               /* Discard the following (offset, data) pairs. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               i -= 2; /*  prevent from for-loop += 2 */
+                       } else {
+                               /* Configure matched pairs and skip to end of if-else. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2) {
+                                       odm_ConfigBB_PHY_8723A(pDM_Odm, v1, bMaskDWord, v2);
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               }
+                               while (v2 != 0xDEAD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                       }
+               }
+       }
+}
+
+/******************************************************************************
+*                           PHY_REG_PG.TXT
+******************************************************************************/
+
+static u32 Array_PHY_REG_PG_8723A[] = {
+       0xE00, 0xFFFFFFFF, 0x0A0C0C0C,
+       0xE04, 0xFFFFFFFF, 0x02040608,
+       0xE08, 0x0000FF00, 0x00000000,
+       0x86C, 0xFFFFFF00, 0x00000000,
+       0xE10, 0xFFFFFFFF, 0x0A0C0D0E,
+       0xE14, 0xFFFFFFFF, 0x02040608,
+       0xE18, 0xFFFFFFFF, 0x0A0C0D0E,
+       0xE1C, 0xFFFFFFFF, 0x02040608,
+       0x830, 0xFFFFFFFF, 0x0A0C0C0C,
+       0x834, 0xFFFFFFFF, 0x02040608,
+       0x838, 0xFFFFFF00, 0x00000000,
+       0x86C, 0x000000FF, 0x00000000,
+       0x83C, 0xFFFFFFFF, 0x0A0C0D0E,
+       0x848, 0xFFFFFFFF, 0x02040608,
+       0x84C, 0xFFFFFFFF, 0x0A0C0D0E,
+       0x868, 0xFFFFFFFF, 0x02040608,
+       0xE00, 0xFFFFFFFF, 0x00000000,
+       0xE04, 0xFFFFFFFF, 0x00000000,
+       0xE08, 0x0000FF00, 0x00000000,
+       0x86C, 0xFFFFFF00, 0x00000000,
+       0xE10, 0xFFFFFFFF, 0x00000000,
+       0xE14, 0xFFFFFFFF, 0x00000000,
+       0xE18, 0xFFFFFFFF, 0x00000000,
+       0xE1C, 0xFFFFFFFF, 0x00000000,
+       0x830, 0xFFFFFFFF, 0x00000000,
+       0x834, 0xFFFFFFFF, 0x00000000,
+       0x838, 0xFFFFFF00, 0x00000000,
+       0x86C, 0x000000FF, 0x00000000,
+       0x83C, 0xFFFFFFFF, 0x00000000,
+       0x848, 0xFFFFFFFF, 0x00000000,
+       0x84C, 0xFFFFFFFF, 0x00000000,
+       0x868, 0xFFFFFFFF, 0x00000000,
+       0xE00, 0xFFFFFFFF, 0x04040404,
+       0xE04, 0xFFFFFFFF, 0x00020204,
+       0xE08, 0x0000FF00, 0x00000000,
+       0x86C, 0xFFFFFF00, 0x00000000,
+       0xE10, 0xFFFFFFFF, 0x06060606,
+       0xE14, 0xFFFFFFFF, 0x00020406,
+       0xE18, 0xFFFFFFFF, 0x00000000,
+       0xE1C, 0xFFFFFFFF, 0x00000000,
+       0x830, 0xFFFFFFFF, 0x04040404,
+       0x834, 0xFFFFFFFF, 0x00020204,
+       0x838, 0xFFFFFF00, 0x00000000,
+       0x86C, 0x000000FF, 0x00000000,
+       0x83C, 0xFFFFFFFF, 0x06060606,
+       0x848, 0xFFFFFFFF, 0x00020406,
+       0x84C, 0xFFFFFFFF, 0x00000000,
+       0x868, 0xFFFFFFFF, 0x00000000,
+       0xE00, 0xFFFFFFFF, 0x00000000,
+       0xE04, 0xFFFFFFFF, 0x00000000,
+       0xE08, 0x0000FF00, 0x00000000,
+       0x86C, 0xFFFFFF00, 0x00000000,
+       0xE10, 0xFFFFFFFF, 0x00000000,
+       0xE14, 0xFFFFFFFF, 0x00000000,
+       0xE18, 0xFFFFFFFF, 0x00000000,
+       0xE1C, 0xFFFFFFFF, 0x00000000,
+       0x830, 0xFFFFFFFF, 0x00000000,
+       0x834, 0xFFFFFFFF, 0x00000000,
+       0x838, 0xFFFFFF00, 0x00000000,
+       0x86C, 0x000000FF, 0x00000000,
+       0x83C, 0xFFFFFFFF, 0x00000000,
+       0x848, 0xFFFFFFFF, 0x00000000,
+       0x84C, 0xFFFFFFFF, 0x00000000,
+       0x868, 0xFFFFFFFF, 0x00000000,
+       0xE00, 0xFFFFFFFF, 0x00000000,
+       0xE04, 0xFFFFFFFF, 0x00000000,
+       0xE08, 0x0000FF00, 0x00000000,
+       0x86C, 0xFFFFFF00, 0x00000000,
+       0xE10, 0xFFFFFFFF, 0x00000000,
+       0xE14, 0xFFFFFFFF, 0x00000000,
+       0xE18, 0xFFFFFFFF, 0x00000000,
+       0xE1C, 0xFFFFFFFF, 0x00000000,
+       0x830, 0xFFFFFFFF, 0x00000000,
+       0x834, 0xFFFFFFFF, 0x00000000,
+       0x838, 0xFFFFFF00, 0x00000000,
+       0x86C, 0x000000FF, 0x00000000,
+       0x83C, 0xFFFFFFFF, 0x00000000,
+       0x848, 0xFFFFFFFF, 0x00000000,
+       0x84C, 0xFFFFFFFF, 0x00000000,
+       0x868, 0xFFFFFFFF, 0x00000000,
+       0xE00, 0xFFFFFFFF, 0x04040404,
+       0xE04, 0xFFFFFFFF, 0x00020204,
+       0xE08, 0x0000FF00, 0x00000000,
+       0x86C, 0xFFFFFF00, 0x00000000,
+       0xE10, 0xFFFFFFFF, 0x00000000,
+       0xE14, 0xFFFFFFFF, 0x00000000,
+       0xE18, 0xFFFFFFFF, 0x00000000,
+       0xE1C, 0xFFFFFFFF, 0x00000000,
+       0x830, 0xFFFFFFFF, 0x04040404,
+       0x834, 0xFFFFFFFF, 0x00020204,
+       0x838, 0xFFFFFF00, 0x00000000,
+       0x86C, 0x000000FF, 0x00000000,
+       0x83C, 0xFFFFFFFF, 0x00000000,
+       0x848, 0xFFFFFFFF, 0x00000000,
+       0x84C, 0xFFFFFFFF, 0x00000000,
+       0x868, 0xFFFFFFFF, 0x00000000,
+       0xE00, 0xFFFFFFFF, 0x00000000,
+       0xE04, 0xFFFFFFFF, 0x00000000,
+       0xE08, 0x0000FF00, 0x00000000,
+       0x86C, 0xFFFFFF00, 0x00000000,
+       0xE10, 0xFFFFFFFF, 0x00000000,
+       0xE14, 0xFFFFFFFF, 0x00000000,
+       0xE18, 0xFFFFFFFF, 0x00000000,
+       0xE1C, 0xFFFFFFFF, 0x00000000,
+       0x830, 0xFFFFFFFF, 0x00000000,
+       0x834, 0xFFFFFFFF, 0x00000000,
+       0x838, 0xFFFFFF00, 0x00000000,
+       0x86C, 0x000000FF, 0x00000000,
+       0x83C, 0xFFFFFFFF, 0x00000000,
+       0x848, 0xFFFFFFFF, 0x00000000,
+       0x84C, 0xFFFFFFFF, 0x00000000,
+       0x868, 0xFFFFFFFF, 0x00000000,
+};
+
+void ODM_ReadAndConfig_PHY_REG_PG_8723A(struct dm_odm_t *pDM_Odm)
+{
+       u32     hex = 0;
+       u32     i           = 0;
+       u8     platform    = 0x04;
+       u8     interfaceValue   = pDM_Odm->SupportInterface;
+       u8     board       = pDM_Odm->BoardType;
+       u32     ArrayLen    = sizeof(Array_PHY_REG_PG_8723A)/sizeof(u32);
+       u32 *Array       = Array_PHY_REG_PG_8723A;
+
+       hex += board;
+       hex += interfaceValue << 8;
+       hex += platform << 16;
+       hex += 0xFF000000;
+       for (i = 0; i < ArrayLen; i += 3) {
+               u32 v1 = Array[i];
+               u32 v2 = Array[i+1];
+               u32 v3 = Array[i+2];
+
+               /*  this line is a line of pure_body */
+               if (v1 < 0xCDCDCDCD) {
+                        odm_ConfigBB_PHY_REG_PG_8723A(pDM_Odm, v1, v2, v3);
+                        continue;
+               } else { /*  this line is the start of branch */
+                       if (!CheckCondition(Array[i], hex)) {
+                               /*  don't need the hw_body */
+                               i += 2; /*  skip the pair of expression */
+                               v1 = Array[i];
+                               v2 = Array[i+1];
+                               v3 = Array[i+2];
+                               while (v2 != 0xDEAD) {
+                                       i += 3;
+                                       v1 = Array[i];
+                                       v2 = Array[i+1];
+                                       v3 = Array[i+1];
+                               }
+                       }
+               }
+       }
+}
diff --git a/drivers/staging/rtl8723au/hal/HalHWImg8723A_MAC.c b/drivers/staging/rtl8723au/hal/HalHWImg8723A_MAC.c
new file mode 100644 (file)
index 0000000..1207145
--- /dev/null
@@ -0,0 +1,188 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License 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 "odm_precomp.h"
+
+static bool CheckCondition(const u32  Condition, const u32  Hex)
+{
+       u32 _board     = (Hex & 0x000000FF);
+       u32 _interface = (Hex & 0x0000FF00) >> 8;
+       u32 _platform  = (Hex & 0x00FF0000) >> 16;
+       u32 cond = Condition;
+
+       if (Condition == 0xCDCDCDCD)
+               return true;
+
+       cond = Condition & 0x000000FF;
+       if ((_board == cond) && cond != 0x00)
+               return false;
+
+       cond = Condition & 0x0000FF00;
+       cond = cond >> 8;
+       if ((_interface & cond) == 0 && cond != 0x07)
+               return false;
+
+       cond = Condition & 0x00FF0000;
+       cond = cond >> 16;
+       if ((_platform & cond) == 0 && cond != 0x0F)
+               return false;
+       return true;
+}
+
+/******************************************************************************
+*                           MAC_REG.TXT
+******************************************************************************/
+
+static u32 Array_MAC_REG_8723A[] = {
+               0x420, 0x00000080,
+               0x423, 0x00000000,
+               0x430, 0x00000000,
+               0x431, 0x00000000,
+               0x432, 0x00000000,
+               0x433, 0x00000001,
+               0x434, 0x00000004,
+               0x435, 0x00000005,
+               0x436, 0x00000006,
+               0x437, 0x00000007,
+               0x438, 0x00000000,
+               0x439, 0x00000000,
+               0x43A, 0x00000000,
+               0x43B, 0x00000001,
+               0x43C, 0x00000004,
+               0x43D, 0x00000005,
+               0x43E, 0x00000006,
+               0x43F, 0x00000007,
+               0x440, 0x0000005D,
+               0x441, 0x00000001,
+               0x442, 0x00000000,
+               0x444, 0x00000015,
+               0x445, 0x000000F0,
+               0x446, 0x0000000F,
+               0x447, 0x00000000,
+               0x458, 0x00000041,
+               0x459, 0x000000A8,
+               0x45A, 0x00000072,
+               0x45B, 0x000000B9,
+               0x460, 0x00000066,
+               0x461, 0x00000066,
+               0x462, 0x00000008,
+               0x463, 0x00000003,
+               0x4C8, 0x000000FF,
+               0x4C9, 0x00000008,
+               0x4CC, 0x000000FF,
+               0x4CD, 0x000000FF,
+               0x4CE, 0x00000001,
+               0x500, 0x00000026,
+               0x501, 0x000000A2,
+               0x502, 0x0000002F,
+               0x503, 0x00000000,
+               0x504, 0x00000028,
+               0x505, 0x000000A3,
+               0x506, 0x0000005E,
+               0x507, 0x00000000,
+               0x508, 0x0000002B,
+               0x509, 0x000000A4,
+               0x50A, 0x0000005E,
+               0x50B, 0x00000000,
+               0x50C, 0x0000004F,
+               0x50D, 0x000000A4,
+               0x50E, 0x00000000,
+               0x50F, 0x00000000,
+               0x512, 0x0000001C,
+               0x514, 0x0000000A,
+               0x515, 0x00000010,
+               0x516, 0x0000000A,
+               0x517, 0x00000010,
+               0x51A, 0x00000016,
+               0x524, 0x0000000F,
+               0x525, 0x0000004F,
+               0x546, 0x00000040,
+               0x547, 0x00000000,
+               0x550, 0x00000010,
+               0x551, 0x00000010,
+               0x559, 0x00000002,
+               0x55A, 0x00000002,
+               0x55D, 0x000000FF,
+               0x605, 0x00000030,
+               0x608, 0x0000000E,
+               0x609, 0x0000002A,
+               0x652, 0x00000020,
+               0x63C, 0x0000000A,
+               0x63D, 0x0000000A,
+               0x63E, 0x0000000E,
+               0x63F, 0x0000000E,
+               0x66E, 0x00000005,
+               0x700, 0x00000021,
+               0x701, 0x00000043,
+               0x702, 0x00000065,
+               0x703, 0x00000087,
+               0x708, 0x00000021,
+               0x709, 0x00000043,
+               0x70A, 0x00000065,
+               0x70B, 0x00000087,
+};
+
+void ODM_ReadAndConfig_MAC_REG_8723A(struct dm_odm_t *pDM_Odm)
+{
+       #define READ_NEXT_PAIR(v1, v2, i)                       \
+                do {                                           \
+                       i += 2; v1 = Array[i]; v2 = Array[i+1]; \
+                } while (0)
+
+       u32     hex         = 0;
+       u32     i           = 0;
+       u8     platform    = 0x04;
+       u8     interfaceValue   = pDM_Odm->SupportInterface;
+       u8     board       = pDM_Odm->BoardType;
+       u32     ArrayLen    = sizeof(Array_MAC_REG_8723A)/sizeof(u32);
+       u32 *Array       = Array_MAC_REG_8723A;
+
+       hex += board;
+       hex += interfaceValue << 8;
+       hex += platform << 16;
+       hex += 0xFF000000;
+       for (i = 0; i < ArrayLen; i += 2) {
+               u32 v1 = Array[i];
+               u32 v2 = Array[i+1];
+
+               /*  This (offset, data) pair meets the condition. */
+               if (v1 < 0xCDCDCDCD) {
+                       odm_ConfigMAC_8723A(pDM_Odm, v1, (u8)v2);
+                       continue;
+               } else {
+                       if (!CheckCondition(Array[i], hex)) {
+                               /* Discard the following (offset, data) pairs. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               i -= 2; /*  prevent from for-loop += 2 */
+                       } else {
+                               /*  Configure matched pairs and skip to end of if-else. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2) {
+                                       odm_ConfigMAC_8723A(pDM_Odm, v1, (u8)v2);
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               }
+
+                               while (v2 != 0xDEAD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                       }
+               }
+       }
+}
diff --git a/drivers/staging/rtl8723au/hal/HalHWImg8723A_RF.c b/drivers/staging/rtl8723au/hal/HalHWImg8723A_RF.c
new file mode 100644 (file)
index 0000000..0f2ae05
--- /dev/null
@@ -0,0 +1,259 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License 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 "odm_precomp.h"
+
+static bool CheckCondition(const u32  Condition, const u32  Hex)
+{
+       u32 _board     = (Hex & 0x000000FF);
+       u32 _interface = (Hex & 0x0000FF00) >> 8;
+       u32 _platform  = (Hex & 0x00FF0000) >> 16;
+       u32 cond = Condition;
+
+       if (Condition == 0xCDCDCDCD)
+               return true;
+
+       cond = Condition & 0x000000FF;
+       if ((_board == cond) && cond != 0x00)
+               return false;
+
+       cond = Condition & 0x0000FF00;
+       cond = cond >> 8;
+       if ((_interface & cond) == 0 && cond != 0x07)
+               return false;
+
+       cond = Condition & 0x00FF0000;
+       cond = cond >> 16;
+       if ((_platform & cond) == 0 && cond != 0x0F)
+               return false;
+       return true;
+}
+
+/******************************************************************************
+*                           RadioA_1T.TXT
+******************************************************************************/
+
+static u32 Array_RadioA_1T_8723A[] = {
+       0x000, 0x00030159,
+       0x001, 0x00031284,
+       0x002, 0x00098000,
+       0xFF0F011F, 0xABCD,
+       0x003, 0x00018C63,
+       0xCDCDCDCD, 0xCDCD,
+       0x003, 0x00039C63,
+       0xFF0F011F, 0xDEAD,
+       0x004, 0x000210E7,
+       0x009, 0x0002044F,
+       0x00A, 0x0001A3F1,
+       0x00B, 0x00014787,
+       0x00C, 0x000896FE,
+       0x00D, 0x0000E02C,
+       0x00E, 0x00039CE7,
+       0x00F, 0x00000451,
+       0x019, 0x00000000,
+       0x01A, 0x00030355,
+       0x01B, 0x00060A00,
+       0x01C, 0x000FC378,
+       0x01D, 0x000A1250,
+       0x01E, 0x0000024F,
+       0x01F, 0x00000000,
+       0x020, 0x0000B614,
+       0x021, 0x0006C000,
+       0x022, 0x00000000,
+       0x023, 0x00001558,
+       0x024, 0x00000060,
+       0x025, 0x00000483,
+       0x026, 0x0004F000,
+       0x027, 0x000EC7D9,
+       0x028, 0x00057730,
+       0x029, 0x00004783,
+       0x02A, 0x00000001,
+       0x02B, 0x00021334,
+       0x02A, 0x00000000,
+       0x02B, 0x00000054,
+       0x02A, 0x00000001,
+       0x02B, 0x00000808,
+       0x02B, 0x00053333,
+       0x02C, 0x0000000C,
+       0x02A, 0x00000002,
+       0x02B, 0x00000808,
+       0x02B, 0x0005B333,
+       0x02C, 0x0000000D,
+       0x02A, 0x00000003,
+       0x02B, 0x00000808,
+       0x02B, 0x00063333,
+       0x02C, 0x0000000D,
+       0x02A, 0x00000004,
+       0x02B, 0x00000808,
+       0x02B, 0x0006B333,
+       0x02C, 0x0000000D,
+       0x02A, 0x00000005,
+       0x02B, 0x00000808,
+       0x02B, 0x00073333,
+       0x02C, 0x0000000D,
+       0x02A, 0x00000006,
+       0x02B, 0x00000709,
+       0x02B, 0x0005B333,
+       0x02C, 0x0000000D,
+       0x02A, 0x00000007,
+       0x02B, 0x00000709,
+       0x02B, 0x00063333,
+       0x02C, 0x0000000D,
+       0x02A, 0x00000008,
+       0x02B, 0x0000060A,
+       0x02B, 0x0004B333,
+       0x02C, 0x0000000D,
+       0x02A, 0x00000009,
+       0x02B, 0x0000060A,
+       0x02B, 0x00053333,
+       0x02C, 0x0000000D,
+       0x02A, 0x0000000A,
+       0x02B, 0x0000060A,
+       0x02B, 0x0005B333,
+       0x02C, 0x0000000D,
+       0x02A, 0x0000000B,
+       0x02B, 0x0000060A,
+       0x02B, 0x00063333,
+       0x02C, 0x0000000D,
+       0x02A, 0x0000000C,
+       0x02B, 0x0000060A,
+       0x02B, 0x0006B333,
+       0x02C, 0x0000000D,
+       0x02A, 0x0000000D,
+       0x02B, 0x0000060A,
+       0x02B, 0x00073333,
+       0x02C, 0x0000000D,
+       0x02A, 0x0000000E,
+       0x02B, 0x0000050B,
+       0x02B, 0x00066666,
+       0x02C, 0x0000001A,
+       0x02A, 0x000E0000,
+       0x010, 0x0004000F,
+       0x011, 0x000E31FC,
+       0x010, 0x0006000F,
+       0x011, 0x000FF9F8,
+       0x010, 0x0002000F,
+       0x011, 0x000203F9,
+       0x010, 0x0003000F,
+       0x011, 0x000FF500,
+       0x010, 0x00000000,
+       0x011, 0x00000000,
+       0x010, 0x0008000F,
+       0x011, 0x0003F100,
+       0x010, 0x0009000F,
+       0x011, 0x00023100,
+       0x012, 0x00032000,
+       0x012, 0x00071000,
+       0x012, 0x000B0000,
+       0x012, 0x000FC000,
+       0x013, 0x000287B3,
+       0x013, 0x000244B7,
+       0x013, 0x000204AB,
+       0x013, 0x0001C49F,
+       0x013, 0x00018493,
+       0x013, 0x0001429B,
+       0x013, 0x00010299,
+       0x013, 0x0000C29C,
+       0x013, 0x000081A0,
+       0x013, 0x000040AC,
+       0x013, 0x00000020,
+       0x014, 0x0001944C,
+       0x014, 0x00059444,
+       0x014, 0x0009944C,
+       0x014, 0x000D9444,
+       0xFF0F011F, 0xABCD,
+       0x015, 0x0000F424,
+       0x015, 0x0004F424,
+       0x015, 0x0008F424,
+       0x015, 0x000CF424,
+       0xCDCDCDCD, 0xCDCD,
+       0x015, 0x0000F474,
+       0x015, 0x0004F477,
+       0x015, 0x0008F455,
+       0x015, 0x000CF455,
+       0xFF0F011F, 0xDEAD,
+       0x016, 0x00000339,
+       0x016, 0x00040339,
+       0x016, 0x00080339,
+       0xFF0F011F, 0xABCD,
+       0x016, 0x000C0356,
+       0xCDCDCDCD, 0xCDCD,
+       0x016, 0x000C0366,
+       0xFF0F011F, 0xDEAD,
+       0x000, 0x00010159,
+       0x018, 0x0000F401,
+       0x0FE, 0x00000000,
+       0x0FE, 0x00000000,
+       0x01F, 0x00000003,
+       0x0FE, 0x00000000,
+       0x0FE, 0x00000000,
+       0x01E, 0x00000247,
+       0x01F, 0x00000000,
+       0x000, 0x00030159,
+};
+
+void ODM_ReadAndConfig_RadioA_1T_8723A(struct dm_odm_t *pDM_Odm)
+{
+       #define READ_NEXT_PAIR(v1, v2, i)                       \
+                do {                                           \
+                        i += 2; v1 = Array[i]; v2 = Array[i+1];\
+                } while (0)
+
+       u32     hex         = 0;
+       u32     i           = 0;
+       u8     platform    = 0x04;
+       u8     interfaceValue   = pDM_Odm->SupportInterface;
+       u8     board       = pDM_Odm->BoardType;
+       u32     ArrayLen    = sizeof(Array_RadioA_1T_8723A)/sizeof(u32);
+       u32 *Array = Array_RadioA_1T_8723A;
+
+       hex += board;
+       hex += interfaceValue << 8;
+       hex += platform << 16;
+       hex += 0xFF000000;
+
+       for (i = 0; i < ArrayLen; i += 2) {
+               u32 v1 = Array[i];
+               u32 v2 = Array[i+1];
+
+               /*  This (offset, data) pair meets the condition. */
+               if (v1 < 0xCDCDCDCD) {
+                       odm_ConfigRF_RadioA_8723A(pDM_Odm, v1, v2);
+                       continue;
+               } else {
+                       if (!CheckCondition(Array[i], hex)) {
+                               /*  Discard the following (offset, data) pairs. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               i -= 2; /*  prevent from for-loop += 2 */
+                       } else {
+                               /*  Configure matched pairs and skip to end of if-else. */
+                               READ_NEXT_PAIR(v1, v2, i);
+                               while (v2 != 0xDEAD &&
+                                      v2 != 0xCDEF &&
+                                      v2 != 0xCDCD && i < ArrayLen - 2) {
+                                       odm_ConfigRF_RadioA_8723A(pDM_Odm, v1, v2);
+                                       READ_NEXT_PAIR(v1, v2, i);
+                               }
+
+                               while (v2 != 0xDEAD && i < ArrayLen - 2)
+                                       READ_NEXT_PAIR(v1, v2, i);
+                       }
+               }
+       }
+}
diff --git a/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c b/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c
new file mode 100644 (file)
index 0000000..4f6b4b7
--- /dev/null
@@ -0,0 +1,163 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+/*++
+Copyright (c) Realtek Semiconductor Corp. All rights reserved.
+
+Module Name:
+       HalPwrSeqCmd.c
+
+Abstract:
+       Implement HW Power sequence configuration CMD handling routine for
+       Realtek devices.
+
+Major Change History:
+       When       Who               What
+       ---------- ---------------   -------------------------------
+       2011-10-26 Lucas            Modify to be compatible with SD4-CE driver.
+       2011-07-07 Roger            Create.
+
+--*/
+#include <HalPwrSeqCmd.h>
+
+/*  */
+/*     Description: */
+/*             This routine deal with the Power Configuration CMDs parsing
+               for RTL8723/RTL8188E Series IC. */
+/*  */
+/*     Assumption: */
+/*             We should follow specific format which was released from
+               HW SD. */
+/*  */
+/*     2011.07.07, added by Roger. */
+/*  */
+u8 HalPwrSeqCmdParsing23a(struct rtw_adapter *padapter, u8 CutVersion,
+                      u8 FabVersion, u8 InterfaceType,
+                      struct wlan_pwr_cfg PwrSeqCmd[])
+{
+       struct wlan_pwr_cfg PwrCfgCmd = { 0 };
+       u8 bPollingBit = false;
+       u32 AryIdx = 0;
+       u8 value = 0;
+       u32 offset = 0;
+       u32 pollingCount = 0;   /*  polling autoload done. */
+       u32 maxPollingCnt = 5000;
+
+       do {
+               PwrCfgCmd = PwrSeqCmd[AryIdx];
+
+               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                        ("HalPwrSeqCmdParsing23a: offset(%#x) cut_msk(%#x) "
+                         "fab_msk(%#x) interface_msk(%#x) base(%#x) cmd(%#x) "
+                         "msk(%#x) value(%#x)\n",
+                         GET_PWR_CFG_OFFSET(PwrCfgCmd),
+                         GET_PWR_CFG_CUT_MASK(PwrCfgCmd),
+                         GET_PWR_CFG_FAB_MASK(PwrCfgCmd),
+                         GET_PWR_CFG_INTF_MASK(PwrCfgCmd),
+                         GET_PWR_CFG_BASE(PwrCfgCmd),
+                         GET_PWR_CFG_CMD(PwrCfgCmd),
+                         GET_PWR_CFG_MASK(PwrCfgCmd),
+                         GET_PWR_CFG_VALUE(PwrCfgCmd)));
+
+               /* 2 Only Handle the command whose FAB, CUT, and Interface are
+                  matched */
+               if ((GET_PWR_CFG_FAB_MASK(PwrCfgCmd) & FabVersion) &&
+                   (GET_PWR_CFG_CUT_MASK(PwrCfgCmd) & CutVersion) &&
+                   (GET_PWR_CFG_INTF_MASK(PwrCfgCmd) & InterfaceType)) {
+                       switch (GET_PWR_CFG_CMD(PwrCfgCmd)) {
+                       case PWR_CMD_READ:
+                               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                                        ("HalPwrSeqCmdParsing23a: "
+                                         "PWR_CMD_READ\n"));
+                               break;
+
+                       case PWR_CMD_WRITE:
+                               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                                        ("HalPwrSeqCmdParsing23a: "
+                                         "PWR_CMD_WRITE\n"));
+                               offset = GET_PWR_CFG_OFFSET(PwrCfgCmd);
+
+                               /*  Read the value from system register */
+                               value = rtw_read8(padapter, offset);
+
+                               value &= ~(GET_PWR_CFG_MASK(PwrCfgCmd));
+                               value |= (GET_PWR_CFG_VALUE(PwrCfgCmd) &
+                                         GET_PWR_CFG_MASK(PwrCfgCmd));
+
+                               /*  Write the value back to sytem register */
+                               rtw_write8(padapter, offset, value);
+                               break;
+
+                       case PWR_CMD_POLLING:
+                               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                                        ("HalPwrSeqCmdParsing23a: "
+                                         "PWR_CMD_POLLING\n"));
+
+                               bPollingBit = false;
+                               offset = GET_PWR_CFG_OFFSET(PwrCfgCmd);
+                               do {
+                                       value = rtw_read8(padapter, offset);
+
+                                       value &= GET_PWR_CFG_MASK(PwrCfgCmd);
+                                       if (value ==
+                                           (GET_PWR_CFG_VALUE(PwrCfgCmd) &
+                                            GET_PWR_CFG_MASK(PwrCfgCmd)))
+                                               bPollingBit = true;
+                                       else
+                                               udelay(10);
+
+                                       if (pollingCount++ > maxPollingCnt) {
+                                               DBG_8723A("Fail to polling "
+                                                         "Offset[%#x]\n",
+                                                         offset);
+                                               return false;
+                                       }
+                               } while (!bPollingBit);
+
+                               break;
+
+                       case PWR_CMD_DELAY:
+                               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                                        ("HalPwrSeqCmdParsing23a: "
+                                         "PWR_CMD_DELAY\n"));
+                               if (GET_PWR_CFG_VALUE(PwrCfgCmd) ==
+                                   PWRSEQ_DELAY_US)
+                                       udelay(GET_PWR_CFG_OFFSET(PwrCfgCmd));
+                               else
+                                       udelay(GET_PWR_CFG_OFFSET(PwrCfgCmd) *
+                                              1000);
+                               break;
+
+                       case PWR_CMD_END:
+                               /*  When this command is parsed, end
+                                   the process */
+                               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                                        ("HalPwrSeqCmdParsing23a: "
+                                         "PWR_CMD_END\n"));
+                               return true;
+                               break;
+
+                       default:
+                               RT_TRACE(_module_hal_init_c_, _drv_err_,
+                                        ("HalPwrSeqCmdParsing23a: "
+                                         "Unknown CMD!!\n"));
+                               break;
+                       }
+               }
+
+               AryIdx++;       /* Add Array Index */
+       } while (1);
+
+       return true;
+}
diff --git a/drivers/staging/rtl8723au/hal/hal_com.c b/drivers/staging/rtl8723au/hal/hal_com.c
new file mode 100644 (file)
index 0000000..0640f35
--- /dev/null
@@ -0,0 +1,881 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 <osdep_service.h>
+#include <drv_types.h>
+
+#include <hal_intf.h>
+#include <hal_com.h>
+#include <rtl8723a_hal.h>
+
+#define _HAL_INIT_C_
+
+void dump_chip_info23a(struct hal_version ChipVersion)
+{
+       int cnt = 0;
+       u8 buf[128];
+
+       cnt += sprintf((buf + cnt), "Chip Version Info: CHIP_8723A_");
+
+       cnt += sprintf((buf + cnt), "%s_", IS_NORMAL_CHIP(ChipVersion) ?
+                      "Normal_Chip" : "Test_Chip");
+       cnt += sprintf((buf + cnt), "%s_",
+                      IS_CHIP_VENDOR_TSMC(ChipVersion) ? "TSMC" : "UMC");
+       if (IS_A_CUT(ChipVersion))
+               cnt += sprintf((buf + cnt), "A_CUT_");
+       else if (IS_B_CUT(ChipVersion))
+               cnt += sprintf((buf + cnt), "B_CUT_");
+       else if (IS_C_CUT(ChipVersion))
+               cnt += sprintf((buf + cnt), "C_CUT_");
+       else if (IS_D_CUT(ChipVersion))
+               cnt += sprintf((buf + cnt), "D_CUT_");
+       else if (IS_E_CUT(ChipVersion))
+               cnt += sprintf((buf + cnt), "E_CUT_");
+       else
+               cnt += sprintf((buf + cnt), "UNKNOWN_CUT(%d)_",
+                              ChipVersion.CUTVersion);
+
+       if (IS_1T1R(ChipVersion))
+               cnt += sprintf((buf + cnt), "1T1R_");
+       else if (IS_1T2R(ChipVersion))
+               cnt += sprintf((buf + cnt), "1T2R_");
+       else if (IS_2T2R(ChipVersion))
+               cnt += sprintf((buf + cnt), "2T2R_");
+       else
+               cnt += sprintf((buf + cnt), "UNKNOWN_RFTYPE(%d)_",
+                              ChipVersion.RFType);
+
+       cnt += sprintf((buf + cnt), "RomVer(%d)\n", ChipVersion.ROMVer);
+
+       DBG_8723A("%s", buf);
+}
+
+#define        EEPROM_CHANNEL_PLAN_BY_HW_MASK  0x80
+
+/* return the final channel plan decision */
+/* hw_channel_plan:  channel plan from HW (efuse/eeprom) */
+/* sw_channel_plan:  channel plan from SW (registry/module param) */
+/* def_channel_plan: channel plan used when the former two is invalid */
+u8 hal_com_get_channel_plan23a(struct rtw_adapter *padapter, u8 hw_channel_plan,
+                           u8 sw_channel_plan, u8 def_channel_plan,
+                           bool AutoLoadFail)
+{
+       u8 swConfig;
+       u8 chnlPlan;
+
+       swConfig = true;
+       if (!AutoLoadFail) {
+               if (!rtw_is_channel_plan_valid(sw_channel_plan))
+                       swConfig = false;
+               if (hw_channel_plan & EEPROM_CHANNEL_PLAN_BY_HW_MASK)
+                       swConfig = false;
+       }
+
+       if (swConfig == true)
+               chnlPlan = sw_channel_plan;
+       else
+               chnlPlan = hw_channel_plan & (~EEPROM_CHANNEL_PLAN_BY_HW_MASK);
+
+       if (!rtw_is_channel_plan_valid(chnlPlan))
+               chnlPlan = def_channel_plan;
+
+       return chnlPlan;
+}
+
+u8 MRateToHwRate23a(u8 rate)
+{
+       u8 ret = DESC_RATE1M;
+
+       switch (rate) {
+               /*  CCK and OFDM non-HT rates */
+       case IEEE80211_CCK_RATE_1MB:
+               ret = DESC_RATE1M;
+               break;
+       case IEEE80211_CCK_RATE_2MB:
+               ret = DESC_RATE2M;
+               break;
+       case IEEE80211_CCK_RATE_5MB:
+               ret = DESC_RATE5_5M;
+               break;
+       case IEEE80211_CCK_RATE_11MB:
+               ret = DESC_RATE11M;
+               break;
+       case IEEE80211_OFDM_RATE_6MB:
+               ret = DESC_RATE6M;
+               break;
+       case IEEE80211_OFDM_RATE_9MB:
+               ret = DESC_RATE9M;
+               break;
+       case IEEE80211_OFDM_RATE_12MB:
+               ret = DESC_RATE12M;
+               break;
+       case IEEE80211_OFDM_RATE_18MB:
+               ret = DESC_RATE18M;
+               break;
+       case IEEE80211_OFDM_RATE_24MB:
+               ret = DESC_RATE24M;
+               break;
+       case IEEE80211_OFDM_RATE_36MB:
+               ret = DESC_RATE36M;
+               break;
+       case IEEE80211_OFDM_RATE_48MB:
+               ret = DESC_RATE48M;
+               break;
+       case IEEE80211_OFDM_RATE_54MB:
+               ret = DESC_RATE54M;
+               break;
+
+               /*  HT rates since here */
+               /* case MGN_MCS0:       ret = DESC_RATEMCS0;    break; */
+               /* case MGN_MCS1:       ret = DESC_RATEMCS1;    break; */
+               /* case MGN_MCS2:       ret = DESC_RATEMCS2;    break; */
+               /* case MGN_MCS3:       ret = DESC_RATEMCS3;    break; */
+               /* case MGN_MCS4:       ret = DESC_RATEMCS4;    break; */
+               /* case MGN_MCS5:       ret = DESC_RATEMCS5;    break; */
+               /* case MGN_MCS6:       ret = DESC_RATEMCS6;    break; */
+               /* case MGN_MCS7:       ret = DESC_RATEMCS7;    break; */
+
+       default:
+               break;
+       }
+       return ret;
+}
+
+void HalSetBrateCfg23a(struct rtw_adapter *padapter, u8 *mBratesOS)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 i, is_brate, brate;
+       u16 brate_cfg = 0;
+       u8 rate_index;
+
+       for (i = 0; i < NDIS_802_11_LENGTH_RATES_EX; i++) {
+               is_brate = mBratesOS[i] & IEEE80211_BASIC_RATE_MASK;
+               brate = mBratesOS[i] & 0x7f;
+
+               if (is_brate) {
+                       switch (brate) {
+                       case IEEE80211_CCK_RATE_1MB:
+                               brate_cfg |= RATE_1M;
+                               break;
+                       case IEEE80211_CCK_RATE_2MB:
+                               brate_cfg |= RATE_2M;
+                               break;
+                       case IEEE80211_CCK_RATE_5MB:
+                               brate_cfg |= RATE_5_5M;
+                               break;
+                       case IEEE80211_CCK_RATE_11MB:
+                               brate_cfg |= RATE_11M;
+                               break;
+                       case IEEE80211_OFDM_RATE_6MB:
+                               brate_cfg |= RATE_6M;
+                               break;
+                       case IEEE80211_OFDM_RATE_9MB:
+                               brate_cfg |= RATE_9M;
+                               break;
+                       case IEEE80211_OFDM_RATE_12MB:
+                               brate_cfg |= RATE_12M;
+                               break;
+                       case IEEE80211_OFDM_RATE_18MB:
+                               brate_cfg |= RATE_18M;
+                               break;
+                       case IEEE80211_OFDM_RATE_24MB:
+                               brate_cfg |= RATE_24M;
+                               break;
+                       case IEEE80211_OFDM_RATE_36MB:
+                               brate_cfg |= RATE_36M;
+                               break;
+                       case IEEE80211_OFDM_RATE_48MB:
+                               brate_cfg |= RATE_48M;
+                               break;
+                       case IEEE80211_OFDM_RATE_54MB:
+                               brate_cfg |= RATE_54M;
+                               break;
+                       }
+               }
+       }
+
+       /*  2007.01.16, by Emily */
+       /*  Select RRSR (in Legacy-OFDM and CCK) */
+       /*  For 8190, we select only 24M, 12M, 6M, 11M, 5.5M, 2M,
+           and 1M from the Basic rate. */
+       /*  We do not use other rates. */
+       /* 2011.03.30 add by Luke Lee */
+       /* CCK 2M ACK should be disabled for some BCM and Atheros AP IOT */
+       /* because CCK 2M has poor TXEVM */
+       /* CCK 5.5M & 11M ACK should be enabled for better
+          performance */
+
+       brate_cfg = (brate_cfg | 0xd) & 0x15d;
+       pHalData->BasicRateSet = brate_cfg;
+       brate_cfg |= 0x01;      /*  default enable 1M ACK rate */
+       DBG_8723A("HW_VAR_BASIC_RATE: BrateCfg(%#x)\n", brate_cfg);
+
+       /*  Set RRSR rate table. */
+       rtw_write8(padapter, REG_RRSR, brate_cfg & 0xff);
+       rtw_write8(padapter, REG_RRSR + 1, (brate_cfg >> 8) & 0xff);
+       rtw_write8(padapter, REG_RRSR + 2,
+                  rtw_read8(padapter, REG_RRSR + 2) & 0xf0);
+
+       rate_index = 0;
+       /*  Set RTS initial rate */
+       while (brate_cfg > 0x1) {
+               brate_cfg = (brate_cfg >> 1);
+               rate_index++;
+       }
+               /*  Ziv - Check */
+       rtw_write8(padapter, REG_INIRTS_RATE_SEL, rate_index);
+
+       return;
+}
+
+static void _OneOutPipeMapping(struct rtw_adapter *pAdapter)
+{
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter);
+
+       pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0];   /* VO */
+       pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0];   /* VI */
+       pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[0];   /* BE */
+       pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0];   /* BK */
+
+       pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0];   /* BCN */
+       pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0];   /* MGT */
+       pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0];   /* HIGH */
+       pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0];   /* TXCMD */
+}
+
+static void _TwoOutPipeMapping(struct rtw_adapter *pAdapter, bool bWIFICfg)
+{
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter);
+
+       if (bWIFICfg) {         /* WMM */
+               /*    BK,   BE,   VI,   VO,   BCN,  CMD,  MGT, HIGH, HCCA */
+               /*     0,    1,    0,    1,     0,    0,    0,    0,    0 }; */
+               /* 0:H, 1:L */
+               pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[1]; /* VO */
+               pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0]; /* VI */
+               pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1]; /* BE */
+               pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[0]; /* BK */
+
+               pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */
+               pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */
+               pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */
+               pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/
+       } else {                /* typical setting */
+               /*    BK,   BE,   VI,   VO,   BCN,  CMD,  MGT, HIGH, HCCA */
+               /*     1,    1,    0,    0,     0,    0,    0,    0,    0 }; */
+               /* 0:H, 1:L */
+               pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */
+               pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[0]; /* VI */
+               pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[1]; /* BE */
+               pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1]; /* BK */
+
+               pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */
+               pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */
+               pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */
+               pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/
+       }
+}
+
+static void _ThreeOutPipeMapping(struct rtw_adapter *pAdapter, bool bWIFICfg)
+{
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(pAdapter);
+
+       if (bWIFICfg) {         /* for WMM */
+               /*    BK,   BE,   VI,   VO,   BCN,  CMD,  MGT, HIGH, HCCA */
+               /*     1,    2,    1,    0,     0,    0,    0,    0,    0 }; */
+               /* 0:H, 1:N, 2:L */
+               pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */
+               pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1]; /* VI */
+               pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2]; /* BE */
+               pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[1]; /* BK */
+
+               pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */
+               pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */
+               pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */
+               pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/
+       } else {                /* typical setting */
+               /*    BK,   BE,   VI,   VO,   BCN,  CMD,  MGT, HIGH, HCCA */
+               /*     2,    2,    1,    0,     0,    0,    0,    0,    0 }; */
+               /* 0:H, 1:N, 2:L */
+               pdvobjpriv->Queue2Pipe[0] = pdvobjpriv->RtOutPipe[0]; /* VO */
+               pdvobjpriv->Queue2Pipe[1] = pdvobjpriv->RtOutPipe[1]; /* VI */
+               pdvobjpriv->Queue2Pipe[2] = pdvobjpriv->RtOutPipe[2]; /* BE */
+               pdvobjpriv->Queue2Pipe[3] = pdvobjpriv->RtOutPipe[2]; /* BK */
+
+               pdvobjpriv->Queue2Pipe[4] = pdvobjpriv->RtOutPipe[0]; /* BCN */
+               pdvobjpriv->Queue2Pipe[5] = pdvobjpriv->RtOutPipe[0]; /* MGT */
+               pdvobjpriv->Queue2Pipe[6] = pdvobjpriv->RtOutPipe[0]; /* HIGH */
+               pdvobjpriv->Queue2Pipe[7] = pdvobjpriv->RtOutPipe[0]; /* TXCMD*/
+       }
+}
+
+bool Hal_MappingOutPipe23a(struct rtw_adapter *pAdapter, u8 NumOutPipe)
+{
+       struct registry_priv *pregistrypriv = &pAdapter->registrypriv;
+       bool bWIFICfg = (pregistrypriv->wifi_spec) ? true : false;
+       bool result = true;
+
+       switch (NumOutPipe) {
+       case 2:
+               _TwoOutPipeMapping(pAdapter, bWIFICfg);
+               break;
+       case 3:
+               _ThreeOutPipeMapping(pAdapter, bWIFICfg);
+               break;
+       case 1:
+               _OneOutPipeMapping(pAdapter);
+               break;
+       default:
+               result = false;
+               break;
+       }
+
+       return result;
+}
+
+void hal_init_macaddr23a(struct rtw_adapter *adapter)
+{
+       rtw_hal_set_hwreg23a(adapter, HW_VAR_MAC_ADDR,
+                         adapter->eeprompriv.mac_addr);
+}
+
+/*
+* C2H event format:
+* Field         TRIGGER                CONTENT    CMD_SEQ      CMD_LEN          CMD_ID
+* BITS  [127:120]      [119:16]      [15:8]              [7:4]            [3:0]
+*/
+
+void c2h_evt_clear23a(struct rtw_adapter *adapter)
+{
+       rtw_write8(adapter, REG_C2HEVT_CLEAR, C2H_EVT_HOST_CLOSE);
+}
+
+s32 c2h_evt_read23a(struct rtw_adapter *adapter, u8 *buf)
+{
+       s32 ret = _FAIL;
+       struct c2h_evt_hdr *c2h_evt;
+       int i;
+       u8 trigger;
+
+       if (buf == NULL)
+               goto exit;
+
+       trigger = rtw_read8(adapter, REG_C2HEVT_CLEAR);
+
+       if (trigger == C2H_EVT_HOST_CLOSE)
+               goto exit;      /* Not ready */
+       else if (trigger != C2H_EVT_FW_CLOSE)
+               goto clear_evt; /* Not a valid value */
+
+       c2h_evt = (struct c2h_evt_hdr *)buf;
+
+       memset(c2h_evt, 0, 16);
+
+       *buf = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL);
+       *(buf + 1) = rtw_read8(adapter, REG_C2HEVT_MSG_NORMAL + 1);
+
+       RT_PRINT_DATA(_module_hal_init_c_, _drv_info_, "c2h_evt_read23a(): ",
+                     &c2h_evt, sizeof(c2h_evt));
+
+       if (0) {
+               DBG_8723A("%s id:%u, len:%u, seq:%u, trigger:0x%02x\n",
+                         __func__, c2h_evt->id, c2h_evt->plen, c2h_evt->seq,
+                         trigger);
+       }
+
+       /* Read the content */
+       for (i = 0; i < c2h_evt->plen; i++)
+               c2h_evt->payload[i] = rtw_read8(adapter,
+                                               REG_C2HEVT_MSG_NORMAL +
+                                               sizeof(*c2h_evt) + i);
+
+       RT_PRINT_DATA(_module_hal_init_c_, _drv_info_,
+                     "c2h_evt_read23a(): Command Content:\n", c2h_evt->payload,
+                     c2h_evt->plen);
+
+       ret = _SUCCESS;
+
+clear_evt:
+       /*
+        * Clear event to notify FW we have read the command.
+        * If this field isn't clear, the FW won't update the
+        * next command message.
+        */
+       c2h_evt_clear23a(adapter);
+exit:
+       return ret;
+}
+
+void
+rtl8723a_set_ampdu_min_space(struct rtw_adapter *padapter, u8 MinSpacingToSet)
+{
+       u8 SecMinSpace;
+
+       if (MinSpacingToSet <= 7) {
+               switch (padapter->securitypriv.dot11PrivacyAlgrthm) {
+               case _NO_PRIVACY_:
+               case _AES_:
+                       SecMinSpace = 0;
+                       break;
+
+               case _WEP40_:
+               case _WEP104_:
+               case _TKIP_:
+               case _TKIP_WTMIC_:
+                       SecMinSpace = 6;
+                       break;
+               default:
+                       SecMinSpace = 7;
+                       break;
+               }
+
+               if (MinSpacingToSet < SecMinSpace)
+                       MinSpacingToSet = SecMinSpace;
+
+               /* RT_TRACE(COMP_MLME, DBG_LOUD,
+                  ("Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+                  padapter->MgntInfo.MinSpaceCfg)); */
+               MinSpacingToSet |=
+                       rtw_read8(padapter, REG_AMPDU_MIN_SPACE) & 0xf8;
+               rtw_write8(padapter, REG_AMPDU_MIN_SPACE,
+                          MinSpacingToSet);
+       }
+}
+
+void rtl8723a_set_ampdu_factor(struct rtw_adapter *padapter, u8 FactorToSet)
+{
+       u8 RegToSet_Normal[4] = { 0x41, 0xa8, 0x72, 0xb9 };
+       u8 MaxAggNum;
+       u8 *pRegToSet;
+       u8 index = 0;
+
+       pRegToSet = RegToSet_Normal;    /*  0xb972a841; */
+#ifdef CONFIG_8723AU_BT_COEXIST
+       if ((BT_IsBtDisabled(padapter) == false) &&
+           (BT_1Ant(padapter) == true)) {
+               MaxAggNum = 0x8;
+       } else
+#endif /*  CONFIG_8723AU_BT_COEXIST */
+       {
+               MaxAggNum = 0xF;
+       }
+
+       if (FactorToSet <= 3) {
+               FactorToSet = (1 << (FactorToSet + 2));
+               if (FactorToSet > MaxAggNum)
+                       FactorToSet = MaxAggNum;
+
+               for (index = 0; index < 4; index++) {
+                       if ((pRegToSet[index] & 0xf0) > (FactorToSet << 4))
+                               pRegToSet[index] = (pRegToSet[index] & 0x0f) |
+                                       (FactorToSet << 4);
+
+                       if ((pRegToSet[index] & 0x0f) > FactorToSet)
+                               pRegToSet[index] = (pRegToSet[index] & 0xf0) |
+                                       FactorToSet;
+
+                       rtw_write8(padapter, REG_AGGLEN_LMT + index,
+                                  pRegToSet[index]);
+               }
+
+               /* RT_TRACE(COMP_MLME, DBG_LOUD,
+                  ("Set HW_VAR_AMPDU_FACTOR: %#x\n", FactorToSet)); */
+       }
+}
+
+void rtl8723a_set_acm_ctrl(struct rtw_adapter *padapter, u8 ctrl)
+{
+       u8 hwctrl = 0;
+
+       if (ctrl != 0) {
+               hwctrl |= AcmHw_HwEn;
+
+               if (ctrl & BIT(1))      /*  BE */
+                       hwctrl |= AcmHw_BeqEn;
+
+               if (ctrl & BIT(2))      /*  VI */
+                       hwctrl |= AcmHw_ViqEn;
+
+               if (ctrl & BIT(3))      /*  VO */
+                       hwctrl |= AcmHw_VoqEn;
+       }
+
+       DBG_8723A("[HW_VAR_ACM_CTRL] Write 0x%02X\n", hwctrl);
+       rtw_write8(padapter, REG_ACMHWCTRL, hwctrl);
+}
+
+void rtl8723a_set_media_status(struct rtw_adapter *padapter, u8 status)
+{
+       u8 val8;
+
+       val8 = rtw_read8(padapter, MSR) & 0x0c;
+       val8 |= status;
+       rtw_write8(padapter, MSR, val8);
+}
+
+void rtl8723a_set_media_status1(struct rtw_adapter *padapter, u8 status)
+{
+       u8 val8;
+
+       val8 = rtw_read8(padapter, MSR) & 0x03;
+       val8 |= status << 2;
+       rtw_write8(padapter, MSR, val8);
+}
+
+void rtl8723a_set_bcn_func(struct rtw_adapter *padapter, u8 val)
+{
+       if (val)
+               SetBcnCtrlReg23a(padapter, EN_BCN_FUNCTION | EN_TXBCN_RPT, 0);
+       else
+               SetBcnCtrlReg23a(padapter, 0, EN_BCN_FUNCTION | EN_TXBCN_RPT);
+}
+
+void rtl8723a_check_bssid(struct rtw_adapter *padapter, u8 val)
+{
+       u32 val32;
+       val32 = rtw_read32(padapter, REG_RCR);
+       if (val)
+               val32 |= RCR_CBSSID_DATA | RCR_CBSSID_BCN;
+       else
+               val32 &= ~(RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+       rtw_write32(padapter, REG_RCR, val32);
+}
+
+void rtl8723a_mlme_sitesurvey(struct rtw_adapter *padapter, u8 flag)
+{
+       if (flag) {     /* under sitesurvey */
+               u32 v32;
+
+               /*  config RCR to receive different BSSID & not
+                   to receive data frame */
+               v32 = rtw_read32(padapter, REG_RCR);
+               v32 &= ~(RCR_CBSSID_BCN);
+               rtw_write32(padapter, REG_RCR, v32);
+               /*  reject all data frame */
+               rtw_write16(padapter, REG_RXFLTMAP2, 0);
+
+               /*  disable update TSF */
+               SetBcnCtrlReg23a(padapter, DIS_TSF_UDT, 0);
+       } else {        /* sitesurvey done */
+
+               struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+               struct mlme_ext_info *pmlmeinfo;
+               u32 v32;
+
+               pmlmeinfo = &pmlmeext->mlmext_info;
+
+               if ((is_client_associated_to_ap23a(padapter) == true) ||
+                   ((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) ||
+                   ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) {
+                       /*  enable to rx data frame */
+                       rtw_write16(padapter, REG_RXFLTMAP2, 0xFFFF);
+
+                       /*  enable update TSF */
+                       SetBcnCtrlReg23a(padapter, 0, DIS_TSF_UDT);
+               }
+
+               v32 = rtw_read32(padapter, REG_RCR);
+               v32 |= RCR_CBSSID_BCN;
+               rtw_write32(padapter, REG_RCR, v32);
+       }
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       BT_WifiScanNotify(padapter, flag ? true : false);
+#endif
+}
+
+void rtl8723a_on_rcr_am(struct rtw_adapter *padapter)
+{
+       rtw_write32(padapter, REG_RCR, rtw_read32(padapter, REG_RCR) | RCR_AM);
+       DBG_8723A("%s, %d, RCR = %x \n", __FUNCTION__, __LINE__,
+                 rtw_read32(padapter, REG_RCR));
+}
+
+void rtl8723a_off_rcr_am(struct rtw_adapter *padapter)
+{
+       rtw_write32(padapter, REG_RCR,
+                   rtw_read32(padapter, REG_RCR) & (~RCR_AM));
+       DBG_8723A("%s, %d, RCR = %x \n", __FUNCTION__, __LINE__,
+                 rtw_read32(padapter, REG_RCR));
+}
+
+void rtl8723a_set_slot_time(struct rtw_adapter *padapter, u8 slottime)
+{
+       u8 u1bAIFS, aSifsTime;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       rtw_write8(padapter, REG_SLOT, slottime);
+
+       if (pmlmeinfo->WMM_enable == 0) {
+               if (pmlmeext->cur_wireless_mode == WIRELESS_11B)
+                       aSifsTime = 10;
+               else
+                       aSifsTime = 16;
+
+               u1bAIFS = aSifsTime + (2 * pmlmeinfo->slotTime);
+
+               /*  <Roger_EXP> Temporary removed, 2008.06.20. */
+               rtw_write8(padapter, REG_EDCA_VO_PARAM, u1bAIFS);
+               rtw_write8(padapter, REG_EDCA_VI_PARAM, u1bAIFS);
+               rtw_write8(padapter, REG_EDCA_BE_PARAM, u1bAIFS);
+               rtw_write8(padapter, REG_EDCA_BK_PARAM, u1bAIFS);
+       }
+}
+
+void rtl8723a_ack_preamble(struct rtw_adapter *padapter, u8 bShortPreamble)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 regTmp;
+
+       /*  Joseph marked out for Netgear 3500 TKIP
+           channel 7 issue.(Temporarily) */
+       regTmp = (pHalData->nCur40MhzPrimeSC) << 5;
+       /* regTmp = 0; */
+       if (bShortPreamble)
+               regTmp |= 0x80;
+       rtw_write8(padapter, REG_RRSR + 2, regTmp);
+}
+
+void rtl8723a_set_sec_cfg(struct rtw_adapter *padapter, u8 sec)
+{
+       rtw_write8(padapter, REG_SECCFG, sec);
+}
+
+void rtl8723a_cam_empty_entry(struct rtw_adapter *padapter, u8 ucIndex)
+{
+       u8 i;
+       u32 ulCommand = 0;
+       u32 ulContent = 0;
+       u32 ulEncAlgo = CAM_AES;
+
+       for (i = 0; i < CAM_CONTENT_COUNT; i++) {
+               /*  filled id in CAM config 2 byte */
+               if (i == 0) {
+                       ulContent |= (ucIndex & 0x03) |
+                               ((u16) (ulEncAlgo) << 2);
+                       /* ulContent |= CAM_VALID; */
+               } else {
+                       ulContent = 0;
+               }
+               /*  polling bit, and No Write enable, and address */
+               ulCommand = CAM_CONTENT_COUNT * ucIndex + i;
+               ulCommand = ulCommand | CAM_POLLINIG | CAM_WRITE;
+               /*  write content 0 is equall to mark invalid */
+               /* delay_ms(40); */
+               rtw_write32(padapter, WCAMI, ulContent);
+               /* RT_TRACE(COMP_SEC, DBG_LOUD,
+                  ("CAM_empty_entry23a(): WRITE A4: %lx \n", ulContent));*/
+               /* delay_ms(40); */
+               rtw_write32(padapter, RWCAM, ulCommand);
+               /* RT_TRACE(COMP_SEC, DBG_LOUD,
+                  ("CAM_empty_entry23a(): WRITE A0: %lx \n", ulCommand));*/
+       }
+}
+
+void rtl8723a_cam_invalid_all(struct rtw_adapter *padapter)
+{
+       rtw_write32(padapter, RWCAM, BIT(31) | BIT(30));
+}
+
+void rtl8723a_cam_write(struct rtw_adapter *padapter, u32 val1, u32 val2)
+{
+       u32 cmd;
+
+       rtw_write32(padapter, WCAMI, val1);
+
+       cmd = CAM_POLLINIG | CAM_WRITE | val2;
+       rtw_write32(padapter, RWCAM, cmd);
+}
+
+void rtl8723a_fifo_cleanup(struct rtw_adapter *padapter)
+{
+#define RW_RELEASE_EN          BIT(18)
+#define RXDMA_IDLE             BIT(17)
+
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       u8 trycnt = 100;
+
+       /*  pause tx */
+       rtw_write8(padapter, REG_TXPAUSE, 0xff);
+
+       /*  keep sn */
+       padapter->xmitpriv.nqos_ssn = rtw_read16(padapter, REG_NQOS_SEQ);
+
+       if (pwrpriv->bkeepfwalive != true) {
+               u32 v32;
+
+               /*  RX DMA stop */
+               v32 = rtw_read32(padapter, REG_RXPKT_NUM);
+               v32 |= RW_RELEASE_EN;
+               rtw_write32(padapter, REG_RXPKT_NUM, v32);
+               do {
+                       v32 = rtw_read32(padapter, REG_RXPKT_NUM) & RXDMA_IDLE;
+                       if (!v32)
+                               break;
+               } while (trycnt--);
+               if (trycnt == 0) {
+                       DBG_8723A("Stop RX DMA failed......\n");
+               }
+
+               /*  RQPN Load 0 */
+               rtw_write16(padapter, REG_RQPN_NPQ, 0);
+               rtw_write32(padapter, REG_RQPN, 0x80000000);
+               mdelay(10);
+       }
+}
+
+void rtl8723a_set_apfm_on_mac(struct rtw_adapter *padapter, u8 val)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       pHalData->bMacPwrCtrlOn = val;
+       DBG_8723A("%s: bMacPwrCtrlOn =%d\n", __func__, pHalData->bMacPwrCtrlOn);
+}
+
+void rtl8723a_bcn_valid(struct rtw_adapter *padapter)
+{
+       /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2,
+          write 1 to clear, Clear by sw */
+       rtw_write8(padapter, REG_TDECTRL + 2,
+                  rtw_read8(padapter, REG_TDECTRL + 2) | BIT0);
+}
+
+void rtl8723a_set_tx_pause(struct rtw_adapter *padapter, u8 pause)
+{
+       rtw_write8(padapter, REG_TXPAUSE, pause);
+}
+
+void rtl8723a_set_beacon_interval(struct rtw_adapter *padapter, u16 interval)
+{
+       rtw_write16(padapter, REG_BCN_INTERVAL, interval);
+}
+
+void rtl8723a_set_resp_sifs(struct rtw_adapter *padapter,
+                           u8 r2t1, u8 r2t2, u8 t2t1, u8 t2t2)
+{
+       /* SIFS_Timer = 0x0a0a0808; */
+       /* RESP_SIFS for CCK */
+       /*  SIFS_T2T_CCK (0x08) */
+       rtw_write8(padapter, REG_R2T_SIFS, r2t1);
+       /* SIFS_R2T_CCK(0x08) */
+       rtw_write8(padapter, REG_R2T_SIFS + 1, r2t2);
+       /* RESP_SIFS for OFDM */
+       /* SIFS_T2T_OFDM (0x0a) */
+       rtw_write8(padapter, REG_T2T_SIFS, t2t1);
+       /* SIFS_R2T_OFDM(0x0a) */
+       rtw_write8(padapter, REG_T2T_SIFS + 1, t2t2);
+}
+
+void rtl8723a_set_ac_param_vo(struct rtw_adapter *padapter, u32 vo)
+{
+       rtw_write32(padapter, REG_EDCA_VO_PARAM, vo);
+}
+
+void rtl8723a_set_ac_param_vi(struct rtw_adapter *padapter, u32 vi)
+{
+       rtw_write32(padapter, REG_EDCA_VI_PARAM, vi);
+}
+
+void rtl8723a_set_ac_param_be(struct rtw_adapter *padapter, u32 be)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       pHalData->AcParam_BE = be;
+       rtw_write32(padapter, REG_EDCA_BE_PARAM, be);
+}
+
+void rtl8723a_set_ac_param_bk(struct rtw_adapter *padapter, u32 bk)
+{
+       rtw_write32(padapter, REG_EDCA_BK_PARAM, bk);
+}
+
+void rtl8723a_set_rxdma_agg_pg_th(struct rtw_adapter *padapter, u8 val)
+{
+       rtw_write8(padapter, REG_RXDMA_AGG_PG_TH, val);
+}
+
+void rtl8723a_set_nav_upper(struct rtw_adapter *padapter, u32 usNavUpper)
+{
+       if (usNavUpper > HAL_8723A_NAV_UPPER_UNIT * 0xFF) {
+               RT_TRACE(_module_hal_init_c_, _drv_notice_,
+                        ("The setting value (0x%08X us) of NAV_UPPER "
+                         "is larger than (%d * 0xFF)!!!\n",
+                         usNavUpper, HAL_8723A_NAV_UPPER_UNIT));
+               return;
+       }
+
+       /*  The value of ((usNavUpper + HAL_8723A_NAV_UPPER_UNIT - 1) /
+           HAL_8723A_NAV_UPPER_UNIT) */
+       /*  is getting the upper integer. */
+       usNavUpper = (usNavUpper + HAL_8723A_NAV_UPPER_UNIT - 1) /
+               HAL_8723A_NAV_UPPER_UNIT;
+       rtw_write8(padapter, REG_NAV_UPPER, (u8) usNavUpper);
+}
+
+void rtl8723a_set_initial_gain(struct rtw_adapter *padapter, u32 rx_gain)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct dig_t *pDigTable = &pHalData->odmpriv.DM_DigTable;
+
+       if (rx_gain == 0xff)    /* restore rx gain */
+               ODM_Write_DIG23a(&pHalData->odmpriv, pDigTable->BackupIGValue);
+       else {
+               pDigTable->BackupIGValue = pDigTable->CurIGValue;
+               ODM_Write_DIG23a(&pHalData->odmpriv, rx_gain);
+       }
+}
+
+void rtl8723a_odm_support_ability_write(struct rtw_adapter *padapter, u32 val)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       pHalData->odmpriv.SupportAbility = val;
+}
+
+void rtl8723a_odm_support_ability_backup(struct rtw_adapter *padapter, u8 val)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (val)        /*  save dm flag */
+               pHalData->odmpriv.BK_SupportAbility =
+                       pHalData->odmpriv.SupportAbility;
+       else            /*  restore dm flag */
+               pHalData->odmpriv.SupportAbility =
+                       pHalData->odmpriv.BK_SupportAbility;
+}
+
+void rtl8723a_odm_support_ability_set(struct rtw_adapter *padapter, u32 val)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (val == DYNAMIC_ALL_FUNC_ENABLE) {
+               pHalData->dmpriv.DMFlag = pHalData->dmpriv.InitDMFlag;
+               pHalData->odmpriv.SupportAbility = pHalData->dmpriv.InitODMFlag;
+       } else {
+               pHalData->odmpriv.SupportAbility |= val;
+       }
+}
+
+void rtl8723a_odm_support_ability_clr(struct rtw_adapter *padapter, u32 val)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       pHalData->odmpriv.SupportAbility &= val;
+}
+
+void rtl8723a_set_rpwm(struct rtw_adapter *padapter, u8 val)
+{
+       rtw_write8(padapter, REG_USB_HRPWM, val);
+}
diff --git a/drivers/staging/rtl8723au/hal/hal_intf.c b/drivers/staging/rtl8723au/hal/hal_intf.c
new file mode 100644 (file)
index 0000000..de3608b
--- /dev/null
@@ -0,0 +1,420 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+#define _HAL_INTF_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <hal_intf.h>
+
+#include <usb_hal.h>
+
+void rtw_hal_chip_configure23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.intf_chip_configure)
+               padapter->HalFunc.intf_chip_configure(padapter);
+}
+
+void rtw_hal_read_chip_info23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.read_adapter_info)
+               padapter->HalFunc.read_adapter_info(padapter);
+}
+
+void rtw_hal_read_chip_version23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.read_chip_version)
+               padapter->HalFunc.read_chip_version(padapter);
+}
+
+void rtw_hal_def_value_init23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.init_default_value)
+               padapter->HalFunc.init_default_value(padapter);
+}
+void   rtw_hal_free_data23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.free_hal_data)
+               padapter->HalFunc.free_hal_data(padapter);
+}
+void   rtw_hal_dm_init23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.dm_init)
+               padapter->HalFunc.dm_init(padapter);
+}
+void rtw_hal_dm_deinit23a(struct rtw_adapter *padapter)
+{
+       /*  cancel dm  timer */
+       if (padapter->HalFunc.dm_deinit)
+               padapter->HalFunc.dm_deinit(padapter);
+}
+void   rtw_hal_sw_led_init23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.InitSwLeds)
+               padapter->HalFunc.InitSwLeds(padapter);
+}
+
+void rtw_hal_sw_led_deinit23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.DeInitSwLeds)
+               padapter->HalFunc.DeInitSwLeds(padapter);
+}
+
+u32 rtw_hal_power_on23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.hal_power_on)
+               return padapter->HalFunc.hal_power_on(padapter);
+       return _FAIL;
+}
+
+uint    rtw_hal_init23a(struct rtw_adapter *padapter)
+{
+       uint    status = _SUCCESS;
+
+       padapter->hw_init_completed = false;
+
+       status = padapter->HalFunc.hal_init(padapter);
+
+       if (status == _SUCCESS) {
+               padapter->hw_init_completed = true;
+
+               if (padapter->registrypriv.notch_filter == 1)
+                       rtw_hal_notch_filter23a(padapter, 1);
+
+               rtw_hal_reset_security_engine23a(padapter);
+       } else {
+               padapter->hw_init_completed = false;
+               DBG_8723A("rtw_hal_init23a: hal__init fail\n");
+       }
+
+       RT_TRACE(_module_hal_init_c_, _drv_err_, ("-rtl871x_hal_init:status = 0x%x\n", status));
+
+       return status;
+}
+
+uint rtw_hal_deinit23a(struct rtw_adapter *padapter)
+{
+       uint    status = _SUCCESS;
+
+       status = padapter->HalFunc.hal_deinit(padapter);
+
+       if (status == _SUCCESS)
+               padapter->hw_init_completed = false;
+       else
+               DBG_8723A("\n rtw_hal_deinit23a: hal_init fail\n");
+       return status;
+}
+
+void rtw_hal_set_hwreg23a(struct rtw_adapter *padapter, u8 variable, u8 *val)
+{
+       if (padapter->HalFunc.SetHwRegHandler)
+               padapter->HalFunc.SetHwRegHandler(padapter, variable, val);
+}
+
+void rtw23a_hal_get_hwreg(struct rtw_adapter *padapter, u8 variable, u8 *val)
+{
+       if (padapter->HalFunc.GetHwRegHandler)
+               padapter->HalFunc.GetHwRegHandler(padapter, variable, val);
+}
+
+u8 rtw_hal_set_def_var23a(struct rtw_adapter *padapter, enum hal_def_variable eVariable, void *pValue)
+{
+       if (padapter->HalFunc.SetHalDefVarHandler)
+               return padapter->HalFunc.SetHalDefVarHandler(padapter, eVariable, pValue);
+       return _FAIL;
+}
+u8 rtw_hal_get_def_var23a(struct rtw_adapter *padapter, enum hal_def_variable eVariable, void *pValue)
+{
+       if (padapter->HalFunc.GetHalDefVarHandler)
+               return padapter->HalFunc.GetHalDefVarHandler(padapter, eVariable, pValue);
+       return _FAIL;
+}
+
+void rtw_hal_set_odm_var23a(struct rtw_adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet)
+{
+       if (padapter->HalFunc.SetHalODMVarHandler)
+               padapter->HalFunc.SetHalODMVarHandler(padapter, eVariable, pValue1, bSet);
+}
+void   rtw_hal_get_odm_var23a(struct rtw_adapter *padapter, enum hal_odm_variable eVariable, void *pValue1, bool bSet)
+{
+       if (padapter->HalFunc.GetHalODMVarHandler)
+               padapter->HalFunc.GetHalODMVarHandler(padapter, eVariable, pValue1, bSet);
+}
+
+void rtw_hal_enable_interrupt23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.enable_interrupt)
+               padapter->HalFunc.enable_interrupt(padapter);
+       else
+               DBG_8723A("%s: HalFunc.enable_interrupt is NULL!\n", __FUNCTION__);
+
+}
+void rtw_hal_disable_interrupt23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.disable_interrupt)
+               padapter->HalFunc.disable_interrupt(padapter);
+       else
+               DBG_8723A("%s: HalFunc.disable_interrupt is NULL!\n", __FUNCTION__);
+
+}
+
+u32    rtw_hal_inirp_init23a(struct rtw_adapter *padapter)
+{
+       u32 rst = _FAIL;
+       if (padapter->HalFunc.inirp_init)
+               rst = padapter->HalFunc.inirp_init(padapter);
+       else
+               DBG_8723A(" %s HalFunc.inirp_init is NULL!!!\n", __FUNCTION__);
+       return rst;
+}
+
+u32    rtw_hal_inirp_deinit23a(struct rtw_adapter *padapter)
+{
+
+       if (padapter->HalFunc.inirp_deinit)
+               return padapter->HalFunc.inirp_deinit(padapter);
+
+       return _FAIL;
+
+}
+
+u8     rtw_hal_intf_ps_func23a(struct rtw_adapter *padapter, enum hal_intf_ps_func efunc_id, u8 *val)
+{
+       if (padapter->HalFunc.interface_ps_func)
+               return padapter->HalFunc.interface_ps_func(padapter, efunc_id, val);
+       return _FAIL;
+}
+
+s32    rtw_hal_xmit23aframe_enqueue(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       if (padapter->HalFunc.hal_xmitframe_enqueue)
+               return padapter->HalFunc.hal_xmitframe_enqueue(padapter, pxmitframe);
+
+       return false;
+}
+
+s32    rtw_hal_xmit23a(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       if (padapter->HalFunc.hal_xmit)
+               return padapter->HalFunc.hal_xmit(padapter, pxmitframe);
+
+       return false;
+}
+
+s32    rtw_hal_mgnt_xmit23a(struct rtw_adapter *padapter, struct xmit_frame *pmgntframe)
+{
+       s32 ret = _FAIL;
+       if (padapter->HalFunc.mgnt_xmit)
+               ret = padapter->HalFunc.mgnt_xmit(padapter, pmgntframe);
+       return ret;
+}
+
+s32    rtw_hal_init23a_xmit_priv(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.init_xmit_priv != NULL)
+               return padapter->HalFunc.init_xmit_priv(padapter);
+       return _FAIL;
+}
+void   rtw_hal_free_xmit_priv23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.free_xmit_priv != NULL)
+               padapter->HalFunc.free_xmit_priv(padapter);
+}
+
+s32    rtw_hal_init23a_recv_priv(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.init_recv_priv)
+               return padapter->HalFunc.init_recv_priv(padapter);
+
+       return _FAIL;
+}
+void   rtw_hal_free_recv_priv23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.free_recv_priv)
+               padapter->HalFunc.free_recv_priv(padapter);
+}
+
+void rtw_hal_update_ra_mask23a(struct sta_info *psta, u8 rssi_level)
+{
+       struct rtw_adapter *padapter;
+       struct mlme_priv *pmlmepriv;
+
+       if (!psta)
+               return;
+
+       padapter = psta->padapter;
+
+       pmlmepriv = &padapter->mlmepriv;
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+#ifdef CONFIG_8723AU_AP_MODE
+               add_RATid23a(padapter, psta, rssi_level);
+#endif
+       } else {
+               if (padapter->HalFunc.UpdateRAMaskHandler)
+                       padapter->HalFunc.UpdateRAMaskHandler(padapter, psta->mac_id, rssi_level);
+       }
+}
+
+void   rtw_hal_add_ra_tid23a(struct rtw_adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level)
+{
+       if (padapter->HalFunc.Add_RateATid)
+               padapter->HalFunc.Add_RateATid(padapter, bitmap, arg, rssi_level);
+}
+
+/*     Start specifical interface thread               */
+void   rtw_hal_start_thread23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.run_thread)
+               padapter->HalFunc.run_thread(padapter);
+}
+/*     Start specifical interface thread               */
+void   rtw_hal_stop_thread23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.cancel_thread)
+               padapter->HalFunc.cancel_thread(padapter);
+}
+
+u32    rtw_hal_read_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask)
+{
+       u32 data = 0;
+       if (padapter->HalFunc.read_bbreg)
+                data = padapter->HalFunc.read_bbreg(padapter, RegAddr, BitMask);
+       return data;
+}
+void   rtw_hal_write_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data)
+{
+       if (padapter->HalFunc.write_bbreg)
+               padapter->HalFunc.write_bbreg(padapter, RegAddr, BitMask, Data);
+}
+
+u32    rtw_hal_read_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask)
+{
+       u32 data = 0;
+       if (padapter->HalFunc.read_rfreg)
+               data = padapter->HalFunc.read_rfreg(padapter, eRFPath, RegAddr, BitMask);
+       return data;
+}
+void   rtw_hal_write_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data)
+{
+       if (padapter->HalFunc.write_rfreg)
+               padapter->HalFunc.write_rfreg(padapter, eRFPath, RegAddr, BitMask, Data);
+}
+
+s32    rtw_hal_interrupt_handler23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.interrupt_handler)
+               return padapter->HalFunc.interrupt_handler(padapter);
+       return _FAIL;
+}
+
+void   rtw_hal_set_bwmode23a(struct rtw_adapter *padapter,
+                          enum ht_channel_width Bandwidth, u8 offset)
+{
+       if (padapter->HalFunc.set_bwmode_handler)
+               padapter->HalFunc.set_bwmode_handler(padapter, Bandwidth,
+                                                    offset);
+}
+
+void   rtw_hal_set_chan23a(struct rtw_adapter *padapter, u8 channel)
+{
+       if (padapter->HalFunc.set_channel_handler)
+               padapter->HalFunc.set_channel_handler(padapter, channel);
+}
+
+void   rtw_hal_dm_watchdog23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.hal_dm_watchdog)
+               padapter->HalFunc.hal_dm_watchdog(padapter);
+}
+
+void rtw_hal_bcn_related_reg_setting23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.SetBeaconRelatedRegistersHandler)
+               padapter->HalFunc.SetBeaconRelatedRegistersHandler(padapter);
+}
+
+void   rtw_hal_sreset_init23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.sreset_init_value23a)
+               padapter->HalFunc.sreset_init_value23a(padapter);
+}
+void rtw_hal_sreset_reset23a(struct rtw_adapter *padapter)
+{
+       padapter = GET_PRIMARY_ADAPTER(padapter);
+
+       if (padapter->HalFunc.silentreset)
+               padapter->HalFunc.silentreset(padapter);
+}
+
+void rtw_hal_sreset_reset23a_value23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.sreset_reset_value23a)
+               padapter->HalFunc.sreset_reset_value23a(padapter);
+}
+
+void rtw_hal_sreset_xmit_status_check23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.sreset_xmit_status_check)
+               padapter->HalFunc.sreset_xmit_status_check(padapter);
+}
+void rtw_hal_sreset_linked_status_check23a(struct rtw_adapter *padapter)
+{
+       if (padapter->HalFunc.sreset_linked_status_check)
+               padapter->HalFunc.sreset_linked_status_check(padapter);
+}
+u8   rtw_hal_sreset_get_wifi_status23a(struct rtw_adapter *padapter)
+{
+       u8 status = 0;
+       if (padapter->HalFunc.sreset_get_wifi_status23a)
+               status = padapter->HalFunc.sreset_get_wifi_status23a(padapter);
+       return status;
+}
+
+bool rtw_hal_sreset_inprogress(struct rtw_adapter *padapter)
+{
+       bool inprogress = false;
+
+       padapter = GET_PRIMARY_ADAPTER(padapter);
+
+       if (padapter->HalFunc.sreset_inprogress)
+               inprogress = padapter->HalFunc.sreset_inprogress(padapter);
+       return inprogress;
+}
+
+void rtw_hal_notch_filter23a(struct rtw_adapter *adapter, bool enable)
+{
+       if (adapter->HalFunc.hal_notch_filter)
+               adapter->HalFunc.hal_notch_filter(adapter, enable);
+}
+
+void rtw_hal_reset_security_engine23a(struct rtw_adapter *adapter)
+{
+       if (adapter->HalFunc.hal_reset_security_engine)
+               adapter->HalFunc.hal_reset_security_engine(adapter);
+}
+
+s32 rtw_hal_c2h_handler23a(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt)
+{
+       s32 ret = _FAIL;
+       if (adapter->HalFunc.c2h_handler)
+               ret = adapter->HalFunc.c2h_handler(adapter, c2h_evt);
+       return ret;
+}
+
+c2h_id_filter rtw_hal_c2h_id_filter_ccx23a(struct rtw_adapter *adapter)
+{
+       return adapter->HalFunc.c2h_id_filter_ccx;
+}
diff --git a/drivers/staging/rtl8723au/hal/odm.c b/drivers/staging/rtl8723au/hal/odm.c
new file mode 100644 (file)
index 0000000..584a74e
--- /dev/null
@@ -0,0 +1,2090 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 "odm_precomp.h"
+
+static const u16 dB_Invert_Table[8][12] = {
+       {1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4},
+       {4, 5, 6, 6, 7, 8, 9, 10, 11, 13, 14, 16},
+       {18, 20, 22, 25, 28, 32, 35, 40, 45, 50, 56, 63},
+       {71, 79, 89, 100, 112, 126, 141, 158, 178, 200, 224, 251},
+       {282, 316, 355, 398, 447, 501, 562, 631, 708, 794, 891, 1000},
+       {1122, 1259, 1413, 1585, 1778, 1995, 2239, 2512, 2818, 3162, 3548, 3981},
+       {4467, 5012, 5623, 6310, 7079, 7943, 8913, 10000, 11220, 12589, 14125, 15849},
+       {17783, 19953, 22387, 25119, 28184, 31623, 35481, 39811, 44668, 50119, 56234, 65535}
+};
+
+static u32 EDCAParam[HT_IOT_PEER_MAX][3] = {          /*  UL                   DL */
+       {0x5ea42b, 0x5ea42b, 0x5ea42b}, /* 0:unknown AP */
+       {0xa44f, 0x5ea44f, 0x5e431c}, /*  1:realtek AP */
+       {0x5ea42b, 0x5ea42b, 0x5ea42b}, /*  2:unknown AP => realtek_92SE */
+       {0x5ea32b, 0x5ea42b, 0x5e4322}, /*  3:broadcom AP */
+       {0x5ea422, 0x00a44f, 0x00a44f}, /*  4:ralink AP */
+       {0x5ea322, 0x00a630, 0x00a44f}, /*  5:atheros AP */
+       {0x5e4322, 0x5e4322, 0x5e4322},/*  6:cisco AP */
+       {0x5ea44f, 0x00a44f, 0x5ea42b}, /*  8:marvell AP */
+       {0x5ea42b, 0x5ea42b, 0x5ea42b}, /*  10:unknown AP => 92U AP */
+       {0x5ea42b, 0xa630, 0x5e431c}, /*  11:airgocap AP */
+};
+
+/*  EDCA Paramter for AP/ADSL   by Mingzhi 2011-11-22 */
+
+/*  Global var */
+u32 OFDMSwingTable23A[OFDM_TABLE_SIZE_92D] = {
+       0x7f8001fe, /*  0, +6.0dB */
+       0x788001e2, /*  1, +5.5dB */
+       0x71c001c7, /*  2, +5.0dB */
+       0x6b8001ae, /*  3, +4.5dB */
+       0x65400195, /*  4, +4.0dB */
+       0x5fc0017f, /*  5, +3.5dB */
+       0x5a400169, /*  6, +3.0dB */
+       0x55400155, /*  7, +2.5dB */
+       0x50800142, /*  8, +2.0dB */
+       0x4c000130, /*  9, +1.5dB */
+       0x47c0011f, /*  10, +1.0dB */
+       0x43c0010f, /*  11, +0.5dB */
+       0x40000100, /*  12, +0dB */
+       0x3c8000f2, /*  13, -0.5dB */
+       0x390000e4, /*  14, -1.0dB */
+       0x35c000d7, /*  15, -1.5dB */
+       0x32c000cb, /*  16, -2.0dB */
+       0x300000c0, /*  17, -2.5dB */
+       0x2d4000b5, /*  18, -3.0dB */
+       0x2ac000ab, /*  19, -3.5dB */
+       0x288000a2, /*  20, -4.0dB */
+       0x26000098, /*  21, -4.5dB */
+       0x24000090, /*  22, -5.0dB */
+       0x22000088, /*  23, -5.5dB */
+       0x20000080, /*  24, -6.0dB */
+       0x1e400079, /*  25, -6.5dB */
+       0x1c800072, /*  26, -7.0dB */
+       0x1b00006c, /*  27. -7.5dB */
+       0x19800066, /*  28, -8.0dB */
+       0x18000060, /*  29, -8.5dB */
+       0x16c0005b, /*  30, -9.0dB */
+       0x15800056, /*  31, -9.5dB */
+       0x14400051, /*  32, -10.0dB */
+       0x1300004c, /*  33, -10.5dB */
+       0x12000048, /*  34, -11.0dB */
+       0x11000044, /*  35, -11.5dB */
+       0x10000040, /*  36, -12.0dB */
+       0x0f00003c,/*  37, -12.5dB */
+       0x0e400039,/*  38, -13.0dB */
+       0x0d800036,/*  39, -13.5dB */
+       0x0cc00033,/*  40, -14.0dB */
+       0x0c000030,/*  41, -14.5dB */
+       0x0b40002d,/*  42, -15.0dB */
+};
+
+u8 CCKSwingTable_Ch1_Ch1323A[CCK_TABLE_SIZE][8] = {
+       {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /*  0, +0dB */
+       {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04}, /*  1, -0.5dB */
+       {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /*  2, -1.0dB */
+       {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03}, /*  3, -1.5dB */
+       {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /*  4, -2.0dB */
+       {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03}, /*  5, -2.5dB */
+       {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /*  6, -3.0dB */
+       {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03}, /*  7, -3.5dB */
+       {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /*  8, -4.0dB */
+       {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02}, /*  9, -4.5dB */
+       {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /*  10, -5.0dB */
+       {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02}, /*  11, -5.5dB */
+       {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /*  12, -6.0dB */
+       {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02}, /*  13, -6.5dB */
+       {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /*  14, -7.0dB */
+       {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02}, /*  15, -7.5dB */
+       {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /*  16, -8.0dB */
+       {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02}, /*  17, -8.5dB */
+       {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /*  18, -9.0dB */
+       {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /*  19, -9.5dB */
+       {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /*  20, -10.0dB */
+       {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01}, /*  21, -10.5dB */
+       {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01}, /*  22, -11.0dB */
+       {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01}, /*  23, -11.5dB */
+       {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01}, /*  24, -12.0dB */
+       {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01}, /*  25, -12.5dB */
+       {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01}, /*  26, -13.0dB */
+       {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01}, /*  27, -13.5dB */
+       {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01}, /*  28, -14.0dB */
+       {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01}, /*  29, -14.5dB */
+       {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01}, /*  30, -15.0dB */
+       {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01}, /*  31, -15.5dB */
+       {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}        /*  32, -16.0dB */
+};
+
+u8 CCKSwingTable_Ch1423A[CCK_TABLE_SIZE][8] = {
+       {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /*  0, +0dB */
+       {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00}, /*  1, -0.5dB */
+       {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /*  2, -1.0dB */
+       {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00}, /*  3, -1.5dB */
+       {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /*  4, -2.0dB */
+       {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00}, /*  5, -2.5dB */
+       {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /*  6, -3.0dB */
+       {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00}, /*  7, -3.5dB */
+       {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /*  8, -4.0dB */
+       {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00}, /*  9, -4.5dB */
+       {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /*  10, -5.0dB */
+       {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00}, /*  11, -5.5dB */
+       {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /*  12, -6.0dB */
+       {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00}, /*  13, -6.5dB */
+       {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /*  14, -7.0dB */
+       {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00}, /*  15, -7.5dB */
+       {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /*  16, -8.0dB */
+       {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00}, /*  17, -8.5dB */
+       {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /*  18, -9.0dB */
+       {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /*  19, -9.5dB */
+       {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /*  20, -10.0dB */
+       {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00}, /*  21, -10.5dB */
+       {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00}, /*  22, -11.0dB */
+       {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /*  23, -11.5dB */
+       {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00}, /*  24, -12.0dB */
+       {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  25, -12.5dB */
+       {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  26, -13.0dB */
+       {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00}, /*  27, -13.5dB */
+       {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  28, -14.0dB */
+       {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  29, -14.5dB */
+       {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  30, -15.0dB */
+       {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00}, /*  31, -15.5dB */
+       {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}        /*  32, -16.0dB */
+};
+
+/*  Local Function predefine. */
+
+/* START------------COMMON INFO RELATED--------------- */
+void odm_CommonInfoSelfInit23a(struct dm_odm_t *pDM_Odm);
+
+void odm_CommonInfoSelfUpdate23a(struct dm_odm_t *pDM_Odm);
+
+void odm_CmnInfoInit_Debug23a(struct dm_odm_t *pDM_Odm);
+
+void odm_CmnInfoHook_Debug23a(struct dm_odm_t *pDM_Odm);
+
+void odm_CmnInfoUpdate_Debug23a(struct dm_odm_t *pDM_Odm);
+
+/* START---------------DIG--------------------------- */
+void odm_FalseAlarmCounterStatistics23a(struct dm_odm_t *pDM_Odm);
+
+void odm_DIG23aInit(struct dm_odm_t *pDM_Odm);
+
+void odm_DIG23a(struct dm_odm_t *pDM_Odm);
+
+void odm_CCKPacketDetectionThresh23a(struct dm_odm_t *pDM_Odm);
+/* END---------------DIG--------------------------- */
+
+/* START-------BB POWER SAVE----------------------- */
+void odm23a_DynBBPSInit(struct dm_odm_t *pDM_Odm);
+
+void odm_DynamicBBPowerSaving23a(struct dm_odm_t *pDM_Odm);
+
+void odm_1R_CCA23a(struct dm_odm_t *pDM_Odm);
+/* END---------BB POWER SAVE----------------------- */
+
+void odm_RefreshRateAdaptiveMask23aMP23a(struct dm_odm_t *pDM_Odm);
+
+void odm_RefreshRateAdaptiveMask23aCE23a(struct dm_odm_t *pDM_Odm);
+
+void odm_RefreshRateAdaptiveMask23aAPADSL23a(struct dm_odm_t *pDM_Odm);
+
+void odm_DynamicTxPower23aInit(struct dm_odm_t *pDM_Odm);
+
+void odm_DynamicTxPower23aRestorePowerIndex(struct dm_odm_t *pDM_Odm);
+
+void odm_DynamicTxPower23aSavePowerIndex(struct dm_odm_t *pDM_Odm);
+
+void odm_DynamicTxPower23aWritePowerIndex(struct dm_odm_t *pDM_Odm,
+       u8 Value);
+
+void odm_DynamicTxPower23a_92C(struct dm_odm_t *pDM_Odm);
+
+void odm_DynamicTxPower23a_92D(struct dm_odm_t *pDM_Odm);
+
+void odm_RSSIMonitorInit(struct dm_odm_t *pDM_Odm);
+
+void odm_RSSIMonitorCheck23aMP(struct dm_odm_t *pDM_Odm);
+
+void odm_RSSIMonitorCheck23aCE(struct dm_odm_t *pDM_Odm);
+void odm_RSSIMonitorCheck23aAP(struct dm_odm_t *pDM_Odm);
+
+void odm_RSSIMonitorCheck23a(struct dm_odm_t *pDM_Odm);
+void odm_DynamicTxPower23a(struct dm_odm_t *pDM_Odm);
+
+void odm_SwAntDivInit(struct dm_odm_t *pDM_Odm);
+
+void odm_SwAntDivInit_NIC(struct dm_odm_t *pDM_Odm);
+
+void odm_SwAntDivChkAntSwitch(struct dm_odm_t *pDM_Odm, u8 Step);
+
+void odm_SwAntDivChkAntSwitchNIC(struct dm_odm_t *pDM_Odm,
+               u8 Step
+       );
+
+void odm_SwAntDivChkAntSwitchCallback23a(unsigned long data);
+
+void odm_GlobalAdapterCheck(void);
+
+void odm_RefreshRateAdaptiveMask23a(struct dm_odm_t *pDM_Odm);
+
+void ODM_TXPowerTrackingCheck23a(struct dm_odm_t *pDM_Odm);
+
+void odm_TXPowerTrackingCheckAP(struct dm_odm_t *pDM_Odm);
+
+void odm_RateAdaptiveMaskInit23a(struct dm_odm_t *pDM_Odm);
+
+void odm_TXPowerTrackingThermalMeterInit23a(struct dm_odm_t *pDM_Odm);
+
+void odm_TXPowerTrackingInit23a(struct dm_odm_t *pDM_Odm);
+
+void odm_TXPowerTrackingCheckMP(struct dm_odm_t *pDM_Odm);
+
+void odm_TXPowerTrackingCheckCE23a(struct dm_odm_t *pDM_Odm);
+
+void odm_EdcaTurboCheck23a(struct dm_odm_t *pDM_Odm);
+void ODM_EdcaTurboInit23a(struct dm_odm_t *pDM_Odm);
+
+void odm_EdcaTurboCheck23aCE23a(struct dm_odm_t *pDM_Odm);
+
+#define                RxDefaultAnt1           0x65a9
+#define        RxDefaultAnt2           0x569a
+
+void odm_InitHybridAntDiv23a(struct dm_odm_t *pDM_Odm);
+
+bool odm_StaDefAntSel(struct dm_odm_t *pDM_Odm,
+ u32 OFDM_Ant1_Cnt,
+ u32 OFDM_Ant2_Cnt,
+ u32 CCK_Ant1_Cnt,
+ u32 CCK_Ant2_Cnt,
+ u8 *pDefAnt
+       );
+
+void odm_SetRxIdleAnt(struct dm_odm_t *pDM_Odm,
+       u8 Ant,
+   bool   bDualPath
+);
+
+void odm_HwAntDiv23a(struct dm_odm_t *pDM_Odm);
+
+/* 3 Export Interface */
+
+/*  2011/09/21 MH Add to describe different team necessary resource allocate?? */
+void ODM23a_DMInit(struct dm_odm_t *pDM_Odm)
+{
+       /* For all IC series */
+       odm_CommonInfoSelfInit23a(pDM_Odm);
+       odm_CmnInfoInit_Debug23a(pDM_Odm);
+       odm_DIG23aInit(pDM_Odm);
+       odm_RateAdaptiveMaskInit23a(pDM_Odm);
+
+       if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) {
+               odm23a_DynBBPSInit(pDM_Odm);
+               odm_DynamicTxPower23aInit(pDM_Odm);
+               odm_TXPowerTrackingInit23a(pDM_Odm);
+               ODM_EdcaTurboInit23a(pDM_Odm);
+               if ((pDM_Odm->AntDivType == CG_TRX_HW_ANTDIV)   ||
+                   (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV)  ||
+                   (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV))
+                       odm_InitHybridAntDiv23a(pDM_Odm);
+               else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV)
+                       odm_SwAntDivInit(pDM_Odm);
+       }
+}
+
+/*  2011/09/20 MH This is the entry pointer for all team to execute HW out source DM. */
+/*  You can not add any dummy function here, be care, you can only use DM structure */
+/*  to perform any new ODM_DM. */
+void ODM_DMWatchdog23a(struct dm_odm_t *pDM_Odm)
+{
+       /* 2012.05.03 Luke: For all IC series */
+       odm_GlobalAdapterCheck();
+       odm_CmnInfoHook_Debug23a(pDM_Odm);
+       odm_CmnInfoUpdate_Debug23a(pDM_Odm);
+       odm_CommonInfoSelfUpdate23a(pDM_Odm);
+       odm_FalseAlarmCounterStatistics23a(pDM_Odm);
+       odm_RSSIMonitorCheck23a(pDM_Odm);
+
+       /* 8723A or 8189ES platform */
+       /* NeilChen--2012--08--24-- */
+       /* Fix Leave LPS issue */
+       if ((pDM_Odm->Adapter->pwrctrlpriv.pwr_mode != PS_MODE_ACTIVE) &&/*  in LPS mode */
+           (pDM_Odm->SupportICType & (ODM_RTL8723A))) {
+                       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("----Step1: odm_DIG23a is in LPS mode\n"));
+                       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Step2: 8723AS is in LPS mode\n"));
+                       odm_DIG23abyRSSI_LPS(pDM_Odm);
+       } else {
+               odm_DIG23a(pDM_Odm);
+       }
+
+       odm_CCKPacketDetectionThresh23a(pDM_Odm);
+
+       if (*(pDM_Odm->pbPowerSaving))
+               return;
+
+       odm_RefreshRateAdaptiveMask23a(pDM_Odm);
+
+       odm_DynamicBBPowerSaving23a(pDM_Odm);
+       if ((pDM_Odm->AntDivType ==  CG_TRX_HW_ANTDIV)  ||
+           (pDM_Odm->AntDivType == CGCS_RX_HW_ANTDIV)  ||
+           (pDM_Odm->AntDivType == CG_TRX_SMART_ANTDIV))
+               odm_HwAntDiv23a(pDM_Odm);
+       else if (pDM_Odm->AntDivType == CGCS_RX_SW_ANTDIV)
+               odm_SwAntDivChkAntSwitch(pDM_Odm, SWAW_STEP_PEAK);
+
+       if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) {
+               ODM_TXPowerTrackingCheck23a(pDM_Odm);
+             odm_EdcaTurboCheck23a(pDM_Odm);
+               odm_DynamicTxPower23a(pDM_Odm);
+       }
+
+       odm_dtc(pDM_Odm);
+}
+
+/*  */
+/*  Init /.. Fixed HW value. Only init time. */
+/*  */
+void ODM_CmnInfoInit23a(struct dm_odm_t *pDM_Odm,
+               enum odm_cmninfo CmnInfo,
+               u32 Value
+       )
+{
+       /* ODM_RT_TRACE(pDM_Odm,); */
+
+       /*  */
+       /*  This section is used for init value */
+       /*  */
+       switch  (CmnInfo) {
+       /*  Fixed ODM value. */
+       case    ODM_CMNINFO_ABILITY:
+               pDM_Odm->SupportAbility = (u32)Value;
+               break;
+       case    ODM_CMNINFO_PLATFORM:
+               break;
+       case    ODM_CMNINFO_INTERFACE:
+               pDM_Odm->SupportInterface = (u8)Value;
+               break;
+       case    ODM_CMNINFO_MP_TEST_CHIP:
+               pDM_Odm->bIsMPChip = (u8)Value;
+               break;
+       case    ODM_CMNINFO_IC_TYPE:
+               pDM_Odm->SupportICType = Value;
+               break;
+       case    ODM_CMNINFO_CUT_VER:
+               pDM_Odm->CutVersion = (u8)Value;
+               break;
+       case    ODM_CMNINFO_FAB_VER:
+               pDM_Odm->FabVersion = (u8)Value;
+               break;
+       case    ODM_CMNINFO_RF_TYPE:
+               pDM_Odm->RFType = (u8)Value;
+               break;
+       case    ODM_CMNINFO_RF_ANTENNA_TYPE:
+               pDM_Odm->AntDivType = (u8)Value;
+               break;
+       case    ODM_CMNINFO_BOARD_TYPE:
+               pDM_Odm->BoardType = (u8)Value;
+               break;
+       case    ODM_CMNINFO_EXT_LNA:
+               pDM_Odm->ExtLNA = (u8)Value;
+               break;
+       case    ODM_CMNINFO_EXT_PA:
+               pDM_Odm->ExtPA = (u8)Value;
+               break;
+       case    ODM_CMNINFO_EXT_TRSW:
+               pDM_Odm->ExtTRSW = (u8)Value;
+               break;
+       case    ODM_CMNINFO_PATCH_ID:
+               pDM_Odm->PatchID = (u8)Value;
+               break;
+       case    ODM_CMNINFO_BINHCT_TEST:
+               pDM_Odm->bInHctTest = (bool)Value;
+               break;
+       case    ODM_CMNINFO_BWIFI_TEST:
+               pDM_Odm->bWIFITest = (bool)Value;
+               break;
+       case    ODM_CMNINFO_SMART_CONCURRENT:
+               pDM_Odm->bDualMacSmartConcurrent = (bool)Value;
+               break;
+       /* To remove the compiler warning, must add an empty default statement to handle the other values. */
+       default:
+               /* do nothing */
+               break;
+       }
+
+       /*  */
+       /*  Tx power tracking BB swing table. */
+       /*  The base index = 12. +((12-n)/2)dB 13~?? = decrease tx pwr by -((n-12)/2)dB */
+       /*  */
+       pDM_Odm->BbSwingIdxOfdm                 = 12; /*  Set defalut value as index 12. */
+       pDM_Odm->BbSwingIdxOfdmCurrent  = 12;
+       pDM_Odm->BbSwingFlagOfdm                = false;
+
+}
+
+void ODM23a_CmnInfoHook(struct dm_odm_t *pDM_Odm,
+               enum odm_cmninfo CmnInfo,
+               void *pValue
+       )
+{
+       /*  Hook call by reference pointer. */
+       switch  (CmnInfo) {
+       /*  Dynamic call by reference pointer. */
+       case    ODM_CMNINFO_MAC_PHY_MODE:
+               pDM_Odm->pMacPhyMode = (u8 *)pValue;
+               break;
+       case    ODM_CMNINFO_TX_UNI:
+               pDM_Odm->pNumTxBytesUnicast = (u64 *)pValue;
+               break;
+       case    ODM_CMNINFO_RX_UNI:
+               pDM_Odm->pNumRxBytesUnicast = (u64 *)pValue;
+               break;
+       case    ODM_CMNINFO_WM_MODE:
+               pDM_Odm->pWirelessMode = (u8 *)pValue;
+               break;
+       case    ODM_CMNINFO_BAND:
+               pDM_Odm->pBandType = (u8 *)pValue;
+               break;
+       case    ODM_CMNINFO_SEC_CHNL_OFFSET:
+               pDM_Odm->pSecChOffset = (u8 *)pValue;
+               break;
+       case    ODM_CMNINFO_SEC_MODE:
+               pDM_Odm->pSecurity = (u8 *)pValue;
+               break;
+       case    ODM_CMNINFO_BW:
+               pDM_Odm->pBandWidth = (u8 *)pValue;
+               break;
+       case    ODM_CMNINFO_CHNL:
+               pDM_Odm->pChannel = (u8 *)pValue;
+               break;
+       case    ODM_CMNINFO_DMSP_GET_VALUE:
+               pDM_Odm->pbGetValueFromOtherMac = (bool *)pValue;
+               break;
+       case    ODM_CMNINFO_BUDDY_ADAPTOR:
+               pDM_Odm->pBuddyAdapter = (struct rtw_adapter **)pValue;
+               break;
+       case    ODM_CMNINFO_DMSP_IS_MASTER:
+               pDM_Odm->pbMasterOfDMSP = (bool *)pValue;
+               break;
+       case    ODM_CMNINFO_SCAN:
+               pDM_Odm->pbScanInProcess = (bool *)pValue;
+               break;
+       case    ODM_CMNINFO_POWER_SAVING:
+               pDM_Odm->pbPowerSaving = (bool *)pValue;
+               break;
+       case    ODM_CMNINFO_ONE_PATH_CCA:
+               pDM_Odm->pOnePathCCA = (u8 *)pValue;
+               break;
+       case    ODM_CMNINFO_DRV_STOP:
+               pDM_Odm->pbDriverStopped =  (bool *)pValue;
+               break;
+       case    ODM_CMNINFO_PNP_IN:
+               pDM_Odm->pbDriverIsGoingToPnpSetPowerSleep =  (bool *)pValue;
+               break;
+       case    ODM_CMNINFO_INIT_ON:
+               pDM_Odm->pinit_adpt_in_progress =  (bool *)pValue;
+               break;
+       case    ODM_CMNINFO_ANT_TEST:
+               pDM_Odm->pAntennaTest =  (u8 *)pValue;
+               break;
+       case    ODM_CMNINFO_NET_CLOSED:
+               pDM_Odm->pbNet_closed = (bool *)pValue;
+               break;
+       /* To remove the compiler warning, must add an empty default statement to handle the other values. */
+       default:
+               /* do nothing */
+               break;
+       }
+}
+
+void ODM_CmnInfoPtrArrayHook23a(struct dm_odm_t *pDM_Odm, enum odm_cmninfo CmnInfo,
+                               u16 Index, void *pValue)
+{
+       /*  Hook call by reference pointer. */
+       switch  (CmnInfo) {
+       /*  Dynamic call by reference pointer. */
+       case    ODM_CMNINFO_STA_STATUS:
+               pDM_Odm->pODM_StaInfo[Index] = (struct sta_info *)pValue;
+               break;
+       /* To remove the compiler warning, must add an empty default statement to handle the other values. */
+       default:
+               /* do nothing */
+               break;
+       }
+}
+
+/*  Update Band/CHannel/.. The values are dynamic but non-per-packet. */
+void ODM_CmnInfoUpdate23a(struct dm_odm_t *pDM_Odm, u32 CmnInfo, u64 Value)
+{
+       /*  This init variable may be changed in run time. */
+       switch  (CmnInfo) {
+       case    ODM_CMNINFO_ABILITY:
+               pDM_Odm->SupportAbility = (u32)Value;
+               break;
+       case    ODM_CMNINFO_RF_TYPE:
+               pDM_Odm->RFType = (u8)Value;
+               break;
+       case    ODM_CMNINFO_WIFI_DIRECT:
+               pDM_Odm->bWIFI_Direct = (bool)Value;
+               break;
+       case    ODM_CMNINFO_WIFI_DISPLAY:
+               pDM_Odm->bWIFI_Display = (bool)Value;
+               break;
+       case    ODM_CMNINFO_LINK:
+               pDM_Odm->bLinked = (bool)Value;
+               break;
+       case    ODM_CMNINFO_RSSI_MIN:
+               pDM_Odm->RSSI_Min = (u8)Value;
+               break;
+       case    ODM_CMNINFO_DBG_COMP:
+               pDM_Odm->DebugComponents = Value;
+               break;
+       case    ODM_CMNINFO_DBG_LEVEL:
+               pDM_Odm->DebugLevel = (u32)Value;
+               break;
+       case    ODM_CMNINFO_RA_THRESHOLD_HIGH:
+               pDM_Odm->RateAdaptive.HighRSSIThresh = (u8)Value;
+               break;
+       case    ODM_CMNINFO_RA_THRESHOLD_LOW:
+               pDM_Odm->RateAdaptive.LowRSSIThresh = (u8)Value;
+               break;
+       }
+
+}
+
+void odm_CommonInfoSelfInit23a(struct dm_odm_t *pDM_Odm
+       )
+{
+       pDM_Odm->bCckHighPower = (bool) ODM_GetBBReg(pDM_Odm, 0x824, BIT9);
+       pDM_Odm->RFPathRxEnable = (u8) ODM_GetBBReg(pDM_Odm, 0xc04, 0x0F);
+       if (pDM_Odm->SupportICType & (ODM_RTL8723A))
+               pDM_Odm->AntDivType = CGCS_RX_SW_ANTDIV;
+
+       ODM_InitDebugSetting23a(pDM_Odm);
+}
+
+void odm_CommonInfoSelfUpdate23a(struct dm_odm_t *pDM_Odm)
+{
+       u8 EntryCnt = 0;
+       u8 i;
+       struct sta_info *pEntry;
+
+       if (*(pDM_Odm->pBandWidth) == ODM_BW40M) {
+               if (*(pDM_Odm->pSecChOffset) == 1)
+                       pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) - 2;
+               else if (*(pDM_Odm->pSecChOffset) == 2)
+                       pDM_Odm->ControlChannel = *(pDM_Odm->pChannel) + 2;
+       } else {
+               pDM_Odm->ControlChannel = *(pDM_Odm->pChannel);
+       }
+
+       for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+               pEntry = pDM_Odm->pODM_StaInfo[i];
+               if (IS_STA_VALID(pEntry))
+                       EntryCnt++;
+       }
+       if (EntryCnt == 1)
+               pDM_Odm->bOneEntryOnly = true;
+       else
+               pDM_Odm->bOneEntryOnly = false;
+}
+
+void odm_CmnInfoInit_Debug23a(struct dm_odm_t *pDM_Odm)
+{
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoInit_Debug23a ==>\n"));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportAbility = 0x%x\n", pDM_Odm->SupportAbility));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportInterface =%d\n", pDM_Odm->SupportInterface));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("SupportICType = 0x%x\n", pDM_Odm->SupportICType));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("CutVersion =%d\n", pDM_Odm->CutVersion));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("FabVersion =%d\n", pDM_Odm->FabVersion));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RFType =%d\n", pDM_Odm->RFType));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("BoardType =%d\n", pDM_Odm->BoardType));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtLNA =%d\n", pDM_Odm->ExtLNA));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtPA =%d\n", pDM_Odm->ExtPA));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("ExtTRSW =%d\n", pDM_Odm->ExtTRSW));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("PatchID =%d\n", pDM_Odm->PatchID));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bInHctTest =%d\n", pDM_Odm->bInHctTest));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFITest =%d\n", pDM_Odm->bWIFITest));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bDualMacSmartConcurrent =%d\n", pDM_Odm->bDualMacSmartConcurrent));
+
+}
+
+void odm_CmnInfoHook_Debug23a(struct dm_odm_t *pDM_Odm)
+{
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoHook_Debug23a ==>\n"));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumTxBytesUnicast =%llu\n", *(pDM_Odm->pNumTxBytesUnicast)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pNumRxBytesUnicast =%llu\n", *(pDM_Odm->pNumRxBytesUnicast)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pWirelessMode = 0x%x\n", *(pDM_Odm->pWirelessMode)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecChOffset =%d\n", *(pDM_Odm->pSecChOffset)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pSecurity =%d\n", *(pDM_Odm->pSecurity)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pBandWidth =%d\n", *(pDM_Odm->pBandWidth)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pChannel =%d\n", *(pDM_Odm->pChannel)));
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbScanInProcess =%d\n", *(pDM_Odm->pbScanInProcess)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("pbPowerSaving =%d\n", *(pDM_Odm->pbPowerSaving)));
+}
+
+void odm_CmnInfoUpdate_Debug23a(struct dm_odm_t *pDM_Odm)
+{
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("odm_CmnInfoUpdate_Debug23a ==>\n"));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Direct =%d\n", pDM_Odm->bWIFI_Direct));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bWIFI_Display =%d\n", pDM_Odm->bWIFI_Display));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("bLinked =%d\n", pDM_Odm->bLinked));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_COMMON, ODM_DBG_LOUD, ("RSSI_Min =%d\n", pDM_Odm->RSSI_Min));
+}
+
+void ODM_Write_DIG23a(struct dm_odm_t *pDM_Odm,
+       u8 CurrentIGI
+       )
+{
+       struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable;
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("ODM_REG(IGI_A, pDM_Odm) = 0x%x, ODM_BIT(IGI, pDM_Odm) = 0x%x \n",
+               ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm)));
+
+       if (pDM_DigTable->CurIGValue != CurrentIGI) {
+               ODM_SetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm), CurrentIGI);
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("CurrentIGI(0x%02x). \n", CurrentIGI));
+               pDM_DigTable->CurIGValue = CurrentIGI;
+       }
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+                    ("ODM_Write_DIG23a():CurrentIGI = 0x%x \n", CurrentIGI));
+}
+
+/* Need LPS mode for CE platform --2012--08--24--- */
+/* 8723AS/8189ES */
+void odm_DIG23abyRSSI_LPS(struct dm_odm_t *pDM_Odm)
+{
+       struct rtw_adapter *pAdapter = pDM_Odm->Adapter;
+       struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt;
+       u8 RSSI_Lower = DM_DIG_MIN_NIC;   /* 0x1E or 0x1C */
+       u8 bFwCurrentInPSMode = false;
+       u8 CurrentIGI = pDM_Odm->RSSI_Min;
+
+       if (!(pDM_Odm->SupportICType & (ODM_RTL8723A)))
+               return;
+
+       CurrentIGI = CurrentIGI+RSSI_OFFSET_DIG;
+       bFwCurrentInPSMode = pAdapter->pwrctrlpriv.bFwCurrentInPSMode;
+
+       /* ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG_LPS, ODM_DBG_LOUD, ("odm_DIG23a() ==>\n")); */
+
+       /*  Using FW PS mode to make IGI */
+       if (bFwCurrentInPSMode) {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("---Neil---odm_DIG23a is in LPS mode\n"));
+               /* Adjust by  FA in LPS MODE */
+               if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2_LPS)
+                       CurrentIGI = CurrentIGI+2;
+               else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1_LPS)
+                       CurrentIGI = CurrentIGI+1;
+               else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0_LPS)
+                       CurrentIGI = CurrentIGI-1;
+       } else {
+               CurrentIGI = RSSI_Lower;
+       }
+
+       /* Lower bound checking */
+
+       /* RSSI Lower bound check */
+       if ((pDM_Odm->RSSI_Min-10) > DM_DIG_MIN_NIC)
+               RSSI_Lower = (pDM_Odm->RSSI_Min-10);
+       else
+               RSSI_Lower = DM_DIG_MIN_NIC;
+
+       /* Upper and Lower Bound checking */
+        if (CurrentIGI > DM_DIG_MAX_NIC)
+               CurrentIGI = DM_DIG_MAX_NIC;
+        else if (CurrentIGI < RSSI_Lower)
+               CurrentIGI = RSSI_Lower;
+
+       ODM_Write_DIG23a(pDM_Odm, CurrentIGI);/* ODM_Write_DIG23a(pDM_Odm, pDM_DigTable->CurIGValue); */
+
+}
+
+void odm_DIG23aInit(struct dm_odm_t *pDM_Odm)
+{
+       struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable;
+
+       pDM_DigTable->CurIGValue = (u8) ODM_GetBBReg(pDM_Odm, ODM_REG(IGI_A, pDM_Odm), ODM_BIT(IGI, pDM_Odm));
+       pDM_DigTable->RssiLowThresh     = DM_DIG_THRESH_LOW;
+       pDM_DigTable->RssiHighThresh    = DM_DIG_THRESH_HIGH;
+       pDM_DigTable->FALowThresh       = DM_FALSEALARM_THRESH_LOW;
+       pDM_DigTable->FAHighThresh      = DM_FALSEALARM_THRESH_HIGH;
+       if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) {
+               pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+               pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
+       } else {
+               pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+               pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
+       }
+       pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT;
+       pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX;
+       pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN;
+       pDM_DigTable->PreCCK_CCAThres = 0xFF;
+       pDM_DigTable->CurCCK_CCAThres = 0x83;
+       pDM_DigTable->ForbiddenIGI = DM_DIG_MIN_NIC;
+       pDM_DigTable->LargeFAHit = 0;
+       pDM_DigTable->Recover_cnt = 0;
+       pDM_DigTable->DIG_Dynamic_MIN_0 = DM_DIG_MIN_NIC;
+       pDM_DigTable->DIG_Dynamic_MIN_1 = DM_DIG_MIN_NIC;
+       pDM_DigTable->bMediaConnect_0 = false;
+       pDM_DigTable->bMediaConnect_1 = false;
+
+       /* To Initialize pDM_Odm->bDMInitialGainEnable == false to avoid DIG error */
+       pDM_Odm->bDMInitialGainEnable = true;
+
+}
+
+void odm_DIG23a(struct dm_odm_t *pDM_Odm)
+{
+
+       struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable;
+       struct false_alarm_stats *pFalseAlmCnt = &pDM_Odm->FalseAlmCnt;
+       u8 DIG_Dynamic_MIN;
+       u8 DIG_MaxOfMin;
+       bool FirstConnect, FirstDisConnect;
+       u8 dm_dig_max, dm_dig_min;
+       u8 CurrentIGI = pDM_DigTable->CurIGValue;
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a() ==>\n"));
+       /* if (!(pDM_Odm->SupportAbility & (ODM_BB_DIG|ODM_BB_FA_CNT))) */
+       if ((!(pDM_Odm->SupportAbility&ODM_BB_DIG)) || (!(pDM_Odm->SupportAbility&ODM_BB_FA_CNT))) {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+                            ("odm_DIG23a() Return: SupportAbility ODM_BB_DIG or ODM_BB_FA_CNT is disabled\n"));
+               return;
+       }
+
+       if (*(pDM_Odm->pbScanInProcess)) {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a() Return: In Scan Progress \n"));
+               return;
+       }
+
+       /* add by Neil Chen to avoid PSD is processing */
+       if (!pDM_Odm->bDMInitialGainEnable) {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a() Return: PSD is Processing \n"));
+               return;
+       }
+
+       DIG_Dynamic_MIN = pDM_DigTable->DIG_Dynamic_MIN_0;
+       FirstConnect = (pDM_Odm->bLinked) && (!pDM_DigTable->bMediaConnect_0);
+       FirstDisConnect = (!pDM_Odm->bLinked) && (pDM_DigTable->bMediaConnect_0);
+
+       /* 1 Boundary Decision */
+       if ((pDM_Odm->SupportICType & (ODM_RTL8723A)) &&
+           ((pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) || pDM_Odm->ExtLNA)) {
+               dm_dig_max = DM_DIG_MAX_NIC_HP;
+               dm_dig_min = DM_DIG_MIN_NIC_HP;
+               DIG_MaxOfMin = DM_DIG_MAX_AP_HP;
+       } else {
+               dm_dig_max = DM_DIG_MAX_NIC;
+               dm_dig_min = DM_DIG_MIN_NIC;
+               DIG_MaxOfMin = DM_DIG_MAX_AP;
+       }
+
+       if (pDM_Odm->bLinked) {
+             /* 2 8723A Series, offset need to be 10 */
+               if (pDM_Odm->SupportICType == (ODM_RTL8723A)) {
+                       /* 2 Upper Bound */
+                       if ((pDM_Odm->RSSI_Min + 10) > DM_DIG_MAX_NIC)
+                               pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+                       else if ((pDM_Odm->RSSI_Min + 10) < DM_DIG_MIN_NIC)
+                               pDM_DigTable->rx_gain_range_max = DM_DIG_MIN_NIC;
+                       else
+                               pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 10;
+
+                       /* 2 If BT is Concurrent, need to set Lower Bound */
+                       DIG_Dynamic_MIN = DM_DIG_MIN_NIC;
+               } else {
+                       /* 2 Modify DIG upper bound */
+                       if ((pDM_Odm->RSSI_Min + 20) > dm_dig_max)
+                               pDM_DigTable->rx_gain_range_max = dm_dig_max;
+                       else if ((pDM_Odm->RSSI_Min + 20) < dm_dig_min)
+                               pDM_DigTable->rx_gain_range_max = dm_dig_min;
+                       else
+                               pDM_DigTable->rx_gain_range_max = pDM_Odm->RSSI_Min + 20;
+
+                       /* 2 Modify DIG lower bound */
+                       if (pDM_Odm->bOneEntryOnly) {
+                               if (pDM_Odm->RSSI_Min < dm_dig_min)
+                                       DIG_Dynamic_MIN = dm_dig_min;
+                               else if (pDM_Odm->RSSI_Min > DIG_MaxOfMin)
+                                       DIG_Dynamic_MIN = DIG_MaxOfMin;
+                               else
+                                       DIG_Dynamic_MIN = pDM_Odm->RSSI_Min;
+                               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+                                            ("odm_DIG23a() : bOneEntryOnly = true,  DIG_Dynamic_MIN = 0x%x\n",
+                                            DIG_Dynamic_MIN));
+                               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+                                            ("odm_DIG23a() : pDM_Odm->RSSI_Min =%d\n",
+                                            pDM_Odm->RSSI_Min));
+                       } else {
+                               DIG_Dynamic_MIN = dm_dig_min;
+                       }
+               }
+       } else {
+               pDM_DigTable->rx_gain_range_max = dm_dig_max;
+               DIG_Dynamic_MIN = dm_dig_min;
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a() : No Link\n"));
+       }
+
+       /* 1 Modify DIG lower bound, deal with abnormally large false alarm */
+       if (pFalseAlmCnt->Cnt_all > 10000) {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+                            ("dm_DIG(): Abnornally false alarm case. \n"));
+
+               if (pDM_DigTable->LargeFAHit != 3)
+                       pDM_DigTable->LargeFAHit++;
+               if (pDM_DigTable->ForbiddenIGI < CurrentIGI) {
+                       pDM_DigTable->ForbiddenIGI = CurrentIGI;
+                       pDM_DigTable->LargeFAHit = 1;
+               }
+
+               if (pDM_DigTable->LargeFAHit >= 3) {
+                       if ((pDM_DigTable->ForbiddenIGI+1) > pDM_DigTable->rx_gain_range_max)
+                               pDM_DigTable->rx_gain_range_min = pDM_DigTable->rx_gain_range_max;
+                       else
+                               pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1);
+                       pDM_DigTable->Recover_cnt = 3600; /* 3600 = 2hr */
+               }
+       } else {
+               /* Recovery mechanism for IGI lower bound */
+               if (pDM_DigTable->Recover_cnt != 0) {
+                       pDM_DigTable->Recover_cnt--;
+               } else {
+                       if (pDM_DigTable->LargeFAHit < 3) {
+                               if ((pDM_DigTable->ForbiddenIGI - 1) < DIG_Dynamic_MIN) {
+                                       pDM_DigTable->ForbiddenIGI = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
+                                       pDM_DigTable->rx_gain_range_min = DIG_Dynamic_MIN; /* DM_DIG_MIN; */
+                                       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+                                                    ("odm_DIG23a(): Normal Case: At Lower Bound\n"));
+                               } else {
+                                       pDM_DigTable->ForbiddenIGI--;
+                                       pDM_DigTable->rx_gain_range_min = (pDM_DigTable->ForbiddenIGI + 1);
+                                       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD,
+                                                    ("odm_DIG23a(): Normal Case: Approach Lower Bound\n"));
+                               }
+                       } else {
+                               pDM_DigTable->LargeFAHit = 0;
+                       }
+               }
+       }
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): pDM_DigTable->LargeFAHit =%d\n", pDM_DigTable->LargeFAHit));
+
+       /* 1 Adjust initial gain by false alarm */
+       if (pDM_Odm->bLinked) {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): DIG AfterLink\n"));
+               if (FirstConnect) {
+                       CurrentIGI = pDM_Odm->RSSI_Min;
+                       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("DIG: First Connect\n"));
+               } else {
+                       if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH2)
+                               CurrentIGI = CurrentIGI + 4;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */
+                       else if (pFalseAlmCnt->Cnt_all > DM_DIG_FA_TH1)
+                               CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */
+                       else if (pFalseAlmCnt->Cnt_all < DM_DIG_FA_TH0)
+                               CurrentIGI = CurrentIGI - 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue-1; */
+               }
+       } else {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): DIG BeforeLink\n"));
+               if (FirstDisConnect) {
+                       CurrentIGI = pDM_DigTable->rx_gain_range_min;
+                       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): First DisConnect \n"));
+               } else {
+                       /* 2012.03.30 LukeLee: enable DIG before link but with very high thresholds */
+                       if (pFalseAlmCnt->Cnt_all > 10000)
+                               CurrentIGI = CurrentIGI + 2;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+2; */
+                       else if (pFalseAlmCnt->Cnt_all > 8000)
+                               CurrentIGI = CurrentIGI + 1;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue+1; */
+                       else if (pFalseAlmCnt->Cnt_all < 500)
+                               CurrentIGI = CurrentIGI - 1;/* pDM_DigTable->CurIGValue = pDM_DigTable->PreIGValue-1; */
+                       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): England DIG \n"));
+               }
+       }
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): DIG End Adjust IGI\n"));
+       /* 1 Check initial gain by upper/lower bound */
+       if (CurrentIGI > pDM_DigTable->rx_gain_range_max)
+               CurrentIGI = pDM_DigTable->rx_gain_range_max;
+       if (CurrentIGI < pDM_DigTable->rx_gain_range_min)
+               CurrentIGI = pDM_DigTable->rx_gain_range_min;
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): rx_gain_range_max = 0x%x, rx_gain_range_min = 0x%x\n",
+               pDM_DigTable->rx_gain_range_max, pDM_DigTable->rx_gain_range_min));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): TotalFA =%d\n", pFalseAlmCnt->Cnt_all));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_DIG, ODM_DBG_LOUD, ("odm_DIG23a(): CurIGValue = 0x%x\n", CurrentIGI));
+
+       /* 2 High power RSSI threshold */
+
+       ODM_Write_DIG23a(pDM_Odm, CurrentIGI);/* ODM_Write_DIG23a(pDM_Odm, pDM_DigTable->CurIGValue); */
+       pDM_DigTable->bMediaConnect_0 = pDM_Odm->bLinked;
+       pDM_DigTable->DIG_Dynamic_MIN_0 = DIG_Dynamic_MIN;
+}
+
+/* 3 ============================================================ */
+/* 3 FASLE ALARM CHECK */
+/* 3 ============================================================ */
+
+void odm_FalseAlarmCounterStatistics23a(struct dm_odm_t *pDM_Odm)
+{
+       u32 ret_value;
+       struct false_alarm_stats *FalseAlmCnt = &pDM_Odm->FalseAlmCnt;
+
+       if (!(pDM_Odm->SupportAbility & ODM_BB_FA_CNT))
+               return;
+
+       if (pDM_Odm->SupportICType & ODM_IC_11N_SERIES) {
+               /* hold ofdm counter */
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 1); /* hold page C counter */
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 1); /* hold page D counter */
+
+               ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE1_11N, bMaskDWord);
+               FalseAlmCnt->Cnt_Fast_Fsync = (ret_value&0xffff);
+               FalseAlmCnt->Cnt_SB_Search_fail = ((ret_value&0xffff0000)>>16);
+               ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE2_11N, bMaskDWord);
+               FalseAlmCnt->Cnt_OFDM_CCA = (ret_value&0xffff);
+               FalseAlmCnt->Cnt_Parity_Fail = ((ret_value&0xffff0000)>>16);
+               ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE3_11N, bMaskDWord);
+               FalseAlmCnt->Cnt_Rate_Illegal = (ret_value&0xffff);
+               FalseAlmCnt->Cnt_Crc8_fail = ((ret_value&0xffff0000)>>16);
+               ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_TYPE4_11N, bMaskDWord);
+               FalseAlmCnt->Cnt_Mcs_fail = (ret_value&0xffff);
+
+               FalseAlmCnt->Cnt_Ofdm_fail = FalseAlmCnt->Cnt_Parity_Fail +
+                                            FalseAlmCnt->Cnt_Rate_Illegal +
+                                            FalseAlmCnt->Cnt_Crc8_fail +
+                                            FalseAlmCnt->Cnt_Mcs_fail +
+                                            FalseAlmCnt->Cnt_Fast_Fsync +
+                                            FalseAlmCnt->Cnt_SB_Search_fail;
+       /* hold cck counter */
+       ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT12, 1);
+       ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT14, 1);
+
+       ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_LSB_11N, bMaskByte0);
+       FalseAlmCnt->Cnt_Cck_fail = ret_value;
+       ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_MSB_11N, bMaskByte3);
+       FalseAlmCnt->Cnt_Cck_fail +=  (ret_value & 0xff) << 8;
+
+       ret_value = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_CCA_CNT_11N, bMaskDWord);
+       FalseAlmCnt->Cnt_CCK_CCA = ((ret_value&0xFF)<<8) | ((ret_value&0xFF00)>>8);
+
+       FalseAlmCnt->Cnt_all = (FalseAlmCnt->Cnt_Fast_Fsync +
+                               FalseAlmCnt->Cnt_SB_Search_fail +
+                               FalseAlmCnt->Cnt_Parity_Fail +
+                               FalseAlmCnt->Cnt_Rate_Illegal +
+                               FalseAlmCnt->Cnt_Crc8_fail +
+                               FalseAlmCnt->Cnt_Mcs_fail +
+                               FalseAlmCnt->Cnt_Cck_fail);
+
+       FalseAlmCnt->Cnt_CCA_all = FalseAlmCnt->Cnt_OFDM_CCA + FalseAlmCnt->Cnt_CCK_CCA;
+
+       if (pDM_Odm->SupportICType >= ODM_RTL8723A) {
+               /* reset false alarm counter registers */
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 1);
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTC_11N, BIT31, 0);
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 1);
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT27, 0);
+               /* update ofdm counter */
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_HOLDC_11N, BIT31, 0); /* update page C counter */
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RSTD_11N, BIT31, 0); /* update page D counter */
+
+               /* reset CCK CCA counter */
+               ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 0);
+               ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT13|BIT12, 2);
+               /* reset CCK FA counter */
+               ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 0);
+               ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11N, BIT15|BIT14, 2);
+       }
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Enter odm_FalseAlarmCounterStatistics23a\n"));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Fast_Fsync =%d, Cnt_SB_Search_fail =%d\n",
+               FalseAlmCnt->Cnt_Fast_Fsync, FalseAlmCnt->Cnt_SB_Search_fail));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Parity_Fail =%d, Cnt_Rate_Illegal =%d\n",
+               FalseAlmCnt->Cnt_Parity_Fail, FalseAlmCnt->Cnt_Rate_Illegal));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Crc8_fail =%d, Cnt_Mcs_fail =%d\n",
+               FalseAlmCnt->Cnt_Crc8_fail, FalseAlmCnt->Cnt_Mcs_fail));
+       } else { /* FOR ODM_IC_11AC_SERIES */
+               /* read OFDM FA counter */
+               FalseAlmCnt->Cnt_Ofdm_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_OFDM_FA_11AC, bMaskLWord);
+               FalseAlmCnt->Cnt_Cck_fail = ODM_GetBBReg(pDM_Odm, ODM_REG_CCK_FA_11AC, bMaskLWord);
+               FalseAlmCnt->Cnt_all = FalseAlmCnt->Cnt_Ofdm_fail + FalseAlmCnt->Cnt_Cck_fail;
+
+               /*  reset OFDM FA coutner */
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 1);
+               ODM_SetBBReg(pDM_Odm, ODM_REG_OFDM_FA_RST_11AC, BIT17, 0);
+               /*  reset CCK FA counter */
+               ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 0);
+               ODM_SetBBReg(pDM_Odm, ODM_REG_CCK_FA_RST_11AC, BIT15, 1);
+       }
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Cck_fail =%d\n", FalseAlmCnt->Cnt_Cck_fail));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Cnt_Ofdm_fail =%d\n", FalseAlmCnt->Cnt_Ofdm_fail));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_FA_CNT, ODM_DBG_LOUD, ("Total False Alarm =%d\n", FalseAlmCnt->Cnt_all));
+}
+
+/* 3 ============================================================ */
+/* 3 CCK Packet Detect Threshold */
+/* 3 ============================================================ */
+
+void odm_CCKPacketDetectionThresh23a(struct dm_odm_t *pDM_Odm)
+{
+       struct false_alarm_stats *FalseAlmCnt = &pDM_Odm->FalseAlmCnt;
+       u8 CurCCK_CCAThres;
+
+       if (!(pDM_Odm->SupportAbility & (ODM_BB_CCK_PD|ODM_BB_FA_CNT)))
+               return;
+
+       if (pDM_Odm->ExtLNA)
+               return;
+
+       if (pDM_Odm->bLinked) {
+               if (pDM_Odm->RSSI_Min > 25) {
+                       CurCCK_CCAThres = 0xcd;
+               } else if ((pDM_Odm->RSSI_Min <= 25) && (pDM_Odm->RSSI_Min > 10)) {
+                       CurCCK_CCAThres = 0x83;
+               } else {
+                       if (FalseAlmCnt->Cnt_Cck_fail > 1000)
+                               CurCCK_CCAThres = 0x83;
+                       else
+                               CurCCK_CCAThres = 0x40;
+               }
+       } else {
+               if (FalseAlmCnt->Cnt_Cck_fail > 1000)
+                       CurCCK_CCAThres = 0x83;
+               else
+                       CurCCK_CCAThres = 0x40;
+       }
+
+       ODM_Write_CCK_CCA_Thres23a(pDM_Odm, CurCCK_CCAThres);
+}
+
+void ODM_Write_CCK_CCA_Thres23a(struct dm_odm_t *pDM_Odm, u8 CurCCK_CCAThres)
+{
+       struct dig_t *pDM_DigTable = &pDM_Odm->DM_DigTable;
+
+       if (pDM_DigTable->CurCCK_CCAThres != CurCCK_CCAThres)
+               ODM_Write1Byte(pDM_Odm, ODM_REG(CCK_CCA, pDM_Odm), CurCCK_CCAThres);
+       pDM_DigTable->PreCCK_CCAThres = pDM_DigTable->CurCCK_CCAThres;
+       pDM_DigTable->CurCCK_CCAThres = CurCCK_CCAThres;
+
+}
+
+/* 3 ============================================================ */
+/* 3 BB Power Save */
+/* 3 ============================================================ */
+void odm23a_DynBBPSInit(struct dm_odm_t *pDM_Odm)
+{
+       struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable;
+
+       pDM_PSTable->PreCCAState = CCA_MAX;
+       pDM_PSTable->CurCCAState = CCA_MAX;
+       pDM_PSTable->PreRFState = RF_MAX;
+       pDM_PSTable->CurRFState = RF_MAX;
+       pDM_PSTable->Rssi_val_min = 0;
+       pDM_PSTable->initialize = 0;
+}
+
+void odm_DynamicBBPowerSaving23a(struct dm_odm_t *pDM_Odm)
+{
+       return;
+}
+
+void odm_1R_CCA23a(struct dm_odm_t *pDM_Odm)
+{
+       struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable;
+
+       if (pDM_Odm->RSSI_Min != 0xFF) {
+               if (pDM_PSTable->PreCCAState == CCA_2R) {
+                       if (pDM_Odm->RSSI_Min >= 35)
+                               pDM_PSTable->CurCCAState = CCA_1R;
+                       else
+                               pDM_PSTable->CurCCAState = CCA_2R;
+               } else {
+                       if (pDM_Odm->RSSI_Min <= 30)
+                               pDM_PSTable->CurCCAState = CCA_2R;
+                       else
+                               pDM_PSTable->CurCCAState = CCA_1R;
+               }
+       } else {
+               pDM_PSTable->CurCCAState = CCA_MAX;
+       }
+
+       if (pDM_PSTable->PreCCAState != pDM_PSTable->CurCCAState) {
+               if (pDM_PSTable->CurCCAState == CCA_1R) {
+                       if (pDM_Odm->RFType == ODM_2T2R)
+                               ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x13);
+                       else
+                               ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x23);
+               } else {
+                       ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x33);
+                       /* PHY_SetBBReg(pAdapter, 0xe70, bMaskByte3, 0x63); */
+               }
+               pDM_PSTable->PreCCAState = pDM_PSTable->CurCCAState;
+       }
+}
+
+void ODM_RF_Saving23a(struct dm_odm_t *pDM_Odm, u8 bForceInNormal)
+{
+       struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable;
+       u8 Rssi_Up_bound = 30 ;
+       u8 Rssi_Low_bound = 25;
+       if (pDM_Odm->PatchID == 40) { /* RT_CID_819x_FUNAI_TV */
+               Rssi_Up_bound = 50 ;
+               Rssi_Low_bound = 45;
+       }
+       if (pDM_PSTable->initialize == 0) {
+
+               pDM_PSTable->Reg874 = (ODM_GetBBReg(pDM_Odm, 0x874, bMaskDWord)&0x1CC000)>>14;
+               pDM_PSTable->RegC70 = (ODM_GetBBReg(pDM_Odm, 0xc70, bMaskDWord)&BIT3)>>3;
+               pDM_PSTable->Reg85C = (ODM_GetBBReg(pDM_Odm, 0x85c, bMaskDWord)&0xFF000000)>>24;
+               pDM_PSTable->RegA74 = (ODM_GetBBReg(pDM_Odm, 0xa74, bMaskDWord)&0xF000)>>12;
+               /* Reg818 = PHY_QueryBBReg(pAdapter, 0x818, bMaskDWord); */
+               pDM_PSTable->initialize = 1;
+       }
+
+       if (!bForceInNormal) {
+               if (pDM_Odm->RSSI_Min != 0xFF) {
+                       if (pDM_PSTable->PreRFState == RF_Normal) {
+                               if (pDM_Odm->RSSI_Min >= Rssi_Up_bound)
+                                       pDM_PSTable->CurRFState = RF_Save;
+                               else
+                                       pDM_PSTable->CurRFState = RF_Normal;
+                       } else {
+                               if (pDM_Odm->RSSI_Min <= Rssi_Low_bound)
+                                       pDM_PSTable->CurRFState = RF_Normal;
+                               else
+                                       pDM_PSTable->CurRFState = RF_Save;
+                       }
+               } else {
+                       pDM_PSTable->CurRFState = RF_MAX;
+               }
+       } else {
+               pDM_PSTable->CurRFState = RF_Normal;
+       }
+
+       if (pDM_PSTable->PreRFState != pDM_PSTable->CurRFState) {
+               if (pDM_PSTable->CurRFState == RF_Save) {
+                       /*  <tynli_note> 8723 RSSI report will be wrong. Set 0x874[5]= 1 when enter BB power saving mode. */
+                       /*  Suggested by SD3 Yu-Nan. 2011.01.20. */
+                       if (pDM_Odm->SupportICType == ODM_RTL8723A)
+                               ODM_SetBBReg(pDM_Odm, 0x874, BIT5, 0x1); /* Reg874[5]= 1b'1 */
+                       ODM_SetBBReg(pDM_Odm, 0x874, 0x1C0000, 0x2); /* Reg874[20:18]= 3'b010 */
+                       ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, 0); /* RegC70[3]= 1'b0 */
+                       ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, 0x63); /* Reg85C[31:24]= 0x63 */
+                       ODM_SetBBReg(pDM_Odm, 0x874, 0xC000, 0x2); /* Reg874[15:14]= 2'b10 */
+                       ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, 0x3); /* RegA75[7:4]= 0x3 */
+                       ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0); /* Reg818[28]= 1'b0 */
+                       ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x1); /* Reg818[28]= 1'b1 */
+               } else {
+                       ODM_SetBBReg(pDM_Odm, 0x874, 0x1CC000, pDM_PSTable->Reg874);
+                       ODM_SetBBReg(pDM_Odm, 0xc70, BIT3, pDM_PSTable->RegC70);
+                       ODM_SetBBReg(pDM_Odm, 0x85c, 0xFF000000, pDM_PSTable->Reg85C);
+                       ODM_SetBBReg(pDM_Odm, 0xa74, 0xF000, pDM_PSTable->RegA74);
+                       ODM_SetBBReg(pDM_Odm, 0x818, BIT28, 0x0);
+
+                       if (pDM_Odm->SupportICType == ODM_RTL8723A)
+                               ODM_SetBBReg(pDM_Odm, 0x874, BIT5, 0x0); /* Reg874[5]= 1b'0 */
+               }
+               pDM_PSTable->PreRFState = pDM_PSTable->CurRFState;
+       }
+}
+
+/* 3 ============================================================ */
+/* 3 RATR MASK */
+/* 3 ============================================================ */
+/* 3 ============================================================ */
+/* 3 Rate Adaptive */
+/* 3 ============================================================ */
+
+void odm_RateAdaptiveMaskInit23a(struct dm_odm_t *pDM_Odm)
+{
+       struct odm_rate_adapt *pOdmRA = &pDM_Odm->RateAdaptive;
+
+       pOdmRA->Type = DM_Type_ByDriver;
+       if (pOdmRA->Type == DM_Type_ByDriver)
+               pDM_Odm->bUseRAMask = true;
+       else
+               pDM_Odm->bUseRAMask = false;
+
+       pOdmRA->RATRState = DM_RATR_STA_INIT;
+       pOdmRA->HighRSSIThresh = 50;
+       pOdmRA->LowRSSIThresh = 20;
+}
+
+u32 ODM_Get_Rate_Bitmap23a(struct dm_odm_t *pDM_Odm,
+       u32 macid,
+       u32 ra_mask,
+       u8 rssi_level)
+{
+       struct sta_info *pEntry;
+       u32 rate_bitmap = 0x0fffffff;
+       u8 WirelessMode;
+       /* u8 WirelessMode =*(pDM_Odm->pWirelessMode); */
+
+       pEntry = pDM_Odm->pODM_StaInfo[macid];
+       if (!IS_STA_VALID(pEntry))
+               return ra_mask;
+
+       WirelessMode = pEntry->wireless_mode;
+
+       switch (WirelessMode) {
+       case ODM_WM_B:
+               if (ra_mask & 0x0000000c)               /* 11M or 5.5M enable */
+                       rate_bitmap = 0x0000000d;
+               else
+                       rate_bitmap = 0x0000000f;
+               break;
+       case (ODM_WM_A|ODM_WM_G):
+               if (rssi_level == DM_RATR_STA_HIGH)
+                       rate_bitmap = 0x00000f00;
+               else
+                       rate_bitmap = 0x00000ff0;
+               break;
+       case (ODM_WM_B|ODM_WM_G):
+               if (rssi_level == DM_RATR_STA_HIGH)
+                       rate_bitmap = 0x00000f00;
+               else if (rssi_level == DM_RATR_STA_MIDDLE)
+                       rate_bitmap = 0x00000ff0;
+               else
+                       rate_bitmap = 0x00000ff5;
+               break;
+       case (ODM_WM_B|ODM_WM_G|ODM_WM_N24G):
+       case (ODM_WM_A|ODM_WM_B|ODM_WM_G|ODM_WM_N24G):
+               if (pDM_Odm->RFType == ODM_1T2R || pDM_Odm->RFType == ODM_1T1R) {
+                       if (rssi_level == DM_RATR_STA_HIGH) {
+                               rate_bitmap = 0x000f0000;
+                       } else if (rssi_level == DM_RATR_STA_MIDDLE) {
+                               rate_bitmap = 0x000ff000;
+                       } else {
+                               if (*(pDM_Odm->pBandWidth) == ODM_BW40M)
+                                       rate_bitmap = 0x000ff015;
+                               else
+                                       rate_bitmap = 0x000ff005;
+                       }
+               } else {
+                       if (rssi_level == DM_RATR_STA_HIGH) {
+                               rate_bitmap = 0x0f8f0000;
+                       } else if (rssi_level == DM_RATR_STA_MIDDLE) {
+                               rate_bitmap = 0x0f8ff000;
+                       } else {
+                               if (*(pDM_Odm->pBandWidth) == ODM_BW40M)
+                                       rate_bitmap = 0x0f8ff015;
+                               else
+                                       rate_bitmap = 0x0f8ff005;
+                       }
+               }
+               break;
+       default:
+               /* case WIRELESS_11_24N: */
+               /* case WIRELESS_11_5N: */
+               if (pDM_Odm->RFType == RF_1T2R)
+                       rate_bitmap = 0x000fffff;
+               else
+                       rate_bitmap = 0x0fffffff;
+               break;
+       }
+
+       /* printk("%s ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x \n", __FUNCTION__, rssi_level, WirelessMode, rate_bitmap); */
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD, (" ==> rssi_level:0x%02x, WirelessMode:0x%02x, rate_bitmap:0x%08x \n", rssi_level, WirelessMode, rate_bitmap));
+
+       return rate_bitmap;
+
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:   odm_RefreshRateAdaptiveMask23a()
+ *
+ * Overview:   Update rate table mask according to rssi
+ *
+ * Input:              NONE
+ *
+ * Output:             NONE
+ *
+ * Return:             NONE
+ *
+ * Revised History:
+ *When         Who             Remark
+ *05/27/2009   hpfan   Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+void odm_RefreshRateAdaptiveMask23a(struct dm_odm_t *pDM_Odm)
+{
+       if (!(pDM_Odm->SupportAbility & ODM_BB_RA_MASK))
+               return;
+       /*  */
+       /*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+       /*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
+       /*  HW dynamic mechanism. */
+       /*  */
+       odm_RefreshRateAdaptiveMask23aCE23a(pDM_Odm);
+}
+
+void odm_RefreshRateAdaptiveMask23aMP23a(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void odm_RefreshRateAdaptiveMask23aCE23a(struct dm_odm_t *pDM_Odm)
+{
+       u8 i;
+       struct rtw_adapter *pAdapter     =  pDM_Odm->Adapter;
+
+       if (pAdapter->bDriverStopped) {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_TRACE,
+                            ("<---- odm_RefreshRateAdaptiveMask23a(): driver is going to unload\n"));
+               return;
+       }
+
+       if (!pDM_Odm->bUseRAMask) {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD,
+                            ("<---- odm_RefreshRateAdaptiveMask23a(): driver does not control rate adaptive mask\n"));
+               return;
+       }
+
+       /* printk("==> %s \n", __FUNCTION__); */
+
+       for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+               struct sta_info *pstat = pDM_Odm->pODM_StaInfo[i];
+               if (IS_STA_VALID(pstat)) {
+                       if (ODM_RAStateCheck23a(pDM_Odm, pstat->rssi_stat.UndecoratedSmoothedPWDB, false, &pstat->rssi_level)) {
+                               ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD,
+                                            ("RSSI:%d, RSSI_LEVEL:%d\n",
+                                            pstat->rssi_stat.UndecoratedSmoothedPWDB,
+                                            pstat->rssi_level));
+                               rtw_hal_update_ra_mask23a(pstat, pstat->rssi_level);
+                       }
+
+               }
+       }
+
+}
+
+void odm_RefreshRateAdaptiveMask23aAPADSL23a(struct dm_odm_t *pDM_Odm)
+{
+}
+
+/*  Return Value: bool */
+/*  - true: RATRState is changed. */
+bool ODM_RAStateCheck23a(struct dm_odm_t *pDM_Odm, s32 RSSI, bool bForceUpdate,
+                        u8 *pRATRState)
+{
+       struct odm_rate_adapt *pRA = &pDM_Odm->RateAdaptive;
+       const u8 GoUpGap = 5;
+       u8 HighRSSIThreshForRA = pRA->HighRSSIThresh;
+       u8 LowRSSIThreshForRA = pRA->LowRSSIThresh;
+       u8 RATRState;
+
+       /*  Threshold Adjustment: */
+       /*  when RSSI state trends to go up one or two levels, make sure RSSI is high enough. */
+       /*  Here GoUpGap is added to solve the boundary's level alternation issue. */
+       switch (*pRATRState) {
+       case DM_RATR_STA_INIT:
+       case DM_RATR_STA_HIGH:
+               break;
+       case DM_RATR_STA_MIDDLE:
+               HighRSSIThreshForRA += GoUpGap;
+               break;
+       case DM_RATR_STA_LOW:
+               HighRSSIThreshForRA += GoUpGap;
+               LowRSSIThreshForRA += GoUpGap;
+               break;
+       default:
+               ODM_RT_ASSERT(pDM_Odm, false, ("wrong rssi level setting %d !", *pRATRState));
+               break;
+       }
+
+       /*  Decide RATRState by RSSI. */
+       if (RSSI > HighRSSIThreshForRA)
+               RATRState = DM_RATR_STA_HIGH;
+       else if (RSSI > LowRSSIThreshForRA)
+               RATRState = DM_RATR_STA_MIDDLE;
+       else
+               RATRState = DM_RATR_STA_LOW;
+
+       if (*pRATRState != RATRState || bForceUpdate) {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_RA_MASK, ODM_DBG_LOUD,
+                            ("RSSI Level %d -> %d\n", *pRATRState, RATRState));
+               *pRATRState = RATRState;
+               return true;
+       }
+       return false;
+}
+
+/* 3 ============================================================ */
+/* 3 Dynamic Tx Power */
+/* 3 ============================================================ */
+
+void odm_DynamicTxPower23aInit(struct dm_odm_t *pDM_Odm)
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+
+       pdmpriv->bDynamicTxPowerEnable = false;
+
+       pdmpriv->LastDTPLvl = TxHighPwrLevel_Normal;
+       pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal;
+}
+
+void odm_DynamicTxPower23aSavePowerIndex(struct dm_odm_t *pDM_Odm)
+{
+       u8 index;
+       u32 Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a};
+
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+       for (index = 0; index < 6; index++)
+               pdmpriv->PowerIndex_backup[index] = rtw_read8(Adapter, Power_Index_REG[index]);
+}
+
+void odm_DynamicTxPower23aRestorePowerIndex(struct dm_odm_t *pDM_Odm)
+{
+       u8 index;
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       u32 Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a};
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+       for (index = 0; index < 6; index++)
+               rtw_write8(Adapter, Power_Index_REG[index], pdmpriv->PowerIndex_backup[index]);
+}
+
+void odm_DynamicTxPower23aWritePowerIndex(struct dm_odm_t *pDM_Odm,
+       u8 Value)
+{
+
+       u8 index;
+       u32 Power_Index_REG[6] = {0xc90, 0xc91, 0xc92, 0xc98, 0xc99, 0xc9a};
+
+       for (index = 0; index < 6; index++)
+               ODM_Write1Byte(pDM_Odm, Power_Index_REG[index], Value);
+
+}
+
+void odm_DynamicTxPower23a(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void odm_DynamicTxPower23a_92C(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void odm_DynamicTxPower23a_92D(struct dm_odm_t *pDM_Odm)
+{
+}
+
+/* 3 ============================================================ */
+/* 3 RSSI Monitor */
+/* 3 ============================================================ */
+
+void odm_RSSIMonitorInit(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void odm_RSSIMonitorCheck23a(struct dm_odm_t *pDM_Odm)
+{
+       /*  For AP/ADSL use struct rtl8723a_priv * */
+       /*  For CE/NIC use struct rtw_adapter * */
+
+       if (!(pDM_Odm->SupportAbility & ODM_BB_RSSI_MONITOR))
+               return;
+
+       /*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+       /*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
+       /*  HW dynamic mechanism. */
+       odm_RSSIMonitorCheck23aCE(pDM_Odm);
+}      /*  odm_RSSIMonitorCheck23a */
+
+void odm_RSSIMonitorCheck23aMP(struct dm_odm_t *pDM_Odm)
+{
+}
+
+static void
+FindMinimumRSSI(
+       struct rtw_adapter *pAdapter
+       )
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+       struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
+
+       /* 1 1.Determine the minimum RSSI */
+
+       if ((!pDM_Odm->bLinked) &&
+           (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0))
+               pdmpriv->MinUndecoratedPWDBForDM = 0;
+       else
+               pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
+}
+
+void odm_RSSIMonitorCheck23aCE(struct dm_odm_t *pDM_Odm)
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+       int     i;
+       int     tmpEntryMaxPWDB = 0, tmpEntryMinPWDB = 0xff;
+       u8 sta_cnt = 0;
+       u32 PWDB_rssi[NUM_STA] = {0};/* 0~15]:MACID, [16~31]:PWDB_rssi */
+       struct sta_info *psta;
+
+       if (!pDM_Odm->bLinked)
+               return;
+
+       for (i = 0; i < ODM_ASSOCIATE_ENTRY_NUM; i++) {
+               psta = pDM_Odm->pODM_StaInfo[i];
+               if (IS_STA_VALID(psta)) {
+                       if (psta->rssi_stat.UndecoratedSmoothedPWDB < tmpEntryMinPWDB)
+                               tmpEntryMinPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB;
+
+                       if (psta->rssi_stat.UndecoratedSmoothedPWDB > tmpEntryMaxPWDB)
+                               tmpEntryMaxPWDB = psta->rssi_stat.UndecoratedSmoothedPWDB;
+
+                       if (psta->rssi_stat.UndecoratedSmoothedPWDB != (-1))
+                               PWDB_rssi[sta_cnt++] = (psta->mac_id | (psta->rssi_stat.UndecoratedSmoothedPWDB<<16));
+               }
+       }
+
+       for (i = 0; i < sta_cnt; i++) {
+               if (PWDB_rssi[i] != (0)) {
+                       if (pHalData->fw_ractrl) /*  Report every sta's RSSI to FW */
+                               rtl8723a_set_rssi_cmd(Adapter, (u8 *)&PWDB_rssi[i]);
+               }
+       }
+
+       if (tmpEntryMaxPWDB != 0)       /*  If associated entry is found */
+               pdmpriv->EntryMaxUndecoratedSmoothedPWDB = tmpEntryMaxPWDB;
+       else
+               pdmpriv->EntryMaxUndecoratedSmoothedPWDB = 0;
+
+       if (tmpEntryMinPWDB != 0xff) /*  If associated entry is found */
+               pdmpriv->EntryMinUndecoratedSmoothedPWDB = tmpEntryMinPWDB;
+       else
+               pdmpriv->EntryMinUndecoratedSmoothedPWDB = 0;
+
+       FindMinimumRSSI(Adapter);/* get pdmpriv->MinUndecoratedPWDBForDM */
+
+       ODM_CmnInfoUpdate23a(&pHalData->odmpriv, ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM);
+}
+
+void odm_RSSIMonitorCheck23aAP(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void ODM_InitAllTimers(struct dm_odm_t *pDM_Odm)
+{
+       setup_timer(&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer,
+                   odm_SwAntDivChkAntSwitchCallback23a, (unsigned long)pDM_Odm);
+}
+
+void ODM_CancelAllTimers(struct dm_odm_t *pDM_Odm)
+{
+       del_timer_sync(&pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer);
+}
+
+void ODM_ReleaseAllTimers(struct dm_odm_t *pDM_Odm)
+{
+       ODM_ReleaseTimer(pDM_Odm, &pDM_Odm->DM_SWAT_Table.SwAntennaSwitchTimer);
+}
+
+/* endif */
+/* 3 ============================================================ */
+/* 3 Tx Power Tracking */
+/* 3 ============================================================ */
+
+void odm_TXPowerTrackingInit23a(struct dm_odm_t *pDM_Odm)
+{
+       odm_TXPowerTrackingThermalMeterInit23a(pDM_Odm);
+}
+
+void odm_TXPowerTrackingThermalMeterInit23a(struct dm_odm_t *pDM_Odm)
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+
+       pdmpriv->bTXPowerTracking = true;
+       pdmpriv->TXPowercount = 0;
+       pdmpriv->bTXPowerTrackingInit = false;
+       pdmpriv->TxPowerTrackControl = true;
+       MSG_8723A("pdmpriv->TxPowerTrackControl = %d\n", pdmpriv->TxPowerTrackControl);
+
+       pDM_Odm->RFCalibrateInfo.TxPowerTrackControl = true;
+}
+
+void ODM_TXPowerTrackingCheck23a(struct dm_odm_t *pDM_Odm)
+{
+       /*  For AP/ADSL use struct rtl8723a_priv * */
+       /*  For CE/NIC use struct rtw_adapter * */
+
+       /*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+       /*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
+       /*  HW dynamic mechanism. */
+       odm_TXPowerTrackingCheckCE23a(pDM_Odm);
+}
+
+void odm_TXPowerTrackingCheckCE23a(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void odm_TXPowerTrackingCheckMP(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void odm_TXPowerTrackingCheckAP(struct dm_odm_t *pDM_Odm)
+{
+}
+
+/* antenna mapping info */
+/*  1: right-side antenna */
+/*  2/0: left-side antenna */
+/* PpDM_SWAT_Table->CCK_Ant1_Cnt /OFDM_Ant1_Cnt:  for right-side antenna:   Ant:1    RxDefaultAnt1 */
+/* PpDM_SWAT_Table->CCK_Ant2_Cnt /OFDM_Ant2_Cnt:  for left-side antenna:     Ant:0    RxDefaultAnt2 */
+/*  We select left antenna as default antenna in initial process, modify it as needed */
+/*  */
+
+/* 3 ============================================================ */
+/* 3 SW Antenna Diversity */
+/* 3 ============================================================ */
+void odm_SwAntDivInit(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void ODM_SwAntDivChkPerPktRssi(struct dm_odm_t *pDM_Odm, u8 StationID, struct odm_phy_info *pPhyInfo)
+{
+}
+
+void odm_SwAntDivChkAntSwitch(struct dm_odm_t *pDM_Odm, u8 Step)
+{
+}
+
+void ODM_SwAntDivRestAfterLink(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void odm_SwAntDivChkAntSwitchCallback23a(unsigned long data)
+{
+}
+
+/* 3 ============================================================ */
+/* 3 SW Antenna Diversity */
+/* 3 ============================================================ */
+
+void odm_InitHybridAntDiv23a(struct dm_odm_t *pDM_Odm)
+{
+}
+
+void odm_HwAntDiv23a(struct dm_odm_t *pDM_Odm)
+{
+}
+
+/* EDCA Turbo */
+void ODM_EdcaTurboInit23a(struct dm_odm_t *pDM_Odm)
+{
+
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+       pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
+       pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false;
+       Adapter->recvpriv.bIsAnyNonBEPkts = false;
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VO PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VO_PARAM)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial VI PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_VI_PARAM)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BE PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BE_PARAM)));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("Orginial BK PARAM: 0x%x\n", ODM_Read4Byte(pDM_Odm, ODM_EDCA_BK_PARAM)));
+
+}      /*  ODM_InitEdcaTurbo */
+
+void odm_EdcaTurboCheck23a(struct dm_odm_t *pDM_Odm)
+{
+       /*  For AP/ADSL use struct rtl8723a_priv * */
+       /*  For CE/NIC use struct rtw_adapter * */
+
+       /*  2011/09/29 MH In HW integration first stage, we provide 4 different handle to operate */
+       /*  at the same time. In the stage2/3, we need to prive universal interface and merge all */
+       /*  HW dynamic mechanism. */
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("odm_EdcaTurboCheck23a ========================>\n"));
+
+       if (!(pDM_Odm->SupportAbility & ODM_MAC_EDCA_TURBO))
+               return;
+
+       odm_EdcaTurboCheck23aCE23a(pDM_Odm);
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_EDCA_TURBO, ODM_DBG_LOUD, ("<======================== odm_EdcaTurboCheck23a\n"));
+
+}      /*  odm_CheckEdcaTurbo */
+
+void odm_EdcaTurboCheck23aCE23a(struct dm_odm_t *pDM_Odm)
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       u32 trafficIndex;
+       u32 edca_param;
+       u64 cur_tx_bytes = 0;
+       u64 cur_rx_bytes = 0;
+       u8 bbtchange = false;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct xmit_priv *pxmitpriv = &Adapter->xmitpriv;
+       struct recv_priv *precvpriv = &Adapter->recvpriv;
+       struct registry_priv *pregpriv = &Adapter->registrypriv;
+       struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       if ((pregpriv->wifi_spec == 1))/*  (pmlmeinfo->HT_enable == 0)) */
+               goto dm_CheckEdcaTurbo_EXIT;
+
+       if (pmlmeinfo->assoc_AP_vendor >=  HT_IOT_PEER_MAX)
+               goto dm_CheckEdcaTurbo_EXIT;
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       if (BT_DisableEDCATurbo(Adapter))
+               goto dm_CheckEdcaTurbo_EXIT;
+#endif
+
+       /*  Check if the status needs to be changed. */
+       if ((bbtchange) || (!precvpriv->bIsAnyNonBEPkts)) {
+               cur_tx_bytes = pxmitpriv->tx_bytes - pxmitpriv->last_tx_bytes;
+               cur_rx_bytes = precvpriv->rx_bytes - precvpriv->last_rx_bytes;
+
+               /* traffic, TX or RX */
+               if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_RALINK) ||
+                   (pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_ATHEROS)) {
+                       if (cur_tx_bytes > (cur_rx_bytes << 2)) {
+                               /*  Uplink TP is present. */
+                               trafficIndex = UP_LINK;
+                       } else { /*  Balance TP is present. */
+                               trafficIndex = DOWN_LINK;
+                       }
+               } else {
+                       if (cur_rx_bytes > (cur_tx_bytes << 2)) {
+                               /*  Downlink TP is present. */
+                               trafficIndex = DOWN_LINK;
+                       } else { /*  Balance TP is present. */
+                               trafficIndex = UP_LINK;
+                       }
+               }
+
+               if ((pDM_Odm->DM_EDCA_Table.prv_traffic_idx != trafficIndex) ||
+                   (!pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA)) {
+                       if ((pmlmeinfo->assoc_AP_vendor == HT_IOT_PEER_CISCO) &&
+                           (pmlmeext->cur_wireless_mode & WIRELESS_11_24N))
+                               edca_param = EDCAParam[pmlmeinfo->assoc_AP_vendor][trafficIndex];
+                       else
+                               edca_param = EDCAParam[HT_IOT_PEER_UNKNOWN][trafficIndex];
+                       rtw_write32(Adapter, REG_EDCA_BE_PARAM, edca_param);
+
+                       pDM_Odm->DM_EDCA_Table.prv_traffic_idx = trafficIndex;
+               }
+
+               pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = true;
+       } else {
+               /*  Turn Off EDCA turbo here. */
+               /*  Restore original EDCA according to the declaration of AP. */
+               if (pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA) {
+                       rtw_write32(Adapter, REG_EDCA_BE_PARAM, pHalData->AcParam_BE);
+                       pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
+               }
+       }
+
+dm_CheckEdcaTurbo_EXIT:
+       /*  Set variables for next time. */
+       precvpriv->bIsAnyNonBEPkts = false;
+       pxmitpriv->last_tx_bytes = pxmitpriv->tx_bytes;
+       precvpriv->last_rx_bytes = precvpriv->rx_bytes;
+}
+
+u32 GetPSDData(struct dm_odm_t *pDM_Odm, unsigned int point, u8 initial_gain_psd)
+{
+       u32 psd_report;
+
+       /* Set DCO frequency index, offset = (40MHz/SamplePts)*point */
+       ODM_SetBBReg(pDM_Odm, 0x808, 0x3FF, point);
+
+       /* Start PSD calculation, Reg808[22]= 0->1 */
+       ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 1);
+       /* Need to wait for HW PSD report */
+       udelay(30);
+       ODM_SetBBReg(pDM_Odm, 0x808, BIT22, 0);
+       /* Read PSD report, Reg8B4[15:0] */
+       psd_report = ODM_GetBBReg(pDM_Odm, 0x8B4, bMaskDWord) & 0x0000FFFF;
+
+       psd_report = (u32)(ConvertTo_dB23a(psd_report))+(u32)(initial_gain_psd-0x1c);
+
+       return psd_report;
+}
+
+u32
+ConvertTo_dB23a(
+       u32 Value)
+{
+       u8 i;
+       u8 j;
+       u32 dB;
+
+       Value = Value & 0xFFFF;
+
+       for (i = 0; i < 8; i++) {
+               if (Value <= dB_Invert_Table[i][11])
+                       break;
+       }
+
+       if (i >= 8)
+               return 96;      /*  maximum 96 dB */
+
+       for (j = 0; j < 12; j++) {
+               if (Value <= dB_Invert_Table[i][j])
+                       break;
+       }
+
+       dB = i*12 + j + 1;
+
+       return dB;
+}
+
+/*  */
+/*  2011/09/22 MH Add for 92D global spin lock utilization. */
+/*  */
+void
+odm_GlobalAdapterCheck(
+               void
+       )
+{
+}      /*  odm_GlobalAdapterCheck */
+
+/*  */
+/*  Description: */
+/*Set Single/Dual Antenna default setting for products that do not do detection in advance. */
+/*  */
+/*  Added by Joseph, 2012.03.22 */
+/*  */
+void ODM_SingleDualAntennaDefaultSetting(struct dm_odm_t *pDM_Odm)
+{
+       struct sw_ant_sw *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+       pDM_SWAT_Table->ANTA_ON = true;
+       pDM_SWAT_Table->ANTB_ON = true;
+}
+
+/* 2 8723A ANT DETECT */
+
+static void odm_PHY_SaveAFERegisters(
+       struct dm_odm_t *pDM_Odm,
+       u32 *AFEReg,
+       u32 *AFEBackup,
+       u32 RegisterNum
+       )
+{
+       u32 i;
+
+       /* RTPRINT(FINIT, INIT_IQK, ("Save ADDA parameters.\n")); */
+       for (i = 0 ; i < RegisterNum ; i++)
+               AFEBackup[i] = ODM_GetBBReg(pDM_Odm, AFEReg[i], bMaskDWord);
+}
+
+static void odm_PHY_ReloadAFERegisters(struct dm_odm_t *pDM_Odm, u32 *AFEReg,
+                                      u32 *AFEBackup, u32 RegiesterNum)
+{
+       u32 i;
+
+       for (i = 0 ; i < RegiesterNum; i++)
+               ODM_SetBBReg(pDM_Odm, AFEReg[i], bMaskDWord, AFEBackup[i]);
+}
+
+/* 2 8723A ANT DETECT */
+/*  Description: */
+/* Implement IQK single tone for RF DPK loopback and BB PSD scanning. */
+/* This function is cooperated with BB team Neil. */
+bool ODM_SingleDualAntennaDetection(struct dm_odm_t *pDM_Odm, u8 mode)
+{
+       struct sw_ant_sw *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+       u32 CurrentChannel, RfLoopReg;
+       u8 n;
+       u32 Reg88c, Regc08, Reg874, Regc50;
+       u8 initial_gain = 0x5a;
+       u32 PSD_report_tmp;
+       u32 AntA_report = 0x0, AntB_report = 0x0, AntO_report = 0x0;
+       bool bResult = true;
+       u32 AFE_Backup[16];
+       u32 AFE_REG_8723A[16] = {
+               rRx_Wait_CCA, rTx_CCK_RFON,
+               rTx_CCK_BBON, rTx_OFDM_RFON,
+               rTx_OFDM_BBON, rTx_To_Rx,
+               rTx_To_Tx, rRx_CCK,
+               rRx_OFDM, rRx_Wait_RIFS,
+               rRx_TO_Rx, rStandby,
+               rSleep, rPMPD_ANAEN,
+               rFPGA0_XCD_SwitchControl, rBlue_Tooth};
+
+       if (!(pDM_Odm->SupportICType & (ODM_RTL8723A)))
+               return bResult;
+
+       if (!(pDM_Odm->SupportAbility&ODM_BB_ANT_DIV))
+               return bResult;
+       /* 1 Backup Current RF/BB Settings */
+
+       CurrentChannel = ODM_GetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask);
+       RfLoopReg = ODM_GetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask);
+       ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, ODM_DPDT, Antenna_A);  /*  change to Antenna A */
+       /*  Step 1: USE IQK to transmitter single tone */
+
+       udelay(10);
+
+       /* Store A Path Register 88c, c08, 874, c50 */
+       Reg88c = ODM_GetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord);
+       Regc08 = ODM_GetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord);
+       Reg874 = ODM_GetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord);
+       Regc50 = ODM_GetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord);
+
+       /*  Store AFE Registers */
+       odm_PHY_SaveAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16);
+
+       /* Set PSD 128 pts */
+       ODM_SetBBReg(pDM_Odm, rFPGA0_PSDFunction, BIT14|BIT15, 0x0);  /* 128 pts */
+
+       /*  To SET CH1 to do */
+       ODM_SetRFReg(pDM_Odm, RF_PATH_A, ODM_CHANNEL, bRFRegOffsetMask, 0x01);     /* Channel 1 */
+
+       /*  AFE all on step */
+       ODM_SetBBReg(pDM_Odm, rRx_Wait_CCA, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rTx_CCK_RFON, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rTx_CCK_BBON, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rTx_OFDM_RFON, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rTx_OFDM_BBON, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rTx_To_Rx, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rTx_To_Tx, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rRx_CCK, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rRx_OFDM, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rRx_Wait_RIFS, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rRx_TO_Rx, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rStandby, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rSleep, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rPMPD_ANAEN, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_SwitchControl, bMaskDWord, 0x6FDB25A4);
+       ODM_SetBBReg(pDM_Odm, rBlue_Tooth, bMaskDWord, 0x6FDB25A4);
+
+       /*  3 wire Disable */
+       ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, 0xCCF000C0);
+
+       /* BB IQK Setting */
+       ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, 0x000800E4);
+       ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, 0x22208000);
+
+       /* IQK setting tone@ 4.34Mhz */
+       ODM_SetBBReg(pDM_Odm, rTx_IQK_Tone_A, bMaskDWord, 0x10008C1C);
+       ODM_SetBBReg(pDM_Odm, rTx_IQK, bMaskDWord, 0x01007c00);
+
+       /* Page B init */
+       ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x00080000);
+       ODM_SetBBReg(pDM_Odm, rConfig_AntA, bMaskDWord, 0x0f600000);
+       ODM_SetBBReg(pDM_Odm, rRx_IQK, bMaskDWord, 0x01004800);
+       ODM_SetBBReg(pDM_Odm, rRx_IQK_Tone_A, bMaskDWord, 0x10008c1f);
+       ODM_SetBBReg(pDM_Odm, rTx_IQK_PI_A, bMaskDWord, 0x82150008);
+       ODM_SetBBReg(pDM_Odm, rRx_IQK_PI_A, bMaskDWord, 0x28150008);
+       ODM_SetBBReg(pDM_Odm, rIQK_AGC_Rsp, bMaskDWord, 0x001028d0);
+
+       /* RF loop Setting */
+       ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x0, 0xFFFFF, 0x50008);
+
+       /* IQK Single tone start */
+       ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x80800000);
+       ODM_SetBBReg(pDM_Odm, rIQK_AGC_Pts, bMaskDWord, 0xf8000000);
+       udelay(1000);
+       PSD_report_tmp = 0x0;
+
+       for (n = 0; n < 2; n++) {
+               PSD_report_tmp =  GetPSDData(pDM_Odm, 14, initial_gain);
+               if (PSD_report_tmp > AntA_report)
+                       AntA_report = PSD_report_tmp;
+       }
+
+       PSD_report_tmp = 0x0;
+
+       ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_B);  /*  change to Antenna B */
+       udelay(10);
+
+       for (n = 0; n < 2; n++) {
+               PSD_report_tmp =  GetPSDData(pDM_Odm, 14, initial_gain);
+               if (PSD_report_tmp > AntB_report)
+                       AntB_report = PSD_report_tmp;
+       }
+
+       /*  change to open case */
+       ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, 0);  /*  change to Ant A and B all open case */
+       udelay(10);
+
+       for (n = 0; n < 2; n++) {
+               PSD_report_tmp =  GetPSDData(pDM_Odm, 14, initial_gain);
+               if (PSD_report_tmp > AntO_report)
+                       AntO_report = PSD_report_tmp;
+       }
+
+       /* Close IQK Single Tone function */
+       ODM_SetBBReg(pDM_Odm, rFPGA0_IQK, bMaskDWord, 0x00000000);
+       PSD_report_tmp = 0x0;
+
+       /* 1 Return to antanna A */
+       ODM_SetBBReg(pDM_Odm, rFPGA0_XA_RFInterfaceOE, 0x300, Antenna_A);
+       ODM_SetBBReg(pDM_Odm, rFPGA0_AnalogParameter4, bMaskDWord, Reg88c);
+       ODM_SetBBReg(pDM_Odm, rOFDM0_TRMuxPar, bMaskDWord, Regc08);
+       ODM_SetBBReg(pDM_Odm, rFPGA0_XCD_RFInterfaceSW, bMaskDWord, Reg874);
+       ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, 0x7F, 0x40);
+       ODM_SetBBReg(pDM_Odm, rOFDM0_XAAGCCore1, bMaskDWord, Regc50);
+       ODM_SetRFReg(pDM_Odm, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, CurrentChannel);
+       ODM_SetRFReg(pDM_Odm, RF_PATH_A, 0x00, bRFRegOffsetMask, RfLoopReg);
+
+       /* Reload AFE Registers */
+       odm_PHY_ReloadAFERegisters(pDM_Odm, AFE_REG_8723A, AFE_Backup, 16);
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_A[%d]= %d \n", 2416, AntA_report));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_B[%d]= %d \n", 2416, AntB_report));
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("psd_report_O[%d]= %d \n", 2416, AntO_report));
+
+       /* 2 Test Ant B based on Ant A is ON */
+       if (mode == ANTTESTB) {
+               if (AntA_report >= 100) {
+                       if (AntB_report > (AntA_report+1)) {
+                               pDM_SWAT_Table->ANTB_ON = false;
+                               ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Single Antenna A\n"));
+                       } else {
+                               pDM_SWAT_Table->ANTB_ON = true;
+                               ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Dual Antenna is A and B\n"));
+                       }
+               } else {
+                       ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n"));
+                       pDM_SWAT_Table->ANTB_ON = false; /*  Set Antenna B off as default */
+                       bResult = false;
+               }
+       } else if (mode == ANTTESTALL) {
+               /* 2 Test Ant A and B based on DPDT Open */
+               if ((AntO_report >= 100) & (AntO_report < 118)) {
+                       if (AntA_report > (AntO_report+1)) {
+                               pDM_SWAT_Table->ANTA_ON = false;
+                               ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is OFF"));
+                       } else {
+                               pDM_SWAT_Table->ANTA_ON = true;
+                               ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant A is ON"));
+                       }
+
+                       if (AntB_report > (AntO_report+2)) {
+                               pDM_SWAT_Table->ANTB_ON = false;
+                               ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is OFF"));
+                       } else {
+                               pDM_SWAT_Table->ANTB_ON = true;
+                               ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("Ant B is ON"));
+                       }
+               }
+       } else {
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_ANT_DIV, ODM_DBG_LOUD, ("ODM_SingleDualAntennaDetection(): Need to check again\n"));
+               pDM_SWAT_Table->ANTA_ON = true; /*  Set Antenna A on as default */
+               pDM_SWAT_Table->ANTB_ON = false; /*  Set Antenna B off as default */
+               bResult = false;
+       }
+       return bResult;
+}
+
+/* Justin: According to the current RRSI to adjust Response Frame TX power, 2012/11/05 */
+void odm_dtc(struct dm_odm_t *pDM_Odm)
+{
+}
diff --git a/drivers/staging/rtl8723au/hal/odm_HWConfig.c b/drivers/staging/rtl8723au/hal/odm_HWConfig.c
new file mode 100644 (file)
index 0000000..7244170
--- /dev/null
@@ -0,0 +1,481 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 files */
+/*  */
+
+#include "odm_precomp.h"
+
+#define READ_AND_CONFIG     READ_AND_CONFIG_MP
+
+#define READ_AND_CONFIG_MP(ic, txt) (ODM_ReadAndConfig##txt##ic(pDM_Odm))
+#define READ_AND_CONFIG_TC(ic, txt) (ODM_ReadAndConfig_TC##txt##ic(pDM_Odm))
+
+static u8 odm_QueryRxPwrPercentage(s8 AntPower)
+{
+       if ((AntPower <= -100) || (AntPower >= 20))
+               return  0;
+       else if (AntPower >= 0)
+               return  100;
+       else
+               return  100 + AntPower;
+}
+
+static s32 odm_SignalScaleMapping_92CSeries(struct dm_odm_t *pDM_Odm, s32 CurrSig)
+{
+       s32 RetSig = 0;
+
+       if ((pDM_Odm->SupportInterface  == ODM_ITRF_USB) || (pDM_Odm->SupportInterface  == ODM_ITRF_SDIO)) {
+               if (CurrSig >= 51 && CurrSig <= 100)
+                       RetSig = 100;
+               else if (CurrSig >= 41 && CurrSig <= 50)
+                       RetSig = 80 + ((CurrSig - 40)*2);
+               else if (CurrSig >= 31 && CurrSig <= 40)
+                       RetSig = 66 + (CurrSig - 30);
+               else if (CurrSig >= 21 && CurrSig <= 30)
+                       RetSig = 54 + (CurrSig - 20);
+               else if (CurrSig >= 10 && CurrSig <= 20)
+                       RetSig = 42 + (((CurrSig - 10) * 2) / 3);
+               else if (CurrSig >= 5 && CurrSig <= 9)
+                       RetSig = 22 + (((CurrSig - 5) * 3) / 2);
+               else if (CurrSig >= 1 && CurrSig <= 4)
+                       RetSig = 6 + (((CurrSig - 1) * 3) / 2);
+               else
+                       RetSig = CurrSig;
+       }
+       return RetSig;
+}
+
+static s32 odm_SignalScaleMapping(struct dm_odm_t *pDM_Odm, s32 CurrSig)
+{
+       return odm_SignalScaleMapping_92CSeries(pDM_Odm, CurrSig);
+}
+
+static u8
+odm_EVMdbToPercentage(
+       s8 Value
+  )
+{
+       /*  */
+       /*  -33dB~0dB to 0%~99% */
+       /*  */
+       s8 ret_val;
+
+       ret_val = Value;
+
+       if (ret_val >= 0)
+               ret_val = 0;
+       if (ret_val <= -33)
+               ret_val = -33;
+
+       ret_val = 0 - ret_val;
+       ret_val *= 3;
+
+       if (ret_val == 99)
+               ret_val = 100;
+
+       return ret_val;
+}
+
+static void odm_RxPhyStatus92CSeries_Parsing(struct dm_odm_t *pDM_Odm,
+                                            struct odm_phy_info *pPhyInfo,
+                                            u8 *pPhyStatus,
+                                            struct odm_packet_info *pPktinfo)
+{
+       struct phy_status_rpt *pPhyStaRpt = (struct phy_status_rpt *)pPhyStatus;
+       u8 i, Max_spatial_stream;
+       s8 rx_pwr[4], rx_pwr_all = 0;
+       u8 EVM, PWDB_ALL = 0, PWDB_ALL_BT;
+       u8 RSSI, total_rssi = 0;
+       u8 isCCKrate = 0;
+       u8 rf_rx_num = 0;
+       u8 cck_highpwr = 0;
+
+       isCCKrate = (pPktinfo->Rate <= DESC92C_RATE11M) ? true : false;
+       pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = -1;
+       pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1;
+
+       if (isCCKrate) {
+               u8 report;
+               u8 cck_agc_rpt;
+
+               pDM_Odm->PhyDbgInfo.NumQryPhyStatusCCK++;
+               /*  (1)Hardware does not provide RSSI for CCK */
+               /*  (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */
+
+               cck_highpwr = pDM_Odm->bCckHighPower;
+
+               cck_agc_rpt =  pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ;
+
+               /* The RSSI formula should be modified according to the gain table */
+               if (!cck_highpwr) {
+                       report = (cck_agc_rpt & 0xc0)>>6;
+                       switch (report) {
+                       /*  Modify the RF RNA gain value to -40, -20, -2, 14 by Jenyu's suggestion */
+                       /*  Note: different RF with the different RNA gain. */
+                       case 0x3:
+                               rx_pwr_all = -46 - (cck_agc_rpt & 0x3e);
+                               break;
+                       case 0x2:
+                               rx_pwr_all = -26 - (cck_agc_rpt & 0x3e);
+                               break;
+                       case 0x1:
+                               rx_pwr_all = -12 - (cck_agc_rpt & 0x3e);
+                               break;
+                       case 0x0:
+                               rx_pwr_all = 16 - (cck_agc_rpt & 0x3e);
+                               break;
+                       }
+               } else {
+                       report = (cck_agc_rpt & 0x60)>>5;
+                       switch (report) {
+                       case 0x3:
+                               rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ;
+                               break;
+                       case 0x2:
+                               rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1);
+                               break;
+                       case 0x1:
+                               rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1) ;
+                               break;
+                       case 0x0:
+                               rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1) ;
+                               break;
+                       }
+               }
+
+               PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+
+               /* Modification for ext-LNA board */
+               if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) {
+                       if ((cck_agc_rpt>>7) == 0) {
+                               PWDB_ALL = (PWDB_ALL > 94) ? 100 : (PWDB_ALL+6);
+                       } else {
+                               if (PWDB_ALL > 38)
+                                       PWDB_ALL -= 16;
+                               else
+                                       PWDB_ALL = (PWDB_ALL <= 16) ? (PWDB_ALL>>2) : (PWDB_ALL-12);
+                       }
+
+                       /* CCK modification */
+                       if (PWDB_ALL > 25 && PWDB_ALL <= 60)
+                               PWDB_ALL += 6;
+               } else { /* Modification for int-LNA board */
+                       if (PWDB_ALL > 99)
+                               PWDB_ALL -= 8;
+                       else if (PWDB_ALL > 50 && PWDB_ALL <= 68)
+                               PWDB_ALL += 4;
+               }
+               pPhyInfo->RxPWDBAll = PWDB_ALL;
+               pPhyInfo->BTRxRSSIPercentage = PWDB_ALL;
+               pPhyInfo->RecvSignalPower = rx_pwr_all;
+               /*  (3) Get Signal Quality (EVM) */
+               if (pPktinfo->bPacketMatchBSSID) {
+                       u8      SQ, SQ_rpt;
+
+                       SQ_rpt = pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all;
+
+                       if (SQ_rpt > 64)
+                               SQ = 0;
+                       else if (SQ_rpt < 20)
+                               SQ = 100;
+                       else
+                               SQ = ((64-SQ_rpt) * 100) / 44;
+
+                       pPhyInfo->SignalQuality = SQ;
+                       pPhyInfo->RxMIMOSignalQuality[RF_PATH_A] = SQ;
+                       pPhyInfo->RxMIMOSignalQuality[RF_PATH_B] = -1;
+               }
+       } else { /* is OFDM rate */
+               pDM_Odm->PhyDbgInfo.NumQryPhyStatusOFDM++;
+
+               /*  (1)Get RSSI for HT rate */
+
+               for (i = RF_PATH_A; i < RF_PATH_MAX; i++) {
+                       /*  2008/01/30 MH we will judge RF RX path now. */
+                       if (pDM_Odm->RFPathRxEnable & BIT(i))
+                               rf_rx_num++;
+
+                       rx_pwr[i] = ((pPhyStaRpt->path_agc[i].gain & 0x3F)*2) - 110;
+
+                       pPhyInfo->RxPwr[i] = rx_pwr[i];
+
+                       /* Translate DBM to percentage. */
+                       RSSI = odm_QueryRxPwrPercentage(rx_pwr[i]);
+                       total_rssi += RSSI;
+
+                       /* Modification for ext-LNA board */
+                       if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) {
+                               if ((pPhyStaRpt->path_agc[i].trsw) == 1)
+                                       RSSI = (RSSI > 94) ? 100 : (RSSI+6);
+                               else
+                                       RSSI = (RSSI <= 16) ? (RSSI>>3) : (RSSI-16);
+
+                               if ((RSSI <= 34) && (RSSI >= 4))
+                                       RSSI -= 4;
+                       }
+
+                       pPhyInfo->RxMIMOSignalStrength[i] = (u8) RSSI;
+
+                       /* Get Rx snr value in DB */
+                       pPhyInfo->RxSNR[i] = pDM_Odm->PhyDbgInfo.RxSNRdB[i] = (s32)(pPhyStaRpt->path_rxsnr[i]/2);
+               }
+
+               /*  (2)PWDB, Average PWDB cacluated by hardware (for rate adaptive) */
+               rx_pwr_all = (((pPhyStaRpt->cck_sig_qual_ofdm_pwdb_all) >> 1) & 0x7f)-110;
+
+               PWDB_ALL = odm_QueryRxPwrPercentage(rx_pwr_all);
+               PWDB_ALL_BT = PWDB_ALL;
+
+               pPhyInfo->RxPWDBAll = PWDB_ALL;
+               pPhyInfo->BTRxRSSIPercentage = PWDB_ALL_BT;
+               pPhyInfo->RxPower = rx_pwr_all;
+               pPhyInfo->RecvSignalPower = rx_pwr_all;
+
+               /*  (3)EVM of HT rate */
+               if (pPktinfo->Rate >= DESC92C_RATEMCS8 && pPktinfo->Rate <= DESC92C_RATEMCS15)
+                       Max_spatial_stream = 2; /* both spatial stream make sense */
+               else
+                       Max_spatial_stream = 1; /* only spatial stream 1 makes sense */
+
+               for (i = 0; i < Max_spatial_stream; i++) {
+                       /*  Do not use shift operation like "rx_evmX >>= 1" because the compilor of free build environment */
+                       /*  fill most significant bit to "zero" when doing shifting operation which may change a negative */
+                       /*  value to positive one, then the dbm value (which is supposed to be negative)  is not correct anymore. */
+                       EVM = odm_EVMdbToPercentage((pPhyStaRpt->stream_rxevm[i]));     /* dbm */
+
+                       if (pPktinfo->bPacketMatchBSSID) {
+                               if (i == RF_PATH_A) {
+                                       /*  Fill value in RFD, Get the first spatial stream only */
+                                       pPhyInfo->SignalQuality = (u8)(EVM & 0xff);
+                               }
+                               pPhyInfo->RxMIMOSignalQuality[i] = (u8)(EVM & 0xff);
+                       }
+               }
+       }
+       /* UI BSS List signal strength(in percentage), make it good looking, from 0~100. */
+       /* It is assigned to the BSS List in GetValueFromBeaconOrProbeRsp(). */
+       if (isCCKrate) {
+               pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, PWDB_ALL));/* PWDB_ALL; */
+       } else {
+               if (rf_rx_num != 0)
+                       pPhyInfo->SignalStrength = (u8)(odm_SignalScaleMapping(pDM_Odm, total_rssi /= rf_rx_num));
+       }
+}
+
+void odm_Init_RSSIForDM23a(struct dm_odm_t *pDM_Odm)
+{
+}
+
+static void odm_Process_RSSIForDM(struct dm_odm_t *pDM_Odm,
+                                 struct odm_phy_info *pPhyInfo,
+                                 struct odm_packet_info *pPktinfo)
+{
+       s32 UndecoratedSmoothedPWDB, UndecoratedSmoothedCCK;
+       s32 UndecoratedSmoothedOFDM, RSSI_Ave;
+       u8 isCCKrate = 0;
+       u8 RSSI_max, RSSI_min, i;
+       u32 OFDM_pkt = 0;
+       u32 Weighting = 0;
+       struct sta_info *pEntry;
+
+       if (pPktinfo->StationID == 0xFF)
+               return;
+
+       pEntry = pDM_Odm->pODM_StaInfo[pPktinfo->StationID];
+       if (!IS_STA_VALID(pEntry))
+               return;
+       if ((!pPktinfo->bPacketMatchBSSID))
+               return;
+
+       isCCKrate = (pPktinfo->Rate <= DESC92C_RATE11M) ? true : false;
+
+       /* Smart Antenna Debug Message------------------*/
+
+       UndecoratedSmoothedCCK =  pEntry->rssi_stat.UndecoratedSmoothedCCK;
+       UndecoratedSmoothedOFDM = pEntry->rssi_stat.UndecoratedSmoothedOFDM;
+       UndecoratedSmoothedPWDB = pEntry->rssi_stat.UndecoratedSmoothedPWDB;
+
+       if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon) {
+               if (!isCCKrate) { /* ofdm rate */
+                       if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_B] == 0) {
+                               RSSI_Ave = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A];
+                       } else {
+                               if (pPhyInfo->RxMIMOSignalStrength[RF_PATH_A] > pPhyInfo->RxMIMOSignalStrength[RF_PATH_B]) {
+                                       RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A];
+                                       RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B];
+                               } else {
+                                       RSSI_max = pPhyInfo->RxMIMOSignalStrength[RF_PATH_B];
+                                       RSSI_min = pPhyInfo->RxMIMOSignalStrength[RF_PATH_A];
+                               }
+                               if ((RSSI_max - RSSI_min) < 3)
+                                       RSSI_Ave = RSSI_max;
+                               else if ((RSSI_max - RSSI_min) < 6)
+                                       RSSI_Ave = RSSI_max - 1;
+                               else if ((RSSI_max - RSSI_min) < 10)
+                                       RSSI_Ave = RSSI_max - 2;
+                               else
+                                       RSSI_Ave = RSSI_max - 3;
+                       }
+
+                       /* 1 Process OFDM RSSI */
+                       if (UndecoratedSmoothedOFDM <= 0) {
+                               /*  initialize */
+                               UndecoratedSmoothedOFDM = pPhyInfo->RxPWDBAll;
+                       } else {
+                               if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedOFDM) {
+                                       UndecoratedSmoothedOFDM =
+                                                       (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) +
+                                                       (RSSI_Ave)) / (Rx_Smooth_Factor);
+                                       UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM + 1;
+                               } else {
+                                       UndecoratedSmoothedOFDM =
+                                                       (((UndecoratedSmoothedOFDM)*(Rx_Smooth_Factor-1)) +
+                                                       (RSSI_Ave)) / (Rx_Smooth_Factor);
+                               }
+                       }
+                       pEntry->rssi_stat.PacketMap = (pEntry->rssi_stat.PacketMap<<1) | BIT0;
+               } else {
+                       RSSI_Ave = pPhyInfo->RxPWDBAll;
+
+                       /* 1 Process CCK RSSI */
+                       if (UndecoratedSmoothedCCK <= 0) {
+                               /*  initialize */
+                               UndecoratedSmoothedCCK = pPhyInfo->RxPWDBAll;
+                       } else {
+                               if (pPhyInfo->RxPWDBAll > (u32)UndecoratedSmoothedCCK) {
+                                       UndecoratedSmoothedCCK =
+                                                       (((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) +
+                                                       (pPhyInfo->RxPWDBAll)) / (Rx_Smooth_Factor);
+                                       UndecoratedSmoothedCCK = UndecoratedSmoothedCCK + 1;
+                               } else {
+                                       UndecoratedSmoothedCCK =
+                                                       (((UndecoratedSmoothedCCK)*(Rx_Smooth_Factor-1)) +
+                                                       (pPhyInfo->RxPWDBAll)) / (Rx_Smooth_Factor);
+                               }
+                       }
+                       pEntry->rssi_stat.PacketMap = pEntry->rssi_stat.PacketMap<<1;
+               }
+
+               /* 2011.07.28 LukeLee: modified to prevent unstable CCK RSSI */
+               if (pEntry->rssi_stat.ValidBit >= 64)
+                       pEntry->rssi_stat.ValidBit = 64;
+               else
+                       pEntry->rssi_stat.ValidBit++;
+
+               for (i = 0; i < pEntry->rssi_stat.ValidBit; i++)
+                       OFDM_pkt += (u8)(pEntry->rssi_stat.PacketMap>>i)&BIT0;
+
+               if (pEntry->rssi_stat.ValidBit == 64) {
+                       Weighting = ((OFDM_pkt<<4) > 64)?64:(OFDM_pkt<<4);
+                       UndecoratedSmoothedPWDB = (Weighting*UndecoratedSmoothedOFDM+(64-Weighting)*UndecoratedSmoothedCCK)>>6;
+               } else {
+                       if (pEntry->rssi_stat.ValidBit != 0)
+                               UndecoratedSmoothedPWDB = (OFDM_pkt*UndecoratedSmoothedOFDM+(pEntry->rssi_stat.ValidBit-OFDM_pkt)*UndecoratedSmoothedCCK)/pEntry->rssi_stat.ValidBit;
+                       else
+                               UndecoratedSmoothedPWDB = 0;
+               }
+               pEntry->rssi_stat.UndecoratedSmoothedCCK = UndecoratedSmoothedCCK;
+               pEntry->rssi_stat.UndecoratedSmoothedOFDM = UndecoratedSmoothedOFDM;
+               pEntry->rssi_stat.UndecoratedSmoothedPWDB = UndecoratedSmoothedPWDB;
+       }
+}
+
+/*  Endianness before calling this API */
+static void ODM_PhyStatusQuery23a_92CSeries(struct dm_odm_t *pDM_Odm,
+                                        struct odm_phy_info *pPhyInfo,
+                                        u8 *pPhyStatus,
+                                        struct odm_packet_info *pPktinfo)
+{
+       odm_RxPhyStatus92CSeries_Parsing(pDM_Odm, pPhyInfo,
+                                        pPhyStatus, pPktinfo);
+       if (pDM_Odm->RSSI_test) {
+               /*  Select the packets to do RSSI checking for antenna switching. */
+               if (pPktinfo->bPacketToSelf || pPktinfo->bPacketBeacon)
+                       ODM_SwAntDivChkPerPktRssi(pDM_Odm, pPktinfo->StationID, pPhyInfo);
+       } else {
+               odm_Process_RSSIForDM(pDM_Odm, pPhyInfo, pPktinfo);
+       }
+}
+
+void ODM_PhyStatusQuery23a(struct dm_odm_t *pDM_Odm, struct odm_phy_info *pPhyInfo,
+                          u8 *pPhyStatus, struct odm_packet_info *pPktinfo)
+{
+       ODM_PhyStatusQuery23a_92CSeries(pDM_Odm, pPhyInfo, pPhyStatus, pPktinfo);
+}
+
+/*  For future use. */
+void ODM_MacStatusQuery23a(struct dm_odm_t *pDM_Odm, u8 *pMacStatus, u8 MacID,
+                       bool bPacketMatchBSSID, bool bPacketToSelf,
+                       bool bPacketBeacon)
+{
+       /*  2011/10/19 Driver team will handle in the future. */
+
+}
+
+enum hal_status
+ODM_ConfigRFWithHeaderFile23a(
+       struct dm_odm_t *pDM_Odm,
+       enum RF_RADIO_PATH      Content,
+       enum RF_RADIO_PATH      eRFPath
+  )
+{
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                    ("===>ODM_ConfigRFWithHeaderFile23a\n"));
+       if (pDM_Odm->SupportICType == ODM_RTL8723A) {
+               if (eRFPath == RF_PATH_A)
+                       READ_AND_CONFIG_MP(8723A, _RadioA_1T_);
+
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                            (" ===> ODM_ConfigRFWithHeaderFile23a() Radio_A:Rtl8723RadioA_1TArray\n"));
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                            (" ===> ODM_ConfigRFWithHeaderFile23a() Radio_B:Rtl8723RadioB_1TArray\n"));
+       }
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_TRACE,
+                    ("ODM_ConfigRFWithHeaderFile23a: Radio No %x\n", eRFPath));
+       return HAL_STATUS_SUCCESS;
+}
+
+enum hal_status
+ODM_ConfigBBWithHeaderFile23a(
+       struct dm_odm_t *pDM_Odm,
+       enum odm_bb_config_type         ConfigType
+       )
+{
+       if (pDM_Odm->SupportICType == ODM_RTL8723A) {
+               if (ConfigType == CONFIG_BB_PHY_REG)
+                       READ_AND_CONFIG_MP(8723A, _PHY_REG_1T_);
+               else if (ConfigType == CONFIG_BB_AGC_TAB)
+                       READ_AND_CONFIG_MP(8723A, _AGC_TAB_1T_);
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                            (" ===> phy_ConfigBBWithHeaderFile() phy:Rtl8723AGCTAB_1TArray\n"));
+               ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                            (" ===> phy_ConfigBBWithHeaderFile() agc:Rtl8723PHY_REG_1TArray\n"));
+       }
+       return HAL_STATUS_SUCCESS;
+}
+
+enum hal_status
+ODM_ConfigMACWithHeaderFile23a(
+       struct dm_odm_t *pDM_Odm
+       )
+{
+       u8 result = HAL_STATUS_SUCCESS;
+
+       if (pDM_Odm->SupportICType == ODM_RTL8723A)
+               READ_AND_CONFIG_MP(8723A, _MAC_REG_);
+       return result;
+}
diff --git a/drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c b/drivers/staging/rtl8723au/hal/odm_RegConfig8723A.c
new file mode 100644 (file)
index 0000000..d076e14
--- /dev/null
@@ -0,0 +1,162 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 "odm_precomp.h"
+
+void
+odm_ConfigRFReg_8723A(
+       struct dm_odm_t *pDM_Odm,
+       u32                                     Addr,
+       u32                                     Data,
+  enum RF_RADIO_PATH     RF_PATH,
+       u32                                 RegAddr
+       )
+{
+       if (Addr == 0xfe) {
+               msleep(50);
+       } else if (Addr == 0xfd) {
+               mdelay(5);
+       } else if (Addr == 0xfc) {
+               mdelay(1);
+       } else if (Addr == 0xfb) {
+               udelay(50);
+       } else if (Addr == 0xfa) {
+               udelay(5);
+       } else if (Addr == 0xf9) {
+               udelay(1);
+       } else {
+               ODM_SetRFReg(pDM_Odm, RF_PATH, RegAddr, bRFRegOffsetMask, Data);
+               /*  Add 1us delay between BB/RF register setting. */
+               udelay(1);
+       }
+}
+
+void odm_ConfigRF_RadioA_8723A(struct dm_odm_t *pDM_Odm,
+       u32                                     Addr,
+       u32                                     Data
+       )
+{
+       u32  content = 0x1000; /*  RF_Content: radioa_txt */
+       u32     maskforPhySet = (u32)(content&0xE000);
+
+       odm_ConfigRFReg_8723A(pDM_Odm, Addr, Data, RF_PATH_A,
+                             Addr|maskforPhySet);
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                    ("===> ODM_ConfigRFWithHeaderFile23a: [RadioA] %08X %08X\n",
+                    Addr, Data));
+}
+
+void odm_ConfigRF_RadioB_8723A(struct dm_odm_t *pDM_Odm,
+       u32                                     Addr,
+       u32                                     Data
+       )
+{
+       u32  content = 0x1001; /*  RF_Content: radiob_txt */
+       u32     maskforPhySet = (u32)(content&0xE000);
+
+       odm_ConfigRFReg_8723A(pDM_Odm, Addr, Data, RF_PATH_B,
+                             Addr|maskforPhySet);
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                    ("===> ODM_ConfigRFWithHeaderFile23a: [RadioB] %08X %08X\n",
+                    Addr, Data));
+}
+
+void odm_ConfigMAC_8723A(struct dm_odm_t *pDM_Odm,
+       u32             Addr,
+       u8              Data
+       )
+{
+       ODM_Write1Byte(pDM_Odm, Addr, Data);
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                    ("===> ODM_ConfigMACWithHeaderFile23a: [MAC_REG] %08X %08X\n",
+                    Addr, Data));
+}
+
+void
+odm_ConfigBB_AGC_8723A(
+       struct dm_odm_t *pDM_Odm,
+       u32             Addr,
+       u32             Bitmask,
+       u32             Data
+  )
+{
+       ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data);
+       /*  Add 1us delay between BB/RF register setting. */
+       udelay(1);
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                    ("===> ODM_ConfigBBWithHeaderFile23a: [AGC_TAB] %08X %08X\n",
+                    Addr, Data));
+}
+
+void
+odm_ConfigBB_PHY_REG_PG_8723A(
+       struct dm_odm_t *pDM_Odm,
+       u32             Addr,
+       u32             Bitmask,
+       u32             Data
+  )
+{
+       if (Addr == 0xfe)
+               msleep(50);
+       else if (Addr == 0xfd)
+               mdelay(5);
+       else if (Addr == 0xfc)
+               mdelay(1);
+       else if (Addr == 0xfb)
+               udelay(50);
+       else if (Addr == 0xfa)
+               udelay(5);
+       else if (Addr == 0xf9)
+               udelay(1);
+    /*  TODO: ODM_StorePwrIndexDiffRateOffset(...) */
+       /*  storePwrIndexDiffRateOffset(Adapter, Addr, Bitmask, Data); */
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                    ("===> ODM_ConfigBBWithHeaderFile23a: [PHY_REG] %08X %08X %08X\n",
+                    Addr, Bitmask, Data));
+}
+
+void
+odm_ConfigBB_PHY_8723A(
+       struct dm_odm_t *pDM_Odm,
+       u32             Addr,
+       u32             Bitmask,
+       u32             Data
+  )
+{
+       if (Addr == 0xfe)
+               msleep(50);
+       else if (Addr == 0xfd)
+               mdelay(5);
+       else if (Addr == 0xfc)
+               mdelay(1);
+       else if (Addr == 0xfb)
+               udelay(50);
+       else if (Addr == 0xfa)
+               udelay(5);
+       else if (Addr == 0xf9)
+               udelay(1);
+       else if (Addr == 0xa24)
+               pDM_Odm->RFCalibrateInfo.RegA24 = Data;
+       ODM_SetBBReg(pDM_Odm, Addr, Bitmask, Data);
+
+       /*  Add 1us delay between BB/RF register setting. */
+       udelay(1);
+
+       ODM_RT_TRACE(pDM_Odm, ODM_COMP_INIT, ODM_DBG_LOUD,
+                    ("===> ODM_ConfigBBWithHeaderFile23a: [PHY_REG] %08X %08X\n",
+                    Addr, Data));
+}
diff --git a/drivers/staging/rtl8723au/hal/odm_debug.c b/drivers/staging/rtl8723au/hal/odm_debug.c
new file mode 100644 (file)
index 0000000..c912ab8
--- /dev/null
@@ -0,0 +1,24 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 "odm_precomp.h"
+
+void ODM_InitDebugSetting23a(struct dm_odm_t *pDM_Odm)
+{
+       pDM_Odm->DebugLevel = ODM_DBG_TRACE;
+       pDM_Odm->DebugComponents = 0;
+}
+
+u32 GlobalDebugLevel23A;
diff --git a/drivers/staging/rtl8723au/hal/odm_interface.c b/drivers/staging/rtl8723au/hal/odm_interface.c
new file mode 100644 (file)
index 0000000..bef1269
--- /dev/null
@@ -0,0 +1,236 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 files */
+/*  */
+
+#include "odm_precomp.h"
+/*  */
+/*  ODM IO Relative API. */
+/*  */
+
+u8 ODM_Read1Byte(struct dm_odm_t *pDM_Odm,
+       u32                     RegAddr
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       return rtw_read8(Adapter, RegAddr);
+}
+
+u16 ODM_Read2Byte(struct dm_odm_t *pDM_Odm,
+       u32                     RegAddr
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       return rtw_read16(Adapter, RegAddr);
+}
+
+u32 ODM_Read4Byte(struct dm_odm_t *pDM_Odm,
+       u32                     RegAddr
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       return rtw_read32(Adapter, RegAddr);
+}
+
+void ODM_Write1Byte(
+       struct dm_odm_t *pDM_Odm,
+       u32                     RegAddr,
+       u8                      Data
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       rtw_write8(Adapter, RegAddr, Data);
+}
+
+void ODM_Write2Byte(
+       struct dm_odm_t *pDM_Odm,
+       u32                     RegAddr,
+       u16                     Data
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       rtw_write16(Adapter, RegAddr, Data);
+}
+
+void ODM_Write4Byte(
+       struct dm_odm_t *pDM_Odm,
+       u32                     RegAddr,
+       u32                     Data
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       rtw_write32(Adapter, RegAddr, Data);
+
+}
+
+void ODM_SetMACReg(
+       struct dm_odm_t *pDM_Odm,
+       u32             RegAddr,
+       u32             BitMask,
+       u32             Data
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       PHY_SetBBReg(Adapter, RegAddr, BitMask, Data);
+}
+
+u32 ODM_GetMACReg(
+       struct dm_odm_t *pDM_Odm,
+       u32             RegAddr,
+       u32             BitMask
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       return PHY_QueryBBReg(Adapter, RegAddr, BitMask);
+}
+
+void ODM_SetBBReg(
+       struct dm_odm_t *pDM_Odm,
+       u32             RegAddr,
+       u32             BitMask,
+       u32             Data
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       PHY_SetBBReg(Adapter, RegAddr, BitMask, Data);
+}
+
+u32 ODM_GetBBReg(
+       struct dm_odm_t *pDM_Odm,
+       u32             RegAddr,
+       u32             BitMask
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       return PHY_QueryBBReg(Adapter, RegAddr, BitMask);
+}
+
+void ODM_SetRFReg(
+       struct dm_odm_t *pDM_Odm,
+       enum RF_RADIO_PATH      eRFPath,
+       u32                             RegAddr,
+       u32                             BitMask,
+       u32                             Data
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       PHY_SetRFReg(Adapter, eRFPath, RegAddr, BitMask, Data);
+}
+
+u32 ODM_GetRFReg(
+       struct dm_odm_t *pDM_Odm,
+       enum RF_RADIO_PATH      eRFPath,
+       u32                             RegAddr,
+       u32                             BitMask
+       )
+{
+       struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
+       return PHY_QueryRFReg(Adapter, eRFPath, RegAddr, BitMask);
+}
+
+/*  */
+/*  ODM Memory relative API. */
+/*  */
+void ODM_AllocateMemory(
+       struct dm_odm_t *pDM_Odm,
+       void **pPtr,
+       u32             length
+       )
+{
+       *pPtr = rtw_zvmalloc(length);
+}
+
+/*  length could be ignored, used to detect memory leakage. */
+void ODM_FreeMemory(
+       struct dm_odm_t *pDM_Odm,
+       void *pPtr,
+       u32             length
+       )
+{
+       rtw_vmfree(pPtr, length);
+}
+
+/*  */
+/*  ODM MISC relative API. */
+/*  */
+void
+ODM_AcquireSpinLock(
+       struct dm_odm_t *pDM_Odm,
+       enum rt_spinlock_type   type
+       )
+{
+}
+
+void ODM_ReleaseSpinLock(
+       struct dm_odm_t *pDM_Odm,
+       enum rt_spinlock_type   type
+       )
+{
+}
+
+/*  */
+/*  Work item relative API. FOr MP driver only~! */
+/*  */
+void ODM_InitializeWorkItem(
+       struct dm_odm_t *pDM_Odm,
+       void *pRtWorkItem,
+       RT_WORKITEM_CALL_BACK           RtWorkItemCallback,
+       void *pContext,
+       const char *szID
+       )
+{
+}
+
+/*  */
+/*  ODM Timer relative API. */
+/*  */
+void ODM_SetTimer(struct dm_odm_t *pDM_Odm, struct timer_list *pTimer, u32 msDelay)
+{
+       mod_timer(pTimer, jiffies + msecs_to_jiffies(msDelay)); /* ms */
+}
+
+void ODM_ReleaseTimer(struct dm_odm_t *pDM_Odm, struct timer_list *pTimer)
+{
+}
+
+/*  */
+/*  ODM FW relative API. */
+/*  */
+u32 ODM_FillH2CCmd(
+       u8 *pH2CBuffer,
+       u32             H2CBufferLen,
+       u32             CmdNum,
+       u32 *pElementID,
+       u32 *pCmdLen,
+       u8 **pCmbBuffer,
+       u8 *CmdStartSeq
+       )
+{
+       return  true;
+}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c
new file mode 100644 (file)
index 0000000..9d738d7
--- /dev/null
@@ -0,0 +1,11304 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 <drv_types.h>
+#include <rtl8723a_hal.h>
+#include <rtw_ioctl_set.h>
+
+#define DIS_PS_RX_BCN
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+
+u32 BTCoexDbgLevel = _bt_dbg_off_;
+
+#define RTPRINT(_Comp, _Level, Fmt)\
+do {\
+       if ((BTCoexDbgLevel == _bt_dbg_on_)) {\
+               printk Fmt;\
+       }                                       \
+} while (0)
+
+#define RTPRINT_ADDR(dbgtype, dbgflag, printstr, _Ptr)\
+if ((BTCoexDbgLevel == _bt_dbg_on_)) {\
+       u32 __i;                                                \
+       u8 *ptr = (u8 *)_Ptr;   \
+       printk printstr;                                \
+       printk(" ");                                    \
+       for (__i = 0; __i < 6; __i++)           \
+               printk("%02X%s", ptr[__i], (__i == 5)?"":"-");          \
+       printk("\n");                                                   \
+}
+#define RTPRINT_DATA(dbgtype, dbgflag, _TitleString, _HexData, _HexDataLen)\
+if ((BTCoexDbgLevel == _bt_dbg_on_)) {\
+       u32 __i;                                                \
+       u8 *ptr = (u8 *)_HexData;                               \
+       printk(_TitleString);                                   \
+       for (__i = 0; __i < (u32)_HexDataLen; __i++) {          \
+               printk("%02X%s", ptr[__i], (((__i + 1) % 4) == 0)?"  ":" ");\
+               if (((__i + 1) % 16) == 0)                      \
+                       printk("\n");                           \
+       }                                                               \
+       printk("\n");                                                   \
+}
+/*  Added by Annie, 2005-11-22. */
+#define MAX_STR_LEN    64
+/*  I want to see ASCII 33 to 126 only. Otherwise, I print '?'. */
+#define PRINTABLE(_ch) (_ch >= ' ' && _ch <= '~')
+#define RT_PRINT_STR(_Comp, _Level, _TitleString, _Ptr, _Len)          \
+       {                                                               \
+               u32 __i;                                                \
+               u8 buffer[MAX_STR_LEN];                                 \
+               u32 length = (_Len < MAX_STR_LEN) ? _Len : (MAX_STR_LEN-1);\
+               memset(buffer, 0, MAX_STR_LEN);                         \
+               memcpy(buffer, (u8 *)_Ptr, length);                     \
+               for (__i = 0; __i < length; __i++) {                    \
+                       if (!PRINTABLE(buffer[__i]))                    \
+                               buffer[__i] = '?';                      \
+               }                                                       \
+               buffer[length] = '\0';                                  \
+               printk(_TitleString);                                   \
+               printk(": %d, <%s>\n", _Len, buffer);                   \
+       }
+#endif
+
+#define DCMD_Printf(...)
+#define RT_ASSERT(...)
+
+#define rsprintf snprintf
+
+#define GetDefaultAdapter(padapter)    padapter
+
+#define PlatformZeroMemory(ptr, sz)    memset(ptr, 0, sz)
+
+#define PlatformProcessHCICommands(...)
+#define PlatformTxBTQueuedPackets(...)
+#define PlatformIndicateBTACLData(...) (RT_STATUS_SUCCESS)
+#define PlatformAcquireSpinLock(padapter, type)
+#define PlatformReleaseSpinLock(padapter, type)
+
+#define GET_UNDECORATED_AVERAGE_RSSI(padapter) \
+                       (GET_HAL_DATA(padapter)->dmpriv.EntryMinUndecoratedSmoothedPWDB)
+#define RT_RF_CHANGE_SOURCE u32
+
+enum {
+       RT_JOIN_INFRA   = 1,
+       RT_JOIN_IBSS  = 2,
+       RT_START_IBSS = 3,
+       RT_NO_ACTION  = 4,
+};
+
+/*  power saving */
+
+#ifdef __BT_C__ /*  COMMOM/BT.c */
+/*  ===== Below this line is sync from SD7 driver COMMOM/BT.c ===== */
+
+static u8 BT_Operation(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->BtOperationOn)
+               return true;
+       else
+               return false;
+}
+
+static u8 BT_IsLegalChannel(struct rtw_adapter *padapter, u8 channel)
+{
+       struct rt_channel_info *pChanneList = NULL;
+       u8 channelLen, i;
+
+       pChanneList = padapter->mlmeextpriv.channel_set;
+       channelLen = padapter->mlmeextpriv.max_chan_nums;
+
+       for (i = 0; i < channelLen; i++) {
+               RTPRINT(FIOCTL, IOCTL_STATE,
+                       ("Check if chnl(%d) in channel plan contains bt target chnl(%d) for BT connection\n",
+                        pChanneList[i].ChannelNum, channel));
+               if ((channel == pChanneList[i].ChannelNum) ||
+                   (channel == pChanneList[i].ChannelNum + 2))
+                       return channel;
+       }
+       return 0;
+}
+
+void BT_SignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi, u8 *rssi_bt)
+{
+       BTDM_SignalCompensation(padapter, rssi_wifi, rssi_bt);
+}
+
+void BT_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType)
+{
+       BTHCI_WifiScanNotify(padapter, scanType);
+       BTDM_CheckAntSelMode(padapter);
+       BTDM_WifiScanNotify(padapter, scanType);
+}
+
+void BT_WifiAssociateNotify(struct rtw_adapter *padapter, u8 action)
+{
+       /*  action : */
+       /*  true = associate start */
+       /*  false = associate finished */
+       if (action)
+               BTDM_CheckAntSelMode(padapter);
+
+       BTDM_WifiAssociateNotify(padapter, action);
+}
+
+void BT_WifiMediaStatusNotify(struct rtw_adapter *padapter, enum rt_media_status mstatus)
+{
+       BTDM_MediaStatusNotify(padapter, mstatus);
+}
+
+void BT_SpecialPacketNotify(struct rtw_adapter *padapter)
+{
+       BTDM_ForDhcp(padapter);
+}
+
+void BT_HaltProcess(struct rtw_adapter *padapter)
+{
+       BTDM_ForHalt(padapter);
+}
+
+void BT_LpsLeave(struct rtw_adapter *padapter)
+{
+       BTDM_LpsLeave(padapter);
+}
+
+/*  ===== End of sync from SD7 driver COMMOM/BT.c ===== */
+#endif
+
+#ifdef __BT_HANDLEPACKET_C__ /*  COMMOM/bt_handlepacket.c */
+/*  ===== Below this line is sync from SD7 driver COMMOM/bt_handlepacket.c ===== */
+
+/*  ===== End of sync from SD7 driver COMMOM/bt_handlepacket.c ===== */
+#endif
+
+#ifdef __BT_HCI_C__ /*  COMMOM/bt_hci.c */
+
+#define i64fmt         "ll"
+#define UINT64_C(v)  (v)
+
+#define FillOctetString(_os, _octet, _len)             \
+       (_os).Octet = (u8 *)(_octet);                   \
+       (_os).Length = (_len);
+
+static enum rt_status PlatformIndicateBTEvent(
+       struct rtw_adapter *padapter,
+       void                                            *pEvntData,
+       u32                                             dataLen
+       )
+{
+       enum rt_status  rt_status = RT_STATUS_FAILURE;
+
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT_DETAIL, ("BT event start, %d bytes data to Transferred!!\n", dataLen));
+       RTPRINT_DATA(FIOCTL, IOCTL_BT_EVENT_DETAIL, "To transfer Hex Data :\n",
+               pEvntData, dataLen);
+
+       BT_EventParse(padapter, pEvntData, dataLen);
+
+       printk(KERN_WARNING "%s: Linux has no way to report BT event!!\n", __func__);
+
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT_DETAIL, ("BT event end, %s\n",
+               (rt_status == RT_STATUS_SUCCESS) ? "SUCCESS" : "FAIL"));
+
+       return rt_status;
+}
+
+/*  ===== Below this line is sync from SD7 driver COMMOM/bt_hci.c ===== */
+
+static u8 bthci_GetLocalChannel(struct rtw_adapter *padapter)
+{
+       return padapter->mlmeextpriv.cur_channel;
+}
+
+static u8 bthci_GetCurrentEntryNum(struct rtw_adapter *padapter, u8 PhyHandle)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       u8 i;
+
+       for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) {
+               if ((pBTInfo->BtAsocEntry[i].bUsed) &&
+                   (pBTInfo->BtAsocEntry[i].PhyLinkCmdData.BtPhyLinkhandle == PhyHandle))
+                       return i;
+       }
+
+       return 0xFF;
+}
+
+static void bthci_DecideBTChannel(struct rtw_adapter *padapter, u8 EntryNum)
+{
+/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */
+       struct mlme_priv *pmlmepriv;
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_hci_info *pBtHciInfo;
+       struct chnl_txpower_triple *pTriple_subband = NULL;
+       struct common_triple *pTriple;
+       u8 i, j, localchnl, firstRemoteLegalChnlInTriplet = 0;
+       u8 regulatory_skipLen = 0;
+       u8 subbandTripletCnt = 0;
+
+       pmlmepriv = &padapter->mlmepriv;
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtHciInfo = &pBTInfo->BtHciInfo;
+
+       pBtMgnt->CheckChnlIsSuit = true;
+       localchnl = bthci_GetLocalChannel(padapter);
+
+       pTriple = (struct common_triple *)
+               &pBtHciInfo->BTPreChnllist[COUNTRY_STR_LEN];
+
+       /*  contains country string, len is 3 */
+       for (i = 0; i < (pBtHciInfo->BtPreChnlListLen-COUNTRY_STR_LEN); i += 3, pTriple++) {
+               /*  */
+               /*  check every triplet, an triplet may be */
+               /*  regulatory extension identifier or sub-band triplet */
+               /*  */
+               if (pTriple->byte_1st == 0xc9) {
+                       /*  Regulatory Extension Identifier, skip it */
+                       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO),
+                               ("Find Regulatory ID, regulatory class = %d\n", pTriple->byte_2nd));
+                       regulatory_skipLen += 3;
+                       pTriple_subband = NULL;
+                       continue;
+               } else {        /*  Sub-band triplet */
+                       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Find Sub-band triplet \n"));
+                       subbandTripletCnt++;
+                       pTriple_subband = (struct chnl_txpower_triple *)pTriple;
+                       /*  if remote first legal channel not found, then find first remote channel */
+                       /*  and it's legal for our channel plan. */
+
+                       /*  search the sub-band triplet and find if remote channel is legal to our channel plan. */
+                       for (j = pTriple_subband->FirstChnl; j < (pTriple_subband->FirstChnl+pTriple_subband->NumChnls); j++) {
+                               RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), (" Check if chnl(%d) is legal\n", j));
+                               if (BT_IsLegalChannel(padapter, j)) {
+                                       /*  remote channel is legal for our channel plan. */
+                                       firstRemoteLegalChnlInTriplet = j;
+                                       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO),
+                                               ("Find first remote legal channel : %d\n",
+                                               firstRemoteLegalChnlInTriplet));
+
+                                       /*  If we find a remote legal channel in the sub-band triplet */
+                                       /*  and only BT connection is established(local not connect to any AP or IBSS), */
+                                       /*  then we just switch channel to remote channel. */
+                                       if (!(check_fwstate(pmlmepriv, WIFI_ASOC_STATE|WIFI_ADHOC_STATE|WIFI_AP_STATE) ||
+                                           BTHCI_HsConnectionEstablished(padapter))) {
+                                               pBtMgnt->BTChannel = firstRemoteLegalChnlInTriplet;
+                                               RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Remote legal channel (%d) is selected, Local not connect to any!!\n", pBtMgnt->BTChannel));
+                                               return;
+                                       } else {
+                                               if ((localchnl >= firstRemoteLegalChnlInTriplet) &&
+                                                   (localchnl < (pTriple_subband->FirstChnl+pTriple_subband->NumChnls))) {
+                                                       pBtMgnt->BTChannel = localchnl;
+                                                       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Local channel (%d) is selected, wifi or BT connection exists\n", pBtMgnt->BTChannel));
+                                                       return;
+                                               }
+                                       }
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       if (subbandTripletCnt) {
+               /* if any preferred channel triplet exists */
+               RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("There are %d sub band triplet exists, ", subbandTripletCnt));
+               if (firstRemoteLegalChnlInTriplet == 0) {
+                       /* no legal channel is found, reject the connection. */
+                       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("no legal channel is found!!\n"));
+               } else {
+                       /*  Remote Legal channel is found but not match to local */
+                       /* wifi connection exists), so reject the connection. */
+                       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO),
+                               ("Remote Legal channel is found but not match to local(wifi connection exists)!!\n"));
+               }
+               pBtMgnt->CheckChnlIsSuit = false;
+       } else {
+               /*  There are not any preferred channel triplet exists */
+               /*  Use current legal channel as the bt channel. */
+               RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("No sub band triplet exists!!\n"));
+       }
+       pBtMgnt->BTChannel = localchnl;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Local channel (%d) is selected!!\n", pBtMgnt->BTChannel));
+}
+
+/* Success:return true */
+/* Fail:return false */
+static u8 bthci_GetAssocInfo(struct rtw_adapter *padapter, u8 EntryNum)
+{
+       struct bt_30info *pBTInfo;
+       struct bt_hci_info *pBtHciInfo;
+       u8 tempBuf[256];
+       u8 i = 0;
+       u8 BaseMemoryShift = 0;
+       u16     TotalLen = 0;
+       struct amp_assoc_structure *pAmpAsoc;
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("GetAssocInfo start\n"));
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtHciInfo = &pBTInfo->BtHciInfo;
+
+       if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar == 0) {
+               if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocRemLen < (MAX_AMP_ASSOC_FRAG_LEN))
+                       TotalLen = pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocRemLen;
+               else if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocRemLen == (MAX_AMP_ASSOC_FRAG_LEN))
+                       TotalLen = MAX_AMP_ASSOC_FRAG_LEN;
+       } else if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar > 0)
+               TotalLen = pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar;
+
+       while ((pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar >= BaseMemoryShift) || TotalLen > BaseMemoryShift) {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("GetAssocInfo, TotalLen =%d, BaseMemoryShift =%d\n", TotalLen, BaseMemoryShift));
+               memcpy(tempBuf,
+                       (u8 *)pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocfragment+BaseMemoryShift,
+                       TotalLen-BaseMemoryShift);
+               RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_DETAIL, "GetAssocInfo :\n",
+                       tempBuf, TotalLen-BaseMemoryShift);
+
+               pAmpAsoc = (struct amp_assoc_structure *)tempBuf;
+               pAmpAsoc->Length = le16_to_cpu(pAmpAsoc->Length);
+               BaseMemoryShift += 3 + pAmpAsoc->Length;
+
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("TypeID = 0x%x, ", pAmpAsoc->TypeID));
+               RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD, "Hex Data: \n", pAmpAsoc->Data, pAmpAsoc->Length);
+               switch (pAmpAsoc->TypeID) {
+               case AMP_MAC_ADDR:
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> AMP_MAC_ADDR\n"));
+                       if (pAmpAsoc->Length > 6)
+                               return false;
+                       memcpy(pBTInfo->BtAsocEntry[EntryNum].BTRemoteMACAddr, pAmpAsoc->Data, 6);
+                       RTPRINT_ADDR(FIOCTL, IOCTL_BT_HCICMD, ("Remote Mac address \n"), pBTInfo->BtAsocEntry[EntryNum].BTRemoteMACAddr);
+                       break;
+               case AMP_PREFERRED_CHANNEL_LIST:
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> AMP_PREFERRED_CHANNEL_LIST\n"));
+                       pBtHciInfo->BtPreChnlListLen = pAmpAsoc->Length;
+                       memcpy(pBtHciInfo->BTPreChnllist,
+                               pAmpAsoc->Data,
+                               pBtHciInfo->BtPreChnlListLen);
+                       RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD, "Preferred channel list : \n", pBtHciInfo->BTPreChnllist, pBtHciInfo->BtPreChnlListLen);
+                       bthci_DecideBTChannel(padapter, EntryNum);
+                       break;
+               case AMP_CONNECTED_CHANNEL:
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> AMP_CONNECTED_CHANNEL\n"));
+                       pBtHciInfo->BTConnectChnlListLen = pAmpAsoc->Length;
+                       memcpy(pBtHciInfo->BTConnectChnllist,
+                               pAmpAsoc->Data,
+                               pBtHciInfo->BTConnectChnlListLen);
+                       break;
+               case AMP_80211_PAL_CAP_LIST:
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> AMP_80211_PAL_CAP_LIST\n"));
+                       pBTInfo->BtAsocEntry[EntryNum].BTCapability = *(u32 *)(pAmpAsoc->Data);
+                       if (pBTInfo->BtAsocEntry[EntryNum].BTCapability & 0x00000001) {
+                               /*  TODO: */
+
+                               /* Signifies PAL capable of utilizing received activity reports. */
+                       }
+                       if (pBTInfo->BtAsocEntry[EntryNum].BTCapability & 0x00000002) {
+                               /*  TODO: */
+                               /* Signifies PAL is capable of utilizing scheduling information received in an activity reports. */
+                       }
+                       break;
+               case AMP_80211_PAL_VISION:
+                       pBtHciInfo->BTPalVersion = *(u8 *)(pAmpAsoc->Data);
+                       pBtHciInfo->BTPalCompanyID = *(u16 *)(((u8 *)(pAmpAsoc->Data))+1);
+                       pBtHciInfo->BTPalsubversion = *(u16 *)(((u8 *)(pAmpAsoc->Data))+3);
+                       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("==> AMP_80211_PAL_VISION PalVersion  0x%x, PalCompanyID  0x%x, Palsubversion 0x%x\n",
+                               pBtHciInfo->BTPalVersion,
+                               pBtHciInfo->BTPalCompanyID,
+                               pBtHciInfo->BTPalsubversion));
+                       break;
+               default:
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("==> Unsupport TypeID !!\n"));
+                       break;
+               }
+               i++;
+       }
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("GetAssocInfo end\n"));
+
+       return true;
+}
+
+static u8 bthci_AddEntry(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       u8 i;
+
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+
+       for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) {
+               if (pBTInfo->BtAsocEntry[i].bUsed == false) {
+                       pBTInfo->BtAsocEntry[i].bUsed = true;
+                       pBtMgnt->CurrentConnectEntryNum = i;
+                       break;
+               }
+       }
+
+       if (i == MAX_BT_ASOC_ENTRY_NUM) {
+               RTPRINT(FIOCTL, IOCTL_STATE, ("bthci_AddEntry(), Add entry fail!!\n"));
+               return false;
+       }
+       return true;
+}
+
+static u8 bthci_DiscardTxPackets(struct rtw_adapter *padapter, u16 LLH)
+{
+       return false;
+}
+
+static u8
+bthci_CheckLogLinkBehavior(
+       struct rtw_adapter *padapter,
+       struct hci_flow_spec                    TxFlowSpec
+       )
+{
+       u8 ID = TxFlowSpec.Identifier;
+       u8 ServiceType = TxFlowSpec.ServiceType;
+       u16     MaxSDUSize = TxFlowSpec.MaximumSDUSize;
+       u32     SDUInterArrivatime = TxFlowSpec.SDUInterArrivalTime;
+       u8 match = false;
+
+       switch (ID) {
+       case 1:
+               if (ServiceType == BT_LL_BE) {
+                       match = true;
+                       RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type =  TX best effort flowspec\n"));
+               } else if ((ServiceType == BT_LL_GU) && (MaxSDUSize == 0xffff)) {
+                       match = true;
+                       RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type =  RX guaranteed latency flowspec\n"));
+               } else if ((ServiceType == BT_LL_GU) && (MaxSDUSize == 2500)) {
+                       RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type =  RX guaranteed Large latency flowspec\n"));
+               }
+               break;
+       case 2:
+               if (ServiceType == BT_LL_BE) {
+                       match = true;
+                       RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type =  RX best effort flowspec\n"));
+
+               }
+               break;
+       case 3:
+               if ((ServiceType == BT_LL_GU) && (MaxSDUSize == 1492)) {
+                       match = true;
+                       RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type =  TX guaranteed latency flowspec\n"));
+               } else if ((ServiceType == BT_LL_GU) && (MaxSDUSize == 2500)) {
+                       RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type =  TX guaranteed Large latency flowspec\n"));
+               }
+               break;
+       case 4:
+               if (ServiceType == BT_LL_BE) {
+                       if ((SDUInterArrivatime == 0xffffffff) && (ServiceType == BT_LL_BE) && (MaxSDUSize == 1492)) {
+                               match = true;
+                               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type =  TX/RX aggregated best effort flowspec\n"));
+                       }
+               } else if (ServiceType == BT_LL_GU) {
+                       if (SDUInterArrivatime == 100) {
+                               match = true;
+                               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type =  TX/RX guaranteed bandwidth flowspec\n"));
+                       }
+               }
+               break;
+       default:
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Logical Link Type =  Unknow Type !!!!!!!!\n"));
+               break;
+       }
+
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO),
+               ("ID = 0x%x, ServiceType = 0x%x, MaximumSDUSize = 0x%x, SDUInterArrivalTime = 0x%x, AccessLatency = 0x%x, FlushTimeout = 0x%x\n",
+               TxFlowSpec.Identifier, TxFlowSpec.ServiceType, MaxSDUSize,
+               SDUInterArrivatime, TxFlowSpec.AccessLatency, TxFlowSpec.FlushTimeout));
+       return match;
+}
+
+static u16 bthci_AssocMACAddr(struct rtw_adapter *padapter, void       *pbuf)
+{
+       struct amp_assoc_structure *pAssoStrc = (struct amp_assoc_structure *)pbuf;
+       pAssoStrc->TypeID = AMP_MAC_ADDR;
+       pAssoStrc->Length = 0x06;
+       memcpy(&pAssoStrc->Data[0], padapter->eeprompriv.mac_addr, 6);
+       RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO),
+                    ("AssocMACAddr : \n"), pAssoStrc, pAssoStrc->Length+3);
+
+       return pAssoStrc->Length + 3;
+}
+
+static u16
+bthci_PALCapabilities(
+       struct rtw_adapter *padapter,
+       void    *pbuf
+       )
+{
+       struct amp_assoc_structure *pAssoStrc = (struct amp_assoc_structure *)pbuf;
+
+       pAssoStrc->TypeID = AMP_80211_PAL_CAP_LIST;
+       pAssoStrc->Length = 0x04;
+
+       pAssoStrc->Data[0] = 0x00;
+       pAssoStrc->Data[1] = 0x00;
+
+       RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("PALCapabilities:\n"), pAssoStrc, pAssoStrc->Length+3);
+       RTPRINT(FIOCTL, IOCTL_BT_LOGO, ("PALCapabilities \n"));
+
+       RTPRINT(FIOCTL, IOCTL_BT_LOGO, (" TypeID = 0x%x,\n Length = 0x%x,\n Content = 0x0000\n",
+               pAssoStrc->TypeID,
+               pAssoStrc->Length));
+
+       return pAssoStrc->Length + 3;
+}
+
+static u16 bthci_AssocPreferredChannelList(struct rtw_adapter *padapter,
+                                          void *pbuf, u8 EntryNum)
+{
+       struct bt_30info *pBTInfo;
+       struct amp_assoc_structure *pAssoStrc;
+       struct amp_pref_chnl_regulatory *pReg;
+       struct chnl_txpower_triple *pTriple;
+       char ctrString[3] = {'X', 'X', 'X'};
+       u32 len = 0;
+       u8 preferredChnl;
+
+       pBTInfo = GET_BT_INFO(padapter);
+       pAssoStrc = (struct amp_assoc_structure *)pbuf;
+       pReg = (struct amp_pref_chnl_regulatory *)&pAssoStrc->Data[3];
+
+       preferredChnl = bthci_GetLocalChannel(padapter);
+       pAssoStrc->TypeID = AMP_PREFERRED_CHANNEL_LIST;
+
+       /*  locale unknown */
+       memcpy(&pAssoStrc->Data[0], &ctrString[0], 3);
+       pReg->reXId = 201;
+       pReg->regulatoryClass = 254;
+       pReg->coverageClass = 0;
+       len += 6;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD | IOCTL_BT_LOGO), ("PREFERRED_CHNL_LIST\n"));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD | IOCTL_BT_LOGO), ("XXX, 201, 254, 0\n"));
+       /*  at the following, chnl 1~11 should be contained */
+       pTriple = (struct chnl_txpower_triple *)&pAssoStrc->Data[len];
+
+       /*  (1) if any wifi or bt HS connection exists */
+       if ((pBTInfo->BtAsocEntry[EntryNum].AMPRole == AMP_BTAP_CREATOR) ||
+           (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE |
+                          WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE |
+                          WIFI_AP_STATE)) ||
+           BTHCI_HsConnectionEstablished(padapter)) {
+               pTriple->FirstChnl = preferredChnl;
+               pTriple->NumChnls = 1;
+               pTriple->MaxTxPowerInDbm = 20;
+               len += 3;
+               RTPRINT(FIOCTL, (IOCTL_BT_HCICMD | IOCTL_BT_LOGO), ("First Channel = %d, Channel Num = %d, MaxDbm = %d\n",
+                       pTriple->FirstChnl,
+                       pTriple->NumChnls,
+                       pTriple->MaxTxPowerInDbm));
+       }
+
+       pAssoStrc->Length = (u16)len;
+       RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD, ("AssocPreferredChannelList : \n"), pAssoStrc, pAssoStrc->Length+3);
+
+       return pAssoStrc->Length + 3;
+}
+
+static u16 bthci_AssocPALVer(struct rtw_adapter *padapter, void *pbuf)
+{
+       struct amp_assoc_structure *pAssoStrc = (struct amp_assoc_structure *)pbuf;
+       u8 *pu1Tmp;
+       u16     *pu2Tmp;
+
+       pAssoStrc->TypeID = AMP_80211_PAL_VISION;
+       pAssoStrc->Length = 0x5;
+       pu1Tmp = &pAssoStrc->Data[0];
+       *pu1Tmp = 0x1;  /*  PAL Version */
+       pu2Tmp = (u16 *)&pAssoStrc->Data[1];
+       *pu2Tmp = 0x5D; /*  SIG Company identifier of 802.11 PAL vendor */
+       pu2Tmp = (u16 *)&pAssoStrc->Data[3];
+       *pu2Tmp = 0x1;  /*  PAL Sub-version specifier */
+
+       RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("AssocPALVer : \n"), pAssoStrc, pAssoStrc->Length+3);
+       RTPRINT(FIOCTL, IOCTL_BT_LOGO, ("AssocPALVer \n"));
+
+       RTPRINT(FIOCTL, IOCTL_BT_LOGO, (" TypeID = 0x%x,\n Length = 0x%x,\n PAL Version = 0x01,\n PAL vendor = 0x01,\n PAL Sub-version specifier = 0x01\n",
+               pAssoStrc->TypeID,
+               pAssoStrc->Length));
+       return pAssoStrc->Length + 3;
+}
+
+static u8 bthci_CheckRfStateBeforeConnect(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo;
+       enum rt_rf_power_state          RfState;
+
+       pBTInfo = GET_BT_INFO(padapter);
+
+       RfState = padapter->pwrctrlpriv.rf_pwrstate;
+
+       if (RfState != rf_on) {
+               mod_timer(&pBTInfo->BTPsDisableTimer,
+                         jiffies + msecs_to_jiffies(50));
+               return false;
+       }
+       return true;
+}
+
+static void bthci_ResponderStartToScan(struct rtw_adapter *padapter)
+{
+}
+
+static u8 bthci_PhyLinkConnectionInProgress(struct rtw_adapter *padapter, u8 PhyLinkHandle)
+{
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->bPhyLinkInProgress &&
+               (pBtMgnt->BtCurrentPhyLinkhandle == PhyLinkHandle))
+               return true;
+       return false;
+}
+
+static void bthci_ResetFlowSpec(struct rtw_adapter *padapter, u8 EntryNum, u8 index)
+{
+       struct bt_30info *pBTinfo;
+
+       pBTinfo = GET_BT_INFO(padapter);
+
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].BtLogLinkhandle = 0;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].BtPhyLinkhandle = 0;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].bLLCompleteEventIsSet = false;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].bLLCancelCMDIsSetandComplete = false;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].BtTxFlowSpecID = 0;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].TxPacketCount = 0;
+
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.Identifier = 0x01;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.ServiceType = SERVICE_BEST_EFFORT;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.MaximumSDUSize = 0xffff;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.SDUInterArrivalTime = 0xffffffff;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.AccessLatency = 0xffffffff;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Tx_Flow_Spec.FlushTimeout = 0xffffffff;
+
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.Identifier = 0x01;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.ServiceType = SERVICE_BEST_EFFORT;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.MaximumSDUSize = 0xffff;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.SDUInterArrivalTime = 0xffffffff;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.AccessLatency = 0xffffffff;
+       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[index].Rx_Flow_Spec.FlushTimeout = 0xffffffff;
+}
+
+static void bthci_ResetEntry(struct rtw_adapter *padapter, u8 EntryNum)
+{
+       struct bt_30info *pBTinfo;
+       struct bt_mgnt *pBtMgnt;
+       u8 j;
+
+       pBTinfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTinfo->BtMgnt;
+
+       pBTinfo->BtAsocEntry[EntryNum].bUsed = false;
+       pBTinfo->BtAsocEntry[EntryNum].BtCurrentState = HCI_STATE_DISCONNECTED;
+       pBTinfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTED;
+
+       pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocRemLen = 0;
+       pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.BtPhyLinkhandle = 0;
+       if (pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocfragment != NULL)
+               memset(pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocfragment, 0, TOTAL_ALLOCIATE_ASSOC_LEN);
+       pBTinfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar = 0;
+
+       pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyType = 0;
+       pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle = 0;
+       memset(pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKey, 0,
+              pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen);
+       pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen = 0;
+
+       /* 0x640; 0.625ms*1600 = 1000ms, 0.625ms*16000 = 10000ms */
+       pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.LinkSuperversionTimeout = 0x3e80;
+
+       pBTinfo->BtAsocEntry[EntryNum].AMPRole = AMP_BTAP_NONE;
+
+       pBTinfo->BtAsocEntry[EntryNum].mAssoc = false;
+       pBTinfo->BtAsocEntry[EntryNum].b4waySuccess = false;
+
+       /*  Reset BT WPA */
+       pBTinfo->BtAsocEntry[EntryNum].KeyReplayCounter = 0;
+       pBTinfo->BtAsocEntry[EntryNum].BTWPAAuthState = STATE_WPA_AUTH_UNINITIALIZED;
+
+       pBTinfo->BtAsocEntry[EntryNum].bSendSupervisionPacket = false;
+       pBTinfo->BtAsocEntry[EntryNum].NoRxPktCnt = 0;
+       pBTinfo->BtAsocEntry[EntryNum].ShortRangeMode = 0;
+       pBTinfo->BtAsocEntry[EntryNum].rxSuvpPktCnt = 0;
+
+       for (j = 0; j < MAX_LOGICAL_LINK_NUM; j++)
+               bthci_ResetFlowSpec(padapter, EntryNum, j);
+
+       pBtMgnt->BTAuthCount = 0;
+       pBtMgnt->BTAsocCount = 0;
+       pBtMgnt->BTCurrentConnectType = BT_DISCONNECT;
+       pBtMgnt->BTReceiveConnectPkt = BT_DISCONNECT;
+
+       HALBT_RemoveKey(padapter, EntryNum);
+}
+
+static void bthci_RemoveEntryByEntryNum(struct rtw_adapter *padapter, u8 EntryNum)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       bthci_ResetEntry(padapter, EntryNum);
+
+       if (pBtMgnt->CurrentBTConnectionCnt > 0)
+               pBtMgnt->CurrentBTConnectionCnt--;
+
+       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], CurrentBTConnectionCnt = %d!!\n",
+               pBtMgnt->CurrentBTConnectionCnt));
+
+       if (pBtMgnt->CurrentBTConnectionCnt > 0) {
+               pBtMgnt->BtOperationOn = true;
+       } else {
+               pBtMgnt->BtOperationOn = false;
+               RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], Bt Operation OFF!!\n"));
+       }
+
+       if (!pBtMgnt->BtOperationOn) {
+               del_timer_sync(&pBTInfo->BTHCIDiscardAclDataTimer);
+               del_timer_sync(&pBTInfo->BTBeaconTimer);
+               pBtMgnt->bStartSendSupervisionPkt = false;
+       }
+}
+
+static u8
+bthci_CommandCompleteHeader(
+       u8 *pbuf,
+       u16             OGF,
+       u16             OCF,
+       enum hci_status status
+       )
+{
+       struct packet_irp_hcievent_data *PPacketIrpEvent = (struct packet_irp_hcievent_data *)pbuf;
+       u8 NumHCI_Comm = 0x1;
+
+       PPacketIrpEvent->EventCode = HCI_EVENT_COMMAND_COMPLETE;
+       PPacketIrpEvent->Data[0] = NumHCI_Comm; /* packet # */
+       PPacketIrpEvent->Data[1] = HCIOPCODELOW(OCF, OGF);
+       PPacketIrpEvent->Data[2] = HCIOPCODEHIGHT(OCF, OGF);
+
+       if (OGF == OGF_EXTENSION) {
+               if (OCF == HCI_SET_RSSI_VALUE) {
+                       RTPRINT(FIOCTL, (IOCTL_BT_EVENT_PERIODICAL),
+                               ("[BT event], CommandComplete, Num_HCI_Comm = 0x%x, Opcode = 0x%02x%02x, status = 0x%x, OGF = 0x%x, OCF = 0x%x\n",
+                               NumHCI_Comm, (HCIOPCODEHIGHT(OCF, OGF)), (HCIOPCODELOW(OCF, OGF)), status, OGF, OCF));
+               } else {
+                       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_EXT),
+                               ("[BT event], CommandComplete, Num_HCI_Comm = 0x%x, Opcode = 0x%02x%02x, status = 0x%x, OGF = 0x%x, OCF = 0x%x\n",
+                               NumHCI_Comm, (HCIOPCODEHIGHT(OCF, OGF)), (HCIOPCODELOW(OCF, OGF)), status, OGF, OCF));
+               }
+       } else {
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO),
+                       ("[BT event], CommandComplete, Num_HCI_Comm = 0x%x, Opcode = 0x%02x%02x, status = 0x%x, OGF = 0x%x, OCF = 0x%x\n",
+                       NumHCI_Comm, (HCIOPCODEHIGHT(OCF, OGF)), (HCIOPCODELOW(OCF, OGF)), status, OGF, OCF));
+       }
+       return 3;
+}
+
+static u8 bthci_ExtensionEventHeaderRtk(u8 *pbuf, u8 extensionEvent)
+{
+       struct packet_irp_hcievent_data *PPacketIrpEvent = (struct packet_irp_hcievent_data *)pbuf;
+       PPacketIrpEvent->EventCode = HCI_EVENT_EXTENSION_RTK;
+       PPacketIrpEvent->Data[0] = extensionEvent;      /* extension event code */
+
+       return 1;
+}
+
+static enum rt_status
+bthci_IndicateEvent(
+       struct rtw_adapter *padapter,
+       void            *pEvntData,
+       u32             dataLen
+       )
+{
+       enum rt_status  rt_status;
+
+       rt_status = PlatformIndicateBTEvent(padapter, pEvntData, dataLen);
+
+       return rt_status;
+}
+
+static void
+bthci_EventWriteRemoteAmpAssoc(
+       struct rtw_adapter *padapter,
+       enum hci_status status,
+       u8 PLHandle
+       )
+{
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_STATUS_PARAMETERS,
+               HCI_WRITE_REMOTE_AMP_ASSOC,
+               status);
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("PhyLinkHandle = 0x%x, status = %d\n", PLHandle, status));
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       pRetPar[1] = PLHandle;
+       len += 2;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+}
+
+static void
+bthci_EventEnhancedFlushComplete(
+       struct rtw_adapter *padapter,
+       u16                                     LLH
+       )
+{
+       u8 localBuf[4] = "";
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("EventEnhancedFlushComplete, LLH = 0x%x\n", LLH));
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_ENHANCED_FLUSH_COMPLETE;
+       PPacketIrpEvent->Length = 2;
+       /* Logical link handle */
+       PPacketIrpEvent->Data[0] = TWOBYTE_LOWBYTE(LLH);
+       PPacketIrpEvent->Data[1] = TWOBYTE_HIGHTBYTE(LLH);
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 4);
+}
+
+static void
+bthci_EventShortRangeModeChangeComplete(
+       struct rtw_adapter *padapter,
+       enum hci_status                         HciStatus,
+       u8              ShortRangeState,
+       u8              EntryNum
+       )
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[5] = "";
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE)) {
+               RTPRINT(FIOCTL, IOCTL_BT_EVENT,
+                       ("[BT event], Short Range Mode Change Complete, Ignore to send this event due to event mask page 2\n"));
+               return;
+       }
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Short Range Mode Change Complete, Status = %d\n , PLH = 0x%x\n, Short_Range_Mode_State = 0x%x\n",
+               HciStatus, pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle, ShortRangeState));
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE;
+       PPacketIrpEvent->Length = 3;
+       PPacketIrpEvent->Data[0] = HciStatus;
+       PPacketIrpEvent->Data[1] = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle;
+       PPacketIrpEvent->Data[2] = ShortRangeState;
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 5);
+}
+
+static void bthci_EventSendFlowSpecModifyComplete(struct rtw_adapter *padapter,
+                                                 enum hci_status HciStatus,
+                                                 u16 logicHandle)
+{
+       u8 localBuf[5] = "";
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+
+       if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE)) {
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO),
+                       ("[BT event], Flow Spec Modify Complete, Ignore to send this event due to event mask page 2\n"));
+               return;
+       }
+       RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO),
+               ("[BT event], Flow Spec Modify Complete, status = 0x%x, LLH = 0x%x\n", HciStatus, logicHandle));
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE;
+       PPacketIrpEvent->Length = 3;
+
+       PPacketIrpEvent->Data[0] = HciStatus;
+       /* Logical link handle */
+       PPacketIrpEvent->Data[1] = TWOBYTE_LOWBYTE(logicHandle);
+       PPacketIrpEvent->Data[2] = TWOBYTE_HIGHTBYTE(logicHandle);
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 5);
+}
+
+static void
+bthci_EventExtWifiScanNotify(
+       struct rtw_adapter *padapter,
+       u8                      scanType
+       )
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       u8 len = 0;
+       u8 localBuf[7] = "";
+       u8 *pRetPar;
+       u8 *pu1Temp;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       if (!pBtMgnt->BtOperationOn)
+               return;
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_ExtensionEventHeaderRtk(&localBuf[0], HCI_EVENT_EXT_WIFI_SCAN_NOTIFY);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pu1Temp = (u8 *)&pRetPar[0];
+       *pu1Temp = scanType;
+       len += 1;
+
+       PPacketIrpEvent->Length = len;
+
+       if (bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2) == RT_STATUS_SUCCESS) {
+               RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Wifi scan notify, scan type = %d\n",
+                       scanType));
+       }
+}
+
+static void
+bthci_EventAMPReceiverReport(
+       struct rtw_adapter *padapter,
+       u8 Reason
+       )
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+
+       if (pBtHciInfo->bTestNeedReport) {
+               u8 localBuf[20] = "";
+               u32     *pu4Temp;
+               u16     *pu2Temp;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), (" HCI_EVENT_AMP_RECEIVER_REPORT\n"));
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+               PPacketIrpEvent->EventCode = HCI_EVENT_AMP_RECEIVER_REPORT;
+               PPacketIrpEvent->Length = 2;
+
+               PPacketIrpEvent->Data[0] = pBtHciInfo->TestCtrType;
+
+               PPacketIrpEvent->Data[1] = Reason;
+
+               pu4Temp = (u32 *)&PPacketIrpEvent->Data[2];
+               *pu4Temp = pBtHciInfo->TestEventType;
+
+               pu2Temp = (u16 *)&PPacketIrpEvent->Data[6];
+               *pu2Temp = pBtHciInfo->TestNumOfFrame;
+
+               pu2Temp = (u16 *)&PPacketIrpEvent->Data[8];
+               *pu2Temp = pBtHciInfo->TestNumOfErrFrame;
+
+               pu4Temp = (u32 *)&PPacketIrpEvent->Data[10];
+               *pu4Temp = pBtHciInfo->TestNumOfBits;
+
+               pu4Temp = (u32 *)&PPacketIrpEvent->Data[14];
+               *pu4Temp = pBtHciInfo->TestNumOfErrBits;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, 20);
+
+               /* Return to Idel state with RX and TX off. */
+
+       }
+
+       pBtHciInfo->TestNumOfFrame = 0x00;
+}
+
+static void
+bthci_EventChannelSelected(
+       struct rtw_adapter *padapter,
+       u8      EntryNum
+       )
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[3] = "";
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_CHANNEL_SELECT)) {
+               RTPRINT(FIOCTL, IOCTL_BT_EVENT,
+                       ("[BT event], Channel Selected, Ignore to send this event due to event mask page 2\n"));
+               return;
+       }
+
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT|IOCTL_STATE,
+               ("[BT event], Channel Selected, PhyLinkHandle %d\n",
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle));
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_CHANNEL_SELECT;
+       PPacketIrpEvent->Length = 1;
+       PPacketIrpEvent->Data[0] = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle;
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 3);
+}
+
+static void
+bthci_EventDisconnectPhyLinkComplete(
+       struct rtw_adapter *padapter,
+       enum hci_status                         HciStatus,
+       enum hci_status                         Reason,
+       u8              EntryNum
+       )
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[5] = "";
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE)) {
+               RTPRINT(FIOCTL, IOCTL_BT_EVENT,
+                       ("[BT event], Disconnect Physical Link Complete, Ignore to send this event due to event mask page 2\n"));
+               return;
+       }
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT,
+               ("[BT event], Disconnect Physical Link Complete, Status = 0x%x, PLH = 0x%x Reason = 0x%x\n",
+               HciStatus, pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle, Reason));
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE;
+       PPacketIrpEvent->Length = 3;
+       PPacketIrpEvent->Data[0] = HciStatus;
+       PPacketIrpEvent->Data[1] = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle;
+       PPacketIrpEvent->Data[2] = Reason;
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 5);
+}
+
+static void
+bthci_EventPhysicalLinkComplete(
+       struct rtw_adapter *padapter,
+       enum hci_status                         HciStatus,
+       u8              EntryNum,
+       u8              PLHandle
+       )
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+       u8 localBuf[4] = "";
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u8 PL_handle;
+
+       pBtMgnt->bPhyLinkInProgress = false;
+       pBtDbg->dbgHciInfo.hciCmdPhyLinkStatus = HciStatus;
+       if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_PHY_LINK_COMPLETE)) {
+               RTPRINT(FIOCTL, IOCTL_BT_EVENT,
+                       ("[BT event], Physical Link Complete, Ignore to send this event due to event mask page 2\n"));
+               return;
+       }
+
+       if (EntryNum == 0xff) {
+               /*  connection not started yet, just use the input physical link handle to response. */
+               PL_handle = PLHandle;
+       } else {
+               /*  connection is under progress, use the phy link handle we recorded. */
+               PL_handle  = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle;
+               pBTInfo->BtAsocEntry[EntryNum].bNeedPhysLinkCompleteEvent = false;
+       }
+
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Physical Link Complete, Status = 0x%x PhyLinkHandle = 0x%x\n", HciStatus,
+               PL_handle));
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_PHY_LINK_COMPLETE;
+       PPacketIrpEvent->Length = 2;
+
+       PPacketIrpEvent->Data[0] = HciStatus;
+       PPacketIrpEvent->Data[1] = PL_handle;
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 4);
+
+}
+
+static void
+bthci_EventCommandStatus(
+       struct rtw_adapter *padapter,
+       u8              OGF,
+       u16                                     OCF,
+       enum hci_status                         HciStatus
+       )
+{
+
+       u8 localBuf[6] = "";
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u8 Num_Hci_Comm = 0x1;
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT,
+               ("[BT event], CommandStatus, Opcode = 0x%02x%02x, OGF = 0x%x,  OCF = 0x%x, Status = 0x%x, Num_HCI_COMM = 0x%x\n",
+               (HCIOPCODEHIGHT(OCF, OGF)), (HCIOPCODELOW(OCF, OGF)), OGF, OCF, HciStatus, Num_Hci_Comm));
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_COMMAND_STATUS;
+       PPacketIrpEvent->Length = 4;
+       PPacketIrpEvent->Data[0] = HciStatus;   /* current pending */
+       PPacketIrpEvent->Data[1] = Num_Hci_Comm;        /* packet # */
+       PPacketIrpEvent->Data[2] = HCIOPCODELOW(OCF, OGF);
+       PPacketIrpEvent->Data[3] = HCIOPCODEHIGHT(OCF, OGF);
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 6);
+
+}
+
+static void
+bthci_EventLogicalLinkComplete(
+       struct rtw_adapter *padapter,
+       enum hci_status                         HciStatus,
+       u8              PhyLinkHandle,
+       u16                                     LogLinkHandle,
+       u8              LogLinkIndex,
+       u8              EntryNum
+       )
+{
+/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[7] = "";
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_LOGICAL_LINK_COMPLETE)) {
+               RTPRINT(FIOCTL, IOCTL_BT_EVENT,
+                       ("[BT event], Logical Link Complete, Ignore to send this event due to event mask page 2\n"));
+               return;
+       }
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Logical Link Complete, PhyLinkHandle = 0x%x,  LogLinkHandle = 0x%x, Status = 0x%x\n",
+               PhyLinkHandle, LogLinkHandle, HciStatus));
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_LOGICAL_LINK_COMPLETE;
+       PPacketIrpEvent->Length = 5;
+
+       PPacketIrpEvent->Data[0] = HciStatus;/* status code */
+       /* Logical link handle */
+       PPacketIrpEvent->Data[1] = TWOBYTE_LOWBYTE(LogLinkHandle);
+       PPacketIrpEvent->Data[2] = TWOBYTE_HIGHTBYTE(LogLinkHandle);
+       /* Physical link handle */
+       PPacketIrpEvent->Data[3] = TWOBYTE_LOWBYTE(PhyLinkHandle);
+       /* corresponding Tx flow spec ID */
+       if (HciStatus == HCI_STATUS_SUCCESS) {
+               PPacketIrpEvent->Data[4] =
+                       pBTInfo->BtAsocEntry[EntryNum].LogLinkCmdData[LogLinkIndex].Tx_Flow_Spec.Identifier;
+       } else {
+               PPacketIrpEvent->Data[4] = 0x0;
+       }
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 7);
+}
+
+static void
+bthci_EventDisconnectLogicalLinkComplete(
+       struct rtw_adapter *padapter,
+       enum hci_status                         HciStatus,
+       u16                                     LogLinkHandle,
+       enum hci_status                         Reason
+       )
+{
+       u8 localBuf[6] = "";
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE)) {
+               RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Disconnect Logical Link Complete, Ignore to send this event due to event mask page 2\n"));
+               return;
+       }
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Disconnect Logical Link Complete, Status = 0x%x, LLH = 0x%x Reason = 0x%x\n", HciStatus, LogLinkHandle, Reason));
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE;
+       PPacketIrpEvent->Length = 4;
+
+       PPacketIrpEvent->Data[0] = HciStatus;
+       /* Logical link handle */
+       PPacketIrpEvent->Data[1] = TWOBYTE_LOWBYTE(LogLinkHandle);
+       PPacketIrpEvent->Data[2] = TWOBYTE_HIGHTBYTE(LogLinkHandle);
+       /* Disconnect reason */
+       PPacketIrpEvent->Data[3] = Reason;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 6);
+}
+
+static void
+bthci_EventFlushOccurred(
+       struct rtw_adapter *padapter,
+       u16                                     LogLinkHandle
+       )
+{
+       u8 localBuf[4] = "";
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("bthci_EventFlushOccurred(), LLH = 0x%x\n", LogLinkHandle));
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       PPacketIrpEvent->EventCode = HCI_EVENT_FLUSH_OCCRUED;
+       PPacketIrpEvent->Length = 2;
+       /* Logical link handle */
+       PPacketIrpEvent->Data[0] = TWOBYTE_LOWBYTE(LogLinkHandle);
+       PPacketIrpEvent->Data[1] = TWOBYTE_HIGHTBYTE(LogLinkHandle);
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, 4);
+}
+
+static enum hci_status
+bthci_BuildPhysicalLink(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd,
+       u16     OCF
+)
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       u8 EntryNum, PLH;
+
+       /* Send HCI Command status event to AMP. */
+       bthci_EventCommandStatus(padapter,
+                       LINK_CONTROL_COMMANDS,
+                       OCF,
+                       HCI_STATUS_SUCCESS);
+
+       PLH = *((u8 *)pHciCmd->Data);
+
+       /*  Check if resource or bt connection is under progress, if yes, reject the link creation. */
+       if (!bthci_AddEntry(padapter)) {
+               status = HCI_STATUS_CONNECT_RJT_LIMIT_RESOURCE;
+               bthci_EventPhysicalLinkComplete(padapter, status, INVALID_ENTRY_NUM, PLH);
+               return status;
+       }
+
+       EntryNum = pBtMgnt->CurrentConnectEntryNum;
+       pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle = PLH;
+       pBtMgnt->BtCurrentPhyLinkhandle = PLH;
+
+       if (pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.AMPAssocfragment == NULL) {
+               RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Create/Accept PhysicalLink, AMP controller is busy\n"));
+               status = HCI_STATUS_CONTROLLER_BUSY;
+               bthci_EventPhysicalLinkComplete(padapter, status, INVALID_ENTRY_NUM, PLH);
+               return status;
+       }
+
+       /*  Record Key and the info */
+       pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen = (*((u8 *)pHciCmd->Data+1));
+       pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyType = (*((u8 *)pHciCmd->Data+2));
+       memcpy(pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKey,
+               (((u8 *)pHciCmd->Data+3)), pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen);
+       memcpy(pBTInfo->BtAsocEntry[EntryNum].PMK, pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKey, PMK_LEN);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("BuildPhysicalLink, EntryNum = %d, PLH = 0x%x  KeyLen = 0x%x, KeyType = 0x%x\n",
+               EntryNum, pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle,
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen,
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyType));
+       RTPRINT_DATA(FIOCTL, (IOCTL_BT_LOGO|IOCTL_BT_HCICMD), ("BtAMPKey\n"), pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKey,
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtAMPKeyLen);
+       RTPRINT_DATA(FIOCTL, (IOCTL_BT_LOGO|IOCTL_BT_HCICMD), ("PMK\n"), pBTInfo->BtAsocEntry[EntryNum].PMK,
+               PMK_LEN);
+
+       if (OCF == HCI_CREATE_PHYSICAL_LINK) {
+               /* These macros require braces */
+               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_CREATE_PHY_LINK, EntryNum);
+       } else if (OCF == HCI_ACCEPT_PHYSICAL_LINK) {
+               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_ACCEPT_PHY_LINK, EntryNum);
+       }
+
+       return status;
+}
+
+static void
+bthci_BuildLogicalLink(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd,
+       u16 OCF
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTinfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTinfo->BtMgnt;
+       u8 PhyLinkHandle, EntryNum;
+       static u16 AssignLogHandle = 1;
+
+       struct hci_flow_spec    TxFlowSpec;
+       struct hci_flow_spec    RxFlowSpec;
+       u32     MaxSDUSize, ArriveTime, Bandwidth;
+
+       PhyLinkHandle = *((u8 *)pHciCmd->Data);
+
+       EntryNum = bthci_GetCurrentEntryNum(padapter, PhyLinkHandle);
+
+       memcpy(&TxFlowSpec,
+               &pHciCmd->Data[1], sizeof(struct hci_flow_spec));
+       memcpy(&RxFlowSpec,
+               &pHciCmd->Data[17], sizeof(struct hci_flow_spec));
+
+       MaxSDUSize = TxFlowSpec.MaximumSDUSize;
+       ArriveTime = TxFlowSpec.SDUInterArrivalTime;
+
+       if (bthci_CheckLogLinkBehavior(padapter, TxFlowSpec) && bthci_CheckLogLinkBehavior(padapter, RxFlowSpec))
+               Bandwidth = BTTOTALBANDWIDTH;
+       else if (MaxSDUSize == 0xffff && ArriveTime == 0xffffffff)
+               Bandwidth = BTTOTALBANDWIDTH;
+       else
+               Bandwidth = MaxSDUSize*8*1000/(ArriveTime+244);
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD,
+               ("BuildLogicalLink, PhyLinkHandle = 0x%x, MaximumSDUSize = 0x%x, SDUInterArrivalTime = 0x%x, Bandwidth = 0x%x\n",
+               PhyLinkHandle, MaxSDUSize, ArriveTime, Bandwidth));
+
+       if (EntryNum == 0xff) {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Invalid Physical Link handle = 0x%x, status = HCI_STATUS_UNKNOW_CONNECT_ID, return\n", PhyLinkHandle));
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+
+               /* When we receive Create/Accept logical link command, we should send command status event first. */
+               bthci_EventCommandStatus(padapter,
+                       LINK_CONTROL_COMMANDS,
+                       OCF,
+                       status);
+               return;
+       }
+
+       if (!pBtMgnt->bLogLinkInProgress) {
+               if (bthci_PhyLinkConnectionInProgress(padapter, PhyLinkHandle)) {
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Physical link connection in progress, status = HCI_STATUS_CMD_DISALLOW, return\n"));
+                       status = HCI_STATUS_CMD_DISALLOW;
+
+                       pBtMgnt->bPhyLinkInProgressStartLL = true;
+                       /* When we receive Create/Accept logical link command, we should send command status event first. */
+                       bthci_EventCommandStatus(padapter,
+                               LINK_CONTROL_COMMANDS,
+                               OCF,
+                               status);
+
+                       return;
+               }
+
+               if (Bandwidth > BTTOTALBANDWIDTH) {
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("status = HCI_STATUS_QOS_REJECT, Bandwidth = 0x%x, return\n", Bandwidth));
+                       status = HCI_STATUS_QOS_REJECT;
+
+                       /* When we receive Create/Accept logical link command, we should send command status event first. */
+                       bthci_EventCommandStatus(padapter,
+                               LINK_CONTROL_COMMANDS,
+                               OCF,
+                               status);
+               } else {
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("status = HCI_STATUS_SUCCESS\n"));
+                       status = HCI_STATUS_SUCCESS;
+
+                       /* When we receive Create/Accept logical link command, we should send command status event first. */
+                       bthci_EventCommandStatus(padapter,
+                               LINK_CONTROL_COMMANDS,
+                               OCF,
+                               status);
+
+               }
+
+               if (pBTinfo->BtAsocEntry[EntryNum].BtCurrentState != HCI_STATE_CONNECTED) {
+                       bthci_EventLogicalLinkComplete(padapter,
+                               HCI_STATUS_CMD_DISALLOW, 0, 0, 0, EntryNum);
+               } else {
+                       u8 i, find = 0;
+
+                       pBtMgnt->bLogLinkInProgress = true;
+
+                       /*  find an unused logical link index and copy the data */
+                       for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) {
+                               if (pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtLogLinkhandle == 0) {
+                                       enum hci_status LogCompEventstatus = HCI_STATUS_SUCCESS;
+
+                                       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtPhyLinkhandle = *((u8 *)pHciCmd->Data);
+                                       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtLogLinkhandle = AssignLogHandle;
+                                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("BuildLogicalLink, EntryNum = %d, physical link handle = 0x%x, logical link handle = 0x%x\n",
+                                               EntryNum, pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle,
+                                                                 pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtLogLinkhandle));
+                                       memcpy(&pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].Tx_Flow_Spec,
+                                               &TxFlowSpec, sizeof(struct hci_flow_spec));
+                                       memcpy(&pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].Rx_Flow_Spec,
+                                               &RxFlowSpec, sizeof(struct hci_flow_spec));
+
+                                       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].bLLCompleteEventIsSet = false;
+
+                                       if (pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].bLLCancelCMDIsSetandComplete)
+                                               LogCompEventstatus = HCI_STATUS_UNKNOW_CONNECT_ID;
+                                       bthci_EventLogicalLinkComplete(padapter,
+                                               LogCompEventstatus,
+                                               pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtPhyLinkhandle,
+                                               pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].BtLogLinkhandle, i, EntryNum);
+
+                                       pBTinfo->BtAsocEntry[EntryNum].LogLinkCmdData[i].bLLCompleteEventIsSet = true;
+
+                                       find = 1;
+                                       pBtMgnt->BtCurrentLogLinkhandle = AssignLogHandle;
+                                       AssignLogHandle++;
+                                       break;
+                               }
+                       }
+
+                       if (!find) {
+                               bthci_EventLogicalLinkComplete(padapter,
+                                       HCI_STATUS_CONNECT_RJT_LIMIT_RESOURCE, 0, 0, 0, EntryNum);
+                       }
+                       pBtMgnt->bLogLinkInProgress = false;
+               }
+       } else {
+               bthci_EventLogicalLinkComplete(padapter,
+                       HCI_STATUS_CONTROLLER_BUSY, 0, 0, 0, EntryNum);
+       }
+
+}
+
+static void
+bthci_StartBeaconAndConnect(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd,
+       u8 CurrentAssocNum
+       )
+{
+/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("StartBeaconAndConnect, CurrentAssocNum =%d, AMPRole =%d\n",
+               CurrentAssocNum,
+               pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole));
+
+       if (!pBtMgnt->CheckChnlIsSuit) {
+               bthci_EventPhysicalLinkComplete(padapter, HCI_STATUS_CONNECT_REJ_NOT_SUIT_CHNL_FOUND, CurrentAssocNum, INVALID_PL_HANDLE);
+               bthci_RemoveEntryByEntryNum(padapter, CurrentAssocNum);
+               return;
+       }
+
+       if (pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole == AMP_BTAP_CREATOR) {
+               rsprintf((char *)pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsidBuf, 32, "AMP-%02x-%02x-%02x-%02x-%02x-%02x",
+               padapter->eeprompriv.mac_addr[0],
+               padapter->eeprompriv.mac_addr[1],
+               padapter->eeprompriv.mac_addr[2],
+               padapter->eeprompriv.mac_addr[3],
+               padapter->eeprompriv.mac_addr[4],
+               padapter->eeprompriv.mac_addr[5]);
+       } else if (pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole == AMP_BTAP_JOINER) {
+               rsprintf((char *)pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsidBuf, 32, "AMP-%02x-%02x-%02x-%02x-%02x-%02x",
+               pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[0],
+               pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[1],
+               pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[2],
+               pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[3],
+               pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[4],
+               pBTInfo->BtAsocEntry[CurrentAssocNum].BTRemoteMACAddr[5]);
+       }
+
+       FillOctetString(pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsid, pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsidBuf, 21);
+       pBTInfo->BtAsocEntry[CurrentAssocNum].BTSsid.Length = 21;
+
+       /* To avoid set the start ap or connect twice, or the original connection will be disconnected. */
+       if (!pBtMgnt->bBTConnectInProgress) {
+               pBtMgnt->bBTConnectInProgress = true;
+               RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress ON!!\n"));
+               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_STARTING, STATE_CMD_MAC_START_COMPLETE, CurrentAssocNum);
+
+               /*  20100325 Joseph: Check RF ON/OFF. */
+               /*  If RF OFF, it reschedule connecting operation after 50ms. */
+               if (!bthci_CheckRfStateBeforeConnect(padapter))
+                       return;
+
+               if (pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole == AMP_BTAP_CREATOR) {
+                       /* These macros need braces */
+                       BTHCI_SM_WITH_INFO(padapter, HCI_STATE_CONNECTING, STATE_CMD_MAC_CONNECT_COMPLETE, CurrentAssocNum);
+               } else if (pBTInfo->BtAsocEntry[CurrentAssocNum].AMPRole == AMP_BTAP_JOINER) {
+                       bthci_ResponderStartToScan(padapter);
+               }
+       }
+       RT_PRINT_STR(_module_rtl871x_mlme_c_, _drv_notice_,
+                    "StartBeaconAndConnect, SSID:\n",
+                    pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].BTSsid.Octet,
+                    pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].BTSsid.Length);
+}
+
+static void bthci_ResetBtMgnt(struct bt_mgnt *pBtMgnt)
+{
+       pBtMgnt->BtOperationOn = false;
+       pBtMgnt->bBTConnectInProgress = false;
+       pBtMgnt->bLogLinkInProgress = false;
+       pBtMgnt->bPhyLinkInProgress = false;
+       pBtMgnt->bPhyLinkInProgressStartLL = false;
+       pBtMgnt->DisconnectEntryNum = 0xff;
+       pBtMgnt->bStartSendSupervisionPkt = false;
+       pBtMgnt->JoinerNeedSendAuth = false;
+       pBtMgnt->CurrentBTConnectionCnt = 0;
+       pBtMgnt->BTCurrentConnectType = BT_DISCONNECT;
+       pBtMgnt->BTReceiveConnectPkt = BT_DISCONNECT;
+       pBtMgnt->BTAuthCount = 0;
+       pBtMgnt->btLogoTest = 0;
+}
+
+static void bthci_ResetBtHciInfo(struct bt_hci_info *pBtHciInfo)
+{
+       pBtHciInfo->BTEventMask = 0;
+       pBtHciInfo->BTEventMaskPage2 = 0;
+       pBtHciInfo->ConnAcceptTimeout =  10000;
+       pBtHciInfo->PageTimeout  =  0x30;
+       pBtHciInfo->LocationDomainAware = 0x0;
+       pBtHciInfo->LocationDomain = 0x5858;
+       pBtHciInfo->LocationDomainOptions = 0x58;
+       pBtHciInfo->LocationOptions = 0x0;
+       pBtHciInfo->FlowControlMode = 0x1;      /*  0:Packet based data flow control mode(BR/EDR), 1: Data block based data flow control mode(AMP). */
+
+       pBtHciInfo->enFlush_LLH = 0;
+       pBtHciInfo->FLTO_LLH = 0;
+
+       /* Test command only */
+       pBtHciInfo->bTestIsEnd = true;
+       pBtHciInfo->bInTestMode = false;
+       pBtHciInfo->bTestNeedReport = false;
+       pBtHciInfo->TestScenario = 0xff;
+       pBtHciInfo->TestReportInterval = 0x01;
+       pBtHciInfo->TestCtrType = 0x5d;
+       pBtHciInfo->TestEventType = 0x00;
+       pBtHciInfo->TestNumOfFrame = 0;
+       pBtHciInfo->TestNumOfErrFrame = 0;
+       pBtHciInfo->TestNumOfBits = 0;
+       pBtHciInfo->TestNumOfErrBits = 0;
+}
+
+static void bthci_ResetBtSec(struct rtw_adapter *padapter, struct bt_security *pBtSec)
+{
+/*PMGNT_INFO   pMgntInfo = &padapter->MgntInfo; */
+
+       /*  Set BT used HW or SW encrypt !! */
+       if (GET_HAL_DATA(padapter)->bBTMode)
+               pBtSec->bUsedHwEncrypt = true;
+       else
+               pBtSec->bUsedHwEncrypt = false;
+       RT_TRACE(_module_rtl871x_security_c_, _drv_info_, ("%s: bUsedHwEncrypt =%d\n", __func__, pBtSec->bUsedHwEncrypt));
+
+       pBtSec->RSNIE.Octet = pBtSec->RSNIEBuf;
+}
+
+static void bthci_ResetBtExtInfo(struct bt_mgnt *pBtMgnt)
+{
+       u8 i;
+
+       for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) {
+               pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle = 0;
+               pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = 0;
+               pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = 0;
+               pBtMgnt->ExtConfig.linkInfo[i].BTProfile = BT_PROFILE_NONE;
+               pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec = BT_SPEC_2_1_EDR;
+               pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI = 0;
+               pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile = BT_PROFILE_NONE;
+               pBtMgnt->ExtConfig.linkInfo[i].linkRole = BT_LINK_MASTER;
+       }
+
+       pBtMgnt->ExtConfig.CurrentConnectHandle = 0;
+       pBtMgnt->ExtConfig.CurrentIncomingTrafficMode = 0;
+       pBtMgnt->ExtConfig.CurrentOutgoingTrafficMode = 0;
+       pBtMgnt->ExtConfig.MIN_BT_RSSI = 0;
+       pBtMgnt->ExtConfig.NumberOfHandle = 0;
+       pBtMgnt->ExtConfig.NumberOfSCO = 0;
+       pBtMgnt->ExtConfig.CurrentBTStatus = 0;
+       pBtMgnt->ExtConfig.HCIExtensionVer = 0;
+
+       pBtMgnt->ExtConfig.bManualControl = false;
+       pBtMgnt->ExtConfig.bBTBusy = false;
+       pBtMgnt->ExtConfig.bBTA2DPBusy = false;
+}
+
+static enum hci_status bthci_CmdReset(struct rtw_adapter *_padapter, u8 bNeedSendEvent)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct rtw_adapter *padapter;
+/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_hci_info *pBtHciInfo;
+       struct bt_security *pBtSec;
+       struct bt_dgb *pBtDbg;
+       u8 i;
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_CmdReset()\n"));
+
+       padapter = GetDefaultAdapter(_padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtHciInfo = &pBTInfo->BtHciInfo;
+       pBtSec = &pBTInfo->BtSec;
+       pBtDbg = &pBTInfo->BtDbg;
+
+       pBTInfo->padapter = padapter;
+
+       for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++)
+               bthci_ResetEntry(padapter, i);
+
+       bthci_ResetBtMgnt(pBtMgnt);
+       bthci_ResetBtHciInfo(pBtHciInfo);
+       bthci_ResetBtSec(padapter, pBtSec);
+
+       pBtMgnt->BTChannel = BT_Default_Chnl;
+       pBtMgnt->CheckChnlIsSuit = true;
+
+       pBTInfo->BTBeaconTmrOn = false;
+
+       pBtMgnt->bCreateSpportQos = true;
+
+       del_timer_sync(&pBTInfo->BTHCIDiscardAclDataTimer);
+       del_timer_sync(&pBTInfo->BTBeaconTimer);
+
+       HALBT_SetRtsCtsNoLenLimit(padapter);
+       /*  */
+       /*  Maybe we need to take care Group != AES case !! */
+       /*  now we Pairwise and Group all used AES !! */
+
+       bthci_ResetBtExtInfo(pBtMgnt);
+
+       /* send command complete event here when all data are received. */
+       if (bNeedSendEvent) {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_SET_EVENT_MASK_COMMAND,
+                       HCI_RESET,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWriteRemoteAMPAssoc(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+       u8 CurrentAssocNum;
+       u8 PhyLinkHandle;
+
+       pBtDbg->dbgHciInfo.hciCmdCntWriteRemoteAmpAssoc++;
+       PhyLinkHandle = *((u8 *)pHciCmd->Data);
+       CurrentAssocNum = bthci_GetCurrentEntryNum(padapter, PhyLinkHandle);
+
+       if (CurrentAssocNum == 0xff) {
+               RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("WriteRemoteAMPAssoc, No such Handle in the Entry\n"));
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+               bthci_EventWriteRemoteAmpAssoc(padapter, status, PhyLinkHandle);
+               return status;
+       }
+
+       if (pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocfragment == NULL) {
+               RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("WriteRemoteAMPAssoc, AMP controller is busy\n"));
+               status = HCI_STATUS_CONTROLLER_BUSY;
+               bthci_EventWriteRemoteAmpAssoc(padapter, status, PhyLinkHandle);
+               return status;
+       }
+
+       pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.BtPhyLinkhandle = PhyLinkHandle;/* u8 *)pHciCmd->Data); */
+       pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.LenSoFar = *((u16 *)((u8 *)pHciCmd->Data+1));
+       pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen = *((u16 *)((u8 *)pHciCmd->Data+3));
+
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("WriteRemoteAMPAssoc, LenSoFar = 0x%x, AssocRemLen = 0x%x\n",
+               pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.LenSoFar,
+               pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen));
+
+       RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO),
+                    ("WriteRemoteAMPAssoc fragment \n"),
+                    pHciCmd->Data,
+                    pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen+5);
+       if ((pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen) > MAX_AMP_ASSOC_FRAG_LEN) {
+               memcpy(((u8 *)pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocfragment+(pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.LenSoFar*(sizeof(u8)))),
+                       (u8 *)pHciCmd->Data+5,
+                       MAX_AMP_ASSOC_FRAG_LEN);
+       } else {
+               memcpy((u8 *)(pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocfragment)+(pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.LenSoFar*(sizeof(u8))),
+                       ((u8 *)pHciCmd->Data+5),
+                       (pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen));
+
+               RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), "WriteRemoteAMPAssoc :\n",
+                       pHciCmd->Data+5, pBTInfo->BtAsocEntry[CurrentAssocNum].AmpAsocCmdData.AMPAssocRemLen);
+
+               if (!bthci_GetAssocInfo(padapter, CurrentAssocNum))
+                       status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE;
+
+               bthci_EventWriteRemoteAmpAssoc(padapter, status, PhyLinkHandle);
+
+               bthci_StartBeaconAndConnect(padapter, pHciCmd, CurrentAssocNum);
+       }
+
+       return status;
+}
+
+/* 7.3.13 */
+static enum hci_status bthci_CmdReadConnectionAcceptTimeout(struct rtw_adapter *padapter)
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+/*PMGNT_INFO           pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[8] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp;
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_READ_CONNECTION_ACCEPT_TIMEOUT,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       pu2Temp = (u16 *)&pRetPar[1];           /*  Conn_Accept_Timeout */
+       *pu2Temp = pBtHciInfo->ConnAcceptTimeout;
+       len += 3;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+/* 7.3.3 */
+static enum hci_status
+bthci_CmdSetEventFilter(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+
+       return status;
+}
+
+/* 7.3.14 */
+static enum hci_status
+bthci_CmdWriteConnectionAcceptTimeout(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u16     *pu2Temp;
+       u8 localBuf[6] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       pu2Temp = (u16 *)&pHciCmd->Data[0];
+       pBtHciInfo->ConnAcceptTimeout = *pu2Temp;
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("ConnAcceptTimeout = 0x%x",
+               pBtHciInfo->ConnAcceptTimeout));
+
+       /* send command complete event here when all data are received. */
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       len += 1;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdReadPageTimeout(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[8] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp;
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_READ_PAGE_TIMEOUT,
+               status);
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Read PageTimeout = 0x%x\n", pBtHciInfo->PageTimeout));
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       pu2Temp = (u16 *)&pRetPar[1];           /*  Page_Timeout */
+       *pu2Temp = pBtHciInfo->PageTimeout;
+       len += 3;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWritePageTimeout(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u16     *pu2Temp;
+
+       pu2Temp = (u16 *)&pHciCmd->Data[0];
+       pBtHciInfo->PageTimeout = *pu2Temp;
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Write PageTimeout = 0x%x\n",
+               pBtHciInfo->PageTimeout));
+
+       /* send command complete event here when all data are received. */
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_SET_EVENT_MASK_COMMAND,
+                       HCI_WRITE_PAGE_TIMEOUT,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdReadLinkSupervisionTimeout(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTinfo = GET_BT_INFO(padapter);
+       u8 physicalLinkHandle, EntryNum;
+
+       physicalLinkHandle = *((u8 *)pHciCmd->Data);
+
+       EntryNum = bthci_GetCurrentEntryNum(padapter, physicalLinkHandle);
+
+       if (EntryNum == 0xff) {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLinkSupervisionTimeout, No such Handle in the Entry\n"));
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+               return status;
+       }
+
+       if (pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle != physicalLinkHandle)
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+
+       {
+               u8 localBuf[10] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+               u16 *pu2Temp;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_SET_EVENT_MASK_COMMAND,
+                       HCI_READ_LINK_SUPERVISION_TIMEOUT,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;
+               pRetPar[1] = pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle;
+               pRetPar[2] = 0;
+               pu2Temp = (u16 *)&pRetPar[3];           /*  Conn_Accept_Timeout */
+               *pu2Temp = pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.LinkSuperversionTimeout;
+               len += 5;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWriteLinkSupervisionTimeout(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTinfo = GET_BT_INFO(padapter);
+       u8 physicalLinkHandle, EntryNum;
+
+       physicalLinkHandle = *((u8 *)pHciCmd->Data);
+
+       EntryNum = bthci_GetCurrentEntryNum(padapter, physicalLinkHandle);
+
+       if (EntryNum == 0xff) {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("WriteLinkSupervisionTimeout, No such Handle in the Entry\n"));
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+       } else {
+               if (pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle != physicalLinkHandle) {
+                       status = HCI_STATUS_UNKNOW_CONNECT_ID;
+               } else {
+                       pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.LinkSuperversionTimeout = *((u16 *)(((u8 *)pHciCmd->Data)+2));
+                       RTPRINT(FIOCTL, IOCTL_STATE, ("BT Write LinkSuperversionTimeout[%d] = 0x%x\n",
+                               EntryNum, pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.LinkSuperversionTimeout));
+               }
+       }
+
+       {
+               u8 localBuf[8] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_SET_EVENT_MASK_COMMAND,
+                       HCI_WRITE_LINK_SUPERVISION_TIMEOUT,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;
+               pRetPar[1] = pBTinfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle;
+               pRetPar[2] = 0;
+               len += 3;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdEnhancedFlush(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTinfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTinfo->BtHciInfo;
+       u16             logicHandle;
+       u8 Packet_Type;
+
+       logicHandle = *((u16 *)&pHciCmd->Data[0]);
+       Packet_Type = pHciCmd->Data[2];
+
+       if (Packet_Type != 0)
+               status = HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE;
+       else
+               pBtHciInfo->enFlush_LLH = logicHandle;
+
+       if (bthci_DiscardTxPackets(padapter, pBtHciInfo->enFlush_LLH))
+               bthci_EventFlushOccurred(padapter, pBtHciInfo->enFlush_LLH);
+
+       /*  should send command status event */
+       bthci_EventCommandStatus(padapter,
+                       OGF_SET_EVENT_MASK_COMMAND,
+                       HCI_ENHANCED_FLUSH,
+                       status);
+
+       if (pBtHciInfo->enFlush_LLH) {
+               bthci_EventEnhancedFlushComplete(padapter, pBtHciInfo->enFlush_LLH);
+               pBtHciInfo->enFlush_LLH = 0;
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdReadLogicalLinkAcceptTimeout(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+/*PMGNT_INFO           pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[8] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp;
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;
+
+       pu2Temp = (u16 *)&pRetPar[1];           /*  Conn_Accept_Timeout */
+       *pu2Temp = pBtHciInfo->LogicalAcceptTimeout;
+       len += 3;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWriteLogicalLinkAcceptTimeout(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+/*PMGNT_INFO           pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[6] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       pBtHciInfo->LogicalAcceptTimeout = *((u16 *)pHciCmd->Data);
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;
+
+       len += 1;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       return status;
+}
+
+static enum hci_status
+bthci_CmdSetEventMask(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+/*PMGNT_INFO           pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 *pu8Temp;
+       u8 localBuf[6] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       pu8Temp = (u8 *)&pHciCmd->Data[0];
+       pBtHciInfo->BTEventMask = *pu8Temp;
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("BTEventMask = 0x%"i64fmt"x\n",
+               pBtHciInfo->BTEventMask));
+
+       /* send command complete event here when all data are received. */
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_SET_EVENT_MASK,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       len += 1;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+/*  7.3.69 */
+static enum hci_status
+bthci_CmdSetEventMaskPage2(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 *pu8Temp;
+       u8 localBuf[6] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       pu8Temp = (u8 *)&pHciCmd->Data[0];
+       pBtHciInfo->BTEventMaskPage2 = *pu8Temp;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("BTEventMaskPage2 = 0x%"i64fmt"x\n",
+               pBtHciInfo->BTEventMaskPage2));
+
+       /* send command complete event here when all data are received. */
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_SET_EVENT_MASK_PAGE_2,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       len += 1;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdReadLocationData(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[12] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp;
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_READ_LOCATION_DATA,
+               status);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DomainAware = 0x%x\n", pBtHciInfo->LocationDomainAware));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Domain = 0x%x\n", pBtHciInfo->LocationDomain));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DomainOptions = 0x%x\n", pBtHciInfo->LocationDomainOptions));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Options = 0x%x\n", pBtHciInfo->LocationOptions));
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;
+
+       pRetPar[1] = pBtHciInfo->LocationDomainAware;   /* 0x0;  Location_Domain_Aware */
+       pu2Temp = (u16 *)&pRetPar[2];                                   /*  Location_Domain */
+       *pu2Temp = pBtHciInfo->LocationDomain;          /* 0x5858; */
+       pRetPar[4] = pBtHciInfo->LocationDomainOptions; /* 0x58;        Location_Domain_Options */
+       pRetPar[5] = pBtHciInfo->LocationOptions;               /* 0x0; Location_Options */
+       len += 6;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWriteLocationData(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u16     *pu2Temp;
+       u8 localBuf[6] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       pBtHciInfo->LocationDomainAware = pHciCmd->Data[0];
+       pu2Temp = (u16 *)&pHciCmd->Data[1];
+       pBtHciInfo->LocationDomain = *pu2Temp;
+       pBtHciInfo->LocationDomainOptions = pHciCmd->Data[3];
+       pBtHciInfo->LocationOptions = pHciCmd->Data[4];
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DomainAware = 0x%x\n", pBtHciInfo->LocationDomainAware));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Domain = 0x%x\n", pBtHciInfo->LocationDomain));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DomainOptions = 0x%x\n", pBtHciInfo->LocationDomainOptions));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Options = 0x%x\n", pBtHciInfo->LocationOptions));
+
+       /* send command complete event here when all data are received. */
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_WRITE_LOCATION_DATA,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       len += 1;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdReadFlowControlMode(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[7] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_READ_FLOW_CONTROL_MODE,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;
+       pRetPar[1] = pBtHciInfo->FlowControlMode;       /*  Flow Control Mode */
+       len += 2;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWriteFlowControlMode(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[6] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       pBtHciInfo->FlowControlMode = pHciCmd->Data[0];
+
+       /* send command complete event here when all data are received. */
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_WRITE_FLOW_CONTROL_MODE,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       len += 1;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdReadBestEffortFlushTimeout(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTinfo = GET_BT_INFO(padapter);
+       u16 i, j, logicHandle;
+       u32 BestEffortFlushTimeout = 0xffffffff;
+       u8 find = 0;
+
+       logicHandle = *((u16 *)pHciCmd->Data);
+       /*  find an matched logical link index and copy the data */
+       for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) {
+               for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) {
+                       if (pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle == logicHandle) {
+                               BestEffortFlushTimeout = pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BestEffortFlushTimeout;
+                               find = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (!find)
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+
+       {
+               u8 localBuf[10] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+               u32 *pu4Temp;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_SET_EVENT_MASK_COMMAND,
+                       HCI_READ_BEST_EFFORT_FLUSH_TIMEOUT,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;
+               pu4Temp = (u32 *)&pRetPar[1];   /*  Best_Effort_Flush_Timeout */
+               *pu4Temp = BestEffortFlushTimeout;
+               len += 5;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWriteBestEffortFlushTimeout(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTinfo = GET_BT_INFO(padapter);
+       u16 i, j, logicHandle;
+       u32 BestEffortFlushTimeout = 0xffffffff;
+       u8 find = 0;
+
+       logicHandle = *((u16 *)pHciCmd->Data);
+       BestEffortFlushTimeout = *((u32 *)(pHciCmd->Data+1));
+
+       /*  find an matched logical link index and copy the data */
+       for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) {
+               for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) {
+                       if (pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle == logicHandle) {
+                               pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BestEffortFlushTimeout = BestEffortFlushTimeout;
+                               find = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (!find)
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_SET_EVENT_MASK_COMMAND,
+                       HCI_WRITE_BEST_EFFORT_FLUSH_TIMEOUT,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+       return status;
+}
+
+static enum hci_status
+bthci_CmdShortRangeMode(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       u8 PhyLinkHandle, EntryNum, ShortRangeMode;
+
+       PhyLinkHandle = pHciCmd->Data[0];
+       ShortRangeMode = pHciCmd->Data[1];
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("PLH = 0x%x, Short_Range_Mode = 0x%x\n", PhyLinkHandle, ShortRangeMode));
+
+       EntryNum = bthci_GetCurrentEntryNum(padapter, PhyLinkHandle);
+       if (EntryNum != 0xff) {
+               pBTInfo->BtAsocEntry[EntryNum].ShortRangeMode = ShortRangeMode;
+       } else {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("No such PLH(0x%x)\n", PhyLinkHandle));
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+       }
+
+       bthci_EventCommandStatus(padapter,
+                       OGF_SET_EVENT_MASK_COMMAND,
+                       HCI_SHORT_RANGE_MODE,
+                       status);
+
+       bthci_EventShortRangeModeChangeComplete(padapter, status, ShortRangeMode, EntryNum);
+
+       return status;
+}
+
+static enum hci_status bthci_CmdReadLocalSupportedCommands(struct rtw_adapter *padapter)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar, *pSupportedCmds;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       /*  send command complete event here when all data are received. */
+       PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_INFORMATIONAL_PARAMETERS,
+               HCI_READ_LOCAL_SUPPORTED_COMMANDS,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       len += 1;
+       pSupportedCmds = &pRetPar[1];
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[5]= 0xc0\nBit [6]= Set Event Mask, [7]= Reset\n"));
+       pSupportedCmds[5] = 0xc0;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[6]= 0x01\nBit [0]= Set Event Filter\n"));
+       pSupportedCmds[6] = 0x01;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[7]= 0x0c\nBit [2]= Read Connection Accept Timeout, [3]= Write Connection Accept Timeout\n"));
+       pSupportedCmds[7] = 0x0c;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[10]= 0x80\nBit [7]= Host Number Of Completed Packets\n"));
+       pSupportedCmds[10] = 0x80;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[11]= 0x03\nBit [0]= Read Link Supervision Timeout, [1]= Write Link Supervision Timeout\n"));
+       pSupportedCmds[11] = 0x03;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[14]= 0xa8\nBit [3]= Read Local Version Information, [5]= Read Local Supported Features, [7]= Read Buffer Size\n"));
+       pSupportedCmds[14] = 0xa8;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[15]= 0x1c\nBit [2]= Read Failed Contact Count, [3]= Reset Failed Contact Count, [4]= Get Link Quality\n"));
+       pSupportedCmds[15] = 0x1c;
+       /* pSupportedCmds[16] = 0x04; */
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[19]= 0x40\nBit [6]= Enhanced Flush\n"));
+       pSupportedCmds[19] = 0x40;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[21]= 0xff\nBit [0]= Create Physical Link, [1]= Accept Physical Link, [2]= Disconnect Physical Link, [3]= Create Logical Link\n"));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("     [4]= Accept Logical Link, [5]= Disconnect Logical Link, [6]= Logical Link Cancel, [7]= Flow Spec Modify\n"));
+       pSupportedCmds[21] = 0xff;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[22]= 0xff\nBit [0]= Read Logical Link Accept Timeout, [1]= Write Logical Link Accept Timeout, [2]= Set Event Mask Page 2, [3]= Read Location Data\n"));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("     [4]= Write Location Data, [5]= Read Local AMP Info, [6]= Read Local AMP_ASSOC, [7]= Write Remote AMP_ASSOC\n"));
+       pSupportedCmds[22] = 0xff;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[23]= 0x07\nBit [0]= Read Flow Control Mode, [1]= Write Flow Control Mode, [2]= Read Data Block Size\n"));
+       pSupportedCmds[23] = 0x07;
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD|IOCTL_BT_LOGO), ("Octet[24]= 0x1c\nBit [2]= Read Best Effort Flush Timeout, [3]= Write Best Effort Flush Timeout, [4]= Short Range Mode\n"));
+       pSupportedCmds[24] = 0x1c;
+       len += 64;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status bthci_CmdReadLocalSupportedFeatures(struct rtw_adapter *padapter)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       /* send command complete event here when all data are received. */
+       PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_INFORMATIONAL_PARAMETERS,
+               HCI_READ_LOCAL_SUPPORTED_FEATURES,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       len += 9;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       return status;
+}
+
+static enum hci_status bthci_CmdReadLocalAMPAssoc(struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+       u8 PhyLinkHandle, EntryNum;
+
+       pBtDbg->dbgHciInfo.hciCmdCntReadLocalAmpAssoc++;
+       PhyLinkHandle = *((u8 *)pHciCmd->Data);
+       EntryNum = bthci_GetCurrentEntryNum(padapter, PhyLinkHandle);
+
+       if ((EntryNum == 0xff) && PhyLinkHandle != 0) {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLocalAMPAssoc, EntryNum = %d  !!!!!, physical link handle = 0x%x\n",
+               EntryNum, PhyLinkHandle));
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+       } else if (pBtMgnt->bPhyLinkInProgressStartLL) {
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+               pBtMgnt->bPhyLinkInProgressStartLL = false;
+       } else {
+               pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.BtPhyLinkhandle = *((u8 *)pHciCmd->Data);
+               pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar = *((u16 *)((u8 *)pHciCmd->Data+1));
+               pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.MaxRemoteASSOCLen = *((u16 *)((u8 *)pHciCmd->Data+3));
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("ReadLocalAMPAssoc, LenSoFar =%d, MaxRemoteASSOCLen =%d\n",
+                       pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar,
+                       pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.MaxRemoteASSOCLen));
+       }
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLocalAMPAssoc, EntryNum = %d  !!!!!, physical link handle = 0x%x, LengthSoFar = %x  \n",
+               EntryNum, PhyLinkHandle, pBTInfo->BtAsocEntry[EntryNum].AmpAsocCmdData.LenSoFar));
+
+       /* send command complete event here when all data are received. */
+       {
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               /* PVOID buffer = padapter->IrpHCILocalbuf.Ptr; */
+               u8 localBuf[TmpLocalBufSize] = "";
+               u16     *pRemainLen;
+               u32     totalLen = 0;
+               u16     typeLen = 0, remainLen = 0, ret_index = 0;
+               u8 *pRetPar;
+
+               PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+               /* PPacketIrpEvent = (struct packet_irp_hcievent_data *)(buffer); */
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               totalLen += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_STATUS_PARAMETERS,
+                       HCI_READ_LOCAL_AMP_ASSOC,
+                       status);
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLocalAMPAssoc, Remaining_Len =%d  \n", remainLen));
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[totalLen];
+               pRetPar[0] = status;            /* status */
+               pRetPar[1] = *((u8 *)pHciCmd->Data);
+               pRemainLen = (u16 *)&pRetPar[2];        /* AMP_ASSOC_Remaining_Length */
+               totalLen += 4;  /* 0]~[3] */
+               ret_index = 4;
+
+               typeLen = bthci_AssocMACAddr(padapter, &pRetPar[ret_index]);
+               totalLen += typeLen;
+               remainLen += typeLen;
+               ret_index += typeLen;
+               typeLen = bthci_AssocPreferredChannelList(padapter, &pRetPar[ret_index], EntryNum);
+               totalLen += typeLen;
+               remainLen += typeLen;
+               ret_index += typeLen;
+               typeLen = bthci_PALCapabilities(padapter, &pRetPar[ret_index]);
+               totalLen += typeLen;
+               remainLen += typeLen;
+               ret_index += typeLen;
+               typeLen = bthci_AssocPALVer(padapter, &pRetPar[ret_index]);
+               totalLen += typeLen;
+               remainLen += typeLen;
+               PPacketIrpEvent->Length = (u8)totalLen;
+               *pRemainLen = remainLen;        /*  AMP_ASSOC_Remaining_Length */
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("ReadLocalAMPAssoc, Remaining_Len =%d  \n", remainLen));
+               RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("AMP_ASSOC_fragment : \n"), PPacketIrpEvent->Data, totalLen);
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, totalLen+2);
+       }
+
+       return status;
+}
+
+static enum hci_status bthci_CmdReadFailedContactCounter(struct rtw_adapter *padapter,
+                      struct packet_irp_hcicmd_data *pHciCmd)
+{
+
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 handle;
+
+       handle = *((u16 *)pHciCmd->Data);
+       /* send command complete event here when all data are received. */
+       PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_STATUS_PARAMETERS,
+               HCI_READ_FAILED_CONTACT_COUNTER,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       pRetPar[1] = TWOBYTE_LOWBYTE(handle);
+       pRetPar[2] = TWOBYTE_HIGHTBYTE(handle);
+       pRetPar[3] = TWOBYTE_LOWBYTE(pBtHciInfo->FailContactCount);
+       pRetPar[4] = TWOBYTE_HIGHTBYTE(pBtHciInfo->FailContactCount);
+       len += 5;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdResetFailedContactCounter(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status         status = HCI_STATUS_SUCCESS;
+/*PMGNT_INFO           pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u16             handle;
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+       handle = *((u16 *)pHciCmd->Data);
+       pBtHciInfo->FailContactCount = 0;
+
+       /* send command complete event here when all data are received. */
+       PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+       /* PPacketIrpEvent = (struct packet_irp_hcievent_data *)(buffer); */
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_STATUS_PARAMETERS,
+               HCI_RESET_FAILED_CONTACT_COUNTER,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       pRetPar[1] = TWOBYTE_LOWBYTE(handle);
+       pRetPar[2] = TWOBYTE_HIGHTBYTE(handle);
+       len += 3;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       return status;
+}
+
+/*  */
+/*  BT 3.0+HS [Vol 2] 7.4.1 */
+/*  */
+static enum hci_status
+bthci_CmdReadLocalVersionInformation(
+       struct rtw_adapter *padapter
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       /* send command complete event here when all data are received. */
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp;
+
+       PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_INFORMATIONAL_PARAMETERS,
+               HCI_READ_LOCAL_VERSION_INFORMATION,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       pRetPar[1] = 0x05;                      /*  HCI_Version */
+       pu2Temp = (u16 *)&pRetPar[2];           /*  HCI_Revision */
+       *pu2Temp = 0x0001;
+       pRetPar[4] = 0x05;                      /*  LMP/PAL_Version */
+       pu2Temp = (u16 *)&pRetPar[5];           /*  Manufacturer_Name */
+       *pu2Temp = 0x005d;
+       pu2Temp = (u16 *)&pRetPar[7];           /*  LMP/PAL_Subversion */
+       *pu2Temp = 0x0001;
+       len += 9;
+       PPacketIrpEvent->Length = len;
+
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("LOCAL_VERSION_INFORMATION\n"));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("Status  %x\n", status));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("HCI_Version = 0x05\n"));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("HCI_Revision = 0x0001\n"));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("LMP/PAL_Version = 0x05\n"));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("Manufacturer_Name = 0x0001\n"));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("LMP/PAL_Subversion = 0x0001\n"));
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+/* 7.4.7 */
+static enum hci_status bthci_CmdReadDataBlockSize(struct rtw_adapter *padapter)
+{
+       enum hci_status                 status = HCI_STATUS_SUCCESS;
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp;
+
+       PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_INFORMATIONAL_PARAMETERS,
+               HCI_READ_DATA_BLOCK_SIZE,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = HCI_STATUS_SUCCESS;        /* status */
+       pu2Temp = (u16 *)&pRetPar[1];           /*  Max_ACL_Data_Packet_Length */
+       *pu2Temp = Max80211PALPDUSize;
+
+       pu2Temp = (u16 *)&pRetPar[3];           /*  Data_Block_Length */
+       *pu2Temp = Max80211PALPDUSize;
+       pu2Temp = (u16 *)&pRetPar[5];           /*  Total_Num_Data_Blocks */
+       *pu2Temp = BTTotalDataBlockNum;
+       len += 7;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+/*  7.4.5 */
+static enum hci_status bthci_CmdReadBufferSize(struct rtw_adapter *padapter)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp;
+
+       PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+       /* PPacketIrpEvent = (struct packet_irp_hcievent_data *)(buffer); */
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_INFORMATIONAL_PARAMETERS,
+               HCI_READ_BUFFER_SIZE,
+               status);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Synchronous_Data_Packet_Length = 0x%x\n", BTSynDataPacketLength));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Total_Num_ACL_Data_Packets = 0x%x\n", BTTotalDataBlockNum));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("Total_Num_Synchronous_Data_Packets = 0x%x\n", BTTotalDataBlockNum));
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       pu2Temp = (u16 *)&pRetPar[1];           /*  HC_ACL_Data_Packet_Length */
+       *pu2Temp = Max80211PALPDUSize;
+
+       pRetPar[3] = BTSynDataPacketLength;     /*  HC_Synchronous_Data_Packet_Length */
+       pu2Temp = (u16 *)&pRetPar[4];           /*  HC_Total_Num_ACL_Data_Packets */
+       *pu2Temp = BTTotalDataBlockNum;
+       pu2Temp = (u16 *)&pRetPar[6];           /*  HC_Total_Num_Synchronous_Data_Packets */
+       *pu2Temp = BTTotalDataBlockNum;
+       len += 8;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status bthci_CmdReadLocalAMPInfo(struct rtw_adapter *padapter)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct pwrctrl_priv *ppwrctrl = &padapter->pwrctrlpriv;
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp;
+       u32 *pu4Temp;
+       u32     TotalBandwidth = BTTOTALBANDWIDTH, MaxBandGUBandwidth = BTMAXBANDGUBANDWIDTH;
+       u8 ControlType = 0x01, AmpStatus = 0x01;
+       u32     MaxFlushTimeout = 10000, BestEffortFlushTimeout = 5000;
+       u16 MaxPDUSize = Max80211PALPDUSize, PalCap = 0x1, AmpAssocLen = Max80211AMPASSOCLen, MinLatency = 20;
+
+       if ((ppwrctrl->rfoff_reason & RF_CHANGE_BY_HW) ||
+           (ppwrctrl->rfoff_reason & RF_CHANGE_BY_SW)) {
+               AmpStatus = AMP_STATUS_NO_CAPACITY_FOR_BT;
+       }
+
+       PlatformZeroMemory(&localBuf[0], TmpLocalBufSize);
+       /* PPacketIrpEvent = (struct packet_irp_hcievent_data *)(buffer); */
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_STATUS_PARAMETERS,
+               HCI_READ_LOCAL_AMP_INFO,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;                    /* status */
+       pRetPar[1] = AmpStatus;                 /*  AMP_Status */
+       pu4Temp = (u32 *)&pRetPar[2];           /*  Total_Bandwidth */
+       *pu4Temp = TotalBandwidth;              /* 0x19bfcc00;0x7530; */
+       pu4Temp = (u32 *)&pRetPar[6];           /*  Max_Guaranteed_Bandwidth */
+       *pu4Temp = MaxBandGUBandwidth;          /* 0x19bfcc00;0x4e20; */
+       pu4Temp = (u32 *)&pRetPar[10];          /*  Min_Latency */
+       *pu4Temp = MinLatency;                  /* 150; */
+       pu4Temp = (u32 *)&pRetPar[14];          /*  Max_PDU_Size */
+       *pu4Temp = MaxPDUSize;
+       pRetPar[18] = ControlType;              /*  Controller_Type */
+       pu2Temp = (u16 *)&pRetPar[19];          /*  PAL_Capabilities */
+       *pu2Temp = PalCap;
+       pu2Temp = (u16 *)&pRetPar[21];          /*  AMP_ASSOC_Length */
+       *pu2Temp = AmpAssocLen;
+       pu4Temp = (u32 *)&pRetPar[23];          /*  Max_Flush_Timeout */
+       *pu4Temp = MaxFlushTimeout;
+       pu4Temp = (u32 *)&pRetPar[27];          /*  Best_Effort_Flush_Timeout */
+       *pu4Temp = BestEffortFlushTimeout;
+       len += 31;
+       PPacketIrpEvent->Length = len;
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("AmpStatus = 0x%x\n",
+               AmpStatus));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("TotalBandwidth = 0x%x, MaxBandGUBandwidth = 0x%x, MinLatency = 0x%x, \n MaxPDUSize = 0x%x, ControlType = 0x%x\n",
+               TotalBandwidth, MaxBandGUBandwidth, MinLatency, MaxPDUSize, ControlType));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("PalCap = 0x%x, AmpAssocLen = 0x%x, MaxFlushTimeout = 0x%x, BestEffortFlushTimeout = 0x%x\n",
+               PalCap, AmpAssocLen, MaxFlushTimeout, BestEffortFlushTimeout));
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       return status;
+}
+
+static enum hci_status
+bthci_CmdCreatePhysicalLink(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+
+       pBtDbg->dbgHciInfo.hciCmdCntCreatePhyLink++;
+
+       status = bthci_BuildPhysicalLink(padapter,
+               pHciCmd, HCI_CREATE_PHYSICAL_LINK);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdReadLinkQuality(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status                 status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       u16                             PLH;
+       u8      EntryNum, LinkQuality = 0x55;
+
+       PLH = *((u16 *)&pHciCmd->Data[0]);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("PLH = 0x%x\n", PLH));
+
+       EntryNum = bthci_GetCurrentEntryNum(padapter, (u8)PLH);
+       if (EntryNum == 0xff) {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("No such PLH(0x%x)\n", PLH));
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+       }
+
+       {
+               u8 localBuf[11] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_STATUS_PARAMETERS,
+                       HCI_READ_LINK_QUALITY,
+                       status);
+
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, (" PLH = 0x%x\n Link Quality = 0x%x\n", PLH, LinkQuality));
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;                    /* status */
+               *((u16 *)&pRetPar[1]) = pBTInfo->BtAsocEntry[EntryNum].PhyLinkCmdData.BtPhyLinkhandle;  /*  Handle */
+               pRetPar[3] = 0x55;      /* Link Quailty */
+               len += 4;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status bthci_CmdReadRSSI(struct rtw_adapter *padapter)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       return status;
+}
+
+static enum hci_status
+bthci_CmdCreateLogicalLink(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+
+       pBtDbg->dbgHciInfo.hciCmdCntCreateLogLink++;
+
+       bthci_BuildLogicalLink(padapter, pHciCmd,
+               HCI_CREATE_LOGICAL_LINK);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdAcceptLogicalLink(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+
+       pBtDbg->dbgHciInfo.hciCmdCntAcceptLogLink++;
+
+       bthci_BuildLogicalLink(padapter, pHciCmd,
+               HCI_ACCEPT_LOGICAL_LINK);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdDisconnectLogicalLink(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTinfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTinfo->BtMgnt;
+       struct bt_dgb *pBtDbg = &pBTinfo->BtDbg;
+       u16     logicHandle;
+       u8 i, j, find = 0, LogLinkCount = 0;
+
+       pBtDbg->dbgHciInfo.hciCmdCntDisconnectLogLink++;
+
+       logicHandle = *((u16 *)pHciCmd->Data);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DisconnectLogicalLink, logicHandle = 0x%x\n", logicHandle));
+
+       /*  find an created logical link index and clear the data */
+       for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) {
+               for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) {
+                       if (pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle == logicHandle) {
+                               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("DisconnectLogicalLink, logicHandle is matched  0x%x\n", logicHandle));
+                               bthci_ResetFlowSpec(padapter, j, i);
+                               find = 1;
+                               pBtMgnt->DisconnectEntryNum = j;
+                               break;
+                       }
+               }
+       }
+
+       if (!find)
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+
+       /*  To check each */
+       for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) {
+               if (pBTinfo->BtAsocEntry[pBtMgnt->DisconnectEntryNum].LogLinkCmdData[i].BtLogLinkhandle != 0)
+                       LogLinkCount++;
+       }
+
+       /* When we receive Create logical link command, we should send command status event first. */
+       bthci_EventCommandStatus(padapter,
+                       LINK_CONTROL_COMMANDS,
+                       HCI_DISCONNECT_LOGICAL_LINK,
+                       status);
+       /*  */
+       /* When we determines the logical link is established, we should send command complete event. */
+       /*  */
+       if (status == HCI_STATUS_SUCCESS) {
+               bthci_EventDisconnectLogicalLinkComplete(padapter, status,
+                       logicHandle, HCI_STATUS_CONNECT_TERMINATE_LOCAL_HOST);
+       }
+
+       if (LogLinkCount == 0)
+               mod_timer(&pBTinfo->BTDisconnectPhyLinkTimer,
+                         jiffies + msecs_to_jiffies(100));
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdLogicalLinkCancel(struct rtw_adapter *padapter,
+                          struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTinfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTinfo->BtMgnt;
+       u8 CurrentEntryNum, CurrentLogEntryNum;
+
+       u8 physicalLinkHandle, TxFlowSpecID, i;
+       u16     CurrentLogicalHandle;
+
+       physicalLinkHandle = *((u8 *)pHciCmd->Data);
+       TxFlowSpecID = *(((u8 *)pHciCmd->Data)+1);
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("LogicalLinkCancel, physicalLinkHandle = 0x%x, TxFlowSpecID = 0x%x\n",
+               physicalLinkHandle, TxFlowSpecID));
+
+       CurrentEntryNum = pBtMgnt->CurrentConnectEntryNum;
+       CurrentLogicalHandle = pBtMgnt->BtCurrentLogLinkhandle;
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("CurrentEntryNum = 0x%x, CurrentLogicalHandle = 0x%x\n",
+               CurrentEntryNum, CurrentLogicalHandle));
+
+       CurrentLogEntryNum = 0xff;
+       for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) {
+               if ((CurrentLogicalHandle == pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[i].BtLogLinkhandle) &&
+                       (physicalLinkHandle == pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[i].BtPhyLinkhandle)) {
+                       CurrentLogEntryNum = i;
+                       break;
+               }
+       }
+
+       if (CurrentLogEntryNum == 0xff) {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("LogicalLinkCancel, CurrentLogEntryNum == 0xff !!!!\n"));
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+               return status;
+       } else {
+               if (pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[CurrentLogEntryNum].bLLCompleteEventIsSet) {
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("LogicalLinkCancel, LLCompleteEventIsSet!!!!\n"));
+                       status = HCI_STATUS_ACL_CONNECT_EXISTS;
+               }
+       }
+
+       {
+               u8 localBuf[8] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       LINK_CONTROL_COMMANDS,
+                       HCI_LOGICAL_LINK_CANCEL,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+               pRetPar[1] = pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[CurrentLogEntryNum].BtPhyLinkhandle;
+               pRetPar[2] = pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[CurrentLogEntryNum].BtTxFlowSpecID;
+               len += 3;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       pBTinfo->BtAsocEntry[CurrentEntryNum].LogLinkCmdData[CurrentLogEntryNum].bLLCancelCMDIsSetandComplete = true;
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdFlowSpecModify(struct rtw_adapter *padapter,
+                       struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTinfo = GET_BT_INFO(padapter);
+       u8 i, j, find = 0;
+       u16 logicHandle;
+
+       logicHandle = *((u16 *)pHciCmd->Data);
+       /*  find an matched logical link index and copy the data */
+       for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) {
+               for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) {
+                       if (pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle == logicHandle) {
+                               memcpy(&pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].Tx_Flow_Spec,
+                                       &pHciCmd->Data[2], sizeof(struct hci_flow_spec));
+                               memcpy(&pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].Rx_Flow_Spec,
+                                       &pHciCmd->Data[18], sizeof(struct hci_flow_spec));
+
+                               bthci_CheckLogLinkBehavior(padapter, pBTinfo->BtAsocEntry[j].LogLinkCmdData[i].Tx_Flow_Spec);
+                               find = 1;
+                               break;
+                       }
+               }
+       }
+       RTPRINT(FIOCTL, IOCTL_BT_LOGO, ("FlowSpecModify, LLH = 0x%x, \n", logicHandle));
+
+       /* When we receive Flow Spec Modify command, we should send command status event first. */
+       bthci_EventCommandStatus(padapter,
+               LINK_CONTROL_COMMANDS,
+               HCI_FLOW_SPEC_MODIFY,
+               HCI_STATUS_SUCCESS);
+
+       if (!find)
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+
+       bthci_EventSendFlowSpecModifyComplete(padapter, status, logicHandle);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdAcceptPhysicalLink(struct rtw_adapter *padapter,
+                           struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+
+       pBtDbg->dbgHciInfo.hciCmdCntAcceptPhyLink++;
+
+       status = bthci_BuildPhysicalLink(padapter,
+               pHciCmd, HCI_ACCEPT_PHYSICAL_LINK);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdDisconnectPhysicalLink(struct rtw_adapter *padapter,
+                               struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+       u8 PLH, CurrentEntryNum, PhysLinkDisconnectReason;
+
+       pBtDbg->dbgHciInfo.hciCmdCntDisconnectPhyLink++;
+
+       PLH = *((u8 *)pHciCmd->Data);
+       PhysLinkDisconnectReason = (*((u8 *)pHciCmd->Data+1));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_DISCONNECT_PHYSICAL_LINK  PhyHandle = 0x%x, Reason = 0x%x\n",
+               PLH, PhysLinkDisconnectReason));
+
+       CurrentEntryNum = bthci_GetCurrentEntryNum(padapter, PLH);
+
+       if (CurrentEntryNum == 0xff) {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD,
+                       ("DisconnectPhysicalLink, No such Handle in the Entry\n"));
+               status = HCI_STATUS_UNKNOW_CONNECT_ID;
+       } else {
+               pBTInfo->BtAsocEntry[CurrentEntryNum].PhyLinkDisconnectReason =
+                       (enum hci_status)PhysLinkDisconnectReason;
+       }
+       /* Send HCI Command status event to AMP. */
+       bthci_EventCommandStatus(padapter, LINK_CONTROL_COMMANDS,
+                                HCI_DISCONNECT_PHYSICAL_LINK, status);
+
+       if (status != HCI_STATUS_SUCCESS)
+               return status;
+
+       /* The macros below require { and } in the if statement */
+       if (pBTInfo->BtAsocEntry[CurrentEntryNum].BtCurrentState == HCI_STATE_DISCONNECTED) {
+               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_DISCONNECT_PHY_LINK, CurrentEntryNum);
+       } else {
+               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTING, STATE_CMD_DISCONNECT_PHY_LINK, CurrentEntryNum);
+       }
+       return status;
+}
+
+static enum hci_status
+bthci_CmdSetACLLinkDataFlowMode(struct rtw_adapter *padapter,
+                               struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       u8 localBuf[8] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp;
+
+       pBtMgnt->ExtConfig.CurrentConnectHandle = *((u16 *)pHciCmd->Data);
+       pBtMgnt->ExtConfig.CurrentIncomingTrafficMode = *((u8 *)pHciCmd->Data)+2;
+       pBtMgnt->ExtConfig.CurrentOutgoingTrafficMode = *((u8 *)pHciCmd->Data)+3;
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("Connection Handle = 0x%x, Incoming Traffic mode = 0x%x, Outgoing Traffic mode = 0x%x",
+               pBtMgnt->ExtConfig.CurrentConnectHandle,
+               pBtMgnt->ExtConfig.CurrentIncomingTrafficMode,
+               pBtMgnt->ExtConfig.CurrentOutgoingTrafficMode));
+
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_EXTENSION,
+               HCI_SET_ACL_LINK_DATA_FLOW_MODE,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+
+       pu2Temp = (u16 *)&pRetPar[1];
+       *pu2Temp = pBtMgnt->ExtConfig.CurrentConnectHandle;
+       len += 3;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       return status;
+}
+
+static enum hci_status
+bthci_CmdSetACLLinkStatus(struct rtw_adapter *padapter,
+                         struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+       u8 i;
+       u8 *pTriple;
+
+       pBtDbg->dbgHciInfo.hciCmdCntSetAclLinkStatus++;
+       RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "SetACLLinkStatus, Hex Data :\n",
+                       &pHciCmd->Data[0], pHciCmd->Length);
+
+       /*  Only Core Stack v251 and later version support this command. */
+       pBtMgnt->bSupportProfile = true;
+
+       pBtMgnt->ExtConfig.NumberOfHandle = *((u8 *)pHciCmd->Data);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("NumberOfHandle = 0x%x\n", pBtMgnt->ExtConfig.NumberOfHandle));
+
+       pTriple = &pHciCmd->Data[1];
+       for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) {
+               pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle = *((u16 *)&pTriple[0]);
+               pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = pTriple[2];
+               pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = pTriple[3];
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT,
+                       ("Connection_Handle = 0x%x, Incoming Traffic mode = 0x%x, Outgoing Traffic Mode = 0x%x\n",
+                       pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle,
+                       pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode,
+                       pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode));
+               pTriple += 4;
+       }
+
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_SET_ACL_LINK_STATUS,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdSetSCOLinkStatus(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+
+       pBtDbg->dbgHciInfo.hciCmdCntSetScoLinkStatus++;
+       pBtMgnt->ExtConfig.NumberOfSCO = *((u8 *)pHciCmd->Data);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("NumberOfSCO = 0x%x\n",
+               pBtMgnt->ExtConfig.NumberOfSCO));
+
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_SET_SCO_LINK_STATUS,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdSetRSSIValue(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       s8              min_bt_rssi = 0;
+       u8 i;
+       for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) {
+               if (pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle == *((u16 *)&pHciCmd->Data[0])) {
+                       pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI = (s8)(pHciCmd->Data[2]);
+                       RTPRINT(FIOCTL, IOCTL_BT_EVENT_PERIODICAL,
+                       ("Connection_Handle = 0x%x, RSSI = %d \n",
+                       pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle,
+                       pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI));
+               }
+               /*  get the minimum bt rssi value */
+               if (pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI <= min_bt_rssi)
+                       min_bt_rssi = pBtMgnt->ExtConfig.linkInfo[i].BT_RSSI;
+       }
+
+       pBtMgnt->ExtConfig.MIN_BT_RSSI = min_bt_rssi;
+       RTPRINT(FBT, BT_TRACE, ("[bt rssi], the min rssi is %d\n", min_bt_rssi));
+
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_SET_RSSI_VALUE,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdSetCurrentBluetoothStatus(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+/*PMGNT_INFO   pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       pBtMgnt->ExtConfig.CurrentBTStatus = *((u8 *)&pHciCmd->Data[0]);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("SetCurrentBluetoothStatus, CurrentBTStatus = 0x%x\n",
+               pBtMgnt->ExtConfig.CurrentBTStatus));
+
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_SET_CURRENT_BLUETOOTH_STATUS,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+               len += 1;
+
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdExtensionVersionNotify(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+
+       pBtDbg->dbgHciInfo.hciCmdCntExtensionVersionNotify++;
+       RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "ExtensionVersionNotify, Hex Data :\n",
+                       &pHciCmd->Data[0], pHciCmd->Length);
+
+       pBtMgnt->ExtConfig.HCIExtensionVer = *((u16 *)&pHciCmd->Data[0]);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCIExtensionVer = 0x%x\n", pBtMgnt->ExtConfig.HCIExtensionVer));
+
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_EXTENSION_VERSION_NOTIFY,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdLinkStatusNotify(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+       u8 i;
+       u8 *pTriple;
+
+       pBtDbg->dbgHciInfo.hciCmdCntLinkStatusNotify++;
+       RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "LinkStatusNotify, Hex Data :\n",
+                       &pHciCmd->Data[0], pHciCmd->Length);
+
+       /*  Current only RTL8723 support this command. */
+       pBtMgnt->bSupportProfile = true;
+
+       pBtMgnt->ExtConfig.NumberOfHandle = *((u8 *)pHciCmd->Data);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("NumberOfHandle = 0x%x\n", pBtMgnt->ExtConfig.NumberOfHandle));
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCIExtensionVer = %d\n", pBtMgnt->ExtConfig.HCIExtensionVer));
+
+       pTriple = &pHciCmd->Data[1];
+       for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) {
+               if (pBtMgnt->ExtConfig.HCIExtensionVer < 1) {
+                       pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle = *((u16 *)&pTriple[0]);
+                       pBtMgnt->ExtConfig.linkInfo[i].BTProfile = pTriple[2];
+                       pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec = pTriple[3];
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT,
+                               ("Connection_Handle = 0x%x, BTProfile =%d, BTSpec =%d\n",
+                               pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle,
+                               pBtMgnt->ExtConfig.linkInfo[i].BTProfile,
+                               pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec));
+                       pTriple += 4;
+               } else if (pBtMgnt->ExtConfig.HCIExtensionVer >= 1) {
+                       pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle = *((u16 *)&pTriple[0]);
+                       pBtMgnt->ExtConfig.linkInfo[i].BTProfile = pTriple[2];
+                       pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec = pTriple[3];
+                       pBtMgnt->ExtConfig.linkInfo[i].linkRole = pTriple[4];
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT,
+                               ("Connection_Handle = 0x%x, BTProfile =%d, BTSpec =%d, LinkRole =%d\n",
+                               pBtMgnt->ExtConfig.linkInfo[i].ConnectHandle,
+                               pBtMgnt->ExtConfig.linkInfo[i].BTProfile,
+                               pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec,
+                               pBtMgnt->ExtConfig.linkInfo[i].linkRole));
+                       pTriple += 5;
+               }
+
+       }
+       BTHCI_UpdateBTProfileRTKToMoto(padapter);
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_LINK_STATUS_NOTIFY,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdBtOperationNotify(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "Bt Operation notify, Hex Data :\n",
+                       &pHciCmd->Data[0], pHciCmd->Length);
+
+       pBtMgnt->ExtConfig.btOperationCode = *((u8 *)pHciCmd->Data);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("btOperationCode = 0x%x\n", pBtMgnt->ExtConfig.btOperationCode));
+       switch (pBtMgnt->ExtConfig.btOperationCode) {
+       case HCI_BT_OP_NONE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Operation None!!\n"));
+               break;
+       case HCI_BT_OP_INQUIRY_START:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Inquire start!!\n"));
+               break;
+       case HCI_BT_OP_INQUIRY_FINISH:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Inquire finished!!\n"));
+               break;
+       case HCI_BT_OP_PAGING_START:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Paging is started!!\n"));
+               break;
+       case HCI_BT_OP_PAGING_SUCCESS:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Paging complete successfully!!\n"));
+               break;
+       case HCI_BT_OP_PAGING_UNSUCCESS:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Paging complete unsuccessfully!!\n"));
+               break;
+       case HCI_BT_OP_PAIRING_START:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Pairing start!!\n"));
+               break;
+       case HCI_BT_OP_PAIRING_FINISH:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Pairing finished!!\n"));
+               break;
+       case HCI_BT_OP_BT_DEV_ENABLE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : BT Device is enabled!!\n"));
+               break;
+       case HCI_BT_OP_BT_DEV_DISABLE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : BT Device is disabled!!\n"));
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[bt operation] : Unknown, error!!\n"));
+               break;
+       }
+       BTDM_AdjustForBtOperation(padapter);
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_BT_OPERATION_NOTIFY,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdEnableWifiScanNotify(struct rtw_adapter *padapter,
+                             struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT_DATA(FIOCTL, IOCTL_BT_HCICMD_EXT, "Enable Wifi scan notify, Hex Data :\n",
+                       &pHciCmd->Data[0], pHciCmd->Length);
+
+       pBtMgnt->ExtConfig.bEnableWifiScanNotify = *((u8 *)pHciCmd->Data);
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("bEnableWifiScanNotify = %d\n", pBtMgnt->ExtConfig.bEnableWifiScanNotify));
+
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_ENABLE_WIFI_SCAN_NOTIFY,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWIFICurrentChannel(struct rtw_adapter *padapter,
+                           struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       u8 chnl = pmlmeext->cur_channel;
+
+       if (pmlmeext->cur_bwmode == HT_CHANNEL_WIDTH_40) {
+               if (pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+                       chnl += 2;
+               else if (pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+                       chnl -= 2;
+       }
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("Current Channel  = 0x%x\n", chnl));
+
+       {
+               u8 localBuf[8] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_WIFI_CURRENT_CHANNEL,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+               pRetPar[1] = chnl;                      /* current channel */
+               len += 2;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWIFICurrentBandwidth(struct rtw_adapter *padapter,
+                             struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       enum ht_channel_width bw;
+       u8 CurrentBW = 0;
+
+       bw = padapter->mlmeextpriv.cur_bwmode;
+
+       if (bw == HT_CHANNEL_WIDTH_20)
+               CurrentBW = 0;
+       else if (bw == HT_CHANNEL_WIDTH_40)
+               CurrentBW = 1;
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("Current BW = 0x%x\n",
+               CurrentBW));
+
+       {
+               u8 localBuf[8] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_WIFI_CURRENT_BANDWIDTH,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+               pRetPar[1] = CurrentBW;         /* current BW */
+               len += 2;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdWIFIConnectionStatus(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       u8 connectStatus = HCI_WIFI_NOT_CONNECTED;
+
+       if (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE)) {
+               if (padapter->stapriv.asoc_sta_count >= 3)
+                       connectStatus = HCI_WIFI_CONNECTED;
+               else
+                       connectStatus = HCI_WIFI_NOT_CONNECTED;
+       } else if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE|WIFI_ASOC_STATE)) {
+               connectStatus = HCI_WIFI_CONNECTED;
+       } else if (check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING)) {
+               connectStatus = HCI_WIFI_CONNECT_IN_PROGRESS;
+       } else {
+               connectStatus = HCI_WIFI_NOT_CONNECTED;
+       }
+
+       {
+               u8 localBuf[8] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_EXTENSION,
+                       HCI_WIFI_CONNECTION_STATUS,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;                    /* status */
+               pRetPar[1] = connectStatus;     /* connect status */
+               len += 2;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdEnableDeviceUnderTestMode(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+
+       pBtHciInfo->bInTestMode = true;
+       pBtHciInfo->bTestIsEnd = false;
+
+       /* send command complete event here when all data are received. */
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_TESTING_COMMANDS,
+                       HCI_ENABLE_DEVICE_UNDER_TEST_MODE,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdAMPTestEnd(struct rtw_adapter *padapter,
+                   struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 bFilterOutNonAssociatedBSSID = true;
+
+       if (!pBtHciInfo->bInTestMode) {
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Not in Test mode, return status = HCI_STATUS_CMD_DISALLOW\n"));
+               status = HCI_STATUS_CMD_DISALLOW;
+               return status;
+       }
+
+       pBtHciInfo->bTestIsEnd = true;
+
+       del_timer_sync(&pBTInfo->BTTestSendPacketTimer);
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_CHECK_BSSID, (u8 *)(&bFilterOutNonAssociatedBSSID));
+
+       /* send command complete event here when all data are received. */
+       {
+               u8 localBuf[4] = "";
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("AMP Test End Event \n"));
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+               PPacketIrpEvent->EventCode = HCI_EVENT_AMP_TEST_END;
+               PPacketIrpEvent->Length = 2;
+
+               PPacketIrpEvent->Data[0] = status;
+               PPacketIrpEvent->Data[1] = pBtHciInfo->TestScenario;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, 4);
+       }
+
+       bthci_EventAMPReceiverReport(padapter, 0x01);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdAMPTestCommand(struct rtw_adapter *padapter,
+                       struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+
+       if (!pBtHciInfo->bInTestMode) {
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Not in Test mode, return status = HCI_STATUS_CMD_DISALLOW\n"));
+               status = HCI_STATUS_CMD_DISALLOW;
+               return status;
+       }
+
+       pBtHciInfo->TestScenario = *((u8 *)pHciCmd->Data);
+
+       if (pBtHciInfo->TestScenario == 0x01)
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("TX Single Test \n"));
+       else if (pBtHciInfo->TestScenario == 0x02)
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Receive Frame Test \n"));
+       else
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("No Such Test !!!!!!!!!!!!!!!!!! \n"));
+
+       if (pBtHciInfo->bTestIsEnd) {
+               u8 localBuf[5] = "";
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("AMP Test End Event \n"));
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+               PPacketIrpEvent->EventCode = HCI_EVENT_AMP_TEST_END;
+               PPacketIrpEvent->Length = 2;
+
+               PPacketIrpEvent->Data[0] = status;
+               PPacketIrpEvent->Data[1] = pBtHciInfo->TestScenario ;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, 4);
+
+               /* Return to Idel state with RX and TX off. */
+
+               return status;
+       }
+
+       /*  should send command status event */
+       bthci_EventCommandStatus(padapter,
+                       OGF_TESTING_COMMANDS,
+                       HCI_AMP_TEST_COMMAND,
+                       status);
+
+       /* The HCI_AMP_Start Test Event shall be generated when the */
+       /* HCI_AMP_Test_Command has completed and the first data is ready to be sent */
+       /* or received. */
+
+       {
+               u8 localBuf[5] = "";
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), (" HCI_AMP_Start Test Event \n"));
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+               PPacketIrpEvent->EventCode = HCI_EVENT_AMP_START_TEST;
+               PPacketIrpEvent->Length = 2;
+
+               PPacketIrpEvent->Data[0] = status;
+               PPacketIrpEvent->Data[1] = pBtHciInfo->TestScenario ;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, 4);
+
+               /* Return to Idel state with RX and TX off. */
+       }
+
+       if (pBtHciInfo->TestScenario == 0x01) {
+               /*
+                       When in a transmitter test scenario and the frames/bursts count have been
+                       transmitted the HCI_AMP_Test_End event shall be sent.
+               */
+               mod_timer(&pBTInfo->BTTestSendPacketTimer,
+                         jiffies + msecs_to_jiffies(50));
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("TX Single Test \n"));
+       } else if (pBtHciInfo->TestScenario == 0x02) {
+               u8 bFilterOutNonAssociatedBSSID = false;
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_CHECK_BSSID, (u8 *)(&bFilterOutNonAssociatedBSSID));
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_BT_LOGO), ("Receive Frame Test \n"));
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdEnableAMPReceiverReports(struct rtw_adapter *padapter,
+                                 struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+
+       if (!pBtHciInfo->bInTestMode) {
+               status = HCI_STATUS_CMD_DISALLOW;
+               /* send command complete event here when all data are received. */
+               {
+                       u8 localBuf[6] = "";
+                       u8 *pRetPar;
+                       u8 len = 0;
+                       struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+                       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+                       len += bthci_CommandCompleteHeader(&localBuf[0],
+                               OGF_TESTING_COMMANDS,
+                               HCI_ENABLE_AMP_RECEIVER_REPORTS,
+                               status);
+
+                       /*  Return parameters starts from here */
+                       pRetPar = &PPacketIrpEvent->Data[len];
+                       pRetPar[0] = status;            /* status */
+                       len += 1;
+                       PPacketIrpEvent->Length = len;
+
+                       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+               }
+               return status;
+       }
+
+       pBtHciInfo->bTestNeedReport = *((u8 *)pHciCmd->Data);
+       pBtHciInfo->TestReportInterval = (*((u8 *)pHciCmd->Data+2));
+
+       bthci_EventAMPReceiverReport(padapter, 0x00);
+
+       /* send command complete event here when all data are received. */
+       {
+               u8 localBuf[6] = "";
+               u8 *pRetPar;
+               u8 len = 0;
+               struct packet_irp_hcievent_data *PPacketIrpEvent;
+
+               PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+               len += bthci_CommandCompleteHeader(&localBuf[0],
+                       OGF_TESTING_COMMANDS,
+                       HCI_ENABLE_AMP_RECEIVER_REPORTS,
+                       status);
+
+               /*  Return parameters starts from here */
+               pRetPar = &PPacketIrpEvent->Data[len];
+               pRetPar[0] = status;            /* status */
+               len += 1;
+               PPacketIrpEvent->Length = len;
+
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+       }
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdHostBufferSize(struct rtw_adapter *padapter,
+                       struct packet_irp_hcicmd_data *pHciCmd)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       u8 localBuf[6] = "";
+       u8 *pRetPar;
+       u8 len = 0;
+
+       pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].ACLPacketsData.ACLDataPacketLen = *((u16 *)pHciCmd->Data);
+       pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].SyncDataPacketLen = *((u8 *)(pHciCmd->Data+2));
+       pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].TotalNumACLDataPackets = *((u16 *)(pHciCmd->Data+3));
+       pBTInfo->BtAsocEntry[pBtMgnt->CurrentConnectEntryNum].TotalSyncNumDataPackets = *((u16 *)(pHciCmd->Data+5));
+
+       /* send command complete event here when all data are received. */
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       len += bthci_CommandCompleteHeader(&localBuf[0],
+               OGF_SET_EVENT_MASK_COMMAND,
+               HCI_HOST_BUFFER_SIZE,
+               status);
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[len];
+       pRetPar[0] = status;            /* status */
+       len += 1;
+       PPacketIrpEvent->Length = len;
+
+       bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+
+       return status;
+}
+
+static enum hci_status
+bthci_CmdHostNumberOfCompletedPackets(struct rtw_adapter *padapter,
+                                     struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+
+       return status;
+}
+
+static enum hci_status
+bthci_UnknownCMD(struct rtw_adapter *padapter, struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_UNKNOW_HCI_CMD;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+
+       pBtDbg->dbgHciInfo.hciCmdCntUnknown++;
+       bthci_EventCommandStatus(padapter,
+                       (u8)pHciCmd->OGF,
+                       pHciCmd->OCF,
+                       status);
+
+       return status;
+}
+
+static enum hci_status
+bthci_HandleOGFInformationalParameters(struct rtw_adapter *padapter,
+                                      struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+
+       switch (pHciCmd->OCF) {
+       case HCI_READ_LOCAL_VERSION_INFORMATION:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_VERSION_INFORMATION\n"));
+               status = bthci_CmdReadLocalVersionInformation(padapter);
+               break;
+       case HCI_READ_LOCAL_SUPPORTED_COMMANDS:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_SUPPORTED_COMMANDS\n"));
+               status = bthci_CmdReadLocalSupportedCommands(padapter);
+               break;
+       case HCI_READ_LOCAL_SUPPORTED_FEATURES:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_SUPPORTED_FEATURES\n"));
+               status = bthci_CmdReadLocalSupportedFeatures(padapter);
+               break;
+       case HCI_READ_BUFFER_SIZE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_BUFFER_SIZE\n"));
+               status = bthci_CmdReadBufferSize(padapter);
+               break;
+       case HCI_READ_DATA_BLOCK_SIZE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_DATA_BLOCK_SIZE\n"));
+               status = bthci_CmdReadDataBlockSize(padapter);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_HandleOGFInformationalParameters(), Unknown case = 0x%x\n", pHciCmd->OCF));
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n"));
+               status = bthci_UnknownCMD(padapter, pHciCmd);
+               break;
+       }
+       return status;
+}
+
+static enum hci_status
+bthci_HandleOGFSetEventMaskCMD(struct rtw_adapter *padapter,
+                              struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+
+       switch (pHciCmd->OCF) {
+       case HCI_SET_EVENT_MASK:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_SET_EVENT_MASK\n"));
+               status = bthci_CmdSetEventMask(padapter, pHciCmd);
+               break;
+       case HCI_RESET:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_RESET\n"));
+               status = bthci_CmdReset(padapter, true);
+               break;
+       case HCI_READ_CONNECTION_ACCEPT_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_CONNECTION_ACCEPT_TIMEOUT\n"));
+               status = bthci_CmdReadConnectionAcceptTimeout(padapter);
+               break;
+       case HCI_SET_EVENT_FILTER:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_SET_EVENT_FILTER\n"));
+               status = bthci_CmdSetEventFilter(padapter, pHciCmd);
+               break;
+       case HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT\n"));
+               status = bthci_CmdWriteConnectionAcceptTimeout(padapter, pHciCmd);
+               break;
+       case HCI_READ_PAGE_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_PAGE_TIMEOUT\n"));
+               status = bthci_CmdReadPageTimeout(padapter, pHciCmd);
+               break;
+       case HCI_WRITE_PAGE_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_PAGE_TIMEOUT\n"));
+               status = bthci_CmdWritePageTimeout(padapter, pHciCmd);
+               break;
+       case HCI_HOST_NUMBER_OF_COMPLETED_PACKETS:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_HOST_NUMBER_OF_COMPLETED_PACKETS\n"));
+               status = bthci_CmdHostNumberOfCompletedPackets(padapter, pHciCmd);
+               break;
+       case HCI_READ_LINK_SUPERVISION_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LINK_SUPERVISION_TIMEOUT\n"));
+               status = bthci_CmdReadLinkSupervisionTimeout(padapter, pHciCmd);
+               break;
+       case HCI_WRITE_LINK_SUPERVISION_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_LINK_SUPERVISION_TIMEOUT\n"));
+               status = bthci_CmdWriteLinkSupervisionTimeout(padapter, pHciCmd);
+               break;
+       case HCI_ENHANCED_FLUSH:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ENHANCED_FLUSH\n"));
+               status = bthci_CmdEnhancedFlush(padapter, pHciCmd);
+               break;
+       case HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT\n"));
+               status = bthci_CmdReadLogicalLinkAcceptTimeout(padapter, pHciCmd);
+               break;
+       case HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT\n"));
+               status = bthci_CmdWriteLogicalLinkAcceptTimeout(padapter, pHciCmd);
+               break;
+       case HCI_SET_EVENT_MASK_PAGE_2:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_SET_EVENT_MASK_PAGE_2\n"));
+               status = bthci_CmdSetEventMaskPage2(padapter, pHciCmd);
+               break;
+       case HCI_READ_LOCATION_DATA:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCATION_DATA\n"));
+               status = bthci_CmdReadLocationData(padapter, pHciCmd);
+               break;
+       case HCI_WRITE_LOCATION_DATA:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_LOCATION_DATA\n"));
+               status = bthci_CmdWriteLocationData(padapter, pHciCmd);
+               break;
+       case HCI_READ_FLOW_CONTROL_MODE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_FLOW_CONTROL_MODE\n"));
+               status = bthci_CmdReadFlowControlMode(padapter, pHciCmd);
+               break;
+       case HCI_WRITE_FLOW_CONTROL_MODE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_FLOW_CONTROL_MODE\n"));
+               status = bthci_CmdWriteFlowControlMode(padapter, pHciCmd);
+               break;
+       case HCI_READ_BEST_EFFORT_FLUSH_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_BEST_EFFORT_FLUSH_TIMEOUT\n"));
+               status = bthci_CmdReadBestEffortFlushTimeout(padapter, pHciCmd);
+               break;
+       case HCI_WRITE_BEST_EFFORT_FLUSH_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_BEST_EFFORT_FLUSH_TIMEOUT\n"));
+               status = bthci_CmdWriteBestEffortFlushTimeout(padapter, pHciCmd);
+               break;
+       case HCI_SHORT_RANGE_MODE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_SHORT_RANGE_MODE\n"));
+               status = bthci_CmdShortRangeMode(padapter, pHciCmd);
+               break;
+       case HCI_HOST_BUFFER_SIZE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_HOST_BUFFER_SIZE\n"));
+               status = bthci_CmdHostBufferSize(padapter, pHciCmd);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_HandleOGFSetEventMaskCMD(), Unknown case = 0x%x\n", pHciCmd->OCF));
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n"));
+               status = bthci_UnknownCMD(padapter, pHciCmd);
+               break;
+       }
+       return status;
+}
+
+static enum hci_status
+bthci_HandleOGFStatusParameters(struct rtw_adapter *padapter,
+                               struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+
+       switch (pHciCmd->OCF) {
+       case HCI_READ_FAILED_CONTACT_COUNTER:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_FAILED_CONTACT_COUNTER\n"));
+               status = bthci_CmdReadFailedContactCounter(padapter, pHciCmd);
+               break;
+       case HCI_RESET_FAILED_CONTACT_COUNTER:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_RESET_FAILED_CONTACT_COUNTER\n"));
+               status = bthci_CmdResetFailedContactCounter(padapter, pHciCmd);
+               break;
+       case HCI_READ_LINK_QUALITY:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LINK_QUALITY\n"));
+               status = bthci_CmdReadLinkQuality(padapter, pHciCmd);
+               break;
+       case HCI_READ_RSSI:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_RSSI\n"));
+               status = bthci_CmdReadRSSI(padapter);
+               break;
+       case HCI_READ_LOCAL_AMP_INFO:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_AMP_INFO\n"));
+               status = bthci_CmdReadLocalAMPInfo(padapter);
+               break;
+       case HCI_READ_LOCAL_AMP_ASSOC:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_READ_LOCAL_AMP_ASSOC\n"));
+               status = bthci_CmdReadLocalAMPAssoc(padapter, pHciCmd);
+               break;
+       case HCI_WRITE_REMOTE_AMP_ASSOC:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_WRITE_REMOTE_AMP_ASSOC\n"));
+               status = bthci_CmdWriteRemoteAMPAssoc(padapter, pHciCmd);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_HandleOGFStatusParameters(), Unknown case = 0x%x\n", pHciCmd->OCF));
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n"));
+               status = bthci_UnknownCMD(padapter, pHciCmd);
+               break;
+       }
+       return status;
+}
+
+static enum hci_status
+bthci_HandleOGFLinkControlCMD(struct rtw_adapter *padapter,
+                             struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+
+       switch (pHciCmd->OCF) {
+       case HCI_CREATE_PHYSICAL_LINK:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_CREATE_PHYSICAL_LINK\n"));
+               status = bthci_CmdCreatePhysicalLink(padapter, pHciCmd);
+               break;
+       case HCI_ACCEPT_PHYSICAL_LINK:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ACCEPT_PHYSICAL_LINK\n"));
+               status = bthci_CmdAcceptPhysicalLink(padapter, pHciCmd);
+               break;
+       case HCI_DISCONNECT_PHYSICAL_LINK:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_DISCONNECT_PHYSICAL_LINK\n"));
+               status = bthci_CmdDisconnectPhysicalLink(padapter, pHciCmd);
+               break;
+       case HCI_CREATE_LOGICAL_LINK:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_CREATE_LOGICAL_LINK\n"));
+               status = bthci_CmdCreateLogicalLink(padapter, pHciCmd);
+               break;
+       case HCI_ACCEPT_LOGICAL_LINK:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ACCEPT_LOGICAL_LINK\n"));
+               status = bthci_CmdAcceptLogicalLink(padapter, pHciCmd);
+               break;
+       case HCI_DISCONNECT_LOGICAL_LINK:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_DISCONNECT_LOGICAL_LINK\n"));
+               status = bthci_CmdDisconnectLogicalLink(padapter, pHciCmd);
+               break;
+       case HCI_LOGICAL_LINK_CANCEL:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_LOGICAL_LINK_CANCEL\n"));
+               status = bthci_CmdLogicalLinkCancel(padapter, pHciCmd);
+               break;
+       case HCI_FLOW_SPEC_MODIFY:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_FLOW_SPEC_MODIFY\n"));
+               status = bthci_CmdFlowSpecModify(padapter, pHciCmd);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("bthci_HandleOGFLinkControlCMD(), Unknown case = 0x%x\n", pHciCmd->OCF));
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n"));
+               status = bthci_UnknownCMD(padapter, pHciCmd);
+               break;
+       }
+       return status;
+}
+
+static enum hci_status
+bthci_HandleOGFTestingCMD(struct rtw_adapter *padapter,
+                         struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       switch (pHciCmd->OCF) {
+       case HCI_ENABLE_DEVICE_UNDER_TEST_MODE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ENABLE_DEVICE_UNDER_TEST_MODE\n"));
+               bthci_CmdEnableDeviceUnderTestMode(padapter, pHciCmd);
+               break;
+       case HCI_AMP_TEST_END:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_AMP_TEST_END\n"));
+               bthci_CmdAMPTestEnd(padapter, pHciCmd);
+               break;
+       case HCI_AMP_TEST_COMMAND:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_AMP_TEST_COMMAND\n"));
+               bthci_CmdAMPTestCommand(padapter, pHciCmd);
+               break;
+       case HCI_ENABLE_AMP_RECEIVER_REPORTS:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_ENABLE_AMP_RECEIVER_REPORTS\n"));
+               bthci_CmdEnableAMPReceiverReports(padapter, pHciCmd);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n"));
+               status = bthci_UnknownCMD(padapter, pHciCmd);
+               break;
+       }
+       return status;
+}
+
+static enum hci_status
+bthci_HandleOGFExtension(struct rtw_adapter *padapter,
+                        struct packet_irp_hcicmd_data *pHciCmd)
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       switch (pHciCmd->OCF) {
+       case HCI_SET_ACL_LINK_DATA_FLOW_MODE:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_SET_ACL_LINK_DATA_FLOW_MODE\n"));
+               status = bthci_CmdSetACLLinkDataFlowMode(padapter, pHciCmd);
+               break;
+       case HCI_SET_ACL_LINK_STATUS:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_SET_ACL_LINK_STATUS\n"));
+               status = bthci_CmdSetACLLinkStatus(padapter, pHciCmd);
+               break;
+       case HCI_SET_SCO_LINK_STATUS:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_SET_SCO_LINK_STATUS\n"));
+               status = bthci_CmdSetSCOLinkStatus(padapter, pHciCmd);
+               break;
+       case HCI_SET_RSSI_VALUE:
+               RTPRINT(FIOCTL, IOCTL_BT_EVENT_PERIODICAL, ("HCI_SET_RSSI_VALUE\n"));
+               status = bthci_CmdSetRSSIValue(padapter, pHciCmd);
+               break;
+       case HCI_SET_CURRENT_BLUETOOTH_STATUS:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_SET_CURRENT_BLUETOOTH_STATUS\n"));
+               status = bthci_CmdSetCurrentBluetoothStatus(padapter, pHciCmd);
+               break;
+       /* The following is for RTK8723 */
+
+       case HCI_EXTENSION_VERSION_NOTIFY:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_EXTENSION_VERSION_NOTIFY\n"));
+               status = bthci_CmdExtensionVersionNotify(padapter, pHciCmd);
+               break;
+       case HCI_LINK_STATUS_NOTIFY:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_LINK_STATUS_NOTIFY\n"));
+               status = bthci_CmdLinkStatusNotify(padapter, pHciCmd);
+               break;
+       case HCI_BT_OPERATION_NOTIFY:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_BT_OPERATION_NOTIFY\n"));
+               status = bthci_CmdBtOperationNotify(padapter, pHciCmd);
+               break;
+       case HCI_ENABLE_WIFI_SCAN_NOTIFY:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_ENABLE_WIFI_SCAN_NOTIFY\n"));
+               status = bthci_CmdEnableWifiScanNotify(padapter, pHciCmd);
+               break;
+
+       /* The following is for IVT */
+       case HCI_WIFI_CURRENT_CHANNEL:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_WIFI_CURRENT_CHANNEL\n"));
+               status = bthci_CmdWIFICurrentChannel(padapter, pHciCmd);
+               break;
+       case HCI_WIFI_CURRENT_BANDWIDTH:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_WIFI_CURRENT_BANDWIDTH\n"));
+               status = bthci_CmdWIFICurrentBandwidth(padapter, pHciCmd);
+               break;
+       case HCI_WIFI_CONNECTION_STATUS:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_WIFI_CONNECTION_STATUS\n"));
+               status = bthci_CmdWIFIConnectionStatus(padapter, pHciCmd);
+               break;
+
+       default:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("HCI_UNKNOWN_COMMAND\n"));
+               status = bthci_UnknownCMD(padapter, pHciCmd);
+               break;
+       }
+       return status;
+}
+
+static void
+bthci_StateStarting(struct rtw_adapter *padapter,
+                   enum hci_state_with_cmd StateCmd, u8 EntryNum)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Starting], "));
+       switch (StateCmd) {
+       case STATE_CMD_CONNECT_ACCEPT_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_CONNECT_ACCEPT_TIMEOUT\n"));
+               pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_CONNECT_ACCEPT_TIMEOUT;
+               pBtMgnt->bNeedNotifyAMPNoCap = true;
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+               break;
+       case STATE_CMD_DISCONNECT_PHY_LINK:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n"));
+
+               bthci_EventDisconnectPhyLinkComplete(padapter,
+               HCI_STATUS_SUCCESS,
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason,
+               EntryNum);
+
+               del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer);
+
+               pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_UNKNOW_CONNECT_ID;
+
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+               break;
+       case STATE_CMD_MAC_START_COMPLETE:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_START_COMPLETE\n"));
+               if (pBTInfo->BtAsocEntry[EntryNum].AMPRole == AMP_BTAP_CREATOR)
+                       bthci_EventChannelSelected(padapter, EntryNum);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd));
+               break;
+       }
+}
+
+static void
+bthci_StateConnecting(struct rtw_adapter *padapter,
+                     enum hci_state_with_cmd StateCmd, u8 EntryNum)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Connecting], "));
+       switch (StateCmd) {
+       case STATE_CMD_CONNECT_ACCEPT_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_CONNECT_ACCEPT_TIMEOUT\n"));
+               pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_CONNECT_ACCEPT_TIMEOUT;
+               pBtMgnt->bNeedNotifyAMPNoCap = true;
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+               break;
+       case STATE_CMD_MAC_CONNECT_COMPLETE:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_CONNECT_COMPLETE\n"));
+
+               if (pBTInfo->BtAsocEntry[EntryNum].AMPRole == AMP_BTAP_JOINER) {
+                       RT_TRACE(_module_rtl871x_security_c_,
+                                _drv_info_, ("StateConnecting \n"));
+               }
+               break;
+       case STATE_CMD_DISCONNECT_PHY_LINK:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n"));
+
+               bthci_EventDisconnectPhyLinkComplete(padapter,
+               HCI_STATUS_SUCCESS,
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason,
+               EntryNum);
+
+               pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_UNKNOW_CONNECT_ID;
+
+               del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer);
+
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+
+               break;
+       case STATE_CMD_MAC_CONNECT_CANCEL_INDICATE:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_CONNECT_CANCEL_INDICATE\n"));
+               pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_CONTROLLER_BUSY;
+               /*  Because this state cmd is caused by the BTHCI_EventAMPStatusChange(), */
+               /*  we don't need to send event in the following BTHCI_DisconnectPeer() again. */
+               pBtMgnt->bNeedNotifyAMPNoCap = false;
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd));
+               break;
+       }
+}
+
+static void
+bthci_StateConnected(struct rtw_adapter *padapter,
+                    enum hci_state_with_cmd StateCmd, u8 EntryNum)
+{
+/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       u8 i;
+       u16 logicHandle = 0;
+
+       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Connected], "));
+       switch (StateCmd) {
+       case STATE_CMD_DISCONNECT_PHY_LINK:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n"));
+
+               /* When we are trying to disconnect the phy link, we should disconnect log link first, */
+               for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) {
+                       if (pBTInfo->BtAsocEntry[EntryNum].LogLinkCmdData->BtLogLinkhandle != 0) {
+                               logicHandle = pBTInfo->BtAsocEntry[EntryNum].LogLinkCmdData->BtLogLinkhandle;
+
+                               bthci_EventDisconnectLogicalLinkComplete(padapter, HCI_STATUS_SUCCESS,
+                                       logicHandle, pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason);
+
+                               pBTInfo->BtAsocEntry[EntryNum].LogLinkCmdData->BtLogLinkhandle = 0;
+                       }
+               }
+
+               bthci_EventDisconnectPhyLinkComplete(padapter,
+               HCI_STATUS_SUCCESS,
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason,
+               EntryNum);
+
+               del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer);
+
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+               break;
+
+       case STATE_CMD_MAC_DISCONNECT_INDICATE:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_DISCONNECT_INDICATE\n"));
+
+               bthci_EventDisconnectPhyLinkComplete(padapter,
+               HCI_STATUS_SUCCESS,
+               /*  TODO: Remote Host not local host */
+               HCI_STATUS_CONNECT_TERMINATE_LOCAL_HOST,
+               EntryNum);
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+
+               break;
+       case STATE_CMD_ENTER_STATE:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_ENTER_STATE\n"));
+
+               if (pBtMgnt->bBTConnectInProgress) {
+                       pBtMgnt->bBTConnectInProgress = false;
+                       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress OFF!!\n"));
+               }
+               pBTInfo->BtAsocEntry[EntryNum].BtCurrentState = HCI_STATE_CONNECTED;
+               pBTInfo->BtAsocEntry[EntryNum].b4waySuccess = true;
+               pBtMgnt->bStartSendSupervisionPkt = true;
+
+               /*  for rate adaptive */
+
+               if (padapter->HalFunc.UpdateRAMaskHandler)
+                       padapter->HalFunc.UpdateRAMaskHandler(padapter, MAX_FW_SUPPORT_MACID_NUM-1-EntryNum, 0);
+
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_BASIC_RATE, padapter->mlmepriv.cur_network.network.SupportedRates);
+               BTDM_SetFwChnlInfo(padapter, RT_MEDIA_CONNECT);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd));
+               break;
+       }
+}
+
+static void
+bthci_StateAuth(struct rtw_adapter *padapter, enum hci_state_with_cmd StateCmd,
+               u8 EntryNum)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Authenticating], "));
+       switch (StateCmd) {
+       case STATE_CMD_CONNECT_ACCEPT_TIMEOUT:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_CONNECT_ACCEPT_TIMEOUT\n"));
+               pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_CONNECT_ACCEPT_TIMEOUT;
+               pBtMgnt->bNeedNotifyAMPNoCap = true;
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+               break;
+       case STATE_CMD_DISCONNECT_PHY_LINK:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n"));
+               bthci_EventDisconnectPhyLinkComplete(padapter,
+               HCI_STATUS_SUCCESS,
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason,
+               EntryNum);
+
+               pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_UNKNOW_CONNECT_ID;
+
+               del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer);
+
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+               break;
+       case STATE_CMD_4WAY_FAILED:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_4WAY_FAILED\n"));
+
+               pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus = HCI_STATUS_AUTH_FAIL;
+               pBtMgnt->bNeedNotifyAMPNoCap = true;
+
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+
+               del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer);
+               break;
+       case STATE_CMD_4WAY_SUCCESSED:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_4WAY_SUCCESSED\n"));
+
+               bthci_EventPhysicalLinkComplete(padapter, HCI_STATUS_SUCCESS, EntryNum, INVALID_PL_HANDLE);
+
+               del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer);
+
+               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_CONNECTED, STATE_CMD_ENTER_STATE, EntryNum);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd));
+               break;
+       }
+}
+
+static void
+bthci_StateDisconnecting(struct rtw_adapter *padapter,
+                        enum hci_state_with_cmd StateCmd, u8 EntryNum)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Disconnecting], "));
+       switch (StateCmd) {
+       case STATE_CMD_MAC_CONNECT_CANCEL_INDICATE:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_MAC_CONNECT_CANCEL_INDICATE\n"));
+               if (pBTInfo->BtAsocEntry[EntryNum].bNeedPhysLinkCompleteEvent) {
+                       bthci_EventPhysicalLinkComplete(padapter,
+                               pBTInfo->BtAsocEntry[EntryNum].PhysLinkCompleteStatus,
+                               EntryNum, INVALID_PL_HANDLE);
+               }
+
+               if (pBtMgnt->bBTConnectInProgress) {
+                       pBtMgnt->bBTConnectInProgress = false;
+                       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress OFF!!\n"));
+               }
+
+               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_ENTER_STATE, EntryNum);
+               break;
+       case STATE_CMD_DISCONNECT_PHY_LINK:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n"));
+
+               bthci_EventDisconnectPhyLinkComplete(padapter,
+               HCI_STATUS_SUCCESS,
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason,
+               EntryNum);
+
+               del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer);
+
+               BTHCI_DisconnectPeer(padapter, EntryNum);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd));
+               break;
+       }
+}
+
+static void
+bthci_StateDisconnected(struct rtw_adapter *padapter,
+                       enum hci_state_with_cmd StateCmd, u8 EntryNum)
+{
+/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state], [Disconnected], "));
+       switch (StateCmd) {
+       case STATE_CMD_CREATE_PHY_LINK:
+       case STATE_CMD_ACCEPT_PHY_LINK:
+               if (StateCmd == STATE_CMD_CREATE_PHY_LINK)
+                       RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_CREATE_PHY_LINK\n"));
+               else
+                       RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_ACCEPT_PHY_LINK\n"));
+
+               RTPRINT(FIOCTL, IOCTL_STATE, ("[BT PS], Disable IPS and LPS\n"));
+               ips_leave23a(padapter);
+               LPS_Leave23a(padapter);
+
+               pBtMgnt->bPhyLinkInProgress = true;
+               pBtMgnt->BTCurrentConnectType = BT_DISCONNECT;
+               pBtMgnt->CurrentBTConnectionCnt++;
+               RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], CurrentBTConnectionCnt = %d\n",
+                       pBtMgnt->CurrentBTConnectionCnt));
+               pBtMgnt->BtOperationOn = true;
+               RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], Bt Operation ON!! CurrentConnectEntryNum = %d\n",
+                       pBtMgnt->CurrentConnectEntryNum));
+
+               if (pBtMgnt->bBTConnectInProgress) {
+                       bthci_EventPhysicalLinkComplete(padapter, HCI_STATUS_CONTROLLER_BUSY, INVALID_ENTRY_NUM, pBtMgnt->BtCurrentPhyLinkhandle);
+                       bthci_RemoveEntryByEntryNum(padapter, EntryNum);
+                       return;
+               }
+
+               if (StateCmd == STATE_CMD_CREATE_PHY_LINK)
+                       pBTInfo->BtAsocEntry[EntryNum].AMPRole = AMP_BTAP_CREATOR;
+               else
+                       pBTInfo->BtAsocEntry[EntryNum].AMPRole = AMP_BTAP_JOINER;
+
+               /*  1. MAC not yet in selected channel */
+               while (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE|WIFI_SITE_MONITOR)) {
+                       RTPRINT(FIOCTL, IOCTL_STATE, ("Scan/Roaming/Wifi Link is in Progress, wait 200 ms\n"));
+                       mdelay(200);
+               }
+               /*  2. MAC already in selected channel */
+               RTPRINT(FIOCTL, IOCTL_STATE, ("Channel is Ready\n"));
+               mod_timer(&pBTInfo->BTHCIJoinTimeoutTimer,
+                         jiffies + msecs_to_jiffies(pBtHciInfo->ConnAcceptTimeout));
+
+               pBTInfo->BtAsocEntry[EntryNum].bNeedPhysLinkCompleteEvent = true;
+               break;
+       case STATE_CMD_DISCONNECT_PHY_LINK:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_DISCONNECT_PHY_LINK\n"));
+
+               del_timer_sync(&pBTInfo->BTHCIJoinTimeoutTimer);
+
+               bthci_EventDisconnectPhyLinkComplete(padapter,
+               HCI_STATUS_SUCCESS,
+               pBTInfo->BtAsocEntry[EntryNum].PhyLinkDisconnectReason,
+               EntryNum);
+
+               if (pBTInfo->BtAsocEntry[EntryNum].bNeedPhysLinkCompleteEvent) {
+                       bthci_EventPhysicalLinkComplete(padapter,
+                               HCI_STATUS_UNKNOW_CONNECT_ID,
+                               EntryNum, INVALID_PL_HANDLE);
+               }
+
+               if (pBtMgnt->bBTConnectInProgress) {
+                       pBtMgnt->bBTConnectInProgress = false;
+                       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress OFF!!\n"));
+               }
+               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTED, STATE_CMD_ENTER_STATE, EntryNum);
+               bthci_RemoveEntryByEntryNum(padapter, EntryNum);
+               break;
+       case STATE_CMD_ENTER_STATE:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("STATE_CMD_ENTER_STATE\n"));
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_STATE, ("State command(%d) is Wrong !!!\n", StateCmd));
+               break;
+       }
+}
+
+void BTHCI_EventParse(struct rtw_adapter *padapter, void *pEvntData, u32 dataLen)
+{
+}
+
+u8 BTHCI_HsConnectionEstablished(struct rtw_adapter *padapter)
+{
+       u8 bBtConnectionExist = false;
+       struct bt_30info *pBtinfo = GET_BT_INFO(padapter);
+       u8 i;
+
+       for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) {
+               if (pBtinfo->BtAsocEntry[i].b4waySuccess) {
+                       bBtConnectionExist = true;
+                       break;
+               }
+       }
+
+/*RTPRINT(FIOCTL, IOCTL_STATE, (" BTHCI_HsConnectionEstablished(), connection exist = %d\n", bBtConnectionExist)); */
+
+       return bBtConnectionExist;
+}
+
+static u8
+BTHCI_CheckProfileExist(struct rtw_adapter *padapter,
+                       enum bt_traffic_mode_profile Profile)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       u8 IsPRofile = false;
+       u8 i = 0;
+
+       for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) {
+               if (pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile == Profile) {
+                       IsPRofile = true;
+                       break;
+               }
+       }
+
+       return IsPRofile;
+}
+
+void BTHCI_UpdateBTProfileRTKToMoto(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       u8 i = 0;
+
+       pBtMgnt->ExtConfig.NumberOfSCO = 0;
+
+       for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) {
+               pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile = BT_PROFILE_NONE;
+
+               if (pBtMgnt->ExtConfig.linkInfo[i].BTProfile == BT_PROFILE_SCO)
+                       pBtMgnt->ExtConfig.NumberOfSCO++;
+
+               pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile = pBtMgnt->ExtConfig.linkInfo[i].BTProfile;
+               switch (pBtMgnt->ExtConfig.linkInfo[i].TrafficProfile) {
+               case BT_PROFILE_SCO:
+                       break;
+               case BT_PROFILE_PAN:
+                       pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = BT_MOTOR_EXT_BE;
+                       pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = BT_MOTOR_EXT_BE;
+                       break;
+               case BT_PROFILE_A2DP:
+                       pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = BT_MOTOR_EXT_GULB;
+                       pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = BT_MOTOR_EXT_GULB;
+                       break;
+               case BT_PROFILE_HID:
+                       pBtMgnt->ExtConfig.linkInfo[i].IncomingTrafficMode = BT_MOTOR_EXT_GUL;
+                       pBtMgnt->ExtConfig.linkInfo[i].OutgoingTrafficMode = BT_MOTOR_EXT_BE;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], RTK, NumberOfHandle = %d, NumberOfSCO = %d\n",
+               pBtMgnt->ExtConfig.NumberOfHandle, pBtMgnt->ExtConfig.NumberOfSCO));
+}
+
+void BTHCI_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bEnableWifiScanNotify)
+               bthci_EventExtWifiScanNotify(padapter, scanType);
+}
+
+void
+BTHCI_StateMachine(
+       struct rtw_adapter *padapter,
+       u8              StateToEnter,
+       enum hci_state_with_cmd         StateCmd,
+       u8              EntryNum
+       )
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (EntryNum == 0xff) {
+               RTPRINT(FIOCTL, IOCTL_STATE, (" StateMachine, error EntryNum = 0x%x \n", EntryNum));
+               return;
+       }
+       RTPRINT(FIOCTL, IOCTL_STATE, (" StateMachine, EntryNum = 0x%x, CurrentState = 0x%x, BtNextState = 0x%x,  StateCmd = 0x%x , StateToEnter = 0x%x\n",
+               EntryNum, pBTInfo->BtAsocEntry[EntryNum].BtCurrentState, pBTInfo->BtAsocEntry[EntryNum].BtNextState, StateCmd, StateToEnter));
+
+       if (pBTInfo->BtAsocEntry[EntryNum].BtNextState & StateToEnter) {
+               pBTInfo->BtAsocEntry[EntryNum].BtCurrentState = StateToEnter;
+
+               switch (StateToEnter) {
+               case HCI_STATE_STARTING:
+                       pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTING | HCI_STATE_CONNECTING;
+                       bthci_StateStarting(padapter, StateCmd, EntryNum);
+                       break;
+               case HCI_STATE_CONNECTING:
+                       pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_CONNECTING | HCI_STATE_DISCONNECTING | HCI_STATE_AUTHENTICATING;
+                       bthci_StateConnecting(padapter, StateCmd, EntryNum);
+                       break;
+               case HCI_STATE_AUTHENTICATING:
+                       pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTING | HCI_STATE_CONNECTED;
+                       bthci_StateAuth(padapter, StateCmd, EntryNum);
+                       break;
+               case HCI_STATE_CONNECTED:
+                       pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_CONNECTED | HCI_STATE_DISCONNECTING;
+                       bthci_StateConnected(padapter, StateCmd, EntryNum);
+                       break;
+               case HCI_STATE_DISCONNECTING:
+                       pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTED | HCI_STATE_DISCONNECTING;
+                       bthci_StateDisconnecting(padapter, StateCmd, EntryNum);
+                       break;
+               case HCI_STATE_DISCONNECTED:
+                       pBTInfo->BtAsocEntry[EntryNum].BtNextState = HCI_STATE_DISCONNECTED | HCI_STATE_STARTING | HCI_STATE_CONNECTING;
+                       bthci_StateDisconnected(padapter, StateCmd, EntryNum);
+                       break;
+               default:
+                       RTPRINT(FIOCTL, IOCTL_STATE, (" StateMachine, Unknown state to enter!!!\n"));
+                       break;
+               }
+       } else {
+               RTPRINT(FIOCTL, IOCTL_STATE, (" StateMachine, Wrong state to enter\n"));
+       }
+
+       /*  20100325 Joseph: Disable/Enable IPS/LPS according to BT status. */
+       if (!pBtMgnt->bBTConnectInProgress && !pBtMgnt->BtOperationOn) {
+               RTPRINT(FIOCTL, IOCTL_STATE, ("[BT PS], ips_enter23a()\n"));
+               ips_enter23a(padapter);
+       }
+}
+
+void BTHCI_DisconnectPeer(struct rtw_adapter *padapter, u8 EntryNum)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, (" BTHCI_DisconnectPeer()\n"));
+
+       BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTING, STATE_CMD_MAC_CONNECT_CANCEL_INDICATE, EntryNum);
+
+       if (pBTInfo->BtAsocEntry[EntryNum].bUsed) {
+/*BTPKT_SendDeauthentication(padapter, pBTInfo->BtAsocEntry[EntryNum].BTRemoteMACAddr, unspec_reason); not porting yet */
+       }
+
+       if (pBtMgnt->bBTConnectInProgress) {
+               pBtMgnt->bBTConnectInProgress = false;
+               RTPRINT(FIOCTL, IOCTL_STATE, ("[BT Flag], BT Connect in progress OFF!!\n"));
+       }
+
+       bthci_RemoveEntryByEntryNum(padapter, EntryNum);
+
+       if (pBtMgnt->bNeedNotifyAMPNoCap) {
+               RTPRINT(FIOCTL, IOCTL_STATE, ("[BT AMPStatus], set to invalid in BTHCI_DisconnectPeer()\n"));
+               BTHCI_EventAMPStatusChange(padapter, AMP_STATUS_NO_CAPACITY_FOR_BT);
+       }
+}
+
+void BTHCI_EventNumOfCompletedDataBlocks(struct rtw_adapter *padapter)
+{
+/*PMGNT_INFO pMgntInfo = &padapter->MgntInfo; */
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_hci_info *pBtHciInfo = &pBTInfo->BtHciInfo;
+       u8 localBuf[TmpLocalBufSize] = "";
+       u8 *pRetPar, *pTriple;
+       u8 len = 0, i, j, handleNum = 0;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u16 *pu2Temp, *pPackets, *pHandle, *pDblocks;
+       u8 sent = 0;
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+
+       if (!(pBtHciInfo->BTEventMaskPage2 & EMP2_HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS)) {
+               RTPRINT(FIOCTL, IOCTL_BT_EVENT, ("[BT event], Num Of Completed DataBlocks, Ignore to send NumOfCompletedDataBlocksEvent due to event mask page 2\n"));
+               return;
+       }
+
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[0];
+       pTriple = &pRetPar[3];
+       for (j = 0; j < MAX_BT_ASOC_ENTRY_NUM; j++) {
+
+               for (i = 0; i < MAX_LOGICAL_LINK_NUM; i++) {
+                       if (pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle) {
+                               handleNum++;
+                               pHandle = (u16 *)&pTriple[0];   /*  Handle[i] */
+                               pPackets = (u16 *)&pTriple[2];  /*  Num_Of_Completed_Packets[i] */
+                               pDblocks = (u16 *)&pTriple[4];  /*  Num_Of_Completed_Blocks[i] */
+                               *pHandle = pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].BtLogLinkhandle;
+                               *pPackets = (u16)pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].TxPacketCount;
+                               *pDblocks = (u16)pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].TxPacketCount;
+                               if (pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].TxPacketCount) {
+                                       sent = 1;
+                                       RTPRINT(FIOCTL, IOCTL_BT_EVENT_DETAIL,
+                                               ("[BT event], Num Of Completed DataBlocks, Handle = 0x%x, Num_Of_Completed_Packets = 0x%x, Num_Of_Completed_Blocks = 0x%x\n",
+                                       *pHandle, *pPackets, *pDblocks));
+                               }
+                               pBTInfo->BtAsocEntry[j].LogLinkCmdData[i].TxPacketCount = 0;
+                               len += 6;
+                               pTriple += len;
+                       }
+               }
+       }
+
+       pRetPar[2] = handleNum;                         /*  Number_of_Handles */
+       len += 1;
+       pu2Temp = (u16 *)&pRetPar[0];
+       *pu2Temp = BTTotalDataBlockNum;
+       len += 2;
+
+       PPacketIrpEvent->EventCode = HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS;
+       PPacketIrpEvent->Length = len;
+       if (handleNum && sent)
+               bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2);
+}
+
+void BTHCI_EventAMPStatusChange(struct rtw_adapter *padapter, u8 AMP_Status)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct packet_irp_hcievent_data *PPacketIrpEvent;
+       u8 len = 0;
+       u8 localBuf[7] = "";
+       u8 *pRetPar;
+
+       if (AMP_Status == AMP_STATUS_NO_CAPACITY_FOR_BT) {
+               pBtMgnt->BTNeedAMPStatusChg = true;
+               pBtMgnt->bNeedNotifyAMPNoCap = false;
+
+               BTHCI_DisconnectAll(padapter);
+       } else if (AMP_Status == AMP_STATUS_FULL_CAPACITY_FOR_BT) {
+               pBtMgnt->BTNeedAMPStatusChg = false;
+       }
+
+       PPacketIrpEvent = (struct packet_irp_hcievent_data *)(&localBuf[0]);
+       /*  Return parameters starts from here */
+       pRetPar = &PPacketIrpEvent->Data[0];
+
+       pRetPar[0] = 0; /*  Status */
+       len += 1;
+       pRetPar[1] = AMP_Status;        /*  AMP_Status */
+       len += 1;
+
+       PPacketIrpEvent->EventCode = HCI_EVENT_AMP_STATUS_CHANGE;
+       PPacketIrpEvent->Length = len;
+       if (bthci_IndicateEvent(padapter, PPacketIrpEvent, len+2) == RT_STATUS_SUCCESS)
+               RTPRINT(FIOCTL, (IOCTL_BT_EVENT|IOCTL_STATE), ("[BT event], AMP Status Change, AMP_Status = %d\n", AMP_Status));
+}
+
+void BTHCI_DisconnectAll(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       u8 i;
+
+       RTPRINT(FIOCTL, IOCTL_STATE, (" DisconnectALL()\n"));
+
+       for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) {
+               if (pBTInfo->BtAsocEntry[i].b4waySuccess) {
+                       BTHCI_SM_WITH_INFO(padapter, HCI_STATE_CONNECTED, STATE_CMD_DISCONNECT_PHY_LINK, i);
+               } else if (pBTInfo->BtAsocEntry[i].bUsed) {
+                       if (pBTInfo->BtAsocEntry[i].BtCurrentState == HCI_STATE_CONNECTING) {
+                               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_CONNECTING, STATE_CMD_MAC_CONNECT_CANCEL_INDICATE, i);
+                       } else if (pBTInfo->BtAsocEntry[i].BtCurrentState == HCI_STATE_DISCONNECTING) {
+                               BTHCI_SM_WITH_INFO(padapter, HCI_STATE_DISCONNECTING, STATE_CMD_MAC_CONNECT_CANCEL_INDICATE, i);
+                       }
+               }
+       }
+}
+
+enum hci_status
+BTHCI_HandleHCICMD(
+       struct rtw_adapter *padapter,
+       struct packet_irp_hcicmd_data *pHciCmd
+       )
+{
+       enum hci_status status = HCI_STATUS_SUCCESS;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("\n"));
+       RTPRINT(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), ("HCI Command start, OGF = 0x%x, OCF = 0x%x, Length = 0x%x\n",
+               pHciCmd->OGF, pHciCmd->OCF, pHciCmd->Length));
+       if (pHciCmd->Length) {
+               RTPRINT_DATA(FIOCTL, (IOCTL_BT_HCICMD_DETAIL|IOCTL_BT_LOGO), "HCI Command, Hex Data :\n",
+                       &pHciCmd->Data[0], pHciCmd->Length);
+       }
+       if (pHciCmd->OGF == OGF_EXTENSION) {
+               if (pHciCmd->OCF == HCI_SET_RSSI_VALUE)
+                       RTPRINT(FIOCTL, IOCTL_BT_EVENT_PERIODICAL, ("[BT cmd], "));
+               else
+                       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_EXT, ("[BT cmd], "));
+       } else {
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("[BT cmd], "));
+       }
+
+       pBtDbg->dbgHciInfo.hciCmdCnt++;
+
+       switch (pHciCmd->OGF) {
+       case LINK_CONTROL_COMMANDS:
+               status = bthci_HandleOGFLinkControlCMD(padapter, pHciCmd);
+               break;
+       case HOLD_MODE_COMMAND:
+               break;
+       case OGF_SET_EVENT_MASK_COMMAND:
+               status = bthci_HandleOGFSetEventMaskCMD(padapter, pHciCmd);
+               break;
+       case OGF_INFORMATIONAL_PARAMETERS:
+               status = bthci_HandleOGFInformationalParameters(padapter, pHciCmd);
+               break;
+       case OGF_STATUS_PARAMETERS:
+               status = bthci_HandleOGFStatusParameters(padapter, pHciCmd);
+               break;
+       case OGF_TESTING_COMMANDS:
+               status = bthci_HandleOGFTestingCMD(padapter, pHciCmd);
+               break;
+       case OGF_EXTENSION:
+               status = bthci_HandleOGFExtension(padapter, pHciCmd);
+               break;
+       default:
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI Command(), Unknown OGF = 0x%x\n", pHciCmd->OGF));
+               RTPRINT(FIOCTL, IOCTL_BT_HCICMD, ("HCI_UNKNOWN_COMMAND\n"));
+               status = bthci_UnknownCMD(padapter, pHciCmd);
+               break;
+       }
+       RTPRINT(FIOCTL, IOCTL_BT_HCICMD_DETAIL, ("HCI Command execution end!!\n"));
+
+       return status;
+}
+
+/*  ===== End of sync from SD7 driver COMMOM/bt_hci.c ===== */
+#endif
+
+#ifdef __HALBTC87231ANT_C__ /*  HAL/BTCoexist/HalBtc87231Ant.c */
+
+static const char *const BtStateString[] = {
+       "BT_DISABLED",
+       "BT_NO_CONNECTION",
+       "BT_CONNECT_IDLE",
+       "BT_INQ_OR_PAG",
+       "BT_ACL_ONLY_BUSY",
+       "BT_SCO_ONLY_BUSY",
+       "BT_ACL_SCO_BUSY",
+       "BT_ACL_INQ_OR_PAG",
+       "BT_STATE_NOT_DEFINED"
+};
+
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.c ===== */
+
+static void btdm_SetFwIgnoreWlanAct(struct rtw_adapter *padapter, u8 bEnable)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 H2C_Parameter[1] = {0};
+
+       if (bEnable) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Ignore Wlan_Act !!\n"));
+               H2C_Parameter[0] |= BIT(0);             /*  function enable */
+               pHalData->bt_coexist.bFWCoexistAllOff = false;
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT don't ignore Wlan_Act !!\n"));
+       }
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], set FW for BT Ignore Wlan_Act, write 0x25 = 0x%02x\n",
+               H2C_Parameter[0]));
+
+       FillH2CCmd(padapter, BT_IGNORE_WLAN_ACT_EID, 1, H2C_Parameter);
+}
+
+static void btdm_NotifyFwScan(struct rtw_adapter *padapter, u8 scanType)
+{
+       u8 H2C_Parameter[1] = {0};
+
+       if (scanType == true)
+               H2C_Parameter[0] = 0x1;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Notify FW for wifi scan, write 0x3b = 0x%02x\n",
+               H2C_Parameter[0]));
+
+       FillH2CCmd(padapter, 0x3b, 1, H2C_Parameter);
+}
+
+static void btdm_1AntSetPSMode(struct rtw_adapter *padapter,
+                              u8 enable, u8 smartps, u8 mode)
+{
+       struct pwrctrl_priv *pwrctrl;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Current LPS(%s, %d), smartps =%d\n", enable == true?"ON":"OFF", mode, smartps));
+
+       pwrctrl = &padapter->pwrctrlpriv;
+
+       if (enable == true) {
+               rtw_set_ps_mode23a(padapter, PS_MODE_MIN, smartps, mode);
+       } else {
+               rtw_set_ps_mode23a(padapter, PS_MODE_ACTIVE, 0, 0);
+               LPS_RF_ON_check23a(padapter, 100);
+       }
+}
+
+static void btdm_1AntTSFSwitch(struct rtw_adapter *padapter, u8 enable)
+{
+       u8 oldVal, newVal;
+
+       oldVal = rtw_read8(padapter, 0x550);
+
+       if (enable)
+               newVal = oldVal | EN_BCN_FUNCTION;
+       else
+               newVal = oldVal & ~EN_BCN_FUNCTION;
+
+       if (oldVal != newVal)
+               rtw_write8(padapter, 0x550, newVal);
+}
+
+static u8 btdm_Is1AntPsTdmaStateChange(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_1ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant;
+
+       if ((pBtdm8723->bPrePsTdmaOn != pBtdm8723->bCurPsTdmaOn) ||
+               (pBtdm8723->prePsTdma != pBtdm8723->curPsTdma))
+               return true;
+       else
+               return false;
+}
+
+/*  Before enter TDMA, make sure Power Saving is enable! */
+static void
+btdm_1AntPsTdma(
+       struct rtw_adapter *padapter,
+       u8 bTurnOn,
+       u8 type
+       )
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_1ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant;
+
+       pBtdm8723->bCurPsTdmaOn = bTurnOn;
+       pBtdm8723->curPsTdma = type;
+       if (bTurnOn) {
+               switch (type) {
+               case 1: /*  A2DP Level-1 or FTP/OPP */
+               default:
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  wide duration for WiFi */
+                               BTDM_SetFw3a(padapter, 0xd3, 0x1a, 0x1a, 0x0, 0x58);
+                       }
+                       break;
+               case 2: /*  A2DP Level-2 */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  normal duration for WiFi */
+                               BTDM_SetFw3a(padapter, 0xd3, 0x12, 0x12, 0x0, 0x58);
+                       }
+                       break;
+               case 3: /*  BT FTP/OPP */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  normal duration for WiFi */
+                               BTDM_SetFw3a(padapter, 0xd3, 0x30, 0x03, 0x10, 0x58);
+
+                       }
+                       break;
+               case 4: /*  for wifi scan & BT is connected */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  protect 3 beacons in 3-beacon period & no Tx pause at BT slot */
+                               BTDM_SetFw3a(padapter, 0x93, 0x15, 0x03, 0x14, 0x0);
+                       }
+                       break;
+               case 5: /*  for WiFi connected-busy & BT is Non-Connected-Idle */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  SCO mode, Ant fixed at WiFi, WLAN_Act toggle */
+                               BTDM_SetFw3a(padapter, 0x61, 0x15, 0x03, 0x31, 0x00);
+                       }
+                       break;
+               case 9: /*  ACL high-retry type - 2 */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  narrow duration for WiFi */
+                               BTDM_SetFw3a(padapter, 0xd3, 0xa, 0xa, 0x0, 0x58); /* narrow duration for WiFi */
+                       }
+                       break;
+               case 10: /*  for WiFi connect idle & BT ACL busy or WiFi Connected-Busy & BT is Inquiry */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0x13, 0xa, 0xa, 0x0, 0x40);
+                       break;
+               case 11: /*  ACL high-retry type - 3 */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  narrow duration for WiFi */
+                               BTDM_SetFw3a(padapter, 0xd3, 0x05, 0x05, 0x00, 0x58);
+                       }
+                       break;
+               case 12: /*  for WiFi Connected-Busy & BT is Connected-Idle */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  Allow High-Pri BT */
+                               BTDM_SetFw3a(padapter, 0xeb, 0x0a, 0x03, 0x31, 0x18);
+                       }
+                       break;
+               case 20: /*  WiFi only busy , TDMA mode for power saving */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0x13, 0x25, 0x25, 0x00, 0x00);
+                       break;
+               case 27: /*  WiFi DHCP/Site Survey & BT SCO busy */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0xa3, 0x25, 0x03, 0x31, 0x98);
+                       break;
+               case 28: /*  WiFi DHCP/Site Survey & BT idle */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0x69, 0x25, 0x03, 0x31, 0x00);
+                       break;
+               case 29: /*  WiFi DHCP/Site Survey & BT ACL busy */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               BTDM_SetFw3a(padapter, 0xeb, 0x1a, 0x1a, 0x01, 0x18);
+                               rtw_write32(padapter, 0x6c0, 0x5afa5afa);
+                               rtw_write32(padapter, 0x6c4, 0x5afa5afa);
+                       }
+                       break;
+               case 30: /*  WiFi idle & BT Inquiry */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0x93, 0x15, 0x03, 0x14, 0x00);
+                       break;
+               case 31:  /*  BT HID */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0xd3, 0x1a, 0x1a, 0x00, 0x58);
+                       break;
+               case 32:  /*  BT SCO & Inquiry */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0xab, 0x0a, 0x03, 0x11, 0x98);
+                       break;
+               case 33:  /*  BT SCO & WiFi site survey */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0xa3, 0x25, 0x03, 0x30, 0x98);
+                       break;
+               case 34:  /*  BT HID & WiFi site survey */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0xd3, 0x1a, 0x1a, 0x00, 0x18);
+                       break;
+               case 35:  /*  BT HID & WiFi Connecting */
+                       if (btdm_Is1AntPsTdmaStateChange(padapter))
+                               BTDM_SetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0x00, 0x18);
+                       break;
+               }
+       } else {
+               /*  disable PS-TDMA */
+               switch (type) {
+               case 8:
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  Antenna control by PTA, 0x870 = 0x310 */
+                               BTDM_SetFw3a(padapter, 0x8, 0x0, 0x0, 0x0, 0x0);
+                       }
+                       break;
+               case 0:
+               default:
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  Antenna control by PTA, 0x870 = 0x310 */
+                               BTDM_SetFw3a(padapter, 0x0, 0x0, 0x0, 0x8, 0x0);
+                       }
+                       rtw_write16(padapter, 0x860, 0x210); /*  Switch Antenna to BT */
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], 0x860 = 0x210, Switch Antenna to BT\n"));
+                       break;
+               case 9:
+                       if (btdm_Is1AntPsTdmaStateChange(padapter)) {
+                               /*  Antenna control by PTA, 0x870 = 0x310 */
+                               BTDM_SetFw3a(padapter, 0x0, 0x0, 0x0, 0x8, 0x0);
+                       }
+                       rtw_write16(padapter, 0x860, 0x110); /*  Switch Antenna to WiFi */
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], 0x860 = 0x110, Switch Antenna to WiFi\n"));
+                       break;
+               }
+       }
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Current TDMA(%s, %d)\n",
+               pBtdm8723->bCurPsTdmaOn?"ON":"OFF", pBtdm8723->curPsTdma));
+
+       /*  update pre state */
+       pBtdm8723->bPrePsTdmaOn = pBtdm8723->bCurPsTdmaOn;
+       pBtdm8723->prePsTdma = pBtdm8723->curPsTdma;
+}
+
+static void
+_btdm_1AntSetPSTDMA(struct rtw_adapter *padapter, u8 bPSEn, u8 smartps,
+                   u8 psOption, u8 bTDMAOn, u8 tdmaType)
+{
+       struct pwrctrl_priv *pwrctrl;
+       struct hal_data_8723a *pHalData;
+       struct btdm_8723a_1ant *pBtdm8723;
+       u8 psMode;
+       u8 bSwitchPS;
+
+       if (!check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) &&
+           (get_fwstate(&padapter->mlmepriv) != WIFI_NULL_STATE)) {
+               btdm_1AntPsTdma(padapter, bTDMAOn, tdmaType);
+               return;
+       }
+       psOption &= ~BIT(0);
+
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTCoex], Set LPS(%s, %d) TDMA(%s, %d)\n",
+               bPSEn == true?"ON":"OFF", psOption,
+               bTDMAOn == true?"ON":"OFF", tdmaType));
+
+       pwrctrl = &padapter->pwrctrlpriv;
+       pHalData = GET_HAL_DATA(padapter);
+       pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant;
+
+       if (bPSEn) {
+               if (pBtdm8723->bWiFiHalt) {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Enable PS Fail, WiFi in Halt!!\n"));
+                       return;
+               }
+
+               if (pwrctrl->bInSuspend) {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Enable PS Fail, WiFi in Suspend!!\n"));
+                       return;
+               }
+
+               if (padapter->bDriverStopped) {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Enable PS Fail, WiFi driver stopped!!\n"));
+                       return;
+               }
+
+               if (padapter->bSurpriseRemoved) {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Enable PS Fail, WiFi Surprise Removed!!\n"));
+                       return;
+               }
+
+               psMode = PS_MODE_MIN;
+       } else {
+               psMode = PS_MODE_ACTIVE;
+               psOption = 0;
+       }
+
+       if (psMode != pwrctrl->pwr_mode) {
+               bSwitchPS = true;
+       } else if (psMode != PS_MODE_ACTIVE) {
+               if (psOption != pwrctrl->bcn_ant_mode)
+                       bSwitchPS = true;
+               else if (smartps != pwrctrl->smart_ps)
+                       bSwitchPS = true;
+               else
+                       bSwitchPS = false;
+       } else {
+               bSwitchPS = false;
+       }
+
+       if (bSwitchPS) {
+               /*  disable TDMA */
+               if (pBtdm8723->bCurPsTdmaOn) {
+                       if (!bTDMAOn) {
+                               btdm_1AntPsTdma(padapter, false, tdmaType);
+                       } else {
+                               if ((BT_IsBtDisabled(padapter)) ||
+                                   (pHalData->bt_coexist.halCoex8723.c2hBtInfo == BT_INFO_STATE_NO_CONNECTION) ||
+                                   (pHalData->bt_coexist.halCoex8723.c2hBtInfo == BT_INFO_STATE_CONNECT_IDLE) ||
+                                   (tdmaType == 29))
+                                       btdm_1AntPsTdma(padapter, false, 9);
+                               else
+                                       btdm_1AntPsTdma(padapter, false, 0);
+                       }
+               }
+
+               /*  change Power Save State */
+               btdm_1AntSetPSMode(padapter, bPSEn, smartps, psOption);
+       }
+
+       btdm_1AntPsTdma(padapter, bTDMAOn, tdmaType);
+}
+
+static void
+btdm_1AntSetPSTDMA(struct rtw_adapter *padapter, u8 bPSEn,
+                  u8 psOption, u8 bTDMAOn, u8 tdmaType)
+{
+       _btdm_1AntSetPSTDMA(padapter, bPSEn, 0, psOption, bTDMAOn, tdmaType);
+}
+
+static void btdm_1AntWifiParaAdjust(struct rtw_adapter *padapter, u8 bEnable)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_1ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant;
+
+       if (bEnable) {
+               pBtdm8723->curWifiPara = 1;
+               if (pBtdm8723->preWifiPara != pBtdm8723->curWifiPara)
+                       BTDM_SetSwPenaltyTxRateAdaptive(padapter, BT_TX_RATE_ADAPTIVE_LOW_PENALTY);
+       } else {
+               pBtdm8723->curWifiPara = 2;
+               if (pBtdm8723->preWifiPara != pBtdm8723->curWifiPara)
+                       BTDM_SetSwPenaltyTxRateAdaptive(padapter, BT_TX_RATE_ADAPTIVE_NORMAL);
+       }
+
+}
+
+static void btdm_1AntPtaParaReload(struct rtw_adapter *padapter)
+{
+       /*  PTA parameter */
+       rtw_write8(padapter, 0x6cc, 0x0);                       /*  1-Ant coex */
+       rtw_write32(padapter, 0x6c8, 0xffff);           /*  wifi break table */
+       rtw_write32(padapter, 0x6c4, 0x55555555);       /*  coex table */
+
+       /*  Antenna switch control parameter */
+       rtw_write32(padapter, 0x858, 0xaaaaaaaa);
+       if (IS_8723A_A_CUT(GET_HAL_DATA(padapter)->VersionID)) {
+               rtw_write32(padapter, 0x870, 0x0);      /*  SPDT(connected with TRSW) control by hardware PTA */
+               rtw_write8(padapter, 0x40, 0x24);
+       } else {
+               rtw_write8(padapter, 0x40, 0x20);
+               rtw_write16(padapter, 0x860, 0x210);    /*  set antenna at bt side if ANTSW is software control */
+               rtw_write32(padapter, 0x870, 0x300);    /*  SPDT(connected with TRSW) control by hardware PTA */
+               rtw_write32(padapter, 0x874, 0x22804000);       /*  ANTSW keep by GNT_BT */
+       }
+
+       /*  coexistence parameters */
+       rtw_write8(padapter, 0x778, 0x1);       /*  enable RTK mode PTA */
+
+       /*  BT don't ignore WLAN_Act */
+       btdm_SetFwIgnoreWlanAct(padapter, false);
+}
+
+/*
+ * Return
+ *1: upgrade (add WiFi duration time)
+ *0: keep
+ *-1: downgrade (add BT duration time)
+ */
+static s8 btdm_1AntTdmaJudgement(struct rtw_adapter *padapter, u8 retry)
+{
+       struct hal_data_8723a *pHalData;
+       struct btdm_8723a_1ant *pBtdm8723;
+       static s8 up, dn, m = 1, n = 3, WaitCount;
+       s8 ret;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant;
+       ret = 0;
+
+       if (pBtdm8723->psTdmaMonitorCnt == 0) {
+               up = 0;
+               dn = 0;
+               m = 1;
+               n = 3;
+               WaitCount = 0;
+       } else {
+               WaitCount++;
+       }
+
+       if (retry == 0) {
+       /*  no retry in the last 2-second duration */
+               up++;
+               dn--;
+               if (dn < 0)
+                       dn = 0;
+               if (up >= 3*m) {
+                       /*  retry = 0 in consecutive 3m*(2s), add WiFi duration */
+                       ret = 1;
+
+                       n = 3;
+                       up = 0;
+                       dn = 0;
+                       WaitCount = 0;
+               }
+       } else if (retry <= 3) {
+               /*  retry<= 3 in the last 2-second duration */
+               up--;
+               dn++;
+               if (up < 0)
+                       up = 0;
+
+               if (dn == 2) {
+                       /*  retry<= 3 in consecutive 2*(2s), minus WiFi duration (add BT duration) */
+                       ret = -1;
+
+                       /*  record how many time downgrad WiFi duration */
+                       if (WaitCount <= 2)
+                               m++;
+                       else
+                               m = 1;
+                       /*  the max number of m is 20 */
+                       /*  the longest time of upgrade WiFi duration is 20*3*2s = 120s */
+                       if (m >= 20)
+                               m = 20;
+                       up = 0;
+                       dn = 0;
+                       WaitCount = 0;
+               }
+       } else {
+               /*  retry count > 3 */
+               /*  retry>3, minus WiFi duration (add BT duration) */
+               ret = -1;
+
+               /*  record how many time downgrad WiFi duration */
+               if (WaitCount == 1)
+                       m++;
+               else
+                       m = 1;
+               if (m >= 20)
+                       m = 20;
+
+               up = 0;
+               dn = 0;
+               WaitCount = 0;
+       }
+       return ret;
+}
+
+static void btdm_1AntTdmaDurationAdjustForACL(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_1ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant;
+
+       if (pBtdm8723->psTdmaGlobalCnt != pBtdm8723->psTdmaMonitorCnt) {
+               pBtdm8723->psTdmaMonitorCnt = 0;
+               pBtdm8723->psTdmaGlobalCnt = 0;
+       }
+       if (pBtdm8723->psTdmaMonitorCnt == 0) {
+               btdm_1AntSetPSTDMA(padapter, true, 0, true, 2);
+               pBtdm8723->psTdmaDuAdjType = 2;
+       } else {
+               /*  Now we only have 4 level Ps Tdma, */
+               /*  if that's not the following 4 level(will changed by wifi scan, dhcp...), */
+               /*  then we have to adjust it back to the previous record one. */
+               if ((pBtdm8723->curPsTdma != 1) &&
+                   (pBtdm8723->curPsTdma != 2) &&
+                   (pBtdm8723->curPsTdma != 9) &&
+                   (pBtdm8723->curPsTdma != 11)) {
+                       btdm_1AntSetPSTDMA(padapter, true, 0, true, pBtdm8723->psTdmaDuAdjType);
+               } else {
+                       s32 judge = 0;
+
+                       judge = btdm_1AntTdmaJudgement(padapter, pHalData->bt_coexist.halCoex8723.btRetryCnt);
+                       if (judge == -1) {
+                               if (pBtdm8723->curPsTdma == 1) {
+                                       /*  Decrease WiFi duration for high BT retry */
+                                       if (pHalData->bt_coexist.halCoex8723.btInfoExt)
+                                               pBtdm8723->psTdmaDuAdjType = 9;
+                                       else
+                                               pBtdm8723->psTdmaDuAdjType = 2;
+                                       btdm_1AntSetPSTDMA(padapter, true, 0, true, pBtdm8723->psTdmaDuAdjType);
+                               } else if (pBtdm8723->curPsTdma == 2) {
+                                       btdm_1AntSetPSTDMA(padapter, true, 0, true, 9);
+                                       pBtdm8723->psTdmaDuAdjType = 9;
+                               } else if (pBtdm8723->curPsTdma == 9) {
+                                       btdm_1AntSetPSTDMA(padapter, true, 0, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               }
+                       } else if (judge == 1) {
+                               if (pBtdm8723->curPsTdma == 11) {
+                                       btdm_1AntSetPSTDMA(padapter, true, 0, true, 9);
+                                       pBtdm8723->psTdmaDuAdjType = 9;
+                               } else if (pBtdm8723->curPsTdma == 9) {
+                                       if (pHalData->bt_coexist.halCoex8723.btInfoExt)
+                                               pBtdm8723->psTdmaDuAdjType = 9;
+                                       else
+                                               pBtdm8723->psTdmaDuAdjType = 2;
+                                       btdm_1AntSetPSTDMA(padapter, true, 0, true, pBtdm8723->psTdmaDuAdjType);
+                               } else if (pBtdm8723->curPsTdma == 2) {
+                                       if (pHalData->bt_coexist.halCoex8723.btInfoExt)
+                                               pBtdm8723->psTdmaDuAdjType = 9;
+                                       else
+                                               pBtdm8723->psTdmaDuAdjType = 1;
+                                       btdm_1AntSetPSTDMA(padapter, true, 0, true, pBtdm8723->psTdmaDuAdjType);
+                               }
+                       }
+               }
+               RTPRINT(FBT, BT_TRACE,
+                       ("[BTCoex], ACL current TDMA(%s, %d)\n",
+                       (pBtdm8723->bCurPsTdmaOn ? "ON" : "OFF"), pBtdm8723->curPsTdma));
+       }
+       pBtdm8723->psTdmaMonitorCnt++;
+}
+
+static void btdm_1AntCoexProcessForWifiConnect(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv;
+       struct hal_data_8723a *pHalData;
+       struct bt_coexist_8723a *pBtCoex;
+       struct btdm_8723a_1ant *pBtdm8723;
+       u8 BtState;
+
+       pmlmepriv = &padapter->mlmepriv;
+       pHalData = GET_HAL_DATA(padapter);
+       pBtCoex = &pHalData->bt_coexist.halCoex8723;
+       pBtdm8723 = &pBtCoex->btdm1Ant;
+       BtState = pBtCoex->c2hBtInfo;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], WiFi is %s\n", BTDM_IsWifiBusy(padapter)?"Busy":"IDLE"));
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is %s\n", BtStateString[BtState]));
+
+       padapter->pwrctrlpriv.btcoex_rfon = false;
+
+       if ((!BTDM_IsWifiBusy(padapter)) && (!check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE)) &&
+           ((BtState == BT_INFO_STATE_NO_CONNECTION) || (BtState == BT_INFO_STATE_CONNECT_IDLE))) {
+               switch (BtState) {
+               case BT_INFO_STATE_NO_CONNECTION:
+                       _btdm_1AntSetPSTDMA(padapter, true, 2, 0x26, false, 9);
+                       break;
+               case BT_INFO_STATE_CONNECT_IDLE:
+                       _btdm_1AntSetPSTDMA(padapter, true, 2, 0x26, false, 0);
+                       break;
+               }
+       } else {
+               switch (BtState) {
+               case BT_INFO_STATE_NO_CONNECTION:
+               case BT_INFO_STATE_CONNECT_IDLE:
+                       /*  WiFi is Busy */
+                       btdm_1AntSetPSTDMA(padapter, false, 0, true, 5);
+                       rtw_write32(padapter, 0x6c0, 0x5a5a5a5a);
+                       rtw_write32(padapter, 0x6c4, 0x5a5a5a5a);
+                       break;
+               case BT_INFO_STATE_ACL_INQ_OR_PAG:
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is BT_INFO_STATE_ACL_INQ_OR_PAG\n"));
+               case BT_INFO_STATE_INQ_OR_PAG:
+                       padapter->pwrctrlpriv.btcoex_rfon = true;
+                       btdm_1AntSetPSTDMA(padapter, true, 0, true, 30);
+                       break;
+               case BT_INFO_STATE_SCO_ONLY_BUSY:
+               case BT_INFO_STATE_ACL_SCO_BUSY:
+                       if (true == pBtCoex->bC2hBtInquiryPage) {
+                               btdm_1AntSetPSTDMA(padapter, false, 0, true, 32);
+                       } else {
+#ifdef BTCOEX_CMCC_TEST
+                               btdm_1AntSetPSTDMA(padapter, false, 0, true, 23);
+#else /*  !BTCOEX_CMCC_TEST */
+                               btdm_1AntSetPSTDMA(padapter, false, 0, false, 8);
+                               rtw_write32(padapter, 0x6c0, 0x5a5a5a5a);
+                               rtw_write32(padapter, 0x6c4, 0x5a5a5a5a);
+#endif /*  !BTCOEX_CMCC_TEST */
+                       }
+                       break;
+               case BT_INFO_STATE_ACL_ONLY_BUSY:
+                       padapter->pwrctrlpriv.btcoex_rfon = true;
+                       if (pBtCoex->c2hBtProfile == BT_INFO_HID) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is HID\n"));
+                               btdm_1AntSetPSTDMA(padapter, true, 0, true, 31);
+                       } else if (pBtCoex->c2hBtProfile == BT_INFO_FTP) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is FTP/OPP\n"));
+                               btdm_1AntSetPSTDMA(padapter, true, 0, true, 3);
+                       } else if (pBtCoex->c2hBtProfile == (BT_INFO_A2DP|BT_INFO_FTP)) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is A2DP_FTP\n"));
+                               btdm_1AntSetPSTDMA(padapter, true, 0, true, 11);
+                       } else {
+                               if (pBtCoex->c2hBtProfile == BT_INFO_A2DP)
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is A2DP\n"));
+                               else
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT PROFILE is UNKNOWN(0x%02X)! Use A2DP Profile\n", pBtCoex->c2hBtProfile));
+                               btdm_1AntTdmaDurationAdjustForACL(padapter);
+                       }
+                       break;
+               }
+       }
+
+       pBtdm8723->psTdmaGlobalCnt++;
+}
+
+static void btdm_1AntUpdateHalRAMask(struct rtw_adapter *padapter, u32 mac_id, u32 filter)
+{
+       u8 init_rate = 0;
+       u8 raid;
+       u32 mask;
+       u8 shortGIrate = false;
+       int     supportRateNum = 0;
+       struct sta_info *psta;
+       struct hal_data_8723a *pHalData;
+       struct dm_priv *pdmpriv;
+       struct mlme_ext_priv *pmlmeext;
+       struct mlme_ext_info *pmlmeinfo;
+       struct wlan_bssid_ex *cur_network;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, MACID =%d, filter = 0x%08x!!\n", __func__, mac_id, filter));
+
+       pHalData = GET_HAL_DATA(padapter);
+       pdmpriv = &pHalData->dmpriv;
+       pmlmeext = &padapter->mlmeextpriv;
+       pmlmeinfo = &pmlmeext->mlmext_info;
+       cur_network = &pmlmeinfo->network;
+
+       if (mac_id >= NUM_STA) { /* CAM_SIZE */
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, MACID =%d illegal!!\n", __func__, mac_id));
+               return;
+       }
+
+       psta = pmlmeinfo->FW_sta_info[mac_id].psta;
+       if (psta == NULL) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], %s, Can't find station!!\n", __func__));
+               return;
+       }
+
+       raid = psta->raid;
+
+       switch (mac_id) {
+       case 0:/*  for infra mode */
+               supportRateNum = rtw_get_rateset_len23a(cur_network->SupportedRates);
+               mask = update_supported_rate23a(cur_network->SupportedRates, supportRateNum);
+               mask |= (pmlmeinfo->HT_enable) ? update_MSC_rate23a(&pmlmeinfo->HT_caps):0;
+               if (support_short_GI23a(padapter, &pmlmeinfo->HT_caps))
+                       shortGIrate = true;
+               break;
+       case 1:/* for broadcast/multicast */
+               supportRateNum = rtw_get_rateset_len23a(pmlmeinfo->FW_sta_info[mac_id].SupportedRates);
+               mask = update_basic_rate23a(cur_network->SupportedRates, supportRateNum);
+               break;
+       default: /* for each sta in IBSS */
+               supportRateNum = rtw_get_rateset_len23a(pmlmeinfo->FW_sta_info[mac_id].SupportedRates);
+               mask = update_supported_rate23a(cur_network->SupportedRates, supportRateNum);
+               break;
+       }
+       mask |= ((raid<<28)&0xf0000000);
+       mask &= 0xffffffff;
+       mask &= ~filter;
+       init_rate = get_highest_rate_idx23a(mask)&0x3f;
+
+       if (pHalData->fw_ractrl) {
+               u8 arg = 0;
+
+               arg = mac_id&0x1f;/* MACID */
+               arg |= BIT(7);
+               if (true == shortGIrate)
+                       arg |= BIT(5);
+
+               RTPRINT(FBT, BT_TRACE,
+                       ("[BTCoex], Update FW RAID entry, MASK = 0x%08x, arg = 0x%02x\n",
+                       mask, arg));
+
+               rtl8723a_set_raid_cmd(padapter, mask, arg);
+       } else {
+               if (shortGIrate)
+                       init_rate |= BIT(6);
+
+               rtw_write8(padapter, (REG_INIDATA_RATE_SEL+mac_id), init_rate);
+       }
+
+       psta->init_rate = init_rate;
+       pdmpriv->INIDATA_RATE[mac_id] = init_rate;
+}
+
+static void btdm_1AntUpdateHalRAMaskForSCO(struct rtw_adapter *padapter, u8 forceUpdate)
+{
+       struct btdm_8723a_1ant *pBtdm8723;
+       struct sta_priv *pstapriv;
+       struct wlan_bssid_ex *cur_network;
+       struct sta_info *psta;
+       u32 macid;
+       u32 filter = 0;
+
+       pBtdm8723 = &GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant;
+
+       if ((pBtdm8723->bRAChanged == true) && (forceUpdate == false))
+               return;
+
+       pstapriv = &padapter->stapriv;
+       cur_network = &padapter->mlmeextpriv.mlmext_info.network;
+       psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress);
+       macid = psta->mac_id;
+
+       filter |= BIT(_1M_RATE_);
+       filter |= BIT(_2M_RATE_);
+       filter |= BIT(_5M_RATE_);
+       filter |= BIT(_11M_RATE_);
+       filter |= BIT(_6M_RATE_);
+       filter |= BIT(_9M_RATE_);
+
+       btdm_1AntUpdateHalRAMask(padapter, macid, filter);
+
+       pBtdm8723->bRAChanged = true;
+}
+
+static void btdm_1AntRecoverHalRAMask(struct rtw_adapter *padapter)
+{
+       struct btdm_8723a_1ant *pBtdm8723;
+       struct sta_priv *pstapriv;
+       struct wlan_bssid_ex *cur_network;
+       struct sta_info *psta;
+
+       pBtdm8723 = &GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant;
+
+       if (pBtdm8723->bRAChanged == false)
+               return;
+
+       pstapriv = &padapter->stapriv;
+       cur_network = &padapter->mlmeextpriv.mlmext_info.network;
+       psta = rtw_get_stainfo23a(pstapriv, cur_network->MacAddress);
+
+       Update_RA_Entry23a(padapter, psta);
+
+       pBtdm8723->bRAChanged = false;
+}
+
+static void
+btdm_1AntBTStateChangeHandler(struct rtw_adapter *padapter,
+                             enum bt_state_1ant oldState, enum bt_state_1ant newState)
+{
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT state change, %s => %s\n", BtStateString[oldState], BtStateString[newState]));
+
+       /*  BT default ignore wlan active, */
+       /*  WiFi MUST disable this when BT is enable */
+       if (newState > BT_INFO_STATE_DISABLED)
+               btdm_SetFwIgnoreWlanAct(padapter, false);
+
+       if ((check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) &&
+           (BTDM_IsWifiConnectionExist(padapter))) {
+               if ((newState == BT_INFO_STATE_SCO_ONLY_BUSY) ||
+                   (newState == BT_INFO_STATE_ACL_SCO_BUSY)) {
+                       btdm_1AntUpdateHalRAMaskForSCO(padapter, false);
+               } else {
+                       /*  Recover original RA setting */
+                       btdm_1AntRecoverHalRAMask(padapter);
+               }
+       } else {
+               GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bRAChanged = false;
+       }
+
+       if (oldState == newState)
+               return;
+
+       if (oldState == BT_INFO_STATE_ACL_ONLY_BUSY) {
+               struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+               pHalData->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCnt = 0;
+               pHalData->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCntForSCO = 0;
+       }
+
+       if ((oldState == BT_INFO_STATE_SCO_ONLY_BUSY) ||
+           (oldState == BT_INFO_STATE_ACL_SCO_BUSY)) {
+               struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+               pHalData->bt_coexist.halCoex8723.btdm1Ant.psTdmaMonitorCntForSCO = 0;
+       }
+
+       /*  Active 2Ant mechanism when BT Connected */
+       if ((oldState == BT_INFO_STATE_DISABLED) ||
+           (oldState == BT_INFO_STATE_NO_CONNECTION)) {
+               if ((newState != BT_INFO_STATE_DISABLED) &&
+                   (newState != BT_INFO_STATE_NO_CONNECTION)) {
+                       BTDM_SetSwRfRxLpfCorner(padapter, BT_RF_RX_LPF_CORNER_SHRINK);
+                       BTDM_AGCTable(padapter, BT_AGCTABLE_ON);
+                       BTDM_BBBackOffLevel(padapter, BT_BB_BACKOFF_ON);
+               }
+       } else {
+               if ((newState == BT_INFO_STATE_DISABLED) ||
+                   (newState == BT_INFO_STATE_NO_CONNECTION)) {
+                       BTDM_SetSwRfRxLpfCorner(padapter, BT_RF_RX_LPF_CORNER_RESUME);
+                       BTDM_AGCTable(padapter, BT_AGCTABLE_OFF);
+                       BTDM_BBBackOffLevel(padapter, BT_BB_BACKOFF_OFF);
+               }
+       }
+}
+
+static void btdm_1AntBtCoexistHandler(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_coexist_8723a *pBtCoex8723;
+       struct btdm_8723a_1ant *pBtdm8723;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBtCoex8723 = &pHalData->bt_coexist.halCoex8723;
+       pBtdm8723 = &pBtCoex8723->btdm1Ant;
+       padapter->pwrctrlpriv.btcoex_rfon = false;
+       if (BT_IsBtDisabled(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is disabled\n"));
+
+               if (BTDM_IsWifiConnectionExist(padapter)) {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is connected\n"));
+
+                       if (BTDM_IsWifiBusy(padapter)) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Wifi is busy\n"));
+                               btdm_1AntSetPSTDMA(padapter, false, 0, false, 9);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Wifi is idle\n"));
+                               _btdm_1AntSetPSTDMA(padapter, true, 2, 1, false, 9);
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is disconnected\n"));
+
+                       btdm_1AntSetPSTDMA(padapter, false, 0, false, 9);
+               }
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT is enabled\n"));
+
+               if (BTDM_IsWifiConnectionExist(padapter)) {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is connected\n"));
+
+                       btdm_1AntWifiParaAdjust(padapter, true);
+                       btdm_1AntCoexProcessForWifiConnect(padapter);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is disconnected\n"));
+
+                       /*  Antenna switch at BT side(0x870 = 0x300, 0x860 = 0x210) after PSTDMA off */
+                       btdm_1AntWifiParaAdjust(padapter, false);
+                       btdm_1AntSetPSTDMA(padapter, false, 0, false, 0);
+               }
+       }
+
+       btdm_1AntBTStateChangeHandler(padapter, pBtCoex8723->prec2hBtInfo, pBtCoex8723->c2hBtInfo);
+       pBtCoex8723->prec2hBtInfo = pBtCoex8723->c2hBtInfo;
+}
+
+void BTDM_1AntSignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi, u8 *rssi_bt)
+{
+       struct hal_data_8723a *pHalData;
+       struct btdm_8723a_1ant *pBtdm8723;
+       u8 RSSI_WiFi_Cmpnstn, RSSI_BT_Cmpnstn;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm1Ant;
+       RSSI_WiFi_Cmpnstn = 0;
+       RSSI_BT_Cmpnstn = 0;
+
+       switch (pBtdm8723->curPsTdma) {
+       case 1: /*  WiFi 52ms */
+               RSSI_WiFi_Cmpnstn = 11; /*  22*0.48 */
+               break;
+       case 2: /*  WiFi 36ms */
+               RSSI_WiFi_Cmpnstn = 14; /*  22*0.64 */
+               break;
+       case 9: /*  WiFi 20ms */
+               RSSI_WiFi_Cmpnstn = 18; /*  22*0.80 */
+               break;
+       case 11: /*  WiFi 10ms */
+               RSSI_WiFi_Cmpnstn = 20; /*  22*0.90 */
+               break;
+       case 4: /*  WiFi 21ms */
+               RSSI_WiFi_Cmpnstn = 17; /*  22*0.79 */
+               break;
+       case 16: /*  WiFi 24ms */
+               RSSI_WiFi_Cmpnstn = 18; /*  22*0.76 */
+               break;
+       case 18: /*  WiFi 37ms */
+               RSSI_WiFi_Cmpnstn = 14; /*  22*0.64 */
+               break;
+       case 23: /* Level-1, Antenna switch to BT at all time */
+       case 24: /* Level-2, Antenna switch to BT at all time */
+       case 25: /* Level-3a, Antenna switch to BT at all time */
+       case 26: /* Level-3b, Antenna switch to BT at all time */
+       case 27: /* Level-3b, Antenna switch to BT at all time */
+       case 33: /* BT SCO & WiFi site survey */
+               RSSI_WiFi_Cmpnstn = 22;
+               break;
+       default:
+               break;
+       }
+
+       if (rssi_wifi && RSSI_WiFi_Cmpnstn) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1AntSgnlCmpnstn, case %d, WiFiCmpnstn =%d(%d => %d)\n",
+                               pBtdm8723->curPsTdma, RSSI_WiFi_Cmpnstn, *rssi_wifi, *rssi_wifi+RSSI_WiFi_Cmpnstn));
+               *rssi_wifi += RSSI_WiFi_Cmpnstn;
+       }
+
+       if (rssi_bt && RSSI_BT_Cmpnstn) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1AntSgnlCmpnstn, case %d, BTCmpnstn =%d(%d => %d)\n",
+                               pBtdm8723->curPsTdma, RSSI_BT_Cmpnstn, *rssi_bt, *rssi_bt+RSSI_BT_Cmpnstn));
+               *rssi_bt += RSSI_BT_Cmpnstn;
+       }
+}
+
+static void BTDM_1AntParaInit(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_coexist_8723a *pBtCoex;
+       struct btdm_8723a_1ant *pBtdm8723;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBtCoex = &pHalData->bt_coexist.halCoex8723;
+       pBtdm8723 = &pBtCoex->btdm1Ant;
+
+       /*  Enable counter statistics */
+       rtw_write8(padapter, 0x76e, 0x4);
+       btdm_1AntPtaParaReload(padapter);
+
+       pBtdm8723->wifiRssiThresh = 48;
+
+       pBtdm8723->bWiFiHalt = false;
+       pBtdm8723->bRAChanged = false;
+
+       if ((pBtCoex->c2hBtInfo != BT_INFO_STATE_DISABLED) &&
+           (pBtCoex->c2hBtInfo != BT_INFO_STATE_NO_CONNECTION)) {
+               BTDM_SetSwRfRxLpfCorner(padapter, BT_RF_RX_LPF_CORNER_SHRINK);
+               BTDM_AGCTable(padapter, BT_AGCTABLE_ON);
+               BTDM_BBBackOffLevel(padapter, BT_BB_BACKOFF_ON);
+       }
+}
+
+static void BTDM_1AntForHalt(struct rtw_adapter *padapter)
+{
+       RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for halt\n"));
+
+       GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bWiFiHalt = true;
+
+       btdm_1AntWifiParaAdjust(padapter, false);
+
+       /*  don't use btdm_1AntSetPSTDMA() here */
+       /*  it will call rtw_set_ps_mode23a() and request pwrpriv->lock. */
+       /*  This will lead to deadlock, if this function is called in IPS */
+       /*  Lucas@20130205 */
+       btdm_1AntPsTdma(padapter, false, 0);
+
+       btdm_SetFwIgnoreWlanAct(padapter, true);
+}
+
+static void BTDM_1AntLpsLeave(struct rtw_adapter *padapter)
+{
+       RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for LPS Leave\n"));
+
+       /*  Prevent from entering LPS again */
+       GET_HAL_DATA(padapter)->bt_coexist.halCoex8723.btdm1Ant.bWiFiHalt = true;
+
+       btdm_1AntSetPSTDMA(padapter, false, 0, false, 8);
+/*btdm_1AntPsTdma(padapter, false, 8); */
+}
+
+static void BTDM_1AntWifiAssociateNotify(struct rtw_adapter *padapter, u8 type)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for associate, type =%d\n", type));
+
+       if (type) {
+               rtl8723a_CheckAntenna_Selection(padapter);
+               if (BT_IsBtDisabled(padapter)) {
+                       btdm_1AntSetPSTDMA(padapter, false, 0, false, 9);
+               } else {
+                       struct bt_coexist_8723a *pBtCoex;
+                       u8 BtState;
+
+                       pBtCoex = &pHalData->bt_coexist.halCoex8723;
+                       BtState = pBtCoex->c2hBtInfo;
+
+                       btdm_1AntTSFSwitch(padapter, true);
+
+                       if ((BtState == BT_INFO_STATE_NO_CONNECTION) ||
+                           (BtState == BT_INFO_STATE_CONNECT_IDLE)) {
+                               btdm_1AntSetPSTDMA(padapter, false, 0, true, 28);
+                       } else if ((BtState == BT_INFO_STATE_SCO_ONLY_BUSY) ||
+                                  (BtState == BT_INFO_STATE_ACL_SCO_BUSY)) {
+                               btdm_1AntSetPSTDMA(padapter, false, 0, false, 8);
+                               rtw_write32(padapter, 0x6c0, 0x5a5a5a5a);
+                               rtw_write32(padapter, 0x6c4, 0x5a5a5a5a);
+                       } else if ((BtState == BT_INFO_STATE_ACL_ONLY_BUSY) ||
+                                  (BtState == BT_INFO_STATE_ACL_INQ_OR_PAG)) {
+                               if (pBtCoex->c2hBtProfile == BT_INFO_HID)
+                                       btdm_1AntSetPSTDMA(padapter, false, 0, true, 35);
+                               else
+                                       btdm_1AntSetPSTDMA(padapter, false, 0, true, 29);
+                       }
+               }
+       } else {
+               if (BT_IsBtDisabled(padapter)) {
+                       if (!BTDM_IsWifiConnectionExist(padapter)) {
+                               btdm_1AntPsTdma(padapter, false, 0);
+                               btdm_1AntTSFSwitch(padapter, false);
+                       }
+               }
+
+               btdm_1AntBtCoexistHandler(padapter);
+       }
+}
+
+static void
+BTDM_1AntMediaStatusNotify(struct rtw_adapter *padapter,
+                          enum rt_media_status mstatus)
+{
+       struct bt_coexist_8723a *pBtCoex;
+
+       pBtCoex = &GET_HAL_DATA(padapter)->bt_coexist.halCoex8723;
+
+       RTPRINT(FBT, BT_TRACE, ("\n\n[BTCoex]******************************\n"));
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], MediaStatus, WiFi %s !!\n",
+                       mstatus == RT_MEDIA_CONNECT?"CONNECT":"DISCONNECT"));
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex]******************************\n"));
+
+       if (RT_MEDIA_CONNECT == mstatus) {
+               if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) {
+                       if ((pBtCoex->c2hBtInfo == BT_INFO_STATE_SCO_ONLY_BUSY) ||
+                           (pBtCoex->c2hBtInfo == BT_INFO_STATE_ACL_SCO_BUSY))
+                               btdm_1AntUpdateHalRAMaskForSCO(padapter, true);
+               }
+
+               padapter->pwrctrlpriv.DelayLPSLastTimeStamp = jiffies;
+               BTDM_1AntForDhcp(padapter);
+       } else {
+               /* DBG_8723A("%s rtl8723a_DeinitAntenna_Selection\n", __func__); */
+               rtl8723a_DeinitAntenna_Selection(padapter);
+               btdm_1AntBtCoexistHandler(padapter);
+               pBtCoex->btdm1Ant.bRAChanged = false;
+       }
+}
+
+void BTDM_1AntForDhcp(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       u8 BtState;
+       struct bt_coexist_8723a *pBtCoex;
+       struct btdm_8723a_1ant *pBtdm8723;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBtCoex = &pHalData->bt_coexist.halCoex8723;
+       BtState = pBtCoex->c2hBtInfo;
+       pBtdm8723 = &pBtCoex->btdm1Ant;
+
+       RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for DHCP\n"));
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for DHCP, WiFi is %s\n", BTDM_IsWifiBusy(padapter)?"Busy":"IDLE"));
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for DHCP, %s\n", BtStateString[BtState]));
+
+       BTDM_1AntWifiAssociateNotify(padapter, true);
+}
+
+static void BTDM_1AntWifiScanNotify(struct rtw_adapter *padapter, u8 scanType)
+{
+       struct hal_data_8723a *pHalData;
+       u8 BtState;
+       struct bt_coexist_8723a *pBtCoex;
+       struct btdm_8723a_1ant *pBtdm8723;
+
+       pHalData = GET_HAL_DATA(padapter);
+       BtState = pHalData->bt_coexist.halCoex8723.c2hBtInfo;
+       pBtCoex = &pHalData->bt_coexist.halCoex8723;
+       pBtdm8723 = &pBtCoex->btdm1Ant;
+
+       RTPRINT(FBT, BT_TRACE, ("\n[BTCoex], 1Ant for wifi scan =%d!!\n", scanType));
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for wifi scan, WiFi is %s\n", BTDM_IsWifiBusy(padapter)?"Busy":"IDLE"));
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1Ant for wifi scan, %s\n", BtStateString[BtState]));
+
+       if (scanType) {
+               rtl8723a_CheckAntenna_Selection(padapter);
+               if (BT_IsBtDisabled(padapter)) {
+                       btdm_1AntSetPSTDMA(padapter, false, 0, false, 9);
+               } else if (BTDM_IsWifiConnectionExist(padapter) == false) {
+                       BTDM_1AntWifiAssociateNotify(padapter, true);
+               } else {
+                       if ((BtState == BT_INFO_STATE_SCO_ONLY_BUSY) ||
+                           (BtState == BT_INFO_STATE_ACL_SCO_BUSY)) {
+                               if (pBtCoex->bC2hBtInquiryPage) {
+                                       btdm_1AntSetPSTDMA(padapter, false, 0, true, 32);
+                               } else {
+                                       padapter->pwrctrlpriv.btcoex_rfon = true;
+                                       btdm_1AntSetPSTDMA(padapter, true, 0, true, 33);
+                               }
+                       } else if (true == pBtCoex->bC2hBtInquiryPage) {
+                               padapter->pwrctrlpriv.btcoex_rfon = true;
+                               btdm_1AntSetPSTDMA(padapter, true, 0, true, 30);
+                       } else if (BtState == BT_INFO_STATE_ACL_ONLY_BUSY) {
+                               padapter->pwrctrlpriv.btcoex_rfon = true;
+                               if (pBtCoex->c2hBtProfile == BT_INFO_HID)
+                                       btdm_1AntSetPSTDMA(padapter, true, 0, true, 34);
+                               else
+                                       btdm_1AntSetPSTDMA(padapter, true, 0, true, 4);
+                       } else {
+                               padapter->pwrctrlpriv.btcoex_rfon = true;
+                               btdm_1AntSetPSTDMA(padapter, true, 0, true, 5);
+                       }
+               }
+
+               btdm_NotifyFwScan(padapter, 1);
+       } else {
+               /*  WiFi_Finish_Scan */
+               btdm_NotifyFwScan(padapter, 0);
+               btdm_1AntBtCoexistHandler(padapter);
+       }
+}
+
+static void BTDM_1AntFwC2hBtInfo8723A(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_coexist_8723a *pBtCoex;
+       u8 u1tmp, btState;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtCoex = &pHalData->bt_coexist.halCoex8723;
+
+       u1tmp = pBtCoex->c2hBtInfoOriginal;
+       /*  sco BUSY bit is not used on voice over PCM platform */
+       btState = u1tmp & 0xF;
+       pBtCoex->c2hBtProfile = u1tmp & 0xE0;
+
+       /*  default set bt to idle state. */
+       pBtMgnt->ExtConfig.bBTBusy = false;
+       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_IDLE;
+
+       /*  check BIT2 first ==> check if bt is under inquiry or page scan */
+       if (btState & BIT(2))
+               pBtCoex->bC2hBtInquiryPage = true;
+       else
+               pBtCoex->bC2hBtInquiryPage = false;
+       btState &= ~BIT(2);
+
+       if (!(btState & BIT(0))) {
+               pBtCoex->c2hBtInfo = BT_INFO_STATE_NO_CONNECTION;
+       } else {
+               if (btState == 0x1) {
+                       pBtCoex->c2hBtInfo = BT_INFO_STATE_CONNECT_IDLE;
+               } else if (btState == 0x9) {
+                       if (pBtCoex->bC2hBtInquiryPage == true)
+                               pBtCoex->c2hBtInfo = BT_INFO_STATE_ACL_INQ_OR_PAG;
+                       else
+                               pBtCoex->c2hBtInfo = BT_INFO_STATE_ACL_ONLY_BUSY;
+                       pBtMgnt->ExtConfig.bBTBusy = true;
+               } else if (btState == 0x3) {
+                       pBtCoex->c2hBtInfo = BT_INFO_STATE_SCO_ONLY_BUSY;
+                       pBtMgnt->ExtConfig.bBTBusy = true;
+               } else if (btState == 0xb) {
+                       pBtCoex->c2hBtInfo = BT_INFO_STATE_ACL_SCO_BUSY;
+                       pBtMgnt->ExtConfig.bBTBusy = true;
+               } else {
+                       pBtCoex->c2hBtInfo = BT_INFO_STATE_MAX;
+               }
+               if (pBtMgnt->ExtConfig.bBTBusy)
+                       pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_IDLE;
+       }
+
+       if ((BT_INFO_STATE_NO_CONNECTION == pBtCoex->c2hBtInfo) ||
+           (BT_INFO_STATE_CONNECT_IDLE == pBtCoex->c2hBtInfo)) {
+               if (pBtCoex->bC2hBtInquiryPage)
+                       pBtCoex->c2hBtInfo = BT_INFO_STATE_INQ_OR_PAG;
+       }
+
+       RTPRINT(FBT, BT_TRACE, ("[BTC2H], %s(%d)\n",
+                       BtStateString[pBtCoex->c2hBtInfo], pBtCoex->c2hBtInfo));
+
+       if (pBtCoex->c2hBtProfile != BT_INFO_HID)
+               pBtCoex->c2hBtProfile &= ~BT_INFO_HID;
+}
+
+void BTDM_1AntBtCoexist8723A(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv;
+       struct hal_data_8723a *pHalData;
+       unsigned long delta_time;
+
+       pmlmepriv = &padapter->mlmepriv;
+       pHalData = GET_HAL_DATA(padapter);
+
+       if (check_fwstate(pmlmepriv, WIFI_SITE_MONITOR)) {
+               /*  already done in BTDM_1AntForScan() */
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is under scan progress!!\n"));
+               return;
+       }
+
+       if (check_fwstate(pmlmepriv, WIFI_UNDER_LINKING)) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is under link progress!!\n"));
+               return;
+       }
+
+       /*  under DHCP(Special packet) */
+       delta_time = jiffies - padapter->pwrctrlpriv.DelayLPSLastTimeStamp;
+       delta_time = jiffies_to_msecs(delta_time);
+       if (delta_time < 500) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], wifi is under DHCP "
+                                       "progress(%li ms)!!\n", delta_time));
+               return;
+       }
+
+       BTDM_CheckWiFiState(padapter);
+
+       btdm_1AntBtCoexistHandler(padapter);
+}
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.c ===== */
+#endif
+
+#ifdef __HALBTC87232ANT_C__ /*  HAL/BTCoexist/HalBtc87232Ant.c */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.c ===== */
+
+/*  local function start with btdm_ */
+static u8 btdm_ActionAlgorithm(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+       u8 bScoExist = false, bBtLinkExist = false, bBtHsModeExist = false;
+       u8 algorithm = BT_2ANT_COEX_ALGO_UNDEFINED;
+
+       if (pBtMgnt->ExtConfig.NumberOfHandle)
+               bBtLinkExist = true;
+       if (pBtMgnt->ExtConfig.NumberOfSCO)
+               bScoExist = true;
+       if (BT_HsConnectionEstablished(padapter))
+               bBtHsModeExist = true;
+
+       /*  here we get BT status first */
+       /*  1) initialize */
+       pBtdm8723->btStatus = BT_2ANT_BT_STATUS_IDLE;
+
+       if ((bScoExist) || (bBtHsModeExist) ||
+           (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID))) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO or HID or HS exists, set BT non-idle !!!\n"));
+               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE;
+       } else {
+               /*  A2dp profile */
+               if ((pBtMgnt->ExtConfig.NumberOfHandle == 1) &&
+                   (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP))) {
+                       if (BTDM_BtTxRxCounterL(padapter) < 100) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP, low priority tx+rx < 100, set BT connected-idle!!!\n"));
+                               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE;
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP, low priority tx+rx >= 100, set BT non-idle!!!\n"));
+                               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE;
+                       }
+               }
+               /*  Pan profile */
+               if ((pBtMgnt->ExtConfig.NumberOfHandle == 1) &&
+                   (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN))) {
+                       if (BTDM_BtTxRxCounterL(padapter) < 600) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN, low priority tx+rx < 600, set BT connected-idle!!!\n"));
+                               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE;
+                       } else {
+                               if (pHalData->bt_coexist.halCoex8723.lowPriorityTx) {
+                                       if ((pHalData->bt_coexist.halCoex8723.lowPriorityRx /
+                                           pHalData->bt_coexist.halCoex8723.lowPriorityTx) > 9) {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN, low priority rx/tx > 9, set BT connected-idle!!!\n"));
+                                               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE;
+                                       }
+                               }
+                       }
+                       if (BT_2ANT_BT_STATUS_CONNECTED_IDLE != pBtdm8723->btStatus) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN, set BT non-idle!!!\n"));
+                               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE;
+                       }
+               }
+               /*  Pan+A2dp profile */
+               if ((pBtMgnt->ExtConfig.NumberOfHandle == 2) &&
+                   (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) &&
+                   (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN))) {
+                       if (BTDM_BtTxRxCounterL(padapter) < 600) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN+A2DP, low priority tx+rx < 600, set BT connected-idle!!!\n"));
+                               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE;
+                       } else {
+                               if (pHalData->bt_coexist.halCoex8723.lowPriorityTx) {
+                                       if ((pHalData->bt_coexist.halCoex8723.lowPriorityRx /
+                                           pHalData->bt_coexist.halCoex8723.lowPriorityTx) > 9) {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN+A2DP, low priority rx/tx > 9, set BT connected-idle!!!\n"));
+                                               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE;
+                                       }
+                               }
+                       }
+                       if (BT_2ANT_BT_STATUS_CONNECTED_IDLE != pBtdm8723->btStatus) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN+A2DP, set BT non-idle!!!\n"));
+                               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE;
+                       }
+               }
+       }
+       if (BT_2ANT_BT_STATUS_IDLE != pBtdm8723->btStatus)
+               pBtMgnt->ExtConfig.bBTBusy = true;
+       else
+               pBtMgnt->ExtConfig.bBTBusy = false;
+
+       if (!bBtLinkExist) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], No profile exists!!!\n"));
+               return algorithm;
+       }
+
+       if (pBtMgnt->ExtConfig.NumberOfHandle == 1) {
+               if (bScoExist) {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO only\n"));
+                       algorithm = BT_2ANT_COEX_ALGO_SCO;
+               } else {
+                       if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID)) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID only\n"));
+                               algorithm = BT_2ANT_COEX_ALGO_HID;
+                       } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP only\n"));
+                               algorithm = BT_2ANT_COEX_ALGO_A2DP;
+                       } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) {
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN(HS) only\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_PANHS;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN(EDR) only\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_PANEDR;
+                               }
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! NO matched profile for NumberOfHandle =%d \n",
+                               pBtMgnt->ExtConfig.NumberOfHandle));
+                       }
+               }
+       } else if (pBtMgnt->ExtConfig.NumberOfHandle == 2) {
+               if (bScoExist) {
+                       if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID)) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + HID\n"));
+                               algorithm = BT_2ANT_COEX_ALGO_HID;
+                       } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + A2DP\n"));
+                       } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) {
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + PAN(HS)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_SCO;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + PAN(EDR)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID;
+                               }
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO exists but why NO matched ACL profile for NumberOfHandle =%d\n",
+                               pBtMgnt->ExtConfig.NumberOfHandle));
+                       }
+               } else {
+                       if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) &&
+                           BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP\n"));
+                               algorithm = BT_2ANT_COEX_ALGO_HID_A2DP;
+               } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) &&
+                          BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) {
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(HS)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_HID_A2DP;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(EDR)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID;
+                               }
+                       } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) &&
+                                  BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(HS)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_A2DP;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_PANEDR_A2DP;
+                               }
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! NO matched profile for NumberOfHandle =%d\n",
+                                       pBtMgnt->ExtConfig.NumberOfHandle));
+                       }
+               }
+       } else if (pBtMgnt->ExtConfig.NumberOfHandle == 3) {
+               if (bScoExist) {
+                       if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) &&
+                           BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP\n"));
+                       } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) &&
+                                  BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) {
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + HID + PAN(HS)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_HID_A2DP;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + HID + PAN(EDR)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID;
+                               }
+                       } else if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) &&
+                                  BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + A2DP + PAN(HS)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_SCO;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + A2DP + PAN(EDR)\n"));
+                               }
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO exists but why NO matched profile for NumberOfHandle =%d\n",
+                                       pBtMgnt->ExtConfig.NumberOfHandle));
+                       }
+               } else {
+                       if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) &&
+                           BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) &&
+                           BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_HID_A2DP_PANHS;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+                               }
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! NO matched profile for NumberOfHandle =%d\n",
+                                       pBtMgnt->ExtConfig.NumberOfHandle));
+                       }
+               }
+       } else if (pBtMgnt->ExtConfig.NumberOfHandle >= 3) {
+               if (bScoExist) {
+                       if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) &&
+                           BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) &&
+                           BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                               if (bBtHsModeExist)
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(HS)\n"));
+                               else
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + HID + A2DP + PAN(EDR)\n"));
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO exists but why NO matched profile for NumberOfHandle =%d\n",
+                                       pBtMgnt->ExtConfig.NumberOfHandle));
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! NO matched profile for NumberOfHandle =%d\n",
+                               pBtMgnt->ExtConfig.NumberOfHandle));
+               }
+       }
+       return algorithm;
+}
+
+static u8 btdm_NeedToDecBtPwr(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 bRet = false;
+
+       if (BT_Operation(padapter)) {
+               if (pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB > 47) {
+                       RTPRINT(FBT, BT_TRACE, ("Need to decrease bt power for HS mode!!\n"));
+                       bRet = true;
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("NO Need to decrease bt power for HS mode!!\n"));
+               }
+       } else {
+               if (BTDM_IsWifiConnectionExist(padapter)) {
+                       RTPRINT(FBT, BT_TRACE, ("Need to decrease bt power for Wifi is connected!!\n"));
+                       bRet = true;
+               }
+       }
+       return bRet;
+}
+
+static void
+btdm_SetCoexTable(struct rtw_adapter *padapter, u32 val0x6c0,
+                 u32 val0x6c8, u8 val0x6cc)
+{
+       RTPRINT(FBT, BT_TRACE, ("set coex table, set 0x6c0 = 0x%x\n", val0x6c0));
+       rtw_write32(padapter, 0x6c0, val0x6c0);
+
+       RTPRINT(FBT, BT_TRACE, ("set coex table, set 0x6c8 = 0x%x\n", val0x6c8));
+       rtw_write32(padapter, 0x6c8, val0x6c8);
+
+       RTPRINT(FBT, BT_TRACE, ("set coex table, set 0x6cc = 0x%x\n", val0x6cc));
+       rtw_write8(padapter, 0x6cc, val0x6cc);
+}
+
+static void
+btdm_SetSwFullTimeDacSwing(struct rtw_adapter *padapter, u8 bSwDacSwingOn,
+                          u32 swDacSwingLvl)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (bSwDacSwingOn) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], SwDacSwing = 0x%x\n", swDacSwingLvl));
+               PHY_SetBBReg(padapter, 0x880, 0xff000000, swDacSwingLvl);
+               pHalData->bt_coexist.bSWCoexistAllOff = false;
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], SwDacSwing Off!\n"));
+               PHY_SetBBReg(padapter, 0x880, 0xff000000, 0xc0);
+       }
+}
+
+static void
+btdm_SetFwDacSwingLevel(struct rtw_adapter *padapter, u8 dacSwingLvl)
+{
+       u8 H2C_Parameter[1] = {0};
+
+       H2C_Parameter[0] = dacSwingLvl;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Set Dac Swing Level = 0x%x\n", dacSwingLvl));
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], write 0x29 = 0x%x\n", H2C_Parameter[0]));
+
+       FillH2CCmd(padapter, 0x29, 1, H2C_Parameter);
+}
+
+static void btdm_2AntDecBtPwr(struct rtw_adapter *padapter, u8 bDecBtPwr)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTCoex], Dec BT power = %s\n",
+               ((bDecBtPwr) ? "ON" : "OFF")));
+       pBtdm8723->bCurDecBtPwr = bDecBtPwr;
+
+       if (pBtdm8723->bPreDecBtPwr == pBtdm8723->bCurDecBtPwr)
+               return;
+
+       BTDM_SetFwDecBtPwr(padapter, pBtdm8723->bCurDecBtPwr);
+
+       pBtdm8723->bPreDecBtPwr = pBtdm8723->bCurDecBtPwr;
+}
+
+static void
+btdm_2AntFwDacSwingLvl(struct rtw_adapter *padapter, u8 fwDacSwingLvl)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], set FW Dac Swing level = %d\n",  fwDacSwingLvl));
+       pBtdm8723->curFwDacSwingLvl = fwDacSwingLvl;
+
+       /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], preFwDacSwingLvl =%d, curFwDacSwingLvl =%d\n", */
+       /*pBtdm8723->preFwDacSwingLvl, pBtdm8723->curFwDacSwingLvl)); */
+
+       if (pBtdm8723->preFwDacSwingLvl == pBtdm8723->curFwDacSwingLvl)
+               return;
+
+       btdm_SetFwDacSwingLevel(padapter, pBtdm8723->curFwDacSwingLvl);
+
+       pBtdm8723->preFwDacSwingLvl = pBtdm8723->curFwDacSwingLvl;
+}
+
+static void
+btdm_2AntRfShrink(struct rtw_adapter *padapter, u8 bRxRfShrinkOn)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTCoex], turn Rx RF Shrink = %s\n",
+               ((bRxRfShrinkOn) ? "ON" : "OFF")));
+       pBtdm8723->bCurRfRxLpfShrink = bRxRfShrinkOn;
+
+       /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], bPreRfRxLpfShrink =%d, bCurRfRxLpfShrink =%d\n", */
+       /*pBtdm8723->bPreRfRxLpfShrink, pBtdm8723->bCurRfRxLpfShrink)); */
+
+       if (pBtdm8723->bPreRfRxLpfShrink == pBtdm8723->bCurRfRxLpfShrink)
+               return;
+
+       BTDM_SetSwRfRxLpfCorner(padapter, (u8)pBtdm8723->bCurRfRxLpfShrink);
+
+       pBtdm8723->bPreRfRxLpfShrink = pBtdm8723->bCurRfRxLpfShrink;
+}
+
+static void
+btdm_2AntLowPenaltyRa(struct rtw_adapter *padapter, u8 bLowPenaltyRa)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTCoex], turn LowPenaltyRA = %s\n",
+               ((bLowPenaltyRa) ? "ON" : "OFF")));
+       pBtdm8723->bCurLowPenaltyRa = bLowPenaltyRa;
+
+       /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], bPreLowPenaltyRa =%d, bCurLowPenaltyRa =%d\n", */
+       /*pBtdm8723->bPreLowPenaltyRa, pBtdm8723->bCurLowPenaltyRa)); */
+
+       if (pBtdm8723->bPreLowPenaltyRa == pBtdm8723->bCurLowPenaltyRa)
+               return;
+
+       BTDM_SetSwPenaltyTxRateAdaptive(padapter, (u8)pBtdm8723->bCurLowPenaltyRa);
+
+       pBtdm8723->bPreLowPenaltyRa = pBtdm8723->bCurLowPenaltyRa;
+}
+
+static void
+btdm_2AntDacSwing(struct rtw_adapter *padapter,
+                 u8 bDacSwingOn, u32 dacSwingLvl)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTCoex], turn DacSwing =%s, dacSwingLvl = 0x%x\n",
+               (bDacSwingOn ? "ON" : "OFF"), dacSwingLvl));
+       pBtdm8723->bCurDacSwingOn = bDacSwingOn;
+       pBtdm8723->curDacSwingLvl = dacSwingLvl;
+
+       if ((pBtdm8723->bPreDacSwingOn == pBtdm8723->bCurDacSwingOn) &&
+           (pBtdm8723->preDacSwingLvl == pBtdm8723->curDacSwingLvl))
+               return;
+
+       mdelay(30);
+       btdm_SetSwFullTimeDacSwing(padapter, bDacSwingOn, dacSwingLvl);
+
+       pBtdm8723->bPreDacSwingOn = pBtdm8723->bCurDacSwingOn;
+       pBtdm8723->preDacSwingLvl = pBtdm8723->curDacSwingLvl;
+}
+
+static void btdm_2AntAdcBackOff(struct rtw_adapter *padapter, u8 bAdcBackOff)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTCoex], turn AdcBackOff = %s\n",
+               ((bAdcBackOff) ? "ON" : "OFF")));
+       pBtdm8723->bCurAdcBackOff = bAdcBackOff;
+
+       if (pBtdm8723->bPreAdcBackOff == pBtdm8723->bCurAdcBackOff)
+               return;
+
+       BTDM_BBBackOffLevel(padapter, (u8)pBtdm8723->bCurAdcBackOff);
+
+       pBtdm8723->bPreAdcBackOff = pBtdm8723->bCurAdcBackOff;
+}
+
+static void btdm_2AntAgcTable(struct rtw_adapter *padapter, u8 bAgcTableEn)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTCoex], %s Agc Table\n", ((bAgcTableEn) ? "Enable" : "Disable")));
+       pBtdm8723->bCurAgcTableEn = bAgcTableEn;
+
+       /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], bPreAgcTableEn =%d, bCurAgcTableEn =%d\n", */
+       /*pBtdm8723->bPreAgcTableEn, pBtdm8723->bCurAgcTableEn)); */
+
+       if (pBtdm8723->bPreAgcTableEn == pBtdm8723->bCurAgcTableEn)
+               return;
+
+       BTDM_AGCTable(padapter, (u8)bAgcTableEn);
+
+       pBtdm8723->bPreAgcTableEn = pBtdm8723->bCurAgcTableEn;
+}
+
+static void
+btdm_2AntCoexTable(struct rtw_adapter *padapter,
+                  u32 val0x6c0, u32 val0x6c8, u8 val0x6cc)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], write Coex Table 0x6c0 = 0x%x, 0x6c8 = 0x%x, 0x6cc = 0x%x\n",
+               val0x6c0, val0x6c8, val0x6cc));
+       pBtdm8723->curVal0x6c0 = val0x6c0;
+       pBtdm8723->curVal0x6c8 = val0x6c8;
+       pBtdm8723->curVal0x6cc = val0x6cc;
+
+       /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], preVal0x6c0 = 0x%x, preVal0x6c8 = 0x%x, preVal0x6cc = 0x%x !!\n", */
+       /*pBtdm8723->preVal0x6c0, pBtdm8723->preVal0x6c8, pBtdm8723->preVal0x6cc)); */
+       /* RTPRINT(FBT, BT_TRACE, ("[BTCoex], curVal0x6c0 = 0x%x, curVal0x6c8 = 0x%x, curVal0x6cc = 0x%x !!\n", */
+       /*pBtdm8723->curVal0x6c0, pBtdm8723->curVal0x6c8, pBtdm8723->curVal0x6cc)); */
+
+       if ((pBtdm8723->preVal0x6c0 == pBtdm8723->curVal0x6c0) &&
+           (pBtdm8723->preVal0x6c8 == pBtdm8723->curVal0x6c8) &&
+           (pBtdm8723->preVal0x6cc == pBtdm8723->curVal0x6cc))
+               return;
+
+       btdm_SetCoexTable(padapter, val0x6c0, val0x6c8, val0x6cc);
+
+       pBtdm8723->preVal0x6c0 = pBtdm8723->curVal0x6c0;
+       pBtdm8723->preVal0x6c8 = pBtdm8723->curVal0x6c8;
+       pBtdm8723->preVal0x6cc = pBtdm8723->curVal0x6cc;
+}
+
+static void btdm_2AntIgnoreWlanAct(struct rtw_adapter *padapter, u8 bEnable)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTCoex], turn Ignore WlanAct %s\n", (bEnable ? "ON" : "OFF")));
+       pBtdm8723->bCurIgnoreWlanAct = bEnable;
+
+
+       if (pBtdm8723->bPreIgnoreWlanAct == pBtdm8723->bCurIgnoreWlanAct)
+               return;
+
+       btdm_SetFwIgnoreWlanAct(padapter, bEnable);
+       pBtdm8723->bPreIgnoreWlanAct = pBtdm8723->bCurIgnoreWlanAct;
+}
+
+static void
+btdm_2AntSetFw3a(struct rtw_adapter *padapter, u8 byte1, u8 byte2,
+                u8 byte3, u8 byte4, u8 byte5)
+{
+       u8 H2C_Parameter[5] = {0};
+
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       /*  byte1[1:0] != 0 means enable pstdma */
+       /*  for 2Ant bt coexist, if byte1 != 0 means enable pstdma */
+       if (byte1)
+               pHalData->bt_coexist.bFWCoexistAllOff = false;
+       H2C_Parameter[0] = byte1;
+       H2C_Parameter[1] = byte2;
+       H2C_Parameter[2] = byte3;
+       H2C_Parameter[3] = byte4;
+       H2C_Parameter[4] = byte5;
+
+       pHalData->bt_coexist.fw3aVal[0] = byte1;
+       pHalData->bt_coexist.fw3aVal[1] = byte2;
+       pHalData->bt_coexist.fw3aVal[2] = byte3;
+       pHalData->bt_coexist.fw3aVal[3] = byte4;
+       pHalData->bt_coexist.fw3aVal[4] = byte5;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], FW write 0x3a(5bytes) = 0x%x%08x\n",
+               H2C_Parameter[0],
+               H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4]));
+
+       FillH2CCmd(padapter, 0x3a, 5, H2C_Parameter);
+       }
+
+static void btdm_2AntPsTdma(struct rtw_adapter *padapter, u8 bTurnOn, u8 type)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+       u32                     btTxRxCnt = 0;
+       u8 bTurnOnByCnt = false;
+       u8 psTdmaTypeByCnt = 0;
+
+       btTxRxCnt = BTDM_BtTxRxCounterH(padapter)+BTDM_BtTxRxCounterL(padapter);
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT TxRx Counters = %d\n", btTxRxCnt));
+       if (btTxRxCnt > 3000) {
+               bTurnOnByCnt = true;
+               psTdmaTypeByCnt = 8;
+
+               RTPRINT(FBT, BT_TRACE,
+                       ("[BTCoex], For BTTxRxCounters, turn %s PS TDMA, type =%d\n",
+                       (bTurnOnByCnt ? "ON" : "OFF"), psTdmaTypeByCnt));
+               pBtdm8723->bCurPsTdmaOn = bTurnOnByCnt;
+               pBtdm8723->curPsTdma = psTdmaTypeByCnt;
+       } else {
+               RTPRINT(FBT, BT_TRACE,
+                       ("[BTCoex], turn %s PS TDMA, type =%d\n",
+                       (bTurnOn ? "ON" : "OFF"), type));
+               pBtdm8723->bCurPsTdmaOn = bTurnOn;
+               pBtdm8723->curPsTdma = type;
+       }
+
+       if ((pBtdm8723->bPrePsTdmaOn == pBtdm8723->bCurPsTdmaOn) &&
+           (pBtdm8723->prePsTdma == pBtdm8723->curPsTdma))
+               return;
+
+       if (bTurnOn) {
+               switch (type) {
+               case 1:
+               default:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0xa1, 0x98);
+                       break;
+               case 2:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x12, 0x12, 0xa1, 0x98);
+                       break;
+               case 3:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0xa, 0xa, 0xa1, 0x98);
+                       break;
+               case 4:
+                       btdm_2AntSetFw3a(padapter, 0xa3, 0x5, 0x5, 0xa1, 0x80);
+                       break;
+               case 5:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0x20, 0x98);
+                       break;
+               case 6:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x12, 0x12, 0x20, 0x98);
+                       break;
+               case 7:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0xa, 0xa, 0x20, 0x98);
+                       break;
+               case 8:
+                       btdm_2AntSetFw3a(padapter, 0xa3, 0x5, 0x5, 0x20, 0x80);
+                       break;
+               case 9:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0xa1, 0x98);
+                       break;
+               case 10:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x12, 0x12, 0xa1, 0x98);
+                       break;
+               case 11:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0xa, 0xa, 0xa1, 0x98);
+                       break;
+               case 12:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x5, 0x5, 0xa1, 0x98);
+                       break;
+               case 13:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x1a, 0x1a, 0x20, 0x98);
+                       break;
+               case 14:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x12, 0x12, 0x20, 0x98);
+                       break;
+               case 15:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0xa, 0xa, 0x20, 0x98);
+                       break;
+               case 16:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x5, 0x5, 0x20, 0x98);
+                       break;
+               case 17:
+                       btdm_2AntSetFw3a(padapter, 0xa3, 0x2f, 0x2f, 0x20, 0x80);
+                       break;
+               case 18:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x5, 0x5, 0xa1, 0x98);
+                       break;
+               case 19:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x25, 0x25, 0xa1, 0x98);
+                       break;
+               case 20:
+                       btdm_2AntSetFw3a(padapter, 0xe3, 0x25, 0x25, 0x20, 0x98);
+                       break;
+               }
+       } else {
+               /*  disable PS tdma */
+               switch (type) {
+               case 0:
+                       btdm_2AntSetFw3a(padapter, 0x0, 0x0, 0x0, 0x8, 0x0);
+                       break;
+               case 1:
+                       btdm_2AntSetFw3a(padapter, 0x0, 0x0, 0x0, 0x0, 0x0);
+                       break;
+               default:
+                       btdm_2AntSetFw3a(padapter, 0x0, 0x0, 0x0, 0x8, 0x0);
+                       break;
+               }
+       }
+
+       /*  update pre state */
+       pBtdm8723->bPrePsTdmaOn =  pBtdm8723->bCurPsTdmaOn;
+       pBtdm8723->prePsTdma = pBtdm8723->curPsTdma;
+}
+
+static void btdm_2AntBtInquiryPage(struct rtw_adapter *padapter)
+{
+       btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+       btdm_2AntIgnoreWlanAct(padapter, false);
+       btdm_2AntPsTdma(padapter, true, 8);
+}
+
+static u8 btdm_HoldForBtInqPage(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u32 curTime = jiffies;
+
+       if (pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage) {
+               /*  bt inquiry or page is started. */
+               if (pHalData->bt_coexist.halCoex8723.btInqPageStartTime == 0) {
+                       pHalData->bt_coexist.halCoex8723.btInqPageStartTime = curTime;
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page is started at time : 0x%lx \n",
+                       pHalData->bt_coexist.halCoex8723.btInqPageStartTime));
+               }
+       }
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page started time : 0x%lx, curTime : 0x%x \n",
+               pHalData->bt_coexist.halCoex8723.btInqPageStartTime, curTime));
+
+       if (pHalData->bt_coexist.halCoex8723.btInqPageStartTime) {
+               if (((curTime - pHalData->bt_coexist.halCoex8723.btInqPageStartTime)/1000000) >= 10) {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], BT Inquiry/page >= 10sec!!!"));
+                       pHalData->bt_coexist.halCoex8723.btInqPageStartTime = 0;
+               }
+       }
+
+       if (pHalData->bt_coexist.halCoex8723.btInqPageStartTime) {
+               btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+               btdm_2AntIgnoreWlanAct(padapter, false);
+               btdm_2AntPsTdma(padapter, true, 8);
+               return true;
+       } else {
+               return false;
+       }
+}
+
+static u8 btdm_Is2Ant8723ACommonAction(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+       u8 bCommon = false;
+
+       RTPRINT(FBT, BT_TRACE, ("%s :BTDM_IsWifiConnectionExist =%x check_fwstate =%x pmlmepriv->fw_state = 0x%x\n", __func__, BTDM_IsWifiConnectionExist(padapter), check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)), padapter->mlmepriv.fw_state));
+
+       if ((!BTDM_IsWifiConnectionExist(padapter)) &&
+           (!check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) &&
+           (BT_2ANT_BT_STATUS_IDLE == pBtdm8723->btStatus)) {
+               RTPRINT(FBT, BT_TRACE, ("Wifi idle + Bt idle!!\n"));
+
+               btdm_2AntLowPenaltyRa(padapter, false);
+               btdm_2AntRfShrink(padapter, false);
+               btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+
+               btdm_2AntIgnoreWlanAct(padapter, false);
+               btdm_2AntPsTdma(padapter, false, 0);
+               btdm_2AntFwDacSwingLvl(padapter, 0x20);
+               btdm_2AntDecBtPwr(padapter, false);
+
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, false);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+
+               bCommon = true;
+       } else if (((BTDM_IsWifiConnectionExist(padapter)) ||
+                  (check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)))) &&
+                  (BT_2ANT_BT_STATUS_IDLE == pBtdm8723->btStatus)) {
+               RTPRINT(FBT, BT_TRACE, ("Wifi non-idle + BT idle!!\n"));
+
+               btdm_2AntLowPenaltyRa(padapter, true);
+               btdm_2AntRfShrink(padapter, false);
+               btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+
+               btdm_2AntIgnoreWlanAct(padapter, false);
+               btdm_2AntPsTdma(padapter, false, 0);
+               btdm_2AntFwDacSwingLvl(padapter, 0x20);
+               btdm_2AntDecBtPwr(padapter, true);
+
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, false);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+
+               bCommon = true;
+       } else if ((!BTDM_IsWifiConnectionExist(padapter)) &&
+                  (!check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) &&
+                  (BT_2ANT_BT_STATUS_CONNECTED_IDLE == pBtdm8723->btStatus)) {
+               RTPRINT(FBT, BT_TRACE, ("Wifi idle + Bt connected idle!!\n"));
+
+               btdm_2AntLowPenaltyRa(padapter, true);
+               btdm_2AntRfShrink(padapter, true);
+               btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+
+               btdm_2AntIgnoreWlanAct(padapter, false);
+               btdm_2AntPsTdma(padapter, false, 0);
+               btdm_2AntFwDacSwingLvl(padapter, 0x20);
+               btdm_2AntDecBtPwr(padapter, false);
+
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, false);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+
+               bCommon = true;
+       } else if (((BTDM_IsWifiConnectionExist(padapter)) ||
+                  (check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING)))) &&
+                  (BT_2ANT_BT_STATUS_CONNECTED_IDLE == pBtdm8723->btStatus)) {
+               RTPRINT(FBT, BT_TRACE, ("Wifi non-idle + Bt connected idle!!\n"));
+
+               btdm_2AntLowPenaltyRa(padapter, true);
+               btdm_2AntRfShrink(padapter, true);
+               btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+
+               btdm_2AntIgnoreWlanAct(padapter, false);
+               btdm_2AntPsTdma(padapter, false, 0);
+               btdm_2AntFwDacSwingLvl(padapter, 0x20);
+               btdm_2AntDecBtPwr(padapter, true);
+
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, false);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+
+               bCommon = true;
+       } else if ((!BTDM_IsWifiConnectionExist(padapter)) &&
+                  (!check_fwstate(&padapter->mlmepriv, (_FW_UNDER_SURVEY|_FW_UNDER_LINKING))) &&
+                  (BT_2ANT_BT_STATUS_NON_IDLE == pBtdm8723->btStatus)) {
+               RTPRINT(FBT, BT_TRACE, ("Wifi idle + BT non-idle!!\n"));
+
+               btdm_2AntLowPenaltyRa(padapter, true);
+               btdm_2AntRfShrink(padapter, true);
+               btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+
+               btdm_2AntIgnoreWlanAct(padapter, false);
+               btdm_2AntPsTdma(padapter, false, 0);
+               btdm_2AntFwDacSwingLvl(padapter, 0x20);
+               btdm_2AntDecBtPwr(padapter, false);
+
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, false);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+
+               bCommon = true;
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("Wifi non-idle + BT non-idle!!\n"));
+               btdm_2AntLowPenaltyRa(padapter, true);
+               btdm_2AntRfShrink(padapter, true);
+               btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+               btdm_2AntIgnoreWlanAct(padapter, false);
+               btdm_2AntFwDacSwingLvl(padapter, 0x20);
+
+               bCommon = false;
+       }
+       return bCommon;
+}
+
+static void
+btdm_2AntTdmaDurationAdjust(struct rtw_adapter *padapter, u8 bScoHid,
+                           u8 bTxPause, u8 maxInterval)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+       static s32              up, dn, m, n, WaitCount;
+       s32                     result;   /* 0: no change, +1: increase WiFi duration, -1: decrease WiFi duration */
+       u8 retryCount = 0;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], TdmaDurationAdjust()\n"));
+
+       if (pBtdm8723->bResetTdmaAdjust) {
+               pBtdm8723->bResetTdmaAdjust = false;
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], first run TdmaDurationAdjust()!!\n"));
+               if (bScoHid) {
+                       if (bTxPause) {
+                               if (maxInterval == 1) {
+                                       btdm_2AntPsTdma(padapter, true, 15);
+                                       pBtdm8723->psTdmaDuAdjType = 15;
+                               } else if (maxInterval == 2) {
+                                       btdm_2AntPsTdma(padapter, true, 15);
+                                       pBtdm8723->psTdmaDuAdjType = 15;
+                               } else if (maxInterval == 3) {
+                                       btdm_2AntPsTdma(padapter, true, 15);
+                                       pBtdm8723->psTdmaDuAdjType = 15;
+                               } else {
+                                       btdm_2AntPsTdma(padapter, true, 15);
+                                       pBtdm8723->psTdmaDuAdjType = 15;
+                               }
+                       } else {
+                               if (maxInterval == 1) {
+                                       btdm_2AntPsTdma(padapter, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               } else if (maxInterval == 2) {
+                                       btdm_2AntPsTdma(padapter, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               } else if (maxInterval == 3) {
+                                       btdm_2AntPsTdma(padapter, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               } else {
+                                       btdm_2AntPsTdma(padapter, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               }
+                       }
+               } else {
+                       if (bTxPause) {
+                               if (maxInterval == 1) {
+                                       btdm_2AntPsTdma(padapter, true, 7);
+                                       pBtdm8723->psTdmaDuAdjType = 7;
+                               } else if (maxInterval == 2) {
+                                       btdm_2AntPsTdma(padapter, true, 7);
+                                       pBtdm8723->psTdmaDuAdjType = 7;
+                               } else if (maxInterval == 3) {
+                                       btdm_2AntPsTdma(padapter, true, 7);
+                                       pBtdm8723->psTdmaDuAdjType = 7;
+                               } else {
+                                       btdm_2AntPsTdma(padapter, true, 7);
+                                       pBtdm8723->psTdmaDuAdjType = 7;
+                               }
+                       } else {
+                               if (maxInterval == 1) {
+                                       btdm_2AntPsTdma(padapter, true, 3);
+                                       pBtdm8723->psTdmaDuAdjType = 3;
+                               } else if (maxInterval == 2) {
+                                       btdm_2AntPsTdma(padapter, true, 3);
+                                       pBtdm8723->psTdmaDuAdjType = 3;
+                               } else if (maxInterval == 3) {
+                                       btdm_2AntPsTdma(padapter, true, 3);
+                                       pBtdm8723->psTdmaDuAdjType = 3;
+                               } else {
+                                       btdm_2AntPsTdma(padapter, true, 3);
+                                       pBtdm8723->psTdmaDuAdjType = 3;
+                               }
+                       }
+               }
+               up = 0;
+               dn = 0;
+               m = 1;
+               n = 3;
+               result = 0;
+               WaitCount = 0;
+       } else {
+               /* accquire the BT TRx retry count from BT_Info byte2 */
+               retryCount = pHalData->bt_coexist.halCoex8723.btRetryCnt;
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], retryCount = %d\n", retryCount));
+               result = 0;
+               WaitCount++;
+
+               if (retryCount == 0) {  /*  no retry in the last 2-second duration */
+                       up++;
+                       dn--;
+
+                       if (dn <= 0)
+                               dn = 0;
+
+                       if (up >= n) {  /*  if ³sÄò n ­Ó2¬í retry count¬°0, «h½Õ¼eWiFi duration */
+                               WaitCount = 0;
+                               n = 3;
+                               up = 0;
+                               dn = 0;
+                               result = 1;
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Increase wifi duration!!\n"));
+                       }
+               } else if (retryCount <= 3) {   /*  <= 3 retry in the last 2-second duration */
+                       up--;
+                       dn++;
+
+                       if (up <= 0)
+                               up = 0;
+
+                       if (dn == 2) {  /*  if ³sÄò 2 ­Ó2¬í retry count< 3, «h½Õ¯¶WiFi duration */
+                               if (WaitCount <= 2)
+                                       m++; /*  ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ */
+                               else
+                                       m = 1;
+
+                               if (m >= 20) /* m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. */
+                                       m = 20;
+
+                               n = 3*m;
+                               up = 0;
+                               dn = 0;
+                               WaitCount = 0;
+                               result = -1;
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Decrease wifi duration for retryCounter<3!!\n"));
+                       }
+               } else {  /* retry count > 3, ¥u­n1¦¸ retry count > 3, «h½Õ¯¶WiFi duration */
+                       if (WaitCount == 1)
+                               m++; /*  ÁקK¤@ª½¦b¨â­Ólevel¤¤¨Ó¦^ */
+                       else
+                               m = 1;
+
+                       if (m >= 20) /* m ³Ì¤j­È = 20 ' ³Ì¤j120¬í recheck¬O§_½Õ¾ã WiFi duration. */
+                               m = 20;
+                       n = 3*m;
+                       up = 0;
+                       dn = 0;
+                       WaitCount = 0;
+                       result = -1;
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Decrease wifi duration for retryCounter>3!!\n"));
+               }
+
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], max Interval = %d\n", maxInterval));
+               if (maxInterval == 1) {
+                       if (bTxPause) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 1\n"));
+                               if (pBtdm8723->curPsTdma == 1) {
+                                       btdm_2AntPsTdma(padapter, true, 5);
+                                       pBtdm8723->psTdmaDuAdjType = 5;
+                               } else if (pBtdm8723->curPsTdma == 2) {
+                                       btdm_2AntPsTdma(padapter, true, 6);
+                                       pBtdm8723->psTdmaDuAdjType = 6;
+                               } else if (pBtdm8723->curPsTdma == 3) {
+                                       btdm_2AntPsTdma(padapter, true, 7);
+                                       pBtdm8723->psTdmaDuAdjType = 7;
+                               } else if (pBtdm8723->curPsTdma == 4) {
+                                       btdm_2AntPsTdma(padapter, true, 8);
+                                       pBtdm8723->psTdmaDuAdjType = 8;
+                               }
+                               if (pBtdm8723->curPsTdma == 9) {
+                                       btdm_2AntPsTdma(padapter, true, 13);
+                                       pBtdm8723->psTdmaDuAdjType = 13;
+                               } else if (pBtdm8723->curPsTdma == 10) {
+                                       btdm_2AntPsTdma(padapter, true, 14);
+                                       pBtdm8723->psTdmaDuAdjType = 14;
+                               } else if (pBtdm8723->curPsTdma == 11) {
+                                       btdm_2AntPsTdma(padapter, true, 15);
+                                       pBtdm8723->psTdmaDuAdjType = 15;
+                               } else if (pBtdm8723->curPsTdma == 12) {
+                                       btdm_2AntPsTdma(padapter, true, 16);
+                                       pBtdm8723->psTdmaDuAdjType = 16;
+                               }
+
+                               if (result == -1) {
+                                       if (pBtdm8723->curPsTdma == 5) {
+                                               btdm_2AntPsTdma(padapter, true, 6);
+                                               pBtdm8723->psTdmaDuAdjType = 6;
+                                       } else if (pBtdm8723->curPsTdma == 6) {
+                                               btdm_2AntPsTdma(padapter, true, 7);
+                                               pBtdm8723->psTdmaDuAdjType = 7;
+                                       } else if (pBtdm8723->curPsTdma == 7) {
+                                               btdm_2AntPsTdma(padapter, true, 8);
+                                               pBtdm8723->psTdmaDuAdjType = 8;
+                                       } else if (pBtdm8723->curPsTdma == 13) {
+                                               btdm_2AntPsTdma(padapter, true, 14);
+                                               pBtdm8723->psTdmaDuAdjType = 14;
+                                       } else if (pBtdm8723->curPsTdma == 14) {
+                                               btdm_2AntPsTdma(padapter, true, 15);
+                                               pBtdm8723->psTdmaDuAdjType = 15;
+                                       } else if (pBtdm8723->curPsTdma == 15) {
+                                               btdm_2AntPsTdma(padapter, true, 16);
+                                               pBtdm8723->psTdmaDuAdjType = 16;
+                                       }
+                               } else if (result == 1) {
+                                       if (pBtdm8723->curPsTdma == 8) {
+                                               btdm_2AntPsTdma(padapter, true, 7);
+                                               pBtdm8723->psTdmaDuAdjType = 7;
+                                       } else if (pBtdm8723->curPsTdma == 7) {
+                                               btdm_2AntPsTdma(padapter, true, 6);
+                                               pBtdm8723->psTdmaDuAdjType = 6;
+                                       } else if (pBtdm8723->curPsTdma == 6) {
+                                               btdm_2AntPsTdma(padapter, true, 5);
+                                               pBtdm8723->psTdmaDuAdjType = 5;
+                                       } else if (pBtdm8723->curPsTdma == 16) {
+                                               btdm_2AntPsTdma(padapter, true, 15);
+                                               pBtdm8723->psTdmaDuAdjType = 15;
+                                       } else if (pBtdm8723->curPsTdma == 15) {
+                                               btdm_2AntPsTdma(padapter, true, 14);
+                                               pBtdm8723->psTdmaDuAdjType = 14;
+                                       } else if (pBtdm8723->curPsTdma == 14) {
+                                               btdm_2AntPsTdma(padapter, true, 13);
+                                               pBtdm8723->psTdmaDuAdjType = 13;
+                                       }
+                               }
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 0\n"));
+                               if (pBtdm8723->curPsTdma == 5) {
+                                       btdm_2AntPsTdma(padapter, true, 1);
+                                       pBtdm8723->psTdmaDuAdjType = 1;
+                               } else if (pBtdm8723->curPsTdma == 6) {
+                                       btdm_2AntPsTdma(padapter, true, 2);
+                                       pBtdm8723->psTdmaDuAdjType = 2;
+                               } else if (pBtdm8723->curPsTdma == 7) {
+                                       btdm_2AntPsTdma(padapter, true, 3);
+                                       pBtdm8723->psTdmaDuAdjType = 3;
+                               } else if (pBtdm8723->curPsTdma == 8) {
+                                       btdm_2AntPsTdma(padapter, true, 4);
+                                       pBtdm8723->psTdmaDuAdjType = 4;
+                               }
+                               if (pBtdm8723->curPsTdma == 13) {
+                                       btdm_2AntPsTdma(padapter, true, 9);
+                                       pBtdm8723->psTdmaDuAdjType = 9;
+                               } else if (pBtdm8723->curPsTdma == 14) {
+                                       btdm_2AntPsTdma(padapter, true, 10);
+                                       pBtdm8723->psTdmaDuAdjType = 10;
+                               } else if (pBtdm8723->curPsTdma == 15) {
+                                       btdm_2AntPsTdma(padapter, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               } else if (pBtdm8723->curPsTdma == 16) {
+                                       btdm_2AntPsTdma(padapter, true, 12);
+                                       pBtdm8723->psTdmaDuAdjType = 12;
+                               }
+
+                               if (result == -1) {
+                                       if (pBtdm8723->curPsTdma == 1) {
+                                               btdm_2AntPsTdma(padapter, true, 2);
+                                               pBtdm8723->psTdmaDuAdjType = 2;
+                                       } else if (pBtdm8723->curPsTdma == 2) {
+                                               btdm_2AntPsTdma(padapter, true, 3);
+                                               pBtdm8723->psTdmaDuAdjType = 3;
+                                       } else if (pBtdm8723->curPsTdma == 3) {
+                                               btdm_2AntPsTdma(padapter, true, 4);
+                                               pBtdm8723->psTdmaDuAdjType = 4;
+                                       } else if (pBtdm8723->curPsTdma == 9) {
+                                               btdm_2AntPsTdma(padapter, true, 10);
+                                               pBtdm8723->psTdmaDuAdjType = 10;
+                                       } else if (pBtdm8723->curPsTdma == 10) {
+                                               btdm_2AntPsTdma(padapter, true, 11);
+                                               pBtdm8723->psTdmaDuAdjType = 11;
+                                       } else if (pBtdm8723->curPsTdma == 11) {
+                                               btdm_2AntPsTdma(padapter, true, 12);
+                                               pBtdm8723->psTdmaDuAdjType = 12;
+                                       }
+                               } else if (result == 1) {
+                                       if (pBtdm8723->curPsTdma == 4) {
+                                               btdm_2AntPsTdma(padapter, true, 3);
+                                               pBtdm8723->psTdmaDuAdjType = 3;
+                                       } else if (pBtdm8723->curPsTdma == 3) {
+                                               btdm_2AntPsTdma(padapter, true, 2);
+                                               pBtdm8723->psTdmaDuAdjType = 2;
+                                       } else if (pBtdm8723->curPsTdma == 2) {
+                                               btdm_2AntPsTdma(padapter, true, 1);
+                                               pBtdm8723->psTdmaDuAdjType = 1;
+                                       } else if (pBtdm8723->curPsTdma == 12) {
+                                               btdm_2AntPsTdma(padapter, true, 11);
+                                               pBtdm8723->psTdmaDuAdjType = 11;
+                                       } else if (pBtdm8723->curPsTdma == 11) {
+                                               btdm_2AntPsTdma(padapter, true, 10);
+                                               pBtdm8723->psTdmaDuAdjType = 10;
+                                       } else if (pBtdm8723->curPsTdma == 10) {
+                                               btdm_2AntPsTdma(padapter, true, 9);
+                                               pBtdm8723->psTdmaDuAdjType = 9;
+                                       }
+                               }
+                       }
+               } else if (maxInterval == 2) {
+                       if (bTxPause) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 1\n"));
+                               if (pBtdm8723->curPsTdma == 1) {
+                                       btdm_2AntPsTdma(padapter, true, 6);
+                                       pBtdm8723->psTdmaDuAdjType = 6;
+                               } else if (pBtdm8723->curPsTdma == 2) {
+                                       btdm_2AntPsTdma(padapter, true, 6);
+                                       pBtdm8723->psTdmaDuAdjType = 6;
+                               } else if (pBtdm8723->curPsTdma == 3) {
+                                       btdm_2AntPsTdma(padapter, true, 7);
+                                       pBtdm8723->psTdmaDuAdjType = 7;
+                               } else if (pBtdm8723->curPsTdma == 4) {
+                                       btdm_2AntPsTdma(padapter, true, 8);
+                                       pBtdm8723->psTdmaDuAdjType = 8;
+                               }
+                               if (pBtdm8723->curPsTdma == 9) {
+                                       btdm_2AntPsTdma(padapter, true, 14);
+                                       pBtdm8723->psTdmaDuAdjType = 14;
+                               } else if (pBtdm8723->curPsTdma == 10) {
+                                       btdm_2AntPsTdma(padapter, true, 14);
+                                       pBtdm8723->psTdmaDuAdjType = 14;
+                               } else if (pBtdm8723->curPsTdma == 11) {
+                                       btdm_2AntPsTdma(padapter, true, 15);
+                                       pBtdm8723->psTdmaDuAdjType = 15;
+                               } else if (pBtdm8723->curPsTdma == 12) {
+                                       btdm_2AntPsTdma(padapter, true, 16);
+                                       pBtdm8723->psTdmaDuAdjType = 16;
+                               }
+                               if (result == -1) {
+                                       if (pBtdm8723->curPsTdma == 5) {
+                                               btdm_2AntPsTdma(padapter, true, 6);
+                                               pBtdm8723->psTdmaDuAdjType = 6;
+                                       } else if (pBtdm8723->curPsTdma == 6) {
+                                               btdm_2AntPsTdma(padapter, true, 7);
+                                               pBtdm8723->psTdmaDuAdjType = 7;
+                                       } else if (pBtdm8723->curPsTdma == 7) {
+                                               btdm_2AntPsTdma(padapter, true, 8);
+                                               pBtdm8723->psTdmaDuAdjType = 8;
+                                       } else if (pBtdm8723->curPsTdma == 13) {
+                                               btdm_2AntPsTdma(padapter, true, 14);
+                                               pBtdm8723->psTdmaDuAdjType = 14;
+                                       } else if (pBtdm8723->curPsTdma == 14) {
+                                               btdm_2AntPsTdma(padapter, true, 15);
+                                               pBtdm8723->psTdmaDuAdjType = 15;
+                                       } else if (pBtdm8723->curPsTdma == 15) {
+                                               btdm_2AntPsTdma(padapter, true, 16);
+                                               pBtdm8723->psTdmaDuAdjType = 16;
+                                       }
+                               } else if (result == 1) {
+                                       if (pBtdm8723->curPsTdma == 8) {
+                                               btdm_2AntPsTdma(padapter, true, 7);
+                                               pBtdm8723->psTdmaDuAdjType = 7;
+                                       } else if (pBtdm8723->curPsTdma == 7) {
+                                               btdm_2AntPsTdma(padapter, true, 6);
+                                               pBtdm8723->psTdmaDuAdjType = 6;
+                                       } else if (pBtdm8723->curPsTdma == 6) {
+                                               btdm_2AntPsTdma(padapter, true, 6);
+                                               pBtdm8723->psTdmaDuAdjType = 6;
+                                       } else if (pBtdm8723->curPsTdma == 16) {
+                                               btdm_2AntPsTdma(padapter, true, 15);
+                                               pBtdm8723->psTdmaDuAdjType = 15;
+                                       } else if (pBtdm8723->curPsTdma == 15) {
+                                               btdm_2AntPsTdma(padapter, true, 14);
+                                               pBtdm8723->psTdmaDuAdjType = 14;
+                                       } else if (pBtdm8723->curPsTdma == 14) {
+                                               btdm_2AntPsTdma(padapter, true, 14);
+                                               pBtdm8723->psTdmaDuAdjType = 14;
+                                       }
+                               }
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 0\n"));
+                               if (pBtdm8723->curPsTdma == 5) {
+                                       btdm_2AntPsTdma(padapter, true, 2);
+                                       pBtdm8723->psTdmaDuAdjType = 2;
+                               } else if (pBtdm8723->curPsTdma == 6) {
+                                       btdm_2AntPsTdma(padapter, true, 2);
+                                       pBtdm8723->psTdmaDuAdjType = 2;
+                               } else if (pBtdm8723->curPsTdma == 7) {
+                                       btdm_2AntPsTdma(padapter, true, 3);
+                                       pBtdm8723->psTdmaDuAdjType = 3;
+                               } else if (pBtdm8723->curPsTdma == 8) {
+                                       btdm_2AntPsTdma(padapter, true, 4);
+                                       pBtdm8723->psTdmaDuAdjType = 4;
+                               }
+                               if (pBtdm8723->curPsTdma == 13) {
+                                       btdm_2AntPsTdma(padapter, true, 10);
+                                       pBtdm8723->psTdmaDuAdjType = 10;
+                               } else if (pBtdm8723->curPsTdma == 14) {
+                                       btdm_2AntPsTdma(padapter, true, 10);
+                                       pBtdm8723->psTdmaDuAdjType = 10;
+                               } else if (pBtdm8723->curPsTdma == 15) {
+                                       btdm_2AntPsTdma(padapter, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               } else if (pBtdm8723->curPsTdma == 16) {
+                                       btdm_2AntPsTdma(padapter, true, 12);
+                                       pBtdm8723->psTdmaDuAdjType = 12;
+                               }
+                               if (result == -1) {
+                                       if (pBtdm8723->curPsTdma == 1) {
+                                               btdm_2AntPsTdma(padapter, true, 2);
+                                               pBtdm8723->psTdmaDuAdjType = 2;
+                                       } else if (pBtdm8723->curPsTdma == 2) {
+                                               btdm_2AntPsTdma(padapter, true, 3);
+                                               pBtdm8723->psTdmaDuAdjType = 3;
+                                       } else if (pBtdm8723->curPsTdma == 3) {
+                                               btdm_2AntPsTdma(padapter, true, 4);
+                                               pBtdm8723->psTdmaDuAdjType = 4;
+                                       } else if (pBtdm8723->curPsTdma == 9) {
+                                               btdm_2AntPsTdma(padapter, true, 10);
+                                               pBtdm8723->psTdmaDuAdjType = 10;
+                                       } else if (pBtdm8723->curPsTdma == 10) {
+                                               btdm_2AntPsTdma(padapter, true, 11);
+                                               pBtdm8723->psTdmaDuAdjType = 11;
+                                       } else if (pBtdm8723->curPsTdma == 11) {
+                                               btdm_2AntPsTdma(padapter, true, 12);
+                                               pBtdm8723->psTdmaDuAdjType = 12;
+                                       }
+                               } else if (result == 1) {
+                                       if (pBtdm8723->curPsTdma == 4) {
+                                               btdm_2AntPsTdma(padapter, true, 3);
+                                               pBtdm8723->psTdmaDuAdjType = 3;
+                                       } else if (pBtdm8723->curPsTdma == 3) {
+                                               btdm_2AntPsTdma(padapter, true, 2);
+                                               pBtdm8723->psTdmaDuAdjType = 2;
+                                       } else if (pBtdm8723->curPsTdma == 2) {
+                                               btdm_2AntPsTdma(padapter, true, 2);
+                                               pBtdm8723->psTdmaDuAdjType = 2;
+                                       } else if (pBtdm8723->curPsTdma == 12) {
+                                               btdm_2AntPsTdma(padapter, true, 11);
+                                               pBtdm8723->psTdmaDuAdjType = 11;
+                                       } else if (pBtdm8723->curPsTdma == 11) {
+                                               btdm_2AntPsTdma(padapter, true, 10);
+                                               pBtdm8723->psTdmaDuAdjType = 10;
+                                       } else if (pBtdm8723->curPsTdma == 10) {
+                                               btdm_2AntPsTdma(padapter, true, 10);
+                                               pBtdm8723->psTdmaDuAdjType = 10;
+                                       }
+                               }
+                       }
+               } else if (maxInterval == 3) {
+                       if (bTxPause) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 1\n"));
+                               if (pBtdm8723->curPsTdma == 1) {
+                                       btdm_2AntPsTdma(padapter, true, 7);
+                                       pBtdm8723->psTdmaDuAdjType = 7;
+                               } else if (pBtdm8723->curPsTdma == 2) {
+                                       btdm_2AntPsTdma(padapter, true, 7);
+                                       pBtdm8723->psTdmaDuAdjType = 7;
+                               } else if (pBtdm8723->curPsTdma == 3) {
+                                       btdm_2AntPsTdma(padapter, true, 7);
+                                       pBtdm8723->psTdmaDuAdjType = 7;
+                               } else if (pBtdm8723->curPsTdma == 4) {
+                                       btdm_2AntPsTdma(padapter, true, 8);
+                                       pBtdm8723->psTdmaDuAdjType = 8;
+                               }
+                               if (pBtdm8723->curPsTdma == 9) {
+                                       btdm_2AntPsTdma(padapter, true, 15);
+                                       pBtdm8723->psTdmaDuAdjType = 15;
+                               } else if (pBtdm8723->curPsTdma == 10) {
+                                       btdm_2AntPsTdma(padapter, true, 15);
+                                       pBtdm8723->psTdmaDuAdjType = 15;
+                               } else if (pBtdm8723->curPsTdma == 11) {
+                                       btdm_2AntPsTdma(padapter, true, 15);
+                                       pBtdm8723->psTdmaDuAdjType = 15;
+                               } else if (pBtdm8723->curPsTdma == 12) {
+                                       btdm_2AntPsTdma(padapter, true, 16);
+                                       pBtdm8723->psTdmaDuAdjType = 16;
+                               }
+                               if (result == -1) {
+                                       if (pBtdm8723->curPsTdma == 5) {
+                                               btdm_2AntPsTdma(padapter, true, 7);
+                                               pBtdm8723->psTdmaDuAdjType = 7;
+                                       } else if (pBtdm8723->curPsTdma == 6) {
+                                               btdm_2AntPsTdma(padapter, true, 7);
+                                               pBtdm8723->psTdmaDuAdjType = 7;
+                                       } else if (pBtdm8723->curPsTdma == 7) {
+                                               btdm_2AntPsTdma(padapter, true, 8);
+                                               pBtdm8723->psTdmaDuAdjType = 8;
+                                       } else if (pBtdm8723->curPsTdma == 13) {
+                                               btdm_2AntPsTdma(padapter, true, 15);
+                                               pBtdm8723->psTdmaDuAdjType = 15;
+                                       } else if (pBtdm8723->curPsTdma == 14) {
+                                               btdm_2AntPsTdma(padapter, true, 15);
+                                               pBtdm8723->psTdmaDuAdjType = 15;
+                                       } else if (pBtdm8723->curPsTdma == 15) {
+                                               btdm_2AntPsTdma(padapter, true, 16);
+                                               pBtdm8723->psTdmaDuAdjType = 16;
+                                       }
+                               } else if (result == 1) {
+                                       if (pBtdm8723->curPsTdma == 8) {
+                                               btdm_2AntPsTdma(padapter, true, 7);
+                                               pBtdm8723->psTdmaDuAdjType = 7;
+                                       } else if (pBtdm8723->curPsTdma == 7) {
+                                               btdm_2AntPsTdma(padapter, true, 7);
+                                               pBtdm8723->psTdmaDuAdjType = 7;
+                                       } else if (pBtdm8723->curPsTdma == 6) {
+                                               btdm_2AntPsTdma(padapter, true, 7);
+                                               pBtdm8723->psTdmaDuAdjType = 7;
+                                       } else if (pBtdm8723->curPsTdma == 16) {
+                                               btdm_2AntPsTdma(padapter, true, 15);
+                                               pBtdm8723->psTdmaDuAdjType = 15;
+                                       } else if (pBtdm8723->curPsTdma == 15) {
+                                               btdm_2AntPsTdma(padapter, true, 15);
+                                               pBtdm8723->psTdmaDuAdjType = 15;
+                                       } else if (pBtdm8723->curPsTdma == 14) {
+                                               btdm_2AntPsTdma(padapter, true, 15);
+                                               pBtdm8723->psTdmaDuAdjType = 15;
+                                       }
+                               }
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], TxPause = 0\n"));
+                               if (pBtdm8723->curPsTdma == 5) {
+                                       btdm_2AntPsTdma(padapter, true, 3);
+                                       pBtdm8723->psTdmaDuAdjType = 3;
+                               } else if (pBtdm8723->curPsTdma == 6) {
+                                       btdm_2AntPsTdma(padapter, true, 3);
+                                       pBtdm8723->psTdmaDuAdjType = 3;
+                               } else if (pBtdm8723->curPsTdma == 7) {
+                                       btdm_2AntPsTdma(padapter, true, 3);
+                                       pBtdm8723->psTdmaDuAdjType = 3;
+                               } else if (pBtdm8723->curPsTdma == 8) {
+                                       btdm_2AntPsTdma(padapter, true, 4);
+                                       pBtdm8723->psTdmaDuAdjType = 4;
+                               }
+                               if (pBtdm8723->curPsTdma == 13) {
+                                       btdm_2AntPsTdma(padapter, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               } else if (pBtdm8723->curPsTdma == 14) {
+                                       btdm_2AntPsTdma(padapter, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               } else if (pBtdm8723->curPsTdma == 15) {
+                                       btdm_2AntPsTdma(padapter, true, 11);
+                                       pBtdm8723->psTdmaDuAdjType = 11;
+                               } else if (pBtdm8723->curPsTdma == 16) {
+                                       btdm_2AntPsTdma(padapter, true, 12);
+                                       pBtdm8723->psTdmaDuAdjType = 12;
+                               }
+                               if (result == -1) {
+                                       if (pBtdm8723->curPsTdma == 1) {
+                                               btdm_2AntPsTdma(padapter, true, 3);
+                                               pBtdm8723->psTdmaDuAdjType = 3;
+                                       } else if (pBtdm8723->curPsTdma == 2) {
+                                               btdm_2AntPsTdma(padapter, true, 3);
+                                               pBtdm8723->psTdmaDuAdjType = 3;
+                                       } else if (pBtdm8723->curPsTdma == 3) {
+                                               btdm_2AntPsTdma(padapter, true, 4);
+                                               pBtdm8723->psTdmaDuAdjType = 4;
+                                       } else if (pBtdm8723->curPsTdma == 9) {
+                                               btdm_2AntPsTdma(padapter, true, 11);
+                                               pBtdm8723->psTdmaDuAdjType = 11;
+                                       } else if (pBtdm8723->curPsTdma == 10) {
+                                               btdm_2AntPsTdma(padapter, true, 11);
+                                               pBtdm8723->psTdmaDuAdjType = 11;
+                                       } else if (pBtdm8723->curPsTdma == 11) {
+                                               btdm_2AntPsTdma(padapter, true, 12);
+                                               pBtdm8723->psTdmaDuAdjType = 12;
+                                       }
+                               } else if (result == 1) {
+                                       if (pBtdm8723->curPsTdma == 4) {
+                                               btdm_2AntPsTdma(padapter, true, 3);
+                                               pBtdm8723->psTdmaDuAdjType = 3;
+                                       } else if (pBtdm8723->curPsTdma == 3) {
+                                               btdm_2AntPsTdma(padapter, true, 3);
+                                               pBtdm8723->psTdmaDuAdjType = 3;
+                                       } else if (pBtdm8723->curPsTdma == 2) {
+                                               btdm_2AntPsTdma(padapter, true, 3);
+                                               pBtdm8723->psTdmaDuAdjType = 3;
+                                       } else if (pBtdm8723->curPsTdma == 12) {
+                                               btdm_2AntPsTdma(padapter, true, 11);
+                                               pBtdm8723->psTdmaDuAdjType = 11;
+                                       } else if (pBtdm8723->curPsTdma == 11) {
+                                               btdm_2AntPsTdma(padapter, true, 11);
+                                               pBtdm8723->psTdmaDuAdjType = 11;
+                                       } else if (pBtdm8723->curPsTdma == 10) {
+                                               btdm_2AntPsTdma(padapter, true, 11);
+                                               pBtdm8723->psTdmaDuAdjType = 11;
+                                       }
+                               }
+                       }
+               }
+       }
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], PsTdma type : recordPsTdma =%d\n", pBtdm8723->psTdmaDuAdjType));
+       /*  if current PsTdma not match with the recorded one (when scan, dhcp...), */
+       /*  then we have to adjust it back to the previous record one. */
+       if (pBtdm8723->curPsTdma != pBtdm8723->psTdmaDuAdjType) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], PsTdma type dismatch!!!, curPsTdma =%d, recordPsTdma =%d\n",
+                       pBtdm8723->curPsTdma, pBtdm8723->psTdmaDuAdjType));
+
+               if (!check_fwstate(&padapter->mlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING))
+                       btdm_2AntPsTdma(padapter, true, pBtdm8723->psTdmaDuAdjType);
+               else
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], roaming/link/scan is under progress, will adjust next time!!!\n"));
+       }
+}
+
+/*  default Action */
+/*  SCO only or SCO+PAN(HS) */
+static void btdm_2Ant8723ASCOAction(struct rtw_adapter *padapter)
+{
+       u8 btRssiState, btRssiState1;
+
+       if (btdm_NeedToDecBtPwr(padapter))
+               btdm_2AntDecBtPwr(padapter, true);
+       else
+               btdm_2AntDecBtPwr(padapter, false);
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               /*  fw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntPsTdma(padapter, true, 11);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       btdm_2AntPsTdma(padapter, true, 15);
+               }
+
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, true);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0);
+
+               /*  fw mechanism */
+               if ((btRssiState1 == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntPsTdma(padapter, true, 11);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       btdm_2AntPsTdma(padapter, true, 15);
+               }
+
+               /*  sw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+static void btdm_2Ant8723AHIDAction(struct rtw_adapter *padapter)
+{
+       u8 btRssiState, btRssiState1;
+
+       if (btdm_NeedToDecBtPwr(padapter))
+               btdm_2AntDecBtPwr(padapter, true);
+       else
+               btdm_2AntDecBtPwr(padapter, false);
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+                       /*  fw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntPsTdma(padapter, true, 9);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       btdm_2AntPsTdma(padapter, true, 13);
+               }
+
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, false);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0);
+
+               /*  fw mechanism */
+               if ((btRssiState1 == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntPsTdma(padapter, true, 9);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       btdm_2AntPsTdma(padapter, true, 13);
+               }
+
+               /*  sw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+/* A2DP only / PAN(EDR) only/ A2DP+PAN(HS) */
+static void btdm_2Ant8723AA2DPAction(struct rtw_adapter *padapter)
+{
+       u8 btRssiState, btRssiState1;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt;
+
+       if (btdm_NeedToDecBtPwr(padapter))
+               btdm_2AntDecBtPwr(padapter, true);
+       else
+               btdm_2AntDecBtPwr(padapter, false);
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+
+               /*  fw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, false, false, 3);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, false, false, 1);
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, false, true, 3);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                       btdm_2AntTdmaDurationAdjust(padapter, false, true, 1);
+                       }
+               }
+
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, true);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0);
+
+               /*  fw mechanism */
+               if ((btRssiState1 == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, false, false, 3);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, false, false, 1);
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, false, true, 3);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, false, true, 1);
+                       }
+               }
+
+               /*  sw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+static void btdm_2Ant8723APANEDRAction(struct rtw_adapter *padapter)
+{
+       u8 btRssiState, btRssiState1;
+
+       if (btdm_NeedToDecBtPwr(padapter))
+               btdm_2AntDecBtPwr(padapter, true);
+       else
+               btdm_2AntDecBtPwr(padapter, false);
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+
+               /*  fw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntPsTdma(padapter, true, 2);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntPsTdma(padapter, true, 6);
+               }
+
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, true);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0);
+
+               /*  fw mechanism */
+               if ((btRssiState1 == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntPsTdma(padapter, true, 2);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       btdm_2AntPsTdma(padapter, true, 6);
+               }
+
+               /*  sw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+/* PAN(HS) only */
+static void btdm_2Ant8723APANHSAction(struct rtw_adapter *padapter)
+{
+       u8 btRssiState;
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 47, 0);
+               /*  fw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       btdm_2AntDecBtPwr(padapter, true);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntDecBtPwr(padapter, false);
+               }
+               btdm_2AntPsTdma(padapter, false, 0);
+
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, true);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 47, 0);
+
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high\n"));
+                       /*  fw mechanism */
+                       btdm_2AntDecBtPwr(padapter, true);
+                       btdm_2AntPsTdma(padapter, false, 0);
+
+                       /*  sw mechanism */
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low\n"));
+                       /*  fw mechanism */
+                       btdm_2AntDecBtPwr(padapter, false);
+                       btdm_2AntPsTdma(padapter, false, 0);
+
+                       /*  sw mechanism */
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+/* PAN(EDR)+A2DP */
+static void btdm_2Ant8723APANEDRA2DPAction(struct rtw_adapter *padapter)
+{
+       u8 btRssiState, btRssiState1, btInfoExt;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt;
+
+       if (btdm_NeedToDecBtPwr(padapter))
+               btdm_2AntDecBtPwr(padapter, true);
+       else
+               btdm_2AntDecBtPwr(padapter, false);
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       /*  fw mechanism */
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 4);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 2);
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       /*  fw mechanism */
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 8);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 6);
+                       }
+               }
+
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, true);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0);
+
+               if ((btRssiState1 == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       /*  fw mechanism */
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 4);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 2);
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       /*  fw mechanism */
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 8);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 6);
+                       }
+               }
+
+               /*  sw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+static void btdm_2Ant8723APANEDRHIDAction(struct rtw_adapter *padapter)
+{
+       u8 btRssiState, btRssiState1;
+
+       if (btdm_NeedToDecBtPwr(padapter))
+               btdm_2AntDecBtPwr(padapter, true);
+       else
+               btdm_2AntDecBtPwr(padapter, false);
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               /*  fw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntPsTdma(padapter, true, 10);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntPsTdma(padapter, true, 14);
+               }
+
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, true);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0);
+
+               /*  fw mechanism */
+               if ((btRssiState1 == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntPsTdma(padapter, true, 10);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       btdm_2AntPsTdma(padapter, true, 14);
+               }
+
+               /*  sw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+/*  HID+A2DP+PAN(EDR) */
+static void btdm_2Ant8723AHIDA2DPPANEDRAction(struct rtw_adapter *padapter)
+{
+       u8 btRssiState, btRssiState1, btInfoExt;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt;
+
+       if (btdm_NeedToDecBtPwr(padapter))
+               btdm_2AntDecBtPwr(padapter, true);
+       else
+               btdm_2AntDecBtPwr(padapter, false);
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 12);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 10);
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 16);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 14);
+                       }
+               }
+
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, true);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 37, 0);
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 27, 0);
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 12);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 10);
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 16);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntPsTdma(padapter, true, 14);
+                       }
+               }
+
+               /*  sw mechanism */
+               if ((btRssiState1 == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+static void btdm_2Ant8723AHIDA2DPAction(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 btRssiState, btRssiState1, btInfoExt;
+
+       btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt;
+
+       if (btdm_NeedToDecBtPwr(padapter))
+               btdm_2AntDecBtPwr(padapter, true);
+       else
+               btdm_2AntDecBtPwr(padapter, false);
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, true, false, 3);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, true, false, 1);
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, true, true, 3);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, true, true, 1);
+                       }
+               }
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, true);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               btRssiState1 = BTDM_CheckCoexRSSIState(padapter, 2, 27, 0);
+
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, true, false, 3);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, true, false, 1);
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       if (btInfoExt&BIT(0)) { /* a2dp rate, 1:basic /0:edr */
+                               RTPRINT(FBT, BT_TRACE, ("a2dp basic rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, true, true, 3);
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("a2dp edr rate \n"));
+                               btdm_2AntTdmaDurationAdjust(padapter, true, true, 1);
+                       }
+               }
+               if ((btRssiState1 == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       /*  sw mechanism */
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       /*  sw mechanism */
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+static void btdm_2Ant8723AA2dp(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 btRssiState, btRssiState1, btInfoExt;
+
+       btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt;
+
+       if (btdm_NeedToDecBtPwr(padapter))
+               btdm_2AntDecBtPwr(padapter, true);
+       else
+               btdm_2AntDecBtPwr(padapter, false);
+       /*  coex table */
+       btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+       btdm_2AntIgnoreWlanAct(padapter, false);
+
+       if (BTDM_IsHT40(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("HT40\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 37, 0);
+               /*  fw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntTdmaDurationAdjust(padapter, false, false, 1);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       btdm_2AntTdmaDurationAdjust(padapter, false, true, 1);
+               }
+
+               /*  sw mechanism */
+               btdm_2AntAgcTable(padapter, false);
+               btdm_2AntAdcBackOff(padapter, true);
+               btdm_2AntDacSwing(padapter, false, 0xc0);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("HT20 or Legacy\n"));
+               btRssiState = BTDM_CheckCoexRSSIState(padapter, 2, 47, 0);
+               btRssiState1 = BTDM_CheckCoexRSSIState1(padapter, 2, 27, 0);
+
+               /*  fw mechanism */
+               if ((btRssiState1 == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 high \n"));
+                       PlatformEFIOWrite1Byte(padapter, 0x883, 0x40);
+                       btdm_2AntTdmaDurationAdjust(padapter, false, false, 1);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi-1 low \n"));
+                       btdm_2AntTdmaDurationAdjust(padapter, false, true, 1);
+               }
+
+               /*  sw mechanism */
+               if ((btRssiState == BT_RSSI_STATE_HIGH) ||
+                   (btRssiState == BT_RSSI_STATE_STAY_HIGH)) {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi high \n"));
+                       btdm_2AntAgcTable(padapter, true);
+                       btdm_2AntAdcBackOff(padapter, true);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("Wifi rssi low \n"));
+                       btdm_2AntAgcTable(padapter, false);
+                       btdm_2AntAdcBackOff(padapter, false);
+                       btdm_2AntDacSwing(padapter, false, 0xc0);
+               }
+       }
+}
+
+/*  extern function start with BTDM_ */
+static void BTDM_2AntParaInit(struct rtw_adapter *padapter)
+{
+
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], 2Ant Parameter Init!!\n"));
+
+       /*  Enable counter statistics */
+       rtw_write8(padapter, 0x76e, 0x4);
+       rtw_write8(padapter, 0x778, 0x3);
+       rtw_write8(padapter, 0x40, 0x20);
+
+       /*  force to reset coex mechanism */
+       pBtdm8723->preVal0x6c0 = 0x0;
+       btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+
+       pBtdm8723->bPrePsTdmaOn = true;
+       btdm_2AntPsTdma(padapter, false, 0);
+
+       pBtdm8723->preFwDacSwingLvl = 0x10;
+       btdm_2AntFwDacSwingLvl(padapter, 0x20);
+
+       pBtdm8723->bPreDecBtPwr = true;
+       btdm_2AntDecBtPwr(padapter, false);
+
+       pBtdm8723->bPreAgcTableEn = true;
+       btdm_2AntAgcTable(padapter, false);
+
+       pBtdm8723->bPreAdcBackOff = true;
+       btdm_2AntAdcBackOff(padapter, false);
+
+       pBtdm8723->bPreLowPenaltyRa = true;
+       btdm_2AntLowPenaltyRa(padapter, false);
+
+       pBtdm8723->bPreRfRxLpfShrink = true;
+       btdm_2AntRfShrink(padapter, false);
+
+       pBtdm8723->bPreDacSwingOn = true;
+       btdm_2AntDacSwing(padapter, false, 0xc0);
+
+       pBtdm8723->bPreIgnoreWlanAct = true;
+       btdm_2AntIgnoreWlanAct(padapter, false);
+}
+
+static void BTDM_2AntHwCoexAllOff8723A(struct rtw_adapter *padapter)
+{
+       btdm_2AntCoexTable(padapter, 0x55555555, 0xffff, 0x3);
+}
+
+static void BTDM_2AntFwCoexAllOff8723A(struct rtw_adapter *padapter)
+{
+       btdm_2AntIgnoreWlanAct(padapter, false);
+       btdm_2AntPsTdma(padapter, false, 0);
+       btdm_2AntFwDacSwingLvl(padapter, 0x20);
+       btdm_2AntDecBtPwr(padapter, false);
+}
+
+static void BTDM_2AntSwCoexAllOff8723A(struct rtw_adapter *padapter)
+{
+       btdm_2AntAgcTable(padapter, false);
+       btdm_2AntAdcBackOff(padapter, false);
+       btdm_2AntLowPenaltyRa(padapter, false);
+       btdm_2AntRfShrink(padapter, false);
+       btdm_2AntDacSwing(padapter, false, 0xc0);
+}
+
+static void BTDM_2AntFwC2hBtInfo8723A(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+       u8 btInfo = 0;
+       u8 algorithm = BT_2ANT_COEX_ALGO_UNDEFINED;
+       u8 bBtLinkExist = false, bBtHsModeExist = false;
+
+       btInfo = pHalData->bt_coexist.halCoex8723.c2hBtInfoOriginal;
+       pBtdm8723->btStatus = BT_2ANT_BT_STATUS_IDLE;
+
+       /*  check BIT2 first ==> check if bt is under inquiry or page scan */
+       if (btInfo & BIT(2)) {
+               if (!pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage) {
+                       pBtMgnt->ExtConfig.bHoldForBtOperation = true;
+                       pBtMgnt->ExtConfig.bHoldPeriodCnt = 1;
+                       btdm_2AntBtInquiryPage(padapter);
+               } else {
+                       pBtMgnt->ExtConfig.bHoldPeriodCnt++;
+                       btdm_HoldForBtInqPage(padapter);
+               }
+               pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage = true;
+
+       } else {
+               pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage = false;
+               pBtMgnt->ExtConfig.bHoldForBtOperation = false;
+               pBtMgnt->ExtConfig.bHoldPeriodCnt = 0;
+
+       }
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTC2H], pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage =%x pBtMgnt->ExtConfig.bHoldPeriodCnt =%x pBtMgnt->ExtConfig.bHoldForBtOperation =%x\n",
+               pHalData->bt_coexist.halCoex8723.bC2hBtInquiryPage,
+               pBtMgnt->ExtConfig.bHoldPeriodCnt,
+               pBtMgnt->ExtConfig.bHoldForBtOperation));
+
+       RTPRINT(FBT, BT_TRACE,
+               ("[BTC2H],   btInfo =%x   pHalData->bt_coexist.halCoex8723.c2hBtInfoOriginal =%x\n",
+               btInfo, pHalData->bt_coexist.halCoex8723.c2hBtInfoOriginal));
+       if (btInfo&BT_INFO_ACL) {
+               RTPRINT(FBT, BT_TRACE, ("[BTC2H], BTInfo: bConnect = true   btInfo =%x\n", btInfo));
+               bBtLinkExist = true;
+               if (((btInfo&(BT_INFO_FTP|BT_INFO_A2DP|BT_INFO_HID|BT_INFO_SCO_BUSY)) != 0) ||
+                   pHalData->bt_coexist.halCoex8723.btRetryCnt > 0) {
+                       pBtdm8723->btStatus = BT_2ANT_BT_STATUS_NON_IDLE;
+               } else {
+                       pBtdm8723->btStatus = BT_2ANT_BT_STATUS_CONNECTED_IDLE;
+               }
+
+               if (btInfo&BT_INFO_SCO || btInfo&BT_INFO_SCO_BUSY) {
+                       if (btInfo&BT_INFO_FTP || btInfo&BT_INFO_A2DP || btInfo&BT_INFO_HID) {
+                               switch (btInfo&0xe0) {
+                               case BT_INFO_HID:
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + HID\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_HID;
+                                       break;
+                               case BT_INFO_A2DP:
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Error!!! SCO + A2DP\n"));
+                                       break;
+                               case BT_INFO_FTP:
+                                       if (bBtHsModeExist) {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + PAN(HS)\n"));
+                                               algorithm = BT_2ANT_COEX_ALGO_SCO;
+                                       } else {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO + PAN(EDR)\n"));
+                                               algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID;
+                                       }
+                                       break;
+                               case (BT_INFO_HID | BT_INFO_A2DP):
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_HID_A2DP;
+                                       break;
+                               case (BT_INFO_HID | BT_INFO_FTP):
+                                       if (bBtHsModeExist) {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(HS)\n"));
+                                               algorithm = BT_2ANT_COEX_ALGO_HID_A2DP;
+                                       } else {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(EDR)\n"));
+                                               algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID;
+                                       }
+                                       break;
+                               case (BT_INFO_A2DP | BT_INFO_FTP):
+                                       if (bBtHsModeExist) {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(HS)\n"));
+                                               algorithm = BT_2ANT_COEX_ALGO_A2DP;
+                                       } else {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n"));
+                                               algorithm = BT_2ANT_COEX_ALGO_PANEDR_A2DP;
+                                       }
+                                       break;
+                               case (BT_INFO_HID | BT_INFO_A2DP | BT_INFO_FTP):
+                                       if (bBtHsModeExist) {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n"));
+                                               algorithm = BT_2ANT_COEX_ALGO_HID_A2DP;
+                                       } else {
+                                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n"));
+                                               algorithm = BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+                                       }
+                                       break;
+                               }
+                       } else {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], SCO only\n"));
+                               algorithm = BT_2ANT_COEX_ALGO_SCO;
+                       }
+               } else {
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], non SCO\n"));
+                       switch (btInfo&0xe0) {
+                       case BT_INFO_HID:
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID\n"));
+                               algorithm = BT_2ANT_COEX_ALGO_HID;
+                               break;
+                       case BT_INFO_A2DP:
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex],  A2DP\n"));
+                               algorithm = BT_2ANT_COEX_ALGO_A2DP;
+                               break;
+                       case BT_INFO_FTP:
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], PAN(EDR)\n"));
+                               algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID;
+                               break;
+                       case (BT_INFO_HID | BT_INFO_A2DP):
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP\n"));
+                               algorithm = BT_2ANT_COEX_ALGO_HID_A2DP;
+                               break;
+                       case (BT_INFO_HID|BT_INFO_FTP):
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(HS)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_HID_A2DP;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + PAN(EDR)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_PANEDR_HID;
+                               }
+                               break;
+                       case (BT_INFO_A2DP|BT_INFO_FTP):
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(HS)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_A2DP;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], A2DP + PAN(EDR)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_PANEDR_A2DP;
+                               }
+                               break;
+                       case (BT_INFO_HID|BT_INFO_A2DP|BT_INFO_FTP):
+                               if (bBtHsModeExist) {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(HS)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_HID_A2DP;
+                               } else {
+                                       RTPRINT(FBT, BT_TRACE, ("[BTCoex], HID + A2DP + PAN(EDR)\n"));
+                                       algorithm = BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR;
+                               }
+                               break;
+                       }
+
+               }
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("[BTC2H], BTInfo: bConnect = false\n"));
+               pBtdm8723->btStatus = BT_2ANT_BT_STATUS_IDLE;
+       }
+
+       pBtdm8723->curAlgorithm = algorithm;
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], Algorithm = %d \n", pBtdm8723->curAlgorithm));
+
+/* From */
+       BTDM_CheckWiFiState(padapter);
+       if (pBtMgnt->ExtConfig.bManualControl) {
+               RTPRINT(FBT, BT_TRACE, ("Action Manual control, won't execute bt coexist mechanism!!\n"));
+               return;
+       }
+}
+
+void BTDM_2AntBtCoexist8723A(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct bt_dgb *pBtDbg = &pBTInfo->BtDbg;
+       u8 btInfoOriginal = 0;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct btdm_8723a_2ant *pBtdm8723 = &pHalData->bt_coexist.halCoex8723.btdm2Ant;
+
+       if (BTDM_BtProfileSupport(padapter)) {
+               if (pBtMgnt->ExtConfig.bHoldForBtOperation) {
+                       RTPRINT(FBT, BT_TRACE, ("Action for BT Operation adjust!!\n"));
+                       return;
+               }
+               if (pBtMgnt->ExtConfig.bHoldPeriodCnt) {
+                       RTPRINT(FBT, BT_TRACE, ("Hold BT inquiry/page scan setting (cnt = %d)!!\n",
+                               pBtMgnt->ExtConfig.bHoldPeriodCnt));
+                       if (pBtMgnt->ExtConfig.bHoldPeriodCnt >= 11) {
+                               pBtMgnt->ExtConfig.bHoldPeriodCnt = 0;
+                               /*  next time the coexist parameters should be reset again. */
+                       } else {
+                               pBtMgnt->ExtConfig.bHoldPeriodCnt++;
+                       }
+                       return;
+               }
+
+               if (pBtDbg->dbgCtrl)
+                       RTPRINT(FBT, BT_TRACE, ("[Dbg control], "));
+
+               pBtdm8723->curAlgorithm = btdm_ActionAlgorithm(padapter);
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Algorithm = %d \n", pBtdm8723->curAlgorithm));
+
+               if (btdm_Is2Ant8723ACommonAction(padapter)) {
+                       RTPRINT(FBT, BT_TRACE, ("Action 2-Ant common.\n"));
+                       pBtdm8723->bResetTdmaAdjust = true;
+               } else {
+                       if (pBtdm8723->curAlgorithm != pBtdm8723->preAlgorithm) {
+                               RTPRINT(FBT, BT_TRACE, ("[BTCoex], preAlgorithm =%d, curAlgorithm =%d\n",
+                               pBtdm8723->preAlgorithm, pBtdm8723->curAlgorithm));
+                               pBtdm8723->bResetTdmaAdjust = true;
+                       }
+                       switch (pBtdm8723->curAlgorithm) {
+                       case BT_2ANT_COEX_ALGO_SCO:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = SCO.\n"));
+                               btdm_2Ant8723ASCOAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_HID:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID.\n"));
+                               btdm_2Ant8723AHIDAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_A2DP:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = A2DP.\n"));
+                               btdm_2Ant8723AA2DPAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_PANEDR:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN(EDR).\n"));
+                               btdm_2Ant8723APANEDRAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_PANHS:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HS mode.\n"));
+                               btdm_2Ant8723APANHSAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_PANEDR_A2DP:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN+A2DP.\n"));
+                               btdm_2Ant8723APANEDRA2DPAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_PANEDR_HID:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN(EDR)+HID.\n"));
+                               btdm_2Ant8723APANEDRHIDAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID+A2DP+PAN.\n"));
+                               btdm_2Ant8723AHIDA2DPPANEDRAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_HID_A2DP:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID+A2DP.\n"));
+                               btdm_2Ant8723AHIDA2DPAction(padapter);
+                               break;
+                       default:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = 0.\n"));
+                               btdm_2Ant8723AA2DPAction(padapter);
+                               break;
+                       }
+                       pBtdm8723->preAlgorithm = pBtdm8723->curAlgorithm;
+               }
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex] Get bt info by fw!!\n"));
+               /* msg shows c2h rsp for bt_info is received or not. */
+               if (pHalData->bt_coexist.halCoex8723.bC2hBtInfoReqSent)
+                       RTPRINT(FBT, BT_TRACE, ("[BTCoex] c2h for btInfo not rcvd yet!!\n"));
+
+               btInfoOriginal = pHalData->bt_coexist.halCoex8723.c2hBtInfoOriginal;
+
+               if (pBtMgnt->ExtConfig.bHoldForBtOperation) {
+                       RTPRINT(FBT, BT_TRACE, ("Action for BT Operation adjust!!\n"));
+                       return;
+               }
+               if (pBtMgnt->ExtConfig.bHoldPeriodCnt) {
+                       RTPRINT(FBT, BT_TRACE,
+                               ("Hold BT inquiry/page scan setting (cnt = %d)!!\n",
+                               pBtMgnt->ExtConfig.bHoldPeriodCnt));
+                       if (pBtMgnt->ExtConfig.bHoldPeriodCnt >= 11) {
+                               pBtMgnt->ExtConfig.bHoldPeriodCnt = 0;
+                               /*  next time the coexist parameters should be reset again. */
+                       } else {
+                                pBtMgnt->ExtConfig.bHoldPeriodCnt++;
+                       }
+                       return;
+               }
+
+               if (pBtDbg->dbgCtrl)
+                       RTPRINT(FBT, BT_TRACE, ("[Dbg control], "));
+               if (btdm_Is2Ant8723ACommonAction(padapter)) {
+                       RTPRINT(FBT, BT_TRACE, ("Action 2-Ant common.\n"));
+                       pBtdm8723->bResetTdmaAdjust = true;
+               } else {
+                       if (pBtdm8723->curAlgorithm != pBtdm8723->preAlgorithm) {
+                               RTPRINT(FBT, BT_TRACE,
+                                       ("[BTCoex], preAlgorithm =%d, curAlgorithm =%d\n",
+                                       pBtdm8723->preAlgorithm,
+                                       pBtdm8723->curAlgorithm));
+                               pBtdm8723->bResetTdmaAdjust = true;
+                       }
+                       switch (pBtdm8723->curAlgorithm) {
+                       case BT_2ANT_COEX_ALGO_SCO:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = SCO.\n"));
+                               btdm_2Ant8723ASCOAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_HID:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID.\n"));
+                               btdm_2Ant8723AHIDAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_A2DP:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = A2DP.\n"));
+                               btdm_2Ant8723AA2dp(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_PANEDR:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN(EDR).\n"));
+                               btdm_2Ant8723APANEDRAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_PANHS:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HS mode.\n"));
+                               btdm_2Ant8723APANHSAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_PANEDR_A2DP:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN+A2DP.\n"));
+                               btdm_2Ant8723APANEDRA2DPAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_PANEDR_HID:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = PAN(EDR)+HID.\n"));
+                               btdm_2Ant8723APANEDRHIDAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID+A2DP+PAN.\n"));
+                               btdm_2Ant8723AHIDA2DPPANEDRAction(padapter);
+                               break;
+                       case BT_2ANT_COEX_ALGO_HID_A2DP:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = HID+A2DP.\n"));
+                               btdm_2Ant8723AHIDA2DPAction(padapter);
+                               break;
+                       default:
+                               RTPRINT(FBT, BT_TRACE, ("Action 2-Ant, algorithm = 0.\n"));
+                               btdm_2Ant8723AA2DPAction(padapter);
+                               break;
+                       }
+                       pBtdm8723->preAlgorithm = pBtdm8723->curAlgorithm;
+               }
+       }
+}
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.c ===== */
+#endif
+
+#ifdef __HALBTC8723_C__ /*  HAL/BTCoexist/HalBtc8723.c */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc8723.c ===== */
+
+static u8 btCoexDbgBuf[BT_TMP_BUF_SIZE];
+
+static const char *const BtProfileString[] = {
+       "NONE",
+       "A2DP",
+       "PAN",
+       "HID",
+       "SCO",
+};
+
+static const char *const BtSpecString[] = {
+       "1.0b",
+       "1.1",
+       "1.2",
+       "2.0+EDR",
+       "2.1+EDR",
+       "3.0+HS",
+       "4.0",
+};
+
+static const char *const BtLinkRoleString[] = {
+       "Master",
+       "Slave",
+};
+
+static u8 btdm_BtWifiAntNum(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct bt_coexist_8723a *pBtCoex = &pHalData->bt_coexist.halCoex8723;
+
+       if (Ant_x2 == pHalData->bt_coexist.BT_Ant_Num) {
+               if (Ant_x2 == pBtCoex->TotalAntNum)
+                       return Ant_x2;
+               else
+                       return Ant_x1;
+       } else {
+               return Ant_x1;
+       }
+       return Ant_x2;
+}
+
+static void btdm_BtHwCountersMonitor(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u32     regHPTxRx, regLPTxRx, u4Tmp;
+       u32     regHPTx = 0, regHPRx = 0, regLPTx = 0, regLPRx = 0;
+
+       regHPTxRx = REG_HIGH_PRIORITY_TXRX;
+       regLPTxRx = REG_LOW_PRIORITY_TXRX;
+
+       u4Tmp = rtw_read32(padapter, regHPTxRx);
+       regHPTx = u4Tmp & bMaskLWord;
+       regHPRx = (u4Tmp & bMaskHWord)>>16;
+
+       u4Tmp = rtw_read32(padapter, regLPTxRx);
+       regLPTx = u4Tmp & bMaskLWord;
+       regLPRx = (u4Tmp & bMaskHWord)>>16;
+
+       pHalData->bt_coexist.halCoex8723.highPriorityTx = regHPTx;
+       pHalData->bt_coexist.halCoex8723.highPriorityRx = regHPRx;
+       pHalData->bt_coexist.halCoex8723.lowPriorityTx = regLPTx;
+       pHalData->bt_coexist.halCoex8723.lowPriorityRx = regLPRx;
+
+       RTPRINT(FBT, BT_TRACE, ("High Priority Tx/Rx = %d / %d\n", regHPTx, regHPRx));
+       RTPRINT(FBT, BT_TRACE, ("Low Priority Tx/Rx = %d / %d\n", regLPTx, regLPRx));
+
+       /*  reset counter */
+       rtw_write8(padapter, 0x76e, 0xc);
+}
+
+/*  This function check if 8723 bt is disabled */
+static void btdm_BtEnableDisableCheck8723A(struct rtw_adapter *padapter)
+{
+       u8 btAlife = true;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+#ifdef CHECK_BT_EXIST_FROM_REG
+       u8 val8;
+
+       /*  ox68[28]= 1 => BT enable; otherwise disable */
+       val8 = rtw_read8(padapter, 0x6B);
+       if (!(val8 & BIT(4)))
+               btAlife = false;
+
+       if (btAlife)
+               pHalData->bt_coexist.bCurBtDisabled = false;
+       else
+               pHalData->bt_coexist.bCurBtDisabled = true;
+#else
+       if (pHalData->bt_coexist.halCoex8723.highPriorityTx == 0 &&
+           pHalData->bt_coexist.halCoex8723.highPriorityRx == 0 &&
+           pHalData->bt_coexist.halCoex8723.lowPriorityTx == 0 &&
+           pHalData->bt_coexist.halCoex8723.lowPriorityRx == 0)
+               btAlife = false;
+       if (pHalData->bt_coexist.halCoex8723.highPriorityTx == 0xeaea &&
+           pHalData->bt_coexist.halCoex8723.highPriorityRx == 0xeaea &&
+           pHalData->bt_coexist.halCoex8723.lowPriorityTx == 0xeaea &&
+           pHalData->bt_coexist.halCoex8723.lowPriorityRx == 0xeaea)
+               btAlife = false;
+       if (pHalData->bt_coexist.halCoex8723.highPriorityTx == 0xffff &&
+           pHalData->bt_coexist.halCoex8723.highPriorityRx == 0xffff &&
+           pHalData->bt_coexist.halCoex8723.lowPriorityTx == 0xffff &&
+           pHalData->bt_coexist.halCoex8723.lowPriorityRx == 0xffff)
+               btAlife = false;
+       if (btAlife) {
+               pHalData->bt_coexist.btActiveZeroCnt = 0;
+               pHalData->bt_coexist.bCurBtDisabled = false;
+               RTPRINT(FBT, BT_TRACE, ("8723A BT is enabled !!\n"));
+       } else {
+               pHalData->bt_coexist.btActiveZeroCnt++;
+               RTPRINT(FBT, BT_TRACE, ("8723A bt all counters = 0, %d times!!\n",
+                               pHalData->bt_coexist.btActiveZeroCnt));
+               if (pHalData->bt_coexist.btActiveZeroCnt >= 2) {
+                       pHalData->bt_coexist.bCurBtDisabled = true;
+                       RTPRINT(FBT, BT_TRACE, ("8723A BT is disabled !!\n"));
+               }
+       }
+#endif
+
+       if (!pHalData->bt_coexist.bCurBtDisabled) {
+               if (BTDM_IsWifiConnectionExist(padapter))
+                       BTDM_SetFwChnlInfo(padapter, RT_MEDIA_CONNECT);
+               else
+                       BTDM_SetFwChnlInfo(padapter, RT_MEDIA_DISCONNECT);
+       }
+
+       if (pHalData->bt_coexist.bPreBtDisabled !=
+           pHalData->bt_coexist.bCurBtDisabled) {
+               RTPRINT(FBT, BT_TRACE, ("8723A BT is from %s to %s!!\n",
+                       (pHalData->bt_coexist.bPreBtDisabled ? "disabled":"enabled"),
+                       (pHalData->bt_coexist.bCurBtDisabled ? "disabled":"enabled")));
+               pHalData->bt_coexist.bPreBtDisabled = pHalData->bt_coexist.bCurBtDisabled;
+       }
+}
+
+static void btdm_BTCoexist8723AHandler(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+
+       pHalData = GET_HAL_DATA(padapter);
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x2) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], 2 Ant mechanism\n"));
+               BTDM_2AntBtCoexist8723A(padapter);
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], 1 Ant mechanism\n"));
+               BTDM_1AntBtCoexist8723A(padapter);
+       }
+
+       if (!BTDM_IsSameCoexistState(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Coexist State[bitMap] change from 0x%"i64fmt"x to 0x%"i64fmt"x\n",
+                       pHalData->bt_coexist.PreviousState,
+                       pHalData->bt_coexist.CurrentState));
+               pHalData->bt_coexist.PreviousState = pHalData->bt_coexist.CurrentState;
+
+               RTPRINT(FBT, BT_TRACE, ("["));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_BT30)
+                       RTPRINT(FBT, BT_TRACE, ("BT 3.0, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_HT20)
+                       RTPRINT(FBT, BT_TRACE, ("HT20, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_HT40)
+                       RTPRINT(FBT, BT_TRACE, ("HT40, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_LEGACY)
+                       RTPRINT(FBT, BT_TRACE, ("Legacy, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_RSSI_LOW)
+                       RTPRINT(FBT, BT_TRACE, ("Rssi_Low, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_RSSI_MEDIUM)
+                       RTPRINT(FBT, BT_TRACE, ("Rssi_Mid, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_RSSI_HIGH)
+                       RTPRINT(FBT, BT_TRACE, ("Rssi_High, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_IDLE)
+                       RTPRINT(FBT, BT_TRACE, ("Wifi_Idle, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_UPLINK)
+                       RTPRINT(FBT, BT_TRACE, ("Wifi_Uplink, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_WIFI_DOWNLINK)
+                       RTPRINT(FBT, BT_TRACE, ("Wifi_Downlink, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_BT_IDLE)
+                       RTPRINT(FBT, BT_TRACE, ("BT_idle, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_PROFILE_HID)
+                       RTPRINT(FBT, BT_TRACE, ("PRO_HID, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_PROFILE_A2DP)
+                       RTPRINT(FBT, BT_TRACE, ("PRO_A2DP, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_PROFILE_PAN)
+                       RTPRINT(FBT, BT_TRACE, ("PRO_PAN, "));
+               if (pHalData->bt_coexist.CurrentState & BT_COEX_STATE_PROFILE_SCO)
+                       RTPRINT(FBT, BT_TRACE, ("PRO_SCO, "));
+               RTPRINT(FBT, BT_TRACE, ("]\n"));
+       }
+}
+
+/*  extern function start with BTDM_ */
+u32 BTDM_BtTxRxCounterH(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u32     counters = 0;
+
+       counters = pHalData->bt_coexist.halCoex8723.highPriorityTx+
+               pHalData->bt_coexist.halCoex8723.highPriorityRx;
+       return counters;
+}
+
+u32 BTDM_BtTxRxCounterL(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u32     counters = 0;
+
+       counters = pHalData->bt_coexist.halCoex8723.lowPriorityTx+
+               pHalData->bt_coexist.halCoex8723.lowPriorityRx ;
+       return counters;
+}
+
+void BTDM_SetFwChnlInfo(struct rtw_adapter *padapter, enum rt_media_status mstatus)
+{
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       u8 H2C_Parameter[3] = {0};
+       u8 chnl;
+
+       /*  opMode */
+       if (RT_MEDIA_CONNECT == mstatus)
+               H2C_Parameter[0] = 0x1; /*  0: disconnected, 1:connected */
+
+       if (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE)) {
+               /*  channel */
+               chnl = pmlmeext->cur_channel;
+               if (BTDM_IsHT40(padapter)) {
+                       if (pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+                               chnl -= 2;
+                       else if (pmlmeext->cur_ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+                               chnl += 2;
+               }
+               H2C_Parameter[1] = chnl;
+       } else {        /*  check if HS link is exists */
+               /*  channel */
+               if (BT_Operation(padapter))
+                       H2C_Parameter[1] = pBtMgnt->BTChannel;
+               else
+                       H2C_Parameter[1] = pmlmeext->cur_channel;
+       }
+
+       if (BTDM_IsHT40(padapter))
+               H2C_Parameter[2] = 0x30;
+       else
+               H2C_Parameter[2] = 0x20;
+
+       FillH2CCmd(padapter, 0x19, 3, H2C_Parameter);
+}
+
+u8 BTDM_IsWifiConnectionExist(struct rtw_adapter *padapter)
+{
+       u8 bRet = false;
+
+       if (BTHCI_HsConnectionEstablished(padapter))
+               bRet = true;
+
+       if (check_fwstate(&padapter->mlmepriv, WIFI_ASOC_STATE) == true)
+               bRet = true;
+
+       return bRet;
+}
+
+void BTDM_SetFw3a(
+       struct rtw_adapter *padapter,
+       u8 byte1,
+       u8 byte2,
+       u8 byte3,
+       u8 byte4,
+       u8 byte5
+       )
+{
+       u8 H2C_Parameter[5] = {0};
+
+       if (BTDM_1Ant8723A(padapter)) {
+               if ((!check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE)) &&
+                   (get_fwstate(&padapter->mlmepriv) != WIFI_NULL_STATE)) {
+                       /*  for softap mode */
+                       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+                       struct bt_coexist_8723a *pBtCoex = &pHalData->bt_coexist.halCoex8723;
+                       u8 BtState = pBtCoex->c2hBtInfo;
+
+                       if ((BtState != BT_INFO_STATE_NO_CONNECTION) &&
+                           (BtState != BT_INFO_STATE_CONNECT_IDLE)) {
+                               if (byte1 & BIT(4)) {
+                                       byte1 &= ~BIT(4);
+                                       byte1 |= BIT(5);
+                               }
+
+                               byte5 |= BIT(5);
+                               if (byte5 & BIT(6))
+                                       byte5 &= ~BIT(6);
+                       }
+               }
+       }
+
+       H2C_Parameter[0] = byte1;
+       H2C_Parameter[1] = byte2;
+       H2C_Parameter[2] = byte3;
+       H2C_Parameter[3] = byte4;
+       H2C_Parameter[4] = byte5;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], FW write 0x3a(5bytes) = 0x%02x%08x\n",
+               H2C_Parameter[0],
+               H2C_Parameter[1]<<24|H2C_Parameter[2]<<16|H2C_Parameter[3]<<8|H2C_Parameter[4]));
+
+       FillH2CCmd(padapter, 0x3a, 5, H2C_Parameter);
+}
+
+void BTDM_QueryBtInformation(struct rtw_adapter *padapter)
+{
+       u8 H2C_Parameter[1] = {0};
+       struct hal_data_8723a *pHalData;
+       struct bt_coexist_8723a *pBtCoex;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBtCoex = &pHalData->bt_coexist.halCoex8723;
+
+       if (BT_IsBtDisabled(padapter)) {
+               pBtCoex->c2hBtInfo = BT_INFO_STATE_DISABLED;
+               pBtCoex->bC2hBtInfoReqSent = false;
+               return;
+       }
+
+       if (pBtCoex->c2hBtInfo == BT_INFO_STATE_DISABLED)
+               pBtCoex->c2hBtInfo = BT_INFO_STATE_NO_CONNECTION;
+
+       if (pBtCoex->bC2hBtInfoReqSent == true)
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], didn't recv previous BtInfo report!\n"));
+       else
+               pBtCoex->bC2hBtInfoReqSent = true;
+
+       H2C_Parameter[0] |= BIT(0);     /*  trigger */
+
+/*RTPRINT(FBT, BT_TRACE, ("[BTCoex], Query Bt information, write 0x38 = 0x%x\n", */
+/*H2C_Parameter[0])); */
+
+       FillH2CCmd(padapter, 0x38, 1, H2C_Parameter);
+}
+
+void BTDM_SetSwRfRxLpfCorner(struct rtw_adapter *padapter, u8 type)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (BT_RF_RX_LPF_CORNER_SHRINK == type) {
+               /* Shrink RF Rx LPF corner */
+               RTPRINT(FBT, BT_TRACE, ("Shrink RF Rx LPF corner!!\n"));
+               PHY_SetRFReg(padapter, PathA, 0x1e, bRFRegOffsetMask, 0xf0ff7);
+               pHalData->bt_coexist.bSWCoexistAllOff = false;
+       } else if (BT_RF_RX_LPF_CORNER_RESUME == type) {
+               /* Resume RF Rx LPF corner */
+               RTPRINT(FBT, BT_TRACE, ("Resume RF Rx LPF corner!!\n"));
+               PHY_SetRFReg(padapter, PathA, 0x1e, bRFRegOffsetMask, pHalData->bt_coexist.BtRfRegOrigin1E);
+       }
+}
+
+void
+BTDM_SetSwPenaltyTxRateAdaptive(
+       struct rtw_adapter *padapter,
+       u8 raType
+       )
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 tmpU1;
+
+       tmpU1 = rtw_read8(padapter, 0x4fd);
+       tmpU1 |= BIT(0);
+       if (BT_TX_RATE_ADAPTIVE_LOW_PENALTY == raType) {
+               tmpU1 &= ~BIT(2);
+               pHalData->bt_coexist.bSWCoexistAllOff = false;
+       } else if (BT_TX_RATE_ADAPTIVE_NORMAL == raType) {
+               tmpU1 |= BIT(2);
+       }
+
+       rtw_write8(padapter, 0x4fd, tmpU1);
+}
+
+void BTDM_SetFwDecBtPwr(struct rtw_adapter *padapter, u8 bDecBtPwr)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 H2C_Parameter[1] = {0};
+
+       H2C_Parameter[0] = 0;
+
+       if (bDecBtPwr) {
+               H2C_Parameter[0] |= BIT(1);
+               pHalData->bt_coexist.bFWCoexistAllOff = false;
+       }
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], decrease Bt Power : %s, write 0x21 = 0x%x\n",
+               (bDecBtPwr ? "Yes!!" : "No!!"), H2C_Parameter[0]));
+
+       FillH2CCmd(padapter, 0x21, 1, H2C_Parameter);
+}
+
+u8 BTDM_BtProfileSupport(struct rtw_adapter *padapter)
+{
+       u8 bRet = false;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (pBtMgnt->bSupportProfile &&
+           !pHalData->bt_coexist.halCoex8723.bForceFwBtInfo)
+               bRet = true;
+
+       return bRet;
+}
+
+static void BTDM_AdjustForBtOperation8723A(struct rtw_adapter *padapter)
+{
+       /* BTDM_2AntAdjustForBtOperation8723(padapter); */
+}
+
+static void BTDM_FwC2hBtRssi8723A(struct rtw_adapter *padapter, u8 *tmpBuf)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 percent = 0, u1tmp = 0;
+
+       u1tmp = tmpBuf[0];
+       percent = u1tmp*2+10;
+
+       pHalData->bt_coexist.halCoex8723.btRssi = percent;
+/*RTPRINT(FBT, BT_TRACE, ("[BTC2H], BT RSSI =%d\n", percent)); */
+}
+
+static void
+BTDM_FwC2hBtInfo8723A(struct rtw_adapter *padapter, u8 *tmpBuf, u8 length)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_coexist_8723a *pBtCoex;
+       u8 i;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtCoex = &pHalData->bt_coexist.halCoex8723;
+
+       pBtCoex->bC2hBtInfoReqSent = false;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTC2H], BT info[%d]=[", length));
+
+       pBtCoex->btRetryCnt = 0;
+       for (i = 0; i < length; i++) {
+               switch (i) {
+               case 0:
+                       pBtCoex->c2hBtInfoOriginal = tmpBuf[i];
+                       break;
+               case 1:
+                       pBtCoex->btRetryCnt = tmpBuf[i];
+                       break;
+               case 2:
+                       BTDM_FwC2hBtRssi8723A(padapter, &tmpBuf[i]);
+                       break;
+               case 3:
+                       pBtCoex->btInfoExt = tmpBuf[i]&BIT(0);
+                       break;
+               }
+
+               if (i == length-1)
+                       RTPRINT(FBT, BT_TRACE, ("0x%02x]\n", tmpBuf[i]));
+               else
+                       RTPRINT(FBT, BT_TRACE, ("0x%02x, ", tmpBuf[i]));
+       }
+       RTPRINT(FBT, BT_TRACE, ("[BTC2H], BT RSSI =%d\n", pBtCoex->btRssi));
+       if (pBtCoex->btInfoExt)
+               RTPRINT(FBT, BT_TRACE, ("[BTC2H], pBtCoex->btInfoExt =%x\n", pBtCoex->btInfoExt));
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+               BTDM_1AntFwC2hBtInfo8723A(padapter);
+       else
+               BTDM_2AntFwC2hBtInfo8723A(padapter);
+
+       if (pBtMgnt->ExtConfig.bManualControl) {
+               RTPRINT(FBT, BT_TRACE, ("%s: Action Manual control!!\n", __func__));
+               return;
+       }
+
+       btdm_BTCoexist8723AHandler(padapter);
+}
+
+static void BTDM_Display8723ABtCoexInfo(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct bt_coexist_8723a *pBtCoex = &pHalData->bt_coexist.halCoex8723;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       u8 u1Tmp, u1Tmp1, u1Tmp2, i, btInfoExt, psTdmaCase = 0;
+       u32 u4Tmp[4];
+       u8 antNum = Ant_x2;
+
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n ============[BT Coexist info]============");
+       DCMD_Printf(btCoexDbgBuf);
+
+       if (!pHalData->bt_coexist.BluetoothCoexist) {
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n BT not exists !!!");
+               DCMD_Printf(btCoexDbgBuf);
+               return;
+       }
+
+       antNum = btdm_BtWifiAntNum(padapter);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d/%d ", "Ant mechanism PG/Now run :", \
+               ((pHalData->bt_coexist.BT_Ant_Num == Ant_x2) ? 2 : 1), ((antNum == Ant_x2) ? 2 : 1));
+       DCMD_Printf(btCoexDbgBuf);
+
+       if (pBtMgnt->ExtConfig.bManualControl) {
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "[Action Manual control]!!");
+               DCMD_Printf(btCoexDbgBuf);
+       } else {
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s / %d", "BT stack/ hci ext ver", \
+                       ((pBtMgnt->bSupportProfile) ? "Yes" : "No"), pBtMgnt->ExtConfig.HCIExtensionVer);
+               DCMD_Printf(btCoexDbgBuf);
+       }
+
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\n %-35s = / %d", "Dot11 channel / BT channel", \
+               pBtMgnt->BTChannel);
+               DCMD_Printf(btCoexDbgBuf);
+
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\n %-35s = %d / %d / %d", "Wifi/BT/HS rssi", \
+               BTDM_GetRxSS(padapter),
+               pHalData->bt_coexist.halCoex8723.btRssi,
+               pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB);
+                       DCMD_Printf(btCoexDbgBuf);
+
+       if (!pBtMgnt->ExtConfig.bManualControl) {
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\n %-35s = %s / %s ", "WIfi status",
+                       ((BTDM_Legacy(padapter)) ? "Legacy" : (((BTDM_IsHT40(padapter)) ? "HT40" : "HT20"))),
+                       ((!BTDM_IsWifiBusy(padapter)) ? "idle" : ((BTDM_IsWifiUplink(padapter)) ? "uplink" : "downlink")));
+               DCMD_Printf(btCoexDbgBuf);
+
+               if (pBtMgnt->bSupportProfile) {
+                       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d / %d / %d", "SCO/HID/PAN/A2DP",
+                               ((BTHCI_CheckProfileExist(padapter, BT_PROFILE_SCO)) ? 1 : 0),
+                               ((BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID)) ? 1 : 0),
+                               ((BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) ? 1 : 0),
+                               ((BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) ? 1 : 0));
+               DCMD_Printf(btCoexDbgBuf);
+
+                       for (i = 0; i < pBtMgnt->ExtConfig.NumberOfHandle; i++) {
+                               if (pBtMgnt->ExtConfig.HCIExtensionVer >= 1) {
+                                       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s/ %s", "Bt link type/spec/role",
+                                               BtProfileString[pBtMgnt->ExtConfig.linkInfo[i].BTProfile],
+                                               BtSpecString[pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec],
+                                               BtLinkRoleString[pBtMgnt->ExtConfig.linkInfo[i].linkRole]);
+                                       DCMD_Printf(btCoexDbgBuf);
+
+                                       btInfoExt = pHalData->bt_coexist.halCoex8723.btInfoExt;
+                                       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s", "A2DP rate", \
+                                               (btInfoExt&BIT0) ? "Basic rate" : "EDR rate");
+                                       DCMD_Printf(btCoexDbgBuf);
+                               } else {
+                                       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %s/ %s", "Bt link type/spec", \
+                                               BtProfileString[pBtMgnt->ExtConfig.linkInfo[i].BTProfile],
+                                               BtSpecString[pBtMgnt->ExtConfig.linkInfo[i].BTCoreSpec]);
+                                       DCMD_Printf(btCoexDbgBuf);
+                               }
+                       }
+               }
+       }
+
+       /*  Sw mechanism */
+       if (!pBtMgnt->ExtConfig.bManualControl) {
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Sw BT Coex mechanism]============");
+               DCMD_Printf(btCoexDbgBuf);
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "AGC Table", \
+                       pBtCoex->btdm2Ant.bCurAgcTableEn);
+               DCMD_Printf(btCoexDbgBuf);
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "ADC Backoff", \
+                       pBtCoex->btdm2Ant.bCurAdcBackOff);
+               DCMD_Printf(btCoexDbgBuf);
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "Low penalty RA", \
+                       pBtCoex->btdm2Ant.bCurLowPenaltyRa);
+               DCMD_Printf(btCoexDbgBuf);
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "RF Rx LPF Shrink", \
+                       pBtCoex->btdm2Ant.bCurRfRxLpfShrink);
+               DCMD_Printf(btCoexDbgBuf);
+       }
+       u4Tmp[0] = PHY_QueryRFReg(padapter, PathA, 0x1e, 0xff0);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x", "RF-A, 0x1e[11:4]/original val", \
+               u4Tmp[0], pHalData->bt_coexist.BtRfRegOrigin1E);
+       DCMD_Printf(btCoexDbgBuf);
+
+       /*  Fw mechanism */
+       if (!pBtMgnt->ExtConfig.bManualControl) {
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Fw BT Coex mechanism]============");
+               DCMD_Printf(btCoexDbgBuf);
+       }
+       if (!pBtMgnt->ExtConfig.bManualControl) {
+               if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+                       psTdmaCase = pHalData->bt_coexist.halCoex8723.btdm1Ant.curPsTdma;
+               else
+                       psTdmaCase = pHalData->bt_coexist.halCoex8723.btdm2Ant.curPsTdma;
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %02x %02x %02x %02x %02x case-%d", "PS TDMA(0x3a)", \
+                       pHalData->bt_coexist.fw3aVal[0], pHalData->bt_coexist.fw3aVal[1],
+                       pHalData->bt_coexist.fw3aVal[2], pHalData->bt_coexist.fw3aVal[3],
+                       pHalData->bt_coexist.fw3aVal[4], psTdmaCase);
+               DCMD_Printf(btCoexDbgBuf);
+
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d ", "Decrease Bt Power", \
+                       pBtCoex->btdm2Ant.bCurDecBtPwr);
+               DCMD_Printf(btCoexDbgBuf);
+       }
+       u1Tmp = rtw_read8(padapter, 0x778);
+       u1Tmp1 = rtw_read8(padapter, 0x783);
+       u1Tmp2 = rtw_read8(padapter, 0x796);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x", "0x778/ 0x783/ 0x796", \
+               u1Tmp, u1Tmp1, u1Tmp2);
+       DCMD_Printf(btCoexDbgBuf);
+
+       if (!pBtMgnt->ExtConfig.bManualControl) {
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x / 0x%x", "Sw DacSwing Ctrl/Val", \
+                       pBtCoex->btdm2Ant.bCurDacSwingOn, pBtCoex->btdm2Ant.curDacSwingLvl);
+               DCMD_Printf(btCoexDbgBuf);
+       }
+       u4Tmp[0] =  rtw_read32(padapter, 0x880);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x880", \
+               u4Tmp[0]);
+       DCMD_Printf(btCoexDbgBuf);
+
+       /*  Hw mechanism */
+       if (!pBtMgnt->ExtConfig.bManualControl) {
+               rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s", "============[Hw BT Coex mechanism]============");
+               DCMD_Printf(btCoexDbgBuf);
+       }
+
+       u1Tmp = rtw_read8(padapter, 0x40);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x40", \
+               u1Tmp);
+       DCMD_Printf(btCoexDbgBuf);
+
+       u4Tmp[0] = rtw_read32(padapter, 0x550);
+       u1Tmp = rtw_read8(padapter, 0x522);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/0x%x", "0x550(bcn contrl)/0x522", \
+               u4Tmp[0], u1Tmp);
+       DCMD_Printf(btCoexDbgBuf);
+
+       u4Tmp[0] = rtw_read32(padapter, 0x484);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x484(rate adaptive)", \
+               u4Tmp[0]);
+       DCMD_Printf(btCoexDbgBuf);
+
+       u4Tmp[0] = rtw_read32(padapter, 0x50);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0xc50(dig)", \
+               u4Tmp[0]);
+       DCMD_Printf(btCoexDbgBuf);
+
+       u4Tmp[0] = rtw_read32(padapter, 0xda0);
+       u4Tmp[1] = rtw_read32(padapter, 0xda4);
+       u4Tmp[2] = rtw_read32(padapter, 0xda8);
+       u4Tmp[3] = rtw_read32(padapter, 0xdac);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0xda0/0xda4/0xda8/0xdac(FA cnt)", \
+               u4Tmp[0], u4Tmp[1], u4Tmp[2], u4Tmp[3]);
+       DCMD_Printf(btCoexDbgBuf);
+
+       u4Tmp[0] = rtw_read32(padapter, 0x6c0);
+       u4Tmp[1] = rtw_read32(padapter, 0x6c4);
+       u4Tmp[2] = rtw_read32(padapter, 0x6c8);
+       u1Tmp = rtw_read8(padapter, 0x6cc);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x/ 0x%x/ 0x%x/ 0x%x", "0x6c0/0x6c4/0x6c8/0x6cc(coexTable)", \
+               u4Tmp[0], u4Tmp[1], u4Tmp[2], u1Tmp);
+       DCMD_Printf(btCoexDbgBuf);
+
+       /* u4Tmp = rtw_read32(padapter, 0x770); */
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d", "0x770(Hi pri Rx[31:16]/Tx[15:0])", \
+               pHalData->bt_coexist.halCoex8723.highPriorityRx,
+               pHalData->bt_coexist.halCoex8723.highPriorityTx);
+       DCMD_Printf(btCoexDbgBuf);
+       /* u4Tmp = rtw_read32(padapter, 0x774); */
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = %d / %d", "0x774(Lo pri Rx[31:16]/Tx[15:0])", \
+               pHalData->bt_coexist.halCoex8723.lowPriorityRx,
+               pHalData->bt_coexist.halCoex8723.lowPriorityTx);
+       DCMD_Printf(btCoexDbgBuf);
+
+       /*  Tx mgnt queue hang or not, 0x41b should = 0xf, ex: 0xd ==>hang */
+       u1Tmp = rtw_read8(padapter, 0x41b);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "0x41b (hang chk == 0xf)", \
+               u1Tmp);
+       DCMD_Printf(btCoexDbgBuf);
+       rsprintf(btCoexDbgBuf, BT_TMP_BUF_SIZE, "\r\n %-35s = 0x%x", "lastHMEBoxNum", \
+               pHalData->LastHMEBoxNum);
+       DCMD_Printf(btCoexDbgBuf);
+}
+
+static void
+BTDM_8723ASignalCompensation(struct rtw_adapter *padapter,
+                            u8 *rssi_wifi, u8 *rssi_bt)
+{
+       if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+               BTDM_1AntSignalCompensation(padapter, rssi_wifi, rssi_bt);
+}
+
+static void BTDM_8723AInit(struct rtw_adapter *padapter)
+{
+       if (btdm_BtWifiAntNum(padapter) == Ant_x2)
+               BTDM_2AntParaInit(padapter);
+       else
+               BTDM_1AntParaInit(padapter);
+}
+
+static void BTDM_HWCoexAllOff8723A(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x2)
+               BTDM_2AntHwCoexAllOff8723A(padapter);
+}
+
+static void BTDM_FWCoexAllOff8723A(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x2)
+               BTDM_2AntFwCoexAllOff8723A(padapter);
+}
+
+static void BTDM_SWCoexAllOff8723A(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x2)
+               BTDM_2AntSwCoexAllOff8723A(padapter);
+}
+
+static void
+BTDM_Set8723ABtCoexCurrAntNum(struct rtw_adapter *padapter, u8 antNum)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct bt_coexist_8723a *pBtCoex = &pHalData->bt_coexist.halCoex8723;
+
+       if (antNum == 1)
+               pBtCoex->TotalAntNum = Ant_x1;
+       else if (antNum == 2)
+               pBtCoex->TotalAntNum = Ant_x2;
+}
+
+void BTDM_LpsLeave(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+               BTDM_1AntLpsLeave(padapter);
+}
+
+static void BTDM_ForHalt8723A(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+               BTDM_1AntForHalt(padapter);
+}
+
+static void BTDM_WifiScanNotify8723A(struct rtw_adapter *padapter, u8 scanType)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+               BTDM_1AntWifiScanNotify(padapter, scanType);
+}
+
+static void
+BTDM_WifiAssociateNotify8723A(struct rtw_adapter *padapter, u8 action)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+               BTDM_1AntWifiAssociateNotify(padapter, action);
+}
+
+static void
+BTDM_MediaStatusNotify8723A(struct rtw_adapter *padapter,
+                           enum rt_media_status mstatus)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], MediaStatusNotify, %s\n",
+               mstatus?"connect":"disconnect"));
+
+       BTDM_SetFwChnlInfo(padapter, mstatus);
+
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+               BTDM_1AntMediaStatusNotify(padapter, mstatus);
+}
+
+static void BTDM_ForDhcp8723A(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+
+       if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+               BTDM_1AntForDhcp(padapter);
+}
+
+u8 BTDM_1Ant8723A(struct rtw_adapter *padapter)
+{
+       if (btdm_BtWifiAntNum(padapter) == Ant_x1)
+               return true;
+       else
+               return false;
+}
+
+static void BTDM_BTCoexist8723A(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_coexist_8723a *pBtCoex;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtCoex = &pHalData->bt_coexist.halCoex8723;
+
+       RTPRINT(FBT, BT_TRACE, ("[BTCoex], beacon RSSI = 0x%x(%d)\n",
+               pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB,
+               pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB));
+
+       btdm_BtHwCountersMonitor(padapter);
+       btdm_BtEnableDisableCheck8723A(padapter);
+
+       if (pBtMgnt->ExtConfig.bManualControl) {
+               RTPRINT(FBT, BT_TRACE, ("%s: Action Manual control!!\n", __func__));
+               return;
+       }
+
+       if (pBtCoex->bC2hBtInfoReqSent) {
+               if (BT_IsBtDisabled(padapter)) {
+                       pBtCoex->c2hBtInfo = BT_INFO_STATE_DISABLED;
+               } else {
+                       if (pBtCoex->c2hBtInfo == BT_INFO_STATE_DISABLED)
+                               pBtCoex->c2hBtInfo = BT_INFO_STATE_NO_CONNECTION;
+               }
+
+               btdm_BTCoexist8723AHandler(padapter);
+       } else if (BT_IsBtDisabled(padapter) == true) {
+               pBtCoex->c2hBtInfo = BT_INFO_STATE_DISABLED;
+               btdm_BTCoexist8723AHandler(padapter);
+       }
+
+       BTDM_QueryBtInformation(padapter);
+}
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc8723.c ===== */
+#endif
+
+#ifdef __HALBTCCSR1ANT_C__ /*  HAL/BTCoexist/HalBtcCsr1Ant.c */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.c ===== */
+
+/*  local function start with btdm_ */
+/*  extern function start with BTDM_ */
+
+static void BTDM_SetAntenna(struct rtw_adapter *padapter, u8 who)
+{
+}
+
+void
+BTDM_SingleAnt(
+       struct rtw_adapter *padapter,
+       u8 bSingleAntOn,
+       u8 bInterruptOn,
+       u8 bMultiNAVOn
+       )
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 H2C_Parameter[3] = {0};
+
+       if (pHalData->bt_coexist.BT_Ant_Num != Ant_x1)
+               return;
+
+       H2C_Parameter[2] = 0;
+       H2C_Parameter[1] = 0;
+       H2C_Parameter[0] = 0;
+
+       if (bInterruptOn) {
+               H2C_Parameter[2] |= 0x02;       /* BIT1 */
+               pHalData->bt_coexist.bFWCoexistAllOff = false;
+       }
+       pHalData->bt_coexist.bInterruptOn = bInterruptOn;
+
+       if (bSingleAntOn) {
+               H2C_Parameter[2] |= 0x10;       /* BIT4 */
+               pHalData->bt_coexist.bFWCoexistAllOff = false;
+       }
+       pHalData->bt_coexist.bSingleAntOn = bSingleAntOn;
+
+       if (bMultiNAVOn) {
+               H2C_Parameter[2] |= 0x20;       /* BIT5 */
+               pHalData->bt_coexist.bFWCoexistAllOff = false;
+       }
+       pHalData->bt_coexist.bMultiNAVOn = bMultiNAVOn;
+
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], SingleAntenna =[%s:%s:%s], write 0xe = 0x%x\n",
+               bSingleAntOn?"ON":"OFF", bInterruptOn?"ON":"OFF", bMultiNAVOn?"ON":"OFF",
+               H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2]));
+}
+
+void BTDM_CheckBTIdleChange1Ant(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+/*PMGNT_INFO           pMgntInfo = &padapter->MgntInfo; */
+       u8      stateChange = false;
+       u32                     BT_Polling, Ratio_Act, Ratio_STA;
+       u32                             BT_Active, BT_State;
+       u32                             regBTActive = 0, regBTState = 0, regBTPolling = 0;
+
+       if (!pHalData->bt_coexist.BluetoothCoexist)
+               return;
+       if (pBtMgnt->ExtConfig.bManualControl)
+               return;
+       if (pHalData->bt_coexist.BT_CoexistType != BT_CSR_BC8)
+               return;
+       if (pHalData->bt_coexist.BT_Ant_Num != Ant_x1)
+               return;
+
+       /*  The following we only consider CSR BC8 and fw version should be >= 62 */
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], FirmwareVersion = 0x%x(%d)\n",
+       pHalData->FirmwareVersion, pHalData->FirmwareVersion));
+       regBTActive = REG_BT_ACTIVE;
+       regBTState = REG_BT_STATE;
+       if (pHalData->FirmwareVersion >= FW_VER_BT_REG1)
+               regBTPolling = REG_BT_POLLING1;
+       else
+               regBTPolling = REG_BT_POLLING;
+
+       BT_Active = rtw_read32(padapter, regBTActive);
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT_Active(0x%x) =%x\n", regBTActive, BT_Active));
+       BT_Active = BT_Active & 0x00ffffff;
+
+       BT_State = rtw_read32(padapter, regBTState);
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT_State(0x%x) =%x\n", regBTState, BT_State));
+       BT_State = BT_State & 0x00ffffff;
+
+       BT_Polling = rtw_read32(padapter, regBTPolling);
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT_Polling(0x%x) =%x\n", regBTPolling, BT_Polling));
+
+       if (BT_Active == 0xffffffff && BT_State == 0xffffffff && BT_Polling == 0xffffffff)
+               return;
+       if (BT_Polling == 0)
+               return;
+
+       Ratio_Act = BT_Active*1000/BT_Polling;
+       Ratio_STA = BT_State*1000/BT_Polling;
+
+       pHalData->bt_coexist.Ratio_Tx = Ratio_Act;
+       pHalData->bt_coexist.Ratio_PRI = Ratio_STA;
+
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], Ratio_Act =%d\n", Ratio_Act));
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], Ratio_STA =%d\n", Ratio_STA));
+
+       if (Ratio_STA < 60 && Ratio_Act < 500) {        /*  BT PAN idle */
+               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_PAN_IDLE;
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_DOWNLINK;
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_UPLINK;
+       } else {
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_IDLE;
+
+               if (Ratio_STA) {
+                       /*  Check if BT PAN (under BT 2.1) is uplink or downlink */
+                       if ((Ratio_Act/Ratio_STA) < 2) {
+                               /*  BT PAN Uplink */
+                               pHalData->bt_coexist.BT21TrafficStatistics.bTxBusyTraffic = true;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_PAN_UPLINK;
+                               pHalData->bt_coexist.BT21TrafficStatistics.bRxBusyTraffic = false;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_DOWNLINK;
+                       } else {
+                               /*  BT PAN downlink */
+                               pHalData->bt_coexist.BT21TrafficStatistics.bTxBusyTraffic = false;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_UPLINK;
+                               pHalData->bt_coexist.BT21TrafficStatistics.bRxBusyTraffic = true;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_PAN_DOWNLINK;
+                       }
+               } else {
+                       /*  BT PAN downlink */
+                       pHalData->bt_coexist.BT21TrafficStatistics.bTxBusyTraffic = false;
+                       pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_PAN_UPLINK;
+                       pHalData->bt_coexist.BT21TrafficStatistics.bRxBusyTraffic = true;
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_PAN_DOWNLINK;
+               }
+       }
+
+       /*  Check BT is idle or not */
+       if (pBtMgnt->ExtConfig.NumberOfHandle == 0 &&
+           pBtMgnt->ExtConfig.NumberOfSCO == 0) {
+               pBtMgnt->ExtConfig.bBTBusy = false;
+               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_IDLE;
+       } else {
+               if (Ratio_STA < 60) {
+                       pBtMgnt->ExtConfig.bBTBusy = false;
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_IDLE;
+               } else {
+                       pBtMgnt->ExtConfig.bBTBusy = true;
+                       pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_IDLE;
+               }
+       }
+
+       if (pBtMgnt->ExtConfig.NumberOfHandle == 0 &&
+           pBtMgnt->ExtConfig.NumberOfSCO == 0) {
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_RSSI_LOW;
+               pBtMgnt->ExtConfig.MIN_BT_RSSI = 0;
+               BTDM_SetAntenna(padapter, BTDM_ANT_BT_IDLE);
+       } else {
+               if (pBtMgnt->ExtConfig.MIN_BT_RSSI <= -5) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT_RSSI_LOW;
+                       RTPRINT(FBT, BT_TRACE, ("[DM][BT], core stack notify bt rssi Low\n"));
+               } else {
+                       pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT_RSSI_LOW;
+                       RTPRINT(FBT, BT_TRACE, ("[DM][BT], core stack notify bt rssi Normal\n"));
+               }
+       }
+
+       if (pHalData->bt_coexist.bBTBusyTraffic != pBtMgnt->ExtConfig.bBTBusy) {
+               /*  BT idle or BT non-idle */
+               pHalData->bt_coexist.bBTBusyTraffic = pBtMgnt->ExtConfig.bBTBusy;
+               stateChange = true;
+       }
+
+       if (stateChange) {
+               if (!pBtMgnt->ExtConfig.bBTBusy)
+                       RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT is idle or disable\n"));
+               else
+                       RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT is non-idle\n"));
+       }
+       if (!pBtMgnt->ExtConfig.bBTBusy) {
+               RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT is idle or disable\n"));
+               if (check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING|WIFI_SITE_MONITOR) == true)
+                       BTDM_SetAntenna(padapter, BTDM_ANT_WIFI);
+       }
+}
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.c ===== */
+#endif
+
+#ifdef __HALBTCCSR2ANT_C__ /*  HAL/BTCoexist/HalBtcCsr2Ant.c */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.c ===== */
+
+/*  local function start with btdm_ */
+
+/*  Note: */
+/*  In the following, FW should be done before SW mechanism. */
+/*  BTDM_Balance(), BTDM_DiminishWiFi(), BT_NAV() should be done */
+/*  before BTDM_AGCTable(), BTDM_BBBackOffLevel(), btdm_DacSwing(). */
+
+/*  extern function start with BTDM_ */
+
+void
+BTDM_DiminishWiFi(
+       struct rtw_adapter *padapter,
+       u8 bDACOn,
+       u8 bInterruptOn,
+       u8 DACSwingLevel,
+       u8 bNAVOn
+       )
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 H2C_Parameter[3] = {0};
+
+       if (pHalData->bt_coexist.BT_Ant_Num != Ant_x2)
+               return;
+
+       if ((pHalData->bt_coexist.CurrentState & BT_COEX_STATE_BT_RSSI_LOW) &&
+           (DACSwingLevel == 0x20)) {
+               RTPRINT(FBT, BT_TRACE, ("[BT]DiminishWiFi 0x20 original, but set 0x18 for Low RSSI!\n"));
+               DACSwingLevel = 0x18;
+       }
+
+       H2C_Parameter[2] = 0;
+       H2C_Parameter[1] = DACSwingLevel;
+       H2C_Parameter[0] = 0;
+       if (bDACOn) {
+               H2C_Parameter[2] |= 0x01;       /* BIT0 */
+               if (bInterruptOn)
+                       H2C_Parameter[2] |= 0x02;       /* BIT1 */
+               pHalData->bt_coexist.bFWCoexistAllOff = false;
+       }
+       if (bNAVOn) {
+               H2C_Parameter[2] |= 0x08;       /* BIT3 */
+               pHalData->bt_coexist.bFWCoexistAllOff = false;
+       }
+
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], bDACOn = %s, bInterruptOn = %s, write 0xe = 0x%x\n",
+               bDACOn?"ON":"OFF", bInterruptOn?"ON":"OFF",
+               H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2]));
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], bNAVOn = %s\n",
+               bNAVOn?"ON":"OFF"));
+}
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.c ===== */
+#endif
+
+#ifdef __HALBTCOEXIST_C__ /*  HAL/BTCoexist/HalBtCoexist.c */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtCoexist.c ===== */
+
+/*  local function */
+static void btdm_ResetFWCoexState(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       pHalData->bt_coexist.CurrentState = 0;
+       pHalData->bt_coexist.PreviousState = 0;
+}
+
+static void btdm_InitBtCoexistDM(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       /*  20100415 Joseph: Restore RF register 0x1E and 0x1F value for further usage. */
+       pHalData->bt_coexist.BtRfRegOrigin1E = PHY_QueryRFReg(padapter, PathA, RF_RCK1, bRFRegOffsetMask);
+       pHalData->bt_coexist.BtRfRegOrigin1F = PHY_QueryRFReg(padapter, PathA, RF_RCK2, 0xf0);
+
+       pHalData->bt_coexist.CurrentState = 0;
+       pHalData->bt_coexist.PreviousState = 0;
+
+       BTDM_8723AInit(padapter);
+       pHalData->bt_coexist.bInitlized = true;
+}
+
+/*  */
+/*  extern function */
+/*  */
+void BTDM_CheckAntSelMode(struct rtw_adapter *padapter)
+{
+}
+
+void BTDM_FwC2hBtRssi(struct rtw_adapter *padapter, u8 *tmpBuf)
+{
+       BTDM_FwC2hBtRssi8723A(padapter, tmpBuf);
+}
+
+void BTDM_FwC2hBtInfo(struct rtw_adapter *padapter, u8 *tmpBuf, u8 length)
+{
+       BTDM_FwC2hBtInfo8723A(padapter, tmpBuf, length);
+}
+
+void BTDM_DisplayBtCoexInfo(struct rtw_adapter *padapter)
+{
+       BTDM_Display8723ABtCoexInfo(padapter);
+}
+
+void BTDM_RejectAPAggregatedPacket(struct rtw_adapter *padapter, u8 bReject)
+{
+}
+
+u8 BTDM_IsHT40(struct rtw_adapter *padapter)
+{
+       u8 isht40 = true;
+       enum ht_channel_width bw;
+
+       bw = padapter->mlmeextpriv.cur_bwmode;
+
+       if (bw == HT_CHANNEL_WIDTH_20)
+               isht40 = false;
+       else if (bw == HT_CHANNEL_WIDTH_40)
+               isht40 = true;
+
+       return isht40;
+}
+
+u8 BTDM_Legacy(struct rtw_adapter *padapter)
+{
+       struct mlme_ext_priv *pmlmeext;
+       u8 isLegacy = false;
+
+       pmlmeext = &padapter->mlmeextpriv;
+       if ((pmlmeext->cur_wireless_mode == WIRELESS_11B) ||
+               (pmlmeext->cur_wireless_mode == WIRELESS_11G) ||
+               (pmlmeext->cur_wireless_mode == WIRELESS_11BG))
+               isLegacy = true;
+
+       return isLegacy;
+}
+
+void BTDM_CheckWiFiState(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct mlme_priv *pmlmepriv;
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pmlmepriv = &padapter->mlmepriv;
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pmlmepriv->LinkDetectInfo.bBusyTraffic) {
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_IDLE;
+
+               if (pmlmepriv->LinkDetectInfo.bTxBusyTraffic)
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_UPLINK;
+               else
+                       pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_UPLINK;
+
+               if (pmlmepriv->LinkDetectInfo.bRxBusyTraffic)
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_DOWNLINK;
+               else
+                       pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_DOWNLINK;
+       } else {
+               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_IDLE;
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_UPLINK;
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_DOWNLINK;
+       }
+
+       if (BTDM_Legacy(padapter)) {
+               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_LEGACY;
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_HT20;
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_HT40;
+       } else {
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_LEGACY;
+               if (BTDM_IsHT40(padapter)) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_HT40;
+                       pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_HT20;
+               } else {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_HT20;
+                       pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_HT40;
+               }
+       }
+
+       if (pBtMgnt->BtOperationOn)
+               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_BT30;
+       else
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_BT30;
+}
+
+s32 BTDM_GetRxSS(struct rtw_adapter *padapter)
+{
+/*PMGNT_INFO           pMgntInfo = &padapter->MgntInfo; */
+       struct mlme_priv *pmlmepriv;
+       struct hal_data_8723a *pHalData;
+       s32                     UndecoratedSmoothedPWDB = 0;
+
+       pmlmepriv = &padapter->mlmepriv;
+       pHalData = GET_HAL_DATA(padapter);
+
+       if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+               UndecoratedSmoothedPWDB = GET_UNDECORATED_AVERAGE_RSSI(padapter);
+       } else { /*  associated entry pwdb */
+               UndecoratedSmoothedPWDB = pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB;
+               /* pHalData->BT_EntryMinUndecoratedSmoothedPWDB */
+       }
+       RTPRINT(FBT, BT_TRACE, ("BTDM_GetRxSS() = %d\n", UndecoratedSmoothedPWDB));
+       return UndecoratedSmoothedPWDB;
+}
+
+static s32 BTDM_GetRxBeaconSS(struct rtw_adapter *padapter)
+{
+/*PMGNT_INFO           pMgntInfo = &padapter->MgntInfo; */
+       struct mlme_priv *pmlmepriv;
+       struct hal_data_8723a *pHalData;
+       s32                     pwdbBeacon = 0;
+
+       pmlmepriv = &padapter->mlmepriv;
+       pHalData = GET_HAL_DATA(padapter);
+
+       if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+               /* pwdbBeacon = pHalData->dmpriv.UndecoratedSmoothedBeacon; */
+               pwdbBeacon = pHalData->dmpriv.EntryMinUndecoratedSmoothedPWDB;
+       }
+       RTPRINT(FBT, BT_TRACE, ("BTDM_GetRxBeaconSS() = %d\n", pwdbBeacon));
+       return pwdbBeacon;
+}
+
+/*  Get beacon rssi state */
+u8 BTDM_CheckCoexBcnRssiState(struct rtw_adapter *padapter, u8 levelNum,
+                             u8 RssiThresh, u8 RssiThresh1)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       s32 pwdbBeacon = 0;
+       u8 bcnRssiState = 0;
+
+       pwdbBeacon = BTDM_GetRxBeaconSS(padapter);
+
+       if (levelNum == 2) {
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM;
+
+               if ((pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_LOW) ||
+                   (pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_STAY_LOW)) {
+                       if (pwdbBeacon >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) {
+                               bcnRssiState = BT_RSSI_STATE_HIGH;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to High\n"));
+                       } else {
+                               bcnRssiState = BT_RSSI_STATE_STAY_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at Low\n"));
+                       }
+               } else {
+                       if (pwdbBeacon < RssiThresh) {
+                               bcnRssiState = BT_RSSI_STATE_LOW;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to Low\n"));
+                       } else {
+                               bcnRssiState = BT_RSSI_STATE_STAY_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at High\n"));
+                       }
+               }
+       } else if (levelNum == 3) {
+               if (RssiThresh > RssiThresh1) {
+                       RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON thresh error!!\n"));
+                       return pHalData->bt_coexist.preRssiStateBeacon;
+               }
+
+               if ((pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_LOW) ||
+                   (pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_STAY_LOW)) {
+                       if (pwdbBeacon >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) {
+                               bcnRssiState = BT_RSSI_STATE_MEDIUM;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to Medium\n"));
+                       } else {
+                               bcnRssiState = BT_RSSI_STATE_STAY_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at Low\n"));
+                       }
+               } else if ((pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_MEDIUM) ||
+                          (pHalData->bt_coexist.preRssiStateBeacon == BT_RSSI_STATE_STAY_MEDIUM)) {
+                       if (pwdbBeacon >= (RssiThresh1+BT_FW_COEX_THRESH_TOL)) {
+                               bcnRssiState = BT_RSSI_STATE_HIGH;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to High\n"));
+                       } else if (pwdbBeacon < RssiThresh) {
+                               bcnRssiState = BT_RSSI_STATE_LOW;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to Low\n"));
+                       } else {
+                               bcnRssiState = BT_RSSI_STATE_STAY_MEDIUM;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at Medium\n"));
+                       }
+               } else {
+                       if (pwdbBeacon < RssiThresh1) {
+                               bcnRssiState = BT_RSSI_STATE_MEDIUM;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_BEACON_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state switch to Medium\n"));
+                       } else {
+                               bcnRssiState = BT_RSSI_STATE_STAY_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_BEACON state stay at High\n"));
+                       }
+               }
+       }
+
+       pHalData->bt_coexist.preRssiStateBeacon = bcnRssiState;
+
+       return bcnRssiState;
+}
+
+u8 BTDM_CheckCoexRSSIState1(struct rtw_adapter *padapter, u8 levelNum,
+                           u8 RssiThresh, u8 RssiThresh1)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       s32 UndecoratedSmoothedPWDB = 0;
+       u8 btRssiState = 0;
+
+       UndecoratedSmoothedPWDB = BTDM_GetRxSS(padapter);
+
+       if (levelNum == 2) {
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+
+               if ((pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_LOW) ||
+                   (pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_STAY_LOW)) {
+                       if (UndecoratedSmoothedPWDB >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) {
+                               btRssiState = BT_RSSI_STATE_HIGH;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to High\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at Low\n"));
+                       }
+               } else {
+                       if (UndecoratedSmoothedPWDB < RssiThresh) {
+                               btRssiState = BT_RSSI_STATE_LOW;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to Low\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at High\n"));
+                       }
+               }
+       } else if (levelNum == 3) {
+               if (RssiThresh > RssiThresh1) {
+                       RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 thresh error!!\n"));
+                       return pHalData->bt_coexist.preRssiState1;
+               }
+
+               if ((pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_LOW) ||
+                   (pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_STAY_LOW)) {
+                       if (UndecoratedSmoothedPWDB >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) {
+                               btRssiState = BT_RSSI_STATE_MEDIUM;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to Medium\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at Low\n"));
+                       }
+               } else if ((pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_MEDIUM) ||
+                          (pHalData->bt_coexist.preRssiState1 == BT_RSSI_STATE_STAY_MEDIUM)) {
+                       if (UndecoratedSmoothedPWDB >= (RssiThresh1+BT_FW_COEX_THRESH_TOL)) {
+                               btRssiState = BT_RSSI_STATE_HIGH;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to High\n"));
+                       } else if (UndecoratedSmoothedPWDB < RssiThresh) {
+                               btRssiState = BT_RSSI_STATE_LOW;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to Low\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_MEDIUM;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at Medium\n"));
+                       }
+               } else {
+                       if (UndecoratedSmoothedPWDB < RssiThresh1) {
+                               btRssiState = BT_RSSI_STATE_MEDIUM;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state switch to Medium\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI_1 state stay at High\n"));
+                       }
+               }
+       }
+
+       pHalData->bt_coexist.preRssiState1 = btRssiState;
+
+       return btRssiState;
+}
+
+u8 BTDM_CheckCoexRSSIState(struct rtw_adapter *padapter, u8 levelNum,
+                          u8 RssiThresh, u8 RssiThresh1)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       s32 UndecoratedSmoothedPWDB = 0;
+       u8 btRssiState = 0;
+
+       UndecoratedSmoothedPWDB = BTDM_GetRxSS(padapter);
+
+       if (levelNum == 2) {
+               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+
+               if ((pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_LOW) ||
+                   (pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_STAY_LOW)) {
+                       if (UndecoratedSmoothedPWDB >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) {
+                               btRssiState = BT_RSSI_STATE_HIGH;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to High\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at Low\n"));
+                       }
+               } else {
+                       if (UndecoratedSmoothedPWDB < RssiThresh) {
+                               btRssiState = BT_RSSI_STATE_LOW;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to Low\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at High\n"));
+                       }
+               }
+       } else if (levelNum == 3) {
+               if (RssiThresh > RssiThresh1) {
+                       RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI thresh error!!\n"));
+                       return pHalData->bt_coexist.preRssiState;
+               }
+
+               if ((pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_LOW) ||
+                   (pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_STAY_LOW)) {
+                       if (UndecoratedSmoothedPWDB >= (RssiThresh+BT_FW_COEX_THRESH_TOL)) {
+                               btRssiState = BT_RSSI_STATE_MEDIUM;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to Medium\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at Low\n"));
+                       }
+               } else if ((pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_MEDIUM) ||
+                          (pHalData->bt_coexist.preRssiState == BT_RSSI_STATE_STAY_MEDIUM)) {
+                       if (UndecoratedSmoothedPWDB >= (RssiThresh1+BT_FW_COEX_THRESH_TOL)) {
+                               btRssiState = BT_RSSI_STATE_HIGH;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to High\n"));
+                       } else if (UndecoratedSmoothedPWDB < RssiThresh) {
+                               btRssiState = BT_RSSI_STATE_LOW;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_LOW;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to Low\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_MEDIUM;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at Medium\n"));
+                       }
+               } else {
+                       if (UndecoratedSmoothedPWDB < RssiThresh1) {
+                               btRssiState = BT_RSSI_STATE_MEDIUM;
+                               pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               pHalData->bt_coexist.CurrentState &= ~BT_COEX_STATE_WIFI_RSSI_LOW;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state switch to Medium\n"));
+                       } else {
+                               btRssiState = BT_RSSI_STATE_STAY_HIGH;
+                               RTPRINT(FBT, BT_TRACE, ("[DM][BT], RSSI state stay at High\n"));
+                       }
+               }
+       }
+
+       pHalData->bt_coexist.preRssiState = btRssiState;
+
+       return btRssiState;
+}
+
+u8 BTDM_DisableEDCATurbo(struct rtw_adapter *padapter)
+{
+       struct bt_mgnt *pBtMgnt;
+       struct hal_data_8723a *pHalData;
+       u8 bBtChangeEDCA = false;
+       u32 EDCA_BT_BE = 0x5ea42b, cur_EDCA_reg;
+       u8 bRet = false;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBtMgnt = &pHalData->BtInfo.BtMgnt;
+
+       if (!pHalData->bt_coexist.BluetoothCoexist) {
+               bRet = false;
+               pHalData->bt_coexist.lastBtEdca = 0;
+               return bRet;
+       }
+       if (!((pBtMgnt->bSupportProfile) ||
+           (pHalData->bt_coexist.BT_CoexistType == BT_CSR_BC8))) {
+               bRet = false;
+               pHalData->bt_coexist.lastBtEdca = 0;
+               return bRet;
+       }
+
+       if (BT_1Ant(padapter)) {
+               bRet = false;
+               pHalData->bt_coexist.lastBtEdca = 0;
+               return bRet;
+       }
+
+       if (pHalData->bt_coexist.exec_cnt < 3)
+               pHalData->bt_coexist.exec_cnt++;
+       else
+               pHalData->bt_coexist.bEDCAInitialized = true;
+
+       /*  When BT is non idle */
+       if (!(pHalData->bt_coexist.CurrentState & BT_COEX_STATE_BT_IDLE)) {
+               RTPRINT(FBT, BT_TRACE, ("BT state non idle, set bt EDCA\n"));
+
+               /* aggr_num = 0x0909; */
+               if (pHalData->odmpriv.DM_EDCA_Table.bCurrentTurboEDCA) {
+                       bBtChangeEDCA = true;
+                       pHalData->odmpriv.DM_EDCA_Table.bCurrentTurboEDCA = false;
+                       pHalData->dmpriv.prv_traffic_idx = 3;
+               }
+               cur_EDCA_reg = rtw_read32(padapter, REG_EDCA_BE_PARAM);
+
+               if (cur_EDCA_reg != EDCA_BT_BE)
+                       bBtChangeEDCA = true;
+               if (bBtChangeEDCA || !pHalData->bt_coexist.bEDCAInitialized) {
+                       rtw_write32(padapter, REG_EDCA_BE_PARAM, EDCA_BT_BE);
+                       pHalData->bt_coexist.lastBtEdca = EDCA_BT_BE;
+               }
+               bRet = true;
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("BT state idle, set original EDCA\n"));
+               pHalData->bt_coexist.lastBtEdca = 0;
+               bRet = false;
+       }
+       return bRet;
+}
+
+void
+BTDM_Balance(
+       struct rtw_adapter *padapter,
+       u8 bBalanceOn,
+       u8 ms0,
+       u8 ms1
+       )
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 H2C_Parameter[3] = {0};
+
+       if (bBalanceOn) {
+               H2C_Parameter[2] = 1;
+               H2C_Parameter[1] = ms1;
+               H2C_Parameter[0] = ms0;
+               pHalData->bt_coexist.bFWCoexistAllOff = false;
+       } else {
+               H2C_Parameter[2] = 0;
+               H2C_Parameter[1] = 0;
+               H2C_Parameter[0] = 0;
+       }
+       pHalData->bt_coexist.bBalanceOn = bBalanceOn;
+
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], Balance =[%s:%dms:%dms], write 0xc = 0x%x\n",
+               bBalanceOn?"ON":"OFF", ms0, ms1,
+               H2C_Parameter[0]<<16|H2C_Parameter[1]<<8|H2C_Parameter[2]));
+
+       FillH2CCmd(padapter, 0xc, 3, H2C_Parameter);
+}
+
+void BTDM_AGCTable(struct rtw_adapter *padapter, u8 type)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       if (type == BT_AGCTABLE_OFF) {
+               RTPRINT(FBT, BT_TRACE, ("[BT]AGCTable Off!\n"));
+               rtw_write32(padapter, 0xc78, 0x641c0001);
+               rtw_write32(padapter, 0xc78, 0x631d0001);
+               rtw_write32(padapter, 0xc78, 0x621e0001);
+               rtw_write32(padapter, 0xc78, 0x611f0001);
+               rtw_write32(padapter, 0xc78, 0x60200001);
+
+               PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x32000);
+               PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x71000);
+               PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0xb0000);
+               PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0xfc000);
+               PHY_SetRFReg(padapter, PathA, RF_RX_G1, bRFRegOffsetMask, 0x30355);
+
+               pHalData->bt_coexist.b8723aAgcTableOn = false;
+       } else if (type == BT_AGCTABLE_ON) {
+               RTPRINT(FBT, BT_TRACE, ("[BT]AGCTable On!\n"));
+               rtw_write32(padapter, 0xc78, 0x4e1c0001);
+               rtw_write32(padapter, 0xc78, 0x4d1d0001);
+               rtw_write32(padapter, 0xc78, 0x4c1e0001);
+               rtw_write32(padapter, 0xc78, 0x4b1f0001);
+               rtw_write32(padapter, 0xc78, 0x4a200001);
+
+               PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0xdc000);
+               PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x90000);
+               PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x51000);
+               PHY_SetRFReg(padapter, PathA, RF_RX_AGC_HP, bRFRegOffsetMask, 0x12000);
+               PHY_SetRFReg(padapter, PathA, RF_RX_G1, bRFRegOffsetMask, 0x00355);
+
+               pHalData->bt_coexist.b8723aAgcTableOn = true;
+
+               pHalData->bt_coexist.bSWCoexistAllOff = false;
+       }
+}
+
+void BTDM_BBBackOffLevel(struct rtw_adapter *padapter, u8 type)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (type == BT_BB_BACKOFF_OFF) {
+               RTPRINT(FBT, BT_TRACE, ("[BT]BBBackOffLevel Off!\n"));
+               rtw_write32(padapter, 0xc04, 0x3a05611);
+       } else if (type == BT_BB_BACKOFF_ON) {
+               RTPRINT(FBT, BT_TRACE, ("[BT]BBBackOffLevel On!\n"));
+               rtw_write32(padapter, 0xc04, 0x3a07611);
+               pHalData->bt_coexist.bSWCoexistAllOff = false;
+       }
+}
+
+void BTDM_FWCoexAllOff(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);;
+
+       RTPRINT(FBT, BT_TRACE, ("BTDM_FWCoexAllOff()\n"));
+       if (pHalData->bt_coexist.bFWCoexistAllOff)
+               return;
+       RTPRINT(FBT, BT_TRACE, ("BTDM_FWCoexAllOff(), real Do\n"));
+
+       BTDM_FWCoexAllOff8723A(padapter);
+
+       pHalData->bt_coexist.bFWCoexistAllOff = true;
+}
+
+void BTDM_SWCoexAllOff(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);;
+
+       RTPRINT(FBT, BT_TRACE, ("BTDM_SWCoexAllOff()\n"));
+       if (pHalData->bt_coexist.bSWCoexistAllOff)
+               return;
+       RTPRINT(FBT, BT_TRACE, ("BTDM_SWCoexAllOff(), real Do\n"));
+       BTDM_SWCoexAllOff8723A(padapter);
+
+       pHalData->bt_coexist.bSWCoexistAllOff = true;
+}
+
+void BTDM_HWCoexAllOff(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);;
+
+       RTPRINT(FBT, BT_TRACE, ("BTDM_HWCoexAllOff()\n"));
+       if (pHalData->bt_coexist.bHWCoexistAllOff)
+               return;
+       RTPRINT(FBT, BT_TRACE, ("BTDM_HWCoexAllOff(), real Do\n"));
+
+       BTDM_HWCoexAllOff8723A(padapter);
+
+       pHalData->bt_coexist.bHWCoexistAllOff = true;
+}
+
+void BTDM_CoexAllOff(struct rtw_adapter *padapter)
+{
+       BTDM_FWCoexAllOff(padapter);
+       BTDM_SWCoexAllOff(padapter);
+       BTDM_HWCoexAllOff(padapter);
+}
+
+void BTDM_TurnOffBtCoexistBeforeEnterIPS(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct pwrctrl_priv *ppwrctrl = &padapter->pwrctrlpriv;
+
+       if (!pHalData->bt_coexist.BluetoothCoexist)
+               return;
+
+       /*  8723 1Ant doesn't need to turn off bt coexist mechanism. */
+       if (BTDM_1Ant8723A(padapter))
+               return;
+
+       /*  Before enter IPS, turn off FW BT Co-exist mechanism */
+       if (ppwrctrl->reg_rfoff == rf_on) {
+               RTPRINT(FBT, BT_TRACE, ("[BT][DM], Before enter IPS, turn off all Coexist DM\n"));
+               btdm_ResetFWCoexState(padapter);
+               BTDM_CoexAllOff(padapter);
+               BTDM_SetAntenna(padapter, BTDM_ANT_BT);
+       }
+}
+
+void BTDM_SignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi, u8 *rssi_bt)
+{
+       BTDM_8723ASignalCompensation(padapter, rssi_wifi, rssi_bt);
+}
+
+void BTDM_Coexist(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (!pHalData->bt_coexist.BluetoothCoexist) {
+               RTPRINT(FBT, BT_TRACE, ("[DM][BT], BT not exists!!\n"));
+               return;
+       }
+
+       if (!pHalData->bt_coexist.bInitlized) {
+               RTPRINT(FBT, BT_TRACE, ("[DM][BT], btdm_InitBtCoexistDM()\n"));
+               btdm_InitBtCoexistDM(padapter);
+       }
+
+       RTPRINT(FBT, BT_TRACE, ("\n\n[DM][BT], BTDM start!!\n"));
+
+       BTDM_PWDBMonitor(padapter);
+
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], HW type is 8723\n"));
+       BTDM_BTCoexist8723A(padapter);
+       RTPRINT(FBT, BT_TRACE, ("[DM][BT], BTDM end!!\n\n"));
+}
+
+void BTDM_UpdateCoexState(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (!BTDM_IsSameCoexistState(padapter)) {
+               RTPRINT(FBT, BT_TRACE, ("[BTCoex], Coexist State[bitMap] change from 0x%"i64fmt"x to 0x%"i64fmt"x,  changeBits = 0x%"i64fmt"x\n",
+                       pHalData->bt_coexist.PreviousState,
+                       pHalData->bt_coexist.CurrentState,
+                       (pHalData->bt_coexist.PreviousState^pHalData->bt_coexist.CurrentState)));
+               pHalData->bt_coexist.PreviousState = pHalData->bt_coexist.CurrentState;
+       }
+}
+
+u8 BTDM_IsSameCoexistState(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (pHalData->bt_coexist.PreviousState == pHalData->bt_coexist.CurrentState) {
+               return true;
+       } else {
+               RTPRINT(FBT, BT_TRACE, ("[DM][BT], Coexist state changed!!\n"));
+               return false;
+       }
+}
+
+void BTDM_PWDBMonitor(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(GetDefaultAdapter(padapter));
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 H2C_Parameter[3] = {0};
+       s32 tmpBTEntryMaxPWDB = 0, tmpBTEntryMinPWDB = 0xff;
+       u8 i;
+
+       if (pBtMgnt->BtOperationOn) {
+               for (i = 0; i < MAX_BT_ASOC_ENTRY_NUM; i++) {
+                       if (pBTInfo->BtAsocEntry[i].bUsed) {
+                               if (pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB < tmpBTEntryMinPWDB)
+                                       tmpBTEntryMinPWDB = pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB;
+                               if (pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB > tmpBTEntryMaxPWDB)
+                                       tmpBTEntryMaxPWDB = pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB;
+                               /*  Report every BT connection (HS mode) RSSI to FW */
+                               H2C_Parameter[2] = (u8)(pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB & 0xFF);
+                               H2C_Parameter[0] = (MAX_FW_SUPPORT_MACID_NUM-1-i);
+                               RTPRINT(FDM, DM_BT30, ("RSSI report for BT[%d], H2C_Par = 0x%x\n", i, H2C_Parameter[0]));
+                               FillH2CCmd(padapter, RSSI_SETTING_EID, 3, H2C_Parameter);
+                               RTPRINT_ADDR(FDM, (DM_PWDB|DM_BT30), ("BT_Entry Mac :"),
+                                            pBTInfo->BtAsocEntry[i].BTRemoteMACAddr)
+                               RTPRINT(FDM, (DM_PWDB|DM_BT30),
+                                       ("BT rx pwdb[%d] = 0x%x(%d)\n", i,
+                                       pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB,
+                                       pBTInfo->BtAsocEntry[i].UndecoratedSmoothedPWDB));
+                       }
+               }
+               if (tmpBTEntryMaxPWDB != 0) {   /*  If associated entry is found */
+                       pHalData->dmpriv.BT_EntryMaxUndecoratedSmoothedPWDB = tmpBTEntryMaxPWDB;
+                       RTPRINT(FDM, (DM_PWDB|DM_BT30), ("BT_EntryMaxPWDB = 0x%x(%d)\n",
+                               tmpBTEntryMaxPWDB, tmpBTEntryMaxPWDB));
+               } else {
+                       pHalData->dmpriv.BT_EntryMaxUndecoratedSmoothedPWDB = 0;
+               }
+               if (tmpBTEntryMinPWDB != 0xff) { /*  If associated entry is found */
+                       pHalData->dmpriv.BT_EntryMinUndecoratedSmoothedPWDB = tmpBTEntryMinPWDB;
+                       RTPRINT(FDM, (DM_PWDB|DM_BT30), ("BT_EntryMinPWDB = 0x%x(%d)\n",
+                               tmpBTEntryMinPWDB, tmpBTEntryMinPWDB));
+               } else {
+                       pHalData->dmpriv.BT_EntryMinUndecoratedSmoothedPWDB = 0;
+               }
+       }
+}
+
+u8 BTDM_IsBTBusy(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_mgnt *pBtMgnt = &pBTInfo->BtMgnt;
+
+       if (pBtMgnt->ExtConfig.bBTBusy)
+               return true;
+       else
+               return false;
+}
+
+u8 BTDM_IsWifiBusy(struct rtw_adapter *padapter)
+{
+/*PMGNT_INFO           pMgntInfo = &GetDefaultAdapter(padapter)->MgntInfo; */
+       struct mlme_priv *pmlmepriv = &GetDefaultAdapter(padapter)->mlmepriv;
+       struct bt_30info *pBTInfo = GET_BT_INFO(padapter);
+       struct bt_traffic *pBtTraffic = &pBTInfo->BtTraffic;
+
+       if (pmlmepriv->LinkDetectInfo.bBusyTraffic ||
+               pBtTraffic->Bt30TrafficStatistics.bTxBusyTraffic ||
+               pBtTraffic->Bt30TrafficStatistics.bRxBusyTraffic)
+               return true;
+       else
+               return false;
+}
+
+u8 BTDM_IsCoexistStateChanged(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (pHalData->bt_coexist.PreviousState == pHalData->bt_coexist.CurrentState)
+               return false;
+       else
+               return true;
+}
+
+u8 BTDM_IsWifiUplink(struct rtw_adapter *padapter)
+{
+/*PMGNT_INFO           pMgntInfo = &GetDefaultAdapter(padapter)->MgntInfo; */
+       struct mlme_priv *pmlmepriv;
+       struct bt_30info *pBTInfo;
+       struct bt_traffic *pBtTraffic;
+
+       pmlmepriv = &padapter->mlmepriv;
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtTraffic = &pBTInfo->BtTraffic;
+
+       if ((pmlmepriv->LinkDetectInfo.bTxBusyTraffic) ||
+               (pBtTraffic->Bt30TrafficStatistics.bTxBusyTraffic))
+               return true;
+       else
+               return false;
+}
+
+u8 BTDM_IsWifiDownlink(struct rtw_adapter *padapter)
+{
+/*PMGNT_INFO           pMgntInfo = &GetDefaultAdapter(padapter)->MgntInfo; */
+       struct mlme_priv *pmlmepriv;
+       struct bt_30info *pBTInfo;
+       struct bt_traffic *pBtTraffic;
+
+       pmlmepriv = &padapter->mlmepriv;
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtTraffic = &pBTInfo->BtTraffic;
+
+       if ((pmlmepriv->LinkDetectInfo.bRxBusyTraffic) ||
+               (pBtTraffic->Bt30TrafficStatistics.bRxBusyTraffic))
+               return true;
+       else
+               return false;
+}
+
+u8 BTDM_IsBTHSMode(struct rtw_adapter *padapter)
+{
+/*PMGNT_INFO           pMgntInfo = &GetDefaultAdapter(padapter)->MgntInfo; */
+       struct hal_data_8723a *pHalData;
+       struct bt_mgnt *pBtMgnt;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBtMgnt = &pHalData->BtInfo.BtMgnt;
+
+       if (pBtMgnt->BtOperationOn)
+               return true;
+       else
+               return false;
+}
+
+u8 BTDM_IsBTUplink(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (pHalData->bt_coexist.BT21TrafficStatistics.bTxBusyTraffic)
+               return true;
+       else
+               return false;
+}
+
+u8 BTDM_IsBTDownlink(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (pHalData->bt_coexist.BT21TrafficStatistics.bRxBusyTraffic)
+               return true;
+       else
+               return false;
+}
+
+void BTDM_AdjustForBtOperation(struct rtw_adapter *padapter)
+{
+       RTPRINT(FBT, BT_TRACE, ("[BT][DM], BTDM_AdjustForBtOperation()\n"));
+       BTDM_AdjustForBtOperation8723A(padapter);
+}
+
+void BTDM_SetBtCoexCurrAntNum(struct rtw_adapter *padapter, u8 antNum)
+{
+       BTDM_Set8723ABtCoexCurrAntNum(padapter, antNum);
+}
+
+void BTDM_ForHalt(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (!pHalData->bt_coexist.BluetoothCoexist)
+               return;
+
+       BTDM_ForHalt8723A(padapter);
+       GET_HAL_DATA(padapter)->bt_coexist.bInitlized = false;
+}
+
+void BTDM_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (!pHalData->bt_coexist.BluetoothCoexist)
+               return;
+
+       BTDM_WifiScanNotify8723A(padapter, scanType);
+}
+
+void BTDM_WifiAssociateNotify(struct rtw_adapter *padapter, u8 action)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (!pHalData->bt_coexist.BluetoothCoexist)
+               return;
+
+       BTDM_WifiAssociateNotify8723A(padapter, action);
+}
+
+void BTDM_MediaStatusNotify(struct rtw_adapter *padapter, enum rt_media_status mstatus)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (!pHalData->bt_coexist.BluetoothCoexist)
+               return;
+
+       BTDM_MediaStatusNotify8723A(padapter, mstatus);
+}
+
+void BTDM_ForDhcp(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (!pHalData->bt_coexist.BluetoothCoexist)
+               return;
+
+       BTDM_ForDhcp8723A(padapter);
+}
+
+void BTDM_ResetActionProfileState(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       pHalData->bt_coexist.CurrentState &= ~\
+               (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_A2DP|
+               BT_COEX_STATE_PROFILE_PAN|BT_COEX_STATE_PROFILE_SCO);
+}
+
+u8 BTDM_IsActionSCO(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_dgb *pBtDbg;
+       u8 bRet;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtDbg = &pBTInfo->BtDbg;
+       bRet = false;
+
+       if (pBtDbg->dbgCtrl) {
+               if (pBtDbg->dbgProfile == BT_DBG_PROFILE_SCO) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_SCO;
+                       bRet = true;
+               }
+       } else {
+               if (pBtMgnt->ExtConfig.NumberOfSCO > 0) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_SCO;
+                       bRet = true;
+               }
+       }
+       return bRet;
+}
+
+u8 BTDM_IsActionHID(struct rtw_adapter *padapter)
+{
+       struct bt_30info *pBTInfo;
+       struct hal_data_8723a *pHalData;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_dgb *pBtDbg;
+       u8 bRet;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtDbg = &pBTInfo->BtDbg;
+       bRet = false;
+
+       if (pBtDbg->dbgCtrl) {
+               if (pBtDbg->dbgProfile == BT_DBG_PROFILE_HID) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_HID;
+                       bRet = true;
+               }
+       } else {
+               if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) &&
+                   pBtMgnt->ExtConfig.NumberOfHandle == 1) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_HID;
+                       bRet = true;
+               }
+       }
+       return bRet;
+}
+
+u8 BTDM_IsActionA2DP(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_dgb *pBtDbg;
+       u8 bRet;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtDbg = &pBTInfo->BtDbg;
+       bRet = false;
+
+       if (pBtDbg->dbgCtrl) {
+               if (pBtDbg->dbgProfile == BT_DBG_PROFILE_A2DP) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_A2DP;
+                       bRet = true;
+               }
+       } else {
+               if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP) &&
+                   pBtMgnt->ExtConfig.NumberOfHandle == 1) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_A2DP;
+                       bRet = true;
+               }
+       }
+       return bRet;
+}
+
+u8 BTDM_IsActionPAN(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_dgb *pBtDbg;
+       u8 bRet;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtDbg = &pBTInfo->BtDbg;
+       bRet = false;
+
+       if (pBtDbg->dbgCtrl) {
+               if (pBtDbg->dbgProfile == BT_DBG_PROFILE_PAN) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_PAN;
+                       bRet = true;
+               }
+       } else {
+               if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) &&
+                   pBtMgnt->ExtConfig.NumberOfHandle == 1) {
+                       pHalData->bt_coexist.CurrentState |= BT_COEX_STATE_PROFILE_PAN;
+                       bRet = true;
+               }
+       }
+       return bRet;
+}
+
+u8 BTDM_IsActionHIDA2DP(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_30info *pBTInfo;
+       struct bt_mgnt *pBtMgnt;
+       struct bt_dgb *pBtDbg;
+       u8 bRet;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtMgnt = &pBTInfo->BtMgnt;
+       pBtDbg = &pBTInfo->BtDbg;
+       bRet = false;
+
+       if (pBtDbg->dbgCtrl) {
+               if (pBtDbg->dbgProfile == BT_DBG_PROFILE_HID_A2DP) {
+                       pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_A2DP);
+                       bRet = true;
+               }
+       } else {
+               if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) &&
+                   BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                       pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_A2DP);
+                       bRet = true;
+               }
+       }
+       return bRet;
+}
+
+u8 BTDM_IsActionHIDPAN(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_30info *pBTInfo;
+       struct bt_dgb *pBtDbg;
+       u8 bRet;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtDbg = &pBTInfo->BtDbg;
+       bRet = false;
+
+       if (pBtDbg->dbgCtrl) {
+               if (pBtDbg->dbgProfile == BT_DBG_PROFILE_HID_PAN) {
+                       pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_PAN);
+                       bRet = true;
+               }
+       } else {
+               if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_HID) &&
+                   BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN)) {
+                       pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_HID|BT_COEX_STATE_PROFILE_PAN);
+                       bRet = true;
+               }
+       }
+       return bRet;
+}
+
+u8 BTDM_IsActionPANA2DP(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct bt_30info *pBTInfo;
+       struct bt_dgb *pBtDbg;
+       u8 bRet;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pBTInfo = GET_BT_INFO(padapter);
+       pBtDbg = &pBTInfo->BtDbg;
+       bRet = false;
+
+       if (pBtDbg->dbgCtrl) {
+               if (pBtDbg->dbgProfile == BT_DBG_PROFILE_PAN_A2DP) {
+                       pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_PAN|BT_COEX_STATE_PROFILE_A2DP);
+                       bRet = true;
+               }
+       } else {
+               if (BTHCI_CheckProfileExist(padapter, BT_PROFILE_PAN) && BTHCI_CheckProfileExist(padapter, BT_PROFILE_A2DP)) {
+                       pHalData->bt_coexist.CurrentState |= (BT_COEX_STATE_PROFILE_PAN|BT_COEX_STATE_PROFILE_A2DP);
+                       bRet = true;
+               }
+       }
+       return bRet;
+}
+
+u8 BTDM_IsBtDisabled(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (pHalData->bt_coexist.bCurBtDisabled)
+               return true;
+       else
+               return false;
+}
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtCoexist.c ===== */
+#endif
+
+#ifdef __HALBT_C__ /*  HAL/HalBT.c */
+/*  ===== Below this line is sync from SD7 driver HAL/HalBT.c ===== */
+
+/*  */
+/*local function */
+/*  */
+
+static void halbt_InitHwConfig8723A(struct rtw_adapter *padapter)
+{
+}
+
+/*  */
+/*extern function */
+/*  */
+u8 HALBT_GetPGAntNum(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       return pHalData->bt_coexist.BT_Ant_Num;
+}
+
+void HALBT_SetKey(struct rtw_adapter *padapter, u8 EntryNum)
+{
+       struct bt_30info *pBTinfo;
+       struct bt_asoc_entry *pBtAssocEntry;
+       u16                             usConfig = 0;
+
+       pBTinfo = GET_BT_INFO(padapter);
+       pBtAssocEntry = &pBTinfo->BtAsocEntry[EntryNum];
+
+       pBtAssocEntry->HwCAMIndex = BT_HWCAM_STAR + EntryNum;
+
+       usConfig = CAM_VALID | (CAM_AES << 2);
+       write_cam23a(padapter, pBtAssocEntry->HwCAMIndex, usConfig, pBtAssocEntry->BTRemoteMACAddr, pBtAssocEntry->PTK + TKIP_ENC_KEY_POS);
+}
+
+void HALBT_RemoveKey(struct rtw_adapter *padapter, u8 EntryNum)
+{
+       struct bt_30info *pBTinfo;
+       struct bt_asoc_entry *pBtAssocEntry;
+
+       pBTinfo = GET_BT_INFO(padapter);
+       pBtAssocEntry = &pBTinfo->BtAsocEntry[EntryNum];
+
+       if (pBTinfo->BtAsocEntry[EntryNum].HwCAMIndex != 0) {
+               /*  ToDo : add New HALBT_RemoveKey function !! */
+               if (pBtAssocEntry->HwCAMIndex >= BT_HWCAM_STAR && pBtAssocEntry->HwCAMIndex < HALF_CAM_ENTRY)
+                       CAM_empty_entry23a(padapter, pBtAssocEntry->HwCAMIndex);
+               pBTinfo->BtAsocEntry[EntryNum].HwCAMIndex = 0;
+       }
+}
+
+void HALBT_InitBTVars8723A(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+
+       pHalData = GET_HAL_DATA(padapter);
+
+       pHalData->bt_coexist.BluetoothCoexist = pHalData->EEPROMBluetoothCoexist;
+       pHalData->bt_coexist.BT_Ant_Num = pHalData->EEPROMBluetoothAntNum;
+       pHalData->bt_coexist.BT_CoexistType = pHalData->EEPROMBluetoothType;
+       pHalData->bt_coexist.BT_Ant_isolation = pHalData->EEPROMBluetoothAntIsolation;
+       pHalData->bt_coexist.bt_radiosharedtype = pHalData->EEPROMBluetoothRadioShared;
+
+       RT_TRACE(_module_hal_init_c_, _drv_info_, ("BT Coexistance = 0x%x\n", pHalData->bt_coexist.BluetoothCoexist));
+       if (pHalData->bt_coexist.BluetoothCoexist) {
+               if (pHalData->bt_coexist.BT_Ant_Num == Ant_x2) {
+                       BTDM_SetBtCoexCurrAntNum(padapter, 2);
+                       RT_TRACE(_module_hal_init_c_, _drv_info_, ("BlueTooth BT_Ant_Num = Antx2\n"));
+               } else if (pHalData->bt_coexist.BT_Ant_Num == Ant_x1) {
+                       BTDM_SetBtCoexCurrAntNum(padapter, 1);
+                       RT_TRACE(_module_hal_init_c_, _drv_info_, ("BlueTooth BT_Ant_Num = Antx1\n"));
+               }
+               pHalData->bt_coexist.bBTBusyTraffic = false;
+               pHalData->bt_coexist.bBTTrafficModeSet = false;
+               pHalData->bt_coexist.bBTNonTrafficModeSet = false;
+               pHalData->bt_coexist.CurrentState = 0;
+               pHalData->bt_coexist.PreviousState = 0;
+
+               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                        ("bt_radiosharedType = 0x%x\n",
+                        pHalData->bt_coexist.bt_radiosharedtype));
+       }
+}
+
+u8 HALBT_IsBTExist(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (pHalData->bt_coexist.BluetoothCoexist)
+               return true;
+       else
+               return false;
+}
+
+u8 HALBT_BTChipType(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       return pHalData->bt_coexist.BT_CoexistType;
+}
+
+void HALBT_InitHwConfig(struct rtw_adapter *padapter)
+{
+       halbt_InitHwConfig8723A(padapter);
+       BTDM_Coexist(padapter);
+}
+
+void HALBT_SetRtsCtsNoLenLimit(struct rtw_adapter *padapter)
+{
+}
+
+/*  ===== End of sync from SD7 driver HAL/HalBT.c ===== */
+#endif
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_cmd.c b/drivers/staging/rtl8723au/hal/rtl8723a_cmd.c
new file mode 100644 (file)
index 0000000..0b205e1
--- /dev/null
@@ -0,0 +1,845 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTL8723A_CMD_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <cmd_osdep.h>
+#include <mlme_osdep.h>
+#include <rtw_ioctl_set.h>
+#include <rtl8723a_hal.h>
+
+#define RTL92C_MAX_H2C_BOX_NUMS                4
+#define RTL92C_MAX_CMD_LEN             5
+#define MESSAGE_BOX_SIZE               4
+#define EX_MESSAGE_BOX_SIZE            2
+
+static u8 _is_fw_read_cmd_down(struct rtw_adapter *padapter, u8 msgbox_num)
+{
+       u8 read_down = false;
+       int     retry_cnts = 100;
+       u8 valid;
+
+       do {
+               valid = rtw_read8(padapter, REG_HMETFR) & BIT(msgbox_num);
+               if (0 == valid)
+                       read_down = true;
+       } while ((!read_down) && (retry_cnts--));
+
+       return read_down;
+}
+
+/*****************************************
+* H2C Msg format :
+*| 31 - 8              |7              | 6 - 0 |
+*| h2c_msg     |Ext_bit        |CMD_ID |
+*
+******************************************/
+s32 FillH2CCmd(struct rtw_adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer)
+{
+       u8 bcmd_down = false;
+       s32 retry_cnts = 100;
+       u8 h2c_box_num;
+       u32 msgbox_addr;
+       u32 msgbox_ex_addr;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u32 h2c_cmd = 0;
+       u16 h2c_cmd_ex = 0;
+       s32 ret = _FAIL;
+
+       padapter = GET_PRIMARY_ADAPTER(padapter);
+       pHalData = GET_HAL_DATA(padapter);
+
+       mutex_lock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex);
+
+       if (!pCmdBuffer)
+               goto exit;
+       if (CmdLen > RTL92C_MAX_CMD_LEN)
+               goto exit;
+       if (padapter->bSurpriseRemoved == true)
+               goto exit;
+
+       /* pay attention to if  race condition happened in  H2C cmd setting. */
+       do {
+               h2c_box_num = pHalData->LastHMEBoxNum;
+
+               if (!_is_fw_read_cmd_down(padapter, h2c_box_num)) {
+                       DBG_8723A(" fw read cmd failed...\n");
+                       goto exit;
+               }
+
+               if (CmdLen <= 3) {
+                       memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer, CmdLen);
+               } else {
+                       memcpy((u8 *)(&h2c_cmd_ex), pCmdBuffer, EX_MESSAGE_BOX_SIZE);
+                       memcpy((u8 *)(&h2c_cmd)+1, pCmdBuffer+2, (CmdLen-EX_MESSAGE_BOX_SIZE));
+                       *(u8 *)(&h2c_cmd) |= BIT(7);
+               }
+
+               *(u8 *)(&h2c_cmd) |= ElementID;
+
+               if (h2c_cmd & BIT(7)) {
+                       msgbox_ex_addr = REG_HMEBOX_EXT_0 + (h2c_box_num * EX_MESSAGE_BOX_SIZE);
+                       h2c_cmd_ex = le16_to_cpu(h2c_cmd_ex);
+                       rtw_write16(padapter, msgbox_ex_addr, h2c_cmd_ex);
+               }
+               msgbox_addr = REG_HMEBOX_0 + (h2c_box_num * MESSAGE_BOX_SIZE);
+               h2c_cmd = le32_to_cpu(h2c_cmd);
+               rtw_write32(padapter, msgbox_addr, h2c_cmd);
+
+               bcmd_down = true;
+
+               pHalData->LastHMEBoxNum = (h2c_box_num+1) % RTL92C_MAX_H2C_BOX_NUMS;
+
+       } while ((!bcmd_down) && (retry_cnts--));
+
+       ret = _SUCCESS;
+
+exit:
+       mutex_unlock(&adapter_to_dvobj(padapter)->h2c_fwcmd_mutex);
+       return ret;
+}
+
+u8 rtl8723a_set_rssi_cmd(struct rtw_adapter *padapter, u8 *param)
+{
+       u8 res = _SUCCESS;
+
+       *((u32 *)param) = cpu_to_le32(*((u32 *)param));
+
+       FillH2CCmd(padapter, RSSI_SETTING_EID, 3, param);
+
+       return res;
+}
+
+u8 rtl8723a_set_raid_cmd(struct rtw_adapter *padapter, u32 mask, u8 arg)
+{
+       u8 buf[5];
+       u8 res = _SUCCESS;
+
+       memset(buf, 0, 5);
+       mask = cpu_to_le32(mask);
+       memcpy(buf, &mask, 4);
+       buf[4]  = arg;
+
+       FillH2CCmd(padapter, MACID_CONFIG_EID, 5, buf);
+
+       return res;
+
+}
+
+/* bitmap[0:27] = tx_rate_bitmap */
+/* bitmap[28:31]= Rate Adaptive id */
+/* arg[0:4] = macid */
+/* arg[5] = Short GI */
+void rtl8723a_add_rateatid(struct rtw_adapter *pAdapter, u32 bitmap, u8 arg, u8 rssi_level)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(pAdapter);
+       u8 macid = arg&0x1f;
+       u8 raid = (bitmap>>28) & 0x0f;
+
+       bitmap &= 0x0fffffff;
+       if (rssi_level != DM_RATR_STA_INIT)
+               bitmap = ODM_Get_Rate_Bitmap23a(&pHalData->odmpriv, macid, bitmap, rssi_level);
+
+       bitmap |= ((raid<<28)&0xf0000000);
+
+       if (pHalData->fw_ractrl == true) {
+               rtl8723a_set_raid_cmd(pAdapter, bitmap, arg);
+       } else {
+               u8 init_rate, shortGIrate = false;
+
+               init_rate = get_highest_rate_idx23a(bitmap&0x0fffffff)&0x3f;
+
+               shortGIrate = (arg&BIT(5)) ? true:false;
+
+               if (shortGIrate == true)
+                       init_rate |= BIT(6);
+
+               rtw_write8(pAdapter, (REG_INIDATA_RATE_SEL+macid), (u8)init_rate);
+       }
+}
+
+void rtl8723a_set_FwPwrMode_cmd(struct rtw_adapter *padapter, u8 Mode)
+{
+       struct setpwrmode_parm H2CSetPwrMode;
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       DBG_8723A("%s: Mode =%d SmartPS =%d UAPSD =%d BcnMode = 0x%02x\n", __FUNCTION__,
+                       Mode, pwrpriv->smart_ps, padapter->registrypriv.uapsd_enable, pwrpriv->bcn_ant_mode);
+
+       /*  Forece leave RF low power mode for 1T1R to
+           prevent conficting setting in Fw power */
+       /*  saving sequence. 2010.06.07. Added by tynli.
+           Suggested by SD3 yschang. */
+       if ((Mode != PS_MODE_ACTIVE) &&
+           (!IS_92C_SERIAL(pHalData->VersionID))) {
+               ODM_RF_Saving23a(&pHalData->odmpriv, true);
+       }
+
+       H2CSetPwrMode.Mode = Mode;
+       H2CSetPwrMode.SmartPS = pwrpriv->smart_ps;
+       H2CSetPwrMode.AwakeInterval = 1;
+       H2CSetPwrMode.bAllQueueUAPSD = padapter->registrypriv.uapsd_enable;
+       H2CSetPwrMode.BcnAntMode = pwrpriv->bcn_ant_mode;
+
+       FillH2CCmd(padapter, SET_PWRMODE_EID, sizeof(H2CSetPwrMode), (u8 *)&H2CSetPwrMode);
+
+}
+
+static void ConstructBeacon(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength)
+{
+       struct ieee80211_hdr *pwlanhdr;
+       u16 *fctrl;
+       u32 rate_len, pktlen;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+       u8 bc_addr[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+
+       /* DBG_8723A("%s\n", __FUNCTION__); */
+
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *(fctrl) = 0;
+
+       memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+       memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
+       memcpy(pwlanhdr->addr3, get_my_bssid23a(cur_network), ETH_ALEN);
+
+       SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
+       /* pmlmeext->mgnt_seq++; */
+       SetFrameSubType(pframe, WIFI_BEACON);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pktlen = sizeof (struct ieee80211_hdr_3addr);
+
+       /* timestamp will be inserted by hardware */
+       pframe += 8;
+       pktlen += 8;
+
+       /*  beacon interval: 2 bytes */
+       memcpy(pframe, (unsigned char *)(rtw_get_beacon_interval23a_from_ie(cur_network->IEs)), 2);
+
+       pframe += 2;
+       pktlen += 2;
+
+       /*  capability info: 2 bytes */
+       memcpy(pframe, (unsigned char *)(rtw_get_capability23a_from_ie(cur_network->IEs)), 2);
+
+       pframe += 2;
+       pktlen += 2;
+
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_AP_STATE) {
+               /* DBG_8723A("ie len =%d\n", cur_network->IELength); */
+               pktlen += cur_network->IELength - sizeof(struct ndis_802_11_fixed_ies);
+               memcpy(pframe, cur_network->IEs+sizeof(struct ndis_802_11_fixed_ies), pktlen);
+
+               goto _ConstructBeacon;
+       }
+
+       /* below for ad-hoc mode */
+
+       /*  SSID */
+       pframe = rtw_set_ie23a(pframe, _SSID_IE_, cur_network->Ssid.ssid_len,
+                           cur_network->Ssid.ssid, &pktlen);
+
+       /*  supported rates... */
+       rate_len = rtw_get_rateset_len23a(cur_network->SupportedRates);
+       pframe = rtw_set_ie23a(pframe, _SUPPORTEDRATES_IE_, ((rate_len > 8) ?
+                              8 : rate_len), cur_network->SupportedRates, &pktlen);
+
+       /*  DS parameter set */
+       pframe = rtw_set_ie23a(pframe, _DSSET_IE_, 1, (unsigned char *)&cur_network->Configuration.DSConfig, &pktlen);
+
+       if ((pmlmeinfo->state&0x03) == WIFI_FW_ADHOC_STATE) {
+               u32 ATIMWindow;
+               /*  IBSS Parameter Set... */
+               /* ATIMWindow = cur->Configuration.ATIMWindow; */
+               ATIMWindow = 0;
+               pframe = rtw_set_ie23a(pframe, _IBSS_PARA_IE_, 2, (unsigned char *)(&ATIMWindow), &pktlen);
+       }
+
+       /* todo: ERP IE */
+
+       /*  EXTERNDED SUPPORTED RATE */
+       if (rate_len > 8)
+               pframe = rtw_set_ie23a(pframe, _EXT_SUPPORTEDRATES_IE_, (rate_len - 8), (cur_network->SupportedRates + 8), &pktlen);
+
+       /* todo:HT for adhoc */
+
+_ConstructBeacon:
+
+       if ((pktlen + TXDESC_SIZE) > 512) {
+               DBG_8723A("beacon frame too large\n");
+               return;
+       }
+
+       *pLength = pktlen;
+
+       /* DBG_8723A("%s bcn_sz =%d\n", __FUNCTION__, pktlen); */
+
+}
+
+static void ConstructPSPoll(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength)
+{
+       struct ieee80211_hdr *pwlanhdr;
+       u16 *fctrl;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       /*  Frame control. */
+       fctrl = &pwlanhdr->frame_control;
+       *(fctrl) = 0;
+       SetPwrMgt(fctrl);
+       SetFrameSubType(pframe, WIFI_PSPOLL);
+
+       /*  AID. */
+       SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
+
+       /*  BSSID. */
+       memcpy(pwlanhdr->addr1, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
+
+       /*  TA. */
+       memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
+
+       *pLength = 16;
+}
+
+static void ConstructNullFunctionData(
+       struct rtw_adapter *padapter,
+       u8 *pframe,
+       u32 *pLength,
+       u8 *StaAddr,
+       u8 bQoS,
+       u8 AC,
+       u8 bEosp,
+       u8 bForcePowerSave)
+{
+       struct ieee80211_hdr *pwlanhdr;
+       u16 *fctrl;
+       u32 pktlen;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_network             *cur_network = &pmlmepriv->cur_network;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       fctrl = &pwlanhdr->frame_control;
+       *(fctrl) = 0;
+       if (bForcePowerSave)
+               SetPwrMgt(fctrl);
+
+       switch (cur_network->network.InfrastructureMode) {
+       case Ndis802_11Infrastructure:
+               SetToDs(fctrl);
+               memcpy(pwlanhdr->addr1,
+                      get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
+               memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv),
+                      ETH_ALEN);
+               memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
+               break;
+       case Ndis802_11APMode:
+               SetFrDs(fctrl);
+               memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
+               memcpy(pwlanhdr->addr2,
+                      get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
+               memcpy(pwlanhdr->addr3, myid(&padapter->eeprompriv),
+                      ETH_ALEN);
+               break;
+       case Ndis802_11IBSS:
+       default:
+               memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
+               memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
+               memcpy(pwlanhdr->addr3,
+                      get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
+               break;
+       }
+
+       SetSeqNum(pwlanhdr, 0);
+
+       if (bQoS == true) {
+               struct ieee80211_qos_hdr *pwlanqoshdr;
+
+               SetFrameSubType(pframe, WIFI_QOS_DATA_NULL);
+
+               pwlanqoshdr = (struct ieee80211_qos_hdr *)pframe;
+               SetPriority(&pwlanqoshdr->qos_ctrl, AC);
+               SetEOSP(&pwlanqoshdr->qos_ctrl, bEosp);
+
+               pktlen = sizeof(struct ieee80211_qos_hdr);
+       } else {
+               SetFrameSubType(pframe, WIFI_DATA_NULL);
+
+               pktlen = sizeof(struct ieee80211_hdr_3addr);
+       }
+
+       *pLength = pktlen;
+}
+
+static void ConstructProbeRsp(struct rtw_adapter *padapter, u8 *pframe, u32 *pLength, u8 *StaAddr, bool bHideSSID)
+{
+       struct ieee80211_hdr *pwlanhdr;
+       u16 *fctrl;
+       u8 *mac, *bssid;
+       u32 pktlen;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+
+       /* DBG_8723A("%s\n", __FUNCTION__); */
+
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       mac = myid(&padapter->eeprompriv);
+       bssid = cur_network->MacAddress;
+
+       fctrl = &pwlanhdr->frame_control;
+       *(fctrl) = 0;
+       memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
+       memcpy(pwlanhdr->addr2, mac, ETH_ALEN);
+       memcpy(pwlanhdr->addr3, bssid, ETH_ALEN);
+
+       SetSeqNum(pwlanhdr, 0);
+       SetFrameSubType(fctrl, WIFI_PROBERSP);
+
+       pktlen = sizeof(struct ieee80211_hdr_3addr);
+       pframe += pktlen;
+
+       if (cur_network->IELength > MAX_IE_SZ)
+               return;
+
+       memcpy(pframe, cur_network->IEs, cur_network->IELength);
+       pframe += cur_network->IELength;
+       pktlen += cur_network->IELength;
+
+       *pLength = pktlen;
+}
+
+/*  To check if reserved page content is destroyed by beacon beacuse beacon is too large. */
+void CheckFwRsvdPageContent23a(struct rtw_adapter *Adapter)
+{
+}
+
+/*  */
+/*  Description: Fill the reserved packets that FW will use to RSVD page. */
+/*                     Now we just send 4 types packet to rsvd page. */
+/*                     (1)Beacon, (2)Ps-poll, (3)Null data, (4)ProbeRsp. */
+/*     Input: */
+/*         bDLFinished - false: At the first time we will send all the packets as a large packet to Hw, */
+/*                                             so we need to set the packet length to total lengh. */
+/*                           true: At the second time, we should send the first packet (default:beacon) */
+/*                                             to Hw again and set the lengh in descriptor to the real beacon lengh. */
+/*  2009.10.15 by tynli. */
+static void SetFwRsvdPagePkt(struct rtw_adapter *padapter, bool bDLFinished)
+{
+       struct hal_data_8723a *pHalData;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       struct xmit_priv *pxmitpriv;
+       struct mlme_ext_priv *pmlmeext;
+       struct mlme_ext_info *pmlmeinfo;
+       u32 BeaconLength = 0, ProbeRspLength = 0, PSPollLength;
+       u32 NullDataLength, QosNullLength, BTQosNullLength;
+       u8 *ReservedPagePacket;
+       u8 PageNum, PageNeed, TxDescLen;
+       u16 BufIndex;
+       u32 TotalPacketLen;
+       struct rsvdpage_loc     RsvdPageLoc;
+
+       DBG_8723A("%s\n", __FUNCTION__);
+
+       ReservedPagePacket = kzalloc(1000, GFP_KERNEL);
+       if (ReservedPagePacket == NULL) {
+               DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__);
+               return;
+       }
+
+       pHalData = GET_HAL_DATA(padapter);
+       pxmitpriv = &padapter->xmitpriv;
+       pmlmeext = &padapter->mlmeextpriv;
+       pmlmeinfo = &pmlmeext->mlmext_info;
+
+       TxDescLen = TXDESC_SIZE;
+       PageNum = 0;
+
+       /* 3 (1) beacon */
+       BufIndex = TXDESC_OFFSET;
+       ConstructBeacon(padapter, &ReservedPagePacket[BufIndex], &BeaconLength);
+
+       /*  When we count the first page size, we need to reserve description size for the RSVD */
+       /*  packet, it will be filled in front of the packet in TXPKTBUF. */
+       PageNeed = (u8)PageNum_128(TxDescLen + BeaconLength);
+       /*  To reserved 2 pages for beacon buffer. 2010.06.24. */
+       if (PageNeed == 1)
+               PageNeed += 1;
+       PageNum += PageNeed;
+       pHalData->FwRsvdPageStartOffset = PageNum;
+
+       BufIndex += PageNeed*128;
+
+       /* 3 (2) ps-poll */
+       RsvdPageLoc.LocPsPoll = PageNum;
+       ConstructPSPoll(padapter, &ReservedPagePacket[BufIndex], &PSPollLength);
+       rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], PSPollLength, true, false);
+
+       PageNeed = (u8)PageNum_128(TxDescLen + PSPollLength);
+       PageNum += PageNeed;
+
+       BufIndex += PageNeed*128;
+
+       /* 3 (3) null data */
+       RsvdPageLoc.LocNullData = PageNum;
+       ConstructNullFunctionData(
+               padapter,
+               &ReservedPagePacket[BufIndex],
+               &NullDataLength,
+               get_my_bssid23a(&pmlmeinfo->network),
+               false, 0, 0, false);
+       rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
+
+       PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
+       PageNum += PageNeed;
+
+       BufIndex += PageNeed*128;
+
+       /* 3 (4) probe response */
+       RsvdPageLoc.LocProbeRsp = PageNum;
+       ConstructProbeRsp(
+               padapter,
+               &ReservedPagePacket[BufIndex],
+               &ProbeRspLength,
+               get_my_bssid23a(&pmlmeinfo->network),
+               false);
+       rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
+
+       PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
+       PageNum += PageNeed;
+
+       BufIndex += PageNeed*128;
+
+       /* 3 (5) Qos null data */
+       RsvdPageLoc.LocQosNull = PageNum;
+       ConstructNullFunctionData(
+               padapter,
+               &ReservedPagePacket[BufIndex],
+               &QosNullLength,
+               get_my_bssid23a(&pmlmeinfo->network),
+               true, 0, 0, false);
+       rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
+
+       PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
+       PageNum += PageNeed;
+
+       BufIndex += PageNeed*128;
+
+       /* 3 (6) BT Qos null data */
+       RsvdPageLoc.LocBTQosNull = PageNum;
+       ConstructNullFunctionData(
+               padapter,
+               &ReservedPagePacket[BufIndex],
+               &BTQosNullLength,
+               get_my_bssid23a(&pmlmeinfo->network),
+               true, 0, 0, false);
+       rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true);
+
+       TotalPacketLen = BufIndex + BTQosNullLength;
+
+       pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
+       if (pmgntframe == NULL)
+               goto exit;
+
+       /*  update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+       pattrib->qsel = 0x10;
+       pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
+       memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
+
+       rtw_hal_mgnt_xmit23a(padapter, pmgntframe);
+
+       DBG_8723A("%s: Set RSVD page location to Fw\n", __FUNCTION__);
+       FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
+
+exit:
+       kfree(ReservedPagePacket);
+}
+
+void rtl8723a_set_FwJoinBssReport_cmd(struct rtw_adapter *padapter, u8 mstatus)
+{
+       struct joinbssrpt_parm  JoinBssRptParm;
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       DBG_8723A("%s mstatus(%x)\n", __FUNCTION__, mstatus);
+
+       if (mstatus == 1) {
+               bool bRecover = false;
+               u8 v8;
+
+               /*  We should set AID, correct TSF, HW seq enable before set JoinBssReport to Fw in 88/92C. */
+               /*  Suggested by filen. Added by tynli. */
+               rtw_write16(padapter, REG_BCN_PSR_RPT, (0xC000|pmlmeinfo->aid));
+               /*  Do not set TSF again here or vWiFi beacon DMA INT will not work. */
+               /* correct_TSF23a(padapter, pmlmeext); */
+               /*  Hw sequende enable by dedault. 2010.06.23. by tynli. */
+               /* rtw_write16(padapter, REG_NQOS_SEQ, ((pmlmeext->mgnt_seq+100)&0xFFF)); */
+               /* rtw_write8(padapter, REG_HWSEQ_CTRL, 0xFF); */
+
+               /*  set REG_CR bit 8 */
+               v8 = rtw_read8(padapter, REG_CR+1);
+               v8 |= BIT(0); /*  ENSWBCN */
+               rtw_write8(padapter,  REG_CR+1, v8);
+
+               /*  Disable Hw protection for a time which revserd for Hw sending beacon. */
+               /*  Fix download reserved page packet fail that access collision with the protection time. */
+               /*  2010.05.11. Added by tynli. */
+/*                     SetBcnCtrlReg23a(padapter, 0, BIT(3)); */
+/*                     SetBcnCtrlReg23a(padapter, BIT(4), 0); */
+               SetBcnCtrlReg23a(padapter, BIT(4), BIT(3));
+
+               /*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
+               if (pHalData->RegFwHwTxQCtrl & BIT(6))
+                       bRecover = true;
+
+               /*  To tell Hw the packet is not a real beacon frame. */
+               /* U1bTmp = rtw_read8(padapter, REG_FWHW_TXQ_CTRL+2); */
+               rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl & ~BIT(6));
+               pHalData->RegFwHwTxQCtrl &= ~BIT(6);
+               SetFwRsvdPagePkt(padapter, 0);
+
+               /*  2010.05.11. Added by tynli. */
+               SetBcnCtrlReg23a(padapter, BIT(3), BIT(4));
+
+               /*  To make sure that if there exists an adapter which would like to send beacon. */
+               /*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
+               /*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
+               /*  the beacon cannot be sent by HW. */
+               /*  2010.06.23. Added by tynli. */
+               if (bRecover) {
+                       rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl | BIT(6));
+                       pHalData->RegFwHwTxQCtrl |= BIT(6);
+               }
+
+               /*  Clear CR[8] or beacon packet will not be send to TxBuf anymore. */
+               v8 = rtw_read8(padapter, REG_CR+1);
+               v8 &= ~BIT(0); /*  ~ENSWBCN */
+               rtw_write8(padapter, REG_CR+1, v8);
+       }
+
+       JoinBssRptParm.OpMode = mstatus;
+
+       FillH2CCmd(padapter, JOINBSS_RPT_EID, sizeof(JoinBssRptParm), (u8 *)&JoinBssRptParm);
+
+}
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+static void SetFwRsvdPagePkt_BTCoex(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       struct xmit_priv *pxmitpriv;
+       struct mlme_ext_priv *pmlmeext;
+       struct mlme_ext_info *pmlmeinfo;
+       u8 fakemac[6] = {0x00, 0xe0, 0x4c, 0x00, 0x00, 0x00};
+       u32 NullDataLength, BTQosNullLength;
+       u8 *ReservedPagePacket;
+       u8 PageNum, PageNeed, TxDescLen;
+       u16 BufIndex;
+       u32 TotalPacketLen;
+       struct rsvdpage_loc     RsvdPageLoc;
+
+       DBG_8723A("+%s\n", __FUNCTION__);
+
+       ReservedPagePacket = kzalloc(1024, GFP_KERNEL);
+       if (ReservedPagePacket == NULL) {
+               DBG_8723A("%s: alloc ReservedPagePacket fail!\n", __FUNCTION__);
+               return;
+       }
+
+       pHalData = GET_HAL_DATA(padapter);
+       pxmitpriv = &padapter->xmitpriv;
+       pmlmeext = &padapter->mlmeextpriv;
+       pmlmeinfo = &pmlmeext->mlmext_info;
+
+       TxDescLen = TXDESC_SIZE;
+       PageNum = 0;
+
+       /* 3 (1) beacon */
+       BufIndex = TXDESC_OFFSET;
+       /*  skip Beacon Packet */
+       PageNeed = 3;
+
+       PageNum += PageNeed;
+       pHalData->FwRsvdPageStartOffset = PageNum;
+
+       BufIndex += PageNeed*128;
+
+       /* 3 (3) null data */
+       RsvdPageLoc.LocNullData = PageNum;
+       ConstructNullFunctionData(
+               padapter,
+               &ReservedPagePacket[BufIndex],
+               &NullDataLength,
+               fakemac,
+               false, 0, 0, false);
+       rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
+
+       PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
+       PageNum += PageNeed;
+
+       BufIndex += PageNeed*128;
+
+       /* 3 (6) BT Qos null data */
+       RsvdPageLoc.LocBTQosNull = PageNum;
+       ConstructNullFunctionData(
+               padapter,
+               &ReservedPagePacket[BufIndex],
+               &BTQosNullLength,
+               fakemac,
+               true, 0, 0, false);
+       rtl8723a_fill_fake_txdesc(padapter, &ReservedPagePacket[BufIndex-TxDescLen], BTQosNullLength, false, true);
+
+       TotalPacketLen = BufIndex + BTQosNullLength;
+
+       pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
+       if (pmgntframe == NULL)
+               goto exit;
+
+       /*  update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+       pattrib->qsel = 0x10;
+       pattrib->pktlen = pattrib->last_txcmdsz = TotalPacketLen - TXDESC_OFFSET;
+       memcpy(pmgntframe->buf_addr, ReservedPagePacket, TotalPacketLen);
+
+       rtw_hal_mgnt_xmit23a(padapter, pmgntframe);
+
+       DBG_8723A("%s: Set RSVD page location to Fw\n", __FUNCTION__);
+       FillH2CCmd(padapter, RSVD_PAGE_EID, sizeof(RsvdPageLoc), (u8 *)&RsvdPageLoc);
+
+exit:
+       kfree(ReservedPagePacket);
+}
+
+void rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       u8 bRecover = false;
+
+       DBG_8723A("+%s\n", __FUNCTION__);
+
+       pHalData = GET_HAL_DATA(padapter);
+
+       /*  Set FWHW_TXQ_CTRL 0x422[6]= 0 to tell Hw the packet is not a real beacon frame. */
+       if (pHalData->RegFwHwTxQCtrl & BIT(6))
+               bRecover = true;
+
+       /*  To tell Hw the packet is not a real beacon frame. */
+       pHalData->RegFwHwTxQCtrl &= ~BIT(6);
+       rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
+       SetFwRsvdPagePkt_BTCoex(padapter);
+
+       /*  To make sure that if there exists an adapter which would like to send beacon. */
+       /*  If exists, the origianl value of 0x422[6] will be 1, we should check this to */
+       /*  prevent from setting 0x422[6] to 0 after download reserved page, or it will cause */
+       /*  the beacon cannot be sent by HW. */
+       /*  2010.06.23. Added by tynli. */
+       if (bRecover) {
+               pHalData->RegFwHwTxQCtrl |= BIT(6);
+               rtw_write8(padapter, REG_FWHW_TXQ_CTRL+2, pHalData->RegFwHwTxQCtrl);
+       }
+}
+#endif
+
+#ifdef CONFIG_8723AU_P2P
+void rtl8723a_set_p2p_ps_offload_cmd(struct rtw_adapter *padapter, u8 p2p_ps_state)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       struct P2P_PS_Offload_t *p2p_ps_offload = &pHalData->p2p_ps_offload;
+       u8 i;
+
+       switch (p2p_ps_state) {
+       case P2P_PS_DISABLE:
+               DBG_8723A("P2P_PS_DISABLE \n");
+               memset(p2p_ps_offload, 0, 1);
+               break;
+       case P2P_PS_ENABLE:
+               DBG_8723A("P2P_PS_ENABLE \n");
+               /*  update CTWindow value. */
+               if (pwdinfo->ctwindow > 0) {
+                       p2p_ps_offload->CTWindow_En = 1;
+                       rtw_write8(padapter, REG_P2P_CTWIN, pwdinfo->ctwindow);
+               }
+
+               /*  hw only support 2 set of NoA */
+               for (i = 0; i < pwdinfo->noa_num; i++) {
+                       /*  To control the register setting for which NOA */
+                       rtw_write8(padapter, REG_NOA_DESC_SEL, (i << 4));
+                       if (i == 0)
+                               p2p_ps_offload->NoA0_En = 1;
+                       else
+                               p2p_ps_offload->NoA1_En = 1;
+
+                       /*  config P2P NoA Descriptor Register */
+                       rtw_write32(padapter, REG_NOA_DESC_DURATION, pwdinfo->noa_duration[i]);
+
+                       rtw_write32(padapter, REG_NOA_DESC_INTERVAL, pwdinfo->noa_interval[i]);
+
+                       rtw_write32(padapter, REG_NOA_DESC_START, pwdinfo->noa_start_time[i]);
+
+                       rtw_write8(padapter, REG_NOA_DESC_COUNT, pwdinfo->noa_count[i]);
+               }
+
+               if ((pwdinfo->opp_ps == 1) || (pwdinfo->noa_num > 0)) {
+                       /*  rst p2p circuit */
+                       rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(4));
+
+                       p2p_ps_offload->Offload_En = 1;
+
+                       if (rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+                               p2p_ps_offload->role = 1;
+                               p2p_ps_offload->AllStaSleep = 0;
+                       } else {
+                               p2p_ps_offload->role = 0;
+                       }
+
+                       p2p_ps_offload->discovery = 0;
+               }
+               break;
+       case P2P_PS_SCAN:
+               DBG_8723A("P2P_PS_SCAN \n");
+               p2p_ps_offload->discovery = 1;
+               break;
+       case P2P_PS_SCAN_DONE:
+               DBG_8723A("P2P_PS_SCAN_DONE \n");
+               p2p_ps_offload->discovery = 0;
+               pwdinfo->p2p_ps_state = P2P_PS_ENABLE;
+               break;
+       default:
+               break;
+       }
+
+       FillH2CCmd(padapter, P2P_PS_OFFLOAD_EID, 1, (u8 *)p2p_ps_offload);
+}
+#endif /* CONFIG_8723AU_P2P */
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_dm.c b/drivers/staging/rtl8723au/hal/rtl8723a_dm.c
new file mode 100644 (file)
index 0000000..f204ab1
--- /dev/null
@@ -0,0 +1,273 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+/*  */
+/*  Description: */
+/*  */
+/*  This file is for 92CE/92CU dynamic mechanism only */
+/*  */
+/*  */
+/*  */
+#define _RTL8723A_DM_C_
+
+/*  */
+/*  include files */
+/*  */
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <rtl8723a_hal.h>
+
+/*  */
+/*  Global var */
+/*  */
+
+static void dm_CheckStatistics(struct rtw_adapter *Adapter)
+{
+}
+
+static void dm_CheckPbcGPIO(struct rtw_adapter *padapter)
+{
+       u8      tmp1byte;
+       u8      bPbcPressed = false;
+
+       if (!padapter->registrypriv.hw_wps_pbc)
+               return;
+
+       tmp1byte = rtw_read8(padapter, GPIO_IO_SEL);
+       tmp1byte |= (HAL_8192C_HW_GPIO_WPS_BIT);
+       rtw_write8(padapter, GPIO_IO_SEL, tmp1byte);    /* enable GPIO[2] as output mode */
+
+       tmp1byte &= ~(HAL_8192C_HW_GPIO_WPS_BIT);
+       rtw_write8(padapter,  GPIO_IN, tmp1byte);               /* reset the floating voltage level */
+
+       tmp1byte = rtw_read8(padapter, GPIO_IO_SEL);
+       tmp1byte &= ~(HAL_8192C_HW_GPIO_WPS_BIT);
+       rtw_write8(padapter, GPIO_IO_SEL, tmp1byte);    /* enable GPIO[2] as input mode */
+
+       tmp1byte = rtw_read8(padapter, GPIO_IN);
+
+       if (tmp1byte == 0xff)
+               return;
+
+       if (tmp1byte&HAL_8192C_HW_GPIO_WPS_BIT)
+               bPbcPressed = true;
+
+       if (bPbcPressed) {
+               /*  Here we only set bPbcPressed to true */
+               /*  After trigger PBC, the variable will be set to false */
+               DBG_8723A("CheckPbcGPIO - PBC is pressed\n");
+
+               if (padapter->pid[0] == 0) {
+                       /* 0 is the default value and it means the application
+                        * monitors the HW PBC doesn't privde its pid to driver.
+                        */
+                       return;
+               }
+
+               rtw_signal_process(padapter->pid[0], SIGUSR1);
+       }
+}
+
+/*  Initialize GPIO setting registers */
+/*  functions */
+static void Init_ODM_ComInfo_8723a(struct rtw_adapter *Adapter)
+{
+
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
+       u8      cut_ver, fab_ver;
+
+       /*  */
+       /*  Init Value */
+       /*  */
+       memset(pDM_Odm, 0, sizeof(*pDM_Odm));
+
+       pDM_Odm->Adapter = Adapter;
+       ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_PLATFORM, 0x04);
+       ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_INTERFACE, RTW_USB);/* RTL871X_HCI_TYPE */
+
+       ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_IC_TYPE, ODM_RTL8723A);
+
+       if (IS_8723A_A_CUT(pHalData->VersionID)) {
+               fab_ver = ODM_UMC;
+               cut_ver = ODM_CUT_A;
+       } else if (IS_8723A_B_CUT(pHalData->VersionID)) {
+               fab_ver = ODM_UMC;
+               cut_ver = ODM_CUT_B;
+       } else {
+               fab_ver = ODM_TSMC;
+               cut_ver = ODM_CUT_A;
+       }
+       ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_FAB_VER, fab_ver);
+       ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_CUT_VER, cut_ver);
+       ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_MP_TEST_CHIP, IS_NORMAL_CHIP(pHalData->VersionID));
+
+       ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_BOARD_TYPE, pHalData->BoardType);
+
+       if (pHalData->BoardType == BOARD_USB_High_PA) {
+               ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_EXT_LNA, true);
+               ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_EXT_PA, true);
+       }
+       ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_PATCH_ID, pHalData->CustomerID);
+       ODM_CmnInfoInit23a(pDM_Odm, ODM_CMNINFO_BWIFI_TEST, Adapter->registrypriv.wifi_spec);
+
+       if (pHalData->rf_type == RF_1T1R)
+               ODM_CmnInfoUpdate23a(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T1R);
+       else if (pHalData->rf_type == RF_2T2R)
+               ODM_CmnInfoUpdate23a(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_2T2R);
+       else if (pHalData->rf_type == RF_1T2R)
+               ODM_CmnInfoUpdate23a(pDM_Odm, ODM_CMNINFO_RF_TYPE, ODM_1T2R);
+}
+
+static void Update_ODM_ComInfo_8723a(struct rtw_adapter *Adapter)
+{
+       struct mlme_ext_priv    *pmlmeext = &Adapter->mlmeextpriv;
+       struct mlme_priv                *pmlmepriv = &Adapter->mlmepriv;
+       struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
+       struct dm_priv  *pdmpriv = &pHalData->dmpriv;
+       int i;
+       pdmpriv->InitODMFlag =  ODM_BB_DIG              |
+                               ODM_BB_RA_MASK          |
+                               ODM_BB_DYNAMIC_TXPWR    |
+                               ODM_BB_FA_CNT           |
+                               ODM_BB_RSSI_MONITOR     |
+                               ODM_BB_CCK_PD           |
+                               ODM_BB_PWR_SAVE         |
+                               ODM_MAC_EDCA_TURBO      |
+                               ODM_RF_TX_PWR_TRACK     |
+                               ODM_RF_CALIBRATION;
+       /*  Pointer reference */
+
+       ODM_CmnInfoUpdate23a(pDM_Odm, ODM_CMNINFO_ABILITY, pdmpriv->InitODMFlag);
+
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_TX_UNI,
+                          &Adapter->xmitpriv.tx_bytes);
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_RX_UNI,
+                          &Adapter->recvpriv.rx_bytes);
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_WM_MODE,
+                          &pmlmeext->cur_wireless_mode);
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_SEC_CHNL_OFFSET,
+                          &pHalData->nCur40MhzPrimeSC);
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_SEC_MODE,
+                          &Adapter->securitypriv.dot11PrivacyAlgrthm);
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_BW,
+                          &pHalData->CurrentChannelBW);
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_CHNL,
+                          &pHalData->CurrentChannel);
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_NET_CLOSED, &Adapter->net_closed);
+
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_SCAN, &pmlmepriv->bScanInProcess);
+       ODM23a_CmnInfoHook(pDM_Odm, ODM_CMNINFO_POWER_SAVING,
+                          &pwrctrlpriv->bpower_saving);
+
+       for (i = 0; i < NUM_STA; i++)
+               ODM_CmnInfoPtrArrayHook23a(pDM_Odm, ODM_CMNINFO_STA_STATUS, i, NULL);
+}
+
+void rtl8723a_InitHalDm(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv  *pdmpriv = &pHalData->dmpriv;
+       struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
+       u8      i;
+
+       pdmpriv->DM_Type = DM_Type_ByDriver;
+       pdmpriv->DMFlag = DYNAMIC_FUNC_DISABLE;
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       pdmpriv->DMFlag |= DYNAMIC_FUNC_BT;
+#endif
+       pdmpriv->InitDMFlag = pdmpriv->DMFlag;
+
+       Update_ODM_ComInfo_8723a(Adapter);
+       ODM23a_DMInit(pDM_Odm);
+       /*  Save REG_INIDATA_RATE_SEL value for TXDESC. */
+       for (i = 0; i < 32; i++)
+               pdmpriv->INIDATA_RATE[i] = rtw_read8(Adapter, REG_INIDATA_RATE_SEL+i) & 0x3f;
+}
+
+void
+rtl8723a_HalDmWatchDog(
+       struct rtw_adapter *Adapter
+       )
+{
+       bool            bFwCurrentInPSMode = false;
+       bool            bFwPSAwake = true;
+       u8 hw_init_completed = false;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv  *pdmpriv = &pHalData->dmpriv;
+
+       hw_init_completed = Adapter->hw_init_completed;
+
+       if (hw_init_completed == false)
+               goto skip_dm;
+
+       bFwCurrentInPSMode = Adapter->pwrctrlpriv.bFwCurrentInPSMode;
+       rtw23a_hal_get_hwreg(Adapter, HW_VAR_FWLPS_RF_ON, (u8 *)(&bFwPSAwake));
+
+#ifdef CONFIG_8723AU_P2P
+       /*  Fw is under p2p powersaving mode, driver should stop dynamic mechanism. */
+       /*  modifed by thomas. 2011.06.11. */
+       if (Adapter->wdinfo.p2p_ps_mode)
+               bFwPSAwake = false;
+#endif /* CONFIG_8723AU_P2P */
+
+       if ((hw_init_completed) && ((!bFwCurrentInPSMode) && bFwPSAwake)) {
+               /*  Calculate Tx/Rx statistics. */
+               dm_CheckStatistics(Adapter);
+
+               /*  Read REG_INIDATA_RATE_SEL value for TXDESC. */
+               if (check_fwstate(&Adapter->mlmepriv, WIFI_STATION_STATE)) {
+                       pdmpriv->INIDATA_RATE[0] = rtw_read8(Adapter, REG_INIDATA_RATE_SEL) & 0x3f;
+               } else {
+                       u8      i;
+                       for (i = 1 ; i < (Adapter->stapriv.asoc_sta_count + 1); i++)
+                               pdmpriv->INIDATA_RATE[i] = rtw_read8(Adapter, (REG_INIDATA_RATE_SEL+i)) & 0x3f;
+               }
+       }
+
+       /* ODM */
+       if (hw_init_completed == true) {
+               u8      bLinked = false;
+
+               if (rtw_linked_check(Adapter))
+                       bLinked = true;
+
+               ODM_CmnInfoUpdate23a(&pHalData->odmpriv, ODM_CMNINFO_LINK,
+                                    bLinked);
+               ODM_DMWatchdog23a(&pHalData->odmpriv);
+       }
+
+skip_dm:
+
+       /*  Check GPIO to determine current RF on/off and Pbc status. */
+       /*  Check Hardware Radio ON/OFF or not */
+       dm_CheckPbcGPIO(Adapter);
+}
+
+void rtl8723a_init_dm_priv(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv  *pdmpriv = &pHalData->dmpriv;
+
+       memset(pdmpriv, 0, sizeof(struct dm_priv));
+       Init_ODM_ComInfo_8723a(Adapter);
+}
+
+void rtl8723a_deinit_dm_priv(struct rtw_adapter *Adapter)
+{
+}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c b/drivers/staging/rtl8723au/hal/rtl8723a_hal_init.c
new file mode 100644 (file)
index 0000000..0982b0a
--- /dev/null
@@ -0,0 +1,3452 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _HAL_INIT_C_
+
+#include <linux/firmware.h>
+#include <drv_types.h>
+#include <rtw_efuse.h>
+
+#include <rtl8723a_hal.h>
+
+static void _FWDownloadEnable(struct rtw_adapter *padapter, bool enable)
+{
+       u8 tmp;
+
+       if (enable) {
+               /*  8051 enable */
+               tmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
+               rtw_write8(padapter, REG_SYS_FUNC_EN + 1, tmp | 0x04);
+
+               /*  MCU firmware download enable. */
+               tmp = rtw_read8(padapter, REG_MCUFWDL);
+               rtw_write8(padapter, REG_MCUFWDL, tmp | 0x01);
+
+               /*  8051 reset */
+               tmp = rtw_read8(padapter, REG_MCUFWDL + 2);
+               rtw_write8(padapter, REG_MCUFWDL + 2, tmp & 0xf7);
+       } else {
+               /*  MCU firmware download disable. */
+               tmp = rtw_read8(padapter, REG_MCUFWDL);
+               rtw_write8(padapter, REG_MCUFWDL, tmp & 0xfe);
+
+               /*  Reserved for fw extension. */
+               rtw_write8(padapter, REG_MCUFWDL + 1, 0x00);
+       }
+}
+
+static int _BlockWrite(struct rtw_adapter *padapter, void *buffer, u32 buffSize)
+{
+       int ret = _SUCCESS;
+       /*  (Default) Phase #1 : PCI muse use 4-byte write to download FW */
+       u32 blockSize_p1 = 4;
+       /*  Phase #2 : Use 8-byte, if Phase#1 use big size to write FW. */
+       u32 blockSize_p2 = 8;
+       /*  Phase #3 : Use 1-byte, the remnant of FW image. */
+       u32 blockSize_p3 = 1;
+       u32 blockCount_p1 = 0, blockCount_p2 = 0, blockCount_p3 = 0;
+       u32 remainSize_p1 = 0, remainSize_p2 = 0;
+       u8 *bufferPtr = (u8 *) buffer;
+       u32 i = 0, offset = 0;
+
+       blockSize_p1 = 254;
+
+       /* 3 Phase #1 */
+       blockCount_p1 = buffSize / blockSize_p1;
+       remainSize_p1 = buffSize % blockSize_p1;
+
+       if (blockCount_p1) {
+               RT_TRACE(_module_hal_init_c_, _drv_notice_,
+                        ("_BlockWrite: [P1] buffSize(%d) blockSize_p1(%d) "
+                         "blockCount_p1(%d) remainSize_p1(%d)\n",
+                         buffSize, blockSize_p1, blockCount_p1,
+                         remainSize_p1));
+       }
+
+       for (i = 0; i < blockCount_p1; i++) {
+               ret = rtw_writeN(padapter,
+                                (FW_8723A_START_ADDRESS + i * blockSize_p1),
+                                blockSize_p1, (bufferPtr + i * blockSize_p1));
+               if (ret == _FAIL)
+                       goto exit;
+       }
+
+       /* 3 Phase #2 */
+       if (remainSize_p1) {
+               offset = blockCount_p1 * blockSize_p1;
+
+               blockCount_p2 = remainSize_p1 / blockSize_p2;
+               remainSize_p2 = remainSize_p1 % blockSize_p2;
+
+               if (blockCount_p2) {
+                       RT_TRACE(_module_hal_init_c_, _drv_notice_,
+                                ("_BlockWrite: [P2] buffSize_p2(%d) "
+                                 "blockSize_p2(%d) blockCount_p2(%d) "
+                                 "remainSize_p2(%d)\n",
+                                 (buffSize - offset), blockSize_p2,
+                                 blockCount_p2, remainSize_p2));
+               }
+
+               for (i = 0; i < blockCount_p2; i++) {
+                       ret = rtw_writeN(padapter,
+                                        (FW_8723A_START_ADDRESS + offset +
+                                         i * blockSize_p2), blockSize_p2,
+                                        (bufferPtr + offset +
+                                         i * blockSize_p2));
+
+                       if (ret == _FAIL)
+                               goto exit;
+               }
+       }
+
+       /* 3 Phase #3 */
+       if (remainSize_p2) {
+               offset = (blockCount_p1 * blockSize_p1) +
+                       (blockCount_p2 * blockSize_p2);
+
+               blockCount_p3 = remainSize_p2 / blockSize_p3;
+
+               RT_TRACE(_module_hal_init_c_, _drv_notice_,
+                        ("_BlockWrite: [P3] buffSize_p3(%d) blockSize_p3(%d) "
+                         "blockCount_p3(%d)\n",
+                         (buffSize - offset), blockSize_p3, blockCount_p3));
+
+               for (i = 0; i < blockCount_p3; i++) {
+                       ret = rtw_write8(padapter,
+                                        (FW_8723A_START_ADDRESS + offset + i),
+                                        *(bufferPtr + offset + i));
+
+                       if (ret == _FAIL)
+                               goto exit;
+               }
+       }
+
+exit:
+       return ret;
+}
+
+static int
+_PageWrite(struct rtw_adapter *padapter, u32 page, void *buffer, u32 size)
+{
+       u8 value8;
+       u8 u8Page = (u8) (page & 0x07);
+
+       value8 = (rtw_read8(padapter, REG_MCUFWDL + 2) & 0xF8) | u8Page;
+       rtw_write8(padapter, REG_MCUFWDL + 2, value8);
+
+       return _BlockWrite(padapter, buffer, size);
+}
+
+static int _WriteFW(struct rtw_adapter *padapter, void *buffer, u32 size)
+{
+       /*  Since we need dynamic decide method of dwonload fw, so we
+           call this function to get chip version. */
+       /*  We can remove _ReadChipVersion from ReadpadapterInfo8192C later. */
+       int ret = _SUCCESS;
+       u32 pageNums, remainSize;
+       u32 page, offset;
+       u8 *bufferPtr = (u8 *) buffer;
+
+       pageNums = size / MAX_PAGE_SIZE;
+       /* RT_ASSERT((pageNums <= 4),
+          ("Page numbers should not greater then 4 \n")); */
+       remainSize = size % MAX_PAGE_SIZE;
+
+       for (page = 0; page < pageNums; page++) {
+               offset = page * MAX_PAGE_SIZE;
+               ret = _PageWrite(padapter, page, bufferPtr + offset,
+                                MAX_PAGE_SIZE);
+
+               if (ret == _FAIL)
+                       goto exit;
+       }
+       if (remainSize) {
+               offset = pageNums * MAX_PAGE_SIZE;
+               page = pageNums;
+               ret = _PageWrite(padapter, page, bufferPtr + offset,
+                                remainSize);
+
+               if (ret == _FAIL)
+                       goto exit;
+       }
+       RT_TRACE(_module_hal_init_c_, _drv_info_,
+                ("_WriteFW Done- for Normal chip.\n"));
+
+exit:
+       return ret;
+}
+
+static s32 _FWFreeToGo(struct rtw_adapter *padapter)
+{
+       u32 counter = 0;
+       u32 value32;
+
+       /*  polling CheckSum report */
+       do {
+               value32 = rtw_read32(padapter, REG_MCUFWDL);
+               if (value32 & FWDL_ChkSum_rpt)
+                       break;
+       } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
+
+       if (counter >= POLLING_READY_TIMEOUT_COUNT) {
+               RT_TRACE(_module_hal_init_c_, _drv_err_,
+                        ("%s: chksum report fail! REG_MCUFWDL:0x%08x\n",
+                         __func__, value32));
+               return _FAIL;
+       }
+       RT_TRACE(_module_hal_init_c_, _drv_info_,
+                ("%s: Checksum report OK! REG_MCUFWDL:0x%08x\n", __func__,
+                 value32));
+
+       value32 = rtw_read32(padapter, REG_MCUFWDL);
+       value32 |= MCUFWDL_RDY;
+       value32 &= ~WINTINI_RDY;
+       rtw_write32(padapter, REG_MCUFWDL, value32);
+
+       /*  polling for FW ready */
+       counter = 0;
+       do {
+               value32 = rtw_read32(padapter, REG_MCUFWDL);
+               if (value32 & WINTINI_RDY) {
+                       RT_TRACE(_module_hal_init_c_, _drv_info_,
+                                ("%s: Polling FW ready success!! "
+                                 "REG_MCUFWDL:0x%08x\n",
+                                 __func__, value32));
+                       return _SUCCESS;
+               }
+               udelay(5);
+       } while (counter++ < POLLING_READY_TIMEOUT_COUNT);
+
+       RT_TRACE(_module_hal_init_c_, _drv_err_,
+                ("%s: Polling FW ready fail!! REG_MCUFWDL:0x%08x\n",
+                 __func__, value32));
+       return _FAIL;
+}
+
+#define IS_FW_81xxC(padapter)  (((GET_HAL_DATA(padapter))->FirmwareSignature & 0xFFF0) == 0x88C0)
+
+void rtl8723a_FirmwareSelfReset(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 u1bTmp;
+       u8 Delay = 100;
+
+       if (!(IS_FW_81xxC(padapter) &&
+             ((pHalData->FirmwareVersion < 0x21) ||
+              (pHalData->FirmwareVersion == 0x21 &&
+               pHalData->FirmwareSubVersion < 0x01)))) {
+               /*  after 88C Fw v33.1 */
+               /* 0x1cf = 0x20. Inform 8051 to reset. 2009.12.25. tynli_test */
+               rtw_write8(padapter, REG_HMETFR + 3, 0x20);
+
+               u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
+               while (u1bTmp & BIT2) {
+                       Delay--;
+                       if (Delay == 0)
+                               break;
+                       udelay(50);
+                       u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
+               }
+               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                        ("-%s: 8051 reset success (%d)\n", __func__,
+                         Delay));
+
+               if ((Delay == 0)) {
+                       /* force firmware reset */
+                       u1bTmp = rtw_read8(padapter, REG_SYS_FUNC_EN + 1);
+                       rtw_write8(padapter, REG_SYS_FUNC_EN + 1,
+                                  u1bTmp & (~BIT2));
+               }
+       }
+}
+
+/*  */
+/*     Description: */
+/*             Download 8192C firmware code. */
+/*  */
+/*  */
+s32 rtl8723a_FirmwareDownload(struct rtw_adapter *padapter)
+{
+       s32 rtStatus = _SUCCESS;
+       u8 writeFW_retry = 0;
+       unsigned long fwdl_start_time;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct dvobj_priv *dvobj = adapter_to_dvobj(padapter);
+       struct device *device = dvobj_to_dev(dvobj);
+       struct rt_8723a_firmware_hdr *pFwHdr = NULL;
+       const struct firmware *fw;
+       char *fw_name;
+       u8 *firmware_buf = NULL;
+       u8 *buf;
+       int fw_size;
+       static int log_version;
+
+       RT_TRACE(_module_hal_init_c_, _drv_info_, ("+%s\n", __func__));
+
+       if (IS_8723A_A_CUT(pHalData->VersionID)) {
+               fw_name = "rtlwifi/rtl8723aufw.bin";
+               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                        ("rtl8723a_FirmwareDownload: R8723FwImageArray_UMC "
+                         "for RTL8723A A CUT\n"));
+       } else if (IS_8723A_B_CUT(pHalData->VersionID)) {
+               /*  WLAN Fw. */
+               if (padapter->registrypriv.wifi_spec == 1) {
+                       fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin";
+                       DBG_8723A(" Rtl8723_FwUMCBCutImageArrayWithoutBT for "
+                                 "RTL8723A B CUT\n");
+               } else {
+#ifdef CONFIG_8723AU_BT_COEXIST
+                       fw_name = "rtlwifi/rtl8723aufw_B.bin";
+                       DBG_8723A(" Rtl8723_FwUMCBCutImageArrayWithBT for "
+                                 "RTL8723A B CUT\n");
+#else
+                       fw_name = "rtlwifi/rtl8723aufw_B_NoBT.bin";
+                       DBG_8723A(" Rtl8723_FwUMCBCutImageArrayWithoutBT for "
+                                 "RTL8723A B CUT\n");
+#endif
+               }
+       } else {
+               /*  <Roger_TODO> We should download proper RAM Code here
+                   to match the ROM code. */
+               RT_TRACE(_module_hal_init_c_, _drv_err_,
+                        ("%s: unknow version!\n", __func__));
+               rtStatus = _FAIL;
+               goto Exit;
+       }
+
+       pr_info("rtl8723au: Loading firmware %s\n", fw_name);
+       if (request_firmware(&fw, fw_name, device)) {
+               pr_err("rtl8723au: request_firmware load failed\n");
+               rtStatus = _FAIL;
+               goto Exit;
+       }
+       if (!fw) {
+               pr_err("rtl8723au: Firmware %s not available\n", fw_name);
+               rtStatus = _FAIL;
+               goto Exit;
+       }
+       firmware_buf = kzalloc(fw->size, GFP_KERNEL);
+       if (!firmware_buf) {
+               rtStatus = _FAIL;
+               goto Exit;
+       }
+       memcpy(firmware_buf, fw->data, fw->size);
+       buf = firmware_buf;
+       fw_size = fw->size;
+       release_firmware(fw);
+
+       /*  To Check Fw header. Added by tynli. 2009.12.04. */
+       pFwHdr = (struct rt_8723a_firmware_hdr *)firmware_buf;
+
+       pHalData->FirmwareVersion = le16_to_cpu(pFwHdr->Version);
+       pHalData->FirmwareSubVersion = pFwHdr->Subversion;
+       pHalData->FirmwareSignature = le16_to_cpu(pFwHdr->Signature);
+
+       DBG_8723A("%s: fw_ver =%d fw_subver =%d sig = 0x%x\n",
+                 __func__, pHalData->FirmwareVersion,
+                 pHalData->FirmwareSubVersion, pHalData->FirmwareSignature);
+
+       if (!log_version++)
+               pr_info("%sFirmware Version %d, SubVersion %d, Signature "
+                       "0x%x\n", DRIVER_PREFIX, pHalData->FirmwareVersion,
+                       pHalData->FirmwareSubVersion,
+                       pHalData->FirmwareSignature);
+
+       if (IS_FW_HEADER_EXIST(pFwHdr)) {
+               /*  Shift 32 bytes for FW header */
+               buf = buf + 32;
+               fw_size = fw_size - 32;
+       }
+
+       /*  Suggested by Filen. If 8051 is running in RAM code, driver should
+           inform Fw to reset by itself, */
+       /*  or it will cause download Fw fail. 2010.02.01. by tynli. */
+       if (rtw_read8(padapter, REG_MCUFWDL) & RAM_DL_SEL) {
+               /* 8051 RAM code */
+               rtl8723a_FirmwareSelfReset(padapter);
+               rtw_write8(padapter, REG_MCUFWDL, 0x00);
+       }
+
+       _FWDownloadEnable(padapter, true);
+       fwdl_start_time = jiffies;
+       while (1) {
+               /* reset the FWDL chksum */
+               rtw_write8(padapter, REG_MCUFWDL,
+                          rtw_read8(padapter, REG_MCUFWDL) | FWDL_ChkSum_rpt);
+
+               rtStatus = _WriteFW(padapter, buf, fw_size);
+
+               if (rtStatus == _SUCCESS ||
+                   (jiffies_to_msecs(jiffies - fwdl_start_time) > 500 &&
+                    writeFW_retry++ >= 3))
+                       break;
+
+               DBG_8723A("%s writeFW_retry:%u, time after fwdl_start_time:"
+                         "%ums\n", __func__, writeFW_retry,
+                         jiffies_to_msecs(jiffies - fwdl_start_time));
+       }
+       _FWDownloadEnable(padapter, false);
+       if (_SUCCESS != rtStatus) {
+               DBG_8723A("DL Firmware failed!\n");
+               goto Exit;
+       }
+
+       rtStatus = _FWFreeToGo(padapter);
+       if (_SUCCESS != rtStatus) {
+               RT_TRACE(_module_hal_init_c_, _drv_err_,
+                        ("DL Firmware failed!\n"));
+               goto Exit;
+       }
+       RT_TRACE(_module_hal_init_c_, _drv_info_,
+                ("Firmware is ready to run!\n"));
+
+Exit:
+       kfree(firmware_buf);
+       return rtStatus;
+}
+
+void rtl8723a_InitializeFirmwareVars(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       /*  Init Fw LPS related. */
+       padapter->pwrctrlpriv.bFwCurrentInPSMode = false;
+
+       /*  Init H2C counter. by tynli. 2009.12.09. */
+       pHalData->LastHMEBoxNum = 0;
+}
+
+static void rtl8723a_free_hal_data(struct rtw_adapter *padapter)
+{
+
+       kfree(padapter->HalData);
+       padapter->HalData = NULL;
+
+}
+
+/*  */
+/*                             Efuse related code */
+/*  */
+static u8
+hal_EfuseSwitchToBank(struct rtw_adapter *padapter, u8 bank)
+{
+       u8 bRet = false;
+       u32 value32 = 0;
+
+       DBG_8723A("%s: Efuse switch bank to %d\n", __func__, bank);
+       value32 = rtw_read32(padapter, EFUSE_TEST);
+       bRet = true;
+       switch (bank) {
+       case 0:
+               value32 = (value32 & ~EFUSE_SEL_MASK) |
+                       EFUSE_SEL(EFUSE_WIFI_SEL_0);
+               break;
+       case 1:
+               value32 = (value32 & ~EFUSE_SEL_MASK) |
+                       EFUSE_SEL(EFUSE_BT_SEL_0);
+               break;
+       case 2:
+               value32 = (value32 & ~EFUSE_SEL_MASK) |
+                       EFUSE_SEL(EFUSE_BT_SEL_1);
+               break;
+       case 3:
+               value32 = (value32 & ~EFUSE_SEL_MASK) |
+                       EFUSE_SEL(EFUSE_BT_SEL_2);
+               break;
+       default:
+               value32 = (value32 & ~EFUSE_SEL_MASK) |
+                       EFUSE_SEL(EFUSE_WIFI_SEL_0);
+               bRet = false;
+               break;
+       }
+       rtw_write32(padapter, EFUSE_TEST, value32);
+
+       return bRet;
+}
+
+static void
+Hal_GetEfuseDefinition(struct rtw_adapter *padapter,
+                      u8 efuseType, u8 type, void *pOut)
+{
+       u8 *pu1Tmp;
+       u16 *pu2Tmp;
+       u8 *pMax_section;
+
+       switch (type) {
+       case TYPE_EFUSE_MAX_SECTION:
+               pMax_section = (u8 *) pOut;
+
+               if (efuseType == EFUSE_WIFI)
+                       *pMax_section = EFUSE_MAX_SECTION_8723A;
+               else
+                       *pMax_section = EFUSE_BT_MAX_SECTION;
+               break;
+
+       case TYPE_EFUSE_REAL_CONTENT_LEN:
+               pu2Tmp = (u16 *) pOut;
+
+               if (efuseType == EFUSE_WIFI)
+                       *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723A;
+               else
+                       *pu2Tmp = EFUSE_BT_REAL_CONTENT_LEN;
+               break;
+
+       case TYPE_AVAILABLE_EFUSE_BYTES_BANK:
+               pu2Tmp = (u16 *) pOut;
+
+               if (efuseType == EFUSE_WIFI)
+                       *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723A -
+                                  EFUSE_OOB_PROTECT_BYTES);
+               else
+                       *pu2Tmp = (EFUSE_BT_REAL_BANK_CONTENT_LEN -
+                                  EFUSE_PROTECT_BYTES_BANK);
+               break;
+
+       case TYPE_AVAILABLE_EFUSE_BYTES_TOTAL:
+               pu2Tmp = (u16 *) pOut;
+
+               if (efuseType == EFUSE_WIFI)
+                       *pu2Tmp = (EFUSE_REAL_CONTENT_LEN_8723A -
+                                  EFUSE_OOB_PROTECT_BYTES);
+               else
+                       *pu2Tmp = (EFUSE_BT_REAL_CONTENT_LEN -
+                                  (EFUSE_PROTECT_BYTES_BANK * 3));
+               break;
+
+       case TYPE_EFUSE_MAP_LEN:
+               pu2Tmp = (u16 *) pOut;
+
+               if (efuseType == EFUSE_WIFI)
+                       *pu2Tmp = EFUSE_MAP_LEN_8723A;
+               else
+                       *pu2Tmp = EFUSE_BT_MAP_LEN;
+               break;
+
+       case TYPE_EFUSE_PROTECT_BYTES_BANK:
+               pu1Tmp = (u8 *) pOut;
+
+               if (efuseType == EFUSE_WIFI)
+                       *pu1Tmp = EFUSE_OOB_PROTECT_BYTES;
+               else
+                       *pu1Tmp = EFUSE_PROTECT_BYTES_BANK;
+               break;
+
+       case TYPE_EFUSE_CONTENT_LEN_BANK:
+               pu2Tmp = (u16 *) pOut;
+
+               if (efuseType == EFUSE_WIFI)
+                       *pu2Tmp = EFUSE_REAL_CONTENT_LEN_8723A;
+               else
+                       *pu2Tmp = EFUSE_BT_REAL_BANK_CONTENT_LEN;
+               break;
+
+       default:
+               pu1Tmp = (u8 *) pOut;
+               *pu1Tmp = 0;
+               break;
+       }
+}
+
+#define VOLTAGE_V25            0x03
+#define LDOE25_SHIFT   28
+
+static void
+Hal_EfusePowerSwitch(struct rtw_adapter *padapter, u8 bWrite, u8 PwrState)
+{
+       u8 tempval;
+       u16 tmpV16;
+
+       if (PwrState == true) {
+               rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_ON);
+
+               /*  1.2V Power: From VDDON with Power
+                   Cut(0x0000h[15]), defualt valid */
+               tmpV16 = rtw_read16(padapter, REG_SYS_ISO_CTRL);
+               if (!(tmpV16 & PWC_EV12V)) {
+                       tmpV16 |= PWC_EV12V;
+                       rtw_write16(padapter, REG_SYS_ISO_CTRL, tmpV16);
+               }
+               /*  Reset: 0x0000h[28], default valid */
+               tmpV16 = rtw_read16(padapter, REG_SYS_FUNC_EN);
+               if (!(tmpV16 & FEN_ELDR)) {
+                       tmpV16 |= FEN_ELDR;
+                       rtw_write16(padapter, REG_SYS_FUNC_EN, tmpV16);
+               }
+
+               /*  Clock: Gated(0x0008h[5]) 8M(0x0008h[1]) clock
+                   from ANA, default valid */
+               tmpV16 = rtw_read16(padapter, REG_SYS_CLKR);
+               if ((!(tmpV16 & LOADER_CLK_EN)) || (!(tmpV16 & ANA8M))) {
+                       tmpV16 |= (LOADER_CLK_EN | ANA8M);
+                       rtw_write16(padapter, REG_SYS_CLKR, tmpV16);
+               }
+
+               if (bWrite == true) {
+                       /*  Enable LDO 2.5V before read/write action */
+                       tempval = rtw_read8(padapter, EFUSE_TEST + 3);
+                       tempval &= 0x0F;
+                       tempval |= (VOLTAGE_V25 << 4);
+                       rtw_write8(padapter, EFUSE_TEST + 3, (tempval | 0x80));
+               }
+       } else {
+               rtw_write8(padapter, REG_EFUSE_ACCESS, EFUSE_ACCESS_OFF);
+
+               if (bWrite == true) {
+                       /*  Disable LDO 2.5V after read/write action */
+                       tempval = rtw_read8(padapter, EFUSE_TEST + 3);
+                       rtw_write8(padapter, EFUSE_TEST + 3, (tempval & 0x7F));
+               }
+       }
+}
+
+static void
+hal_ReadEFuse_WiFi(struct rtw_adapter *padapter,
+                  u16 _offset, u16 _size_byte, u8 *pbuf)
+{
+       u8 *efuseTbl = NULL;
+       u16 eFuse_Addr = 0;
+       u8 offset, wden;
+       u8 efuseHeader, efuseExtHdr, efuseData;
+       u16 i, total, used;
+
+       /*  Do NOT excess total size of EFuse table.
+           Added by Roger, 2008.11.10. */
+       if ((_offset + _size_byte) > EFUSE_MAP_LEN_8723A) {
+               DBG_8723A("%s: Invalid offset(%#x) with read bytes(%#x)!!\n",
+                         __func__, _offset, _size_byte);
+               return;
+       }
+
+       efuseTbl = (u8 *) kmalloc(EFUSE_MAP_LEN_8723A, GFP_KERNEL);
+       if (efuseTbl == NULL) {
+               DBG_8723A("%s: alloc efuseTbl fail!\n", __func__);
+               return;
+       }
+       /*  0xff will be efuse default value instead of 0x00. */
+       memset(efuseTbl, 0xFF, EFUSE_MAP_LEN_8723A);
+
+       /*  switch bank back to bank 0 for later BT and wifi use. */
+       hal_EfuseSwitchToBank(padapter, 0);
+
+       while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) {
+               ReadEFuseByte23a(padapter, eFuse_Addr++, &efuseHeader);
+               if (efuseHeader == 0xFF) {
+                       DBG_8723A("%s: data end at address =%#x\n", __func__,
+                                 eFuse_Addr);
+                       break;
+               }
+
+               /*  Check PG header for section num. */
+               if (EXT_HEADER(efuseHeader)) {  /* extended header */
+                       offset = GET_HDR_OFFSET_2_0(efuseHeader);
+
+                       ReadEFuseByte23a(padapter, eFuse_Addr++, &efuseExtHdr);
+                       if (ALL_WORDS_DISABLED(efuseExtHdr)) {
+                               continue;
+                       }
+
+                       offset |= ((efuseExtHdr & 0xF0) >> 1);
+                       wden = (efuseExtHdr & 0x0F);
+               } else {
+                       offset = ((efuseHeader >> 4) & 0x0f);
+                       wden = (efuseHeader & 0x0f);
+               }
+
+               if (offset < EFUSE_MAX_SECTION_8723A) {
+                       u16 addr;
+                       /*  Get word enable value from PG header */
+
+                       addr = offset * PGPKT_DATA_SIZE;
+                       for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+                               /* Check word enable condition in the section */
+                               if (!(wden & (0x01 << i))) {
+                                       ReadEFuseByte23a(padapter, eFuse_Addr++,
+                                                     &efuseData);
+                                       efuseTbl[addr] = efuseData;
+
+                                       ReadEFuseByte23a(padapter, eFuse_Addr++,
+                                                     &efuseData);
+                                       efuseTbl[addr + 1] = efuseData;
+                               }
+                               addr += 2;
+                       }
+               } else {
+                       DBG_8723A(KERN_ERR "%s: offset(%d) is illegal!!\n",
+                                 __func__, offset);
+                       eFuse_Addr += Efuse_CalculateWordCnts23a(wden) * 2;
+               }
+       }
+
+       /*  Copy from Efuse map to output pointer memory!!! */
+       for (i = 0; i < _size_byte; i++)
+               pbuf[i] = efuseTbl[_offset + i];
+
+       /*  Calculate Efuse utilization */
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI,
+                                TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total);
+       used = eFuse_Addr - 1;
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BYTES, (u8 *)&used);
+
+       kfree(efuseTbl);
+}
+
+static void
+hal_ReadEFuse_BT(struct rtw_adapter *padapter,
+                u16 _offset, u16 _size_byte, u8 *pbuf)
+{
+       u8 *efuseTbl;
+       u8 bank;
+       u16 eFuse_Addr;
+       u8 efuseHeader, efuseExtHdr, efuseData;
+       u8 offset, wden;
+       u16 i, total, used;
+
+       /*  Do NOT excess total size of EFuse table.
+           Added by Roger, 2008.11.10. */
+       if ((_offset + _size_byte) > EFUSE_BT_MAP_LEN) {
+               DBG_8723A("%s: Invalid offset(%#x) with read bytes(%#x)!!\n",
+                         __func__, _offset, _size_byte);
+               return;
+       }
+
+       efuseTbl = kmalloc(EFUSE_BT_MAP_LEN, GFP_KERNEL);
+       if (efuseTbl == NULL) {
+               DBG_8723A("%s: efuseTbl malloc fail!\n", __func__);
+               return;
+       }
+       /*  0xff will be efuse default value instead of 0x00. */
+       memset(efuseTbl, 0xFF, EFUSE_BT_MAP_LEN);
+
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT,
+                                TYPE_AVAILABLE_EFUSE_BYTES_BANK, &total);
+
+       for (bank = 1; bank < EFUSE_MAX_BANK; bank++) {
+               if (hal_EfuseSwitchToBank(padapter, bank) == false) {
+                       DBG_8723A("%s: hal_EfuseSwitchToBank Fail!!\n",
+                                 __func__);
+                       goto exit;
+               }
+
+               eFuse_Addr = 0;
+
+               while (AVAILABLE_EFUSE_ADDR(eFuse_Addr)) {
+                       ReadEFuseByte23a(padapter, eFuse_Addr++, &efuseHeader);
+                       if (efuseHeader == 0xFF)
+                               break;
+
+                       /*  Check PG header for section num. */
+                       if (EXT_HEADER(efuseHeader)) {  /* extended header */
+                               offset = GET_HDR_OFFSET_2_0(efuseHeader);
+
+                               ReadEFuseByte23a(padapter, eFuse_Addr++,
+                                             &efuseExtHdr);
+                               if (ALL_WORDS_DISABLED(efuseExtHdr)) {
+                                       continue;
+                               }
+
+                               offset |= ((efuseExtHdr & 0xF0) >> 1);
+                               wden = (efuseExtHdr & 0x0F);
+                       } else {
+                               offset = ((efuseHeader >> 4) & 0x0f);
+                               wden = (efuseHeader & 0x0f);
+                       }
+
+                       if (offset < EFUSE_BT_MAX_SECTION) {
+                               u16 addr;
+
+                               /*  Get word enable value from PG header */
+
+                               addr = offset * PGPKT_DATA_SIZE;
+                               for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+                                       /*  Check word enable condition in
+                                           the section */
+                                       if (!(wden & (0x01 << i))) {
+                                               ReadEFuseByte23a(padapter,
+                                                             eFuse_Addr++,
+                                                             &efuseData);
+                                               efuseTbl[addr] = efuseData;
+
+                                               ReadEFuseByte23a(padapter,
+                                                             eFuse_Addr++,
+                                                             &efuseData);
+                                               efuseTbl[addr + 1] = efuseData;
+                                       }
+                                       addr += 2;
+                               }
+                       } else {
+                               DBG_8723A(KERN_ERR
+                                         "%s: offset(%d) is illegal!!\n",
+                                         __func__, offset);
+                               eFuse_Addr += Efuse_CalculateWordCnts23a(wden) * 2;
+                       }
+               }
+
+               if ((eFuse_Addr - 1) < total) {
+                       DBG_8723A("%s: bank(%d) data end at %#x\n",
+                                 __func__, bank, eFuse_Addr - 1);
+                       break;
+               }
+       }
+
+       /*  switch bank back to bank 0 for later BT and wifi use. */
+       hal_EfuseSwitchToBank(padapter, 0);
+
+       /*  Copy from Efuse map to output pointer memory!!! */
+       for (i = 0; i < _size_byte; i++)
+               pbuf[i] = efuseTbl[_offset + i];
+
+       /*  */
+       /*  Calculate Efuse utilization. */
+       /*  */
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT,
+                                TYPE_AVAILABLE_EFUSE_BYTES_TOTAL, &total);
+       used = (EFUSE_BT_REAL_BANK_CONTENT_LEN * (bank - 1)) + eFuse_Addr - 1;
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *) &used);
+
+exit:
+       kfree(efuseTbl);
+}
+
+static void
+Hal_ReadEFuse(struct rtw_adapter *padapter,
+             u8 efuseType, u16 _offset, u16 _size_byte, u8 *pbuf)
+{
+       if (efuseType == EFUSE_WIFI)
+               hal_ReadEFuse_WiFi(padapter, _offset, _size_byte, pbuf);
+       else
+               hal_ReadEFuse_BT(padapter, _offset, _size_byte, pbuf);
+}
+
+static u16
+hal_EfuseGetCurrentSize_WiFi(struct rtw_adapter *padapter)
+{
+       u16 efuse_addr = 0;
+       u8 hoffset = 0, hworden = 0;
+       u8 efuse_data, word_cnts = 0;
+
+       rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES, (u8 *) &efuse_addr);
+
+       DBG_8723A("%s: start_efuse_addr = 0x%X\n", __func__, efuse_addr);
+
+       /*  switch bank back to bank 0 for later BT and wifi use. */
+       hal_EfuseSwitchToBank(padapter, 0);
+
+       while (AVAILABLE_EFUSE_ADDR(efuse_addr)) {
+               if (efuse_OneByteRead23a(padapter, efuse_addr, &efuse_data) ==
+                   false) {
+                       DBG_8723A(KERN_ERR "%s: efuse_OneByteRead23a Fail! "
+                                 "addr = 0x%X !!\n", __func__, efuse_addr);
+                       break;
+               }
+
+               if (efuse_data == 0xFF)
+                       break;
+
+               if (EXT_HEADER(efuse_data)) {
+                       hoffset = GET_HDR_OFFSET_2_0(efuse_data);
+                       efuse_addr++;
+                       efuse_OneByteRead23a(padapter, efuse_addr, &efuse_data);
+                       if (ALL_WORDS_DISABLED(efuse_data)) {
+                               continue;
+                       }
+
+                       hoffset |= ((efuse_data & 0xF0) >> 1);
+                       hworden = efuse_data & 0x0F;
+               } else {
+                       hoffset = (efuse_data >> 4) & 0x0F;
+                       hworden = efuse_data & 0x0F;
+               }
+
+               word_cnts = Efuse_CalculateWordCnts23a(hworden);
+               efuse_addr += (word_cnts * 2) + 1;
+       }
+
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BYTES, (u8 *) &efuse_addr);
+
+       DBG_8723A("%s: CurrentSize =%d\n", __func__, efuse_addr);
+
+       return efuse_addr;
+}
+
+static u16
+hal_EfuseGetCurrentSize_BT(struct rtw_adapter *padapter)
+{
+       u16 btusedbytes;
+       u16 efuse_addr;
+       u8 bank, startBank;
+       u8 hoffset = 0, hworden = 0;
+       u8 efuse_data, word_cnts = 0;
+       u16 retU2 = 0;
+
+       rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *) &btusedbytes);
+
+       efuse_addr = (u16) ((btusedbytes % EFUSE_BT_REAL_BANK_CONTENT_LEN));
+       startBank = (u8) (1 + (btusedbytes / EFUSE_BT_REAL_BANK_CONTENT_LEN));
+
+       DBG_8723A("%s: start from bank =%d addr = 0x%X\n", __func__, startBank,
+                 efuse_addr);
+
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_BT,
+                                TYPE_AVAILABLE_EFUSE_BYTES_BANK, &retU2);
+
+       for (bank = startBank; bank < EFUSE_MAX_BANK; bank++) {
+               if (hal_EfuseSwitchToBank(padapter, bank) == false) {
+                       DBG_8723A(KERN_ERR "%s: switch bank(%d) Fail!!\n",
+                                 __func__, bank);
+                       bank = EFUSE_MAX_BANK;
+                       break;
+               }
+
+               /*  only when bank is switched we have to reset
+                   the efuse_addr. */
+               if (bank != startBank)
+                       efuse_addr = 0;
+
+               while (AVAILABLE_EFUSE_ADDR(efuse_addr)) {
+                       if (efuse_OneByteRead23a(padapter, efuse_addr,
+                                             &efuse_data) == false) {
+                               DBG_8723A(KERN_ERR "%s: efuse_OneByteRead23a Fail!"
+                                         " addr = 0x%X !!\n",
+                                         __func__, efuse_addr);
+                               bank = EFUSE_MAX_BANK;
+                               break;
+                       }
+
+                       if (efuse_data == 0xFF)
+                               break;
+
+                       if (EXT_HEADER(efuse_data)) {
+                               hoffset = GET_HDR_OFFSET_2_0(efuse_data);
+                               efuse_addr++;
+                               efuse_OneByteRead23a(padapter, efuse_addr,
+                                                 &efuse_data);
+                               if (ALL_WORDS_DISABLED(efuse_data)) {
+                                       efuse_addr++;
+                                       continue;
+                               }
+
+                               hoffset |= ((efuse_data & 0xF0) >> 1);
+                               hworden = efuse_data & 0x0F;
+                       } else {
+                               hoffset = (efuse_data >> 4) & 0x0F;
+                               hworden = efuse_data & 0x0F;
+                       }
+                       word_cnts = Efuse_CalculateWordCnts23a(hworden);
+                       /* read next header */
+                       efuse_addr += (word_cnts * 2) + 1;
+               }
+
+               /*  Check if we need to check next bank efuse */
+               if (efuse_addr < retU2) {
+                       break;  /*  don't need to check next bank. */
+               }
+       }
+
+       retU2 = ((bank - 1) * EFUSE_BT_REAL_BANK_CONTENT_LEN) + efuse_addr;
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_EFUSE_BT_BYTES, (u8 *)&retU2);
+
+       DBG_8723A("%s: CurrentSize =%d\n", __func__, retU2);
+       return retU2;
+}
+
+static u16
+Hal_EfuseGetCurrentSize(struct rtw_adapter *pAdapter, u8 efuseType)
+{
+       u16 ret = 0;
+
+       if (efuseType == EFUSE_WIFI)
+               ret = hal_EfuseGetCurrentSize_WiFi(pAdapter);
+       else
+               ret = hal_EfuseGetCurrentSize_BT(pAdapter);
+
+       return ret;
+}
+
+static u8
+Hal_EfuseWordEnableDataWrite(struct rtw_adapter *padapter,
+                            u16 efuse_addr, u8 word_en, u8 *data)
+{
+       u16 tmpaddr = 0;
+       u16 start_addr = efuse_addr;
+       u8 badworden = 0x0F;
+       u8 tmpdata[PGPKT_DATA_SIZE];
+
+       memset(tmpdata, 0xFF, PGPKT_DATA_SIZE);
+
+       if (!(word_en & BIT(0))) {
+               tmpaddr = start_addr;
+               efuse_OneByteWrite23a(padapter, start_addr++, data[0]);
+               efuse_OneByteWrite23a(padapter, start_addr++, data[1]);
+
+               efuse_OneByteRead23a(padapter, tmpaddr, &tmpdata[0]);
+               efuse_OneByteRead23a(padapter, tmpaddr + 1, &tmpdata[1]);
+               if ((data[0] != tmpdata[0]) || (data[1] != tmpdata[1])) {
+                       badworden &= (~BIT(0));
+               }
+       }
+       if (!(word_en & BIT(1))) {
+               tmpaddr = start_addr;
+               efuse_OneByteWrite23a(padapter, start_addr++, data[2]);
+               efuse_OneByteWrite23a(padapter, start_addr++, data[3]);
+
+               efuse_OneByteRead23a(padapter, tmpaddr, &tmpdata[2]);
+               efuse_OneByteRead23a(padapter, tmpaddr + 1, &tmpdata[3]);
+               if ((data[2] != tmpdata[2]) || (data[3] != tmpdata[3])) {
+                       badworden &= (~BIT(1));
+               }
+       }
+       if (!(word_en & BIT(2))) {
+               tmpaddr = start_addr;
+               efuse_OneByteWrite23a(padapter, start_addr++, data[4]);
+               efuse_OneByteWrite23a(padapter, start_addr++, data[5]);
+
+               efuse_OneByteRead23a(padapter, tmpaddr, &tmpdata[4]);
+               efuse_OneByteRead23a(padapter, tmpaddr + 1, &tmpdata[5]);
+               if ((data[4] != tmpdata[4]) || (data[5] != tmpdata[5])) {
+                       badworden &= (~BIT(2));
+               }
+       }
+       if (!(word_en & BIT(3))) {
+               tmpaddr = start_addr;
+               efuse_OneByteWrite23a(padapter, start_addr++, data[6]);
+               efuse_OneByteWrite23a(padapter, start_addr++, data[7]);
+
+               efuse_OneByteRead23a(padapter, tmpaddr, &tmpdata[6]);
+               efuse_OneByteRead23a(padapter, tmpaddr + 1, &tmpdata[7]);
+               if ((data[6] != tmpdata[6]) || (data[7] != tmpdata[7])) {
+                       badworden &= (~BIT(3));
+               }
+       }
+
+       return badworden;
+}
+
+static s32
+Hal_EfusePgPacketRead(struct rtw_adapter *padapter, u8 offset, u8 *data)
+{
+       u8 efuse_data, word_cnts = 0;
+       u16 efuse_addr = 0;
+       u8 hoffset = 0, hworden = 0;
+       u8 i;
+       u8 max_section = 0;
+       s32 ret;
+
+       if (data == NULL)
+               return false;
+
+       EFUSE_GetEfuseDefinition23a(padapter, EFUSE_WIFI, TYPE_EFUSE_MAX_SECTION,
+                                &max_section);
+       if (offset > max_section) {
+               DBG_8723A("%s: Packet offset(%d) is illegal(>%d)!\n",
+                         __func__, offset, max_section);
+               return false;
+       }
+
+       memset(data, 0xFF, PGPKT_DATA_SIZE);
+       ret = true;
+
+       /*  */
+       /*  <Roger_TODO> Efuse has been pre-programmed dummy 5Bytes at the
+           end of Efuse by CP. */
+       /*  Skip dummy parts to prevent unexpected data read from Efuse. */
+       /*  By pass right now. 2009.02.19. */
+       /*  */
+       while (AVAILABLE_EFUSE_ADDR(efuse_addr)) {
+               if (efuse_OneByteRead23a(padapter, efuse_addr++, &efuse_data) ==
+                   false) {
+                       ret = false;
+                       break;
+               }
+
+               if (efuse_data == 0xFF)
+                       break;
+
+               if (EXT_HEADER(efuse_data)) {
+                       hoffset = GET_HDR_OFFSET_2_0(efuse_data);
+                       efuse_OneByteRead23a(padapter, efuse_addr++, &efuse_data);
+                       if (ALL_WORDS_DISABLED(efuse_data)) {
+                               DBG_8723A("%s: Error!! All words disabled!\n",
+                                         __func__);
+                               continue;
+                       }
+
+                       hoffset |= ((efuse_data & 0xF0) >> 1);
+                       hworden = efuse_data & 0x0F;
+               } else {
+                       hoffset = (efuse_data >> 4) & 0x0F;
+                       hworden = efuse_data & 0x0F;
+               }
+
+               if (hoffset == offset) {
+                       for (i = 0; i < EFUSE_MAX_WORD_UNIT; i++) {
+                               /* Check word enable condition in the section */
+                               if (!(hworden & (0x01 << i))) {
+                                       ReadEFuseByte23a(padapter, efuse_addr++,
+                                                     &efuse_data);
+                                       data[i * 2] = efuse_data;
+
+                                       ReadEFuseByte23a(padapter, efuse_addr++,
+                                                     &efuse_data);
+                                       data[(i * 2) + 1] = efuse_data;
+                               }
+                       }
+               } else {
+                       word_cnts = Efuse_CalculateWordCnts23a(hworden);
+                       efuse_addr += word_cnts * 2;
+               }
+       }
+
+       return ret;
+}
+
+static u8
+hal_EfusePgCheckAvailableAddr(struct rtw_adapter *pAdapter, u8 efuseType)
+{
+       u16 max_available = 0;
+       u16 current_size;
+
+       EFUSE_GetEfuseDefinition23a(pAdapter, efuseType,
+                                TYPE_AVAILABLE_EFUSE_BYTES_TOTAL,
+                                &max_available);
+
+       current_size = Efuse_GetCurrentSize23a(pAdapter, efuseType);
+       if (current_size >= max_available) {
+               DBG_8723A("%s: Error!! current_size(%d)>max_available(%d)\n",
+                         __func__, current_size, max_available);
+               return false;
+       }
+       return true;
+}
+
+static void
+hal_EfuseConstructPGPkt(u8 offset, u8 word_en, u8 *pData,
+                       struct pg_pkt_struct *pTargetPkt)
+{
+       memset(pTargetPkt->data, 0xFF, PGPKT_DATA_SIZE);
+       pTargetPkt->offset = offset;
+       pTargetPkt->word_en = word_en;
+       efuse_WordEnableDataRead23a(word_en, pData, pTargetPkt->data);
+       pTargetPkt->word_cnts = Efuse_CalculateWordCnts23a(pTargetPkt->word_en);
+}
+
+static u8
+hal_EfusePartialWriteCheck(struct rtw_adapter *padapter, u8 efuseType,
+                          u16 *pAddr, struct pg_pkt_struct *pTargetPkt)
+{
+       u8 bRet = false;
+       u16 startAddr = 0, efuse_max_available_len = 0, efuse_max = 0;
+       u8 efuse_data = 0;
+
+       EFUSE_GetEfuseDefinition23a(padapter, efuseType,
+                                TYPE_AVAILABLE_EFUSE_BYTES_TOTAL,
+                                &efuse_max_available_len);
+       EFUSE_GetEfuseDefinition23a(padapter, efuseType,
+                                TYPE_EFUSE_CONTENT_LEN_BANK, &efuse_max);
+
+       if (efuseType == EFUSE_WIFI) {
+               rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BYTES,
+                                 (u8 *) &startAddr);
+       } else {
+               rtw23a_hal_get_hwreg(padapter, HW_VAR_EFUSE_BT_BYTES,
+                                 (u8 *) &startAddr);
+       }
+       startAddr %= efuse_max;
+
+       while (1) {
+               if (startAddr >= efuse_max_available_len) {
+                       bRet = false;
+                       DBG_8723A("%s: startAddr(%d) >= efuse_max_available_"
+                                 "len(%d)\n", __func__, startAddr,
+                                 efuse_max_available_len);
+                       break;
+               }
+
+               if (efuse_OneByteRead23a(padapter, startAddr, &efuse_data) &&
+                   (efuse_data != 0xFF)) {
+                       bRet = false;
+                       DBG_8723A("%s: Something Wrong! last bytes(%#X = 0x%02X) "
+                                 "is not 0xFF\n", __func__,
+                                 startAddr, efuse_data);
+                       break;
+               } else {
+                       /*  not used header, 0xff */
+                       *pAddr = startAddr;
+                       bRet = true;
+                       break;
+               }
+       }
+
+       return bRet;
+}
+
+static u8
+hal_EfusePgPacketWrite1ByteHeader(struct rtw_adapter *pAdapter, u8 efuseType,
+                                 u16 *pAddr, struct pg_pkt_struct *pTargetPkt)
+{
+       u8 pg_header = 0, tmp_header = 0;
+       u16 efuse_addr = *pAddr;
+       u8 repeatcnt = 0;
+
+       pg_header = ((pTargetPkt->offset << 4) & 0xf0) | pTargetPkt->word_en;
+
+       do {
+               efuse_OneByteWrite23a(pAdapter, efuse_addr, pg_header);
+               efuse_OneByteRead23a(pAdapter, efuse_addr, &tmp_header);
+               if (tmp_header != 0xFF)
+                       break;
+               if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+                       DBG_8723A("%s: Repeat over limit for pg_header!!\n",
+                                 __func__);
+                       return false;
+               }
+       } while (1);
+
+       if (tmp_header != pg_header) {
+               DBG_8723A(KERN_ERR "%s: PG Header Fail!!(pg = 0x%02X "
+                         "read = 0x%02X)\n", __func__,
+                         pg_header, tmp_header);
+               return false;
+       }
+
+       *pAddr = efuse_addr;
+
+       return true;
+}
+
+static u8
+hal_EfusePgPacketWrite2ByteHeader(struct rtw_adapter *padapter, u8 efuseType,
+                                 u16 *pAddr, struct pg_pkt_struct *pTargetPkt)
+{
+       u16 efuse_addr, efuse_max_available_len = 0;
+       u8 pg_header = 0, tmp_header = 0;
+       u8 repeatcnt = 0;
+
+       EFUSE_GetEfuseDefinition23a(padapter, efuseType,
+                                TYPE_AVAILABLE_EFUSE_BYTES_BANK,
+                                &efuse_max_available_len);
+
+       efuse_addr = *pAddr;
+       if (efuse_addr >= efuse_max_available_len) {
+               DBG_8723A("%s: addr(%d) over avaliable(%d)!!\n", __func__,
+                         efuse_addr, efuse_max_available_len);
+               return false;
+       }
+
+       pg_header = ((pTargetPkt->offset & 0x07) << 5) | 0x0F;
+
+       do {
+               efuse_OneByteWrite23a(padapter, efuse_addr, pg_header);
+               efuse_OneByteRead23a(padapter, efuse_addr, &tmp_header);
+               if (tmp_header != 0xFF)
+                       break;
+               if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+                       DBG_8723A("%s: Repeat over limit for pg_header!!\n",
+                                 __func__);
+                       return false;
+               }
+       } while (1);
+
+       if (tmp_header != pg_header) {
+               DBG_8723A(KERN_ERR
+                         "%s: PG Header Fail!!(pg = 0x%02X read = 0x%02X)\n",
+                         __func__, pg_header, tmp_header);
+               return false;
+       }
+
+       /*  to write ext_header */
+       efuse_addr++;
+       pg_header = ((pTargetPkt->offset & 0x78) << 1) | pTargetPkt->word_en;
+
+       do {
+               efuse_OneByteWrite23a(padapter, efuse_addr, pg_header);
+               efuse_OneByteRead23a(padapter, efuse_addr, &tmp_header);
+               if (tmp_header != 0xFF)
+                       break;
+               if (repeatcnt++ > EFUSE_REPEAT_THRESHOLD_) {
+                       DBG_8723A("%s: Repeat over limit for ext_header!!\n",
+                                 __func__);
+                       return false;
+               }
+       } while (1);
+
+       if (tmp_header != pg_header) {  /* offset PG fail */
+               DBG_8723A(KERN_ERR
+                         "%s: PG EXT Header Fail!!(pg = 0x%02X read = 0x%02X)\n",
+                         __func__, pg_header, tmp_header);
+               return false;
+       }
+
+       *pAddr = efuse_addr;
+
+       return true;
+}
+
+static u8
+hal_EfusePgPacketWriteHeader(struct rtw_adapter *padapter, u8 efuseType,
+                            u16 *pAddr, struct pg_pkt_struct *pTargetPkt)
+{
+       u8 bRet = false;
+
+       if (pTargetPkt->offset >= EFUSE_MAX_SECTION_BASE) {
+               bRet = hal_EfusePgPacketWrite2ByteHeader(padapter, efuseType,
+                                                        pAddr, pTargetPkt);
+       } else {
+               bRet = hal_EfusePgPacketWrite1ByteHeader(padapter, efuseType,
+                                                        pAddr, pTargetPkt);
+       }
+
+       return bRet;
+}
+
+static u8
+hal_EfusePgPacketWriteData(struct rtw_adapter *pAdapter, u8 efuseType,
+                          u16 *pAddr, struct pg_pkt_struct *pTargetPkt)
+{
+       u16 efuse_addr;
+       u8 badworden;
+
+       efuse_addr = *pAddr;
+       badworden =
+           Efuse_WordEnableDataWrite23a(pAdapter, efuse_addr + 1,
+                                     pTargetPkt->word_en, pTargetPkt->data);
+       if (badworden != 0x0F) {
+               DBG_8723A("%s: Fail!!\n", __func__);
+               return false;
+       }
+
+       return true;
+}
+
+static s32
+Hal_EfusePgPacketWrite(struct rtw_adapter *padapter,
+                      u8 offset, u8 word_en, u8 *pData)
+{
+       struct pg_pkt_struct targetPkt;
+       u16 startAddr = 0;
+       u8 efuseType = EFUSE_WIFI;
+
+       if (!hal_EfusePgCheckAvailableAddr(padapter, efuseType))
+               return false;
+
+       hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt);
+
+       if (!hal_EfusePartialWriteCheck(padapter, efuseType,
+                                       &startAddr, &targetPkt))
+               return false;
+
+       if (!hal_EfusePgPacketWriteHeader(padapter, efuseType,
+                                         &startAddr, &targetPkt))
+               return false;
+
+       if (!hal_EfusePgPacketWriteData(padapter, efuseType,
+                                       &startAddr, &targetPkt))
+               return false;
+
+       return true;
+}
+
+static bool
+Hal_EfusePgPacketWrite_BT(struct rtw_adapter *pAdapter,
+                         u8 offset, u8 word_en, u8 *pData)
+{
+       struct pg_pkt_struct targetPkt;
+       u16 startAddr = 0;
+       u8 efuseType = EFUSE_BT;
+
+       if (!hal_EfusePgCheckAvailableAddr(pAdapter, efuseType))
+               return false;
+
+       hal_EfuseConstructPGPkt(offset, word_en, pData, &targetPkt);
+
+       if (!hal_EfusePartialWriteCheck(pAdapter, efuseType,
+                                       &startAddr, &targetPkt))
+               return false;
+
+       if (!hal_EfusePgPacketWriteHeader(pAdapter, efuseType,
+                                         &startAddr, &targetPkt))
+               return false;
+
+       if (!hal_EfusePgPacketWriteData(pAdapter, efuseType,
+                                       &startAddr, &targetPkt))
+               return false;
+
+       return true;
+}
+
+static struct hal_version ReadChipVersion8723A(struct rtw_adapter *padapter)
+{
+       u32 value32;
+       struct hal_version ChipVersion;
+       struct hal_data_8723a *pHalData;
+
+       pHalData = GET_HAL_DATA(padapter);
+
+       value32 = rtw_read32(padapter, REG_SYS_CFG);
+       ChipVersion.ICType = CHIP_8723A;
+       ChipVersion.ChipType = ((value32 & RTL_ID) ? TEST_CHIP : NORMAL_CHIP);
+       ChipVersion.RFType = RF_TYPE_1T1R;
+       ChipVersion.VendorType =
+               ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : CHIP_VENDOR_TSMC);
+       ChipVersion.CUTVersion = (value32 & CHIP_VER_RTL_MASK) >> CHIP_VER_RTL_SHIFT;   /*  IC version (CUT) */
+
+       /*  For regulator mode. by tynli. 2011.01.14 */
+       pHalData->RegulatorMode = ((value32 & SPS_SEL) ?
+                                  RT_LDO_REGULATOR : RT_SWITCHING_REGULATOR);
+
+       value32 = rtw_read32(padapter, REG_GPIO_OUTSTS);
+       /*  ROM code version. */
+       ChipVersion.ROMVer = ((value32 & RF_RL_ID) >> 20);
+
+       /*  For multi-function consideration. Added by Roger, 2010.10.06. */
+       pHalData->MultiFunc = RT_MULTI_FUNC_NONE;
+       value32 = rtw_read32(padapter, REG_MULTI_FUNC_CTRL);
+       pHalData->MultiFunc |=
+               ((value32 & WL_FUNC_EN) ? RT_MULTI_FUNC_WIFI : 0);
+       pHalData->MultiFunc |= ((value32 & BT_FUNC_EN) ? RT_MULTI_FUNC_BT : 0);
+       pHalData->MultiFunc |=
+               ((value32 & GPS_FUNC_EN) ? RT_MULTI_FUNC_GPS : 0);
+       pHalData->PolarityCtl =
+               ((value32 & WL_HWPDN_SL) ? RT_POLARITY_HIGH_ACT :
+                RT_POLARITY_LOW_ACT);
+       dump_chip_info23a(ChipVersion);
+       pHalData->VersionID = ChipVersion;
+
+       if (IS_1T2R(ChipVersion))
+               pHalData->rf_type = RF_1T2R;
+       else if (IS_2T2R(ChipVersion))
+               pHalData->rf_type = RF_2T2R;
+       else
+               pHalData->rf_type = RF_1T1R;
+
+       MSG_8723A("RF_Type is %x!!\n", pHalData->rf_type);
+
+       return ChipVersion;
+}
+
+static void rtl8723a_read_chip_version(struct rtw_adapter *padapter)
+{
+       ReadChipVersion8723A(padapter);
+}
+
+/*  */
+/*  */
+/*  20100209 Joseph: */
+/*  This function is used only for 92C to set REG_BCN_CTRL(0x550) register. */
+/*  We just reserve the value of the register in variable
+    pHalData->RegBcnCtrlVal and then operate */
+/*  the value of the register via atomic operation. */
+/*  This prevents from race condition when setting this register. */
+/*  The value of pHalData->RegBcnCtrlVal is initialized in
+    HwConfigureRTL8192CE() function. */
+/*  */
+void SetBcnCtrlReg23a(struct rtw_adapter *padapter, u8 SetBits, u8 ClearBits)
+{
+       struct hal_data_8723a *pHalData;
+       u32 addr;
+       u8 *pRegBcnCtrlVal;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pRegBcnCtrlVal = (u8 *)&pHalData->RegBcnCtrlVal;
+
+       addr = REG_BCN_CTRL;
+
+       *pRegBcnCtrlVal = rtw_read8(padapter, addr);
+       *pRegBcnCtrlVal |= SetBits;
+       *pRegBcnCtrlVal &= ~ClearBits;
+
+       rtw_write8(padapter, addr, *pRegBcnCtrlVal);
+}
+
+void rtl8723a_InitBeaconParameters(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       rtw_write16(padapter, REG_BCN_CTRL, 0x1010);
+       pHalData->RegBcnCtrlVal = 0x1010;
+
+       /*  TODO: Remove these magic number */
+       rtw_write16(padapter, REG_TBTT_PROHIBIT, 0x6404);       /*  ms */
+       /*  Firmware will control REG_DRVERLYINT when power saving is enable, */
+       /*  so don't set this register on STA mode. */
+       if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == false)
+               rtw_write8(padapter, REG_DRVERLYINT, DRIVER_EARLY_INT_TIME);
+       /*  2ms */
+       rtw_write8(padapter, REG_BCNDMATIM, BCN_DMA_ATIME_INT_TIME);
+
+       /*  Suggested by designer timchen. Change beacon AIFS to the
+           largest number beacause test chip does not contension before
+           sending beacon. by tynli. 2009.11.03 */
+       rtw_write16(padapter, REG_BCNTCFG, 0x660F);
+}
+
+static void ResumeTxBeacon(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       /*  2010.03.01. Marked by tynli. No need to call workitem beacause
+           we record the value */
+       /*  which should be read from register to a global variable. */
+
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+ResumeTxBeacon\n"));
+
+       pHalData->RegFwHwTxQCtrl |= BIT(6);
+       rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2, pHalData->RegFwHwTxQCtrl);
+       rtw_write8(padapter, REG_TBTT_PROHIBIT + 1, 0xff);
+       pHalData->RegReg542 |= BIT(0);
+       rtw_write8(padapter, REG_TBTT_PROHIBIT + 2, pHalData->RegReg542);
+}
+
+static void StopTxBeacon(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       /*  2010.03.01. Marked by tynli. No need to call workitem beacause
+           we record the value */
+       /*  which should be read from register to a global variable. */
+
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("+StopTxBeacon\n"));
+
+       pHalData->RegFwHwTxQCtrl &= ~BIT(6);
+       rtw_write8(padapter, REG_FWHW_TXQ_CTRL + 2, pHalData->RegFwHwTxQCtrl);
+       rtw_write8(padapter, REG_TBTT_PROHIBIT + 1, 0x64);
+       pHalData->RegReg542 &= ~BIT(0);
+       rtw_write8(padapter, REG_TBTT_PROHIBIT + 2, pHalData->RegReg542);
+
+       CheckFwRsvdPageContent23a(padapter); /*  2010.06.23. Added by tynli. */
+}
+
+static void _BeaconFunctionEnable(struct rtw_adapter *padapter, u8 Enable,
+                                 u8 Linked)
+{
+       SetBcnCtrlReg23a(padapter, DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_BCNQ_SUB,
+                     0);
+       rtw_write8(padapter, REG_RD_CTRL + 1, 0x6F);
+}
+
+static void rtl8723a_SetBeaconRelatedRegisters(struct rtw_adapter *padapter)
+{
+       u32 value32;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       /* reset TSF, enable update TSF, correcting TSF On Beacon */
+
+       /* REG_BCN_INTERVAL */
+       /* REG_BCNDMATIM */
+       /* REG_ATIMWND */
+       /* REG_TBTT_PROHIBIT */
+       /* REG_DRVERLYINT */
+       /* REG_BCN_MAX_ERR */
+       /* REG_BCNTCFG (0x510) */
+       /* REG_DUAL_TSF_RST */
+       /* REG_BCN_CTRL (0x550) */
+
+       /*  */
+       /*  ATIM window */
+       /*  */
+       rtw_write16(padapter, REG_ATIMWND, 2);
+
+       /*  */
+       /*  Beacon interval (in unit of TU). */
+       /*  */
+       rtw_write16(padapter, REG_BCN_INTERVAL, pmlmeinfo->bcn_interval);
+
+       rtl8723a_InitBeaconParameters(padapter);
+
+       rtw_write8(padapter, REG_SLOT, 0x09);
+
+       /*  */
+       /*  Reset TSF Timer to zero, added by Roger. 2008.06.24 */
+       /*  */
+       value32 = rtw_read32(padapter, REG_TCR);
+       value32 &= ~TSFRST;
+       rtw_write32(padapter, REG_TCR, value32);
+
+       value32 |= TSFRST;
+       rtw_write32(padapter, REG_TCR, value32);
+
+       /*  NOTE: Fix test chip's bug (about contention windows's randomness) */
+       if (check_fwstate(&padapter->mlmepriv, WIFI_ADHOC_STATE |
+                         WIFI_ADHOC_MASTER_STATE | WIFI_AP_STATE) == true) {
+               rtw_write8(padapter, REG_RXTSF_OFFSET_CCK, 0x50);
+               rtw_write8(padapter, REG_RXTSF_OFFSET_OFDM, 0x50);
+       }
+
+       _BeaconFunctionEnable(padapter, true, true);
+
+       ResumeTxBeacon(padapter);
+       SetBcnCtrlReg23a(padapter, DIS_BCNQ_SUB, 0);
+}
+
+static void rtl8723a_GetHalODMVar(struct rtw_adapter *Adapter,
+                                 enum hal_odm_variable eVariable,
+                                 void *pValue1, bool bSet)
+{
+       switch (eVariable) {
+       case HAL_ODM_STA_INFO:
+               break;
+       default:
+               break;
+       }
+}
+
+static void rtl8723a_SetHalODMVar(struct rtw_adapter *Adapter,
+                                 enum hal_odm_variable eVariable,
+                                 void *pValue1, bool bSet)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_odm_t *podmpriv = &pHalData->odmpriv;
+       switch (eVariable) {
+       case HAL_ODM_STA_INFO:
+       {
+               struct sta_info *psta = (struct sta_info *)pValue1;
+
+               if (bSet) {
+                       DBG_8723A("Set STA_(%d) info\n", psta->mac_id);
+                       ODM_CmnInfoPtrArrayHook23a(podmpriv,
+                                               ODM_CMNINFO_STA_STATUS,
+                                               psta->mac_id, psta);
+               } else {
+                       DBG_8723A("Clean STA_(%d) info\n", psta->mac_id);
+                               ODM_CmnInfoPtrArrayHook23a(podmpriv,
+                                                       ODM_CMNINFO_STA_STATUS,
+                                                       psta->mac_id, NULL);
+               }
+       }
+               break;
+       case HAL_ODM_P2P_STATE:
+               ODM_CmnInfoUpdate23a(podmpriv, ODM_CMNINFO_WIFI_DIRECT, bSet);
+               break;
+       case HAL_ODM_WIFI_DISPLAY_STATE:
+               ODM_CmnInfoUpdate23a(podmpriv, ODM_CMNINFO_WIFI_DISPLAY, bSet);
+               break;
+       default:
+               break;
+       }
+}
+
+static void hal_notch_filter_8723a(struct rtw_adapter *adapter, bool enable)
+{
+       if (enable) {
+               DBG_8723A("Enable notch filter\n");
+               rtw_write8(adapter, rOFDM0_RxDSP + 1,
+                          rtw_read8(adapter, rOFDM0_RxDSP + 1) | BIT1);
+       } else {
+               DBG_8723A("Disable notch filter\n");
+               rtw_write8(adapter, rOFDM0_RxDSP + 1,
+                          rtw_read8(adapter, rOFDM0_RxDSP + 1) & ~BIT1);
+       }
+}
+
+s32 c2h_id_filter_ccx_8723a(u8 id)
+{
+       s32 ret = false;
+       if (id == C2H_CCX_TX_RPT)
+               ret = true;
+
+       return ret;
+}
+
+static s32 c2h_handler_8723a(struct rtw_adapter *padapter,
+                            struct c2h_evt_hdr *c2h_evt)
+{
+       s32 ret = _SUCCESS;
+       u8 i = 0;
+
+       if (c2h_evt == NULL) {
+               DBG_8723A("%s c2h_evt is NULL\n", __func__);
+               ret = _FAIL;
+               goto exit;
+       }
+
+       switch (c2h_evt->id) {
+       case C2H_DBG:
+               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                        ("C2HCommandHandler: %s\n", c2h_evt->payload));
+               break;
+
+       case C2H_CCX_TX_RPT:
+               handle_txrpt_ccx_8723a(padapter, c2h_evt->payload);
+               break;
+       case C2H_EXT_RA_RPT:
+               break;
+       case C2H_HW_INFO_EXCH:
+               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                        ("[BT], C2H_HW_INFO_EXCH\n"));
+               for (i = 0; i < c2h_evt->plen; i++) {
+                       RT_TRACE(_module_hal_init_c_, _drv_info_,
+                                ("[BT], tmpBuf[%d]= 0x%x\n", i,
+                                 c2h_evt->payload[i]));
+               }
+               break;
+
+       case C2H_C2H_H2C_TEST:
+               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                        ("[BT], C2H_H2C_TEST\n"));
+               RT_TRACE(_module_hal_init_c_, _drv_info_,
+                        ("[BT], tmpBuf[0]/[1]/[2]/[3]/[4]= 0x%x/ 0x%x/ "
+                         "0x%x/ 0x%x/ 0x%x\n", c2h_evt->payload[0],
+                         c2h_evt->payload[1], c2h_evt->payload[2],
+                         c2h_evt->payload[3], c2h_evt->payload[4]));
+               break;
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       case C2H_BT_INFO:
+               DBG_8723A("%s ,  Got  C2H_BT_INFO \n", __func__);
+               BT_FwC2hBtInfo(padapter, c2h_evt->payload, c2h_evt->plen);
+               break;
+#endif
+
+       default:
+               ret = _FAIL;
+               break;
+       }
+
+exit:
+       return ret;
+}
+
+void rtl8723a_set_hal_ops(struct hal_ops *pHalFunc)
+{
+       pHalFunc->free_hal_data = &rtl8723a_free_hal_data;
+
+       pHalFunc->dm_init = &rtl8723a_init_dm_priv;
+       pHalFunc->dm_deinit = &rtl8723a_deinit_dm_priv;
+
+       pHalFunc->read_chip_version = &rtl8723a_read_chip_version;
+
+       pHalFunc->set_bwmode_handler = &PHY_SetBWMode23a8723A;
+       pHalFunc->set_channel_handler = &PHY_SwChnl8723A;
+
+       pHalFunc->hal_dm_watchdog = &rtl8723a_HalDmWatchDog;
+
+       pHalFunc->SetBeaconRelatedRegistersHandler =
+               &rtl8723a_SetBeaconRelatedRegisters;
+
+       pHalFunc->Add_RateATid = &rtl8723a_add_rateatid;
+       pHalFunc->run_thread = &rtl8723a_start_thread;
+       pHalFunc->cancel_thread = &rtl8723a_stop_thread;
+
+       pHalFunc->read_bbreg = &PHY_QueryBBReg;
+       pHalFunc->write_bbreg = &PHY_SetBBReg;
+       pHalFunc->read_rfreg = &PHY_QueryRFReg;
+       pHalFunc->write_rfreg = &PHY_SetRFReg;
+
+       /*  Efuse related function */
+       pHalFunc->EfusePowerSwitch = &Hal_EfusePowerSwitch;
+       pHalFunc->ReadEFuse = &Hal_ReadEFuse;
+       pHalFunc->EFUSEGetEfuseDefinition = &Hal_GetEfuseDefinition;
+       pHalFunc->EfuseGetCurrentSize = &Hal_EfuseGetCurrentSize;
+       pHalFunc->Efuse_PgPacketRead23a = &Hal_EfusePgPacketRead;
+       pHalFunc->Efuse_PgPacketWrite23a = &Hal_EfusePgPacketWrite;
+       pHalFunc->Efuse_WordEnableDataWrite23a = &Hal_EfuseWordEnableDataWrite;
+       pHalFunc->Efuse_PgPacketWrite23a_BT = &Hal_EfusePgPacketWrite_BT;
+
+       pHalFunc->sreset_init_value23a = &sreset_init_value23a;
+       pHalFunc->sreset_reset_value23a = &sreset_reset_value23a;
+       pHalFunc->silentreset = &sreset_reset;
+       pHalFunc->sreset_xmit_status_check = &rtl8723a_sreset_xmit_status_check;
+       pHalFunc->sreset_linked_status_check =
+               &rtl8723a_sreset_linked_status_check;
+       pHalFunc->sreset_get_wifi_status23a = &sreset_get_wifi_status23a;
+       pHalFunc->sreset_inprogress = &sreset_inprogress;
+       pHalFunc->GetHalODMVarHandler = &rtl8723a_GetHalODMVar;
+       pHalFunc->SetHalODMVarHandler = &rtl8723a_SetHalODMVar;
+
+       pHalFunc->hal_notch_filter = &hal_notch_filter_8723a;
+
+       pHalFunc->c2h_handler = c2h_handler_8723a;
+       pHalFunc->c2h_id_filter_ccx = c2h_id_filter_ccx_8723a;
+}
+
+void rtl8723a_InitAntenna_Selection(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       u8 val;
+
+       pHalData = GET_HAL_DATA(padapter);
+
+       val = rtw_read8(padapter, REG_LEDCFG2);
+       /*  Let 8051 take control antenna settting */
+       val |= BIT(7);          /*  DPDT_SEL_EN, 0x4C[23] */
+       rtw_write8(padapter, REG_LEDCFG2, val);
+}
+
+void rtl8723a_CheckAntenna_Selection(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       u8 val;
+
+       pHalData = GET_HAL_DATA(padapter);
+
+       val = rtw_read8(padapter, REG_LEDCFG2);
+       /*  Let 8051 take control antenna settting */
+       if (!(val & BIT(7))) {
+               val |= BIT(7);  /*  DPDT_SEL_EN, 0x4C[23] */
+               rtw_write8(padapter, REG_LEDCFG2, val);
+       }
+}
+
+void rtl8723a_DeinitAntenna_Selection(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       u8 val;
+
+       pHalData = GET_HAL_DATA(padapter);
+       val = rtw_read8(padapter, REG_LEDCFG2);
+       /*  Let 8051 take control antenna settting */
+       val &= ~BIT(7);         /*  DPDT_SEL_EN, clear 0x4C[23] */
+       rtw_write8(padapter, REG_LEDCFG2, val);
+}
+
+void rtl8723a_init_default_value(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct dm_priv *pdmpriv;
+       u8 i;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pdmpriv = &pHalData->dmpriv;
+
+       /*  init default value */
+       pHalData->fw_ractrl = false;
+       pHalData->bIQKInitialized = false;
+       if (!padapter->pwrctrlpriv.bkeepfwalive)
+               pHalData->LastHMEBoxNum = 0;
+
+       pHalData->bIQKInitialized = false;
+
+       /*  init dm default value */
+       pdmpriv->TM_Trigger = 0;        /* for IQK */
+/*     pdmpriv->binitialized = false; */
+/*     pdmpriv->prv_traffic_idx = 3; */
+/*     pdmpriv->initialize = 0; */
+
+       pdmpriv->ThermalValue_HP_index = 0;
+       for (i = 0; i < HP_THERMAL_NUM; i++)
+               pdmpriv->ThermalValue_HP[i] = 0;
+
+       /*  init Efuse variables */
+       pHalData->EfuseUsedBytes = 0;
+       pHalData->BTEfuseUsedBytes = 0;
+}
+
+u8 GetEEPROMSize8723A(struct rtw_adapter *padapter)
+{
+       u8 size = 0;
+       u32 cr;
+
+       cr = rtw_read16(padapter, REG_9346CR);
+       /*  6: EEPROM used is 93C46, 4: boot from E-Fuse. */
+       size = (cr & BOOT_FROM_EEPROM) ? 6 : 4;
+
+       MSG_8723A("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46");
+
+       return size;
+}
+
+/*  */
+/*  */
+/*  LLT R/W/Init function */
+/*  */
+/*  */
+static s32 _LLTWrite(struct rtw_adapter *padapter, u32 address, u32 data)
+{
+       s32 status = _SUCCESS;
+       s32 count = 0;
+       u32 value = _LLT_INIT_ADDR(address) | _LLT_INIT_DATA(data) |
+                   _LLT_OP(_LLT_WRITE_ACCESS);
+       u16 LLTReg = REG_LLT_INIT;
+
+       rtw_write32(padapter, LLTReg, value);
+
+       /* polling */
+       do {
+               value = rtw_read32(padapter, LLTReg);
+               if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value)) {
+                       break;
+               }
+
+               if (count > POLLING_LLT_THRESHOLD) {
+                       RT_TRACE(_module_hal_init_c_, _drv_err_,
+                                ("Failed to polling write LLT done at "
+                                 "address %d!\n", address));
+                       status = _FAIL;
+                       break;
+               }
+       } while (count++);
+
+       return status;
+}
+
+s32 InitLLTTable23a(struct rtw_adapter *padapter, u32 boundary)
+{
+       s32 status = _SUCCESS;
+       u32 i;
+       u32 txpktbuf_bndy = boundary;
+       u32 Last_Entry_Of_TxPktBuf = LAST_ENTRY_OF_TX_PKT_BUFFER;
+
+       for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+               status = _LLTWrite(padapter, i, i + 1);
+               if (_SUCCESS != status) {
+                       return status;
+               }
+       }
+
+       /*  end of list */
+       status = _LLTWrite(padapter, (txpktbuf_bndy - 1), 0xFF);
+       if (_SUCCESS != status) {
+               return status;
+       }
+
+       /*  Make the other pages as ring buffer */
+       /*  This ring buffer is used as beacon buffer if we config this
+           MAC as two MAC transfer. */
+       /*  Otherwise used as local loopback buffer. */
+       for (i = txpktbuf_bndy; i < Last_Entry_Of_TxPktBuf; i++) {
+               status = _LLTWrite(padapter, i, (i + 1));
+               if (_SUCCESS != status) {
+                       return status;
+               }
+       }
+
+       /*  Let last entry point to the start entry of ring buffer */
+       status = _LLTWrite(padapter, Last_Entry_Of_TxPktBuf, txpktbuf_bndy);
+       if (_SUCCESS != status) {
+               return status;
+       }
+
+       return status;
+}
+
+static void _DisableGPIO(struct rtw_adapter *padapter)
+{
+/***************************************
+j. GPIO_PIN_CTRL 0x44[31:0]= 0x000
+k.Value = GPIO_PIN_CTRL[7:0]
+l. GPIO_PIN_CTRL 0x44[31:0] = 0x00FF0000 | (value <<8); write external PIN level
+m. GPIO_MUXCFG 0x42 [15:0] = 0x0780
+n. LEDCFG 0x4C[15:0] = 0x8080
+***************************************/
+       u32 value32;
+       u32 u4bTmp;
+
+       /* 1. Disable GPIO[7:0] */
+       rtw_write16(padapter, REG_GPIO_PIN_CTRL + 2, 0x0000);
+       value32 = rtw_read32(padapter, REG_GPIO_PIN_CTRL) & 0xFFFF00FF;
+       u4bTmp = value32 & 0x000000FF;
+       value32 |= ((u4bTmp << 8) | 0x00FF0000);
+       rtw_write32(padapter, REG_GPIO_PIN_CTRL, value32);
+
+       /*  */
+       /*  <Roger_Notes> For RTL8723u multi-function configuration which
+           was autoload from Efuse offset 0x0a and 0x0b, */
+       /*  WLAN HW GPIO[9], GPS HW GPIO[10] and BT HW GPIO[11]. */
+       /*  Added by Roger, 2010.10.07. */
+       /*  */
+       /* 2. Disable GPIO[8] and GPIO[12] */
+
+       /*  Configure all pins as input mode. */
+       rtw_write16(padapter, REG_GPIO_IO_SEL_2, 0x0000);
+       value32 = rtw_read32(padapter, REG_GPIO_PIN_CTRL_2) & 0xFFFF001F;
+       u4bTmp = value32 & 0x0000001F;
+       /*  Set pin 8, 10, 11 and pin 12 to output mode. */
+       value32 |= ((u4bTmp << 8) | 0x001D0000);
+       rtw_write32(padapter, REG_GPIO_PIN_CTRL_2, value32);
+
+       /* 3. Disable LED0 & 1 */
+       rtw_write16(padapter, REG_LEDCFG0, 0x8080);
+}                              /* end of _DisableGPIO() */
+
+static void _DisableRFAFEAndResetBB8192C(struct rtw_adapter *padapter)
+{
+/**************************************
+a.     TXPAUSE 0x522[7:0] = 0xFF               Pause MAC TX queue
+b.     RF path 0 offset 0x00 = 0x00            disable RF
+c.     APSD_CTRL 0x600[7:0] = 0x40
+d.     SYS_FUNC_EN 0x02[7:0] = 0x16            reset BB state machine
+e.     SYS_FUNC_EN 0x02[7:0] = 0x14            reset BB state machine
+***************************************/
+       u8 eRFPath = 0, value8 = 0;
+
+       rtw_write8(padapter, REG_TXPAUSE, 0xFF);
+
+       PHY_SetRFReg(padapter, (enum RF_RADIO_PATH) eRFPath, 0x0, bMaskByte0, 0x0);
+
+       value8 |= APSDOFF;
+       rtw_write8(padapter, REG_APSD_CTRL, value8);    /* 0x40 */
+
+       /*  Set BB reset at first */
+       value8 = 0;
+       value8 |= (FEN_USBD | FEN_USBA | FEN_BB_GLB_RSTn);
+       rtw_write8(padapter, REG_SYS_FUNC_EN, value8);  /* 0x16 */
+
+       /*  Set global reset. */
+       value8 &= ~FEN_BB_GLB_RSTn;
+       rtw_write8(padapter, REG_SYS_FUNC_EN, value8);  /* 0x14 */
+
+       /*  2010/08/12 MH We need to set BB/GLBAL reset to save power
+           for SS mode. */
+
+/*     RT_TRACE(COMP_INIT, DBG_LOUD, ("======> RF off and reset BB.\n")); */
+}
+
+static void _DisableRFAFEAndResetBB(struct rtw_adapter *padapter)
+{
+       _DisableRFAFEAndResetBB8192C(padapter);
+}
+
+static void _ResetDigitalProcedure1_92C(struct rtw_adapter *padapter,
+                                       bool bWithoutHWSM)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (IS_FW_81xxC(padapter) && (pHalData->FirmwareVersion <= 0x20)) {
+       /*****************************
+       f.      MCUFWDL 0x80[7:0]= 0            reset MCU ready status
+       g.      SYS_FUNC_EN 0x02[10]= 0         reset MCU register, (8051 reset)
+       h.      SYS_FUNC_EN 0x02[15-12]= 5      reset MAC register, DCORE
+       i.     SYS_FUNC_EN 0x02[10]= 1          enable MCU register,
+                                               (8051 enable)
+       ******************************/
+               u16 valu16 = 0;
+               rtw_write8(padapter, REG_MCUFWDL, 0);
+
+               valu16 = rtw_read16(padapter, REG_SYS_FUNC_EN);
+               /* reset MCU , 8051 */
+               rtw_write16(padapter, REG_SYS_FUNC_EN, (valu16 & (~FEN_CPUEN)));
+
+               valu16 = rtw_read16(padapter, REG_SYS_FUNC_EN) & 0x0FFF;
+               rtw_write16(padapter, REG_SYS_FUNC_EN,
+                           (valu16 | (FEN_HWPDN | FEN_ELDR))); /* reset MAC */
+
+               valu16 = rtw_read16(padapter, REG_SYS_FUNC_EN);
+               /* enable MCU , 8051 */
+               rtw_write16(padapter, REG_SYS_FUNC_EN, (valu16 | FEN_CPUEN));
+       } else {
+               u8 retry_cnts = 0;
+
+               /*  2010/08/12 MH For USB SS, we can not stop 8051 when we
+                   are trying to enter IPS/HW&SW radio off. For
+                   S3/S4/S5/Disable, we can stop 8051 because */
+               /*  we will init FW when power on again. */
+               /* if (!pDevice->RegUsbSS) */
+               /*  If we want to SS mode, we can not reset 8051. */
+               if (rtw_read8(padapter, REG_MCUFWDL) & BIT1) {
+                       /* IF fw in RAM code, do reset */
+                       if (padapter->bFWReady) {
+                               /*  2010/08/25 MH Accordign to RD alfred's
+                                   suggestion, we need to disable other */
+                               /*  HRCV INT to influence 8051 reset. */
+                               rtw_write8(padapter, REG_FWIMR, 0x20);
+                               /*  2011/02/15 MH According to Alex's
+                                   suggestion, close mask to prevent
+                                   incorrect FW write operation. */
+                               rtw_write8(padapter, REG_FTIMR, 0x00);
+                               rtw_write8(padapter, REG_FSIMR, 0x00);
+
+                               /* 8051 reset by self */
+                               rtw_write8(padapter, REG_HMETFR + 3, 0x20);
+
+                               while ((retry_cnts++ < 100) &&
+                                      (FEN_CPUEN &
+                                       rtw_read16(padapter, REG_SYS_FUNC_EN))) {
+                                       udelay(50);     /* us */
+                               }
+
+                               if (retry_cnts >= 100) {
+                                       /* Reset MAC and Enable 8051 */
+                                       rtw_write8(padapter,
+                                                  REG_SYS_FUNC_EN + 1, 0x50);
+                                       mdelay(10);
+                               }
+                       }
+               }
+               /* Reset MAC and Enable 8051 */
+               rtw_write8(padapter, REG_SYS_FUNC_EN + 1, 0x54);
+               rtw_write8(padapter, REG_MCUFWDL, 0);
+       }
+
+       if (bWithoutHWSM) {
+       /*****************************
+               Without HW auto state machine
+       g.      SYS_CLKR 0x08[15:0] = 0x30A3            disable MAC clock
+       h.      AFE_PLL_CTRL 0x28[7:0] = 0x80           disable AFE PLL
+       i.      AFE_XTAL_CTRL 0x24[15:0] = 0x880F       gated AFE DIG_CLOCK
+       j.      SYS_ISO_CTRL 0x00[7:0] = 0xF9           isolated digital to PON
+       ******************************/
+               /* modify to 0x70A3 by Scott. */
+               rtw_write16(padapter, REG_SYS_CLKR, 0x70A3);
+               rtw_write8(padapter, REG_AFE_PLL_CTRL, 0x80);
+               rtw_write16(padapter, REG_AFE_XTAL_CTRL, 0x880F);
+               rtw_write8(padapter, REG_SYS_ISO_CTRL, 0xF9);
+       } else {
+               /*  Disable all RF/BB power */
+               rtw_write8(padapter, REG_RF_CTRL, 0x00);
+       }
+}
+
+static void _ResetDigitalProcedure1(struct rtw_adapter *padapter,
+                                   bool bWithoutHWSM)
+{
+       _ResetDigitalProcedure1_92C(padapter, bWithoutHWSM);
+}
+
+static void _ResetDigitalProcedure2(struct rtw_adapter *padapter)
+{
+/*****************************
+k.     SYS_FUNC_EN 0x03[7:0] = 0x44            disable ELDR runction
+l.     SYS_CLKR 0x08[15:0] = 0x3083            disable ELDR clock
+m.     SYS_ISO_CTRL 0x01[7:0] = 0x83           isolated ELDR to PON
+******************************/
+       /* modify to 0x70a3 by Scott. */
+       rtw_write16(padapter, REG_SYS_CLKR, 0x70a3);
+       /* modify to 0x82 by Scott. */
+       rtw_write8(padapter, REG_SYS_ISO_CTRL + 1, 0x82);
+}
+
+static void _DisableAnalog(struct rtw_adapter *padapter, bool bWithoutHWSM)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u16 value16 = 0;
+       u8 value8 = 0;
+
+       if (bWithoutHWSM) {
+       /*****************************
+       n.      LDOA15_CTRL 0x20[7:0] = 0x04    disable A15 power
+       o.      LDOV12D_CTRL 0x21[7:0] = 0x54   disable digital core power
+       r.      When driver call disable, the ASIC will turn off remaining
+               clock automatically
+       ******************************/
+
+               rtw_write8(padapter, REG_LDOA15_CTRL, 0x04);
+               /* rtw_write8(padapter, REG_LDOV12D_CTRL, 0x54); */
+
+               value8 = rtw_read8(padapter, REG_LDOV12D_CTRL);
+               value8 &= (~LDV12_EN);
+               rtw_write8(padapter, REG_LDOV12D_CTRL, value8);
+/*             RT_TRACE(COMP_INIT, DBG_LOUD,
+               (" REG_LDOV12D_CTRL Reg0x21:0x%02x.\n", value8)); */
+       }
+
+       /*****************************
+       h.      SPS0_CTRL 0x11[7:0] = 0x23              enter PFM mode
+       i.      APS_FSMCO 0x04[15:0] = 0x4802           set USB suspend
+       ******************************/
+       value8 = 0x23;
+       if (IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID))
+               value8 |= BIT3;
+
+       rtw_write8(padapter, REG_SPS0_CTRL, value8);
+
+       if (bWithoutHWSM) {
+               /* value16 |= (APDM_HOST | FSM_HSUS |/PFM_ALDN); */
+               /*  2010/08/31 According to Filen description, we need to
+                   use HW to shut down 8051 automatically. */
+               /*  Becasue suspend operatione need the asistance of 8051
+                   to wait for 3ms. */
+               value16 |= (APDM_HOST | AFSM_HSUS | PFM_ALDN);
+       } else {
+               value16 |= (APDM_HOST | AFSM_HSUS | PFM_ALDN);
+       }
+
+       rtw_write16(padapter, REG_APS_FSMCO, value16);  /* 0x4802 */
+
+       rtw_write8(padapter, REG_RSV_CTRL, 0x0e);
+}
+
+/*  HW Auto state machine */
+s32 CardDisableHWSM(struct rtw_adapter *padapter, u8 resetMCU)
+{
+       int rtStatus = _SUCCESS;
+
+       if (padapter->bSurpriseRemoved) {
+               return rtStatus;
+       }
+       /*  RF Off Sequence ==== */
+       _DisableRFAFEAndResetBB(padapter);
+
+       /*   ==== Reset digital sequence   ====== */
+       _ResetDigitalProcedure1(padapter, false);
+
+       /*   ==== Pull GPIO PIN to balance level and LED control ====== */
+       _DisableGPIO(padapter);
+
+       /*   ==== Disable analog sequence === */
+       _DisableAnalog(padapter, false);
+
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("======> Card disable finished.\n"));
+
+       return rtStatus;
+}
+
+/*  without HW Auto state machine */
+s32 CardDisableWithoutHWSM(struct rtw_adapter *padapter)
+{
+       s32 rtStatus = _SUCCESS;
+
+       /* RT_TRACE(COMP_INIT, DBG_LOUD,
+          ("======> Card Disable Without HWSM .\n")); */
+       if (padapter->bSurpriseRemoved) {
+               return rtStatus;
+       }
+
+       /*  RF Off Sequence ==== */
+       _DisableRFAFEAndResetBB(padapter);
+
+       /*   ==== Reset digital sequence   ====== */
+       _ResetDigitalProcedure1(padapter, true);
+
+       /*   ==== Pull GPIO PIN to balance level and LED control ====== */
+       _DisableGPIO(padapter);
+
+       /*   ==== Reset digital sequence   ====== */
+       _ResetDigitalProcedure2(padapter);
+
+       /*   ==== Disable analog sequence === */
+       _DisableAnalog(padapter, true);
+
+       /* RT_TRACE(COMP_INIT, DBG_LOUD,
+          ("<====== Card Disable Without HWSM .\n")); */
+       return rtStatus;
+}
+
+void Hal_InitPGData(struct rtw_adapter *padapter, u8 *PROMContent)
+{
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+
+       if (false == pEEPROM->bautoload_fail_flag) {    /*  autoload OK. */
+               if (!pEEPROM->EepromOrEfuse) {
+                       /*  Read EFUSE real map to shadow. */
+                       EFUSE_ShadowMapUpdate23a(padapter, EFUSE_WIFI);
+                       memcpy((void *)PROMContent,
+                              (void *)pEEPROM->efuse_eeprom_data,
+                              HWSET_MAX_SIZE);
+               }
+       } else {                /* autoload fail */
+               RT_TRACE(_module_hci_hal_init_c_, _drv_notice_,
+                        ("AutoLoad Fail reported from CR9346!!\n"));
+/*             pHalData->AutoloadFailFlag = true; */
+               /* update to default value 0xFF */
+               if (false == pEEPROM->EepromOrEfuse)
+                       EFUSE_ShadowMapUpdate23a(padapter, EFUSE_WIFI);
+               memcpy((void *)PROMContent, (void *)pEEPROM->efuse_eeprom_data,
+                      HWSET_MAX_SIZE);
+       }
+}
+
+void Hal_EfuseParseIDCode(struct rtw_adapter *padapter, u8 *hwinfo)
+{
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+/*     struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter); */
+       u16 EEPROMId;
+
+       /*  Checl 0x8129 again for making sure autoload status!! */
+       EEPROMId = le16_to_cpu(*((u16 *) hwinfo));
+       if (EEPROMId != RTL_EEPROM_ID) {
+               DBG_8723A("EEPROM ID(%#x) is invalid!!\n", EEPROMId);
+               pEEPROM->bautoload_fail_flag = true;
+       } else {
+               pEEPROM->bautoload_fail_flag = false;
+       }
+
+       RT_TRACE(_module_hal_init_c_, _drv_info_,
+                ("EEPROM ID = 0x%04x\n", EEPROMId));
+}
+
+static void Hal_EEValueCheck(u8 EEType, void *pInValue, void *pOutValue)
+{
+       switch (EEType) {
+       case EETYPE_TX_PWR:
+       {
+               u8 *pIn, *pOut;
+               pIn = (u8 *) pInValue;
+               pOut = (u8 *) pOutValue;
+               if (*pIn >= 0 && *pIn <= 63) {
+                       *pOut = *pIn;
+               } else {
+                       RT_TRACE(_module_hci_hal_init_c_, _drv_err_,
+                                ("EETYPE_TX_PWR, value =%d is invalid, set "
+                                 "to default = 0x%x\n",
+                                 *pIn, EEPROM_Default_TxPowerLevel));
+                       *pOut = EEPROM_Default_TxPowerLevel;
+               }
+       }
+               break;
+       default:
+               break;
+       }
+}
+
+static void
+Hal_ReadPowerValueFromPROM_8723A(struct txpowerinfo *pwrInfo,
+                                u8 *PROMContent, bool AutoLoadFail)
+{
+       u32 rfPath, eeAddr, group, rfPathMax = 1;
+
+       memset(pwrInfo, 0, sizeof(*pwrInfo));
+
+       if (AutoLoadFail) {
+               for (group = 0; group < MAX_CHNL_GROUP; group++) {
+                       for (rfPath = 0; rfPath < rfPathMax; rfPath++) {
+                               pwrInfo->CCKIndex[rfPath][group] =
+                                       EEPROM_Default_TxPowerLevel;
+                               pwrInfo->HT40_1SIndex[rfPath][group] =
+                                       EEPROM_Default_TxPowerLevel;
+                               pwrInfo->HT40_2SIndexDiff[rfPath][group] =
+                                       EEPROM_Default_HT40_2SDiff;
+                               pwrInfo->HT20IndexDiff[rfPath][group] =
+                                       EEPROM_Default_HT20_Diff;
+                               pwrInfo->OFDMIndexDiff[rfPath][group] =
+                                       EEPROM_Default_LegacyHTTxPowerDiff;
+                               pwrInfo->HT40MaxOffset[rfPath][group] =
+                                       EEPROM_Default_HT40_PwrMaxOffset;
+                               pwrInfo->HT20MaxOffset[rfPath][group] =
+                                       EEPROM_Default_HT20_PwrMaxOffset;
+                       }
+               }
+               pwrInfo->TSSI_A[0] = EEPROM_Default_TSSI;
+               return;
+       }
+
+       for (rfPath = 0; rfPath < rfPathMax; rfPath++) {
+               for (group = 0; group < MAX_CHNL_GROUP; group++) {
+                       eeAddr =
+                           EEPROM_CCK_TX_PWR_INX_8723A + (rfPath * 3) + group;
+                       /* pwrInfo->CCKIndex[rfPath][group] =
+                          PROMContent[eeAddr]; */
+                       Hal_EEValueCheck(EETYPE_TX_PWR, &PROMContent[eeAddr],
+                                        &pwrInfo->CCKIndex[rfPath][group]);
+                       eeAddr = EEPROM_HT40_1S_TX_PWR_INX_8723A +
+                               (rfPath * 3) + group;
+                       /* pwrInfo->HT40_1SIndex[rfPath][group] =
+                          PROMContent[eeAddr]; */
+                       Hal_EEValueCheck(EETYPE_TX_PWR, &PROMContent[eeAddr],
+                                        &pwrInfo->HT40_1SIndex[rfPath][group]);
+               }
+       }
+
+       for (group = 0; group < MAX_CHNL_GROUP; group++) {
+               for (rfPath = 0; rfPath < rfPathMax; rfPath++) {
+                       pwrInfo->HT40_2SIndexDiff[rfPath][group] = 0;
+                       pwrInfo->HT20IndexDiff[rfPath][group] =
+                               (PROMContent
+                                [EEPROM_HT20_TX_PWR_INX_DIFF_8723A +
+                                 group] >> (rfPath * 4)) & 0xF;
+                       /* 4bit sign number to 8 bit sign number */
+                       if (pwrInfo->HT20IndexDiff[rfPath][group] & BIT3)
+                               pwrInfo->HT20IndexDiff[rfPath][group] |= 0xF0;
+
+                       pwrInfo->OFDMIndexDiff[rfPath][group] =
+                               (PROMContent[EEPROM_OFDM_TX_PWR_INX_DIFF_8723A +
+                                            group] >> (rfPath * 4)) & 0xF;
+
+                       pwrInfo->HT40MaxOffset[rfPath][group] =
+                               (PROMContent[EEPROM_HT40_MAX_PWR_OFFSET_8723A +
+                                            group] >> (rfPath * 4)) & 0xF;
+
+                       pwrInfo->HT20MaxOffset[rfPath][group] =
+                               (PROMContent[EEPROM_HT20_MAX_PWR_OFFSET_8723A +
+                                            group] >> (rfPath * 4)) & 0xF;
+               }
+       }
+
+       pwrInfo->TSSI_A[0] = PROMContent[EEPROM_TSSI_A_8723A];
+}
+
+static u8 Hal_GetChnlGroup(u8 chnl)
+{
+       u8 group = 0;
+
+       if (chnl < 3)           /*  Cjanel 1-3 */
+               group = 0;
+       else if (chnl < 9)      /*  Channel 4-9 */
+               group = 1;
+       else                    /*  Channel 10-14 */
+               group = 2;
+
+       return group;
+}
+
+void
+Hal_EfuseParsetxpowerinfo_8723A(struct rtw_adapter *padapter,
+                               u8 *PROMContent, bool AutoLoadFail)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct txpowerinfo pwrInfo;
+       u8 rfPath, ch, group, rfPathMax = 1;
+       u8 pwr, diff;
+
+       Hal_ReadPowerValueFromPROM_8723A(&pwrInfo, PROMContent, AutoLoadFail);
+       for (rfPath = 0; rfPath < rfPathMax; rfPath++) {
+               for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) {
+                       group = Hal_GetChnlGroup(ch);
+
+                       pHalData->TxPwrLevelCck[rfPath][ch] =
+                               pwrInfo.CCKIndex[rfPath][group];
+                       pHalData->TxPwrLevelHT40_1S[rfPath][ch] =
+                               pwrInfo.HT40_1SIndex[rfPath][group];
+
+                       pHalData->TxPwrHt20Diff[rfPath][ch] =
+                               pwrInfo.HT20IndexDiff[rfPath][group];
+                       pHalData->TxPwrLegacyHtDiff[rfPath][ch] =
+                               pwrInfo.OFDMIndexDiff[rfPath][group];
+                       pHalData->PwrGroupHT20[rfPath][ch] =
+                               pwrInfo.HT20MaxOffset[rfPath][group];
+                       pHalData->PwrGroupHT40[rfPath][ch] =
+                               pwrInfo.HT40MaxOffset[rfPath][group];
+
+                       pwr = pwrInfo.HT40_1SIndex[rfPath][group];
+                       diff = pwrInfo.HT40_2SIndexDiff[rfPath][group];
+
+                       pHalData->TxPwrLevelHT40_2S[rfPath][ch] =
+                           (pwr > diff) ? (pwr - diff) : 0;
+               }
+       }
+       for (rfPath = 0; rfPath < RF_PATH_MAX; rfPath++) {
+               for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) {
+                       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                                ("RF(%u)-Ch(%u) [CCK / HT40_1S / HT40_2S] = "
+                                 "[0x%x / 0x%x / 0x%x]\n",
+                                 rfPath, ch,
+                                 pHalData->TxPwrLevelCck[rfPath][ch],
+                                 pHalData->TxPwrLevelHT40_1S[rfPath][ch],
+                                 pHalData->TxPwrLevelHT40_2S[rfPath][ch]));
+
+               }
+       }
+       for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) {
+               RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                        ("RF-A Ht20 to HT40 Diff[%u] = 0x%x(%d)\n", ch,
+                         pHalData->TxPwrHt20Diff[RF_PATH_A][ch],
+                         pHalData->TxPwrHt20Diff[RF_PATH_A][ch]));
+       }
+       for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++)
+               RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                        ("RF-A Legacy to Ht40 Diff[%u] = 0x%x\n", ch,
+                         pHalData->TxPwrLegacyHtDiff[RF_PATH_A][ch]));
+       for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++) {
+               RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                        ("RF-B Ht20 to HT40 Diff[%u] = 0x%x(%d)\n", ch,
+                         pHalData->TxPwrHt20Diff[RF_PATH_B][ch],
+                         pHalData->TxPwrHt20Diff[RF_PATH_B][ch]));
+       }
+       for (ch = 0; ch < CHANNEL_MAX_NUMBER; ch++)
+               RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                        ("RF-B Legacy to HT40 Diff[%u] = 0x%x\n", ch,
+                         pHalData->TxPwrLegacyHtDiff[RF_PATH_B][ch]));
+       if (!AutoLoadFail) {
+               struct registry_priv *registry_par = &padapter->registrypriv;
+               if (registry_par->regulatory_tid == 0xff) {
+                       if (PROMContent[RF_OPTION1_8723A] == 0xff)
+                               pHalData->EEPROMRegulatory = 0;
+                       else
+                               pHalData->EEPROMRegulatory =
+                                       PROMContent[RF_OPTION1_8723A] & 0x7;
+               } else {
+                       pHalData->EEPROMRegulatory =
+                           registry_par->regulatory_tid;
+               }
+       } else {
+               pHalData->EEPROMRegulatory = 0;
+       }
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("EEPROMRegulatory = 0x%x\n", pHalData->EEPROMRegulatory));
+
+       if (!AutoLoadFail)
+               pHalData->bTXPowerDataReadFromEEPORM = true;
+}
+
+void
+Hal_EfuseParseBTCoexistInfo_8723A(struct rtw_adapter *padapter,
+                                 u8 *hwinfo, bool AutoLoadFail)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u8 tempval;
+       u32 tmpu4;
+
+       if (!AutoLoadFail) {
+               tmpu4 = rtw_read32(padapter, REG_MULTI_FUNC_CTRL);
+               if (tmpu4 & BT_FUNC_EN)
+                       pHalData->EEPROMBluetoothCoexist = 1;
+               else
+                       pHalData->EEPROMBluetoothCoexist = 0;
+               pHalData->EEPROMBluetoothType = BT_RTL8723A;
+
+               /*  The following need to be checked with newer version of */
+               /*  eeprom spec */
+               tempval = hwinfo[RF_OPTION4_8723A];
+               pHalData->EEPROMBluetoothAntNum = (tempval & 0x1);
+               pHalData->EEPROMBluetoothAntIsolation = ((tempval & 0x10) >> 4);
+               pHalData->EEPROMBluetoothRadioShared = ((tempval & 0x20) >> 5);
+       } else {
+               pHalData->EEPROMBluetoothCoexist = 0;
+               pHalData->EEPROMBluetoothType = BT_RTL8723A;
+               pHalData->EEPROMBluetoothAntNum = Ant_x2;
+               pHalData->EEPROMBluetoothAntIsolation = 0;
+               pHalData->EEPROMBluetoothRadioShared = BT_Radio_Shared;
+       }
+#ifdef CONFIG_8723AU_BT_COEXIST
+       BT_InitHalVars(padapter);
+#endif
+}
+
+void
+Hal_EfuseParseEEPROMVer(struct rtw_adapter *padapter,
+                       u8 *hwinfo, bool AutoLoadFail)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (!AutoLoadFail)
+               pHalData->EEPROMVersion = hwinfo[EEPROM_VERSION_8723A];
+       else
+               pHalData->EEPROMVersion = 1;
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("Hal_EfuseParseEEPROMVer(), EEVer = %d\n",
+                 pHalData->EEPROMVersion));
+}
+
+void
+rtl8723a_EfuseParseChnlPlan(struct rtw_adapter *padapter,
+                           u8 *hwinfo, bool AutoLoadFail)
+{
+       padapter->mlmepriv.ChannelPlan =
+               hal_com_get_channel_plan23a(padapter, hwinfo ?
+                                        hwinfo[EEPROM_ChannelPlan_8723A]:0xFF,
+                                        padapter->registrypriv.channel_plan,
+                                        RT_CHANNEL_DOMAIN_WORLD_WIDE_13,
+                                        AutoLoadFail);
+
+       DBG_8723A("mlmepriv.ChannelPlan = 0x%02x\n",
+                 padapter->mlmepriv.ChannelPlan);
+}
+
+void
+Hal_EfuseParseCustomerID(struct rtw_adapter *padapter,
+                        u8 *hwinfo, bool AutoLoadFail)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       if (!AutoLoadFail) {
+               pHalData->EEPROMCustomerID = hwinfo[EEPROM_CustomID_8723A];
+               pHalData->EEPROMSubCustomerID =
+                   hwinfo[EEPROM_SubCustomID_8723A];
+       } else {
+               pHalData->EEPROMCustomerID = 0;
+               pHalData->EEPROMSubCustomerID = 0;
+       }
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("EEPROM Customer ID: 0x%2x\n", pHalData->EEPROMCustomerID));
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("EEPROM SubCustomer ID: 0x%02x\n",
+                 pHalData->EEPROMSubCustomerID));
+}
+
+void
+Hal_EfuseParseAntennaDiversity(struct rtw_adapter *padapter,
+                              u8 *hwinfo, bool AutoLoadFail)
+{
+}
+
+void
+Hal_EfuseParseRateIndicationOption(struct rtw_adapter *padapter,
+                                  u8 *hwinfo, bool AutoLoadFail)
+{
+}
+
+void
+Hal_EfuseParseXtal_8723A(struct rtw_adapter *pAdapter,
+                        u8 *hwinfo, u8 AutoLoadFail)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+
+       if (!AutoLoadFail) {
+               pHalData->CrystalCap = hwinfo[EEPROM_XTAL_K_8723A];
+               if (pHalData->CrystalCap == 0xFF)
+                       pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723A;
+       } else {
+               pHalData->CrystalCap = EEPROM_Default_CrystalCap_8723A;
+       }
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("%s: CrystalCap = 0x%2x\n", __func__,
+                 pHalData->CrystalCap));
+}
+
+void
+Hal_EfuseParseThermalMeter_8723A(struct rtw_adapter *padapter,
+                                u8 *PROMContent, u8 AutoloadFail)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       /*  */
+       /*  ThermalMeter from EEPROM */
+       /*  */
+       if (false == AutoloadFail)
+               pHalData->EEPROMThermalMeter =
+                   PROMContent[EEPROM_THERMAL_METER_8723A];
+       else
+               pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter;
+
+       if ((pHalData->EEPROMThermalMeter == 0xff) || (true == AutoloadFail)) {
+               pHalData->bAPKThermalMeterIgnore = true;
+               pHalData->EEPROMThermalMeter = EEPROM_Default_ThermalMeter;
+       }
+
+       DBG_8723A("%s: ThermalMeter = 0x%x\n", __func__,
+                 pHalData->EEPROMThermalMeter);
+}
+
+void Hal_InitChannelPlan23a(struct rtw_adapter *padapter)
+{
+}
+
+static void rtl8723a_cal_txdesc_chksum(struct tx_desc *ptxdesc)
+{
+       u16 *usPtr = (u16 *) ptxdesc;
+       u32 count = 16;         /*  (32 bytes / 2 bytes per XOR) => 16 times */
+       u32 index;
+       u16 checksum = 0;
+
+       /*  Clear first */
+       ptxdesc->txdw7 &= cpu_to_le32(0xffff0000);
+
+       for (index = 0; index < count; index++) {
+               checksum ^= le16_to_cpu(*(usPtr + index));
+       }
+
+       ptxdesc->txdw7 |= cpu_to_le32(checksum & 0x0000ffff);
+}
+
+static void fill_txdesc_sectype(struct pkt_attrib *pattrib,
+                               struct txdesc_8723a *ptxdesc)
+{
+       if ((pattrib->encrypt > 0) && !pattrib->bswenc) {
+               switch (pattrib->encrypt) {
+                       /*  SEC_TYPE */
+               case _WEP40_:
+               case _WEP104_:
+               case _TKIP_:
+               case _TKIP_WTMIC_:
+                       ptxdesc->sectype = 1;
+                       break;
+
+               case _AES_:
+                       ptxdesc->sectype = 3;
+                       break;
+
+               case _NO_PRIVACY_:
+               default:
+                       break;
+               }
+       }
+}
+
+static void fill_txdesc_vcs(struct pkt_attrib *pattrib,
+                           struct txdesc_8723a *ptxdesc)
+{
+       /* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */
+
+       switch (pattrib->vcs_mode) {
+       case RTS_CTS:
+               ptxdesc->rtsen = 1;
+               break;
+
+       case CTS_TO_SELF:
+               ptxdesc->cts2self = 1;
+               break;
+
+       case NONE_VCS:
+       default:
+               break;
+       }
+
+       if (pattrib->vcs_mode) {
+               ptxdesc->hw_rts_en = 1; /*  ENABLE HW RTS */
+
+               /*  Set RTS BW */
+               if (pattrib->ht_en) {
+                       if (pattrib->bwmode & HT_CHANNEL_WIDTH_40)
+                               ptxdesc->rts_bw = 1;
+
+                       switch (pattrib->ch_offset) {
+                       case HAL_PRIME_CHNL_OFFSET_DONT_CARE:
+                               ptxdesc->rts_sc = 0;
+                               break;
+
+                       case HAL_PRIME_CHNL_OFFSET_LOWER:
+                               ptxdesc->rts_sc = 1;
+                               break;
+
+                       case HAL_PRIME_CHNL_OFFSET_UPPER:
+                               ptxdesc->rts_sc = 2;
+                               break;
+
+                       default:
+                               ptxdesc->rts_sc = 3;    /*  Duplicate */
+                               break;
+                       }
+               }
+       }
+}
+
+static void fill_txdesc_phy(struct pkt_attrib *pattrib,
+                           struct txdesc_8723a *ptxdesc)
+{
+       if (pattrib->ht_en) {
+               if (pattrib->bwmode & HT_CHANNEL_WIDTH_40)
+                       ptxdesc->data_bw = 1;
+
+               switch (pattrib->ch_offset) {
+               case HAL_PRIME_CHNL_OFFSET_DONT_CARE:
+                       ptxdesc->data_sc = 0;
+                       break;
+
+               case HAL_PRIME_CHNL_OFFSET_LOWER:
+                       ptxdesc->data_sc = 1;
+                       break;
+
+               case HAL_PRIME_CHNL_OFFSET_UPPER:
+                       ptxdesc->data_sc = 2;
+                       break;
+
+               default:
+                       ptxdesc->data_sc = 3;   /*  Duplicate */
+                       break;
+               }
+       }
+}
+
+static void rtl8723a_fill_default_txdesc(struct xmit_frame *pxmitframe,
+                                        u8 *pbuf)
+{
+       struct rtw_adapter *padapter;
+       struct hal_data_8723a *pHalData;
+       struct dm_priv *pdmpriv;
+       struct mlme_ext_priv *pmlmeext;
+       struct mlme_ext_info *pmlmeinfo;
+       struct pkt_attrib *pattrib;
+       struct txdesc_8723a *ptxdesc;
+       s32 bmcst;
+
+       padapter = pxmitframe->padapter;
+       pHalData = GET_HAL_DATA(padapter);
+       pdmpriv = &pHalData->dmpriv;
+       pmlmeext = &padapter->mlmeextpriv;
+       pmlmeinfo = &pmlmeext->mlmext_info;
+
+       pattrib = &pxmitframe->attrib;
+       bmcst = is_multicast_ether_addr(pattrib->ra);
+
+       ptxdesc = (struct txdesc_8723a *)pbuf;
+
+       if (pxmitframe->frame_tag == DATA_FRAMETAG) {
+               ptxdesc->macid = pattrib->mac_id;       /*  CAM_ID(MAC_ID) */
+
+               if (pattrib->ampdu_en == true)
+                       ptxdesc->agg_en = 1;    /*  AGG EN */
+               else
+                       ptxdesc->bk = 1;        /*  AGG BK */
+
+               ptxdesc->qsel = pattrib->qsel;
+               ptxdesc->rate_id = pattrib->raid;
+
+               fill_txdesc_sectype(pattrib, ptxdesc);
+
+               ptxdesc->seq = pattrib->seqnum;
+
+               if ((pattrib->ether_type != 0x888e) &&
+                   (pattrib->ether_type != 0x0806) &&
+                   (pattrib->dhcp_pkt != 1)) {
+                       /*  Non EAP & ARP & DHCP type data packet */
+
+                       fill_txdesc_vcs(pattrib, ptxdesc);
+                       fill_txdesc_phy(pattrib, ptxdesc);
+
+                       ptxdesc->rtsrate = 8;   /*  RTS Rate = 24M */
+                       ptxdesc->data_ratefb_lmt = 0x1F;
+                       ptxdesc->rts_ratefb_lmt = 0xF;
+
+                       /*  use REG_INIDATA_RATE_SEL value */
+                       ptxdesc->datarate =
+                               pdmpriv->INIDATA_RATE[pattrib->mac_id];
+
+               } else {
+                       /*  EAP data packet and ARP packet. */
+                       /*  Use the 1M data rate to send the EAP/ARP packet. */
+                       /*  This will maybe make the handshake smooth. */
+
+                       ptxdesc->bk = 1;        /*  AGG BK */
+                       ptxdesc->userate = 1;   /*  driver uses rate */
+                       if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT)
+                               ptxdesc->data_short = 1;
+                       ptxdesc->datarate = MRateToHwRate23a(pmlmeext->tx_rate);
+               }
+       } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) {
+/*             RT_TRACE(_module_hal_xmit_c_, _drv_notice_,
+               ("%s: MGNT_FRAMETAG\n", __func__)); */
+
+               ptxdesc->macid = pattrib->mac_id;       /*  CAM_ID(MAC_ID) */
+               ptxdesc->qsel = pattrib->qsel;
+               ptxdesc->rate_id = pattrib->raid;       /*  Rate ID */
+               ptxdesc->seq = pattrib->seqnum;
+               ptxdesc->userate = 1;   /*  driver uses rate, 1M */
+               ptxdesc->rty_lmt_en = 1;        /*  retry limit enable */
+               ptxdesc->data_rt_lmt = 6;       /*  retry limit = 6 */
+
+               /* CCX-TXRPT ack for xmit mgmt frames. */
+               if (pxmitframe->ack_report)
+                       ptxdesc->ccx = 1;
+
+               ptxdesc->datarate = MRateToHwRate23a(pmlmeext->tx_rate);
+       } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) {
+               RT_TRACE(_module_hal_xmit_c_, _drv_warning_,
+                        ("%s: TXAGG_FRAMETAG\n", __func__));
+       } else {
+               RT_TRACE(_module_hal_xmit_c_, _drv_warning_,
+                        ("%s: frame_tag = 0x%x\n", __func__,
+                         pxmitframe->frame_tag));
+
+               ptxdesc->macid = 4;     /*  CAM_ID(MAC_ID) */
+               ptxdesc->rate_id = 6;   /*  Rate ID */
+               ptxdesc->seq = pattrib->seqnum;
+               ptxdesc->userate = 1;   /*  driver uses rate */
+               ptxdesc->datarate = MRateToHwRate23a(pmlmeext->tx_rate);
+       }
+
+       ptxdesc->pktlen = pattrib->last_txcmdsz;
+       ptxdesc->offset = TXDESC_SIZE + OFFSET_SZ;
+       if (bmcst)
+               ptxdesc->bmc = 1;
+       ptxdesc->ls = 1;
+       ptxdesc->fs = 1;
+       ptxdesc->own = 1;
+
+       /*  2009.11.05. tynli_test. Suggested by SD4 Filen for FW LPS. */
+       /*  (1) The sequence number of each non-Qos frame / broadcast /
+        *   multicast / mgnt frame should be controled by Hw because Fw
+        * will also send null data which we cannot control when Fw LPS enable.
+        *  --> default enable non-Qos data sequense number.
+        2010.06.23. by tynli. */
+       /*  (2) Enable HW SEQ control for beacon packet,
+        * because we use Hw beacon. */
+       /*  (3) Use HW Qos SEQ to control the seq num of Ext port
+        * non-Qos packets. */
+       /*  2010.06.23. Added by tynli. */
+       if (!pattrib->qos_en) {
+               /*  Hw set sequence number */
+               ptxdesc->hwseq_en = 1;  /*  HWSEQ_EN */
+               ptxdesc->hwseq_sel = 0; /*  HWSEQ_SEL */
+       }
+}
+
+/*
+ *     Description:
+ *
+ *     Parameters:
+ *             pxmitframe      xmitframe
+ *             pbuf            where to fill tx desc
+ */
+void rtl8723a_update_txdesc(struct xmit_frame *pxmitframe, u8 *pbuf)
+{
+       struct tx_desc *pdesc;
+
+       pdesc = (struct tx_desc *)pbuf;
+       memset(pdesc, 0, sizeof(struct tx_desc));
+
+       rtl8723a_fill_default_txdesc(pxmitframe, pbuf);
+
+       pdesc->txdw0 = cpu_to_le32(pdesc->txdw0);
+       pdesc->txdw1 = cpu_to_le32(pdesc->txdw1);
+       pdesc->txdw2 = cpu_to_le32(pdesc->txdw2);
+       pdesc->txdw3 = cpu_to_le32(pdesc->txdw3);
+       pdesc->txdw4 = cpu_to_le32(pdesc->txdw4);
+       pdesc->txdw5 = cpu_to_le32(pdesc->txdw5);
+       pdesc->txdw6 = cpu_to_le32(pdesc->txdw6);
+       pdesc->txdw7 = cpu_to_le32(pdesc->txdw7);
+       rtl8723a_cal_txdesc_chksum(pdesc);
+}
+
+/*
+ *  Description: In normal chip, we should send some packet to Hw which
+ *  will be used by Fw in FW LPS mode. The function is to fill the Tx
+ * descriptor of this packets, then
+ */
+/*                     Fw can tell Hw to send these packet derectly. */
+/*  Added by tynli. 2009.10.15. */
+/*  */
+void rtl8723a_fill_fake_txdesc(struct rtw_adapter *padapter, u8 *pDesc,
+                              u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull)
+{
+       struct tx_desc *ptxdesc;
+
+       /*  Clear all status */
+       ptxdesc = (struct tx_desc *)pDesc;
+       memset(pDesc, 0, TXDESC_SIZE);
+
+       /* offset 0 */
+       /* own, bFirstSeg, bLastSeg; */
+       ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
+
+       /* 32 bytes for TX Desc */
+       ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE + OFFSET_SZ) <<
+                                      OFFSET_SHT) & 0x00ff0000);
+
+       /*  Buffer size + command header */
+       ptxdesc->txdw0 |= cpu_to_le32(BufferLen & 0x0000ffff);
+
+       /* offset 4 */
+       /*  Fixed queue of Mgnt queue */
+       ptxdesc->txdw1 |= cpu_to_le32((QSLT_MGNT << QSEL_SHT) & 0x00001f00);
+
+       /* Set NAVUSEHDR to prevent Ps-poll AId filed to be changed
+          to error vlaue by Hw. */
+       if (IsPsPoll) {
+               ptxdesc->txdw1 |= cpu_to_le32(NAVUSEHDR);
+       } else {
+               /*  Hw set sequence number */
+               ptxdesc->txdw4 |= cpu_to_le32(BIT(7));
+               /* set bit3 to 1. Suugested by TimChen. 2009.12.29. */
+               ptxdesc->txdw3 |= cpu_to_le32((8 << 28));
+       }
+
+       if (true == IsBTQosNull) {
+               ptxdesc->txdw2 |= cpu_to_le32(BIT(23)); /*  BT NULL */
+       }
+
+       /* offset 16 */
+       ptxdesc->txdw4 |= cpu_to_le32(BIT(8));  /* driver uses rate */
+
+       /*  USB interface drop packet if the checksum of descriptor isn't
+           correct. */
+       /*  Using this checksum can let hardware recovery from packet bulk
+           out error (e.g. Cancel URC, Bulk out error.). */
+       rtl8723a_cal_txdesc_chksum(ptxdesc);
+}
+
+static void hw_var_set_opmode(struct rtw_adapter *padapter, u8 mode)
+{
+       u8 val8;
+
+       if ((mode == _HW_STATE_STATION_) || (mode == _HW_STATE_NOLINK_)) {
+               StopTxBeacon(padapter);
+
+               /*  disable atim wnd */
+               val8 = DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_ATIM;
+               SetBcnCtrlReg23a(padapter, val8, ~val8);
+       } else if ((mode == _HW_STATE_ADHOC_) /*|| (mode == _HW_STATE_AP_) */) {
+               ResumeTxBeacon(padapter);
+
+               val8 = DIS_TSF_UDT | EN_BCN_FUNCTION | DIS_BCNQ_SUB;
+               SetBcnCtrlReg23a(padapter, val8, ~val8);
+       } else if (mode == _HW_STATE_AP_) {
+#ifdef CONFIG_8723AU_BT_COEXIST
+               /*  add NULL Data and BT NULL Data Packets to FW RSVD Page */
+               rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(padapter);
+#endif
+
+               ResumeTxBeacon(padapter);
+
+               val8 = DIS_TSF_UDT | DIS_BCNQ_SUB;
+               SetBcnCtrlReg23a(padapter, val8, ~val8);
+
+               /*  Set RCR */
+               /* rtw_write32(padapter, REG_RCR, 0x70002a8e);
+                  CBSSID_DATA must set to 0 */
+               /* CBSSID_DATA must set to 0 */
+               rtw_write32(padapter, REG_RCR, 0x7000228e);
+               /*  enable to rx data frame */
+               rtw_write16(padapter, REG_RXFLTMAP2, 0xFFFF);
+               /*  enable to rx ps-poll */
+               rtw_write16(padapter, REG_RXFLTMAP1, 0x0400);
+
+               /*  Beacon Control related register for first time */
+               rtw_write8(padapter, REG_BCNDMATIM, 0x02);      /*  2ms */
+               rtw_write8(padapter, REG_DRVERLYINT, 0x05);     /*  5ms */
+               rtw_write8(padapter, REG_ATIMWND, 0x0a); /*  10ms for port0 */
+               rtw_write16(padapter, REG_BCNTCFG, 0x00);
+               rtw_write16(padapter, REG_TBTT_PROHIBIT, 0xff04);
+               /*  +32767 (~32ms) */
+               rtw_write16(padapter, REG_TSFTR_SYN_OFFSET, 0x7fff);
+
+               /*  reset TSF */
+               rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(0));
+
+               /*  enable BCN Function */
+               /*  don't enable update TSF (due to TSF update when
+                   beacon/probe rsp are received) */
+               val8 = DIS_TSF_UDT | EN_BCN_FUNCTION |
+                      EN_TXBCN_RPT | DIS_BCNQ_SUB;
+               SetBcnCtrlReg23a(padapter, val8, ~val8);
+       }
+
+       val8 = rtw_read8(padapter, MSR);
+       val8 = (val8 & 0xC) | mode;
+       rtw_write8(padapter, MSR, val8);
+}
+
+static void hw_var_set_macaddr(struct rtw_adapter *padapter, u8 *val)
+{
+       u8 idx = 0;
+       u32 reg_macid;
+
+       reg_macid = REG_MACID;
+
+       for (idx = 0; idx < 6; idx++)
+               rtw_write8(padapter, (reg_macid + idx), val[idx]);
+}
+
+static void hw_var_set_bssid(struct rtw_adapter *padapter, u8 *val)
+{
+       u8 idx = 0;
+       u32 reg_bssid;
+
+       reg_bssid = REG_BSSID;
+
+       for (idx = 0; idx < 6; idx++)
+               rtw_write8(padapter, (reg_bssid + idx), val[idx]);
+}
+
+static void hw_var_set_correct_tsf(struct rtw_adapter *padapter)
+{
+       u64 tsf;
+       u32 reg_tsftr;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+
+       /* tsf = pmlmeext->TSFValue - ((u32)pmlmeext->TSFValue %
+          (pmlmeinfo->bcn_interval*1024)) - 1024; us */
+       tsf = pmlmeext->TSFValue -
+               rtw_modular6423a(pmlmeext->TSFValue,
+                             (pmlmeinfo->bcn_interval * 1024)) - 1024; /* us */
+
+       if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) ||
+           ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE)) {
+               /* pHalData->RegTxPause |= STOP_BCNQ;BIT(6) */
+               /* rtw_write8(padapter, REG_TXPAUSE,
+                  (rtw_read8(Adapter, REG_TXPAUSE)|BIT(6))); */
+               StopTxBeacon(padapter);
+       }
+
+       reg_tsftr = REG_TSFTR;
+
+       /*  disable related TSF function */
+       SetBcnCtrlReg23a(padapter, 0, EN_BCN_FUNCTION);
+
+       rtw_write32(padapter, reg_tsftr, tsf);
+       rtw_write32(padapter, reg_tsftr + 4, tsf >> 32);
+
+       /* enable related TSF function */
+       SetBcnCtrlReg23a(padapter, EN_BCN_FUNCTION, 0);
+
+       if (((pmlmeinfo->state & 0x03) == WIFI_FW_ADHOC_STATE) ||
+           ((pmlmeinfo->state & 0x03) == WIFI_FW_AP_STATE))
+               ResumeTxBeacon(padapter);
+}
+
+static void hw_var_set_mlme_disconnect(struct rtw_adapter *padapter)
+{
+       /*  reject all data frames */
+       rtw_write16(padapter, REG_RXFLTMAP2, 0);
+
+       /*  reset TSF */
+       rtw_write8(padapter, REG_DUAL_TSF_RST, BIT(0));
+
+       /*  disable update TSF */
+       SetBcnCtrlReg23a(padapter, DIS_TSF_UDT, 0);
+}
+
+static void hw_var_set_mlme_join(struct rtw_adapter *padapter, u8 type)
+{
+       u8 RetryLimit = 0x30;
+
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       if (type == 0) {        /*  prepare to join */
+               u32 v32;
+
+               /*  enable to rx data frame.Accept all data frame */
+               /* rtw_write32(padapter, REG_RCR,
+                  rtw_read32(padapter, REG_RCR)|RCR_ADF); */
+               rtw_write16(padapter, REG_RXFLTMAP2, 0xFFFF);
+
+               v32 = rtw_read32(padapter, REG_RCR);
+               v32 |= RCR_CBSSID_DATA | RCR_CBSSID_BCN;
+               rtw_write32(padapter, REG_RCR, v32);
+
+               if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) == true)
+                       RetryLimit =
+                           (pHalData->CustomerID == RT_CID_CCX) ? 7 : 48;
+               else            /*  Ad-hoc Mode */
+                       RetryLimit = 0x7;
+       } else if (type == 1) { /*  joinbss_event callback when join res < 0 */
+               /*  config RCR to receive different BSSID & not to
+                   receive data frame during linking */
+               rtw_write16(padapter, REG_RXFLTMAP2, 0);
+       } else if (type == 2) { /*  sta add event callback */
+               /*  enable update TSF */
+               SetBcnCtrlReg23a(padapter, 0, DIS_TSF_UDT);
+
+               if (check_fwstate(pmlmepriv,
+                                 WIFI_ADHOC_STATE | WIFI_ADHOC_MASTER_STATE)) {
+                       /*  fixed beacon issue for 8191su........... */
+                       rtw_write8(padapter, 0x542, 0x02);
+                       RetryLimit = 0x7;
+               }
+       }
+
+       rtw_write16(padapter, REG_RL,
+                   RetryLimit << RETRY_LIMIT_SHORT_SHIFT | RetryLimit <<
+                   RETRY_LIMIT_LONG_SHIFT);
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       switch (type) {
+       case 0:
+               /*  prepare to join */
+               BT_WifiAssociateNotify(padapter, true);
+               break;
+       case 1:
+               /*  joinbss_event callback when join res < 0 */
+               BT_WifiAssociateNotify(padapter, false);
+               break;
+       case 2:
+               /*  sta add event callback */
+/*             BT_WifiMediaStatusNotify(padapter, RT_MEDIA_CONNECT); */
+               break;
+       }
+#endif
+}
+
+void SetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       u32 *val32 = (u32 *)val;
+
+       switch (variable) {
+       case HW_VAR_MEDIA_STATUS:
+               rtl8723a_set_media_status(padapter, *val);
+               break;
+
+       case HW_VAR_MEDIA_STATUS1:
+               rtl8723a_set_media_status1(padapter, *val);
+               break;
+
+       case HW_VAR_SET_OPMODE:
+               hw_var_set_opmode(padapter, *val);
+               break;
+
+       case HW_VAR_MAC_ADDR:
+               hw_var_set_macaddr(padapter, val);
+               break;
+
+       case HW_VAR_BSSID:
+               hw_var_set_bssid(padapter, val);
+               break;
+
+       case HW_VAR_BASIC_RATE:
+               HalSetBrateCfg23a(padapter, val);
+               break;
+
+       case HW_VAR_TXPAUSE:
+               rtl8723a_set_tx_pause(padapter, *val);
+               break;
+
+       case HW_VAR_BCN_FUNC:
+               rtl8723a_set_bcn_func(padapter, *val);
+               break;
+
+       case HW_VAR_CORRECT_TSF:
+               hw_var_set_correct_tsf(padapter);
+               break;
+
+       case HW_VAR_CHECK_BSSID:
+               rtl8723a_check_bssid(padapter, *val);
+               break;
+
+       case HW_VAR_MLME_DISCONNECT:
+               hw_var_set_mlme_disconnect(padapter);
+               break;
+
+       case HW_VAR_MLME_SITESURVEY:
+               rtl8723a_mlme_sitesurvey(padapter, *val);
+               break;
+
+       case HW_VAR_MLME_JOIN:
+               hw_var_set_mlme_join(padapter, *val);
+               break;
+
+       case HW_VAR_ON_RCR_AM:
+               rtl8723a_on_rcr_am(padapter);
+               break;
+
+       case HW_VAR_OFF_RCR_AM:
+               rtl8723a_off_rcr_am(padapter);
+               break;
+
+       case HW_VAR_BEACON_INTERVAL:
+               rtl8723a_set_beacon_interval(padapter, *((u16 *) val));
+               break;
+
+       case HW_VAR_SLOT_TIME:
+               rtl8723a_set_slot_time(padapter, *val);
+               break;
+
+       case HW_VAR_RESP_SIFS:
+               rtl8723a_set_resp_sifs(padapter, val[0], val[1],
+                                      val[2], val[3]);
+               break;
+
+       case HW_VAR_ACK_PREAMBLE:
+               rtl8723a_ack_preamble(padapter, *val);
+               break;
+
+       case HW_VAR_SEC_CFG:
+               rtl8723a_set_sec_cfg(padapter, *val);
+               break;
+
+       case HW_VAR_DM_FLAG:
+               rtl8723a_odm_support_ability_write(padapter, *val32);
+               break;
+       case HW_VAR_DM_FUNC_OP:
+               rtl8723a_odm_support_ability_backup(padapter, *val);
+               break;
+       case HW_VAR_DM_FUNC_SET:
+               rtl8723a_odm_support_ability_set(padapter, *val32);
+               break;
+
+       case HW_VAR_DM_FUNC_CLR:
+               rtl8723a_odm_support_ability_clr(padapter, *val32);
+               break;
+
+       case HW_VAR_CAM_EMPTY_ENTRY:
+               rtl8723a_cam_empty_entry(padapter, *val);
+               break;
+
+       case HW_VAR_CAM_INVALID_ALL:
+               rtl8723a_cam_invalid_all(padapter);
+               break;
+
+       case HW_VAR_CAM_WRITE:
+               rtl8723a_cam_write(padapter, val32[0], val32[1]);
+               break;
+
+       case HW_VAR_AC_PARAM_VO:
+               rtl8723a_set_ac_param_vo(padapter, *val32);
+               break;
+
+       case HW_VAR_AC_PARAM_VI:
+               rtl8723a_set_ac_param_vi(padapter, *val32);
+               break;
+
+       case HW_VAR_AC_PARAM_BE:
+               rtl8723a_set_ac_param_be(padapter, *val32);
+               break;
+
+       case HW_VAR_AC_PARAM_BK:
+               rtl8723a_set_ac_param_bk(padapter, *val32);
+               break;
+
+       case HW_VAR_ACM_CTRL:
+               rtl8723a_set_acm_ctrl(padapter, *val);
+               break;
+
+       case HW_VAR_AMPDU_MIN_SPACE:
+               rtl8723a_set_ampdu_min_space(padapter, *val);
+               break;
+
+       case HW_VAR_AMPDU_FACTOR:
+               rtl8723a_set_ampdu_factor(padapter, *val);
+               break;
+
+       case HW_VAR_RXDMA_AGG_PG_TH:
+               rtl8723a_set_rxdma_agg_pg_th(padapter, *val);
+               break;
+
+       case HW_VAR_H2C_FW_PWRMODE:
+               rtl8723a_set_FwPwrMode_cmd(padapter, *val);
+               break;
+
+       case HW_VAR_H2C_FW_JOINBSSRPT:
+               rtl8723a_set_FwJoinBssReport_cmd(padapter, *val);
+               break;
+
+#ifdef CONFIG_8723AU_P2P
+       case HW_VAR_H2C_FW_P2P_PS_OFFLOAD:
+               rtl8723a_set_p2p_ps_offload_cmd(padapter, *val);
+               break;
+#endif /* CONFIG_8723AU_P2P */
+
+       case HW_VAR_INITIAL_GAIN:
+               rtl8723a_set_initial_gain(padapter, *val32);
+               break;
+       case HW_VAR_EFUSE_BYTES:
+               pHalData->EfuseUsedBytes = *((u16 *) val);
+               break;
+       case HW_VAR_EFUSE_BT_BYTES:
+               pHalData->BTEfuseUsedBytes = *((u16 *) val);
+               break;
+       case HW_VAR_FIFO_CLEARN_UP:
+               rtl8723a_fifo_cleanup(padapter);
+               break;
+       case HW_VAR_CHECK_TXBUF:
+               break;
+       case HW_VAR_APFM_ON_MAC:
+               rtl8723a_set_apfm_on_mac(padapter, *val);
+               break;
+
+       case HW_VAR_NAV_UPPER:
+               rtl8723a_set_nav_upper(padapter, *val32);
+               break;
+       case HW_VAR_BCN_VALID:
+               rtl8723a_bcn_valid(padapter);
+               break;
+       default:
+               break;
+       }
+
+}
+
+void GetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+
+       switch (variable) {
+       case HW_VAR_BASIC_RATE:
+               *((u16 *) val) = pHalData->BasicRateSet;
+               break;
+
+       case HW_VAR_TXPAUSE:
+               *val = rtw_read8(padapter, REG_TXPAUSE);
+               break;
+
+       case HW_VAR_BCN_VALID:
+               /* BCN_VALID, BIT16 of REG_TDECTRL = BIT0 of REG_TDECTRL+2 */
+               val[0] = (BIT0 & rtw_read8(padapter, REG_TDECTRL + 2)) ? true :
+                       false;
+               break;
+
+       case HW_VAR_RF_TYPE:
+               *val = pHalData->rf_type;
+               break;
+
+       case HW_VAR_DM_FLAG:
+       {
+               struct dm_odm_t *podmpriv = &pHalData->odmpriv;
+               *((u32 *) val) = podmpriv->SupportAbility;
+       }
+               break;
+
+       case HW_VAR_FWLPS_RF_ON:
+       {
+               /*  When we halt NIC, we should check if FW LPS is leave. */
+               u32 valRCR;
+
+               if ((padapter->bSurpriseRemoved == true) ||
+                   (padapter->pwrctrlpriv.rf_pwrstate == rf_off)) {
+                       /*  If it is in HW/SW Radio OFF or IPS state, we do
+                           not check Fw LPS Leave, because Fw is unload. */
+                       *val = true;
+               } else {
+                       valRCR = rtw_read32(padapter, REG_RCR);
+                       valRCR &= 0x00070000;
+                       if (valRCR)
+                               *val = false;
+                       else
+                               *val = true;
+               }
+       }
+               break;
+       case HW_VAR_EFUSE_BYTES:
+               *((u16 *) val) = pHalData->EfuseUsedBytes;
+               break;
+
+       case HW_VAR_EFUSE_BT_BYTES:
+               *((u16 *) val) = pHalData->BTEfuseUsedBytes;
+               break;
+
+       case HW_VAR_APFM_ON_MAC:
+               *val = pHalData->bMacPwrCtrlOn;
+               break;
+       case HW_VAR_CHK_HI_QUEUE_EMPTY:
+               *val =
+                   ((rtw_read32(padapter, REG_HGQ_INFORMATION) & 0x0000ff00) ==
+                    0) ? true : false;
+               break;
+       }
+}
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+
+void rtl8723a_SingleDualAntennaDetection(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData;
+       struct dm_odm_t *pDM_Odm;
+       struct sw_ant_sw *pDM_SWAT_Table;
+       u8 i;
+
+       pHalData = GET_HAL_DATA(padapter);
+       pDM_Odm = &pHalData->odmpriv;
+       pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+
+       /*  */
+       /*  <Roger_Notes> RTL8723A Single and Dual antenna dynamic detection
+           mechanism when RF power state is on. */
+       /*  We should take power tracking, IQK, LCK, RCK RF read/write
+           operation into consideration. */
+       /*  2011.12.15. */
+       /*  */
+       if (!pHalData->bAntennaDetected) {
+               u8 btAntNum = BT_GetPGAntNum(padapter);
+
+               /*  Set default antenna B status */
+               if (btAntNum == Ant_x2)
+                       pDM_SWAT_Table->ANTB_ON = true;
+               else if (btAntNum == Ant_x1)
+                       pDM_SWAT_Table->ANTB_ON = false;
+               else
+                       pDM_SWAT_Table->ANTB_ON = true;
+
+               if (pHalData->CustomerID != RT_CID_TOSHIBA) {
+                       for (i = 0; i < MAX_ANTENNA_DETECTION_CNT; i++) {
+                               if (ODM_SingleDualAntennaDetection
+                                   (&pHalData->odmpriv, ANTTESTALL) == true)
+                                       break;
+                       }
+
+                       /*  Set default antenna number for BT coexistence */
+                       if (btAntNum == Ant_x2)
+                               BT_SetBtCoexCurrAntNum(padapter,
+                                                      pDM_SWAT_Table->
+                                                      ANTB_ON ? 2 : 1);
+               }
+               pHalData->bAntennaDetected = true;
+       }
+}
+#endif /*  CONFIG_8723AU_BT_COEXIST */
+
+void rtl8723a_clone_haldata(struct rtw_adapter *dst_adapter,
+                           struct rtw_adapter *src_adapter)
+{
+       memcpy(dst_adapter->HalData, src_adapter->HalData,
+              dst_adapter->hal_data_sz);
+}
+
+void rtl8723a_start_thread(struct rtw_adapter *padapter)
+{
+}
+
+void rtl8723a_stop_thread(struct rtw_adapter *padapter)
+{
+}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c b/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c
new file mode 100644 (file)
index 0000000..8400e6e
--- /dev/null
@@ -0,0 +1,1162 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTL8723A_PHYCFG_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <rtl8723a_hal.h>
+
+/*---------------------------Define Local Constant---------------------------*/
+/* Channel switch:The size of command tables for switch channel*/
+#define MAX_PRECMD_CNT 16
+#define MAX_RFDEPENDCMD_CNT 16
+#define MAX_POSTCMD_CNT 16
+
+#define MAX_DOZE_WAITING_TIMES_9x 64
+
+/*---------------------------Define Local Constant---------------------------*/
+
+/*------------------------Define global variable-----------------------------*/
+
+/*------------------------Define local variable------------------------------*/
+
+/*--------------------Define export function prototype-----------------------*/
+/*  Please refer to header file */
+/*--------------------Define export function prototype-----------------------*/
+
+/*----------------------------Function Body----------------------------------*/
+/*  */
+/*  1. BB register R/W API */
+/*  */
+
+/**
+* Function:    phy_CalculateBitShift
+*
+* OverView:    Get shifted position of the BitMask
+*
+* Input:
+*                      u32             BitMask,
+*
+* Output:      none
+* Return:              u32             Return the shift bit bit position of the mask
+*/
+static u32 phy_CalculateBitShift(u32 BitMask)
+{
+       u32 i;
+
+       for (i = 0; i <= 31; i++) {
+               if (((BitMask>>i) & 0x1) == 1)
+                       break;
+       }
+
+       return i;
+}
+
+/**
+* Function:    PHY_QueryBBReg
+*
+* OverView:    Read "sepcific bits" from BB register
+*
+* Input:
+*      struct rtw_adapter *    Adapter,
+*      u32                     RegAddr,        Target address to be readback
+*      u32                     BitMask         Target bit position in the
+*                                              target address to be readback
+* Output:
+*      None
+* Return:
+*      u32                     Data            The readback register value
+* Note:
+*      This function is equal to "GetRegSetting" in PHY programming guide
+*/
+u32
+PHY_QueryBBReg(struct rtw_adapter *Adapter, u32 RegAddr, u32 BitMask)
+{
+       u32     ReturnValue = 0, OriginalValue, BitShift;
+
+       OriginalValue = rtw_read32(Adapter, RegAddr);
+       BitShift = phy_CalculateBitShift(BitMask);
+       ReturnValue = (OriginalValue & BitMask) >> BitShift;
+       return ReturnValue;
+}
+
+/**
+* Function:    PHY_SetBBReg
+*
+* OverView:    Write "Specific bits" to BB register (page 8~)
+*
+* Input:
+*      struct rtw_adapter *    Adapter,
+*      u32                     RegAddr,        Target address to be modified
+*      u32                     BitMask         Target bit position in the
+*                                              target address to be modified
+*      u32                     Data            The new register value in the
+*                                              target bit position of the
+*                                               target address
+*
+* Output:
+*      None
+* Return:
+*      None
+* Note:
+*      This function is equal to "PutRegSetting" in PHY programming guide
+*/
+
+void
+PHY_SetBBReg(struct rtw_adapter *Adapter, u32 RegAddr, u32 BitMask, u32        Data)
+{
+       u32 OriginalValue, BitShift;
+
+       /* RT_TRACE(COMP_RF, DBG_TRACE, ("--->PHY_SetBBReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx)\n", RegAddr, BitMask, Data)); */
+
+       if (BitMask != bMaskDWord) {/* if not "double word" write */
+               OriginalValue = rtw_read32(Adapter, RegAddr);
+               BitShift = phy_CalculateBitShift(BitMask);
+               Data = ((OriginalValue & (~BitMask)) | (Data << BitShift));
+       }
+
+       rtw_write32(Adapter, RegAddr, Data);
+
+       /* RTPRINT(FPHY, PHY_BBW, ("BBW MASK = 0x%lx Addr[0x%lx]= 0x%lx\n", BitMask, RegAddr, Data)); */
+       /* RT_TRACE(COMP_RF, DBG_TRACE, ("<---PHY_SetBBReg(): RegAddr(%#lx), BitMask(%#lx), Data(%#lx)\n", RegAddr, BitMask, Data)); */
+}
+
+/*  */
+/*  2. RF register R/W API */
+/*  */
+
+/**
+* Function:    phy_RFSerialRead
+*
+* OverView:    Read regster from RF chips
+*
+* Input:
+*              struct rtw_adapter *            Adapter,
+*              enum RF_RADIO_PATH      eRFPath,        Radio path of A/B/C/D
+*              u32 Offset,                     The target address to be read
+*
+* Output:      None
+* Return:      u32                     reback value
+* Note:                Threre are three types of serial operations:
+*              1. Software serial write
+*              2. Hardware LSSI-Low Speed Serial Interface
+*              3. Hardware HSSI-High speed
+*              serial write. Driver need to implement (1) and (2).
+*              This function is equal to the combination of RF_ReadReg() and
+*              RFLSSIRead()
+*/
+static u32
+phy_RFSerialRead(struct rtw_adapter *Adapter, enum RF_RADIO_PATH eRFPath,
+                u32 Offset)
+{
+       u32 retValue = 0;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct bb_reg_define *pPhyReg = &pHalData->PHYRegDef[eRFPath];
+       u32 NewOffset;
+       u32 tmplong, tmplong2;
+       u8 RfPiEnable = 0;
+       /*  */
+       /*  Make sure RF register offset is correct */
+       /*  */
+       Offset &= 0x3f;
+
+       /*  */
+       /*  Switch page for 8256 RF IC */
+       /*  */
+       NewOffset = Offset;
+
+       /*  2009/06/17 MH We can not execute IO for power save or
+           other accident mode. */
+       /* if (RT_CANNOT_IO(Adapter)) */
+       /*  */
+       /*      RTPRINT(FPHY, PHY_RFR, ("phy_RFSerialRead return all one\n")); */
+       /*      return  0xFFFFFFFF; */
+       /*  */
+
+       /*  For 92S LSSI Read RFLSSIRead */
+       /*  For RF A/B write 0x824/82c(does not work in the future) */
+       /*  We must use 0x824 for RF A and B to execute read trigger */
+       tmplong = PHY_QueryBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord);
+       if (eRFPath == RF_PATH_A)
+               tmplong2 = tmplong;
+       else
+               tmplong2 = PHY_QueryBBReg(Adapter, pPhyReg->rfHSSIPara2,
+                                         bMaskDWord);
+
+       tmplong2 = (tmplong2 & ~bLSSIReadAddress) |
+               (NewOffset << 23) | bLSSIReadEdge;      /* T65 RF */
+
+       PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2,
+                    bMaskDWord, tmplong & (~bLSSIReadEdge));
+       udelay(10);/*  PlatformStallExecution(10); */
+
+       PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, bMaskDWord, tmplong2);
+       udelay(100);/* PlatformStallExecution(100); */
+
+       PHY_SetBBReg(Adapter, rFPGA0_XA_HSSIParameter2, bMaskDWord,
+                    tmplong | bLSSIReadEdge);
+       udelay(10);/* PlatformStallExecution(10); */
+
+       if (eRFPath == RF_PATH_A)
+               RfPiEnable = (u8)PHY_QueryBBReg(Adapter,
+                                               rFPGA0_XA_HSSIParameter1, BIT8);
+       else if (eRFPath == RF_PATH_B)
+               RfPiEnable = (u8)PHY_QueryBBReg(Adapter,
+                                               rFPGA0_XB_HSSIParameter1, BIT8);
+
+       if (RfPiEnable) {
+               /* Read from BBreg8b8, 12 bits for 8190, 20bits for T65 RF */
+               retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBackPi,
+                                         bLSSIReadBackData);
+               /* DBG_8723A("Readback from RF-PI : 0x%x\n", retValue); */
+       } else {
+               /* Read from BBreg8a0, 12 bits for 8190, 20 bits for T65 RF */
+               retValue = PHY_QueryBBReg(Adapter, pPhyReg->rfLSSIReadBack,
+                                         bLSSIReadBackData);
+               /* DBG_8723A("Readback from RF-SI : 0x%x\n", retValue); */
+       }
+       /* DBG_8723A("RFR-%d Addr[0x%x]= 0x%x\n", eRFPath, pPhyReg->rfLSSIReadBack, retValue); */
+
+       return retValue;
+}
+
+/**
+* Function:    phy_RFSerialWrite
+*
+* OverView:    Write data to RF register (page 8~)
+*
+* Input:
+*      struct rtw_adapter *            Adapter,
+*      enum RF_RADIO_PATH      eRFPath,        Radio path of A/B/C/D
+*      u32 Offset,                     The target address to be read
+*      u32 Data                        The new register Data in the target
+*                                      bit position of the target to be read
+*
+* Output:
+*      None
+* Return:
+*      None
+* Note:
+*      Threre are three types of serial operations:
+*              1. Software serial write
+*              2. Hardware LSSI-Low Speed Serial Interface
+*              3. Hardware HSSI-High speed
+*              serial write. Driver need to implement (1) and (2).
+*              This function is equal to the combination of RF_ReadReg() and
+*              RFLSSIRead()
+*
+* Note:          For RF8256 only
+* The total count of RTL8256(Zebra4) register is around 36 bit it only employs
+* 4-bit RF address. RTL8256 uses "register mode control bit"
+* (Reg00[12], Reg00[10]) to access register address bigger than 0xf.
+* See "Appendix-4 in PHY Configuration programming guide" for more details.
+* Thus, we define a sub-finction for RTL8526 register address conversion
+* ===========================================================
+* Register Mode:       RegCTL[1]       RegCTL[0]       Note
+*                      (Reg00[12])     (Reg00[10])
+* ===========================================================
+* Reg_Mode0            0               x               Reg 0 ~15(0x0 ~ 0xf)
+* ------------------------------------------------------------------
+* Reg_Mode1            1               0               Reg 16 ~30(0x1 ~ 0xf)
+* ------------------------------------------------------------------
+* Reg_Mode2            1               1               Reg 31 ~ 45(0x1 ~ 0xf)
+* ------------------------------------------------------------------
+*
+*      2008/09/02      MH      Add 92S RF definition
+*/
+static void
+phy_RFSerialWrite(struct rtw_adapter *Adapter, enum RF_RADIO_PATH eRFPath,
+                 u32 Offset, u32 Data)
+{
+       u32 DataAndAddr = 0;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct bb_reg_define *pPhyReg = &pHalData->PHYRegDef[eRFPath];
+       u32 NewOffset;
+
+       /*  2009/06/17 MH We can not execute IO for power save or
+           other accident mode. */
+       /* if (RT_CANNOT_IO(Adapter)) */
+       /*  */
+       /*      RTPRINT(FPHY, PHY_RFW, ("phy_RFSerialWrite stop\n")); */
+       /*      return; */
+       /*  */
+
+       Offset &= 0x3f;
+
+       /*  */
+       /*  Shadow Update */
+       /*  */
+       /* PHY_RFShadowWrite(Adapter, eRFPath, Offset, Data); */
+
+       /*  */
+       /*  Switch page for 8256 RF IC */
+       /*  */
+       NewOffset = Offset;
+
+       /*  */
+       /*  Put write addr in [5:0]  and write data in [31:16] */
+       /*  */
+       /* DataAndAddr = (Data<<16) | (NewOffset&0x3f); */
+       /*  T65 RF */
+       DataAndAddr = ((NewOffset<<20) | (Data&0x000fffff)) & 0x0fffffff;
+
+       /*  */
+       /*  Write Operation */
+       /*  */
+       PHY_SetBBReg(Adapter, pPhyReg->rf3wireOffset, bMaskDWord, DataAndAddr);
+       /* RTPRINT(FPHY, PHY_RFW, ("RFW-%d Addr[0x%lx]= 0x%lx\n", eRFPath, pPhyReg->rf3wireOffset, DataAndAddr)); */
+
+}
+
+/**
+* Function:    PHY_QueryRFReg
+*
+* OverView:    Query "Specific bits" to RF register (page 8~)
+*
+* Input:
+*      struct rtw_adapter *            Adapter,
+*      enum RF_RADIO_PATH      eRFPath,        Radio path of A/B/C/D
+*      u32 RegAddr,                    The target address to be read
+*      u32BitMask                      The target bit position in the target
+*                                      address to be read
+*
+* Output:
+*      None
+* Return:
+*      u32                             Readback value
+* Note:
+*      This function is equal to "GetRFRegSetting" in PHY programming guide
+*/
+u32
+PHY_QueryRFReg(struct rtw_adapter *Adapter, enum RF_RADIO_PATH eRFPath,
+              u32 RegAddr, u32 BitMask)
+{
+       u32 Original_Value, Readback_Value, BitShift;
+       /* struct hal_data_8723a        *pHalData = GET_HAL_DATA(Adapter); */
+       /* u8   RFWaitCounter = 0; */
+       /* _irqL        irqL; */
+
+       Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr);
+
+       BitShift =  phy_CalculateBitShift(BitMask);
+       Readback_Value = (Original_Value & BitMask) >> BitShift;
+
+       return Readback_Value;
+}
+
+/**
+* Function:    PHY_SetRFReg
+*
+* OverView:    Write "Specific bits" to RF register (page 8~)
+*
+* Input:
+*      struct rtw_adapter *            Adapter,
+*      enum RF_RADIO_PATH      eRFPath,        Radio path of A/B/C/D
+*      u32 RegAddr,                    The target address to be modified
+*      u32 BitMask                     The target bit position in the target
+*                                      address to be modified
+*      u32 Data                        The new register Data in the target
+*                                      bit position of the target address
+*
+* Output:
+*      None
+* Return:
+*      None
+* Note:        This function is equal to "PutRFRegSetting" in PHY programming guide
+*/
+void
+PHY_SetRFReg(struct rtw_adapter *Adapter, enum RF_RADIO_PATH eRFPath,
+            u32 RegAddr, u32 BitMask, u32 Data)
+{
+       /* struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter); */
+       /* u8 RFWaitCounter     = 0; */
+       u32 Original_Value, BitShift;
+
+       /*  RF data is 12 bits only */
+       if (BitMask != bRFRegOffsetMask) {
+               Original_Value = phy_RFSerialRead(Adapter, eRFPath, RegAddr);
+               BitShift =  phy_CalculateBitShift(BitMask);
+               Data = ((Original_Value & (~BitMask)) | (Data << BitShift));
+       }
+
+       phy_RFSerialWrite(Adapter, eRFPath, RegAddr, Data);
+}
+
+/*  3. Initial MAC/BB/RF config by reading MAC/BB/RF txt. */
+
+/*-----------------------------------------------------------------------------
+ * Function:    PHY_MACConfig8723A
+ *
+ * Overview:   Condig MAC by header file or parameter file.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ *  When               Who             Remark
+ *  08/12/2008 MHC             Create Version 0.
+ *
+ *---------------------------------------------------------------------------*/
+s32 PHY_MACConfig8723A(struct rtw_adapter *Adapter)
+{
+       int rtStatus = _SUCCESS;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       s8 *pszMACRegFile;
+       s8 sz8723MACRegFile[] = RTL8723_PHY_MACREG;
+       bool is92C = IS_92C_SERIAL(pHalData->VersionID);
+
+       pszMACRegFile = sz8723MACRegFile;
+
+       /*  */
+       /*  Config MAC */
+       /*  */
+       if (HAL_STATUS_FAILURE ==
+           ODM_ConfigMACWithHeaderFile23a(&pHalData->odmpriv))
+               rtStatus = _FAIL;
+
+       /*  2010.07.13 AMPDU aggregation number 9 */
+       /* rtw_write16(Adapter, REG_MAX_AGGR_NUM, MAX_AGGR_NUM); */
+       rtw_write8(Adapter, REG_MAX_AGGR_NUM, 0x0A); /* By tynli. 2010.11.18. */
+       if (is92C && (BOARD_USB_DONGLE == pHalData->BoardType))
+               rtw_write8(Adapter, 0x40, 0x04);
+
+       return rtStatus;
+}
+
+/**
+* Function:    phy_InitBBRFRegisterDefinition
+*
+* OverView:    Initialize Register definition offset for Radio Path A/B/C/D
+*
+* Input:
+*                      struct rtw_adapter *            Adapter,
+*
+* Output:      None
+* Return:              None
+* Note:
+*      The initialization value is constant and it should never be changes
+*/
+static void
+phy_InitBBRFRegisterDefinition(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+
+       /*  RF Interface Sowrtware Control */
+        /*  16 LSBs if read 32-bit from 0x870 */
+       pHalData->PHYRegDef[RF_PATH_A].rfintfs = rFPGA0_XAB_RFInterfaceSW;
+        /*  16 MSBs if read 32-bit from 0x870 (16-bit for 0x872) */
+       pHalData->PHYRegDef[RF_PATH_B].rfintfs = rFPGA0_XAB_RFInterfaceSW;
+
+       /*  RF Interface Readback Value */
+       /*  16 LSBs if read 32-bit from 0x8E0 */
+       pHalData->PHYRegDef[RF_PATH_A].rfintfi = rFPGA0_XAB_RFInterfaceRB;
+       /*  16 MSBs if read 32-bit from 0x8E0 (16-bit for 0x8E2) */
+       pHalData->PHYRegDef[RF_PATH_B].rfintfi = rFPGA0_XAB_RFInterfaceRB;
+
+       /*  RF Interface Output (and Enable) */
+       /*  16 LSBs if read 32-bit from 0x860 */
+       pHalData->PHYRegDef[RF_PATH_A].rfintfo = rFPGA0_XA_RFInterfaceOE;
+        /*  16 LSBs if read 32-bit from 0x864 */
+       pHalData->PHYRegDef[RF_PATH_B].rfintfo = rFPGA0_XB_RFInterfaceOE;
+
+       /*  RF Interface (Output and)  Enable */
+        /*  16 MSBs if read 32-bit from 0x860 (16-bit for 0x862) */
+       pHalData->PHYRegDef[RF_PATH_A].rfintfe = rFPGA0_XA_RFInterfaceOE;
+       /*  16 MSBs if read 32-bit from 0x864 (16-bit for 0x866) */
+       pHalData->PHYRegDef[RF_PATH_B].rfintfe = rFPGA0_XB_RFInterfaceOE;
+
+       /* Addr of LSSI. Wirte RF register by driver */
+       pHalData->PHYRegDef[RF_PATH_A].rf3wireOffset = rFPGA0_XA_LSSIParameter;
+       pHalData->PHYRegDef[RF_PATH_B].rf3wireOffset = rFPGA0_XB_LSSIParameter;
+
+       /*  RF parameter */
+       /* BB Band Select */
+       pHalData->PHYRegDef[RF_PATH_A].rfLSSI_Select = rFPGA0_XAB_RFParameter;
+       pHalData->PHYRegDef[RF_PATH_B].rfLSSI_Select = rFPGA0_XAB_RFParameter;
+
+       /*  Tx AGC Gain Stage (same for all path. Should we remove this?) */
+       pHalData->PHYRegDef[RF_PATH_A].rfTxGainStage = rFPGA0_TxGainStage;
+       pHalData->PHYRegDef[RF_PATH_B].rfTxGainStage = rFPGA0_TxGainStage;
+
+       /*  Tranceiver A~D HSSI Parameter-1 */
+       /* wire control parameter1 */
+       pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara1 = rFPGA0_XA_HSSIParameter1;
+       /* wire control parameter1 */
+       pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara1 = rFPGA0_XB_HSSIParameter1;
+
+       /*  Tranceiver A~D HSSI Parameter-2 */
+       /* wire control parameter2 */
+       pHalData->PHYRegDef[RF_PATH_A].rfHSSIPara2 = rFPGA0_XA_HSSIParameter2;
+       /* wire control parameter2 */
+       pHalData->PHYRegDef[RF_PATH_B].rfHSSIPara2 = rFPGA0_XB_HSSIParameter2;
+
+       /*  RF switch Control */
+       pHalData->PHYRegDef[RF_PATH_A].rfSwitchControl =
+               rFPGA0_XAB_SwitchControl; /* TR/Ant switch control */
+       pHalData->PHYRegDef[RF_PATH_B].rfSwitchControl =
+               rFPGA0_XAB_SwitchControl;
+
+       /*  AGC control 1 */
+       pHalData->PHYRegDef[RF_PATH_A].rfAGCControl1 = rOFDM0_XAAGCCore1;
+       pHalData->PHYRegDef[RF_PATH_B].rfAGCControl1 = rOFDM0_XBAGCCore1;
+
+       /*  AGC control 2 */
+       pHalData->PHYRegDef[RF_PATH_A].rfAGCControl2 = rOFDM0_XAAGCCore2;
+       pHalData->PHYRegDef[RF_PATH_B].rfAGCControl2 = rOFDM0_XBAGCCore2;
+
+       /*  RX AFE control 1 */
+       pHalData->PHYRegDef[RF_PATH_A].rfRxIQImbalance = rOFDM0_XARxIQImbalance;
+       pHalData->PHYRegDef[RF_PATH_B].rfRxIQImbalance = rOFDM0_XBRxIQImbalance;
+
+       /*  RX AFE control 1 */
+       pHalData->PHYRegDef[RF_PATH_A].rfRxAFE = rOFDM0_XARxAFE;
+       pHalData->PHYRegDef[RF_PATH_B].rfRxAFE = rOFDM0_XBRxAFE;
+
+       /*  Tx AFE control 1 */
+       pHalData->PHYRegDef[RF_PATH_A].rfTxIQImbalance = rOFDM0_XATxIQImbalance;
+       pHalData->PHYRegDef[RF_PATH_B].rfTxIQImbalance = rOFDM0_XBTxIQImbalance;
+
+       /*  Tx AFE control 2 */
+       pHalData->PHYRegDef[RF_PATH_A].rfTxAFE = rOFDM0_XATxAFE;
+       pHalData->PHYRegDef[RF_PATH_B].rfTxAFE = rOFDM0_XBTxAFE;
+
+       /*  Tranceiver LSSI Readback SI mode */
+       pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBack = rFPGA0_XA_LSSIReadBack;
+       pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBack = rFPGA0_XB_LSSIReadBack;
+
+       /*  Tranceiver LSSI Readback PI mode */
+       pHalData->PHYRegDef[RF_PATH_A].rfLSSIReadBackPi =
+               TransceiverA_HSPI_Readback;
+       pHalData->PHYRegDef[RF_PATH_B].rfLSSIReadBackPi =
+               TransceiverB_HSPI_Readback;
+}
+
+/*  The following is for High Power PA */
+static void
+storePwrIndexDiffRateOffset(struct rtw_adapter *Adapter, u32 RegAddr,
+                           u32 BitMask, u32 Data)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+
+       if (RegAddr == rTxAGC_A_Rate18_06) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][0] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][0] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][0])); */
+       }
+       if (RegAddr == rTxAGC_A_Rate54_24) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][1] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][1] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][1])); */
+       }
+       if (RegAddr == rTxAGC_A_CCK1_Mcs32) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][6] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][6] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][6])); */
+       }
+       if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0xffffff00) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][7] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][7] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][7])); */
+       }
+       if (RegAddr == rTxAGC_A_Mcs03_Mcs00) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][2] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][2] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][2])); */
+       }
+       if (RegAddr == rTxAGC_A_Mcs07_Mcs04) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][3] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][3] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][3])); */
+       }
+       if (RegAddr == rTxAGC_A_Mcs11_Mcs08) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][4] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][4] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][4])); */
+       }
+       if (RegAddr == rTxAGC_A_Mcs15_Mcs12) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][5] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][5] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][5])); */
+       }
+       if (RegAddr == rTxAGC_B_Rate18_06) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][8] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][8] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][8])); */
+       }
+       if (RegAddr == rTxAGC_B_Rate54_24) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][9] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][9] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][9])); */
+       }
+       if (RegAddr == rTxAGC_B_CCK1_55_Mcs32) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][14] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][14] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][14])); */
+       }
+       if (RegAddr == rTxAGC_B_CCK11_A_CCK2_11 && BitMask == 0x000000ff) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][15] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][15] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][15])); */
+       }
+       if (RegAddr == rTxAGC_B_Mcs03_Mcs00) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][10] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][10] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][10])); */
+       }
+       if (RegAddr == rTxAGC_B_Mcs07_Mcs04) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][11] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][11] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][11])); */
+       }
+       if (RegAddr == rTxAGC_B_Mcs11_Mcs08) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][12] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][12] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][12])); */
+       }
+       if (RegAddr == rTxAGC_B_Mcs15_Mcs12) {
+               pHalData->MCSTxPowerLevelOriginalOffset[pHalData->pwrGroupCnt][13] = Data;
+               /* RT_TRACE(COMP_INIT, DBG_TRACE,
+                  ("MCSTxPowerLevelOriginalOffset[%d][13] = 0x%lx\n",
+                  pHalData->pwrGroupCnt, */
+               /*      pHalData->MCSTxPowerLevelOriginalOffset[
+                       pHalData->pwrGroupCnt][13])); */
+               pHalData->pwrGroupCnt++;
+       }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:   phy_ConfigBBWithPgHeaderFile
+ *
+ * Overview:   Config PHY_REG_PG array
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                Who     Remark
+ * 11/06/2008  MHC     Add later!!!!!!.. Please modify for new files!!!!
+ * 11/10/2008  tynli   Modify to mew files.
+ *---------------------------------------------------------------------------*/
+static int
+phy_ConfigBBWithPgHeaderFile(struct rtw_adapter *Adapter, u8 ConfigType)
+{
+       int i;
+       u32 *Rtl819XPHY_REGArray_Table_PG;
+       u16 PHY_REGArrayPGLen;
+
+       PHY_REGArrayPGLen = Rtl8723_PHY_REG_Array_PGLength;
+       Rtl819XPHY_REGArray_Table_PG = (u32 *)Rtl8723_PHY_REG_Array_PG;
+
+       if (ConfigType == BaseBand_Config_PHY_REG) {
+               for (i = 0; i < PHY_REGArrayPGLen; i = i + 3) {
+                       storePwrIndexDiffRateOffset(Adapter,
+                               Rtl819XPHY_REGArray_Table_PG[i],
+                               Rtl819XPHY_REGArray_Table_PG[i+1],
+                               Rtl819XPHY_REGArray_Table_PG[i+2]);
+               }
+       }
+
+       return _SUCCESS;
+}      /* phy_ConfigBBWithPgHeaderFile */
+
+static void
+phy_BB8192C_Config_1T(struct rtw_adapter *Adapter)
+{
+       /* for path - B */
+       PHY_SetBBReg(Adapter, rFPGA0_TxInfo, 0x3, 0x2);
+       PHY_SetBBReg(Adapter, rFPGA1_TxInfo, 0x300033, 0x200022);
+
+       /*  20100519 Joseph: Add for 1T2R config. Suggested by Kevin,
+           Jenyu and Yunan. */
+       PHY_SetBBReg(Adapter, rCCK0_AFESetting, bMaskByte3, 0x45);
+       PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, bMaskByte0, 0x23);
+       /*  B path first AGC */
+       PHY_SetBBReg(Adapter, rOFDM0_AGCParameter1, 0x30, 0x1);
+
+       PHY_SetBBReg(Adapter, 0xe74, 0x0c000000, 0x2);
+       PHY_SetBBReg(Adapter, 0xe78, 0x0c000000, 0x2);
+       PHY_SetBBReg(Adapter, 0xe7c, 0x0c000000, 0x2);
+       PHY_SetBBReg(Adapter, 0xe80, 0x0c000000, 0x2);
+       PHY_SetBBReg(Adapter, 0xe88, 0x0c000000, 0x2);
+}
+
+static int
+phy_BB8723a_Config_ParaFile(struct rtw_adapter *Adapter)
+{
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter);
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       int rtStatus = _SUCCESS;
+
+       u8 sz8723BBRegFile[] = RTL8723_PHY_REG;
+       u8 sz8723AGCTableFile[] = RTL8723_AGC_TAB;
+       u8 sz8723BBRegPgFile[] = RTL8723_PHY_REG_PG;
+       u8 sz8723BBRegMpFile[] = RTL8723_PHY_REG_MP;
+
+       u8 *pszBBRegFile = NULL, *pszAGCTableFile = NULL;
+       u8 *pszBBRegPgFile = NULL, *pszBBRegMpFile = NULL;
+
+       /* RT_TRACE(COMP_INIT, DBG_TRACE, ("==>phy_BB8192S_Config_ParaFile\n")); */
+
+       pszBBRegFile = sz8723BBRegFile ;
+       pszAGCTableFile = sz8723AGCTableFile;
+       pszBBRegPgFile = sz8723BBRegPgFile;
+       pszBBRegMpFile = sz8723BBRegMpFile;
+
+       /*  */
+       /*  1. Read PHY_REG.TXT BB INIT!! */
+       /*  We will seperate as 88C / 92C according to chip version */
+       /*  */
+       if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile23a(&pHalData->odmpriv,
+                                                            CONFIG_BB_PHY_REG))
+               rtStatus = _FAIL;
+       if (rtStatus != _SUCCESS)
+               goto phy_BB8190_Config_ParaFile_Fail;
+
+       /*  */
+       /*  20100318 Joseph: Config 2T2R to 1T2R if necessary. */
+       /*  */
+       if (pHalData->rf_type == RF_1T2R) {
+               phy_BB8192C_Config_1T(Adapter);
+               DBG_8723A("phy_BB8723a_Config_ParaFile():Config to 1T!!\n");
+       }
+
+       /*  */
+       /*  2. If EEPROM or EFUSE autoload OK, We must config by
+           PHY_REG_PG.txt */
+       /*  */
+       if (pEEPROM->bautoload_fail_flag == false) {
+               pHalData->pwrGroupCnt = 0;
+
+               rtStatus = phy_ConfigBBWithPgHeaderFile(Adapter,
+                                                       BaseBand_Config_PHY_REG);
+       }
+
+       if (rtStatus != _SUCCESS)
+               goto phy_BB8190_Config_ParaFile_Fail;
+
+       /*  */
+       /*  3. BB AGC table Initialization */
+       /*  */
+       if (HAL_STATUS_FAILURE == ODM_ConfigBBWithHeaderFile23a(&pHalData->odmpriv,
+                                                            CONFIG_BB_AGC_TAB))
+               rtStatus = _FAIL;
+
+phy_BB8190_Config_ParaFile_Fail:
+
+       return rtStatus;
+}
+
+int
+PHY_BBConfig8723A(struct rtw_adapter *Adapter)
+{
+       int rtStatus = _SUCCESS;
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
+       u8 TmpU1B = 0;
+       u8 CrystalCap;
+
+       phy_InitBBRFRegisterDefinition(Adapter);
+
+       /*  Suggested by Scott. tynli_test. 2010.12.30. */
+       /* 1. 0x28[1] = 1 */
+       TmpU1B = rtw_read8(Adapter, REG_AFE_PLL_CTRL);
+       udelay(2);
+       rtw_write8(Adapter, REG_AFE_PLL_CTRL, (TmpU1B|BIT1));
+       udelay(2);
+
+       /* 2. 0x29[7:0] = 0xFF */
+       rtw_write8(Adapter, REG_AFE_PLL_CTRL+1, 0xff);
+       udelay(2);
+
+       /* 3. 0x02[1:0] = 2b'11 */
+       TmpU1B = rtw_read8(Adapter, REG_SYS_FUNC_EN);
+       rtw_write8(Adapter, REG_SYS_FUNC_EN,
+                  (TmpU1B | FEN_BB_GLB_RSTn | FEN_BBRSTB));
+
+       /* 4. 0x25[6] = 0 */
+       TmpU1B = rtw_read8(Adapter, REG_AFE_XTAL_CTRL + 1);
+       rtw_write8(Adapter, REG_AFE_XTAL_CTRL+1, (TmpU1B & (~BIT6)));
+
+       /* 5. 0x24[20] = 0      Advised by SD3 Alex Wang. 2011.02.09. */
+       TmpU1B = rtw_read8(Adapter, REG_AFE_XTAL_CTRL+2);
+       rtw_write8(Adapter, REG_AFE_XTAL_CTRL+2, (TmpU1B & (~BIT4)));
+
+       /* 6. 0x1f[7:0] = 0x07 */
+       rtw_write8(Adapter, REG_RF_CTRL, 0x07);
+
+       /*  */
+       /*  Config BB and AGC */
+       /*  */
+       rtStatus = phy_BB8723a_Config_ParaFile(Adapter);
+
+/* only for B-cut */
+       if (pHalData->EEPROMVersion >= 0x01) {
+               CrystalCap = pHalData->CrystalCap & 0x3F;
+               PHY_SetBBReg(Adapter, REG_MAC_PHY_CTRL, 0xFFF000,
+                            (CrystalCap | (CrystalCap << 6)));
+       }
+
+       PHY_SetBBReg(Adapter, REG_LDOA15_CTRL, bMaskDWord, 0x01572505);
+       return rtStatus;
+}
+
+int
+PHY_RFConfig8723A(struct rtw_adapter *Adapter)
+{
+       int rtStatus = _SUCCESS;
+
+       /*  */
+       /*  RF config */
+       /*  */
+       rtStatus = PHY_RF6052_Config8723A(Adapter);
+       return rtStatus;
+}
+
+static void getTxPowerIndex(struct rtw_adapter *Adapter,
+                           u8 channel, u8 *cckPowerLevel,  u8 *ofdmPowerLevel)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       u8 index = (channel - 1);
+       /*  1. CCK */
+       cckPowerLevel[RF_PATH_A] = pHalData->TxPwrLevelCck[RF_PATH_A][index];
+       cckPowerLevel[RF_PATH_B] = pHalData->TxPwrLevelCck[RF_PATH_B][index];
+
+       /*  2. OFDM for 1S or 2S */
+       if (GET_RF_TYPE(Adapter) == RF_1T2R || GET_RF_TYPE(Adapter) == RF_1T1R) {
+               /*  Read HT 40 OFDM TX power */
+               ofdmPowerLevel[RF_PATH_A] =
+                       pHalData->TxPwrLevelHT40_1S[RF_PATH_A][index];
+               ofdmPowerLevel[RF_PATH_B] =
+                       pHalData->TxPwrLevelHT40_1S[RF_PATH_B][index];
+       } else if (GET_RF_TYPE(Adapter) == RF_2T2R) {
+               /*  Read HT 40 OFDM TX power */
+               ofdmPowerLevel[RF_PATH_A] =
+                       pHalData->TxPwrLevelHT40_2S[RF_PATH_A][index];
+               ofdmPowerLevel[RF_PATH_B] =
+                       pHalData->TxPwrLevelHT40_2S[RF_PATH_B][index];
+       }
+}
+
+static void ccxPowerIndexCheck(struct rtw_adapter *Adapter, u8 channel,
+                              u8 *cckPowerLevel, u8 *ofdmPowerLevel)
+{
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:    SetTxPowerLevel8723A()
+ *
+ * Overview:    This function is export to "HalCommon" moudule
+ *                     We must consider RF path later!!!!!!!
+ *
+ * Input:       struct rtw_adapter *           Adapter
+ *                     u8              channel
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ *---------------------------------------------------------------------------*/
+void PHY_SetTxPowerLevel8723A(struct rtw_adapter *Adapter, u8 channel)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       u8 cckPowerLevel[2], ofdmPowerLevel[2]; /*  [0]:RF-A, [1]:RF-B */
+
+       if (pHalData->bTXPowerDataReadFromEEPORM == false)
+               return;
+
+       getTxPowerIndex(Adapter, channel, &cckPowerLevel[0],
+                       &ofdmPowerLevel[0]);
+
+       ccxPowerIndexCheck(Adapter, channel, &cckPowerLevel[0],
+                          &ofdmPowerLevel[0]);
+
+       rtl823a_phy_rf6052setccktxpower(Adapter, &cckPowerLevel[0]);
+       rtl8723a_PHY_RF6052SetOFDMTxPower(Adapter, &ofdmPowerLevel[0], channel);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:    PHY_SetBWMode23aCallback8192C()
+ *
+ * Overview:    Timer callback function for SetSetBWMode23a
+ *
+ * Input:              PRT_TIMER               pTimer
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Note:
+ *     (1) We do not take j mode into consideration now
+ *     (2) Will two workitem of "switch channel" and
+ *         "switch channel bandwidth" run concurrently?
+ *---------------------------------------------------------------------------*/
+static void
+_PHY_SetBWMode23a92C(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       u8 regBwOpMode;
+       u8 regRRSR_RSC;
+
+       if (pHalData->rf_chip == RF_PSEUDO_11N)
+               return;
+
+       /*  There is no 40MHz mode in RF_8225. */
+       if (pHalData->rf_chip == RF_8225)
+               return;
+
+       if (Adapter->bDriverStopped)
+               return;
+
+       /* 3 */
+       /* 3<1>Set MAC register */
+       /* 3 */
+
+       regBwOpMode = rtw_read8(Adapter, REG_BWOPMODE);
+       regRRSR_RSC = rtw_read8(Adapter, REG_RRSR+2);
+
+       switch (pHalData->CurrentChannelBW) {
+       case HT_CHANNEL_WIDTH_20:
+               regBwOpMode |= BW_OPMODE_20MHZ;
+               rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode);
+               break;
+       case HT_CHANNEL_WIDTH_40:
+               regBwOpMode &= ~BW_OPMODE_20MHZ;
+               rtw_write8(Adapter, REG_BWOPMODE, regBwOpMode);
+               regRRSR_RSC = (regRRSR_RSC & 0x90) |
+                       (pHalData->nCur40MhzPrimeSC << 5);
+               rtw_write8(Adapter, REG_RRSR+2, regRRSR_RSC);
+               break;
+
+       default:
+               break;
+       }
+
+       /* 3 */
+       /* 3<2>Set PHY related register */
+       /* 3 */
+       switch (pHalData->CurrentChannelBW) {
+               /* 20 MHz channel*/
+       case HT_CHANNEL_WIDTH_20:
+               PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x0);
+               PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x0);
+               PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter2, BIT10, 1);
+
+               break;
+
+               /* 40 MHz channel*/
+       case HT_CHANNEL_WIDTH_40:
+               PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bRFMOD, 0x1);
+               PHY_SetBBReg(Adapter, rFPGA1_RFMOD, bRFMOD, 0x1);
+
+               /*  Set Control channel to upper or lower. These settings
+                   are required only for 40MHz */
+               PHY_SetBBReg(Adapter, rCCK0_System, bCCKSideBand,
+                            (pHalData->nCur40MhzPrimeSC >> 1));
+               PHY_SetBBReg(Adapter, rOFDM1_LSTF, 0xC00,
+                            pHalData->nCur40MhzPrimeSC);
+               PHY_SetBBReg(Adapter, rFPGA0_AnalogParameter2, BIT10, 0);
+
+               PHY_SetBBReg(Adapter, 0x818, (BIT26 | BIT27),
+                            (pHalData->nCur40MhzPrimeSC ==
+                             HAL_PRIME_CHNL_OFFSET_LOWER) ? 2:1);
+               break;
+
+       default:
+               /*RT_TRACE(COMP_DBG, DBG_LOUD,
+                 ("PHY_SetBWMode23aCallback8192C(): unknown Bandwidth: %#X\n" \
+                 , pHalData->CurrentChannelBW));*/
+                       break;
+       }
+       /* Skip over setting of J-mode in BB register here. Default value
+          is "None J mode". Emily 20070315 */
+
+       /*  Added it for 20/40 mhz switch time evaluation by guangan 070531 */
+       /* NowL = PlatformEFIORead4Byte(Adapter, TSFR); */
+       /* NowH = PlatformEFIORead4Byte(Adapter, TSFR+4); */
+       /* EndTime = ((u64)NowH << 32) + NowL; */
+       /* RT_TRACE(COMP_SCAN, DBG_LOUD, ("SetBWMode23aCallback8190Pci: time
+          of SetBWMode23a = %I64d us!\n", (EndTime - BeginTime))); */
+
+       /* 3<3>Set RF related register */
+       switch (pHalData->rf_chip) {
+       case RF_8225:
+               /* PHY_SetRF8225Bandwidth(Adapter,
+                  pHalData->CurrentChannelBW); */
+               break;
+
+       case RF_8256:
+               /*  Please implement this function in Hal8190PciPhy8256.c */
+               /* PHY_SetRF8256Bandwidth(Adapter,
+                  pHalData->CurrentChannelBW); */
+               break;
+
+       case RF_8258:
+               /*  Please implement this function in Hal8190PciPhy8258.c */
+               /*  PHY_SetRF8258Bandwidth(); */
+               break;
+
+       case RF_PSEUDO_11N:
+               /*  Do Nothing */
+               break;
+
+       case RF_6052:
+               rtl8723a_phy_rf6052set_bw(Adapter, pHalData->CurrentChannelBW);
+               break;
+
+       default:
+               /* RT_ASSERT(false, ("Unknown RFChipID: %d\n",
+                  pHalData->RFChipID)); */
+               break;
+       }
+
+       /* pHalData->SetBWMode23aInProgress = false; */
+
+       /* RT_TRACE(COMP_SCAN, DBG_LOUD,
+          ("<== PHY_SetBWMode23aCallback8192C() \n")); */
+}
+
+ /*-----------------------------------------------------------------------------
+ * Function:   SetBWMode23a8190Pci()
+ *
+ * Overview:  This function is export to "HalCommon" moudule
+ *
+ * Input:              struct rtw_adapter *                    Adapter
+ *                     enum ht_channel_width   Bandwidth       20M or 40M
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Note:               We do not take j mode into consideration now
+ *---------------------------------------------------------------------------*/
+void
+PHY_SetBWMode23a8723A(struct rtw_adapter *Adapter,
+                  enum ht_channel_width Bandwidth, unsigned char Offset)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       enum ht_channel_width tmpBW = pHalData->CurrentChannelBW;
+
+       pHalData->CurrentChannelBW = Bandwidth;
+
+       pHalData->nCur40MhzPrimeSC = Offset;
+
+       if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved))
+               _PHY_SetBWMode23a92C(Adapter);
+       else
+               pHalData->CurrentChannelBW = tmpBW;
+}
+
+static void _PHY_SwChnl8723A(struct rtw_adapter *Adapter, u8 channel)
+{
+       u8 eRFPath;
+       u32 param1, param2;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+
+       if (Adapter->bNotifyChannelChange)
+               DBG_8723A("[%s] ch = %d\n", __FUNCTION__, channel);
+
+       /* s1. pre common command - CmdID_SetTxPowerLevel */
+       PHY_SetTxPowerLevel8723A(Adapter, channel);
+
+       /* s2. RF dependent command - CmdID_RF_WriteReg,
+          param1 = RF_CHNLBW, param2 = channel */
+       param1 = RF_CHNLBW;
+       param2 = channel;
+       for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
+               pHalData->RfRegChnlVal[eRFPath] =
+                       (pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2;
+               PHY_SetRFReg(Adapter, (enum RF_RADIO_PATH)eRFPath, param1,
+                            bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]);
+       }
+
+       /* s3. post common command - CmdID_End, None */
+}
+
+void PHY_SwChnl8723A(struct rtw_adapter *Adapter, u8 channel)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       u8 tmpchannel = pHalData->CurrentChannel;
+       bool  result = true;
+
+       if (pHalData->rf_chip == RF_PSEUDO_11N) {
+               /* return immediately if it is peudo-phy */
+               return;
+       }
+
+       if (channel == 0)
+               channel = 1;
+
+       pHalData->CurrentChannel = channel;
+
+       if ((!Adapter->bDriverStopped) && (!Adapter->bSurpriseRemoved)) {
+               _PHY_SwChnl8723A(Adapter, channel);
+
+               if (!result)
+                       pHalData->CurrentChannel = tmpchannel;
+       } else {
+               pHalData->CurrentChannel = tmpchannel;
+       }
+}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c b/drivers/staging/rtl8723au/hal/rtl8723a_rf6052.c
new file mode 100644 (file)
index 0000000..ed39c18
--- /dev/null
@@ -0,0 +1,507 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+/******************************************************************************
+ *
+ *
+ * Module:     rtl8192c_rf6052.c       (Source C File)
+ *
+ * Note:       Provide RF 6052 series relative API.
+ *
+ * Function:
+ *
+ * Export:
+ *
+ * Abbrev:
+ *
+ * History:
+ * Data                        Who             Remark
+ *
+ * 09/25/2008  MHC             Create initial version.
+ * 11/05/2008  MHC             Add API for tw power setting.
+ *
+ *
+******************************************************************************/
+
+#define _RTL8723A_RF6052_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <rtl8723a_hal.h>
+
+/*---------------------------Define Local Constant---------------------------*/
+/*  Define local structure for debug!!!!! */
+struct rf_shadow_compare_map {
+       /*  Shadow register value */
+       u32             Value;
+       /*  Compare or not flag */
+       u8              Compare;
+       /*  Record If it had ever modified unpredicted */
+       u8              ErrorOrNot;
+       /*  Recorver Flag */
+       u8              Recorver;
+       /*  */
+       u8              Driver_Write;
+};
+
+/*-----------------------------------------------------------------------------
+ * Function:    PHY_RF6052SetBandwidth()
+ *
+ * Overview:    This function is called by SetBWMode23aCallback8190Pci() only
+ *
+ * Input:       struct rtw_adapter *                           Adapter
+ *                     WIRELESS_BANDWIDTH_E    Bandwidth       20M or 40M
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Note:               For RF type 0222D
+ *---------------------------------------------------------------------------*/
+void rtl8723a_phy_rf6052set_bw(
+       struct rtw_adapter *Adapter,
+       enum ht_channel_width Bandwidth)        /* 20M or 40M */
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
+
+       switch (Bandwidth) {
+       case HT_CHANNEL_WIDTH_20:
+               pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff) | 0x0400);
+               PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]);
+               break;
+       case HT_CHANNEL_WIDTH_40:
+               pHalData->RfRegChnlVal[0] = ((pHalData->RfRegChnlVal[0] & 0xfffff3ff));
+               PHY_SetRFReg(Adapter, RF_PATH_A, RF_CHNLBW, bRFRegOffsetMask, pHalData->RfRegChnlVal[0]);
+               break;
+       default:
+               break;
+       }
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:   PHY_RF6052SetCckTxPower
+ *
+ * Overview:
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 11/05/2008  MHC             Simulate 8192series..
+ *
+ *---------------------------------------------------------------------------*/
+
+void rtl823a_phy_rf6052setccktxpower(struct rtw_adapter *Adapter, u8 *pPowerlevel)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv *pdmpriv = &pHalData->dmpriv;
+       struct mlme_ext_priv *pmlmeext = &Adapter->mlmeextpriv;
+       u32 TxAGC[2] = {0, 0}, tmpval = 0;
+       bool TurboScanOff = false;
+       u8 idx1, idx2;
+       u8 *ptr;
+
+       /*  According to SD3 eechou's suggestion, we need to disable turbo scan for RU. */
+       /*  Otherwise, external PA will be broken if power index > 0x20. */
+       if (pHalData->EEPROMRegulatory != 0 || pHalData->ExternalPA)
+               TurboScanOff = true;
+
+       if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
+               TxAGC[RF_PATH_A] = 0x3f3f3f3f;
+               TxAGC[RF_PATH_B] = 0x3f3f3f3f;
+
+               TurboScanOff = true;/* disable turbo scan */
+
+               if (TurboScanOff) {
+                       for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
+                               TxAGC[idx1] =
+                                       pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) |
+                                       (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24);
+                               /*  2010/10/18 MH For external PA module. We need to limit power index to be less than 0x20. */
+                               if (TxAGC[idx1] > 0x20 && pHalData->ExternalPA)
+                                       TxAGC[idx1] = 0x20;
+                       }
+               }
+       } else {
+/*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
+/*  Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
+/*  In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. */
+               if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1) {
+                       TxAGC[RF_PATH_A] = 0x10101010;
+                       TxAGC[RF_PATH_B] = 0x10101010;
+               } else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2) {
+                       TxAGC[RF_PATH_A] = 0x00000000;
+                       TxAGC[RF_PATH_B] = 0x00000000;
+               } else {
+                       for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
+                               TxAGC[idx1] =
+                                       pPowerlevel[idx1] | (pPowerlevel[idx1]<<8) |
+                                       (pPowerlevel[idx1]<<16) | (pPowerlevel[idx1]<<24);
+                       }
+
+                       if (pHalData->EEPROMRegulatory == 0) {
+                               tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][6]) +
+                                               (pHalData->MCSTxPowerLevelOriginalOffset[0][7]<<8);
+                               TxAGC[RF_PATH_A] += tmpval;
+
+                               tmpval = (pHalData->MCSTxPowerLevelOriginalOffset[0][14]) +
+                                               (pHalData->MCSTxPowerLevelOriginalOffset[0][15]<<24);
+                               TxAGC[RF_PATH_B] += tmpval;
+                       }
+               }
+       }
+
+       for (idx1 = RF_PATH_A; idx1 <= RF_PATH_B; idx1++) {
+               ptr = (u8 *)(&TxAGC[idx1]);
+               for (idx2 = 0; idx2 < 4; idx2++) {
+                       if (*ptr > RF6052_MAX_TX_PWR)
+                               *ptr = RF6052_MAX_TX_PWR;
+                       ptr++;
+               }
+       }
+
+       /*  rf-A cck tx power */
+       tmpval = TxAGC[RF_PATH_A]&0xff;
+       PHY_SetBBReg(Adapter, rTxAGC_A_CCK1_Mcs32, bMaskByte1, tmpval);
+       tmpval = TxAGC[RF_PATH_A]>>8;
+       PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+       /*  rf-B cck tx power */
+       tmpval = TxAGC[RF_PATH_B]>>24;
+       PHY_SetBBReg(Adapter, rTxAGC_B_CCK11_A_CCK2_11, bMaskByte0, tmpval);
+       tmpval = TxAGC[RF_PATH_B]&0x00ffffff;
+       PHY_SetBBReg(Adapter, rTxAGC_B_CCK1_55_Mcs32, 0xffffff00, tmpval);
+}      /* PHY_RF6052SetCckTxPower */
+
+/*  powerbase0 for OFDM rates */
+/*  powerbase1 for HT MCS rates */
+static void getPowerBase(
+       struct rtw_adapter *Adapter,
+       u8 *pPowerLevel,
+       u8 Channel,
+       u32 *OfdmBase,
+       u32 *MCSBase
+       )
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
+       u32 powerBase0, powerBase1;
+       u8 Legacy_pwrdiff = 0;
+       s8 HT20_pwrdiff = 0;
+       u8 i, powerlevel[2];
+
+       for (i = 0; i < 2; i++) {
+               powerlevel[i] = pPowerLevel[i];
+               Legacy_pwrdiff = pHalData->TxPwrLegacyHtDiff[i][Channel-1];
+               powerBase0 = powerlevel[i] + Legacy_pwrdiff;
+
+               powerBase0 = (powerBase0<<24) | (powerBase0<<16) | (powerBase0<<8) | powerBase0;
+               *(OfdmBase+i) = powerBase0;
+       }
+
+       for (i = 0; i < 2; i++) {
+               /* Check HT20 to HT40 diff */
+               if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20) {
+                       HT20_pwrdiff = pHalData->TxPwrHt20Diff[i][Channel-1];
+                       powerlevel[i] += HT20_pwrdiff;
+               }
+               powerBase1 = powerlevel[i];
+               powerBase1 = (powerBase1<<24) | (powerBase1<<16) | (powerBase1<<8) | powerBase1;
+               *(MCSBase+i) = powerBase1;
+       }
+}
+
+static void getTxPowerWriteValByRegulatory(
+               struct rtw_adapter *Adapter,
+               u8 Channel,
+               u8 index,
+               u32 *powerBase0,
+               u32 *powerBase1,
+               u32 *pOutWriteVal
+       )
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
+       struct dm_priv  *pdmpriv = &pHalData->dmpriv;
+       u8      i, chnlGroup = 0, pwr_diff_limit[4];
+       u32     writeVal, customer_limit, rf;
+
+       /*  Index 0 & 1 = legacy OFDM, 2-5 = HT_MCS rate */
+       for (rf = 0; rf < 2; rf++) {
+               switch (pHalData->EEPROMRegulatory) {
+               case 0: /*  Realtek better performance */
+                       /*  increase power diff defined by Realtek for large power */
+                       chnlGroup = 0;
+                       writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
+                               ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+                       break;
+               case 1: /*  Realtek regulatory */
+                       /*  increase power diff defined by Realtek for regulatory */
+                       if (pHalData->pwrGroupCnt == 1)
+                               chnlGroup = 0;
+                       if (pHalData->pwrGroupCnt >= 3) {
+                               if (Channel <= 3)
+                                       chnlGroup = 0;
+                               else if (Channel >= 4 && Channel <= 9)
+                                       chnlGroup = 1;
+                               else if (Channel > 9)
+                                       chnlGroup = 2;
+
+                               if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
+                                       chnlGroup++;
+                               else
+                                       chnlGroup += 4;
+                       }
+                       writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
+                                  ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+                       break;
+               case 2: /*  Better regulatory */
+                               /*  don't increase any power diff */
+                       writeVal = ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+                       break;
+               case 3: /*  Customer defined power diff. */
+                       chnlGroup = 0;
+
+                       for (i = 0; i < 4; i++) {
+                               pwr_diff_limit[i] = (u8)((pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index +
+                                                   (rf ? 8 : 0)]&(0x7f << (i*8))) >> (i*8));
+                               if (pHalData->CurrentChannelBW == HT_CHANNEL_WIDTH_40) {
+                                       if (pwr_diff_limit[i] > pHalData->PwrGroupHT40[rf][Channel-1])
+                                               pwr_diff_limit[i] = pHalData->PwrGroupHT40[rf][Channel-1];
+                               } else {
+                                       if (pwr_diff_limit[i] > pHalData->PwrGroupHT20[rf][Channel-1])
+                                               pwr_diff_limit[i] = pHalData->PwrGroupHT20[rf][Channel-1];
+                               }
+                       }
+                       customer_limit = (pwr_diff_limit[3]<<24) | (pwr_diff_limit[2]<<16) |
+                                                       (pwr_diff_limit[1]<<8) | (pwr_diff_limit[0]);
+                       writeVal = customer_limit + ((index<2)?powerBase0[rf]:powerBase1[rf]);
+                       break;
+               default:
+                       chnlGroup = 0;
+                       writeVal = pHalData->MCSTxPowerLevelOriginalOffset[chnlGroup][index+(rf?8:0)] +
+                                       ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+                       break;
+               }
+
+/*  20100427 Joseph: Driver dynamic Tx power shall not affect Tx power. It shall be determined by power training mechanism. */
+/*  Currently, we cannot fully disable driver dynamic tx power mechanism because it is referenced by BT coexist mechanism. */
+/*  In the future, two mechanism shall be separated from each other and maintained independantly. Thanks for Lanhsin's reminder. */
+
+               if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level1)
+                       writeVal = 0x14141414;
+               else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_Level2)
+                       writeVal = 0x00000000;
+
+               /*  20100628 Joseph: High power mode for BT-Coexist mechanism. */
+               /*  This mechanism is only applied when Driver-Highpower-Mechanism is OFF. */
+               if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT1)
+                       writeVal = writeVal - 0x06060606;
+               else if (pdmpriv->DynamicTxHighPowerLvl == TxHighPwrLevel_BT2)
+                       writeVal = writeVal;
+               *(pOutWriteVal+rf) = writeVal;
+       }
+}
+
+static void writeOFDMPowerReg(struct rtw_adapter *Adapter, u8 index, u32 *pValue)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
+       u16 RegOffset_A[6] = {
+               rTxAGC_A_Rate18_06, rTxAGC_A_Rate54_24,
+               rTxAGC_A_Mcs03_Mcs00, rTxAGC_A_Mcs07_Mcs04,
+               rTxAGC_A_Mcs11_Mcs08, rTxAGC_A_Mcs15_Mcs12
+       };
+       u16 RegOffset_B[6] = {
+               rTxAGC_B_Rate18_06, rTxAGC_B_Rate54_24,
+               rTxAGC_B_Mcs03_Mcs00, rTxAGC_B_Mcs07_Mcs04,
+               rTxAGC_B_Mcs11_Mcs08, rTxAGC_B_Mcs15_Mcs12
+       };
+       u8 i, rf, pwr_val[4];
+       u32 writeVal;
+       u16 RegOffset;
+
+       for (rf = 0; rf < 2; rf++) {
+               writeVal = pValue[rf];
+               for (i = 0; i < 4; i++) {
+                       pwr_val[i] = (u8)((writeVal & (0x7f<<(i*8)))>>(i*8));
+                       if (pwr_val[i]  > RF6052_MAX_TX_PWR)
+                               pwr_val[i]  = RF6052_MAX_TX_PWR;
+               }
+               writeVal = (pwr_val[3]<<24) | (pwr_val[2]<<16) |
+                          (pwr_val[1]<<8) | pwr_val[0];
+
+               if (rf == 0)
+                       RegOffset = RegOffset_A[index];
+               else
+                       RegOffset = RegOffset_B[index];
+
+               PHY_SetBBReg(Adapter, RegOffset, bMaskDWord, writeVal);
+
+               /*  201005115 Joseph: Set Tx Power diff for Tx power training mechanism. */
+               if (((pHalData->rf_type == RF_2T2R) &&
+                   (RegOffset == rTxAGC_A_Mcs15_Mcs12 ||
+                    RegOffset == rTxAGC_B_Mcs15_Mcs12)) ||
+                   ((pHalData->rf_type != RF_2T2R) &&
+                    (RegOffset == rTxAGC_A_Mcs07_Mcs04 ||
+                     RegOffset == rTxAGC_B_Mcs07_Mcs04))) {
+                       writeVal = pwr_val[3];
+                       if (RegOffset == rTxAGC_A_Mcs15_Mcs12 || RegOffset == rTxAGC_A_Mcs07_Mcs04)
+                               RegOffset = 0xc90;
+                       if (RegOffset == rTxAGC_B_Mcs15_Mcs12 || RegOffset == rTxAGC_B_Mcs07_Mcs04)
+                               RegOffset = 0xc98;
+                       for (i = 0; i < 3; i++) {
+                               if (i != 2)
+                                       writeVal = (writeVal > 8) ? (writeVal-8) : 0;
+                               else
+                                       writeVal = (writeVal > 6) ? (writeVal-6) : 0;
+                               rtw_write8(Adapter, (u32)(RegOffset+i), (u8)writeVal);
+                       }
+               }
+       }
+}
+/*-----------------------------------------------------------------------------
+ * Function:   PHY_RF6052SetOFDMTxPower
+ *
+ * Overview:   For legacy and HY OFDM, we must read EEPROM TX power index for
+ *                     different channel and read original value in TX power register area from
+ *                     0xe00. We increase offset and original value to be correct tx pwr.
+ *
+ * Input:       NONE
+ *
+ * Output:      NONE
+ *
+ * Return:      NONE
+ *
+ * Revised History:
+ * When                        Who             Remark
+ * 11/05/2008  MHC             Simulate 8192 series method.
+ * 01/06/2009  MHC             1. Prevent Path B tx power overflow or underflow dure to
+ *                                             A/B pwr difference or legacy/HT pwr diff.
+ *                                             2. We concern with path B legacy/HT OFDM difference.
+ * 01/22/2009  MHC             Support new EPRO format from SD3.
+ *
+ *---------------------------------------------------------------------------*/
+void rtl8723a_PHY_RF6052SetOFDMTxPower(struct rtw_adapter *Adapter, u8 *pPowerLevel, u8 Channel)
+{
+       u32 writeVal[2], powerBase0[2], powerBase1[2];
+       u8 index = 0;
+
+       getPowerBase(Adapter, pPowerLevel, Channel, &powerBase0[0], &powerBase1[0]);
+
+       for (index = 0; index < 6; index++) {
+               getTxPowerWriteValByRegulatory(Adapter, Channel, index,
+                       &powerBase0[0], &powerBase1[0], &writeVal[0]);
+
+               writeOFDMPowerReg(Adapter, index, &writeVal[0]);
+       }
+}
+
+static int phy_RF6052_Config_ParaFile(struct rtw_adapter *Adapter)
+{
+       u32 u4RegValue = 0;
+       u8 eRFPath;
+       struct bb_reg_define    *pPhyReg;
+       int rtStatus = _SUCCESS;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       static char sz8723RadioAFile[] = RTL8723_PHY_RADIO_A;
+       static char sz8723RadioBFile[] = RTL8723_PHY_RADIO_B;
+       char *pszRadioAFile, *pszRadioBFile;
+
+       pszRadioAFile = sz8723RadioAFile;
+       pszRadioBFile = sz8723RadioBFile;
+
+       /* 3----------------------------------------------------------------- */
+       /* 3 <2> Initialize RF */
+       /* 3----------------------------------------------------------------- */
+       for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
+
+               pPhyReg = &pHalData->PHYRegDef[eRFPath];
+
+               /*----Store original RFENV control type----*/
+               switch (eRFPath) {
+               case RF_PATH_A:
+                       u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV);
+                       break;
+               case RF_PATH_B:
+                       u4RegValue = PHY_QueryBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16);
+                       break;
+               }
+
+               /*----Set RF_ENV enable----*/
+               PHY_SetBBReg(Adapter, pPhyReg->rfintfe, bRFSI_RFENV<<16, 0x1);
+               udelay(1);/* PlatformStallExecution(1); */
+
+               /*----Set RF_ENV output high----*/
+               PHY_SetBBReg(Adapter, pPhyReg->rfintfo, bRFSI_RFENV, 0x1);
+               udelay(1);/* PlatformStallExecution(1); */
+
+               /* Set bit number of Address and Data for RF register */
+               PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireAddressLength, 0x0);  /*  Set 1 to 4 bits for 8255 */
+               udelay(1);/* PlatformStallExecution(1); */
+
+               PHY_SetBBReg(Adapter, pPhyReg->rfHSSIPara2, b3WireDataLength, 0x0);     /*  Set 0 to 12  bits for 8255 */
+               udelay(1);/* PlatformStallExecution(1); */
+
+               /*----Initialize RF fom connfiguration file----*/
+               switch (eRFPath) {
+               case RF_PATH_A:
+                       if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile23a(&pHalData->odmpriv, (enum RF_RADIO_PATH)eRFPath, (enum RF_RADIO_PATH)eRFPath))
+                               rtStatus = _FAIL;
+                       break;
+               case RF_PATH_B:
+                       if (HAL_STATUS_FAILURE == ODM_ConfigRFWithHeaderFile23a(&pHalData->odmpriv, (enum RF_RADIO_PATH)eRFPath, (enum RF_RADIO_PATH)eRFPath))
+                               rtStatus = _FAIL;
+                       break;
+               }
+
+               /*----Restore RFENV control type----*/;
+               switch (eRFPath) {
+               case RF_PATH_A:
+                       PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV, u4RegValue);
+                       break;
+               case RF_PATH_B:
+                       PHY_SetBBReg(Adapter, pPhyReg->rfintfs, bRFSI_RFENV<<16, u4RegValue);
+                       break;
+               }
+
+               if (rtStatus != _SUCCESS) {
+                       /* RT_TRACE(COMP_FPGA, DBG_LOUD, ("phy_RF6052_Config_ParaFile():Radio[%d] Fail!!", eRFPath)); */
+                       goto phy_RF6052_Config_ParaFile_Fail;
+               }
+       }
+phy_RF6052_Config_ParaFile_Fail:
+       return rtStatus;
+}
+
+int PHY_RF6052_Config8723A(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       int rtStatus = _SUCCESS;
+
+       /*  Initialize general global value */
+       /*  TODO: Extend RF_PATH_C and RF_PATH_D in the future */
+       if (pHalData->rf_type == RF_1T1R)
+               pHalData->NumTotalRFPath = 1;
+       else
+               pHalData->NumTotalRFPath = 2;
+
+       /*  Config BB and RF */
+       rtStatus = phy_RF6052_Config_ParaFile(Adapter);
+       return rtStatus;
+}
+
+/* End of HalRf6052.c */
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_rxdesc.c b/drivers/staging/rtl8723au/hal/rtl8723a_rxdesc.c
new file mode 100644 (file)
index 0000000..81b5efe
--- /dev/null
@@ -0,0 +1,69 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTL8723A_REDESC_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtl8723a_hal.h>
+
+static void process_rssi(struct rtw_adapter *padapter,
+                        struct recv_frame *prframe)
+{
+       struct rx_pkt_attrib *pattrib = &prframe->attrib;
+       struct signal_stat *signal_stat = &padapter->recvpriv.signal_strength_data;
+
+       if (signal_stat->update_req) {
+               signal_stat->total_num = 0;
+               signal_stat->total_val = 0;
+               signal_stat->update_req = 0;
+       }
+
+       signal_stat->total_num++;
+       signal_stat->total_val  += pattrib->phy_info.SignalStrength;
+       signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num;
+}
+
+static void process_link_qual(struct rtw_adapter *padapter,
+                             struct recv_frame *prframe)
+{
+       struct rx_pkt_attrib *pattrib;
+       struct signal_stat *signal_stat;
+
+       if (prframe == NULL || padapter == NULL)
+               return;
+
+       pattrib = &prframe->attrib;
+       signal_stat = &padapter->recvpriv.signal_qual_data;
+
+       if (signal_stat->update_req) {
+               signal_stat->total_num = 0;
+               signal_stat->total_val = 0;
+               signal_stat->update_req = 0;
+       }
+
+       signal_stat->total_num++;
+       signal_stat->total_val  += pattrib->phy_info.SignalQuality;
+       signal_stat->avg_val = signal_stat->total_val / signal_stat->total_num;
+}
+
+/* void rtl8723a_process_phy_info(struct rtw_adapter *padapter, union recv_frame *prframe) */
+void rtl8723a_process_phy_info(struct rtw_adapter *padapter, void *prframe)
+{
+       struct recv_frame *precvframe = prframe;
+       /*  Check RSSI */
+       process_rssi(padapter, precvframe);
+       /*  Check EVM */
+       process_link_qual(padapter,  precvframe);
+}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_sreset.c b/drivers/staging/rtl8723au/hal/rtl8723a_sreset.c
new file mode 100644 (file)
index 0000000..c0218e7
--- /dev/null
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTL8723A_SRESET_C_
+
+#include <rtl8723a_sreset.h>
+#include <rtl8723a_hal.h>
+
+void rtl8723a_sreset_xmit_status_check(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+       unsigned long current_time;
+       struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
+       unsigned int diff_time;
+       u32 txdma_status;
+
+       txdma_status = rtw_read32(padapter, REG_TXDMA_STATUS);
+       if (txdma_status != 0) {
+               DBG_8723A("%s REG_TXDMA_STATUS:0x%08x\n", __func__, txdma_status);
+               rtw_hal_sreset_reset23a(padapter);
+       }
+
+       current_time = jiffies;
+
+       if (0 == pxmitpriv->free_xmitbuf_cnt || 0 == pxmitpriv->free_xmit_extbuf_cnt) {
+
+               diff_time = jiffies_to_msecs(jiffies - psrtpriv->last_tx_time);
+
+               if (diff_time > 2000) {
+                       if (psrtpriv->last_tx_complete_time == 0) {
+                               psrtpriv->last_tx_complete_time = current_time;
+                       } else {
+                               diff_time = jiffies_to_msecs(jiffies - psrtpriv->last_tx_complete_time);
+                               if (diff_time > 4000) {
+                                       /* padapter->Wifi_Error_Status = WIFI_TX_HANG; */
+                                       DBG_8723A("%s tx hang\n", __func__);
+                                       rtw_hal_sreset_reset23a(padapter);
+                               }
+                       }
+               }
+       }
+
+       if (psrtpriv->dbg_trigger_point == SRESET_TGP_XMIT_STATUS) {
+               psrtpriv->dbg_trigger_point = SRESET_TGP_NULL;
+               rtw_hal_sreset_reset23a(padapter);
+               return;
+       }
+}
+
+void rtl8723a_sreset_linked_status_check(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct sreset_priv *psrtpriv = &pHalData->srestpriv;
+
+       if (psrtpriv->dbg_trigger_point == SRESET_TGP_LINK_STATUS) {
+               psrtpriv->dbg_trigger_point = SRESET_TGP_NULL;
+               rtw_hal_sreset_reset23a(padapter);
+               return;
+       }
+}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_xmit.c b/drivers/staging/rtl8723au/hal/rtl8723a_xmit.c
new file mode 100644 (file)
index 0000000..d7612cc
--- /dev/null
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTL8723A_XMIT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtl8723a_hal.h>
+
+void dump_txrpt_ccx_8723a(void *buf)
+{
+       struct txrpt_ccx_8723a *txrpt_ccx = buf;
+
+       DBG_8723A("%s:\n"
+               "tag1:%u, rsvd:%u, int_bt:%u, int_tri:%u, int_ccx:%u\n"
+               "mac_id:%u, pkt_drop:%u, pkt_ok:%u, bmc:%u\n"
+               "retry_cnt:%u, lifetime_over:%u, retry_over:%u\n"
+               "ccx_qtime:%u\n"
+               "final_data_rate:0x%02x\n"
+               "qsel:%u, sw:0x%03x\n"
+               , __func__
+               , txrpt_ccx->tag1, txrpt_ccx->rsvd, txrpt_ccx->int_bt, txrpt_ccx->int_tri, txrpt_ccx->int_ccx
+               , txrpt_ccx->mac_id, txrpt_ccx->pkt_drop, txrpt_ccx->pkt_ok, txrpt_ccx->bmc
+               , txrpt_ccx->retry_cnt, txrpt_ccx->lifetime_over, txrpt_ccx->retry_over
+               , txrpt_ccx_qtime_8723a(txrpt_ccx)
+               , txrpt_ccx->final_data_rate
+               , txrpt_ccx->qsel, txrpt_ccx_sw_8723a(txrpt_ccx)
+       );
+}
+
+void handle_txrpt_ccx_8723a(struct rtw_adapter *adapter, void *buf)
+{
+       struct txrpt_ccx_8723a *txrpt_ccx = buf;
+
+       if (txrpt_ccx->int_ccx) {
+               if (txrpt_ccx->pkt_ok)
+                       rtw_ack_tx_done23a(&adapter->xmitpriv, RTW_SCTX_DONE_SUCCESS);
+               else
+                       rtw_ack_tx_done23a(&adapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL);
+       }
+}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_led.c b/drivers/staging/rtl8723au/hal/rtl8723au_led.c
new file mode 100644 (file)
index 0000000..4d5c909
--- /dev/null
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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 "drv_types.h"
+#include "rtl8723a_hal.h"
+#include "rtl8723a_led.h"
+
+/*  */
+/*  LED object. */
+/*  */
+
+/*  */
+/*     Prototype of protected function. */
+/*  */
+
+/*  */
+/*  LED_819xUsb routines. */
+/*  */
+
+/*     Description: */
+/*             Turn on LED according to LedPin specified. */
+void SwLedOn23a(struct rtw_adapter *padapter, struct led_8723a *pLed)
+{
+       u8      LedCfg = 0;
+
+       if ((padapter->bSurpriseRemoved == true) || (padapter->bDriverStopped == true))
+               return;
+       switch (pLed->LedPin) {
+       case LED_PIN_GPIO0:
+               break;
+       case LED_PIN_LED0:
+               rtw_write8(padapter, REG_LEDCFG0, (LedCfg&0xf0)|BIT5|BIT6); /*  SW control led0 on. */
+               break;
+       case LED_PIN_LED1:
+               rtw_write8(padapter, REG_LEDCFG1, (LedCfg&0x00)|BIT6); /*  SW control led1 on. */
+               break;
+       case LED_PIN_LED2:
+               LedCfg = rtw_read8(padapter, REG_LEDCFG2);
+               rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0x80)|BIT5); /*  SW control led1 on. */
+               break;
+       default:
+               break;
+       }
+       pLed->bLedOn = true;
+}
+
+/*     Description: */
+/*             Turn off LED according to LedPin specified. */
+void SwLedOff23a(struct rtw_adapter *padapter, struct led_8723a *pLed)
+{
+       u8      LedCfg = 0;
+       /* struct hal_data_8723a        *pHalData = GET_HAL_DATA(padapter); */
+
+       if ((padapter->bSurpriseRemoved) || (padapter->bDriverStopped))
+               goto exit;
+
+       switch (pLed->LedPin) {
+       case LED_PIN_GPIO0:
+               break;
+       case LED_PIN_LED0:
+               rtw_write8(padapter, REG_LEDCFG0, (LedCfg&0xf0)|BIT5|BIT6); /*  SW control led0 on. */
+               break;
+       case LED_PIN_LED1:
+               rtw_write8(padapter, REG_LEDCFG1, (LedCfg&0x00)|BIT5|BIT6); /*  SW control led1 on. */
+               break;
+       case LED_PIN_LED2:
+               LedCfg = rtw_read8(padapter, REG_LEDCFG2);
+               rtw_write8(padapter, REG_LEDCFG2, (LedCfg&0x80)|BIT3|BIT5); /*  SW control led1 on. */
+               break;
+       default:
+               break;
+       }
+exit:
+       pLed->bLedOn = false;
+}
+
+/*  Interface to manipulate LED objects. */
+
+/*     Description: */
+/*             Initialize all LED_871x objects. */
+void
+rtl8723au_InitSwLeds(struct rtw_adapter        *padapter)
+{
+       struct led_priv *pledpriv = &padapter->ledpriv;
+
+       pledpriv->LedControlHandler = LedControl871x23a;
+       /* 8723as-vau wifi used led2 */
+       InitLed871x23a(padapter, &pledpriv->SwLed0, LED_PIN_LED2);
+
+/*     InitLed871x23a(padapter,&pledpriv->SwLed1, LED_PIN_LED2); */
+}
+
+/*     Description: */
+/*             DeInitialize all LED_819xUsb objects. */
+void
+rtl8723au_DeInitSwLeds(struct rtw_adapter *padapter)
+{
+       struct led_priv *ledpriv = &padapter->ledpriv;
+
+       DeInitLed871x23a(&ledpriv->SwLed0);
+}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_recv.c b/drivers/staging/rtl8723au/hal/rtl8723au_recv.c
new file mode 100644 (file)
index 0000000..213d193
--- /dev/null
@@ -0,0 +1,247 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTL8192CU_RECV_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <mlme_osdep.h>
+#include <linux/ip.h>
+#include <linux/if_ether.h>
+#include <ethernet.h>
+#include <usb_ops.h>
+#include <wifi.h>
+#include <rtl8723a_hal.h>
+
+void rtl8723au_init_recvbuf(struct rtw_adapter *padapter,
+                           struct recv_buf *precvbuf)
+{
+}
+
+int rtl8723au_init_recv_priv(struct rtw_adapter *padapter)
+{
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+       int i, size, res = _SUCCESS;
+       struct recv_buf *precvbuf;
+       unsigned long tmpaddr;
+       unsigned long alignment;
+       struct sk_buff *pskb;
+
+       tasklet_init(&precvpriv->recv_tasklet,
+                    (void(*)(unsigned long))rtl8723au_recv_tasklet,
+                    (unsigned long)padapter);
+
+       precvpriv->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!precvpriv->int_in_urb)
+               DBG_8723A("alloc_urb for interrupt in endpoint fail !!!!\n");
+       precvpriv->int_in_buf = kzalloc(USB_INTR_CONTENT_LENGTH, GFP_KERNEL);
+       if (!precvpriv->int_in_buf)
+               DBG_8723A("alloc_mem for interrupt in endpoint fail !!!!\n");
+
+       /* init recv_buf */
+       _rtw_init_queue23a(&precvpriv->free_recv_buf_queue);
+
+       size = NR_RECVBUFF * sizeof(struct recv_buf);
+       precvpriv->precv_buf = kzalloc(size, GFP_KERNEL);
+       if (!precvpriv->precv_buf) {
+               res = _FAIL;
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                        ("alloc recv_buf fail!\n"));
+               goto exit;
+       }
+
+       precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+
+       for (i = 0; i < NR_RECVBUFF; i++) {
+               INIT_LIST_HEAD(&precvbuf->list);
+
+               res = rtw_os_recvbuf_resource_alloc23a(padapter, precvbuf);
+               if (res == _FAIL)
+                       break;
+
+               precvbuf->adapter = padapter;
+
+               precvbuf++;
+       }
+
+       precvpriv->free_recv_buf_queue_cnt = NR_RECVBUFF;
+
+       skb_queue_head_init(&precvpriv->rx_skb_queue);
+       skb_queue_head_init(&precvpriv->free_recv_skb_queue);
+
+       for (i = 0; i < NR_PREALLOC_RECV_SKB; i++) {
+               size = MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ;
+               pskb = __netdev_alloc_skb(padapter->pnetdev, size, GFP_KERNEL);
+
+               if (pskb) {
+                       pskb->dev = padapter->pnetdev;
+
+                       tmpaddr = (unsigned long)pskb->data;
+                       alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
+                       skb_reserve(pskb, (RECVBUFF_ALIGN_SZ - alignment));
+
+                       skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
+               }
+
+               pskb = NULL;
+       }
+
+exit:
+       return res;
+}
+
+void rtl8723au_free_recv_priv(struct rtw_adapter *padapter)
+{
+       int     i;
+       struct recv_buf *precvbuf;
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+
+       precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+
+       for (i = 0; i < NR_RECVBUFF; i++) {
+               rtw_os_recvbuf_resource_free23a(padapter, precvbuf);
+               precvbuf++;
+       }
+
+       kfree(precvpriv->precv_buf);
+
+       usb_free_urb(precvpriv->int_in_urb);
+       kfree(precvpriv->int_in_buf);
+
+       if (skb_queue_len(&precvpriv->rx_skb_queue))
+               DBG_8723A(KERN_WARNING "rx_skb_queue not empty\n");
+
+       skb_queue_purge(&precvpriv->rx_skb_queue);
+
+       if (skb_queue_len(&precvpriv->free_recv_skb_queue)) {
+               DBG_8723A(KERN_WARNING "free_recv_skb_queue not empty, %d\n",
+                         skb_queue_len(&precvpriv->free_recv_skb_queue));
+       }
+
+       skb_queue_purge(&precvpriv->free_recv_skb_queue);
+}
+
+void update_recvframe_attrib(struct recv_frame *precvframe,
+                            struct recv_stat *prxstat)
+{
+       struct rx_pkt_attrib *pattrib;
+       struct recv_stat report;
+       struct rxreport_8723a *prxreport;
+
+       report.rxdw0 = le32_to_cpu(prxstat->rxdw0);
+       report.rxdw1 = le32_to_cpu(prxstat->rxdw1);
+       report.rxdw2 = le32_to_cpu(prxstat->rxdw2);
+       report.rxdw3 = le32_to_cpu(prxstat->rxdw3);
+       report.rxdw4 = le32_to_cpu(prxstat->rxdw4);
+       report.rxdw5 = le32_to_cpu(prxstat->rxdw5);
+
+       prxreport = (struct rxreport_8723a *)&report;
+
+       pattrib = &precvframe->attrib;
+       memset(pattrib, 0, sizeof(struct rx_pkt_attrib));
+
+       /*  update rx report to recv_frame attribute */
+       pattrib->pkt_len = (u16)prxreport->pktlen;
+       pattrib->drvinfo_sz = (u8)(prxreport->drvinfosize << 3);
+       pattrib->physt = (u8)prxreport->physt;
+
+       pattrib->crc_err = (u8)prxreport->crc32;
+       pattrib->icv_err = (u8)prxreport->icverr;
+
+       pattrib->bdecrypted = (u8)(prxreport->swdec ? 0 : 1);
+       pattrib->encrypt = (u8)prxreport->security;
+
+       pattrib->qos = (u8)prxreport->qos;
+       pattrib->priority = (u8)prxreport->tid;
+
+       pattrib->amsdu = (u8)prxreport->amsdu;
+
+       pattrib->seq_num = (u16)prxreport->seq;
+       pattrib->frag_num = (u8)prxreport->frag;
+       pattrib->mfrag = (u8)prxreport->mf;
+       pattrib->mdata = (u8)prxreport->md;
+
+       pattrib->mcs_rate = (u8)prxreport->rxmcs;
+       pattrib->rxht = (u8)prxreport->rxht;
+}
+
+void update_recvframe_phyinfo(struct recv_frame *precvframe,
+                             struct phy_stat *pphy_status)
+{
+       struct rtw_adapter *padapter = precvframe->adapter;
+       struct rx_pkt_attrib *pattrib = &precvframe->attrib;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct odm_phy_info *pPHYInfo = (struct odm_phy_info *)(&pattrib->phy_info);
+       struct odm_packet_info pkt_info;
+       u8 *sa = NULL, *da;
+       struct sta_priv *pstapriv;
+       struct sta_info *psta;
+       struct sk_buff *skb = precvframe->pkt;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
+       u8 *wlanhdr = skb->data;
+
+       pkt_info.bPacketMatchBSSID = false;
+       pkt_info.bPacketToSelf = false;
+       pkt_info.bPacketBeacon = false;
+
+       pkt_info.bPacketMatchBSSID =
+               (!ieee80211_is_ctl(hdr->frame_control) &&
+                !pattrib->icv_err &&
+                !pattrib->crc_err &&
+                !memcmp(get_hdr_bssid(wlanhdr),
+                        get_bssid(&padapter->mlmepriv), ETH_ALEN));
+
+       da = ieee80211_get_DA(hdr);
+       pkt_info.bPacketToSelf = pkt_info.bPacketMatchBSSID &&
+               (!memcmp(da, myid(&padapter->eeprompriv), ETH_ALEN));
+
+       pkt_info.bPacketBeacon = pkt_info.bPacketMatchBSSID &&
+               ieee80211_is_beacon(hdr->frame_control);
+
+       pkt_info.StationID = 0xFF;
+       if (pkt_info.bPacketBeacon) {
+               if (check_fwstate(&padapter->mlmepriv, WIFI_STATION_STATE) == true)
+                       sa = padapter->mlmepriv.cur_network.network.MacAddress;
+               /* to do Ad-hoc */
+       } else {
+               sa = ieee80211_get_SA(hdr);
+       }
+
+       pstapriv = &padapter->stapriv;
+       psta = rtw_get_stainfo23a(pstapriv, sa);
+       if (psta) {
+               pkt_info.StationID = psta->mac_id;
+               /* printk("%s ==> StationID(%d)\n", __FUNCTION__, pkt_info.StationID); */
+       }
+       pkt_info.Rate = pattrib->mcs_rate;
+
+       ODM_PhyStatusQuery23a(&pHalData->odmpriv, pPHYInfo,
+                          (u8 *)pphy_status, &pkt_info);
+       precvframe->psta = NULL;
+       if (pkt_info.bPacketMatchBSSID &&
+           (check_fwstate(&padapter->mlmepriv, WIFI_AP_STATE) == true)) {
+               if (psta) {
+                       precvframe->psta = psta;
+                       rtl8723a_process_phy_info(padapter, precvframe);
+               }
+       } else if (pkt_info.bPacketToSelf || pkt_info.bPacketBeacon) {
+               if (check_fwstate(&padapter->mlmepriv,
+                                 WIFI_ADHOC_STATE|WIFI_ADHOC_MASTER_STATE) ==
+                   true) {
+                       if (psta)
+                               precvframe->psta = psta;
+               }
+               rtl8723a_process_phy_info(padapter, precvframe);
+       }
+}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c b/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c
new file mode 100644 (file)
index 0000000..2af2e3e
--- /dev/null
@@ -0,0 +1,548 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RTL8192C_XMIT_C_
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+#include <osdep_intf.h>
+#include <usb_ops.h>
+/* include <rtl8192c_hal.h> */
+#include <rtl8723a_hal.h>
+
+s32    rtl8723au_init_xmit_priv(struct rtw_adapter *padapter)
+{
+       struct xmit_priv        *pxmitpriv = &padapter->xmitpriv;
+
+       tasklet_init(&pxmitpriv->xmit_tasklet,
+            (void(*)(unsigned long))rtl8723au_xmit_tasklet,
+            (unsigned long)padapter);
+       return _SUCCESS;
+}
+
+void   rtl8723au_free_xmit_priv(struct rtw_adapter *padapter)
+{
+}
+
+static void do_queue_select(struct rtw_adapter *padapter, struct pkt_attrib *pattrib)
+{
+       u8 qsel;
+
+       qsel = pattrib->priority;
+       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                ("### do_queue_select priority =%d , qsel = %d\n",
+                 pattrib->priority, qsel));
+
+       pattrib->qsel = qsel;
+}
+
+static int urb_zero_packet_chk(struct rtw_adapter *padapter, int sz)
+{
+       int blnSetTxDescOffset;
+       struct dvobj_priv       *pdvobj = adapter_to_dvobj(padapter);
+
+       if (pdvobj->ishighspeed) {
+               if (((sz + TXDESC_SIZE) % 512) == 0)
+                       blnSetTxDescOffset = 1;
+               else
+                       blnSetTxDescOffset = 0;
+       } else {
+               if (((sz + TXDESC_SIZE) % 64) == 0)
+                       blnSetTxDescOffset = 1;
+               else
+                       blnSetTxDescOffset = 0;
+       }
+       return blnSetTxDescOffset;
+}
+
+static void rtl8192cu_cal_txdesc_chksum(struct tx_desc *ptxdesc)
+{
+               u16     *usPtr = (u16 *)ptxdesc;
+               u32 count = 16;         /*  (32 bytes / 2 bytes per XOR) => 16 times */
+               u32 index;
+               u16 checksum = 0;
+
+               /* Clear first */
+               ptxdesc->txdw7 &= cpu_to_le32(0xffff0000);
+
+               for (index = 0 ; index < count ; index++)
+                       checksum = checksum ^ le16_to_cpu(*(usPtr + index));
+
+               ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff&checksum);
+}
+
+static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc)
+{
+       if ((pattrib->encrypt > 0) && !pattrib->bswenc) {
+               switch (pattrib->encrypt) {
+               /* SEC_TYPE */
+               case _WEP40_:
+               case _WEP104_:
+                       ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000);
+                       break;
+               case _TKIP_:
+               case _TKIP_WTMIC_:
+                       /* ptxdesc->txdw1 |= cpu_to_le32((0x02<<22)&0x00c00000); */
+                       ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000);
+                       break;
+               case _AES_:
+                       ptxdesc->txdw1 |= cpu_to_le32((0x03<<22)&0x00c00000);
+                       break;
+               case _NO_PRIVACY_:
+               default:
+                       break;
+               }
+       }
+}
+
+static void fill_txdesc_vcs(struct pkt_attrib *pattrib, u32 *pdw)
+{
+       /* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */
+
+       switch (pattrib->vcs_mode) {
+       case RTS_CTS:
+               *pdw |= cpu_to_le32(BIT(12));
+               break;
+       case CTS_TO_SELF:
+               *pdw |= cpu_to_le32(BIT(11));
+               break;
+       case NONE_VCS:
+       default:
+               break;
+       }
+
+       if (pattrib->vcs_mode) {
+               *pdw |= cpu_to_le32(BIT(13));
+
+               /*  Set RTS BW */
+               if (pattrib->ht_en) {
+                       *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(27)) : 0;
+
+                       if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+                               *pdw |= cpu_to_le32((0x01<<28)&0x30000000);
+                       else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+                               *pdw |= cpu_to_le32((0x02<<28)&0x30000000);
+                       else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+                               *pdw |= 0;
+                       else
+                               *pdw |= cpu_to_le32((0x03<<28)&0x30000000);
+               }
+       }
+}
+
+static void fill_txdesc_phy(struct pkt_attrib *pattrib, u32 *pdw)
+{
+       if (pattrib->ht_en) {
+               *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0;
+
+               if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER)
+                       *pdw |= cpu_to_le32((0x01<<20)&0x003f0000);
+               else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER)
+                       *pdw |= cpu_to_le32((0x02<<20)&0x003f0000);
+               else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE)
+                       *pdw |= 0;
+               else
+                       *pdw |= cpu_to_le32((0x03<<20)&0x003f0000);
+       }
+}
+
+static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz, u8 bagg_pkt)
+{
+       int     pull = 0;
+       uint    qsel;
+       struct rtw_adapter      *padapter = pxmitframe->padapter;
+       struct pkt_attrib       *pattrib = &pxmitframe->attrib;
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct dm_priv  *pdmpriv = &pHalData->dmpriv;
+       struct tx_desc  *ptxdesc = (struct tx_desc *)pmem;
+       struct mlme_ext_priv    *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info    *pmlmeinfo = &pmlmeext->mlmext_info;
+       int     bmcst = is_multicast_ether_addr(pattrib->ra);
+
+       if ((!bagg_pkt) && (urb_zero_packet_chk(padapter, sz) == 0)) {
+               ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ);
+               pull = 1;
+               pxmitframe->pkt_offset--;
+       }
+
+       memset(ptxdesc, 0, sizeof(struct tx_desc));
+
+       if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) {
+               /* offset 4 */
+               ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f);
+
+               qsel = (uint)(pattrib->qsel & 0x0000001f);
+               ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00);
+
+               ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000);
+
+               fill_txdesc_sectype(pattrib, ptxdesc);
+
+               if (pattrib->ampdu_en)
+                       ptxdesc->txdw1 |= cpu_to_le32(BIT(5));/* AGG EN */
+               else
+                       ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */
+
+               /* offset 8 */
+
+               /* offset 12 */
+               ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000);
+
+               /* offset 16 , offset 20 */
+               if (pattrib->qos_en)
+                       ptxdesc->txdw4 |= cpu_to_le32(BIT(6));/* QoS */
+
+               if ((pattrib->ether_type != 0x888e) &&
+                   (pattrib->ether_type != 0x0806) &&
+                   (pattrib->dhcp_pkt != 1)) {
+                       /* Non EAP & ARP & DHCP type data packet */
+
+                       fill_txdesc_vcs(pattrib, &ptxdesc->txdw4);
+                       fill_txdesc_phy(pattrib, &ptxdesc->txdw4);
+
+                       ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate = 24M */
+                       ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/*  */
+
+                       /* use REG_INIDATA_RATE_SEL value */
+                       ptxdesc->txdw5 |= cpu_to_le32(pdmpriv->INIDATA_RATE[pattrib->mac_id]);
+               } else {
+                       /*  EAP data packet and ARP packet. */
+                       /*  Use the 1M data rate to send the EAP/ARP packet. */
+                       /*  This will maybe make the handshake smooth. */
+
+                       ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */
+
+                       ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
+
+                       if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT)
+                               ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/*  DATA_SHORT */
+
+                       ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate));
+               }
+       } else if ((pxmitframe->frame_tag&0x0f) == MGNT_FRAMETAG) {
+               /* offset 4 */
+               ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f);
+
+               qsel = (uint)(pattrib->qsel&0x0000001f);
+               ptxdesc->txdw1 |= cpu_to_le32((qsel<<QSEL_SHT)&0x00001f00);
+
+               ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000);
+
+               /* offset 8 */
+               /* CCX-TXRPT ack for xmit mgmt frames. */
+               if (pxmitframe->ack_report)
+                       ptxdesc->txdw2 |= cpu_to_le32(BIT(19));
+
+               /* offset 12 */
+               ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000);
+
+               /* offset 16 */
+               ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
+
+               /* offset 20 */
+               ptxdesc->txdw5 |= cpu_to_le32(BIT(17));/* retry limit enable */
+               ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */
+
+               ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate));
+       } else if ((pxmitframe->frame_tag&0x0f) == TXAGG_FRAMETAG) {
+               DBG_8723A("pxmitframe->frame_tag == TXAGG_FRAMETAG\n");
+       } else {
+               DBG_8723A("pxmitframe->frame_tag = %d\n", pxmitframe->frame_tag);
+
+               /* offset 4 */
+               ptxdesc->txdw1 |= cpu_to_le32((4)&0x1f);/* CAM_ID(MAC_ID) */
+
+               ptxdesc->txdw1 |= cpu_to_le32((6<<16) & 0x000f0000);/* raid */
+
+               /* offset 8 */
+
+               /* offset 12 */
+               ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000);
+
+               /* offset 16 */
+               ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */
+
+               /* offset 20 */
+               ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate));
+       }
+
+       /*  (1) The sequence number of each non-Qos frame / broadcast / multicast / */
+       /*  mgnt frame should be controled by Hw because Fw will also send null data */
+       /*  which we cannot control when Fw LPS enable. */
+       /*  --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */
+       /*  (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */
+       /*  (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */
+       if (!pattrib->qos_en) {
+               /*  Hw set sequence number */
+               ptxdesc->txdw4 |= cpu_to_le32(BIT(7));
+               /* set bit3 to 1. */
+               ptxdesc->txdw3 |= cpu_to_le32((8 << 28));
+       }
+
+       /* offset 0 */
+       ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff);
+       ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG);
+       ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<<OFFSET_SHT)&0x00ff0000);/* 32 bytes for TX Desc */
+
+       if (bmcst)
+               ptxdesc->txdw0 |= cpu_to_le32(BIT(24));
+
+       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("offset0-txdesc = 0x%x\n", ptxdesc->txdw0));
+
+       /* offset 4 */
+       /*  pkt_offset, unit:8 bytes padding */
+       if (pxmitframe->pkt_offset > 0)
+               ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000);
+
+       rtl8192cu_cal_txdesc_chksum(ptxdesc);
+       return pull;
+}
+
+static s32 rtw_dump_xframe(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       s32 ret = _SUCCESS;
+       s32 inner_ret = _SUCCESS;
+       int t, sz, w_sz, pull = 0;
+       u8 *mem_addr;
+       u32 ff_hwaddr;
+       struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+       if ((pxmitframe->frame_tag == DATA_FRAMETAG) &&
+           (pxmitframe->attrib.ether_type != 0x0806) &&
+           (pxmitframe->attrib.ether_type != 0x888e) &&
+           (pxmitframe->attrib.dhcp_pkt != 1))
+               rtw_issue_addbareq_cmd23a(padapter, pxmitframe);
+
+       mem_addr = pxmitframe->buf_addr;
+
+       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("rtw_dump_xframe()\n"));
+
+       for (t = 0; t < pattrib->nr_frags; t++) {
+               if (inner_ret != _SUCCESS && ret == _SUCCESS)
+                       ret = _FAIL;
+
+               if (t != (pattrib->nr_frags - 1)) {
+                       RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_,
+                                ("pattrib->nr_frags =%d\n", pattrib->nr_frags));
+
+                       sz = pxmitpriv->frag_len;
+                       sz = sz - 4 - pattrib->icv_len;
+               } else {
+                       /* no frag */
+                       sz = pattrib->last_txcmdsz;
+               }
+
+               pull = update_txdesc(pxmitframe, mem_addr, sz, false);
+
+               if (pull) {
+                       mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */
+
+                       pxmitframe->buf_addr = mem_addr;
+
+                       w_sz = sz + TXDESC_SIZE;
+               } else {
+                       w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ;
+               }
+
+               ff_hwaddr = rtw_get_ff_hwaddr23a(pxmitframe);
+               inner_ret = rtw_write_port(padapter, ff_hwaddr, w_sz, pxmitbuf);
+               rtw_count_tx_stats23a(padapter, pxmitframe, sz);
+
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_,
+                        ("rtw_write_port, w_sz =%d\n", w_sz));
+
+               mem_addr += w_sz;
+
+               mem_addr = PTR_ALIGN(mem_addr, 4);
+       }
+
+       rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
+
+       if  (ret != _SUCCESS)
+               rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN);
+
+       return ret;
+}
+
+s32 rtl8723au_xmitframe_complete(struct rtw_adapter *padapter,
+                                struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf)
+{
+       struct hw_xmit *phwxmits;
+       struct xmit_frame *pxmitframe;
+       int hwentry;
+       int res = _SUCCESS, xcnt = 0;
+
+       phwxmits = pxmitpriv->hwxmits;
+       hwentry = pxmitpriv->hwxmit_entry;
+
+       RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("xmitframe_complete()\n"));
+
+       if (pxmitbuf == NULL) {
+               pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv);
+               if (!pxmitbuf)
+                       return false;
+       }
+       pxmitframe =  rtw_dequeue_xframe23a(pxmitpriv, phwxmits, hwentry);
+
+       if (pxmitframe) {
+               pxmitframe->pxmitbuf = pxmitbuf;
+
+               pxmitframe->buf_addr = pxmitbuf->pbuf;
+
+               pxmitbuf->priv_data = pxmitframe;
+
+               if ((pxmitframe->frame_tag&0x0f) == DATA_FRAMETAG) {
+                       if (pxmitframe->attrib.priority <= 15)/* TID0~15 */
+                               res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe);
+
+                       rtw_os_xmit_complete23a(padapter, pxmitframe);/* always return ndis_packet after rtw_xmitframe_coalesce23a */
+               }
+
+               RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, ("xmitframe_complete(): rtw_dump_xframe\n"));
+
+               if (res == _SUCCESS) {
+                       rtw_dump_xframe(padapter, pxmitframe);
+               } else {
+                       rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
+                       rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
+               }
+               xcnt++;
+       } else {
+               rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
+               return false;
+       }
+       return true;
+}
+
+static s32 xmitframe_direct(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       s32 res = _SUCCESS;
+
+       res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe);
+       if (res == _SUCCESS)
+               rtw_dump_xframe(padapter, pxmitframe);
+       return res;
+}
+
+/*
+ * Return
+ *     true    dump packet directly
+ *     false   enqueue packet
+ */
+static s32 pre_xmitframe(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       s32 res;
+       struct xmit_buf *pxmitbuf = NULL;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct pkt_attrib *pattrib = &pxmitframe->attrib;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       do_queue_select(padapter, pattrib);
+       spin_lock_bh(&pxmitpriv->lock);
+
+#ifdef CONFIG_8723AU_AP_MODE
+       if (xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe)) {
+               struct sta_info *psta;
+               struct sta_priv *pstapriv = &padapter->stapriv;
+
+               spin_unlock_bh(&pxmitpriv->lock);
+
+               if (pattrib->psta)
+                       psta = pattrib->psta;
+               else
+                       psta = rtw_get_stainfo23a(pstapriv, pattrib->ra);
+
+               if (psta) {
+                       if (psta->sleepq_len > (NR_XMITFRAME>>3))
+                               wakeup_sta_to_xmit23a(padapter, psta);
+               }
+
+               return false;
+       }
+#endif
+
+       if (rtw_txframes_sta_ac_pending23a(padapter, pattrib) > 0)
+               goto enqueue;
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true)
+               goto enqueue;
+
+       pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv);
+       if (pxmitbuf == NULL)
+               goto enqueue;
+
+       spin_unlock_bh(&pxmitpriv->lock);
+
+       pxmitframe->pxmitbuf = pxmitbuf;
+       pxmitframe->buf_addr = pxmitbuf->pbuf;
+       pxmitbuf->priv_data = pxmitframe;
+
+       if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) {
+               rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
+               rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
+       }
+       return true;
+
+enqueue:
+       res = rtw_xmitframe_enqueue23a(padapter, pxmitframe);
+       spin_unlock_bh(&pxmitpriv->lock);
+
+       if (res != _SUCCESS) {
+               RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
+                        ("pre_xmitframe: enqueue xmitframe fail\n"));
+               rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
+
+               /*  Trick, make the statistics correct */
+               pxmitpriv->tx_pkts--;
+               pxmitpriv->tx_drop++;
+               return true;
+       }
+       return false;
+}
+
+s32 rtl8723au_mgnt_xmit(struct rtw_adapter *padapter, struct xmit_frame *pmgntframe)
+{
+       return rtw_dump_xframe(padapter, pmgntframe);
+}
+
+/*
+ * Return
+ *     true    dump packet directly ok
+ *     false   temporary can't transmit packets to hardware
+ */
+s32 rtl8723au_hal_xmit(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe)
+{
+       return pre_xmitframe(padapter, pxmitframe);
+}
+
+s32    rtl8723au_hal_xmitframe_enqueue(struct rtw_adapter *padapter,
+                                       struct xmit_frame *pxmitframe)
+{
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       s32 err;
+
+       err = rtw_xmitframe_enqueue23a(padapter, pxmitframe);
+       if (err != _SUCCESS) {
+               rtw_free_xmitframe23a(pxmitpriv, pxmitframe);
+
+               /*  Trick, make the statistics correct */
+               pxmitpriv->tx_pkts--;
+               pxmitpriv->tx_drop++;
+       } else {
+               tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+       }
+       return err;
+}
diff --git a/drivers/staging/rtl8723au/hal/usb_halinit.c b/drivers/staging/rtl8723au/hal/usb_halinit.c
new file mode 100644 (file)
index 0000000..e206829
--- /dev/null
@@ -0,0 +1,1834 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _HCI_HAL_INIT_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_efuse.h>
+
+#include <HalPwrSeqCmd.h>
+#include <Hal8723PwrSeq.h>
+#include <rtl8723a_hal.h>
+#include <rtl8723a_led.h>
+#include <linux/ieee80211.h>
+
+#include <usb_ops.h>
+#include <usb_hal.h>
+#include <usb_osintf.h>
+
+static void
+_ConfigChipOutEP(struct rtw_adapter *pAdapter, u8 NumOutPipe)
+{
+       u8 value8;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+
+       pHalData->OutEpQueueSel = 0;
+       pHalData->OutEpNumber = 0;
+
+       /*  Normal and High queue */
+       value8 = rtw_read8(pAdapter, (REG_NORMAL_SIE_EP + 1));
+
+       if (value8 & USB_NORMAL_SIE_EP_MASK) {
+               pHalData->OutEpQueueSel |= TX_SELE_HQ;
+               pHalData->OutEpNumber++;
+       }
+
+       if ((value8 >> USB_NORMAL_SIE_EP_SHIFT) & USB_NORMAL_SIE_EP_MASK) {
+               pHalData->OutEpQueueSel |= TX_SELE_NQ;
+               pHalData->OutEpNumber++;
+       }
+
+       /*  Low queue */
+       value8 = rtw_read8(pAdapter, (REG_NORMAL_SIE_EP + 2));
+       if (value8 & USB_NORMAL_SIE_EP_MASK) {
+               pHalData->OutEpQueueSel |= TX_SELE_LQ;
+               pHalData->OutEpNumber++;
+       }
+
+       /*  TODO: Error recovery for this case */
+       /* RT_ASSERT((NumOutPipe == pHalData->OutEpNumber),
+          ("Out EP number isn't match! %d(Descriptor) != %d (SIE reg)\n",
+          (u32)NumOutPipe, (u32)pHalData->OutEpNumber)); */
+}
+
+static bool rtl8723au_set_queue_pipe_mapping(struct rtw_adapter *pAdapter,
+                                            u8 NumInPipe, u8 NumOutPipe)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+       bool result = false;
+
+       _ConfigChipOutEP(pAdapter, NumOutPipe);
+
+       /*  Normal chip with one IN and one OUT doesn't have interrupt IN EP. */
+       if (pHalData->OutEpNumber == 1) {
+               if (NumInPipe != 1)
+                       return result;
+       }
+
+       result = Hal_MappingOutPipe23a(pAdapter, NumOutPipe);
+
+       return result;
+}
+
+static void rtl8723au_interface_configure(struct rtw_adapter *padapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter);
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+
+       if (pdvobjpriv->ishighspeed == true) {
+               /* 512 bytes */
+               pHalData->UsbBulkOutSize = USB_HIGH_SPEED_BULK_SIZE;
+       } else {
+               /* 64 bytes */
+               pHalData->UsbBulkOutSize = USB_FULL_SPEED_BULK_SIZE;
+       }
+
+       pHalData->interfaceIndex = pdvobjpriv->InterfaceNumber;
+
+       rtl8723au_set_queue_pipe_mapping(padapter,
+                                        pdvobjpriv->RtNumInPipes,
+                                        pdvobjpriv->RtNumOutPipes);
+}
+
+static u8 _InitPowerOn(struct rtw_adapter *padapter)
+{
+       u8 status = _SUCCESS;
+       u16 value16 = 0;
+       u8 value8 = 0;
+
+       /*  RSV_CTRL 0x1C[7:0] = 0x00
+           unlock ISO/CLK/Power control register */
+       rtw_write8(padapter, REG_RSV_CTRL, 0x0);
+
+       /*  HW Power on sequence */
+       if (!HalPwrSeqCmdParsing23a(padapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+                                PWR_INTF_USB_MSK, rtl8723AU_card_enable_flow))
+               return _FAIL;
+
+       /*  0x04[19] = 1, suggest by Jackie 2011.05.09, reset 8051 */
+       value8 = rtw_read8(padapter, REG_APS_FSMCO+2);
+       rtw_write8(padapter, REG_APS_FSMCO + 2, (value8 | BIT3));
+
+       /*  Enable MAC DMA/WMAC/SCHEDULE/SEC block */
+       /*  Set CR bit10 to enable 32k calibration. Suggested by SD1 Gimmy.
+           Added by tynli. 2011.08.31. */
+       value16 = rtw_read16(padapter, REG_CR);
+       value16 |= (HCI_TXDMA_EN | HCI_RXDMA_EN | TXDMA_EN | RXDMA_EN |
+                   PROTOCOL_EN | SCHEDULE_EN | MACTXEN | MACRXEN |
+                   ENSEC | CALTMR_EN);
+       rtw_write16(padapter, REG_CR, value16);
+
+       /* for Efuse PG, suggest by Jackie 2011.11.23 */
+       PHY_SetBBReg(padapter, REG_EFUSE_CTRL, BIT28|BIT29|BIT30, 0x06);
+
+       return status;
+}
+
+/*  Shall USB interface init this? */
+static void _InitInterrupt(struct rtw_adapter *Adapter)
+{
+       u32 value32;
+
+       /*  HISR - turn all on */
+       value32 = 0xFFFFFFFF;
+       rtw_write32(Adapter, REG_HISR, value32);
+
+       /*  HIMR - turn all on */
+       rtw_write32(Adapter, REG_HIMR, value32);
+}
+
+static void _InitQueueReservedPage(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+       u32 numHQ = 0;
+       u32 numLQ = 0;
+       u32 numNQ = 0;
+       u32 numPubQ;
+       u32 value32;
+       u8 value8;
+       bool bWiFiConfig = pregistrypriv->wifi_spec;
+       /* u32                  txQPageNum, txQPageUnit, txQRemainPage; */
+
+       { /* for WMM */
+               /* RT_ASSERT((outEPNum>= 2), ("for WMM , number of out-ep "
+                  "must more than or equal to 2!\n")); */
+
+               numPubQ = bWiFiConfig ?
+                       WMM_NORMAL_PAGE_NUM_PUBQ : NORMAL_PAGE_NUM_PUBQ;
+
+               if (pHalData->OutEpQueueSel & TX_SELE_HQ) {
+                       numHQ = bWiFiConfig ?
+                               WMM_NORMAL_PAGE_NUM_HPQ : NORMAL_PAGE_NUM_HPQ;
+               }
+
+               if (pHalData->OutEpQueueSel & TX_SELE_LQ) {
+                       numLQ = bWiFiConfig ?
+                               WMM_NORMAL_PAGE_NUM_LPQ : NORMAL_PAGE_NUM_LPQ;
+               }
+               /*  NOTE: This step shall be proceed before
+                   writting REG_RQPN. */
+               if (pHalData->OutEpQueueSel & TX_SELE_NQ) {
+                       numNQ = bWiFiConfig ?
+                               WMM_NORMAL_PAGE_NUM_NPQ : NORMAL_PAGE_NUM_NPQ;
+               }
+               value8 = (u8)_NPQ(numNQ);
+               rtw_write8(Adapter, REG_RQPN_NPQ, value8);
+       }
+
+       /*  TX DMA */
+       value32 = _HPQ(numHQ) | _LPQ(numLQ) | _PUBQ(numPubQ) | LD_RQPN;
+       rtw_write32(Adapter, REG_RQPN, value32);
+}
+
+static void _InitTxBufferBoundary(struct rtw_adapter *Adapter)
+{
+       struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+
+       u8 txpktbuf_bndy;
+
+       if (!pregistrypriv->wifi_spec)
+               txpktbuf_bndy = TX_PAGE_BOUNDARY;
+       else /* for WMM */
+               txpktbuf_bndy = WMM_NORMAL_TX_PAGE_BOUNDARY;
+
+       rtw_write8(Adapter, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+       rtw_write8(Adapter, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+       rtw_write8(Adapter, REG_TXPKTBUF_WMAC_LBK_BF_HD, txpktbuf_bndy);
+       rtw_write8(Adapter, REG_TRXFF_BNDY, txpktbuf_bndy);
+       rtw_write8(Adapter, REG_TDECTRL+1, txpktbuf_bndy);
+}
+
+static void _InitPageBoundary(struct rtw_adapter *Adapter)
+{
+       /*  RX Page Boundary */
+       /* srand(static_cast<unsigned int>(time(NULL))); */
+       u16 rxff_bndy = 0x27FF;/* rand() % 1) ? 0x27FF : 0x23FF; */
+
+       rtw_write16(Adapter, (REG_TRXFF_BNDY + 2), rxff_bndy);
+
+       /*  TODO: ?? shall we set tx boundary? */
+}
+
+static void
+_InitNormalChipRegPriority(struct rtw_adapter *Adapter, u16 beQ, u16 bkQ,
+                          u16 viQ, u16 voQ, u16 mgtQ, u16 hiQ)
+{
+       u16 value16 = rtw_read16(Adapter, REG_TRXDMA_CTRL) & 0x7;
+
+       value16 |= _TXDMA_BEQ_MAP(beQ) | _TXDMA_BKQ_MAP(bkQ) |
+               _TXDMA_VIQ_MAP(viQ) | _TXDMA_VOQ_MAP(voQ) |
+               _TXDMA_MGQ_MAP(mgtQ) | _TXDMA_HIQ_MAP(hiQ);
+
+       rtw_write16(Adapter, REG_TRXDMA_CTRL, value16);
+}
+
+static void _InitNormalChipOneOutEpPriority(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       u16 value = 0;
+
+       switch (pHalData->OutEpQueueSel) {
+       case TX_SELE_HQ:
+               value = QUEUE_HIGH;
+               break;
+       case TX_SELE_LQ:
+               value = QUEUE_LOW;
+               break;
+       case TX_SELE_NQ:
+               value = QUEUE_NORMAL;
+               break;
+       default:
+               /* RT_ASSERT(false, ("Shall not reach here!\n")); */
+               break;
+       }
+
+       _InitNormalChipRegPriority(Adapter, value, value, value,
+                                  value, value, value);
+}
+
+static void _InitNormalChipTwoOutEpPriority(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+       u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ;
+       u16 valueHi = 0;
+       u16 valueLow = 0;
+
+       switch (pHalData->OutEpQueueSel) {
+       case (TX_SELE_HQ | TX_SELE_LQ):
+               valueHi = QUEUE_HIGH;
+               valueLow = QUEUE_LOW;
+               break;
+       case (TX_SELE_NQ | TX_SELE_LQ):
+               valueHi = QUEUE_NORMAL;
+               valueLow = QUEUE_LOW;
+               break;
+       case (TX_SELE_HQ | TX_SELE_NQ):
+               valueHi = QUEUE_HIGH;
+               valueLow = QUEUE_NORMAL;
+               break;
+       default:
+               /* RT_ASSERT(false, ("Shall not reach here!\n")); */
+               break;
+       }
+
+       if (!pregistrypriv->wifi_spec) {
+               beQ = valueLow;
+               bkQ = valueLow;
+               viQ = valueHi;
+               voQ = valueHi;
+               mgtQ = valueHi;
+               hiQ = valueHi;
+       } else {/* for WMM , CONFIG_OUT_EP_WIFI_MODE */
+               beQ = valueLow;
+               bkQ = valueHi;
+               viQ = valueHi;
+               voQ = valueLow;
+               mgtQ = valueHi;
+               hiQ = valueHi;
+       }
+
+       _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ);
+}
+
+static void _InitNormalChipThreeOutEpPriority(struct rtw_adapter *Adapter)
+{
+       struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+       u16 beQ, bkQ, viQ, voQ, mgtQ, hiQ;
+
+       if (!pregistrypriv->wifi_spec) {/*  typical setting */
+               beQ = QUEUE_LOW;
+               bkQ = QUEUE_LOW;
+               viQ = QUEUE_NORMAL;
+               voQ = QUEUE_HIGH;
+               mgtQ = QUEUE_HIGH;
+               hiQ = QUEUE_HIGH;
+       } else {/*  for WMM */
+               beQ = QUEUE_LOW;
+               bkQ = QUEUE_NORMAL;
+               viQ = QUEUE_NORMAL;
+               voQ = QUEUE_HIGH;
+               mgtQ = QUEUE_HIGH;
+               hiQ = QUEUE_HIGH;
+       }
+       _InitNormalChipRegPriority(Adapter, beQ, bkQ, viQ, voQ, mgtQ, hiQ);
+}
+
+static void _InitNormalChipQueuePriority(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+
+       switch (pHalData->OutEpNumber) {
+       case 1:
+               _InitNormalChipOneOutEpPriority(Adapter);
+               break;
+       case 2:
+               _InitNormalChipTwoOutEpPriority(Adapter);
+               break;
+       case 3:
+               _InitNormalChipThreeOutEpPriority(Adapter);
+               break;
+       default:
+               /* RT_ASSERT(false, ("Shall not reach here!\n")); */
+               break;
+       }
+}
+
+static void _InitQueuePriority(struct rtw_adapter *Adapter)
+{
+       _InitNormalChipQueuePriority(Adapter);
+}
+
+static void _InitNetworkType(struct rtw_adapter *Adapter)
+{
+       u32 value32;
+
+       value32 = rtw_read32(Adapter, REG_CR);
+
+       /*  TODO: use the other function to set network type */
+       value32 = (value32 & ~MASK_NETTYPE) | _NETTYPE(NT_LINK_AP);
+       rtw_write32(Adapter, REG_CR, value32);
+}
+
+static void _InitTransferPageSize(struct rtw_adapter *Adapter)
+{
+       /*  Tx page size is always 128. */
+
+       u8 value8;
+       value8 = _PSRX(PBP_128) | _PSTX(PBP_128);
+       rtw_write8(Adapter, REG_PBP, value8);
+}
+
+static void _InitDriverInfoSize(struct rtw_adapter *Adapter, u8 drvInfoSize)
+{
+       rtw_write8(Adapter, REG_RX_DRVINFO_SZ, drvInfoSize);
+}
+
+static void _InitWMACSetting(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+
+       /*  don't turn on AAP, it will allow all packets to driver */
+       pHalData->ReceiveConfig = RCR_APM | RCR_AM | RCR_AB | RCR_CBSSID_DATA |
+                                 RCR_CBSSID_BCN | RCR_APP_ICV | RCR_AMF |
+                                 RCR_HTC_LOC_CTRL | RCR_APP_MIC |
+                                 RCR_APP_PHYSTS;
+
+       /*  some REG_RCR will be modified later by
+           phy_ConfigMACWithHeaderFile() */
+       rtw_write32(Adapter, REG_RCR, pHalData->ReceiveConfig);
+
+       /*  Accept all multicast address */
+       rtw_write32(Adapter, REG_MAR, 0xFFFFFFFF);
+       rtw_write32(Adapter, REG_MAR + 4, 0xFFFFFFFF);
+
+       /*  Accept all data frames */
+       /* value16 = 0xFFFF; */
+       /* rtw_write16(Adapter, REG_RXFLTMAP2, value16); */
+
+       /*  2010.09.08 hpfan */
+       /*  Since ADF is removed from RCR, ps-poll will not be indicate
+           to driver, */
+       /*  RxFilterMap should mask ps-poll to gurantee AP mode can
+           rx ps-poll. */
+       /* value16 = 0x400; */
+       /* rtw_write16(Adapter, REG_RXFLTMAP1, value16); */
+
+       /*  Accept all management frames */
+       /* value16 = 0xFFFF; */
+       /* rtw_write16(Adapter, REG_RXFLTMAP0, value16); */
+
+       /* enable RX_SHIFT bits */
+       /* rtw_write8(Adapter, REG_TRXDMA_CTRL, rtw_read8(Adapter,
+          REG_TRXDMA_CTRL)|BIT(1)); */
+}
+
+static void _InitAdaptiveCtrl(struct rtw_adapter *Adapter)
+{
+       u16 value16;
+       u32 value32;
+
+       /*  Response Rate Set */
+       value32 = rtw_read32(Adapter, REG_RRSR);
+       value32 &= ~RATE_BITMAP_ALL;
+       value32 |= RATE_RRSR_CCK_ONLY_1M;
+       rtw_write32(Adapter, REG_RRSR, value32);
+
+       /*  CF-END Threshold */
+       /* m_spIoBase->rtw_write8(REG_CFEND_TH, 0x1); */
+
+       /*  SIFS (used in NAV) */
+       value16 = _SPEC_SIFS_CCK(0x10) | _SPEC_SIFS_OFDM(0x10);
+       rtw_write16(Adapter, REG_SPEC_SIFS, value16);
+
+       /*  Retry Limit */
+       value16 = _LRL(0x30) | _SRL(0x30);
+       rtw_write16(Adapter, REG_RL, value16);
+}
+
+static void _InitRateFallback(struct rtw_adapter *Adapter)
+{
+       /*  Set Data Auto Rate Fallback Retry Count register. */
+       rtw_write32(Adapter, REG_DARFRC, 0x00000000);
+       rtw_write32(Adapter, REG_DARFRC+4, 0x10080404);
+       rtw_write32(Adapter, REG_RARFRC, 0x04030201);
+       rtw_write32(Adapter, REG_RARFRC+4, 0x08070605);
+}
+
+static void _InitEDCA(struct rtw_adapter *Adapter)
+{
+       /*  Set Spec SIFS (used in NAV) */
+       rtw_write16(Adapter, REG_SPEC_SIFS, 0x100a);
+       rtw_write16(Adapter, REG_MAC_SPEC_SIFS, 0x100a);
+
+       /*  Set SIFS for CCK */
+       rtw_write16(Adapter, REG_SIFS_CTX, 0x100a);
+
+       /*  Set SIFS for OFDM */
+       rtw_write16(Adapter, REG_SIFS_TRX, 0x100a);
+
+       /*  TXOP */
+       rtw_write32(Adapter, REG_EDCA_BE_PARAM, 0x005EA42B);
+       rtw_write32(Adapter, REG_EDCA_BK_PARAM, 0x0000A44F);
+       rtw_write32(Adapter, REG_EDCA_VI_PARAM, 0x005EA324);
+       rtw_write32(Adapter, REG_EDCA_VO_PARAM, 0x002FA226);
+}
+
+static void _InitHWLed(struct rtw_adapter *Adapter)
+{
+       struct led_priv *pledpriv = &Adapter->ledpriv;
+
+       if (pledpriv->LedStrategy != HW_LED)
+               return;
+
+/*  HW led control */
+/*  to do .... */
+/* must consider cases of antenna diversity/ commbo card/solo card/mini card */
+}
+
+static void _InitRDGSetting(struct rtw_adapter *Adapter)
+{
+       rtw_write8(Adapter, REG_RD_CTRL, 0xFF);
+       rtw_write16(Adapter, REG_RD_NAV_NXT, 0x200);
+       rtw_write8(Adapter, REG_RD_RESP_PKT_TH, 0x05);
+}
+
+static void _InitRetryFunction(struct rtw_adapter *Adapter)
+{
+       u8 value8;
+
+       value8 = rtw_read8(Adapter, REG_FWHW_TXQ_CTRL);
+       value8 |= EN_AMPDU_RTY_NEW;
+       rtw_write8(Adapter, REG_FWHW_TXQ_CTRL, value8);
+
+       /*  Set ACK timeout */
+       rtw_write8(Adapter, REG_ACKTO, 0x40);
+}
+
+/*-----------------------------------------------------------------------------
+ * Function:   usb_AggSettingTxUpdate()
+ *
+ * Overview:   Seperate TX/RX parameters update independent for TP
+ *             detection and dynamic TX/RX aggreagtion parameters update.
+ *
+ * Input:                      struct rtw_adapter *
+ *
+ * Output/Return:      NONE
+ *
+ * Revised History:
+ *     When            Who             Remark
+ *     12/10/2010      MHC             Seperate to smaller function.
+ *
+ *---------------------------------------------------------------------------*/
+static void usb_AggSettingTxUpdate(struct rtw_adapter *Adapter)
+{
+}      /*  usb_AggSettingTxUpdate */
+
+/*-----------------------------------------------------------------------------
+ * Function:   usb_AggSettingRxUpdate()
+ *
+ * Overview:   Seperate TX/RX parameters update independent for TP
+ *             detection and dynamic TX/RX aggreagtion parameters update.
+ *
+ * Input:                      struct rtw_adapter *
+ *
+ * Output/Return:      NONE
+ *
+ * Revised History:
+ *     When            Who             Remark
+ *     12/10/2010      MHC             Seperate to smaller function.
+ *
+ *---------------------------------------------------------------------------*/
+static void usb_AggSettingRxUpdate(struct rtw_adapter *Adapter)
+{
+}      /*  usb_AggSettingRxUpdate */
+
+static void InitUsbAggregationSetting(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+
+       /*  Tx aggregation setting */
+       usb_AggSettingTxUpdate(Adapter);
+
+       /*  Rx aggregation setting */
+       usb_AggSettingRxUpdate(Adapter);
+
+       /*  201/12/10 MH Add for USB agg mode dynamic switch. */
+       pHalData->UsbRxHighSpeedMode = false;
+}
+
+static void _InitOperationMode(struct rtw_adapter *Adapter)
+{
+}
+
+static void _InitRFType(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       bool is92CU = IS_92C_SERIAL(pHalData->VersionID);
+
+       pHalData->rf_chip = RF_6052;
+
+       if (is92CU == false) {
+               pHalData->rf_type = RF_1T1R;
+               DBG_8723A("Set RF Chip ID to RF_6052 and RF type to 1T1R.\n");
+               return;
+       }
+
+       /*  TODO: Consider that EEPROM set 92CU to 1T1R later. */
+       /*  Force to overwrite setting according to chip version. Ignore
+           EEPROM setting. */
+       /* pHalData->RF_Type = is92CU ? RF_2T2R : RF_1T1R; */
+       MSG_8723A("Set RF Chip ID to RF_6052 and RF type to %d.\n",
+                 pHalData->rf_type);
+}
+
+/*  Set CCK and OFDM Block "ON" */
+static void _BBTurnOnBlock(struct rtw_adapter *Adapter)
+{
+       PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bCCKEn, 0x1);
+       PHY_SetBBReg(Adapter, rFPGA0_RFMOD, bOFDMEn, 0x1);
+}
+
+#define MgntActSet_RF_State(...)
+static void _RfPowerSave(struct rtw_adapter *padapter)
+{
+}
+
+enum {
+       Antenna_Lfet = 1,
+       Antenna_Right = 2,
+};
+
+enum rt_rf_power_state RfOnOffDetect23a(struct rtw_adapter *pAdapter)
+{
+       /* struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter); */
+       u8 val8;
+       enum rt_rf_power_state rfpowerstate = rf_off;
+
+       if (pAdapter->pwrctrlpriv.bHWPowerdown) {
+               val8 = rtw_read8(pAdapter, REG_HSISR);
+               DBG_8723A("pwrdown, 0x5c(BIT7) =%02x\n", val8);
+               rfpowerstate = (val8 & BIT7) ? rf_off : rf_on;
+       } else { /*  rf on/off */
+               rtw_write8(pAdapter, REG_MAC_PINMUX_CFG,
+                          rtw_read8(pAdapter, REG_MAC_PINMUX_CFG) & ~BIT3);
+               val8 = rtw_read8(pAdapter, REG_GPIO_IO_SEL);
+               DBG_8723A("GPIO_IN =%02x\n", val8);
+               rfpowerstate = (val8 & BIT3) ? rf_on : rf_off;
+       }
+       return rfpowerstate;
+}      /*  HalDetectPwrDownMode */
+
+void _ps_open_RF23a(struct rtw_adapter *padapter);
+
+static u32 rtl8723au_hal_init(struct rtw_adapter *Adapter)
+{
+       u8      val8 = 0;
+       u32     boundary, status = _SUCCESS;
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       struct pwrctrl_priv *pwrctrlpriv = &Adapter->pwrctrlpriv;
+       struct registry_priv *pregistrypriv = &Adapter->registrypriv;
+       u32 NavUpper = WiFiNavUpperUs;
+
+       unsigned long init_start_time = jiffies;
+
+#define HAL_INIT_PROFILE_TAG(stage) do {} while (0)
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BEGIN);
+       if (Adapter->pwrctrlpriv.bkeepfwalive) {
+               _ps_open_RF23a(Adapter);
+
+               if (pHalData->bIQKInitialized) {
+                       rtl8723a_phy_iq_calibrate(Adapter, true);
+               } else {
+                       rtl8723a_phy_iq_calibrate(Adapter, false);
+                       pHalData->bIQKInitialized = true;
+               }
+               rtl8723a_odm_check_tx_power_tracking(Adapter);
+               rtl8723a_phy_lc_calibrate(Adapter);
+
+               goto exit;
+       }
+
+       /*  Check if MAC has already power on. by tynli. 2011.05.27. */
+       val8 = rtw_read8(Adapter, REG_CR);
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("%s: REG_CR 0x100 = 0x%02x\n", __func__, val8));
+       /* Fix 92DU-VC S3 hang with the reason is that secondary mac is not
+          initialized. */
+       /* 0x100 value of first mac is 0xEA while 0x100 value of secondary
+          is 0x00 */
+       if (val8 == 0xEA) {
+               pHalData->bMACFuncEnable = false;
+       } else {
+               pHalData->bMACFuncEnable = true;
+               RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                        ("%s: MAC has already power on\n", __func__));
+       }
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PW_ON);
+       status = _InitPowerOn(Adapter);
+       if (status == _FAIL) {
+               RT_TRACE(_module_hci_hal_init_c_, _drv_err_,
+                        ("Failed to init power on!\n"));
+               goto exit;
+       }
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_LLTT);
+       if (!pregistrypriv->wifi_spec) {
+               boundary = TX_PAGE_BOUNDARY;
+       } else {
+               /*  for WMM */
+               boundary = WMM_NORMAL_TX_PAGE_BOUNDARY;
+       }
+
+       if (!pHalData->bMACFuncEnable) {
+               status =  InitLLTTable23a(Adapter, boundary);
+               if (status == _FAIL) {
+                       RT_TRACE(_module_hci_hal_init_c_, _drv_err_,
+                                ("Failed to init LLT table\n"));
+                       goto exit;
+               }
+       }
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC01);
+       if (pHalData->bRDGEnable)
+               _InitRDGSetting(Adapter);
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_DOWNLOAD_FW);
+       status = rtl8723a_FirmwareDownload(Adapter);
+       if (status != _SUCCESS) {
+               Adapter->bFWReady = false;
+               pHalData->fw_ractrl = false;
+               DBG_8723A("fw download fail!\n");
+               goto exit;
+       } else {
+               Adapter->bFWReady = true;
+               pHalData->fw_ractrl = true;
+               DBG_8723A("fw download ok!\n");
+       }
+
+       rtl8723a_InitializeFirmwareVars(Adapter);
+
+       if (pwrctrlpriv->reg_rfoff == true) {
+               pwrctrlpriv->rf_pwrstate = rf_off;
+       }
+
+       /*  2010/08/09 MH We need to check if we need to turnon or off RF after detecting */
+       /*  HW GPIO pin. Before PHY_RFConfig8192C. */
+       /* HalDetectPwrDownMode(Adapter); */
+       /*  2010/08/26 MH If Efuse does not support sective suspend then disable the function. */
+       /* HalDetectSelectiveSuspendMode(Adapter); */
+
+       /*  Set RF type for BB/RF configuration */
+       _InitRFType(Adapter);/* _ReadRFType() */
+
+       /*  Save target channel */
+       /*  <Roger_Notes> Current Channel will be updated again later. */
+       pHalData->CurrentChannel = 6;/* default set to 6 */
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MAC);
+       status = PHY_MACConfig8723A(Adapter);
+       if (status == _FAIL) {
+               DBG_8723A("PHY_MACConfig8723A fault !!\n");
+               goto exit;
+       }
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BB);
+       /*  */
+       /* d. Initialize BB related configurations. */
+       /*  */
+       status = PHY_BBConfig8723A(Adapter);
+       if (status == _FAIL) {
+               DBG_8723A("PHY_BBConfig8723A fault !!\n");
+               goto exit;
+       }
+
+       /*  Add for tx power by rate fine tune. We need to call the function after BB config. */
+       /*  Because the tx power by rate table is inited in BB config. */
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_RF);
+       status = PHY_RFConfig8723A(Adapter);
+       if (status == _FAIL) {
+               DBG_8723A("PHY_RFConfig8723A fault !!\n");
+               goto exit;
+       }
+
+       /* reducing 80M spur */
+       PHY_SetBBReg(Adapter, RF_T_METER, bMaskDWord, 0x0381808d);
+       PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff83);
+       PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff82);
+       PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff83);
+
+       /* RFSW Control */
+       PHY_SetBBReg(Adapter, rFPGA0_TxInfo, bMaskDWord, 0x00000003);   /* 0x804[14]= 0 */
+       PHY_SetBBReg(Adapter, rFPGA0_XAB_RFInterfaceSW, bMaskDWord, 0x07000760);        /* 0x870[6:5]= b'11 */
+       PHY_SetBBReg(Adapter, rFPGA0_XA_RFInterfaceOE, bMaskDWord, 0x66F60210); /* 0x860[6:5]= b'00 */
+
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("%s: 0x870 = value 0x%x\n", __func__, PHY_QueryBBReg(Adapter, 0x870, bMaskDWord)));
+
+       /*  */
+       /*  Joseph Note: Keep RfRegChnlVal for later use. */
+       /*  */
+       pHalData->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (enum RF_RADIO_PATH)0, RF_CHNLBW, bRFRegOffsetMask);
+       pHalData->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (enum RF_RADIO_PATH)1, RF_CHNLBW, bRFRegOffsetMask);
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC02);
+       if (!pHalData->bMACFuncEnable) {
+               _InitQueueReservedPage(Adapter);
+               _InitTxBufferBoundary(Adapter);
+       }
+       _InitQueuePriority(Adapter);
+       _InitPageBoundary(Adapter);
+       _InitTransferPageSize(Adapter);
+
+       /*  Get Rx PHY status in order to report RSSI and others. */
+       _InitDriverInfoSize(Adapter, DRVINFO_SZ);
+
+       _InitInterrupt(Adapter);
+       hal_init_macaddr23a(Adapter);/* set mac_address */
+       _InitNetworkType(Adapter);/* set msr */
+       _InitWMACSetting(Adapter);
+       _InitAdaptiveCtrl(Adapter);
+       _InitEDCA(Adapter);
+       _InitRateFallback(Adapter);
+       _InitRetryFunction(Adapter);
+       InitUsbAggregationSetting(Adapter);
+       _InitOperationMode(Adapter);/* todo */
+       rtl8723a_InitBeaconParameters(Adapter);
+
+       _InitHWLed(Adapter);
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_TURN_ON_BLOCK);
+       _BBTurnOnBlock(Adapter);
+       /* NicIFSetMacAddress(padapter, padapter->PermanentAddress); */
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_SECURITY);
+       invalidate_cam_all23a(Adapter);
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC11);
+       /*  2010/12/17 MH We need to set TX power according to EFUSE content at first. */
+       PHY_SetTxPowerLevel8723A(Adapter, pHalData->CurrentChannel);
+
+       rtl8723a_InitAntenna_Selection(Adapter);
+
+       /*  HW SEQ CTRL */
+       /* set 0x0 to 0xFF by tynli. Default enable HW SEQ NUM. */
+       rtw_write8(Adapter, REG_HWSEQ_CTRL, 0xFF);
+
+       /*  */
+       /*  Disable BAR, suggested by Scott */
+       /*  2010.04.09 add by hpfan */
+       /*  */
+       rtw_write32(Adapter, REG_BAR_MODE_CTRL, 0x0201ffff);
+
+       if (pregistrypriv->wifi_spec)
+               rtw_write16(Adapter, REG_FAST_EDCA_CTRL, 0);
+
+       /*  Move by Neo for USB SS from above setp */
+       _RfPowerSave(Adapter);
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_IQK);
+               /*  2010/08/26 MH Merge from 8192CE. */
+               /* sherry masked that it has been done in _RfPowerSave */
+               /* 20110927 */
+               /* recovery for 8192cu and 9723Au 20111017 */
+               if (pwrctrlpriv->rf_pwrstate == rf_on) {
+                       if (pHalData->bIQKInitialized) {
+                               rtl8723a_phy_iq_calibrate(Adapter, true);
+                       } else {
+                               rtl8723a_phy_iq_calibrate(Adapter, false);
+                               pHalData->bIQKInitialized = true;
+                       }
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_PW_TRACK);
+                       rtl8723a_odm_check_tx_power_tracking(Adapter);
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_LCK);
+                       rtl8723a_phy_lc_calibrate(Adapter);
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+                       rtl8723a_SingleDualAntennaDetection(Adapter);
+#endif
+               }
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC21);
+ /* fixed USB interface interference issue */
+       rtw_write8(Adapter, 0xfe40, 0xe0);
+       rtw_write8(Adapter, 0xfe41, 0x8d);
+       rtw_write8(Adapter, 0xfe42, 0x80);
+       rtw_write32(Adapter, 0x20c, 0xfd0320);
+       /* Solve too many protocol error on USB bus */
+       if (!IS_81xxC_VENDOR_UMC_A_CUT(pHalData->VersionID)) {
+               /*  0xE6 = 0x94 */
+               rtw_write8(Adapter, 0xFE40, 0xE6);
+               rtw_write8(Adapter, 0xFE41, 0x94);
+               rtw_write8(Adapter, 0xFE42, 0x80);
+
+               /*  0xE0 = 0x19 */
+               rtw_write8(Adapter, 0xFE40, 0xE0);
+               rtw_write8(Adapter, 0xFE41, 0x19);
+               rtw_write8(Adapter, 0xFE42, 0x80);
+
+               /*  0xE5 = 0x91 */
+               rtw_write8(Adapter, 0xFE40, 0xE5);
+               rtw_write8(Adapter, 0xFE41, 0x91);
+               rtw_write8(Adapter, 0xFE42, 0x80);
+
+               /*  0xE2 = 0x81 */
+               rtw_write8(Adapter, 0xFE40, 0xE2);
+               rtw_write8(Adapter, 0xFE41, 0x81);
+               rtw_write8(Adapter, 0xFE42, 0x80);
+
+       }
+
+/* HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_PABIAS); */
+/*     _InitPABias(Adapter); */
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_BT_COEXIST);
+       /*  Init BT hw config. */
+       BT_InitHwConfig(Adapter);
+#endif
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_INIT_HAL_DM);
+       rtl8723a_InitHalDm(Adapter);
+
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_MISC31);
+       rtw_hal_set_hwreg23a(Adapter, HW_VAR_NAV_UPPER, (u8 *)&NavUpper);
+
+       /*  2011/03/09 MH debug only, UMC-B cut pass 2500 S5 test, but we need to fin root cause. */
+       if (((rtw_read32(Adapter, rFPGA0_RFMOD) & 0xFF000000) != 0x83000000)) {
+               PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT(24), 1);
+               RT_TRACE(_module_hci_hal_init_c_, _drv_err_, ("%s: IQK fail recorver\n", __func__));
+       }
+
+       /* ack for xmit mgmt frames. */
+       rtw_write32(Adapter, REG_FWHW_TXQ_CTRL, rtw_read32(Adapter, REG_FWHW_TXQ_CTRL)|BIT(12));
+
+exit:
+       HAL_INIT_PROFILE_TAG(HAL_INIT_STAGES_END);
+
+       DBG_8723A("%s in %dms\n", __func__,
+                 jiffies_to_msecs(jiffies - init_start_time));
+       return status;
+}
+
+static void phy_SsPwrSwitch92CU(struct rtw_adapter *Adapter,
+                               enum rt_rf_power_state eRFPowerState,
+                               int bRegSSPwrLvl)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       u8 value8;
+       u8 bytetmp;
+
+       switch (eRFPowerState) {
+       case rf_on:
+               if (bRegSSPwrLvl == 1) {
+                       /*  1. Enable MAC Clock. Can not be enabled now. */
+                       /* WriteXBYTE(REG_SYS_CLKR+1,
+                          ReadXBYTE(REG_SYS_CLKR+1) | BIT(3)); */
+
+                       /*  2. Force PWM, Enable SPS18_LDO_Marco_Block */
+                       rtw_write8(Adapter, REG_SPS0_CTRL,
+                                  rtw_read8(Adapter, REG_SPS0_CTRL) |
+                                  (BIT0|BIT3));
+
+                       /*  3. restore BB, AFE control register. */
+                       /* RF */
+                       if (pHalData->rf_type ==  RF_2T2R)
+                               PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                            0x380038, 1);
+                       else
+                               PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                            0x38, 1);
+                       PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf0, 1);
+                       PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT1, 0);
+
+                       /* AFE */
+                       if (pHalData->rf_type ==  RF_2T2R)
+                               PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord,
+                                            0x63DB25A0);
+                       else if (pHalData->rf_type ==  RF_1T1R)
+                               PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord,
+                                            0x631B25A0);
+
+                       /*  4. issue 3-wire command that RF set to Rx idle
+                           mode. This is used to re-write the RX idle mode. */
+                       /*  We can only prvide a usual value instead and then
+                           HW will modify the value by itself. */
+                       PHY_SetRFReg(Adapter, RF_PATH_A, 0,
+                                    bRFRegOffsetMask, 0x32D95);
+                       if (pHalData->rf_type ==  RF_2T2R) {
+                               PHY_SetRFReg(Adapter, RF_PATH_B, 0,
+                                            bRFRegOffsetMask, 0x32D95);
+                       }
+               } else {                /*  Level 2 or others. */
+                       /* h.   AFE_PLL_CTRL 0x28[7:0] = 0x80
+                          disable AFE PLL */
+                       rtw_write8(Adapter, REG_AFE_PLL_CTRL, 0x81);
+
+                       /*  i.  AFE_XTAL_CTRL 0x24[15:0] = 0x880F
+                           gated AFE DIG_CLOCK */
+                       rtw_write16(Adapter, REG_AFE_XTAL_CTRL, 0x800F);
+                       mdelay(1);
+
+                       /*  2. Force PWM, Enable SPS18_LDO_Marco_Block */
+                       rtw_write8(Adapter, REG_SPS0_CTRL,
+                                  rtw_read8(Adapter, REG_SPS0_CTRL) |
+                                  (BIT0|BIT3));
+
+                       /*  3. restore BB, AFE control register. */
+                       /* RF */
+                       if (pHalData->rf_type ==  RF_2T2R)
+                               PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                            0x380038, 1);
+                       else
+                               PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                            0x38, 1);
+                       PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf0, 1);
+                       PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT1, 0);
+
+                       /* AFE */
+                       if (pHalData->rf_type ==  RF_2T2R)
+                               PHY_SetBBReg(Adapter, rRx_Wait_CCA,
+                                            bMaskDWord, 0x63DB25A0);
+                       else if (pHalData->rf_type ==  RF_1T1R)
+                               PHY_SetBBReg(Adapter, rRx_Wait_CCA,
+                                            bMaskDWord, 0x631B25A0);
+
+                       /*  4. issue 3-wire command that RF set to Rx idle
+                           mode. This is used to re-write the RX idle mode. */
+                       /*  We can only prvide a usual value instead and
+                           then HW will modify the value by itself. */
+                       PHY_SetRFReg(Adapter, RF_PATH_A, 0,
+                                    bRFRegOffsetMask, 0x32D95);
+                       if (pHalData->rf_type ==  RF_2T2R) {
+                               PHY_SetRFReg(Adapter, RF_PATH_B, 0,
+                                            bRFRegOffsetMask, 0x32D95);
+                       }
+
+                       /*  5. gated MAC Clock */
+                       bytetmp = rtw_read8(Adapter, REG_APSD_CTRL);
+                       rtw_write8(Adapter, REG_APSD_CTRL, bytetmp & ~BIT6);
+
+                       mdelay(10);
+
+                       /*  Set BB reset at first */
+                       rtw_write8(Adapter, REG_SYS_FUNC_EN, 0x17); /* 0x16 */
+
+                       /*  Enable TX */
+                       rtw_write8(Adapter, REG_TXPAUSE, 0x0);
+               }
+               break;
+       case rf_sleep:
+       case rf_off:
+               value8 = rtw_read8(Adapter, REG_SPS0_CTRL) ;
+               if (IS_81xxC_VENDOR_UMC_B_CUT(pHalData->VersionID))
+                       value8 &= ~(BIT0);
+               else
+                       value8 &= ~(BIT0|BIT3);
+               if (bRegSSPwrLvl == 1) {
+                       RT_TRACE(_module_hal_init_c_, _drv_err_, ("SS LVL1\n"));
+                       /*  Disable RF and BB only for SelectSuspend. */
+
+                       /*  1. Set BB/RF to shutdown. */
+                       /*      (1) Reg878[5:3]= 0       RF rx_code for
+                                                       preamble power saving */
+                       /*      (2)Reg878[21:19]= 0     Turn off RF-B */
+                       /*      (3) RegC04[7:4]= 0      Turn off all paths
+                                                       for packet detection */
+                       /*      (4) Reg800[1] = 1       enable preamble power
+                                                       saving */
+                       Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF0] =
+                               PHY_QueryBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                              bMaskDWord);
+                       Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF1] =
+                               PHY_QueryBBReg(Adapter, rOFDM0_TRxPathEnable,
+                                              bMaskDWord);
+                       Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF2] =
+                               PHY_QueryBBReg(Adapter, rFPGA0_RFMOD,
+                                              bMaskDWord);
+                       if (pHalData->rf_type ==  RF_2T2R) {
+                               PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                            0x380038, 0);
+                       } else if (pHalData->rf_type ==  RF_1T1R) {
+                               PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                            0x38, 0);
+                       }
+                       PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf0, 0);
+                       PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT1, 1);
+
+                       /*  2 .AFE control register to power down. bit[30:22] */
+                       Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_AFE0] =
+                               PHY_QueryBBReg(Adapter, rRx_Wait_CCA,
+                                              bMaskDWord);
+                       if (pHalData->rf_type ==  RF_2T2R)
+                               PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord,
+                                            0x00DB25A0);
+                       else if (pHalData->rf_type ==  RF_1T1R)
+                               PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord,
+                                            0x001B25A0);
+
+                       /*  3. issue 3-wire command that RF set to power down.*/
+                       PHY_SetRFReg(Adapter, RF_PATH_A, 0, bRFRegOffsetMask, 0);
+                       if (pHalData->rf_type ==  RF_2T2R)
+                               PHY_SetRFReg(Adapter, RF_PATH_B, 0,
+                                            bRFRegOffsetMask, 0);
+
+                       /*  4. Force PFM , disable SPS18_LDO_Marco_Block */
+                       rtw_write8(Adapter, REG_SPS0_CTRL, value8);
+               } else {        /*  Level 2 or others. */
+                       RT_TRACE(_module_hal_init_c_, _drv_err_, ("SS LVL2\n"));
+                       {
+                               u8 eRFPath = RF_PATH_A, value8 = 0;
+                               rtw_write8(Adapter, REG_TXPAUSE, 0xFF);
+                               PHY_SetRFReg(Adapter,
+                                            (enum RF_RADIO_PATH)eRFPath,
+                                            0x0, bMaskByte0, 0x0);
+                               value8 |= APSDOFF;
+                               /* 0x40 */
+                               rtw_write8(Adapter, REG_APSD_CTRL, value8);
+
+                               /*  After switch APSD, we need to delay
+                                   for stability */
+                               mdelay(10);
+
+                               /*  Set BB reset at first */
+                               value8 = 0 ;
+                               value8 |= (FEN_USBD | FEN_USBA |
+                                          FEN_BB_GLB_RSTn);
+                               /* 0x16 */
+                               rtw_write8(Adapter, REG_SYS_FUNC_EN, value8);
+                       }
+
+                       /*  Disable RF and BB only for SelectSuspend. */
+
+                       /*  1. Set BB/RF to shutdown. */
+                       /*      (1) Reg878[5:3]= 0      RF rx_code for
+                                                       preamble power saving */
+                       /*      (2)Reg878[21:19]= 0     Turn off RF-B */
+                       /*      (3) RegC04[7:4]= 0      Turn off all paths for
+                                                       packet detection */
+                       /*      (4) Reg800[1] = 1       enable preamble power
+                                                       saving */
+                       Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF0] =
+                               PHY_QueryBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                              bMaskDWord);
+                       Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF1] =
+                               PHY_QueryBBReg(Adapter, rOFDM0_TRxPathEnable,
+                                              bMaskDWord);
+                       Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_RF2] =
+                               PHY_QueryBBReg(Adapter, rFPGA0_RFMOD,
+                                              bMaskDWord);
+                       if (pHalData->rf_type ==  RF_2T2R)
+                               PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                            0x380038, 0);
+                       else if (pHalData->rf_type ==  RF_1T1R)
+                               PHY_SetBBReg(Adapter, rFPGA0_XAB_RFParameter,
+                                            0x38, 0);
+                       PHY_SetBBReg(Adapter, rOFDM0_TRxPathEnable, 0xf0, 0);
+                       PHY_SetBBReg(Adapter, rFPGA0_RFMOD, BIT1, 1);
+
+                       /*  2 .AFE control register to power down. bit[30:22] */
+                       Adapter->pwrctrlpriv.PS_BBRegBackup[PSBBREG_AFE0] =
+                               PHY_QueryBBReg(Adapter, rRx_Wait_CCA,
+                                              bMaskDWord);
+                       if (pHalData->rf_type ==  RF_2T2R)
+                               PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord,
+                                            0x00DB25A0);
+                       else if (pHalData->rf_type ==  RF_1T1R)
+                               PHY_SetBBReg(Adapter, rRx_Wait_CCA, bMaskDWord,
+                                            0x001B25A0);
+
+                       /* 3. issue 3-wire command that RF set to power down. */
+                       PHY_SetRFReg(Adapter, RF_PATH_A, 0, bRFRegOffsetMask, 0);
+                       if (pHalData->rf_type ==  RF_2T2R)
+                               PHY_SetRFReg(Adapter, RF_PATH_B, 0,
+                                            bRFRegOffsetMask, 0);
+
+                       /*  4. Force PFM , disable SPS18_LDO_Marco_Block */
+                       rtw_write8(Adapter, REG_SPS0_CTRL, value8);
+
+                       /*  2010/10/13 MH/Isaachsu exchange sequence. */
+                       /* h.   AFE_PLL_CTRL 0x28[7:0] = 0x80
+                               disable AFE PLL */
+                       rtw_write8(Adapter, REG_AFE_PLL_CTRL, 0x80);
+                       mdelay(1);
+
+                       /*  i.  AFE_XTAL_CTRL 0x24[15:0] = 0x880F
+                               gated AFE DIG_CLOCK */
+                       rtw_write16(Adapter, REG_AFE_XTAL_CTRL, 0xA80F);
+               }
+               break;
+       default:
+               break;
+       }
+
+}      /*  phy_PowerSwitch92CU */
+
+void _ps_open_RF23a(struct rtw_adapter *padapter)
+{
+       /* here call with bRegSSPwrLvl 1, bRegSSPwrLvl 2 needs to be verified */
+       phy_SsPwrSwitch92CU(padapter, rf_on, 1);
+}
+
+static void CardDisableRTL8723U(struct rtw_adapter *Adapter)
+{
+       u8              u1bTmp;
+
+       DBG_8723A("CardDisableRTL8723U\n");
+       /*  USB-MF Card Disable Flow */
+       /*  1. Run LPS WL RFOFF flow */
+       HalPwrSeqCmdParsing23a(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+                           PWR_INTF_USB_MSK, rtl8723AU_enter_lps_flow);
+
+       /*  2. 0x1F[7:0] = 0            turn off RF */
+       rtw_write8(Adapter, REG_RF_CTRL, 0x00);
+
+       /*      ==== Reset digital sequence   ====== */
+       if ((rtw_read8(Adapter, REG_MCUFWDL)&BIT7) &&
+           Adapter->bFWReady) /* 8051 RAM code */
+               rtl8723a_FirmwareSelfReset(Adapter);
+
+       /*  Reset MCU. Suggested by Filen. 2011.01.26. by tynli. */
+       u1bTmp = rtw_read8(Adapter, REG_SYS_FUNC_EN+1);
+       rtw_write8(Adapter, REG_SYS_FUNC_EN+1, (u1bTmp & (~BIT2)));
+
+       /*  g.  MCUFWDL 0x80[1:0]= 0            reset MCU ready status */
+       rtw_write8(Adapter, REG_MCUFWDL, 0x00);
+
+       /*      ==== Reset digital sequence end ====== */
+       /*  Card disable power action flow */
+       HalPwrSeqCmdParsing23a(Adapter, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+                              PWR_INTF_USB_MSK,
+                              rtl8723AU_card_disable_flow);
+
+       /*  Reset MCU IO Wrapper, added by Roger, 2011.08.30. */
+       u1bTmp = rtw_read8(Adapter, REG_RSV_CTRL + 1);
+       rtw_write8(Adapter, REG_RSV_CTRL+1, (u1bTmp & (~BIT0)));
+       u1bTmp = rtw_read8(Adapter, REG_RSV_CTRL + 1);
+       rtw_write8(Adapter, REG_RSV_CTRL+1, u1bTmp | BIT0);
+
+       /*  7. RSV_CTRL 0x1C[7:0] = 0x0E  lock ISO/CLK/Power control register */
+       rtw_write8(Adapter, REG_RSV_CTRL, 0x0e);
+}
+
+static u32 rtl8723au_hal_deinit(struct rtw_adapter *padapter)
+{
+       DBG_8723A("==> %s\n", __func__);
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       BT_HaltProcess(padapter);
+#endif
+       /*  2011/02/18 To Fix RU LNA  power leakage problem. We need to
+           execute below below in Adapter init and halt sequence.
+           According to EEchou's opinion, we can enable the ability for all */
+       /*  IC. Accord to johnny's opinion, only RU need the support. */
+       CardDisableRTL8723U(padapter);
+
+       return _SUCCESS;
+}
+
+static unsigned int rtl8723au_inirp_init(struct rtw_adapter *Adapter)
+{
+       u8 i;
+       struct recv_buf *precvbuf;
+       uint    status;
+       struct intf_hdl *pintfhdl = &Adapter->iopriv.intf;
+       struct recv_priv *precvpriv = &Adapter->recvpriv;
+       u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+                         struct recv_buf *rbuf);
+       u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr);
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
+
+       _read_port = pintfhdl->io_ops._read_port;
+
+       status = _SUCCESS;
+
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_, ("===> usb_inirp_init\n"));
+
+       precvpriv->ff_hwaddr = RECV_BULK_IN_ADDR;
+
+       /* issue Rx irp to receive data */
+       precvbuf = (struct recv_buf *)precvpriv->precv_buf;
+       for (i = 0; i < NR_RECVBUFF; i++) {
+               if (_read_port(pintfhdl, precvpriv->ff_hwaddr, 0, precvbuf) ==
+                   false) {
+                       RT_TRACE(_module_hci_hal_init_c_, _drv_err_,
+                                ("usb_rx_init: usb_read_port error\n"));
+                       status = _FAIL;
+                       goto exit;
+               }
+               precvbuf++;
+               precvpriv->free_recv_buf_queue_cnt--;
+       }
+       _read_interrupt = pintfhdl->io_ops._read_interrupt;
+       if (_read_interrupt(pintfhdl, RECV_INT_IN_ADDR) == false) {
+               RT_TRACE(_module_hci_hal_init_c_, _drv_err_,
+                        ("usb_rx_init: usb_read_interrupt error\n"));
+               status = _FAIL;
+       }
+       pHalData->IntrMask[0] = rtw_read32(Adapter, REG_USB_HIMR);
+       MSG_8723A("pHalData->IntrMask = 0x%04x\n", pHalData->IntrMask[0]);
+       pHalData->IntrMask[0] |= UHIMR_C2HCMD|UHIMR_CPWM;
+       rtw_write32(Adapter, REG_USB_HIMR, pHalData->IntrMask[0]);
+exit:
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("<=== usb_inirp_init\n"));
+       return status;
+}
+
+static unsigned int rtl8723au_inirp_deinit(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
+
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("\n ===> usb_rx_deinit\n"));
+       rtw_read_port_cancel(Adapter);
+       pHalData->IntrMask[0] = rtw_read32(Adapter, REG_USB_HIMR);
+       MSG_8723A("%s pHalData->IntrMask = 0x%04x\n", __func__,
+                 pHalData->IntrMask[0]);
+       pHalData->IntrMask[0] = 0x0;
+       rtw_write32(Adapter, REG_USB_HIMR, pHalData->IntrMask[0]);
+       RT_TRACE(_module_hci_hal_init_c_, _drv_info_,
+                ("\n <=== usb_rx_deinit\n"));
+       return _SUCCESS;
+}
+
+static void _ReadBoardType(struct rtw_adapter *Adapter, u8 *PROMContent,
+                          bool AutoloadFail)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       u8 boardType = BOARD_USB_DONGLE;
+
+       if (AutoloadFail) {
+               if (IS_8723_SERIES(pHalData->VersionID))
+                       pHalData->rf_type = RF_1T1R;
+               else
+                       pHalData->rf_type = RF_2T2R;
+               pHalData->BoardType = boardType;
+               return;
+       }
+
+       boardType = PROMContent[EEPROM_NORMAL_BoardType];
+       boardType &= BOARD_TYPE_NORMAL_MASK;/* bit[7:5] */
+       boardType >>= 5;
+
+       pHalData->BoardType = boardType;
+       MSG_8723A("_ReadBoardType(%x)\n", pHalData->BoardType);
+
+       if (boardType == BOARD_USB_High_PA)
+               pHalData->ExternalPA = 1;
+}
+
+static void _ReadLEDSetting(struct rtw_adapter *Adapter, u8 *PROMContent,
+                           bool AutoloadFail)
+{
+       struct led_priv *pledpriv = &Adapter->ledpriv;
+
+       pledpriv->LedStrategy = HW_LED;
+}
+
+static void Hal_EfuseParsePIDVID_8723AU(struct rtw_adapter *pAdapter,
+                                       u8 *hwinfo, bool AutoLoadFail)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(pAdapter);
+
+       if (AutoLoadFail) {
+               pHalData->EEPROMVID = 0;
+               pHalData->EEPROMPID = 0;
+       } else {
+               /*  VID, PID */
+               pHalData->EEPROMVID =
+                       le16_to_cpu(*(u16 *)&hwinfo[EEPROM_VID_8723AU]);
+               pHalData->EEPROMPID =
+                       le16_to_cpu(*(u16 *)&hwinfo[EEPROM_PID_8723AU]);
+       }
+
+       MSG_8723A("EEPROM VID = 0x%4x\n", pHalData->EEPROMVID);
+       MSG_8723A("EEPROM PID = 0x%4x\n", pHalData->EEPROMPID);
+}
+
+static void Hal_EfuseParseMACAddr_8723AU(struct rtw_adapter *padapter,
+                                        u8 *hwinfo, bool AutoLoadFail)
+{
+       u16 i;
+       u8 sMacAddr[ETH_ALEN] = {0x00, 0xE0, 0x4C, 0x87, 0x23, 0x00};
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+
+       if (AutoLoadFail) {
+               for (i = 0; i < 6; i++)
+                       pEEPROM->mac_addr[i] = sMacAddr[i];
+       } else {
+               /* Read Permanent MAC address */
+               memcpy(pEEPROM->mac_addr, &hwinfo[EEPROM_MAC_ADDR_8723AU],
+                      ETH_ALEN);
+       }
+
+       RT_TRACE(_module_hci_hal_init_c_, _drv_notice_,
+                ("Hal_EfuseParseMACAddr_8723AU: Permanent Address =%02x:%02x:"
+                 "%02x:%02x:%02x:%02x\n",
+                 pEEPROM->mac_addr[0], pEEPROM->mac_addr[1],
+                 pEEPROM->mac_addr[2], pEEPROM->mac_addr[3],
+                 pEEPROM->mac_addr[4], pEEPROM->mac_addr[5]));
+}
+
+static void readAdapterInfo(struct rtw_adapter *padapter)
+{
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(padapter);
+       /* struct hal_data_8723a * pHalData = GET_HAL_DATA(padapter); */
+       u8 hwinfo[HWSET_MAX_SIZE];
+
+       Hal_InitPGData(padapter, hwinfo);
+       Hal_EfuseParseIDCode(padapter, hwinfo);
+       Hal_EfuseParsePIDVID_8723AU(padapter, hwinfo,
+                                   pEEPROM->bautoload_fail_flag);
+       Hal_EfuseParseEEPROMVer(padapter, hwinfo,
+                               pEEPROM->bautoload_fail_flag);
+       Hal_EfuseParseMACAddr_8723AU(padapter, hwinfo,
+                                    pEEPROM->bautoload_fail_flag);
+       Hal_EfuseParsetxpowerinfo_8723A(padapter, hwinfo,
+                                       pEEPROM->bautoload_fail_flag);
+       _ReadBoardType(padapter, hwinfo, pEEPROM->bautoload_fail_flag);
+       Hal_EfuseParseBTCoexistInfo_8723A(padapter, hwinfo,
+                                         pEEPROM->bautoload_fail_flag);
+
+       rtl8723a_EfuseParseChnlPlan(padapter, hwinfo,
+                                   pEEPROM->bautoload_fail_flag);
+       Hal_EfuseParseThermalMeter_8723A(padapter, hwinfo,
+                                        pEEPROM->bautoload_fail_flag);
+       _ReadLEDSetting(padapter, hwinfo, pEEPROM->bautoload_fail_flag);
+/*     _ReadRFSetting(Adapter, PROMContent, pEEPROM->bautoload_fail_flag); */
+/*     _ReadPSSetting(Adapter, PROMContent, pEEPROM->bautoload_fail_flag); */
+       Hal_EfuseParseAntennaDiversity(padapter, hwinfo,
+                                      pEEPROM->bautoload_fail_flag);
+
+       Hal_EfuseParseEEPROMVer(padapter, hwinfo, pEEPROM->bautoload_fail_flag);
+       Hal_EfuseParseCustomerID(padapter, hwinfo,
+                                pEEPROM->bautoload_fail_flag);
+       Hal_EfuseParseRateIndicationOption(padapter, hwinfo,
+                                          pEEPROM->bautoload_fail_flag);
+       Hal_EfuseParseXtal_8723A(padapter, hwinfo,
+                                pEEPROM->bautoload_fail_flag);
+       /*  */
+       /*  The following part initialize some vars by PG info. */
+       /*  */
+       Hal_InitChannelPlan23a(padapter);
+
+       /* hal_CustomizedBehavior_8723U(Adapter); */
+
+/*     Adapter->bDongle = (PROMContent[EEPROM_EASY_REPLACEMENT] == 1)? 0: 1; */
+       DBG_8723A("%s(): REPLACEMENT = %x\n", __func__, padapter->bDongle);
+}
+
+static void _ReadPROMContent(struct rtw_adapter *Adapter)
+{
+       struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(Adapter);
+       u8 eeValue;
+
+       eeValue = rtw_read8(Adapter, REG_9346CR);
+       /*  To check system boot selection. */
+       pEEPROM->EepromOrEfuse = (eeValue & BOOT_FROM_EEPROM) ? true : false;
+       pEEPROM->bautoload_fail_flag = (eeValue & EEPROM_EN) ? false : true;
+
+       DBG_8723A("Boot from %s, Autoload %s !\n",
+                 (pEEPROM->EepromOrEfuse ? "EEPROM" : "EFUSE"),
+                 (pEEPROM->bautoload_fail_flag ? "Fail" : "OK"));
+
+       readAdapterInfo(Adapter);
+}
+
+static void _ReadRFType(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+
+       pHalData->rf_chip = RF_6052;
+}
+
+static void _ReadSilmComboMode(struct rtw_adapter *Adapter)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+
+       pHalData->SlimComboDbg = false; /*  Default is not debug mode. */
+}
+
+/*  */
+/*     Description: */
+/*             We should set Efuse cell selection to WiFi cell in default. */
+/*  */
+/*     Assumption: */
+/*             PASSIVE_LEVEL */
+/*  */
+/*     Added by Roger, 2010.11.23. */
+/*  */
+static void hal_EfuseCellSel(struct rtw_adapter *Adapter)
+{
+       u32 value32;
+
+       value32 = rtw_read32(Adapter, EFUSE_TEST);
+       value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0);
+       rtw_write32(Adapter, EFUSE_TEST, value32);
+}
+
+static int _ReadAdapterInfo8723AU(struct rtw_adapter *Adapter)
+{
+       /* struct hal_data_8723a        *pHalData = GET_HAL_DATA(Adapter); */
+       unsigned long start = jiffies;
+
+       MSG_8723A("====> _ReadAdapterInfo8723AU\n");
+
+       hal_EfuseCellSel(Adapter);
+
+       _ReadRFType(Adapter);/* rf_chip -> _InitRFType() */
+       _ReadPROMContent(Adapter);
+
+       /*  2010/10/25 MH THe function must be called after
+           borad_type & IC-Version recognize. */
+       _ReadSilmComboMode(Adapter);
+
+       /* MSG_8723A("%s()(done), rf_chip = 0x%x, rf_type = 0x%x\n",
+          __func__, pHalData->rf_chip, pHalData->rf_type); */
+
+       MSG_8723A("<==== _ReadAdapterInfo8723AU in %d ms\n",
+                 jiffies_to_msecs(jiffies - start));
+
+       return _SUCCESS;
+}
+
+static void ReadAdapterInfo8723AU(struct rtw_adapter *Adapter)
+{
+       /*  Read EEPROM size before call any EEPROM function */
+       Adapter->EepromAddressSize = GetEEPROMSize8723A(Adapter);
+
+       _ReadAdapterInfo8723AU(Adapter);
+}
+
+#define GPIO_DEBUG_PORT_NUM 0
+static void rtl8723au_trigger_gpio_0(struct rtw_adapter *padapter)
+{
+       u32 gpioctrl;
+       DBG_8723A("==> trigger_gpio_0...\n");
+       rtw_write16_async(padapter, REG_GPIO_PIN_CTRL, 0);
+       rtw_write8_async(padapter, REG_GPIO_PIN_CTRL+2, 0xFF);
+       gpioctrl = (BIT(GPIO_DEBUG_PORT_NUM) << 24)|
+               (BIT(GPIO_DEBUG_PORT_NUM) << 16);
+       rtw_write32_async(padapter, REG_GPIO_PIN_CTRL, gpioctrl);
+       gpioctrl |= (BIT(GPIO_DEBUG_PORT_NUM)<<8);
+       rtw_write32_async(padapter, REG_GPIO_PIN_CTRL, gpioctrl);
+       DBG_8723A("<=== trigger_gpio_0...\n");
+}
+
+/*
+ * If variable not handled here,
+ * some variables will be processed in SetHwReg8723A()
+ */
+static void SetHwReg8723AU(struct rtw_adapter *Adapter, u8 variable, u8 *val)
+{
+       switch (variable) {
+       case HW_VAR_RXDMA_AGG_PG_TH:
+               break;
+       case HW_VAR_SET_RPWM:
+               rtl8723a_set_rpwm(Adapter, *val);
+               break;
+       case HW_VAR_TRIGGER_GPIO_0:
+               rtl8723au_trigger_gpio_0(Adapter);
+               break;
+       default:
+               SetHwReg8723A(Adapter, variable, val);
+               break;
+       }
+
+}
+
+/*
+ * If variable not handled here,
+ * some variables will be processed in GetHwReg8723A()
+ */
+static void GetHwReg8723AU(struct rtw_adapter *Adapter, u8 variable, u8 *val)
+{
+       GetHwReg8723A(Adapter, variable, val);
+}
+
+/*  */
+/*     Description: */
+/*             Query setting of specified variable. */
+/*  */
+static u8 GetHalDefVar8192CUsb(struct rtw_adapter *Adapter,
+                              enum hal_def_variable eVariable, void *pValue)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
+       u8                      bResult = _SUCCESS;
+
+       switch (eVariable) {
+       case HAL_DEF_UNDERCORATEDSMOOTHEDPWDB:
+               *((int *)pValue) = pHalData->dmpriv.UndecoratedSmoothedPWDB;
+               break;
+       case HAL_DEF_IS_SUPPORT_ANT_DIV:
+               break;
+       case HAL_DEF_CURRENT_ANTENNA:
+               break;
+       case HAL_DEF_DRVINFO_SZ:
+               *((u32 *)pValue) = DRVINFO_SZ;
+               break;
+       case HAL_DEF_MAX_RECVBUF_SZ:
+               *((u32 *)pValue) = MAX_RECVBUF_SZ;
+               break;
+       case HAL_DEF_RX_PACKET_OFFSET:
+               *((u32 *)pValue) = RXDESC_SIZE + DRVINFO_SZ;
+               break;
+       case HAL_DEF_DBG_DUMP_RXPKT:
+               *((u8 *)pValue) = pHalData->bDumpRxPkt;
+               break;
+       case HAL_DEF_DBG_DM_FUNC:
+               *((u32 *)pValue) = pHalData->odmpriv.SupportAbility;
+               break;
+       case HW_VAR_MAX_RX_AMPDU_FACTOR:
+               *((u32 *)pValue) = IEEE80211_HT_MAX_AMPDU_64K;
+               break;
+       case HW_DEF_ODM_DBG_FLAG:
+       {
+               struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
+               printk("pDM_Odm->DebugComponents = 0x%llx\n",
+                      pDM_Odm->DebugComponents);
+       }
+               break;
+       default:
+               /* RT_TRACE(COMP_INIT, DBG_WARNING, ("GetHalDefVar8192CUsb(): "
+                  "Unkown variable: %d!\n", eVariable)); */
+               bResult = _FAIL;
+               break;
+       }
+
+       return bResult;
+}
+
+/*     Change default setting of specified variable. */
+static u8 SetHalDefVar8192CUsb(struct rtw_adapter *Adapter,
+                              enum hal_def_variable eVariable, void *pValue)
+{
+       struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
+       u8 bResult = _SUCCESS;
+
+       switch (eVariable) {
+       case HAL_DEF_DBG_DUMP_RXPKT:
+               pHalData->bDumpRxPkt = *((u8 *)pValue);
+               break;
+       case HAL_DEF_DBG_DM_FUNC:
+       {
+               u8 dm_func = *((u8 *)pValue);
+               struct dm_priv  *pdmpriv = &pHalData->dmpriv;
+               struct dm_odm_t *podmpriv = &pHalData->odmpriv;
+
+               if (dm_func == 0) { /* disable all dynamic func */
+                       podmpriv->SupportAbility = DYNAMIC_FUNC_DISABLE;
+                       DBG_8723A("==> Disable all dynamic function...\n");
+               } else if (dm_func == 1) {/* disable DIG */
+                       podmpriv->SupportAbility &= (~DYNAMIC_BB_DIG);
+                       DBG_8723A("==> Disable DIG...\n");
+               } else if (dm_func == 2) {/* disable High power */
+                       podmpriv->SupportAbility &= (~DYNAMIC_BB_DYNAMIC_TXPWR);
+               } else if (dm_func == 3) {/* disable tx power tracking */
+                       podmpriv->SupportAbility &= (~DYNAMIC_RF_CALIBRATION);
+                       DBG_8723A("==> Disable tx power tracking...\n");
+               } else if (dm_func == 4) {/* disable BT coexistence */
+                       pdmpriv->DMFlag &= (~DYNAMIC_FUNC_BT);
+               } else if (dm_func == 5) {/* disable antenna diversity */
+                       podmpriv->SupportAbility &= (~DYNAMIC_BB_ANT_DIV);
+               } else if (dm_func == 6) {/* turn on all dynamic func */
+                       if (!(podmpriv->SupportAbility & DYNAMIC_BB_DIG)) {
+                               struct dig_t *pDigTable =
+                                       &podmpriv->DM_DigTable;
+                               pDigTable->CurIGValue = rtw_read8(Adapter, 0xc50);
+                       }
+                       pdmpriv->DMFlag |= DYNAMIC_FUNC_BT;
+                       podmpriv->SupportAbility = DYNAMIC_ALL_FUNC_ENABLE;
+                       DBG_8723A("==> Turn on all dynamic function...\n");
+               }
+       }
+               break;
+       case HW_DEF_FA_CNT_DUMP:
+       {
+               u8 bRSSIDump = *((u8 *)pValue);
+               struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
+               if (bRSSIDump)
+                       pDM_Odm->DebugComponents = ODM_COMP_DIG|ODM_COMP_FA_CNT;
+               else
+                       pDM_Odm->DebugComponents = 0;
+       }
+               break;
+       case HW_DEF_ODM_DBG_FLAG:
+       {
+               u64 DebugComponents = *((u64 *)pValue);
+               struct dm_odm_t *pDM_Odm = &pHalData->odmpriv;
+               pDM_Odm->DebugComponents = DebugComponents;
+       }
+               break;
+       default:
+               /* RT_TRACE(COMP_INIT, DBG_TRACE, ("SetHalDefVar819xUsb(): "
+                  "Unkown variable: %d!\n", eVariable)); */
+               bResult = _FAIL;
+               break;
+       }
+
+       return bResult;
+}
+
+static void UpdateHalRAMask8192CUsb(struct rtw_adapter *padapter,
+                                   u32 mac_id, u8 rssi_level)
+{
+       u8      init_rate = 0;
+       u8      networkType, raid;
+       u32     mask, rate_bitmap;
+       u8      shortGIrate = false;
+       int     supportRateNum = 0;
+       struct sta_info *psta;
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+       struct dm_priv  *pdmpriv = &pHalData->dmpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct wlan_bssid_ex *cur_network = &pmlmeinfo->network;
+
+       if (mac_id >= NUM_STA) /* CAM_SIZE */
+               return;
+
+       psta = pmlmeinfo->FW_sta_info[mac_id].psta;
+       if (psta == NULL)
+               return;
+
+       switch (mac_id) {
+       case 0:/*  for infra mode */
+               supportRateNum =
+                       rtw_get_rateset_len23a(cur_network->SupportedRates);
+               networkType = judge_network_type23a(padapter,
+                                                cur_network->SupportedRates,
+                                                supportRateNum) & 0xf;
+               /* pmlmeext->cur_wireless_mode = networkType; */
+               raid = networktype_to_raid23a(networkType);
+
+               mask = update_supported_rate23a(cur_network->SupportedRates,
+                                            supportRateNum);
+               mask |= (pmlmeinfo->HT_enable) ?
+                       update_MSC_rate23a(&pmlmeinfo->HT_caps) : 0;
+
+               if (support_short_GI23a(padapter, &pmlmeinfo->HT_caps))
+                       shortGIrate = true;
+               break;
+
+       case 1:/* for broadcast/multicast */
+               supportRateNum = rtw_get_rateset_len23a(
+                       pmlmeinfo->FW_sta_info[mac_id].SupportedRates);
+               if (pmlmeext->cur_wireless_mode & WIRELESS_11B)
+                       networkType = WIRELESS_11B;
+               else
+                       networkType = WIRELESS_11G;
+               raid = networktype_to_raid23a(networkType);
+
+               mask = update_basic_rate23a(cur_network->SupportedRates,
+                                        supportRateNum);
+               break;
+
+       default: /* for each sta in IBSS */
+               supportRateNum = rtw_get_rateset_len23a(
+                       pmlmeinfo->FW_sta_info[mac_id].SupportedRates);
+               networkType = judge_network_type23a(padapter,
+                                                pmlmeinfo->FW_sta_info[mac_id].SupportedRates,
+                                                supportRateNum) & 0xf;
+               /* pmlmeext->cur_wireless_mode = networkType; */
+               raid = networktype_to_raid23a(networkType);
+
+               mask = update_supported_rate23a(cur_network->SupportedRates,
+                                            supportRateNum);
+
+               /* todo: support HT in IBSS */
+               break;
+       }
+
+       /* mask &= 0x0fffffff; */
+       rate_bitmap = 0x0fffffff;
+       rate_bitmap = ODM_Get_Rate_Bitmap23a(&pHalData->odmpriv,
+                                         mac_id, mask, rssi_level);
+       printk(KERN_DEBUG "%s => mac_id:%d, networkType:0x%02x, "
+              "mask:0x%08x\n\t ==> rssi_level:%d, rate_bitmap:0x%08x\n",
+              __func__,
+              mac_id, networkType, mask, rssi_level, rate_bitmap);
+
+       mask &= rate_bitmap;
+       mask |= ((raid<<28)&0xf0000000);
+
+       init_rate = get_highest_rate_idx23a(mask)&0x3f;
+
+       if (pHalData->fw_ractrl == true) {
+               u8 arg = 0;
+
+               /* arg = (cam_idx-4)&0x1f;MACID */
+               arg = mac_id&0x1f;/* MACID */
+
+               arg |= BIT(7);
+
+               if (shortGIrate == true)
+                       arg |= BIT(5);
+
+               DBG_8723A("update raid entry, mask = 0x%x, arg = 0x%x\n",
+                         mask, arg);
+
+               rtl8723a_set_raid_cmd(padapter, mask, arg);
+       } else {
+               if (shortGIrate == true)
+                       init_rate |= BIT(6);
+
+               rtw_write8(padapter, (REG_INIDATA_RATE_SEL+mac_id), init_rate);
+       }
+
+       /* set ra_id */
+       psta->raid = raid;
+       psta->init_rate = init_rate;
+
+       /* set correct initial date rate for each mac_id */
+       pdmpriv->INIDATA_RATE[mac_id] = init_rate;
+}
+
+static void rtl8723au_init_default_value(struct rtw_adapter *padapter)
+{
+       rtl8723a_init_default_value(padapter);
+}
+
+static u8 rtl8192cu_ps_func(struct rtw_adapter *Adapter,
+                           enum hal_intf_ps_func efunc_id, u8 *val)
+{
+       return true;
+}
+
+int rtl8723au_set_hal_ops(struct rtw_adapter *padapter)
+{
+       struct hal_ops  *pHalFunc = &padapter->HalFunc;
+
+       padapter->HalData = kzalloc(sizeof(struct hal_data_8723a), GFP_KERNEL);
+       if (!padapter->HalData) {
+               DBG_8723A("cannot alloc memory for HAL DATA\n");
+               return -ENOMEM;
+       }
+       padapter->hal_data_sz = sizeof(struct hal_data_8723a);
+
+       pHalFunc->hal_init = &rtl8723au_hal_init;
+       pHalFunc->hal_deinit = &rtl8723au_hal_deinit;
+
+       pHalFunc->inirp_init = &rtl8723au_inirp_init;
+       pHalFunc->inirp_deinit = &rtl8723au_inirp_deinit;
+
+       pHalFunc->init_xmit_priv = &rtl8723au_init_xmit_priv;
+       pHalFunc->free_xmit_priv = &rtl8723au_free_xmit_priv;
+
+       pHalFunc->init_recv_priv = &rtl8723au_init_recv_priv;
+       pHalFunc->free_recv_priv = &rtl8723au_free_recv_priv;
+       pHalFunc->InitSwLeds = NULL;
+       pHalFunc->DeInitSwLeds = NULL;
+
+       pHalFunc->init_default_value = &rtl8723au_init_default_value;
+       pHalFunc->intf_chip_configure = &rtl8723au_interface_configure;
+       pHalFunc->read_adapter_info = &ReadAdapterInfo8723AU;
+       pHalFunc->SetHwRegHandler = &SetHwReg8723AU;
+       pHalFunc->GetHwRegHandler = &GetHwReg8723AU;
+       pHalFunc->GetHalDefVarHandler = &GetHalDefVar8192CUsb;
+       pHalFunc->SetHalDefVarHandler = &SetHalDefVar8192CUsb;
+       pHalFunc->UpdateRAMaskHandler = &UpdateHalRAMask8192CUsb;
+       pHalFunc->hal_xmit = &rtl8723au_hal_xmit;
+       pHalFunc->mgnt_xmit = &rtl8723au_mgnt_xmit;
+       pHalFunc->hal_xmitframe_enqueue = &rtl8723au_hal_xmitframe_enqueue;
+       pHalFunc->interface_ps_func = &rtl8192cu_ps_func;
+       rtl8723a_set_hal_ops(pHalFunc);
+       return 0;
+}
diff --git a/drivers/staging/rtl8723au/hal/usb_ops_linux.c b/drivers/staging/rtl8723au/hal/usb_ops_linux.c
new file mode 100644 (file)
index 0000000..0311cdf
--- /dev/null
@@ -0,0 +1,848 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _HCI_OPS_OS_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+#include <usb_ops.h>
+#include <recv_osdep.h>
+#include <rtl8723a_hal.h>
+#include <rtl8723a_recv.h>
+
+static int usbctrl_vendorreq(struct intf_hdl *pintfhdl, u8 request, u16 value, u16 index, void *pdata, u16 len, u8 requesttype)
+{
+       struct rtw_adapter              *padapter = pintfhdl->padapter ;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+       struct usb_device *udev = pdvobjpriv->pusbdev;
+
+       unsigned int pipe;
+       int status = 0;
+       u8 reqtype;
+       u8 *pIo_buf;
+       int vendorreq_times = 0;
+
+       if ((padapter->bSurpriseRemoved) || (padapter->pwrctrlpriv.pnp_bstop_trx)) {
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("usbctrl_vendorreq:(padapter->bSurpriseRemoved||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n"));
+               status = -EPERM;
+               goto exit;
+       }
+
+       if (len > MAX_VENDOR_REQ_CMD_SIZE) {
+               DBG_8723A("[%s] Buffer len error , vendor request failed\n", __FUNCTION__);
+               status = -EINVAL;
+               goto exit;
+       }
+
+       mutex_lock(&pdvobjpriv->usb_vendor_req_mutex);
+
+       /*  Acquire IO memory for vendorreq */
+       pIo_buf = pdvobjpriv->usb_vendor_req_buf;
+
+       if (pIo_buf == NULL) {
+               DBG_8723A("[%s] pIo_buf == NULL \n", __FUNCTION__);
+               status = -ENOMEM;
+               goto release_mutex;
+       }
+
+       while (++vendorreq_times <= MAX_USBCTRL_VENDORREQ_TIMES) {
+               memset(pIo_buf, 0, len);
+
+               if (requesttype == 0x01) {
+                       pipe = usb_rcvctrlpipe(udev, 0);/* read_in */
+                       reqtype =  REALTEK_USB_VENQT_READ;
+               } else {
+                       pipe = usb_sndctrlpipe(udev, 0);/* write_out */
+                       reqtype =  REALTEK_USB_VENQT_WRITE;
+                       memcpy(pIo_buf, pdata, len);
+               }
+
+               status = rtw_usb_control_msg(udev, pipe, request, reqtype,
+                                            value, index, pIo_buf, len,
+                                            RTW_USB_CONTROL_MSG_TIMEOUT);
+
+               if (status == len) {   /*  Success this control transfer. */
+                       rtw_reset_continual_urb_error(pdvobjpriv);
+                       if (requesttype == 0x01) {
+                               /* For Control read transfer, we have to copy
+                                * the read data from pIo_buf to pdata.
+                                */
+                               memcpy(pdata, pIo_buf,  len);
+                       }
+               } else { /*  error cases */
+                       DBG_8723A("reg 0x%x, usb %s %u fail, status:%d value ="
+                                 " 0x%x, vendorreq_times:%d\n",
+                                 value, (requesttype == 0x01) ? "read" : "write",
+                                 len, status, *(u32 *)pdata, vendorreq_times);
+
+                       if (status < 0) {
+                               if (status == (-ESHUTDOWN) || status == -ENODEV) {
+                                       padapter->bSurpriseRemoved = true;
+                               } else {
+                                       struct hal_data_8723a   *pHalData = GET_HAL_DATA(padapter);
+                                       pHalData->srestpriv.Wifi_Error_Status = USB_VEN_REQ_CMD_FAIL;
+                               }
+                       } else { /*  status != len && status >= 0 */
+                               if (status > 0) {
+                                       if (requesttype == 0x01) {
+                                               /*  For Control read transfer, we have to copy
+                                                * the read data from pIo_buf to pdata.
+                                                */
+                                               memcpy(pdata, pIo_buf,  len);
+                                       }
+                               }
+                       }
+
+                       if (rtw_inc_and_chk_continual_urb_error(pdvobjpriv)) {
+                               padapter->bSurpriseRemoved = true;
+                               break;
+                       }
+
+               }
+
+               /*  firmware download is checksumed, don't retry */
+               if ((value >= FW_8723A_START_ADDRESS && value <= FW_8723A_END_ADDRESS) || status == len)
+                       break;
+       }
+
+release_mutex:
+       mutex_unlock(&pdvobjpriv->usb_vendor_req_mutex);
+exit:
+       return status;
+}
+
+static u8 usb_read8(struct intf_hdl *pintfhdl, u32 addr)
+{
+       u8 request;
+       u8 requesttype;
+       u16 wvalue;
+       u16 index;
+       u16 len;
+       u8 data = 0;
+
+       request = 0x05;
+       requesttype = 0x01;/* read_in */
+       index = 0;/* n/a */
+
+       wvalue = (u16)(addr&0x0000ffff);
+       len = 1;
+
+       usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+       return data;
+}
+
+static u16 usb_read16(struct intf_hdl *pintfhdl, u32 addr)
+{
+       u8 request;
+       u8 requesttype;
+       u16 wvalue;
+       u16 index;
+       u16 len;
+       u16 data = 0;
+
+       request = 0x05;
+       requesttype = 0x01;/* read_in */
+       index = 0;/* n/a */
+
+       wvalue = (u16)(addr&0x0000ffff);
+       len = 2;
+
+       usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+       return data;
+}
+
+static u32 usb_read32(struct intf_hdl *pintfhdl, u32 addr)
+{
+       u8 request;
+       u8 requesttype;
+       u16 wvalue;
+       u16 index;
+       u16 len;
+       u32 data = 0;
+
+       request = 0x05;
+       requesttype = 0x01;/* read_in */
+       index = 0;/* n/a */
+
+       wvalue = (u16)(addr&0x0000ffff);
+       len = 4;
+
+       usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+       return data;
+}
+
+static int usb_write8(struct intf_hdl *pintfhdl, u32 addr, u8 val)
+{
+       u8 request;
+       u8 requesttype;
+       u16 wvalue;
+       u16 index;
+       u16 len;
+       u8 data;
+       int ret;
+
+       request = 0x05;
+       requesttype = 0x00;/* write_out */
+       index = 0;/* n/a */
+
+       wvalue = (u16)(addr&0x0000ffff);
+       len = 1;
+
+       data = val;
+
+       ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+       return ret;
+}
+
+static int usb_write16(struct intf_hdl *pintfhdl, u32 addr, u16 val)
+{
+       u8 request;
+       u8 requesttype;
+       u16 wvalue;
+       u16 index;
+       u16 len;
+       u16 data;
+       int ret;
+
+       request = 0x05;
+       requesttype = 0x00;/* write_out */
+       index = 0;/* n/a */
+
+       wvalue = (u16)(addr&0x0000ffff);
+       len = 2;
+
+       data = val;
+
+       ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+       return ret;
+}
+
+static int usb_write32(struct intf_hdl *pintfhdl, u32 addr, u32 val)
+{
+       u8 request;
+       u8 requesttype;
+       u16 wvalue;
+       u16 index;
+       u16 len;
+       u32 data;
+       int ret;
+
+       request = 0x05;
+       requesttype = 0x00;/* write_out */
+       index = 0;/* n/a */
+
+       wvalue = (u16)(addr&0x0000ffff);
+       len = 4;
+       data = val;
+
+       ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, &data, len, requesttype);
+
+       return ret;
+}
+
+static int usb_writeN(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata)
+{
+       u8 request;
+       u8 requesttype;
+       u16 wvalue;
+       u16 index;
+       u16 len;
+       u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0};
+       int ret;
+
+       request = 0x05;
+       requesttype = 0x00;/* write_out */
+       index = 0;/* n/a */
+
+       wvalue = (u16)(addr&0x0000ffff);
+       len = length;
+        memcpy(buf, pdata, len);
+
+       ret = usbctrl_vendorreq(pintfhdl, request, wvalue, index, buf, len, requesttype);
+
+       return ret;
+}
+
+/*
+ * Description:
+ *     Recognize the interrupt content by reading the interrupt
+ *     register or content and masking interrupt mask (IMR)
+ *     if it is our NIC's interrupt. After recognizing, we may clear
+ *     the all interrupts (ISR).
+ * Arguments:
+ *     [in] Adapter -
+ *             The adapter context.
+ *     [in] pContent -
+ *             Under PCI interface, this field is ignord.
+ *             Under USB interface, the content is the interrupt
+ *             content pointer.
+ *             Under SDIO interface, this is the interrupt type which
+ *             is Local interrupt or system interrupt.
+ *     [in] ContentLen -
+ *             The length in byte of pContent.
+ * Return:
+ *     If any interrupt matches the mask (IMR), return true, and
+ *     return false otherwise.
+ */
+static bool
+InterruptRecognized8723AU(struct rtw_adapter *Adapter, void *pContent,
+                         u32 ContentLen)
+{
+       struct hal_data_8723a   *pHalData = GET_HAL_DATA(Adapter);
+       u8 *buffer = (u8 *)pContent;
+       struct reportpwrstate_parm report;
+
+       memcpy(&pHalData->IntArray[0], &buffer[USB_INTR_CONTENT_HISR_OFFSET],
+              4);
+       pHalData->IntArray[0] &= pHalData->IntrMask[0];
+
+       /* For HISR extension. Added by tynli. 2009.10.07. */
+       memcpy(&pHalData->IntArray[1],
+              &buffer[USB_INTR_CONTENT_HISRE_OFFSET], 4);
+       pHalData->IntArray[1] &= pHalData->IntrMask[1];
+
+       /* We sholud remove this function later because DDK suggest
+        * not to executing too many operations in MPISR  */
+
+       memcpy(&report.state, &buffer[USB_INTR_CPWM_OFFSET], 1);
+
+       return ((pHalData->IntArray[0])&pHalData->IntrMask[0]) != 0 ||
+               ((pHalData->IntArray[1])&pHalData->IntrMask[1]) != 0;
+}
+
+static void usb_read_interrupt_complete(struct urb *purb, struct pt_regs *regs)
+{
+       int err;
+       struct rtw_adapter *padapter = (struct rtw_adapter *)purb->context;
+
+       if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
+           padapter->bReadPortCancel) {
+               DBG_8723A("%s() RX Warning! bDriverStopped(%d) OR "
+                         "bSurpriseRemoved(%d) bReadPortCancel(%d)\n",
+                         __FUNCTION__, padapter->bDriverStopped,
+                         padapter->bSurpriseRemoved,
+                         padapter->bReadPortCancel);
+               return;
+       }
+
+       if (purb->status == 0) {
+               struct c2h_evt_hdr *c2h_evt;
+
+               c2h_evt = (struct c2h_evt_hdr *)purb->transfer_buffer;
+
+               if (purb->actual_length > USB_INTR_CONTENT_LENGTH) {
+                       DBG_8723A("usb_read_interrupt_complete: purb->actual_"
+                                 "length > USB_INTR_CONTENT_LENGTH\n");
+                       goto urb_submit;
+               }
+
+               InterruptRecognized8723AU(padapter, purb->transfer_buffer,
+                                         purb->actual_length);
+
+               if (c2h_evt_exist(c2h_evt)) {
+                       if (c2h_id_filter_ccx_8723a(c2h_evt->id)) {
+                               /* Handle CCX report here */
+                               handle_txrpt_ccx_8723a(padapter, (void *)(c2h_evt->payload));
+                               /* Replace with special pointer to
+                                  trigger c2h_evt_clear23a */
+                               if (rtw_cbuf_push23a(padapter->evtpriv.c2h_queue,
+                                                 (void *)&padapter->evtpriv) !=
+                                   _SUCCESS)
+                                       DBG_8723A("%s rtw_cbuf_push23a fail\n",
+                                                 __func__);
+                               schedule_work(&padapter->evtpriv.c2h_wk);
+                       } else if ((c2h_evt = (struct c2h_evt_hdr *)
+                                   kmalloc(16, GFP_ATOMIC))) {
+                               memcpy(c2h_evt, purb->transfer_buffer, 16);
+                               if (rtw_cbuf_push23a(padapter->evtpriv.c2h_queue,
+                                                 (void *)c2h_evt) != _SUCCESS)
+                                       DBG_8723A("%s rtw_cbuf_push23a fail\n",
+                                                 __func__);
+                               schedule_work(&padapter->evtpriv.c2h_wk);
+                       } else {
+                               /* Error handling for malloc fail */
+                               if (rtw_cbuf_push23a(padapter->evtpriv.c2h_queue,
+                                                 (void *)NULL) != _SUCCESS)
+                                       DBG_8723A("%s rtw_cbuf_push23a fail\n",
+                                                 __func__);
+                               schedule_work(&padapter->evtpriv.c2h_wk);
+                       }
+               }
+
+urb_submit:
+               err = usb_submit_urb(purb, GFP_ATOMIC);
+               if (err && (err != -EPERM)) {
+                       DBG_8723A("cannot submit interrupt in-token(err = "
+                                 "0x%08x), urb_status = %d\n",
+                                 err, purb->status);
+               }
+       } else {
+               DBG_8723A("###=> usb_read_interrupt_complete => urb "
+                         "status(%d)\n", purb->status);
+
+               switch (purb->status) {
+               case -EINVAL:
+               case -EPIPE:
+               case -ENODEV:
+               case -ESHUTDOWN:
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                                ("usb_read_port_complete:bSurpriseRemoved ="
+                                 "true\n"));
+                       /* Fall Through here */
+               case -ENOENT:
+                       padapter->bDriverStopped = true;
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                                ("usb_read_port_complete:bDriverStopped ="
+                                 "true\n"));
+                       break;
+               case -EPROTO:
+                       break;
+               case -EINPROGRESS:
+                       DBG_8723A("ERROR: URB IS IN PROGRESS!/n");
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+static u32 usb_read_interrupt(struct intf_hdl *pintfhdl, u32 addr)
+{
+       int err;
+       unsigned int pipe;
+       u32 ret = _SUCCESS;
+       struct rtw_adapter *adapter = pintfhdl->padapter;
+       struct dvobj_priv *pdvobj = adapter_to_dvobj(adapter);
+       struct recv_priv *precvpriv = &adapter->recvpriv;
+       struct usb_device *pusbd = pdvobj->pusbdev;
+
+       /* translate DMA FIFO addr to pipehandle */
+       pipe = ffaddr2pipehdl23a(pdvobj, addr);
+
+       usb_fill_int_urb(precvpriv->int_in_urb, pusbd, pipe,
+                        precvpriv->int_in_buf, USB_INTR_CONTENT_LENGTH,
+                        usb_read_interrupt_complete, adapter, 1);
+
+       err = usb_submit_urb(precvpriv->int_in_urb, GFP_ATOMIC);
+       if (err && (err != -EPERM)) {
+               DBG_8723A("cannot submit interrupt in-token(err = 0x%08x),"
+                         "urb_status = %d\n", err,
+                         precvpriv->int_in_urb->status);
+               ret = _FAIL;
+       }
+
+       return ret;
+}
+
+static int recvbuf2recvframe(struct rtw_adapter *padapter, struct sk_buff *pskb)
+{
+       u8      *pbuf;
+       u8      shift_sz = 0;
+       u16     pkt_cnt;
+       u32     pkt_offset, skb_len, alloc_sz;
+       s32     transfer_len;
+       struct recv_stat        *prxstat;
+       struct phy_stat *pphy_info = NULL;
+       struct sk_buff          *pkt_copy = NULL;
+       struct recv_frame       *precvframe = NULL;
+       struct rx_pkt_attrib    *pattrib = NULL;
+       struct recv_priv        *precvpriv = &padapter->recvpriv;
+       struct rtw_queue        *pfree_recv_queue = &precvpriv->free_recv_queue;
+
+       transfer_len = (s32)pskb->len;
+       pbuf = pskb->data;
+
+       prxstat = (struct recv_stat *)pbuf;
+       pkt_cnt = (le32_to_cpu(prxstat->rxdw2) >> 16) & 0xff;
+
+       do {
+               RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                        ("recvbuf2recvframe: rxdesc = offsset 0:0x%08x, "
+                         "4:0x%08x, 8:0x%08x, C:0x%08x\n", prxstat->rxdw0,
+                         prxstat->rxdw1, prxstat->rxdw2, prxstat->rxdw4));
+
+               prxstat = (struct recv_stat *)pbuf;
+
+               precvframe = rtw_alloc_recvframe23a(pfree_recv_queue);
+               if (!precvframe) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("recvbuf2recvframe: precvframe == NULL\n"));
+                       DBG_8723A("%s()-%d: rtw_alloc_recvframe23a() failed! RX "
+                                 "Drop!\n", __FUNCTION__, __LINE__);
+                       goto _exit_recvbuf2recvframe;
+               }
+
+               INIT_LIST_HEAD(&precvframe->list);
+
+               update_recvframe_attrib(precvframe, prxstat);
+
+               pattrib = &precvframe->attrib;
+
+               if (pattrib->crc_err) {
+                       DBG_8723A("%s()-%d: RX Warning! rx CRC ERROR !!\n",
+                                 __FUNCTION__, __LINE__);
+                       rtw_free_recvframe23a(precvframe, pfree_recv_queue);
+                       goto _exit_recvbuf2recvframe;
+               }
+
+               pkt_offset = RXDESC_SIZE + pattrib->drvinfo_sz +
+                       pattrib->shift_sz + pattrib->pkt_len;
+
+               if ((pattrib->pkt_len <= 0) || (pkt_offset > transfer_len)) {
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_info_,
+                                ("recvbuf2recvframe: pkt_len<= 0\n"));
+                       DBG_8723A("%s()-%d: RX Warning!\n",
+                                 __FUNCTION__, __LINE__);
+                       rtw_free_recvframe23a(precvframe, pfree_recv_queue);
+                       goto _exit_recvbuf2recvframe;
+               }
+
+               /*      Modified by Albert 20101213 */
+               /*      For 8 bytes IP header alignment. */
+               /*      Qos data, wireless lan header length is 26 */
+               if (pattrib->qos) {
+                       shift_sz = 6;
+               } else {
+                       shift_sz = 0;
+               }
+
+               skb_len = pattrib->pkt_len;
+
+               /* for first fragment packet, driver need allocate
+                * 1536+drvinfo_sz+RXDESC_SIZE to defrag packet.
+                * modify alloc_sz for recvive crc error packet
+                * by thomas 2011-06-02 */
+               if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
+                       /* alloc_sz = 1664;     1664 is 128 alignment. */
+                       if (skb_len <= 1650)
+                               alloc_sz = 1664;
+                       else
+                               alloc_sz = skb_len + 14;
+               } else {
+                       alloc_sz = skb_len;
+               /*  6 is for IP header 8 bytes alignment in QoS packet case. */
+               /*  8 is for skb->data 4 bytes alignment. */
+                       alloc_sz += 14;
+               }
+
+               pkt_copy = netdev_alloc_skb(padapter->pnetdev, alloc_sz);
+               if (pkt_copy) {
+                       pkt_copy->dev = padapter->pnetdev;
+                       precvframe->pkt = pkt_copy;
+                       skb_reserve(pkt_copy, 8 - ((unsigned long)(pkt_copy->data) & 7));/* force pkt_copy->data at 8-byte alignment address */
+       /*force ip_hdr at 8-byte alignment address according to shift_sz. */
+                       skb_reserve(pkt_copy, shift_sz);
+                       memcpy(pkt_copy->data, (pbuf + pattrib->shift_sz + pattrib->drvinfo_sz + RXDESC_SIZE), skb_len);
+                       skb_put(pkt_copy, skb_len);
+               } else {
+                       if ((pattrib->mfrag == 1) && (pattrib->frag_num == 0)) {
+                               DBG_8723A("recvbuf2recvframe: alloc_skb fail, "
+                                         "drop frag frame \n");
+                               rtw_free_recvframe23a(precvframe,
+                                                  pfree_recv_queue);
+                               goto _exit_recvbuf2recvframe;
+                       }
+
+                       precvframe->pkt = skb_clone(pskb, GFP_ATOMIC);
+                       if (!precvframe->pkt) {
+                               DBG_8723A("recvbuf2recvframe: skb_clone "
+                                         "fail\n");
+                               rtw_free_recvframe23a(precvframe,
+                                                  pfree_recv_queue);
+                               goto _exit_recvbuf2recvframe;
+                       }
+               }
+
+               if (pattrib->physt) {
+                       pphy_info = (struct phy_stat *)(pbuf + RXDESC_OFFSET);
+                       update_recvframe_phyinfo(precvframe, pphy_info);
+               }
+
+               if (rtw_recv_entry23a(precvframe) != _SUCCESS)
+                       RT_TRACE(_module_rtl871x_recv_c_, _drv_err_,
+                                ("recvbuf2recvframe: rtw_recv_entry23a"
+                                 "(precvframe) != _SUCCESS\n"));
+
+               pkt_cnt--;
+               transfer_len -= pkt_offset;
+               pbuf += pkt_offset;
+               precvframe = NULL;
+               pkt_copy = NULL;
+
+               if (transfer_len > 0 && pkt_cnt == 0)
+                       pkt_cnt = (le32_to_cpu(prxstat->rxdw2)>>16) & 0xff;
+
+       } while ((transfer_len > 0) && (pkt_cnt > 0));
+
+_exit_recvbuf2recvframe:
+
+       return _SUCCESS;
+}
+
+void rtl8723au_recv_tasklet(void *priv)
+{
+       struct sk_buff *pskb;
+       struct rtw_adapter *padapter = (struct rtw_adapter *)priv;
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+
+       while (NULL != (pskb = skb_dequeue(&precvpriv->rx_skb_queue))) {
+               if ((padapter->bDriverStopped) ||
+                   (padapter->bSurpriseRemoved)) {
+                       DBG_8723A("recv_tasklet => bDriverStopped or "
+                                 "bSurpriseRemoved \n");
+                       dev_kfree_skb_any(pskb);
+                       break;
+               }
+
+               recvbuf2recvframe(padapter, pskb);
+               skb_reset_tail_pointer(pskb);
+
+               pskb->len = 0;
+
+               skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb);
+       }
+}
+
+static void usb_read_port_complete(struct urb *purb, struct pt_regs *regs)
+{
+       struct recv_buf *precvbuf = (struct recv_buf *)purb->context;
+       struct rtw_adapter *padapter = (struct rtw_adapter *)precvbuf->adapter;
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+       struct hal_data_8723a *pHalData;
+
+       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                ("usb_read_port_complete!!!\n"));
+
+       precvpriv->rx_pending_cnt--;
+
+       if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
+           padapter->bReadPortCancel) {
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("usb_read_port_complete:bDriverStopped(%d) OR "
+                         "bSurpriseRemoved(%d)\n", padapter->bDriverStopped,
+                         padapter->bSurpriseRemoved));
+
+               DBG_8723A("%s()-%d: RX Warning! bDriverStopped(%d) OR "
+                         "bSurpriseRemoved(%d) bReadPortCancel(%d)\n",
+                         __FUNCTION__, __LINE__, padapter->bDriverStopped,
+                         padapter->bSurpriseRemoved, padapter->bReadPortCancel);
+               return;
+       }
+
+       if (purb->status == 0) {
+               if ((purb->actual_length > MAX_RECVBUF_SZ) ||
+                   (purb->actual_length < RXDESC_SIZE)) {
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                                ("usb_read_port_complete: (purb->actual_"
+                                 "length > MAX_RECVBUF_SZ) || (purb->actual_"
+                                 "length < RXDESC_SIZE)\n"));
+                       rtw_read_port(padapter, precvpriv->ff_hwaddr, 0,
+                                     precvbuf);
+                       DBG_8723A("%s()-%d: RX Warning!\n",
+                                 __FUNCTION__, __LINE__);
+               } else {
+                       rtw_reset_continual_urb_error(
+                               adapter_to_dvobj(padapter));
+
+                       skb_put(precvbuf->pskb, purb->actual_length);
+                       skb_queue_tail(&precvpriv->rx_skb_queue,
+                                      precvbuf->pskb);
+
+                       if (skb_queue_len(&precvpriv->rx_skb_queue) <= 1)
+                               tasklet_schedule(&precvpriv->recv_tasklet);
+
+                       precvbuf->pskb = NULL;
+                       rtw_read_port(padapter, precvpriv->ff_hwaddr, 0,
+                                     precvbuf);
+               }
+       } else {
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("usb_read_port_complete : purb->status(%d) != 0 \n",
+                         purb->status));
+               skb_put(precvbuf->pskb, purb->actual_length);
+               precvbuf->pskb = NULL;
+
+               DBG_8723A("###=> usb_read_port_complete => urb status(%d)\n",
+                         purb->status);
+
+               if (rtw_inc_and_chk_continual_urb_error(
+                           adapter_to_dvobj(padapter))) {
+                       padapter->bSurpriseRemoved = true;
+               }
+
+               switch (purb->status) {
+               case -EINVAL:
+               case -EPIPE:
+               case -ENODEV:
+               case -ESHUTDOWN:
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                                ("usb_read_port_complete:bSurprise"
+                                 "Removed = true\n"));
+                       /* Intentional fall through here */
+               case -ENOENT:
+                       padapter->bDriverStopped = true;
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                                ("usb_read_port_complete:"
+                                 "bDriverStopped = true\n"));
+                       break;
+               case -EPROTO:
+               case -EOVERFLOW:
+                       pHalData = GET_HAL_DATA(padapter);
+                       pHalData->srestpriv.Wifi_Error_Status =
+                               USB_READ_PORT_FAIL;
+                       rtw_read_port(padapter, precvpriv->ff_hwaddr,
+                                     0, precvbuf);
+                       break;
+               case -EINPROGRESS:
+                       DBG_8723A("ERROR: URB IS IN PROGRESS!/n");
+                       break;
+               default:
+                       break;
+               }
+
+       }
+}
+
+static u32 usb_read_port(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+                        struct recv_buf *precvbuf)
+{
+       int err;
+       unsigned int pipe;
+       unsigned long tmpaddr = 0;
+       unsigned long alignment = 0;
+       u32 ret = _SUCCESS;
+       struct urb *purb = NULL;
+       struct rtw_adapter              *adapter = pintfhdl->padapter;
+       struct dvobj_priv       *pdvobj = adapter_to_dvobj(adapter);
+       struct recv_priv        *precvpriv = &adapter->recvpriv;
+       struct usb_device       *pusbd = pdvobj->pusbdev;
+
+       if (adapter->bDriverStopped || adapter->bSurpriseRemoved ||
+           adapter->pwrctrlpriv.pnp_bstop_trx) {
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("usb_read_port:(padapter->bDriverStopped ||"
+                         "padapter->bSurpriseRemoved ||adapter->"
+                         "pwrctrlpriv.pnp_bstop_trx)!!!\n"));
+               return _FAIL;
+       }
+
+       if (!precvbuf) {
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("usb_read_port:precvbuf == NULL\n"));
+               return _FAIL;
+       }
+
+       if (!precvbuf->pskb)
+               precvbuf->pskb = skb_dequeue(&precvpriv->free_recv_skb_queue);
+
+       rtl8723au_init_recvbuf(adapter, precvbuf);
+
+       /* re-assign for linux based on skb */
+       if (!precvbuf->pskb) {
+               precvbuf->pskb = netdev_alloc_skb(adapter->pnetdev, MAX_RECVBUF_SZ + RECVBUFF_ALIGN_SZ);
+               if (precvbuf->pskb == NULL) {
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("init_recvbuf(): alloc_skb fail!\n"));
+                       return _FAIL;
+               }
+
+               tmpaddr = (unsigned long)precvbuf->pskb->data;
+               alignment = tmpaddr & (RECVBUFF_ALIGN_SZ-1);
+               skb_reserve(precvbuf->pskb, (RECVBUFF_ALIGN_SZ - alignment));
+       }
+
+       precvpriv->rx_pending_cnt++;
+
+       purb = precvbuf->purb;
+
+       /* translate DMA FIFO addr to pipehandle */
+       pipe = ffaddr2pipehdl23a(pdvobj, addr);
+
+       usb_fill_bulk_urb(purb, pusbd, pipe, precvbuf->pskb->data,
+                         MAX_RECVBUF_SZ, usb_read_port_complete,
+                         precvbuf);/* context is precvbuf */
+
+       err = usb_submit_urb(purb, GFP_ATOMIC);
+       if ((err) && (err != -EPERM)) {
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("cannot submit rx in-token(err = 0x%.8x), URB_STATUS "
+                         "= 0x%.8x", err, purb->status));
+               DBG_8723A("cannot submit rx in-token(err = 0x%08x), urb_status "
+                         "= %d\n", err, purb->status);
+               ret = _FAIL;
+       }
+       return ret;
+}
+
+void rtl8723au_xmit_tasklet(void *priv)
+{
+       int ret = false;
+       struct rtw_adapter *padapter = (struct rtw_adapter *)priv;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+
+       if (check_fwstate(&padapter->mlmepriv, _FW_UNDER_SURVEY))
+               return;
+
+       while (1) {
+               if ((padapter->bDriverStopped) ||
+                   (padapter->bSurpriseRemoved) ||
+                   (padapter->bWritePortCancel)) {
+                       DBG_8723A("xmit_tasklet => bDriverStopped or "
+                                 "bSurpriseRemoved or bWritePortCancel\n");
+                       break;
+               }
+
+               ret = rtl8723au_xmitframe_complete(padapter, pxmitpriv, NULL);
+
+               if (!ret)
+                       break;
+       }
+}
+
+void rtl8723au_set_intf_ops(struct _io_ops *pops)
+{
+
+       memset((u8 *)pops, 0, sizeof(struct _io_ops));
+
+       pops->_read8 = &usb_read8;
+       pops->_read16 = &usb_read16;
+       pops->_read32 = &usb_read32;
+       pops->_read_mem = &usb_read_mem23a;
+       pops->_read_port = &usb_read_port;
+
+       pops->_write8 = &usb_write8;
+       pops->_write16 = &usb_write16;
+       pops->_write32 = &usb_write32;
+       pops->_writeN = &usb_writeN;
+
+       pops->_write_mem = &usb_write_mem23a;
+       pops->_write_port = &usb_write_port23a;
+
+       pops->_read_port_cancel = &usb_read_port_cancel23a;
+       pops->_write_port_cancel = &usb_write_port23a_cancel;
+
+       pops->_read_interrupt = &usb_read_interrupt;
+}
+
+void rtl8723au_set_hw_type(struct rtw_adapter *padapter)
+{
+       padapter->chip_type = RTL8723A;
+       padapter->HardwareType = HARDWARE_TYPE_RTL8723AU;
+       DBG_8723A("CHIP TYPE: RTL8723A\n");
+}
diff --git a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h
new file mode 100644 (file)
index 0000000..4b7f347
--- /dev/null
@@ -0,0 +1,230 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ ******************************************************************************/
+#ifndef __INC_HAL8723PHYCFG_H__
+#define __INC_HAL8723PHYCFG_H__
+
+/*--------------------------Define Parameters-------------------------------*/
+#define LOOP_LIMIT                             5
+#define MAX_STALL_TIME         50              /* us */
+#define AntennaDiversityValue  0x80
+#define MAX_TXPWR_IDX_NMODE_92S        63
+#define Reset_Cnt_Limit                3
+
+
+#define MAX_AGGR_NUM   0x0909
+
+/*--------------------------Define Parameters-------------------------------*/
+
+
+/*------------------------------Define structure----------------------------*/
+enum swchnlcmdid {
+       CmdID_End,
+       CmdID_SetTxPowerLevel,
+       CmdID_BBRegWrite10,
+       CmdID_WritePortUlong,
+       CmdID_WritePortUshort,
+       CmdID_WritePortUchar,
+       CmdID_RF_WriteReg,
+};
+
+
+/* 1. Switch channel related */
+struct swchnlcmd {
+       enum swchnlcmdid        CmdID;
+       u32                     Para1;
+       u32                     Para2;
+       u32                     msDelay;
+};
+
+enum HW90_BLOCK {
+       HW90_BLOCK_MAC = 0,
+       HW90_BLOCK_PHY0 = 1,
+       HW90_BLOCK_PHY1 = 2,
+       HW90_BLOCK_RF = 3,
+       HW90_BLOCK_MAXIMUM = 4, /*  Never use this */
+};
+
+enum RF_RADIO_PATH {
+       RF_PATH_A = 0,                  /* Radio Path A */
+       RF_PATH_B = 1,                  /* Radio Path B */
+       RF_PATH_MAX                     /* Max RF number 90 support */
+};
+
+#define CHANNEL_MAX_NUMBER             14      /*  14 is the max channel number */
+#define CHANNEL_GROUP_MAX              3       /*  ch1~3, ch4~9, ch10~14 total three groups */
+
+enum WIRELESS_MODE {
+       WIRELESS_MODE_UNKNOWN   = 0x00,
+       WIRELESS_MODE_A         = BIT2,
+       WIRELESS_MODE_B         = BIT0,
+       WIRELESS_MODE_G         = BIT1,
+       WIRELESS_MODE_AUTO      = BIT5,
+       WIRELESS_MODE_N_24G     = BIT3,
+       WIRELESS_MODE_N_5G      = BIT4,
+       WIRELESS_MODE_AC        = BIT6
+};
+
+enum baseband_config_type {
+       BaseBand_Config_PHY_REG = 0,                    /* Radio Path A */
+       BaseBand_Config_AGC_TAB = 1,                    /* Radio Path B */
+};
+
+enum ra_offset_area {
+       RA_OFFSET_LEGACY_OFDM1,
+       RA_OFFSET_LEGACY_OFDM2,
+       RA_OFFSET_HT_OFDM1,
+       RA_OFFSET_HT_OFDM2,
+       RA_OFFSET_HT_OFDM3,
+       RA_OFFSET_HT_OFDM4,
+       RA_OFFSET_HT_CCK,
+};
+
+
+/* BB/RF related */
+enum rf_type_8190p {
+       RF_TYPE_MIN,            /*  0 */
+       RF_8225 = 1,            /*  1 11b/g RF for verification only */
+       RF_8256 = 2,            /*  2 11b/g/n */
+       RF_8258 = 3,            /*  3 11a/b/g/n RF */
+       RF_6052 = 4,            /*  4 11b/g/n RF */
+       RF_PSEUDO_11N = 5,      /*  5, It is a temporality RF. */
+};
+
+struct bb_reg_define {
+       u32 rfintfs;            /*  set software control: */
+                               /*              0x870~0x877[8 bytes] */
+       u32 rfintfi;            /*  readback data: */
+                               /*              0x8e0~0x8e7[8 bytes] */
+       u32 rfintfo;            /*  output data: */
+                               /*              0x860~0x86f [16 bytes] */
+       u32 rfintfe;            /*  output enable: */
+                               /*              0x860~0x86f [16 bytes] */
+       u32 rf3wireOffset;      /*  LSSI data: */
+                               /*              0x840~0x84f [16 bytes] */
+       u32 rfLSSI_Select;      /*  BB Band Select: */
+                               /*              0x878~0x87f [8 bytes] */
+       u32 rfTxGainStage;      /*  Tx gain stage: */
+                               /*              0x80c~0x80f [4 bytes] */
+       u32 rfHSSIPara1;        /*  wire parameter control1 : */
+                               /*              0x820~0x823, 0x828~0x82b, 0x830~0x833, 0x838~0x83b [16 bytes] */
+       u32 rfHSSIPara2;        /*  wire parameter control2 : */
+                               /*              0x824~0x827, 0x82c~0x82f, 0x834~0x837, 0x83c~0x83f [16 bytes] */
+       u32 rfSwitchControl; /* Tx Rx antenna control : */
+                               /*              0x858~0x85f [16 bytes] */
+       u32 rfAGCControl1;      /* AGC parameter control1 : */
+                               /*      0xc50~0xc53, 0xc58~0xc5b, 0xc60~0xc63, 0xc68~0xc6b [16 bytes] */
+       u32 rfAGCControl2;      /* AGC parameter control2 : */
+                               /*              0xc54~0xc57, 0xc5c~0xc5f, 0xc64~0xc67, 0xc6c~0xc6f [16 bytes] */
+       u32 rfRxIQImbalance; /* OFDM Rx IQ imbalance matrix : */
+                               /*              0xc14~0xc17, 0xc1c~0xc1f, 0xc24~0xc27, 0xc2c~0xc2f [16 bytes] */
+       u32 rfRxAFE;            /* Rx IQ DC ofset and Rx digital filter, Rx DC notch filter : */
+                               /*      0xc10~0xc13, 0xc18~0xc1b, 0xc20~0xc23, 0xc28~0xc2b [16 bytes] */
+       u32 rfTxIQImbalance; /* OFDM Tx IQ imbalance matrix */
+                               /*      0xc80~0xc83, 0xc88~0xc8b, 0xc90~0xc93, 0xc98~0xc9b [16 bytes] */
+       u32 rfTxAFE;            /* Tx IQ DC Offset and Tx DFIR type */
+                               /*      0xc84~0xc87, 0xc8c~0xc8f, 0xc94~0xc97, 0xc9c~0xc9f [16 bytes] */
+       u32 rfLSSIReadBack;     /* LSSI RF readback data SI mode */
+                               /*      0x8a0~0x8af [16 bytes] */
+       u32 rfLSSIReadBackPi;   /* LSSI RF readback data PI mode 0x8b8-8bc for Path A and B */
+};
+
+struct r_antenna_sel_ofdm {
+       u32                     r_tx_antenna:4;
+       u32                     r_ant_l:4;
+       u32                     r_ant_non_ht:4;
+       u32                     r_ant_ht1:4;
+       u32                     r_ant_ht2:4;
+       u32                     r_ant_ht_s1:4;
+       u32                     r_ant_non_ht_s1:4;
+       u32                     OFDM_TXSC:2;
+       u32                     Reserved:2;
+};
+
+struct r_antenna_sel_cck {
+       u8                      r_cckrx_enable_2:2;
+       u8                      r_cckrx_enable:2;
+       u8                      r_ccktx_enable:4;
+};
+
+/*------------------------------Define structure----------------------------*/
+
+
+/*------------------------Export global variable----------------------------*/
+/*------------------------Export global variable----------------------------*/
+
+
+/*------------------------Export Macro Definition---------------------------*/
+/*------------------------Export Macro Definition---------------------------*/
+
+
+/*--------------------------Exported Function prototype---------------------*/
+/*  */
+/*  BB and RF register read/write */
+/*  */
+u32    PHY_QueryBBReg(struct rtw_adapter *Adapter, u32 RegAddr,
+                      u32 BitMask);
+void   PHY_SetBBReg(struct rtw_adapter *Adapter, u32 RegAddr,
+                    u32 BitMask, u32 Data);
+u32    PHY_QueryRFReg(struct rtw_adapter *Adapter,
+                      enum RF_RADIO_PATH       eRFPath, u32 RegAddr,
+                      u32 BitMask);
+void   PHY_SetRFReg(struct rtw_adapter *Adapter,
+                    enum RF_RADIO_PATH eRFPath, u32 RegAddr,
+                    u32 BitMask,  u32  Data);
+
+/*  */
+/*  BB TX Power R/W */
+/*  */
+void PHY_SetTxPowerLevel8723A(struct rtw_adapter *Adapter, u8 channel);
+
+/*  */
+/*  Switch bandwidth for 8723A */
+/*  */
+void   PHY_SetBWMode23a8723A(struct rtw_adapter *pAdapter,
+                          enum ht_channel_width ChnlWidth,
+                          unsigned char Offset);
+
+/*  */
+/*  channel switch related funciton */
+/*  */
+void   PHY_SwChnl8723A(struct rtw_adapter *pAdapter, u8 channel);
+                               /*  Call after initialization */
+void ChkFwCmdIoDone(struct rtw_adapter *Adapter);
+
+/*  */
+/*  Modify the value of the hw register when beacon interval be changed. */
+/*  */
+void
+rtl8192c_PHY_SetBeaconHwReg(struct rtw_adapter *Adapter, u16 BeaconInterval);
+
+
+void PHY_SwitchEphyParameter(struct rtw_adapter *Adapter);
+
+void PHY_EnableHostClkReq(struct rtw_adapter *Adapter);
+
+bool
+SetAntennaConfig92C(struct rtw_adapter *Adapter, u8 DefaultAnt);
+
+/*--------------------------Exported Function prototype---------------------*/
+
+#define PHY_SetMacReg  PHY_SetBBReg
+
+/* MAC/BB/RF HAL config */
+int PHY_BBConfig8723A(struct rtw_adapter *Adapter);
+int PHY_RFConfig8723A(struct rtw_adapter *Adapter);
+s32 PHY_MACConfig8723A(struct rtw_adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/Hal8723APhyReg.h b/drivers/staging/rtl8723au/include/Hal8723APhyReg.h
new file mode 100644 (file)
index 0000000..759928f
--- /dev/null
@@ -0,0 +1,1078 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ ******************************************************************************/
+#ifndef __INC_HAL8723APHYREG_H__
+#define __INC_HAL8723APHYREG_H__
+
+/*  1. PMAC duplicate register due to connection: RF_Mode, TRxRN, NumOf L-STF */
+/*  1. Page1(0x100) */
+#define rPMAC_Reset                            0x100
+#define rPMAC_TxStart                          0x104
+#define rPMAC_TxLegacySIG                      0x108
+#define rPMAC_TxHTSIG1                         0x10c
+#define rPMAC_TxHTSIG2                         0x110
+#define rPMAC_PHYDebug                         0x114
+#define rPMAC_TxPacketNum                      0x118
+#define rPMAC_TxIdle                           0x11c
+#define rPMAC_TxMACHeader0                     0x120
+#define rPMAC_TxMACHeader1                     0x124
+#define rPMAC_TxMACHeader2                     0x128
+#define rPMAC_TxMACHeader3                     0x12c
+#define rPMAC_TxMACHeader4                     0x130
+#define rPMAC_TxMACHeader5                     0x134
+#define rPMAC_TxDataType                       0x138
+#define rPMAC_TxRandomSeed                     0x13c
+#define rPMAC_CCKPLCPPreamble                  0x140
+#define rPMAC_CCKPLCPHeader                    0x144
+#define rPMAC_CCKCRC16                         0x148
+#define rPMAC_OFDMRxCRC32OK                    0x170
+#define rPMAC_OFDMRxCRC32Er                    0x174
+#define rPMAC_OFDMRxParityEr                   0x178
+#define rPMAC_OFDMRxCRC8Er                     0x17c
+#define rPMAC_CCKCRxRC16Er                     0x180
+#define rPMAC_CCKCRxRC32Er                     0x184
+#define rPMAC_CCKCRxRC32OK                     0x188
+#define rPMAC_TxStatus                         0x18c
+
+/*  2. Page2(0x200) */
+/*  The following two definition are only used for USB interface. */
+#define RF_BB_CMD_ADDR         0x02c0  /*  RF/BB read/write command address. */
+#define RF_BB_CMD_DATA         0x02c4  /*  RF/BB read/write command data. */
+
+/*  3. Page8(0x800) */
+#define rFPGA0_RFMOD           0x800   /* RF mode & CCK TxSC  RF BW Setting?? */
+
+#define rFPGA0_TxInfo          0x804   /*  Status report?? */
+#define rFPGA0_PSDFunction     0x808
+
+#define rFPGA0_TxGainStage     0x80c   /*  Set TX PWR init gain? */
+
+#define rFPGA0_RFTiming1       0x810   /*  Useless now */
+#define rFPGA0_RFTiming2       0x814
+
+#define rFPGA0_XA_HSSIParameter1       0x820   /*  RF 3 wire register */
+#define rFPGA0_XA_HSSIParameter2       0x824
+#define rFPGA0_XB_HSSIParameter1       0x828
+#define rFPGA0_XB_HSSIParameter2       0x82c
+#define rTxAGC_B_Rate18_06             0x830
+#define rTxAGC_B_Rate54_24             0x834
+#define rTxAGC_B_CCK1_55_Mcs32         0x838
+#define rTxAGC_B_Mcs03_Mcs00           0x83c
+
+#define rTxAGC_B_Mcs07_Mcs04           0x848
+#define rTxAGC_B_Mcs11_Mcs08           0x84c
+
+#define rFPGA0_XA_LSSIParameter                0x840
+#define rFPGA0_XB_LSSIParameter                0x844
+
+#define rFPGA0_RFWakeUpParameter       0x850   /*  Useless now */
+#define rFPGA0_RFSleepUpParameter      0x854
+
+#define rFPGA0_XAB_SwitchControl       0x858   /*  RF Channel switch */
+#define rFPGA0_XCD_SwitchControl       0x85c
+
+#define rFPGA0_XA_RFInterfaceOE                0x860   /*  RF Channel switch */
+#define rFPGA0_XB_RFInterfaceOE                0x864
+
+#define rTxAGC_B_Mcs15_Mcs12           0x868
+#define rTxAGC_B_CCK11_A_CCK2_11       0x86c
+
+#define rFPGA0_XAB_RFInterfaceSW       0x870   /*  RF Interface Software Control */
+#define rFPGA0_XCD_RFInterfaceSW       0x874
+
+#define rFPGA0_XAB_RFParameter         0x878   /*  RF Parameter */
+#define rFPGA0_XCD_RFParameter         0x87c
+
+#define rFPGA0_AnalogParameter1                0x880   /*  Crystal cap setting RF-R/W protection for parameter4?? */
+#define rFPGA0_AnalogParameter2                0x884
+#define rFPGA0_AnalogParameter3                0x888   /*  Useless now */
+#define rFPGA0_AnalogParameter4                0x88c
+
+#define rFPGA0_XA_LSSIReadBack         0x8a0   /*  Tranceiver LSSI Readback */
+#define rFPGA0_XB_LSSIReadBack         0x8a4
+#define rFPGA0_XC_LSSIReadBack         0x8a8
+#define rFPGA0_XD_LSSIReadBack         0x8ac
+
+#define rFPGA0_PSDReport               0x8b4   /*  Useless now */
+#define TransceiverA_HSPI_Readback     0x8b8   /*  Transceiver A HSPI Readback */
+#define TransceiverB_HSPI_Readback     0x8bc   /*  Transceiver B HSPI Readback */
+#define rFPGA0_XAB_RFInterfaceRB       0x8e0   /*  Useless now RF Interface Readback Value */
+#define rFPGA0_XCD_RFInterfaceRB       0x8e4   /*  Useless now */
+
+/*  4. Page9(0x900) */
+#define rFPGA1_RFMOD                   0x900   /* RF mode & OFDM TxSC RF BW Setting?? */
+
+#define rFPGA1_TxBlock                 0x904   /*  Useless now */
+#define rFPGA1_DebugSelect             0x908   /*  Useless now */
+#define rFPGA1_TxInfo                  0x90c   /*  Useless now Status report?? */
+
+/*  5. PageA(0xA00) */
+/*  Set Control channel to upper or lower. These settings are required only for 40MHz */
+#define rCCK0_System                   0xa00
+
+#define rCCK0_AFESetting               0xa04   /*  Disable init gain now Select RX path by RSSI */
+#define rCCK0_CCA                      0xa08   /*  Disable init gain now Init gain */
+
+#define rCCK0_RxAGC1                   0xa0c   /* AGC default value, saturation level Antenna Diversity, RX AGC, LNA Threshold, RX LNA Threshold useless now. Not the same as 90 series */
+#define rCCK0_RxAGC2                   0xa10   /* AGC & DAGC */
+
+#define rCCK0_RxHP                     0xa14
+
+#define rCCK0_DSPParameter1            0xa18   /* Timing recovery & Channel estimation threshold */
+#define rCCK0_DSPParameter2            0xa1c   /* SQ threshold */
+
+#define rCCK0_TxFilter1                        0xa20
+#define rCCK0_TxFilter2                        0xa24
+#define rCCK0_DebugPort                        0xa28   /* debug port and Tx filter3 */
+#define rCCK0_FalseAlarmReport         0xa2c   /* 0xa2d        useless now 0xa30-a4f channel report */
+#define rCCK0_TRSSIReport              0xa50
+#define rCCK0_RxReport                 0xa54  /* 0xa57 */
+#define rCCK0_FACounterLower           0xa5c  /* 0xa5b */
+#define rCCK0_FACounterUpper           0xa58  /* 0xa5c */
+/*  PageB(0xB00) */
+#define rPdp_AntA                      0xb00
+#define rPdp_AntA_4                    0xb04
+#define rConfig_Pmpd_AntA              0xb28
+#define rConfig_AntA                   0xb68
+#define rConfig_AntB                   0xb6c
+#define rPdp_AntB                      0xb70
+#define rPdp_AntB_4                    0xb74
+#define rConfig_Pmpd_AntB              0xb98
+#define rAPK                           0xbd8
+
+/*  6. PageC(0xC00) */
+#define rOFDM0_LSTF                    0xc00
+
+#define rOFDM0_TRxPathEnable           0xc04
+#define rOFDM0_TRMuxPar                        0xc08
+#define rOFDM0_TRSWIsolation           0xc0c
+
+#define rOFDM0_XARxAFE                 0xc10  /* RxIQ DC offset, Rx digital filter, DC notch filter */
+#define rOFDM0_XARxIQImbalance         0xc14  /* RxIQ imblance matrix */
+#define rOFDM0_XBRxAFE                 0xc18
+#define rOFDM0_XBRxIQImbalance         0xc1c
+#define rOFDM0_XCRxAFE                 0xc20
+#define rOFDM0_XCRxIQImbalance         0xc24
+#define rOFDM0_XDRxAFE                 0xc28
+#define rOFDM0_XDRxIQImbalance         0xc2c
+
+#define rOFDM0_RxDetector1             0xc30  /* PD,BW & SBD   DM tune init gain */
+#define rOFDM0_RxDetector2             0xc34  /* SBD & Fame Sync. */
+#define rOFDM0_RxDetector3             0xc38  /* Frame Sync. */
+#define rOFDM0_RxDetector4             0xc3c  /* PD, SBD, Frame Sync & Short-GI */
+
+#define rOFDM0_RxDSP                   0xc40  /* Rx Sync Path */
+#define rOFDM0_CFOandDAGC              0xc44  /* CFO & DAGC */
+#define rOFDM0_CCADropThreshold        0xc48 /* CCA Drop threshold */
+#define rOFDM0_ECCAThreshold           0xc4c /*  energy CCA */
+
+#define rOFDM0_XAAGCCore1              0xc50   /*  DIG */
+#define rOFDM0_XAAGCCore2              0xc54
+#define rOFDM0_XBAGCCore1              0xc58
+#define rOFDM0_XBAGCCore2              0xc5c
+#define rOFDM0_XCAGCCore1              0xc60
+#define rOFDM0_XCAGCCore2              0xc64
+#define rOFDM0_XDAGCCore1              0xc68
+#define rOFDM0_XDAGCCore2              0xc6c
+
+#define rOFDM0_AGCParameter1           0xc70
+#define rOFDM0_AGCParameter2           0xc74
+#define rOFDM0_AGCRSSITable            0xc78
+#define rOFDM0_HTSTFAGC                        0xc7c
+
+#define rOFDM0_XATxIQImbalance         0xc80   /*  TX PWR TRACK and DIG */
+#define rOFDM0_XATxAFE                 0xc84
+#define rOFDM0_XBTxIQImbalance         0xc88
+#define rOFDM0_XBTxAFE                 0xc8c
+#define rOFDM0_XCTxIQImbalance         0xc90
+#define rOFDM0_XCTxAFE                 0xc94
+#define rOFDM0_XDTxIQImbalance         0xc98
+#define rOFDM0_XDTxAFE                 0xc9c
+
+#define rOFDM0_RxIQExtAnta             0xca0
+#define rOFDM0_TxCoeff1                        0xca4
+#define rOFDM0_TxCoeff2                        0xca8
+#define rOFDM0_TxCoeff3                        0xcac
+#define rOFDM0_TxCoeff4                        0xcb0
+#define rOFDM0_TxCoeff5                        0xcb4
+#define rOFDM0_TxCoeff6                        0xcb8
+#define rOFDM0_RxHPParameter           0xce0
+#define rOFDM0_TxPseudoNoiseWgt                0xce4
+#define rOFDM0_FrameSync               0xcf0
+#define rOFDM0_DFSReport               0xcf4
+
+/*  7. PageD(0xD00) */
+#define rOFDM1_LSTF                    0xd00
+#define rOFDM1_TRxPathEnable           0xd04
+
+#define rOFDM1_CFO                     0xd08   /*  No setting now */
+#define rOFDM1_CSI1                    0xd10
+#define rOFDM1_SBD                     0xd14
+#define rOFDM1_CSI2                    0xd18
+#define rOFDM1_CFOTracking             0xd2c
+#define rOFDM1_TRxMesaure1             0xd34
+#define rOFDM1_IntfDet                 0xd3c
+#define rOFDM1_PseudoNoiseStateAB      0xd50
+#define rOFDM1_PseudoNoiseStateCD      0xd54
+#define rOFDM1_RxPseudoNoiseWgt                0xd58
+
+#define rOFDM_PHYCounter1              0xda0  /* cca, parity fail */
+#define rOFDM_PHYCounter2              0xda4  /* rate illegal, crc8 fail */
+#define rOFDM_PHYCounter3              0xda8  /* MCS not support */
+
+#define rOFDM_ShortCFOAB               0xdac   /*  No setting now */
+#define rOFDM_ShortCFOCD               0xdb0
+#define rOFDM_LongCFOAB                        0xdb4
+#define rOFDM_LongCFOCD                        0xdb8
+#define rOFDM_TailCFOAB                        0xdbc
+#define rOFDM_TailCFOCD                        0xdc0
+#define rOFDM_PWMeasure1               0xdc4
+#define rOFDM_PWMeasure2               0xdc8
+#define rOFDM_BWReport                 0xdcc
+#define rOFDM_AGCReport                        0xdd0
+#define rOFDM_RxSNR                    0xdd4
+#define rOFDM_RxEVMCSI                 0xdd8
+#define rOFDM_SIGReport                        0xddc
+
+
+/*  8. PageE(0xE00) */
+#define rTxAGC_A_Rate18_06             0xe00
+#define rTxAGC_A_Rate54_24             0xe04
+#define rTxAGC_A_CCK1_Mcs32            0xe08
+#define rTxAGC_A_Mcs03_Mcs00           0xe10
+#define rTxAGC_A_Mcs07_Mcs04           0xe14
+#define rTxAGC_A_Mcs11_Mcs08           0xe18
+#define rTxAGC_A_Mcs15_Mcs12           0xe1c
+
+#define rFPGA0_IQK                     0xe28
+#define rTx_IQK_Tone_A                 0xe30
+#define rRx_IQK_Tone_A                 0xe34
+#define rTx_IQK_PI_A                   0xe38
+#define rRx_IQK_PI_A                   0xe3c
+
+#define rTx_IQK                                0xe40
+#define rRx_IQK                                0xe44
+#define rIQK_AGC_Pts                   0xe48
+#define rIQK_AGC_Rsp                   0xe4c
+#define rTx_IQK_Tone_B                 0xe50
+#define rRx_IQK_Tone_B                 0xe54
+#define rTx_IQK_PI_B                   0xe58
+#define rRx_IQK_PI_B                   0xe5c
+#define rIQK_AGC_Cont                  0xe60
+
+#define rBlue_Tooth                    0xe6c
+#define rRx_Wait_CCA                   0xe70
+#define rTx_CCK_RFON                   0xe74
+#define rTx_CCK_BBON                   0xe78
+#define rTx_OFDM_RFON                  0xe7c
+#define rTx_OFDM_BBON                  0xe80
+#define rTx_To_Rx                      0xe84
+#define rTx_To_Tx                      0xe88
+#define rRx_CCK                                0xe8c
+
+#define rTx_Power_Before_IQK_A         0xe94
+#define rTx_Power_After_IQK_A          0xe9c
+
+#define rRx_Power_Before_IQK_A         0xea0
+#define rRx_Power_Before_IQK_A_2       0xea4
+#define rRx_Power_After_IQK_A          0xea8
+#define rRx_Power_After_IQK_A_2                0xeac
+
+#define rTx_Power_Before_IQK_B         0xeb4
+#define rTx_Power_After_IQK_B          0xebc
+
+#define rRx_Power_Before_IQK_B         0xec0
+#define rRx_Power_Before_IQK_B_2       0xec4
+#define rRx_Power_After_IQK_B          0xec8
+#define rRx_Power_After_IQK_B_2                0xecc
+
+#define rRx_OFDM                       0xed0
+#define rRx_Wait_RIFS                  0xed4
+#define rRx_TO_Rx                      0xed8
+#define rStandby                       0xedc
+#define rSleep                         0xee0
+#define rPMPD_ANAEN                    0xeec
+
+/*  7. RF Register 0x00-0x2E (RF 8256) */
+/*     RF-0222D 0x00-3F */
+/* Zebra1 */
+#define rZebra1_HSSIEnable             0x0     /*  Useless now */
+#define rZebra1_TRxEnable1             0x1
+#define rZebra1_TRxEnable2             0x2
+#define rZebra1_AGC                    0x4
+#define rZebra1_ChargePump             0x5
+#define rZebra1_Channel                        0x7     /*  RF channel switch */
+
+#define rZebra1_TxGain                 0x8     /*  Useless now */
+#define rZebra1_TxLPF                  0x9
+#define rZebra1_RxLPF                  0xb
+#define rZebra1_RxHPFCorner            0xc
+
+/* Zebra4 */
+#define rGlobalCtrl                    0       /*  Useless now */
+#define rRTL8256_TxLPF                 19
+#define rRTL8256_RxLPF                 11
+
+/* RTL8258 */
+#define rRTL8258_TxLPF                 0x11    /*  Useless now */
+#define rRTL8258_RxLPF                 0x13
+#define rRTL8258_RSSILPF               0xa
+
+/*  RL6052 Register definition */
+#define RF_AC                          0x00
+#define RF_IQADJ_G1                    0x01
+#define RF_IQADJ_G2                    0x02
+#define RF_BS_PA_APSET_G1_G4           0x03
+#define RF_BS_PA_APSET_G5_G8           0x04
+#define RF_POW_TRSW                    0x05
+#define RF_GAIN_RX                     0x06
+#define RF_GAIN_TX                     0x07
+#define RF_TXM_IDAC                    0x08
+#define RF_IPA_G                       0x09
+#define RF_TXBIAS_G                    0x0A
+#define RF_TXPA_AG                     0x0B
+#define RF_IPA_A                       0x0C
+#define RF_TXBIAS_A                    0x0D
+#define RF_BS_PA_APSET_G9_G11          0x0E
+#define RF_BS_IQGEN                    0x0F
+#define RF_MODE1                       0x10
+#define RF_MODE2                       0x11
+#define RF_RX_AGC_HP                   0x12
+#define RF_TX_AGC                      0x13
+#define RF_BIAS                                0x14
+#define RF_IPA                         0x15
+#define RF_TXBIAS                      0x16
+#define RF_POW_ABILITY                 0x17
+#define RF_MODE_AG                     0x18
+#define rRfChannel                     0x18    /*  RF channel and BW switch */
+#define RF_CHNLBW                      0x18    /*  RF channel and BW switch */
+#define RF_TOP                         0x19
+#define RF_RX_G1                       0x1A
+#define RF_RX_G2                       0x1B
+#define RF_RX_BB2                      0x1C
+#define RF_RX_BB1                      0x1D
+#define RF_RCK1                                0x1E
+#define RF_RCK2                                0x1F
+#define RF_TX_G1                       0x20
+#define RF_TX_G2                       0x21
+#define RF_TX_G3                       0x22
+#define RF_TX_BB1                      0x23
+#define RF_T_METER                     0x24
+#define RF_SYN_G1                      0x25    /*  RF TX Power control */
+#define RF_SYN_G2                      0x26    /*  RF TX Power control */
+#define RF_SYN_G3                      0x27    /*  RF TX Power control */
+#define RF_SYN_G4                      0x28    /*  RF TX Power control */
+#define RF_SYN_G5                      0x29    /*  RF TX Power control */
+#define RF_SYN_G6                      0x2A    /*  RF TX Power control */
+#define RF_SYN_G7                      0x2B    /*  RF TX Power control */
+#define RF_SYN_G8                      0x2C    /*  RF TX Power control */
+
+#define RF_RCK_OS                      0x30    /*  RF TX PA control */
+
+#define RF_TXPA_G1                     0x31    /*  RF TX PA control */
+#define RF_TXPA_G2                     0x32    /*  RF TX PA control */
+#define RF_TXPA_G3                     0x33    /*  RF TX PA control */
+
+/* Bit Mask */
+/*  1. Page1(0x100) */
+#define bBBResetB                      0x100   /*  Useless now? */
+#define bGlobalResetB                  0x200
+#define bOFDMTxStart                   0x4
+#define bCCKTxStart                    0x8
+#define bCRC32Debug                    0x100
+#define bPMACLoopback                  0x10
+#define bTxLSIG                                0xffffff
+#define bOFDMTxRate                    0xf
+#define bOFDMTxReserved                        0x10
+#define bOFDMTxLength                  0x1ffe0
+#define bOFDMTxParity                  0x20000
+#define bTxHTSIG1                      0xffffff
+#define bTxHTMCSRate                   0x7f
+#define bTxHTBW                                0x80
+#define bTxHTLength                    0xffff00
+#define bTxHTSIG2                      0xffffff
+#define bTxHTSmoothing                 0x1
+#define bTxHTSounding                  0x2
+#define bTxHTReserved                  0x4
+#define bTxHTAggreation                        0x8
+#define bTxHTSTBC                      0x30
+#define bTxHTAdvanceCoding             0x40
+#define bTxHTShortGI                   0x80
+#define bTxHTNumberHT_LTF              0x300
+#define bTxHTCRC8                      0x3fc00
+#define bCounterReset                  0x10000
+#define bNumOfOFDMTx                   0xffff
+#define bNumOfCCKTx                    0xffff0000
+#define bTxIdleInterval                        0xffff
+#define bOFDMService                   0xffff0000
+#define bTxMACHeader                   0xffffffff
+#define bTxDataInit                    0xff
+#define bTxHTMode                      0x100
+#define bTxDataType                    0x30000
+#define bTxRandomSeed                  0xffffffff
+#define bCCKTxPreamble                 0x1
+#define bCCKTxSFD                      0xffff0000
+#define bCCKTxSIG                      0xff
+#define bCCKTxService                  0xff00
+#define bCCKLengthExt                  0x8000
+#define bCCKTxLength                   0xffff0000
+#define bCCKTxCRC16                    0xffff
+#define bCCKTxStatus                   0x1
+#define bOFDMTxStatus                  0x2
+
+#define IS_BB_REG_OFFSET_92S(_Offset)                  \
+       ((_Offset >= 0x800) && (_Offset <= 0xfff))
+
+/*  2. Page8(0x800) */
+#define bRFMOD                         0x1     /*  Reg 0x800 rFPGA0_RFMOD */
+#define bJapanMode                     0x2
+#define bCCKTxSC                       0x30
+#define bCCKEn                         0x1000000
+#define bOFDMEn                                0x2000000
+
+#define bOFDMRxADCPhase                        0x10000 /*  Useless now */
+#define bOFDMTxDACPhase                        0x40000
+#define bXATxAGC                       0x3f
+
+#define bAntennaSelect                 0x0300
+
+#define bXBTxAGC                       0xf00   /*  Reg 80c rFPGA0_TxGainStage */
+#define bXCTxAGC                       0xf000
+#define bXDTxAGC                       0xf0000
+
+#define bPAStart                       0xf0000000      /*  Useless now */
+#define bTRStart                       0x00f00000
+#define bRFStart                       0x0000f000
+#define bBBStart                       0x000000f0
+#define bBBCCKStart                    0x0000000f
+#define bPAEnd                         0xf          /* Reg0x814 */
+#define bTREnd                         0x0f000000
+#define bRFEnd                         0x000f0000
+#define bCCAMask                       0x000000f0   /* T2R */
+#define bR2RCCAMask                    0x00000f00
+#define bHSSI_R2TDelay                 0xf8000000
+#define bHSSI_T2RDelay                 0xf80000
+#define bContTxHSSI                    0x400     /* chane gain at continue Tx */
+#define bIGFromCCK                     0x200
+#define bAGCAddress                    0x3f
+#define bRxHPTx                                0x7000
+#define bRxHPT2R                       0x38000
+#define bRxHPCCKIni                    0xc0000
+#define bAGCTxCode                     0xc00000
+#define bAGCRxCode                     0x300000
+
+#define b3WireDataLength               0x800   /*  Reg 0x820~84f rFPGA0_XA_HSSIParameter1 */
+#define b3WireAddressLength            0x400
+
+#define b3WireRFPowerDown              0x1     /*  Useless now */
+/* define bHWSISelect                  0x8 */
+#define b5GPAPEPolarity                        0x40000000
+#define b2GPAPEPolarity                        0x80000000
+#define bRFSW_TxDefaultAnt             0x3
+#define bRFSW_TxOptionAnt              0x30
+#define bRFSW_RxDefaultAnt             0x300
+#define bRFSW_RxOptionAnt              0x3000
+#define bRFSI_3WireData                        0x1
+#define bRFSI_3WireClock               0x2
+#define bRFSI_3WireLoad                        0x4
+#define bRFSI_3WireRW                  0x8
+#define bRFSI_3Wire                    0xf
+
+#define bRFSI_RFENV                    0x10    /*  Reg 0x870 rFPGA0_XAB_RFInterfaceSW */
+
+#define bRFSI_TRSW                     0x20    /*  Useless now */
+#define bRFSI_TRSWB                    0x40
+#define bRFSI_ANTSW                    0x100
+#define bRFSI_ANTSWB                   0x200
+#define bRFSI_PAPE                     0x400
+#define bRFSI_PAPE5G                   0x800
+#define bBandSelect                    0x1
+#define bHTSIG2_GI                     0x80
+#define bHTSIG2_Smoothing              0x01
+#define bHTSIG2_Sounding               0x02
+#define bHTSIG2_Aggreaton              0x08
+#define bHTSIG2_STBC                   0x30
+#define bHTSIG2_AdvCoding              0x40
+#define bHTSIG2_NumOfHTLTF             0x300
+#define bHTSIG2_CRC8                   0x3fc
+#define bHTSIG1_MCS                    0x7f
+#define bHTSIG1_BandWidth              0x80
+#define bHTSIG1_HTLength               0xffff
+#define bLSIG_Rate                     0xf
+#define bLSIG_Reserved                 0x10
+#define bLSIG_Length                   0x1fffe
+#define bLSIG_Parity                   0x20
+#define bCCKRxPhase                    0x4
+
+#define bLSSIReadAddress               0x7f800000   /*  T65 RF */
+
+#define bLSSIReadEdge                  0x80000000   /* LSSI "Read" edge signal */
+
+#define bLSSIReadBackData              0xfffff         /*  T65 RF */
+
+#define bLSSIReadOKFlag                        0x1000  /*  Useless now */
+#define bCCKSampleRate                 0x8       /* 0: 44MHz, 1:88MHz */
+#define bRegulator0Standby             0x1
+#define bRegulatorPLLStandby           0x2
+#define bRegulator1Standby             0x4
+#define bPLLPowerUp                    0x8
+#define bDPLLPowerUp                   0x10
+#define bDA10PowerUp                   0x20
+#define bAD7PowerUp                    0x200
+#define bDA6PowerUp                    0x2000
+#define bXtalPowerUp                   0x4000
+#define b40MDClkPowerUP                        0x8000
+#define bDA6DebugMode                  0x20000
+#define bDA6Swing                      0x380000
+
+#define bADClkPhase                    0x4000000       /*  Reg 0x880 rFPGA0_AnalogParameter1 20/40 CCK support switch 40/80 BB MHZ */
+
+#define b80MClkDelay                   0x18000000      /*  Useless */
+#define bAFEWatchDogEnable             0x20000000
+
+#define bXtalCap01                     0xc0000000      /*  Reg 0x884 rFPGA0_AnalogParameter2 Crystal cap */
+#define bXtalCap23                     0x3
+#define bXtalCap92x                    0x0f000000
+#define                bXtalCap                0x0f000000
+
+#define bIntDifClkEnable               0x400   /*  Useless */
+#define bExtSigClkEnable               0x800
+#define bBandgapMbiasPowerUp           0x10000
+#define bAD11SHGain                    0xc0000
+#define bAD11InputRange                        0x700000
+#define bAD11OPCurrent                 0x3800000
+#define bIPathLoopback                 0x4000000
+#define bQPathLoopback                 0x8000000
+#define bAFELoopback                   0x10000000
+#define bDA10Swing                     0x7e0
+#define bDA10Reverse                   0x800
+#define bDAClkSource                   0x1000
+#define bAD7InputRange                 0x6000
+#define bAD7Gain                       0x38000
+#define bAD7OutputCMMode               0x40000
+#define bAD7InputCMMode                        0x380000
+#define bAD7Current                    0xc00000
+#define bRegulatorAdjust               0x7000000
+#define bAD11PowerUpAtTx               0x1
+#define bDA10PSAtTx                    0x10
+#define bAD11PowerUpAtRx               0x100
+#define bDA10PSAtRx                    0x1000
+#define bCCKRxAGCFormat                        0x200
+#define bPSDFFTSamplepPoint            0xc000
+#define bPSDAverageNum                 0x3000
+#define bIQPathControl                 0xc00
+#define bPSDFreq                       0x3ff
+#define bPSDAntennaPath                        0x30
+#define bPSDIQSwitch                   0x40
+#define bPSDRxTrigger                  0x400000
+#define bPSDTxTrigger                  0x80000000
+#define bPSDSineToneScale              0x7f000000
+#define bPSDReport                     0xffff
+
+/*  3. Page9(0x900) */
+#define bOFDMTxSC                      0x30000000      /*  Useless */
+#define bCCKTxOn                       0x1
+#define bOFDMTxOn                      0x2
+#define bDebugPage                     0xfff  /* reset debug page and also HWord, LWord */
+#define bDebugItem                     0xff   /* reset debug page and LWord */
+#define bAntL                          0x10
+#define bAntNonHT                      0x100
+#define bAntHT1                                0x1000
+#define bAntHT2                                0x10000
+#define bAntHT1S1                      0x100000
+#define bAntNonHTS1                    0x1000000
+
+/*  4. PageA(0xA00) */
+#define bCCKBBMode                     0x3     /*  Useless */
+#define bCCKTxPowerSaving              0x80
+#define bCCKRxPowerSaving              0x40
+
+#define bCCKSideBand                   0x10    /*  Reg 0xa00 rCCK0_System 20/40 switch */
+
+#define bCCKScramble                   0x8     /*  Useless */
+#define bCCKAntDiversity               0x8000
+#define bCCKCarrierRecovery            0x4000
+#define bCCKTxRate                     0x3000
+#define bCCKDCCancel                   0x0800
+#define bCCKISICancel                  0x0400
+#define bCCKMatchFilter                        0x0200
+#define bCCKEqualizer                  0x0100
+#define bCCKPreambleDetect             0x800000
+#define bCCKFastFalseCCA               0x400000
+#define bCCKChEstStart                 0x300000
+#define bCCKCCACount                   0x080000
+#define bCCKcs_lim                     0x070000
+#define bCCKBistMode                   0x80000000
+#define bCCKCCAMask                    0x40000000
+#define bCCKTxDACPhase                 0x4
+#define bCCKRxADCPhase                 0x20000000   /* r_rx_clk */
+#define bCCKr_cp_mode0                 0x0100
+#define bCCKTxDCOffset                 0xf0
+#define bCCKRxDCOffset                 0xf
+#define bCCKCCAMode                    0xc000
+#define bCCKFalseCS_lim                        0x3f00
+#define bCCKCS_ratio                   0xc00000
+#define bCCKCorgBit_sel                        0x300000
+#define bCCKPD_lim                     0x0f0000
+#define bCCKNewCCA                     0x80000000
+#define bCCKRxHPofIG                   0x8000
+#define bCCKRxIG                       0x7f00
+#define bCCKLNAPolarity                        0x800000
+#define bCCKRx1stGain                  0x7f0000
+#define bCCKRFExtend                   0x20000000 /* CCK Rx Iinital gain polarity */
+#define bCCKRxAGCSatLevel              0x1f000000
+#define bCCKRxAGCSatCount              0xe0
+#define bCCKRxRFSettle                 0x1f       /* AGCsamp_dly */
+#define bCCKFixedRxAGC                 0x8000
+/* define bCCKRxAGCFormat              0x4000   remove to HSSI register 0x824 */
+#define bCCKAntennaPolarity            0x2000
+#define bCCKTxFilterType               0x0c00
+#define bCCKRxAGCReportType            0x0300
+#define bCCKRxDAGCEn                   0x80000000
+#define bCCKRxDAGCPeriod               0x20000000
+#define bCCKRxDAGCSatLevel             0x1f000000
+#define bCCKTimingRecovery             0x800000
+#define bCCKTxC0                       0x3f0000
+#define bCCKTxC1                       0x3f000000
+#define bCCKTxC2                       0x3f
+#define bCCKTxC3                       0x3f00
+#define bCCKTxC4                       0x3f0000
+#define bCCKTxC5                       0x3f000000
+#define bCCKTxC6                       0x3f
+#define bCCKTxC7                       0x3f00
+#define bCCKDebugPort                  0xff0000
+#define bCCKDACDebug                   0x0f000000
+#define bCCKFalseAlarmEnable           0x8000
+#define bCCKFalseAlarmRead             0x4000
+#define bCCKTRSSI                      0x7f
+#define bCCKRxAGCReport                        0xfe
+#define bCCKRxReport_AntSel            0x80000000
+#define bCCKRxReport_MFOff             0x40000000
+#define bCCKRxRxReport_SQLoss          0x20000000
+#define bCCKRxReport_Pktloss           0x10000000
+#define bCCKRxReport_Lockedbit         0x08000000
+#define bCCKRxReport_RateError         0x04000000
+#define bCCKRxReport_RxRate            0x03000000
+#define bCCKRxFACounterLower           0xff
+#define bCCKRxFACounterUpper           0xff000000
+#define bCCKRxHPAGCStart               0xe000
+#define bCCKRxHPAGCFinal               0x1c00
+#define bCCKRxFalseAlarmEnable         0x8000
+#define bCCKFACounterFreeze            0x4000
+#define bCCKTxPathSel                  0x10000000
+#define bCCKDefaultRxPath              0xc000000
+#define bCCKOptionRxPath               0x3000000
+
+/*  5. PageC(0xC00) */
+#define bNumOfSTF                      0x3     /*  Useless */
+#define bShift_L                       0xc0
+#define bGI_TH                         0xc
+#define bRxPathA                       0x1
+#define bRxPathB                       0x2
+#define bRxPathC                       0x4
+#define bRxPathD                       0x8
+#define bTxPathA                       0x1
+#define bTxPathB                       0x2
+#define bTxPathC                       0x4
+#define bTxPathD                       0x8
+#define bTRSSIFreq                     0x200
+#define bADCBackoff                    0x3000
+#define bDFIRBackoff                   0xc000
+#define bTRSSILatchPhase               0x10000
+#define bRxIDCOffset                   0xff
+#define bRxQDCOffset                   0xff00
+#define bRxDFIRMode                    0x1800000
+#define bRxDCNFType                    0xe000000
+#define bRXIQImb_A                     0x3ff
+#define bRXIQImb_B                     0xfc00
+#define bRXIQImb_C                     0x3f0000
+#define bRXIQImb_D                     0xffc00000
+#define bDC_dc_Notch                   0x60000
+#define bRxNBINotch                    0x1f000000
+#define bPD_TH                         0xf
+#define bPD_TH_Opt2                    0xc000
+#define bPWED_TH                       0x700
+#define bIfMF_Win_L                    0x800
+#define bPD_Option                     0x1000
+#define bMF_Win_L                      0xe000
+#define bBW_Search_L                   0x30000
+#define bwin_enh_L                     0xc0000
+#define bBW_TH                         0x700000
+#define bED_TH2                                0x3800000
+#define bBW_option                     0x4000000
+#define bRatio_TH                      0x18000000
+#define bWindow_L                      0xe0000000
+#define bSBD_Option                    0x1
+#define bFrame_TH                      0x1c
+#define bFS_Option                     0x60
+#define bDC_Slope_check                        0x80
+#define bFGuard_Counter_DC_L           0xe00
+#define bFrame_Weight_Short            0x7000
+#define bSub_Tune                      0xe00000
+#define bFrame_DC_Length               0xe000000
+#define bSBD_start_offset              0x30000000
+#define bFrame_TH_2                    0x7
+#define bFrame_GI2_TH                  0x38
+#define bGI2_Sync_en                   0x40
+#define bSarch_Short_Early             0x300
+#define bSarch_Short_Late              0xc00
+#define bSarch_GI2_Late                        0x70000
+#define bCFOAntSum                     0x1
+#define bCFOAcc                                0x2
+#define bCFOStartOffset                        0xc
+#define bCFOLookBack                   0x70
+#define bCFOSumWeight                  0x80
+#define bDAGCEnable                    0x10000
+#define bTXIQImb_A                     0x3ff
+#define bTXIQImb_B                     0xfc00
+#define bTXIQImb_C                     0x3f0000
+#define bTXIQImb_D                     0xffc00000
+#define bTxIDCOffset                   0xff
+#define bTxQDCOffset                   0xff00
+#define bTxDFIRMode                    0x10000
+#define bTxPesudoNoiseOn               0x4000000
+#define bTxPesudoNoise_A               0xff
+#define bTxPesudoNoise_B               0xff00
+#define bTxPesudoNoise_C               0xff0000
+#define bTxPesudoNoise_D               0xff000000
+#define bCCADropOption                 0x20000
+#define bCCADropThres                  0xfff00000
+#define bEDCCA_H                       0xf
+#define bEDCCA_L                       0xf0
+#define bLambda_ED                     0x300
+#define bRxInitialGain                 0x7f
+#define bRxAntDivEn                    0x80
+#define bRxAGCAddressForLNA            0x7f00
+#define bRxHighPowerFlow               0x8000
+#define bRxAGCFreezeThres              0xc0000
+#define bRxFreezeStep_AGC1             0x300000
+#define bRxFreezeStep_AGC2             0xc00000
+#define bRxFreezeStep_AGC3             0x3000000
+#define bRxFreezeStep_AGC0             0xc000000
+#define bRxRssi_Cmp_En                 0x10000000
+#define bRxQuickAGCEn                  0x20000000
+#define bRxAGCFreezeThresMode          0x40000000
+#define bRxOverFlowCheckType           0x80000000
+#define bRxAGCShift                    0x7f
+#define bTRSW_Tri_Only                 0x80
+#define bPowerThres                    0x300
+#define bRxAGCEn                       0x1
+#define bRxAGCTogetherEn               0x2
+#define bRxAGCMin                      0x4
+#define bRxHP_Ini                      0x7
+#define bRxHP_TRLNA                    0x70
+#define bRxHP_RSSI                     0x700
+#define bRxHP_BBP1                     0x7000
+#define bRxHP_BBP2                     0x70000
+#define bRxHP_BBP3                     0x700000
+#define bRSSI_H                                0x7f0000     /* the threshold for high power */
+#define bRSSI_Gen                      0x7f000000   /* the threshold for ant diversity */
+#define bRxSettle_TRSW                 0x7
+#define bRxSettle_LNA                  0x38
+#define bRxSettle_RSSI                 0x1c0
+#define bRxSettle_BBP                  0xe00
+#define bRxSettle_RxHP                 0x7000
+#define bRxSettle_AntSW_RSSI           0x38000
+#define bRxSettle_AntSW                        0xc0000
+#define bRxProcessTime_DAGC            0x300000
+#define bRxSettle_HSSI                 0x400000
+#define bRxProcessTime_BBPPW           0x800000
+#define bRxAntennaPowerShift           0x3000000
+#define bRSSITableSelect               0xc000000
+#define bRxHP_Final                    0x7000000
+#define bRxHTSettle_BBP                        0x7
+#define bRxHTSettle_HSSI               0x8
+#define bRxHTSettle_RxHP               0x70
+#define bRxHTSettle_BBPPW              0x80
+#define bRxHTSettle_Idle               0x300
+#define bRxHTSettle_Reserved           0x1c00
+#define bRxHTRxHPEn                    0x8000
+#define bRxHTAGCFreezeThres            0x30000
+#define bRxHTAGCTogetherEn             0x40000
+#define bRxHTAGCMin                    0x80000
+#define bRxHTAGCEn                     0x100000
+#define bRxHTDAGCEn                    0x200000
+#define bRxHTRxHP_BBP                  0x1c00000
+#define bRxHTRxHP_Final                        0xe0000000
+#define bRxPWRatioTH                   0x3
+#define bRxPWRatioEn                   0x4
+#define bRxMFHold                      0x3800
+#define bRxPD_Delay_TH1                        0x38
+#define bRxPD_Delay_TH2                        0x1c0
+#define bRxPD_DC_COUNT_MAX             0x600
+/* define bRxMF_Hold                       0x3800 */
+#define bRxPD_Delay_TH                 0x8000
+#define bRxProcess_Delay               0xf0000
+#define bRxSearchrange_GI2_Early       0x700000
+#define bRxFrame_Guard_Counter_L       0x3800000
+#define bRxSGI_Guard_L                 0xc000000
+#define bRxSGI_Search_L                        0x30000000
+#define bRxSGI_TH                      0xc0000000
+#define bDFSCnt0                       0xff
+#define bDFSCnt1                       0xff00
+#define bDFSFlag                       0xf0000
+#define bMFWeightSum                   0x300000
+#define bMinIdxTH                      0x7f000000
+#define bDAFormat                      0x40000
+#define bTxChEmuEnable                 0x01000000
+#define bTRSWIsolation_A               0x7f
+#define bTRSWIsolation_B               0x7f00
+#define bTRSWIsolation_C               0x7f0000
+#define bTRSWIsolation_D               0x7f000000
+#define bExtLNAGain                    0x7c00
+
+/*  6. PageE(0xE00) */
+#define bSTBCEn                                0x4     /*  Useless */
+#define bAntennaMapping                        0x10
+#define bNss                           0x20
+#define bCFOAntSumD                    0x200
+#define bPHYCounterReset               0x8000000
+#define bCFOReportGet                  0x4000000
+#define bOFDMContinueTx                        0x10000000
+#define bOFDMSingleCarrier             0x20000000
+#define bOFDMSingleTone                        0x40000000
+/* define bRxPath1                 0x01 */
+/* define bRxPath2                 0x02 */
+/* define bRxPath3                 0x04 */
+/* define bRxPath4                 0x08 */
+/* define bTxPath1                 0x10 */
+/* define bTxPath2                 0x20 */
+#define bHTDetect                      0x100
+#define bCFOEn                         0x10000
+#define bCFOValue                      0xfff00000
+#define bSigTone_Re                    0x3f
+#define bSigTone_Im                    0x7f00
+#define bCounter_CCA                   0xffff
+#define bCounter_ParityFail            0xffff0000
+#define bCounter_RateIllegal           0xffff
+#define bCounter_CRC8Fail              0xffff0000
+#define bCounter_MCSNoSupport          0xffff
+#define bCounter_FastSync              0xffff
+#define bShortCFO                      0xfff
+#define bShortCFOTLength               12   /* total */
+#define bShortCFOFLength               11   /* fraction */
+#define bLongCFO                       0x7ff
+#define bLongCFOTLength                        11
+#define bLongCFOFLength                        11
+#define bTailCFO                       0x1fff
+#define bTailCFOTLength                        13
+#define bTailCFOFLength                        12
+#define bmax_en_pwdB                   0xffff
+#define bCC_power_dB                   0xffff0000
+#define bnoise_pwdB                    0xffff
+#define bPowerMeasTLength              10
+#define bPowerMeasFLength              3
+#define bRx_HT_BW                      0x1
+#define bRxSC                          0x6
+#define bRx_HT                         0x8
+#define bNB_intf_det_on                        0x1
+#define bIntf_win_len_cfg              0x30
+#define bNB_Intf_TH_cfg                        0x1c0
+#define bRFGain                                0x3f
+#define bTableSel                      0x40
+#define bTRSW                          0x80
+#define bRxSNR_A                       0xff
+#define bRxSNR_B                       0xff00
+#define bRxSNR_C                       0xff0000
+#define bRxSNR_D                       0xff000000
+#define bSNREVMTLength                 8
+#define bSNREVMFLength                 1
+#define bCSI1st                                0xff
+#define bCSI2nd                                0xff00
+#define bRxEVM1st                      0xff0000
+#define bRxEVM2nd                      0xff000000
+#define bSIGEVM                                0xff
+#define bPWDB                          0xff00
+#define bSGIEN                         0x10000
+
+#define bSFactorQAM1                   0xf     /*  Useless */
+#define bSFactorQAM2                   0xf0
+#define bSFactorQAM3                   0xf00
+#define bSFactorQAM4                   0xf000
+#define bSFactorQAM5                   0xf0000
+#define bSFactorQAM6                   0xf0000
+#define bSFactorQAM7                   0xf00000
+#define bSFactorQAM8                   0xf000000
+#define bSFactorQAM9                   0xf0000000
+#define bCSIScheme                     0x100000
+
+#define bNoiseLvlTopSet                        0x3     /*  Useless */
+#define bChSmooth                      0x4
+#define bChSmoothCfg1                  0x38
+#define bChSmoothCfg2                  0x1c0
+#define bChSmoothCfg3                  0xe00
+#define bChSmoothCfg4                  0x7000
+#define bMRCMode                       0x800000
+#define bTHEVMCfg                      0x7000000
+
+#define bLoopFitType                   0x1     /*  Useless */
+#define bUpdCFO                                0x40
+#define bUpdCFOOffData                 0x80
+#define bAdvUpdCFO                     0x100
+#define bAdvTimeCtrl                   0x800
+#define bUpdClko                       0x1000
+#define bFC                            0x6000
+#define bTrackingMode                  0x8000
+#define bPhCmpEnable                   0x10000
+#define bUpdClkoLTF                    0x20000
+#define bComChCFO                      0x40000
+#define bCSIEstiMode                   0x80000
+#define bAdvUpdEqz                     0x100000
+#define bUChCfg                                0x7000000
+#define bUpdEqz                                0x8000000
+
+/* Rx Pseduo noise */
+#define bRxPesudoNoiseOn               0x20000000      /*  Useless */
+#define bRxPesudoNoise_A               0xff
+#define bRxPesudoNoise_B               0xff00
+#define bRxPesudoNoise_C               0xff0000
+#define bRxPesudoNoise_D               0xff000000
+#define bPesudoNoiseState_A            0xffff
+#define bPesudoNoiseState_B            0xffff0000
+#define bPesudoNoiseState_C            0xffff
+#define bPesudoNoiseState_D            0xffff0000
+
+/* 7. RF Register */
+/* Zebra1 */
+#define bZebra1_HSSIEnable             0x8             /*  Useless */
+#define bZebra1_TRxControl             0xc00
+#define bZebra1_TRxGainSetting         0x07f
+#define bZebra1_RxCorner               0xc00
+#define bZebra1_TxChargePump           0x38
+#define bZebra1_RxChargePump           0x7
+#define bZebra1_ChannelNum             0xf80
+#define bZebra1_TxLPFBW                        0x400
+#define bZebra1_RxLPFBW                        0x600
+
+/* Zebra4 */
+#define bRTL8256RegModeCtrl1           0x100   /*  Useless */
+#define bRTL8256RegModeCtrl0           0x40
+#define bRTL8256_TxLPFBW               0x18
+#define bRTL8256_RxLPFBW               0x600
+
+/* RTL8258 */
+#define bRTL8258_TxLPFBW               0xc     /*  Useless */
+#define bRTL8258_RxLPFBW               0xc00
+#define bRTL8258_RSSILPFBW             0xc0
+
+
+/*  Other Definition */
+
+/* byte endable for sb_write */
+#define bByte0                         0x1     /*  Useless */
+#define bByte1                         0x2
+#define bByte2                         0x4
+#define bByte3                         0x8
+#define bWord0                         0x3
+#define bWord1                         0xc
+#define bDWord                         0xf
+
+/* for PutRegsetting & GetRegSetting BitMask */
+#define bMaskByte0                     0xff    /*  Reg 0xc50 rOFDM0_XAAGCCore~0xC6f */
+#define bMaskByte1                     0xff00
+#define bMaskByte2                     0xff0000
+#define bMaskByte3                     0xff000000
+#define bMaskHWord                     0xffff0000
+#define bMaskLWord                     0x0000ffff
+#define bMaskDWord                     0xffffffff
+#define bMask12Bits                    0xfff
+#define bMaskH4Bits                    0xf0000000
+#define bMaskOFDM_D                    0xffc00000
+#define bMaskCCK                       0x3f3f3f3f
+
+/* for PutRFRegsetting & GetRFRegSetting BitMask */
+#define                bRFRegOffsetMask        0xfffff
+
+#define bDisable                       0x0
+
+#define LeftAntenna                    0x0     /*  Useless */
+#define RightAntenna                   0x1
+
+#define tCheckTxStatus                 500   /* 500ms Useless */
+#define tUpdateRxCounter               100   /* 100ms */
+
+#define rateCCK                                0       /*  Useless */
+#define rateOFDM                       1
+#define rateHT                         2
+
+/* define Register-End */
+#define bPMAC_End                      0x1ff   /*  Useless */
+#define bFPGAPHY0_End                  0x8ff
+#define bFPGAPHY1_End                  0x9ff
+#define bCCKPHY0_End                   0xaff
+#define bOFDMPHY0_End                  0xcff
+#define bOFDMPHY1_End                  0xdff
+
+/* define max debug item in each debug page */
+/* define bMaxItem_FPGA_PHY0        0x9 */
+/* define bMaxItem_FPGA_PHY1        0x3 */
+/* define bMaxItem_PHY_11B          0x16 */
+/* define bMaxItem_OFDM_PHY0        0x29 */
+/* define bMaxItem_OFDM_PHY1        0x0 */
+
+#define bPMACControl                   0x0     /*  Useless */
+#define bWMACControl                   0x1
+#define bWNICControl                   0x2
+
+#define PathA                          0x0     /*  Useless */
+#define PathB                          0x1
+#define PathC                          0x2
+#define PathD                          0x3
+
+/*  PageB(0xB00) */
+#define rPdp_AntA                      0xb00
+#define rPdp_AntA_4                    0xb04
+#define rPdp_AntA_8                    0xb08
+#define rPdp_AntA_C                    0xb0c
+#define rPdp_AntA_18                   0xb18
+#define rPdp_AntA_1C                   0xb1c
+#define rPdp_AntA_20                   0xb20
+#define rPdp_AntA_24                   0xb24
+
+#define rConfig_Pmpd_AntA              0xb28
+#define rConfig_ram64x16               0xb2c
+
+#define rBndA                          0xb30
+#define rHssiPar                       0xb34
+
+#define rConfig_AntA                   0xb68
+#define rConfig_AntB                   0xb6c
+
+#define rPdp_AntB                      0xb70
+#define rPdp_AntB_4                    0xb74
+#define rPdp_AntB_8                    0xb78
+#define rPdp_AntB_C                    0xb7c
+#define rPdp_AntB_10                   0xb80
+#define rPdp_AntB_14                   0xb84
+#define rPdp_AntB_18                   0xb88
+#define rPdp_AntB_1C                   0xb8c
+#define rPdp_AntB_20                   0xb90
+#define rPdp_AntB_24                   0xb94
+
+#define rConfig_Pmpd_AntB              0xb98
+
+#define rBndB                          0xba0
+
+#define rAPK                           0xbd8
+#define rPm_Rx0_AntA                   0xbdc
+#define rPm_Rx1_AntA                   0xbe0
+#define rPm_Rx2_AntA                   0xbe4
+#define rPm_Rx3_AntA                   0xbe8
+#define rPm_Rx0_AntB                   0xbec
+#define rPm_Rx1_AntB                   0xbf0
+#define rPm_Rx2_AntB                   0xbf4
+#define rPm_Rx3_AntB                   0xbf8
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h b/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h
new file mode 100644 (file)
index 0000000..7f3bdea
--- /dev/null
@@ -0,0 +1,150 @@
+#ifndef __HAL8723PWRSEQ_H__
+#define __HAL8723PWRSEQ_H__
+/*
+       Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd
+       There are 6 HW Power States:
+       0: POFF--Power Off
+       1: PDN--Power Down
+       2: CARDEMU--Card Emulation
+       3: ACT--Active Mode
+       4: LPS--Low Power State
+       5: SUS--Suspend
+
+       The transision from different states are defined below
+       TRANS_CARDEMU_TO_ACT
+       TRANS_ACT_TO_CARDEMU
+       TRANS_CARDEMU_TO_SUS
+       TRANS_SUS_TO_CARDEMU
+       TRANS_CARDEMU_TO_PDN
+       TRANS_ACT_TO_LPS
+       TRANS_LPS_TO_ACT
+
+       TRANS_END
+*/
+#include "HalPwrSeqCmd.h"
+#include "rtl8723a_spec.h"
+
+#define        RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS     15
+#define        RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS     15
+#define        RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS     15
+#define        RTL8723A_TRANS_SUS_TO_CARDEMU_STEPS     15
+#define        RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS     15
+#define        RTL8723A_TRANS_PDN_TO_CARDEMU_STEPS     15
+#define        RTL8723A_TRANS_ACT_TO_LPS_STEPS 15
+#define        RTL8723A_TRANS_LPS_TO_ACT_STEPS 15
+#define        RTL8723A_TRANS_END_STEPS        1
+
+
+/* format
+ * { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value },  comments here
+ */
+#define RTL8723A_TRANS_CARDEMU_TO_ACT                                                                                                          \
+       {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/   \
+       {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/    \
+       {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/   \
+       {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, 0}, /*0x00[5] = 1b'0 release analog Ips to digital , 1:isolation*/   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, 0},/* disable SW LPS 0x04[10]= 0*/  \
+       {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, BIT1},/* wait till 0x04[17] = 1    power ready*/  \
+       {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* release WLON reset  0x04[16]= 1*/  \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* disable HWPDN 0x04[15]= 0*/   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT4|BIT3), 0},/* disable WL suspend*/   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, BIT0},/* polling until return 0*/   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT0, 0},/**/   \
+       {0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 1},/*0x4C[23] = 0x4E[7] = 1, switch DPDT_SEL_P output from WL BB */\
+
+#define RTL8723A_TRANS_ACT_TO_CARDEMU                                                                                                  \
+       {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*0x1F[7:0] = 0 turn off RF*/    \
+       {0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/*0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */\
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*0x04[9] = 1 turn off MAC by HW state machine*/     \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT1, 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/   \
+       {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5}, /*0x00[5] = 1b'1 analog Ips to digital , 1:isolation*/   \
+       {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/   \
+
+
+#define RTL8723A_TRANS_CARDEMU_TO_SUS                                                                                                  \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4|BIT3, (BIT4|BIT3)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/       \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/     \
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/   \
+       {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3|BIT4}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/        \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/
+
+#define RTL8723A_TRANS_SUS_TO_CARDEMU                                                                                                  \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/   \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/   \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/
+
+#define RTL8723A_TRANS_CARDEMU_TO_CARDDIS                                                                                                      \
+       {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/       \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, BIT3}, /*0x04[12:11] = 2b'01 enable WL suspend*/     \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT2, BIT2}, /*0x04[10] = 1, enable SW LPS*/      \
+       {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 1}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/   \
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/   \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, BIT0}, /*Set SDIO suspend local register*/        \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, 0}, /*wait power state to suspend*/
+
+#define RTL8723A_TRANS_CARDDIS_TO_CARDEMU                                                                                                      \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3 | BIT7, 0}, /*clear suspend enable and power down enable*/   \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT0, 0}, /*Set SDIO suspend local register*/   \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT1, BIT1}, /*wait power state to suspend*/\
+       {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/   \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT3|BIT4, 0}, /*0x04[12:11] = 2b'01enable WL suspend*/\
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/   \
+       {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/
+
+
+#define RTL8723A_TRANS_CARDEMU_TO_PDN                                                                                          \
+       {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, BIT4}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/   \
+       {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK|PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/   \
+       {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/* 0x04[16] = 0*/\
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, BIT7},/* 0x04[15] = 1*/
+
+#define RTL8723A_TRANS_PDN_TO_CARDEMU                                                                                          \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT7, 0},/* 0x04[15] = 0*/
+
+#define RTL8723A_TRANS_ACT_TO_LPS                                                                                                              \
+       {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/     \
+       {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*Tx Pause*/  \
+       {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/        \
+       {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/        \
+       {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/        \
+       {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/        \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT0, 0},/*CCK and OFDM are disabled, and clock are gated*/       \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},/*Delay 1us*/ \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*Whole BB is reset*/    \
+       {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/     \
+       {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, 0},/*check if removed later*/       \
+       {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/*When driver enter Sus/ Disable, enable LOP for BT*/        \
+       {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT5, BIT5},/*Respond TxOK to scheduler*/
+
+#define RTL8723A_TRANS_LPS_TO_ACT                                                                                                                      \
+       {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\
+       {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\
+       {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\
+       {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT4, 0}, /*.     0x08[4] = 0              switch TSF to 40M*/\
+       {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT7, 0}, /*Polling 0x109[7]= 0  TSF in 40M*/\
+       {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT6|BIT7, 0}, /*.        0x29[7:6] = 2b'00        enable BB clock*/\
+       {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1, BIT1}, /*.  0x101[1] = 1*/\
+       {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF}, /*.  0x100[7:0] = 0xFF        enable WMAC TRX*/\
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT1|BIT0, BIT1|BIT0}, /*.        0x02[1:0] = 2b'11        enable BB macro*/\
+       {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}, /*.     0x522 = 0*/
+
+#define RTL8723A_TRANS_END                                                                                                                     \
+       {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, 0, PWR_CMD_END, 0, 0},
+
+
+extern struct wlan_pwr_cfg rtl8723AU_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723AU_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723AU_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723AU_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723AU_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723AU_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_SUS_STEPS+RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723AU_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STEPS+RTL8723A_TRANS_CARDEMU_TO_PDN_STEPS+RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723AU_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STEPS+RTL8723A_TRANS_END_STEPS];
+extern struct wlan_pwr_cfg rtl8723AU_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STEPS+RTL8723A_TRANS_END_STEPS];
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/Hal8723UHWImg_CE.h b/drivers/staging/rtl8723au/include/Hal8723UHWImg_CE.h
new file mode 100644 (file)
index 0000000..bbeaab4
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef __INC_HAL8723U_FW_IMG_H
+#define __INC_HAL8723U_FW_IMG_H
+
+/*Created on  2013/01/14, 15:51*/
+
+/* FW v16 enable usb interrupt */
+#define Rtl8723UImgArrayLength 22172
+extern u8 Rtl8723UFwImgArray[Rtl8723UImgArrayLength];
+#define Rtl8723UBTImgArrayLength 1
+extern u8 Rtl8723UFwBTImgArray[Rtl8723UBTImgArrayLength];
+
+#define Rtl8723UUMCBCutImgArrayWithBTLength 24118
+#define Rtl8723UUMCBCutImgArrayWithoutBTLength 19200
+
+extern u8 Rtl8723UFwUMCBCutImgArrayWithBT[Rtl8723UUMCBCutImgArrayWithBTLength];
+extern u8 Rtl8723UFwUMCBCutImgArrayWithoutBT[Rtl8723UUMCBCutImgArrayWithoutBTLength];
+
+#define Rtl8723SUMCBCutMPImgArrayLength 24174
+extern const u8 Rtl8723SFwUMCBCutMPImgArray[Rtl8723SUMCBCutMPImgArrayLength];
+
+#define Rtl8723EBTImgArrayLength 15276
+extern u8 Rtl8723EFwBTImgArray[Rtl8723EBTImgArrayLength] ;
+
+#define Rtl8723UPHY_REG_Array_PGLength 336
+extern u32 Rtl8723UPHY_REG_Array_PG[Rtl8723UPHY_REG_Array_PGLength];
+#define Rtl8723UMACPHY_Array_PGLength 1
+extern u32 Rtl8723UMACPHY_Array_PG[Rtl8723UMACPHY_Array_PGLength];
+
+#endif /* ifndef __INC_HAL8723U_FW_IMG_H */
diff --git a/drivers/staging/rtl8723au/include/HalDMOutSrc8723A.h b/drivers/staging/rtl8723au/include/HalDMOutSrc8723A.h
new file mode 100644 (file)
index 0000000..d7651f7
--- /dev/null
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ ******************************************************************************/
+#ifndef        __RTL8723A_ODM_H__
+#define __RTL8723A_ODM_H__
+/*  */
+
+#define        RSSI_CCK        0
+#define        RSSI_OFDM       1
+#define        RSSI_DEFAULT    2
+
+#define IQK_MAC_REG_NUM                4
+#define IQK_ADDA_REG_NUM               16
+#define IQK_BB_REG_NUM                 9
+#define HP_THERMAL_NUM         8
+
+
+/*  */
+/*  structure and define */
+/*  */
+
+
+
+
+/*------------------------Export global variable----------------------------*/
+/*------------------------Export global variable----------------------------*/
+/*------------------------Export Marco Definition---------------------------*/
+/* define DM_MultiSTA_InitGainChangeNotify(Event) {DM_DigTable.CurMultiSTAConnectState = Event;} */
+
+
+/*  */
+/*  function prototype */
+/*  */
+
+/*  */
+/*  IQ calibrate */
+/*  */
+void rtl8723a_phy_iq_calibrate(struct rtw_adapter *pAdapter, bool bReCovery);
+
+/*  */
+/*  LC calibrate */
+/*  */
+void rtl8723a_phy_lc_calibrate(struct rtw_adapter *pAdapter);
+
+/*  */
+/*  AP calibrate */
+/*  */
+void rtl8723a_phy_ap_calibrate(struct rtw_adapter *pAdapter, char delta);
+
+void rtl8723a_odm_check_tx_power_tracking(struct rtw_adapter *Adapter);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/HalHWImg8723A_BB.h b/drivers/staging/rtl8723au/include/HalHWImg8723A_BB.h
new file mode 100644 (file)
index 0000000..e99833c
--- /dev/null
@@ -0,0 +1,44 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License 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.
+*
+*
+******************************************************************************/
+
+#ifndef __INC_BB_8723A_HW_IMG_H
+#define __INC_BB_8723A_HW_IMG_H
+
+/******************************************************************************
+*                           AGC_TAB_1T.TXT
+******************************************************************************/
+
+void ODM_ReadAndConfig_AGC_TAB_1T_8723A(struct dm_odm_t *pDM_Odm);
+
+/******************************************************************************
+*                           PHY_REG_1T.TXT
+******************************************************************************/
+
+void ODM_ReadAndConfig_PHY_REG_1T_8723A(struct dm_odm_t *pDM_Odm);
+
+/******************************************************************************
+*                           PHY_REG_MP.TXT
+******************************************************************************/
+
+void ODM_ReadAndConfig_PHY_REG_MP_8723A(struct dm_odm_t *pDM_Odm);
+
+/******************************************************************************
+*                           PHY_REG_PG.TXT
+******************************************************************************/
+
+void ODM_ReadAndConfig_PHY_REG_PG_8723A(struct dm_odm_t *pDM_Odm);
+
+#endif /*  end of HWIMG_SUPPORT */
diff --git a/drivers/staging/rtl8723au/include/HalHWImg8723A_FW.h b/drivers/staging/rtl8723au/include/HalHWImg8723A_FW.h
new file mode 100644 (file)
index 0000000..7ee363b
--- /dev/null
@@ -0,0 +1,28 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License 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.
+*
+*
+******************************************************************************/
+
+#ifndef __INC_FW_8723A_HW_IMG_H
+#define __INC_FW_8723A_HW_IMG_H
+
+
+/******************************************************************************
+*                           rtl8723fw_B.TXT
+******************************************************************************/
+
+void ODM_ReadFirmware_8723A_rtl8723fw_B(struct dm_odm_t *pDM_Odm,
+                                       u8 *pFirmware, u32 *pFirmwareSize);
+
+#endif /*  end of HWIMG_SUPPORT */
diff --git a/drivers/staging/rtl8723au/include/HalHWImg8723A_MAC.h b/drivers/staging/rtl8723au/include/HalHWImg8723A_MAC.h
new file mode 100644 (file)
index 0000000..201be1f
--- /dev/null
@@ -0,0 +1,26 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License 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.
+*
+*
+******************************************************************************/
+
+#ifndef __INC_MAC_8723A_HW_IMG_H
+#define __INC_MAC_8723A_HW_IMG_H
+
+/******************************************************************************
+*                           MAC_REG.TXT
+******************************************************************************/
+
+void ODM_ReadAndConfig_MAC_REG_8723A(struct dm_odm_t *pDM_Odm);
+
+#endif /*  end of HWIMG_SUPPORT */
diff --git a/drivers/staging/rtl8723au/include/HalHWImg8723A_RF.h b/drivers/staging/rtl8723au/include/HalHWImg8723A_RF.h
new file mode 100644 (file)
index 0000000..c9af1c3
--- /dev/null
@@ -0,0 +1,25 @@
+/******************************************************************************
+*
+* Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of version 2 of the GNU General Public License 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.
+*
+******************************************************************************/
+
+#ifndef __INC_RF_8723A_HW_IMG_H
+#define __INC_RF_8723A_HW_IMG_H
+
+/******************************************************************************
+*                           RadioA_1T.TXT
+******************************************************************************/
+
+void ODM_ReadAndConfig_RadioA_1T_8723A(struct dm_odm_t *pDM_Odm);
+
+#endif /*  end of HWIMG_SUPPORT */
diff --git a/drivers/staging/rtl8723au/include/HalPwrSeqCmd.h b/drivers/staging/rtl8723au/include/HalPwrSeqCmd.h
new file mode 100644 (file)
index 0000000..12e03a3
--- /dev/null
@@ -0,0 +1,130 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ ******************************************************************************/
+#ifndef __HALPWRSEQCMD_H__
+#define __HALPWRSEQCMD_H__
+
+#include <drv_types.h>
+
+/*---------------------------------------------*/
+/*---------------------------------------------*/
+#define PWR_CMD_READ                   0x00
+     /*  offset: the read register offset */
+     /*  msk: the mask of the read value */
+     /*  value: N/A, left by 0 */
+     /*  note: dirver shall implement this function by read & msk */
+
+#define PWR_CMD_WRITE                  0x01
+     /*  offset: the read register offset */
+     /*  msk: the mask of the write bits */
+     /*  value: write value */
+     /*  note: driver shall implement this cmd by read & msk after write */
+
+#define PWR_CMD_POLLING                        0x02
+     /*  offset: the read register offset */
+     /*  msk: the mask of the polled value */
+     /*  value: the value to be polled, masked by the msd field. */
+     /*  note: driver shall implement this cmd by */
+     /*  do{ */
+     /*  if( (Read(offset) & msk) == (value & msk) ) */
+     /*  break; */
+     /*  } while(not timeout); */
+
+#define PWR_CMD_DELAY                  0x03
+     /*  offset: the value to delay */
+     /*  msk: N/A */
+     /*  value: the unit of delay, 0: us, 1: ms */
+
+#define PWR_CMD_END                            0x04
+     /*  offset: N/A */
+     /*  msk: N/A */
+     /*  value: N/A */
+
+/*---------------------------------------------*/
+/* 3 The value of base: 4 bits */
+/*---------------------------------------------*/
+   /*  define the base address of each block */
+#define PWR_BASEADDR_MAC               0x00
+#define PWR_BASEADDR_USB               0x01
+#define PWR_BASEADDR_PCIE              0x02
+#define PWR_BASEADDR_SDIO              0x03
+
+/*---------------------------------------------*/
+/* 3 The value of interface_msk: 4 bits */
+/*---------------------------------------------*/
+#define        PWR_INTF_SDIO_MSK               BIT(0)
+#define        PWR_INTF_USB_MSK                BIT(1)
+#define        PWR_INTF_PCI_MSK                BIT(2)
+#define        PWR_INTF_ALL_MSK                (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+/*---------------------------------------------*/
+/* 3 The value of fab_msk: 4 bits */
+/*---------------------------------------------*/
+#define        PWR_FAB_TSMC_MSK                BIT(0)
+#define        PWR_FAB_UMC_MSK                 BIT(1)
+#define        PWR_FAB_ALL_MSK                 (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+/*---------------------------------------------*/
+/* 3 The value of cut_msk: 8 bits */
+/*---------------------------------------------*/
+#define        PWR_CUT_TESTCHIP_MSK    BIT(0)
+#define        PWR_CUT_A_MSK                   BIT(1)
+#define        PWR_CUT_B_MSK                   BIT(2)
+#define        PWR_CUT_C_MSK                   BIT(3)
+#define        PWR_CUT_D_MSK                   BIT(4)
+#define        PWR_CUT_E_MSK                   BIT(5)
+#define        PWR_CUT_F_MSK                   BIT(6)
+#define        PWR_CUT_G_MSK                   BIT(7)
+#define        PWR_CUT_ALL_MSK                 0xFF
+
+
+enum pwrseq_delay_unit {
+       PWRSEQ_DELAY_US,
+       PWRSEQ_DELAY_MS,
+};
+
+struct wlan_pwr_cfg {
+       u16 offset;
+       u8 cut_msk;
+       u8 fab_msk:4;
+       u8 interface_msk:4;
+       u8 base:4;
+       u8 cmd:4;
+       u8 msk;
+       u8 value;
+};
+
+
+#define GET_PWR_CFG_OFFSET(__PWR_CMD)          __PWR_CMD.offset
+#define GET_PWR_CFG_CUT_MASK(__PWR_CMD)                __PWR_CMD.cut_msk
+#define GET_PWR_CFG_FAB_MASK(__PWR_CMD)                __PWR_CMD.fab_msk
+#define GET_PWR_CFG_INTF_MASK(__PWR_CMD)       __PWR_CMD.interface_msk
+#define GET_PWR_CFG_BASE(__PWR_CMD)                    __PWR_CMD.base
+#define GET_PWR_CFG_CMD(__PWR_CMD)                     __PWR_CMD.cmd
+#define GET_PWR_CFG_MASK(__PWR_CMD)                    __PWR_CMD.msk
+#define GET_PWR_CFG_VALUE(__PWR_CMD)           __PWR_CMD.value
+
+
+/*  */
+/*     Prototype of protected function. */
+/*  */
+u8 HalPwrSeqCmdParsing23a(
+       struct rtw_adapter              *padapter,
+       u8                              CutVersion,
+       u8                              FabVersion,
+       u8                              InterfaceType,
+       struct wlan_pwr_cfg     PwrCfgCmd[]);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/HalVerDef.h b/drivers/staging/rtl8723au/include/HalVerDef.h
new file mode 100644 (file)
index 0000000..607b71f
--- /dev/null
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __HAL_VERSION_DEF_H__
+#define __HAL_VERSION_DEF_H__
+
+enum hal_ic_type {
+       CHIP_8192S              =       0,
+       CHIP_8188C      =       1,
+       CHIP_8192C      =       2,
+       CHIP_8192D      =       3,
+       CHIP_8723A      =       4,
+       CHIP_8188E      =       5,
+       CHIP_8881A      =       6,
+       CHIP_8812A      =       7,
+       CHIP_8821A      =       8,
+       CHIP_8723B      =       9,
+       CHIP_8192E              =       10,
+};
+
+enum hal_chip_type {
+       TEST_CHIP               =       0,
+       NORMAL_CHIP             =       1,
+       FPGA                    =       2,
+};
+
+enum hal_cut_version {
+       A_CUT_VERSION           =       0,
+       B_CUT_VERSION           =       1,
+       C_CUT_VERSION           =       2,
+       D_CUT_VERSION           =       3,
+       E_CUT_VERSION           =       4,
+       F_CUT_VERSION           =       5,
+       G_CUT_VERSION           =       6,
+};
+
+/*  HAL_Manufacturer */
+enum hal_vendor {
+       CHIP_VENDOR_TSMC        =       0,
+       CHIP_VENDOR_UMC         =       1,
+};
+
+enum hal_rf_type {
+       RF_TYPE_1T1R    =       0,
+       RF_TYPE_1T2R    =       1,
+       RF_TYPE_2T2R    =       2,
+       RF_TYPE_2T3R    =       3,
+       RF_TYPE_2T4R    =       4,
+       RF_TYPE_3T3R    =       5,
+       RF_TYPE_3T4R    =       6,
+       RF_TYPE_4T4R    =       7,
+};
+
+struct hal_version {
+       enum hal_ic_type        ICType;
+       enum hal_chip_type      ChipType;
+       enum hal_cut_version    CUTVersion;
+       enum hal_vendor         VendorType;
+       enum hal_rf_type        RFType;
+       u8                      ROMVer;
+};
+
+/*  Get element */
+#define GET_CVID_IC_TYPE(version)      ((version).ICType)
+#define GET_CVID_CHIP_TYPE(version)    ((version).ChipType)
+#define GET_CVID_RF_TYPE(version)      ((version).RFType)
+#define GET_CVID_MANUFACTUER(version)  ((version).VendorType)
+#define GET_CVID_CUT_VERSION(version)  ((version).CUTVersion)
+#define GET_CVID_ROM_VERSION(version)  (((version).ROMVer) & ROM_VERSION_MASK)
+
+/* Common Macro. -- */
+
+#define IS_81XXC(version)                      \
+       (((GET_CVID_IC_TYPE(version) == CHIP_8192C) ||  \
+        (GET_CVID_IC_TYPE(version) == CHIP_8188C)) ? true : false)
+#define IS_8723_SERIES(version)                        \
+       ((GET_CVID_IC_TYPE(version) == CHIP_8723A) ? true : false)
+
+#define IS_TEST_CHIP(version)                  \
+       ((GET_CVID_CHIP_TYPE(version) == TEST_CHIP) ? true : false)
+#define IS_NORMAL_CHIP(version)                        \
+       ((GET_CVID_CHIP_TYPE(version) == NORMAL_CHIP) ? true : false)
+
+#define IS_A_CUT(version)                      \
+       ((GET_CVID_CUT_VERSION(version) == A_CUT_VERSION) ? true : false)
+#define IS_B_CUT(version)                      \
+       ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? true : false)
+#define IS_C_CUT(version)                      \
+       ((GET_CVID_CUT_VERSION(version) == C_CUT_VERSION) ? true : false)
+#define IS_D_CUT(version)                      \
+       ((GET_CVID_CUT_VERSION(version) == D_CUT_VERSION) ? true : false)
+#define IS_E_CUT(version)                      \
+       ((GET_CVID_CUT_VERSION(version) == E_CUT_VERSION) ? true : false)
+
+#define IS_CHIP_VENDOR_TSMC(version)           \
+       ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_TSMC) ? true : false)
+#define IS_CHIP_VENDOR_UMC(version)            \
+       ((GET_CVID_MANUFACTUER(version) == CHIP_VENDOR_UMC) ? true : false)
+
+#define IS_1T1R(version)                       \
+       ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T1R) ? true : false)
+#define IS_1T2R(version)                       \
+       ((GET_CVID_RF_TYPE(version) == RF_TYPE_1T2R) ? true : false)
+#define IS_2T2R(version)                       \
+       ((GET_CVID_RF_TYPE(version) == RF_TYPE_2T2R) ? true : false)
+
+/* Chip version Macro. -- */
+
+#define IS_92C_SERIAL(version)                                 \
+       ((IS_81XXC(version) && IS_2T2R(version)) ? true : false)
+#define IS_81xxC_VENDOR_UMC_A_CUT(version)                     \
+       (IS_81XXC(version)?(IS_CHIP_VENDOR_UMC(version) ?       \
+       (IS_A_CUT(version) ? true : false) : false) : false)
+#define IS_81xxC_VENDOR_UMC_B_CUT(version)                     \
+       (IS_81XXC(version) ? (IS_CHIP_VENDOR_UMC(version) ?     \
+        (IS_B_CUT(version) ? true : false) : false): false)
+#define IS_81xxC_VENDOR_UMC_C_CUT(version)                     \
+       (IS_81XXC(version)?(IS_CHIP_VENDOR_UMC(version) ?       \
+       (IS_C_CUT(version) ? true : false) : false) : false)
+#define IS_8723A_A_CUT(version)                                \
+       ((IS_8723_SERIES(version)) ? (IS_A_CUT(version) ? true : false) : false)
+#define IS_8723A_B_CUT(version)                                        \
+       ((IS_8723_SERIES(version)) ? (IS_B_CUT(version) ? true : false) : false)
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/cmd_osdep.h b/drivers/staging/rtl8723au/include/cmd_osdep.h
new file mode 100644 (file)
index 0000000..4866bee
--- /dev/null
@@ -0,0 +1,26 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __CMD_OSDEP_H_
+#define __CMD_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+int _rtw_init_evt_priv23a(struct evt_priv *pevtpriv);
+void _rtw_free_evt_priv23a(struct      evt_priv *pevtpriv);
+void _rtw_free_cmd_priv23a(struct      cmd_priv *pcmdpriv);
+int _rtw_enqueue_cmd23a(struct rtw_queue *queue, struct cmd_obj *obj);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/drv_types.h b/drivers/staging/rtl8723au/include/drv_types.h
new file mode 100644 (file)
index 0000000..53eecea
--- /dev/null
@@ -0,0 +1,360 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+/*-----------------------------------------------------------------------------
+
+       For type defines and data structure defines
+
+------------------------------------------------------------------------------*/
+
+
+#ifndef __DRV_TYPES_H__
+#define __DRV_TYPES_H__
+
+#include <osdep_service.h>
+#include <wlan_bssdef.h>
+
+
+enum _NIC_VERSION {
+       RTL8711_NIC,
+       RTL8712_NIC,
+       RTL8713_NIC,
+       RTL8716_NIC
+
+};
+
+
+#include <rtw_ht.h>
+
+#include <rtw_cmd.h>
+#include <wlan_bssdef.h>
+#include <rtw_xmit.h>
+#include <rtw_recv.h>
+#include <hal_intf.h>
+#include <hal_com.h>
+#include <rtw_qos.h>
+#include <rtw_security.h>
+#include <rtw_pwrctrl.h>
+#include <rtw_io.h>
+#include <rtw_eeprom.h>
+#include <sta_info.h>
+#include <rtw_mlme.h>
+#include <rtw_debug.h>
+#include <rtw_rf.h>
+#include <rtw_event.h>
+#include <rtw_led.h>
+#include <rtw_mlme_ext.h>
+#include <rtw_p2p.h>
+#include <rtw_ap.h>
+
+#include "ioctl_cfg80211.h"
+
+#define SPEC_DEV_ID_NONE BIT(0)
+#define SPEC_DEV_ID_DISABLE_HT BIT(1)
+#define SPEC_DEV_ID_ENABLE_PS BIT(2)
+#define SPEC_DEV_ID_RF_CONFIG_1T1R BIT(3)
+#define SPEC_DEV_ID_RF_CONFIG_2T2R BIT(4)
+#define SPEC_DEV_ID_ASSIGN_IFNAME BIT(5)
+
+struct specific_device_id {
+       u32             flags;
+
+       u16             idVendor;
+       u16             idProduct;
+
+};
+
+struct registry_priv {
+       u8      chip_version;
+       u8      rfintfs;
+       struct  cfg80211_ssid ssid;
+       u8      channel;/* ad-hoc support requirement */
+       u8      wireless_mode;/* A, B, G, auto */
+       u8      scan_mode;/* active, passive */
+       u8      preamble;/* long, short, auto */
+       u8      vrtl_carrier_sense;/* Enable, Disable, Auto */
+       u8      vcs_type;/* RTS/CTS, CTS-to-self */
+       u16     rts_thresh;
+       u16  frag_thresh;
+       u8      adhoc_tx_pwr;
+       u8      soft_ap;
+       u8      power_mgnt;
+       u8      ips_mode;
+       u8      smart_ps;
+       u8      long_retry_lmt;
+       u8      short_retry_lmt;
+       u16     busy_thresh;
+       u8      ack_policy;
+       u8      software_encrypt;
+       u8      software_decrypt;
+       u8      acm_method;
+         /* UAPSD */
+       u8      wmm_enable;
+       u8      uapsd_enable;
+
+       struct wlan_bssid_ex    dev_network;
+
+       u8      ht_enable;
+       u8      cbw40_enable;
+       u8      ampdu_enable;/* for tx */
+       u8      rx_stbc;
+       u8      ampdu_amsdu;/* A-MPDU Supports A-MSDU is permitted */
+       u8      lowrate_two_xmit;
+
+       u8      rf_config;
+       u8      low_power;
+
+       u8      wifi_spec;/*  !turbo_mode */
+
+       u8      channel_plan;
+#ifdef CONFIG_8723AU_BT_COEXIST
+       u8      btcoex;
+       u8      bt_iso;
+       u8      bt_sco;
+       u8      bt_ampdu;
+#endif
+       bool    bAcceptAddbaReq;
+
+       u8      antdiv_cfg;
+       u8      antdiv_type;
+
+       u8      usbss_enable;/* 0:disable,1:enable */
+       u8      hwpdn_mode;/* 0:disable,1:enable,2:decide by EFUSE config */
+       u8      hwpwrp_detect;/* 0:disable,1:enable */
+
+       u8      hw_wps_pbc;/* 0:disable,1:enable */
+
+       u8      max_roaming_times; /* max number driver will try to roaming */
+
+       u8 enable80211d;
+
+       u8 ifname[16];
+       u8 if2name[16];
+
+       u8 notch_filter;
+
+       u8 regulatory_tid;
+};
+
+
+#define MAX_CONTINUAL_URB_ERR 4
+
+#define GET_PRIMARY_ADAPTER(padapter)                                  \
+       (((struct rtw_adapter *)padapter)->dvobj->if1)
+
+enum _IFACE_ID {
+       IFACE_ID0, /* maping to PRIMARY_ADAPTER */
+       IFACE_ID1, /* maping to SECONDARY_ADAPTER */
+       IFACE_ID2,
+       IFACE_ID3,
+       IFACE_ID_MAX,
+};
+
+struct dvobj_priv {
+       struct rtw_adapter *if1; /* PRIMARY_ADAPTER */
+       struct rtw_adapter *if2; /* SECONDARY_ADAPTER */
+
+       /* for local/global synchronization */
+       struct mutex hw_init_mutex;
+       struct mutex h2c_fwcmd_mutex;
+       struct mutex setch_mutex;
+       struct mutex setbw_mutex;
+
+       unsigned char   oper_channel; /* saved chan info when set chan bw */
+       unsigned char   oper_bwmode;
+       unsigned char   oper_ch_offset;/* PRIME_CHNL_OFFSET */
+
+       struct rtw_adapter *padapters[IFACE_ID_MAX];
+       u8 iface_nums; /*  total number of ifaces used runtime */
+
+       /* For 92D, DMDP have 2 interface. */
+       u8      InterfaceNumber;
+       u8      NumInterfaces;
+
+       /* In /Out Pipe information */
+       int     RtInPipe[2];
+       int     RtOutPipe[3];
+       u8      Queue2Pipe[HW_QUEUE_ENTRY];/* for out pipe mapping */
+
+       u8      irq_alloc;
+
+/*-------- below is for USB INTERFACE --------*/
+
+       u8      nr_endpoint;
+       u8      ishighspeed;
+       u8      RtNumInPipes;
+       u8      RtNumOutPipes;
+       int     ep_num[5]; /* endpoint number */
+
+       int     RegUsbSS;
+
+       struct semaphore usb_suspend_sema;
+
+       struct mutex  usb_vendor_req_mutex;
+
+       u8 *usb_alloc_vendor_req_buf;
+       u8 *usb_vendor_req_buf;
+
+       struct usb_interface *pusbintf;
+       struct usb_device *pusbdev;
+       atomic_t continual_urb_error;
+
+/*-------- below is for PCIE INTERFACE --------*/
+
+};
+
+static inline struct device *dvobj_to_dev(struct dvobj_priv *dvobj)
+{
+       /* todo: get interface type from dvobj and the return the dev accordingly */
+       return &dvobj->pusbintf->dev;
+}
+
+enum _IFACE_TYPE {
+       IFACE_PORT0, /* mapping to port0 for C/D series chips */
+       IFACE_PORT1, /* mapping to port1 for C/D series chip */
+       MAX_IFACE_PORT,
+};
+
+enum _ADAPTER_TYPE {
+       PRIMARY_ADAPTER,
+       SECONDARY_ADAPTER,
+       MAX_ADAPTER,
+};
+
+struct rtw_adapter {
+       int     pid[3];/* process id from UI, 0:wps, 1:hostapd, 2:dhcpcd */
+       int     bDongle;/* build-in module or external dongle */
+       u16     chip_type;
+       u16     HardwareType;
+
+       struct dvobj_priv *dvobj;
+       struct  mlme_priv mlmepriv;
+       struct  mlme_ext_priv mlmeextpriv;
+       struct  cmd_priv        cmdpriv;
+       struct  evt_priv        evtpriv;
+       /* struct       io_queue        *pio_queue; */
+       struct  io_priv iopriv;
+       struct  xmit_priv       xmitpriv;
+       struct  recv_priv       recvpriv;
+       struct  sta_priv        stapriv;
+       struct  security_priv   securitypriv;
+       struct  registry_priv   registrypriv;
+       struct  pwrctrl_priv    pwrctrlpriv;
+       struct  eeprom_priv eeprompriv;
+       struct  led_priv        ledpriv;
+
+#ifdef CONFIG_8723AU_AP_MODE
+       struct  hostapd_priv    *phostapdpriv;
+#endif
+
+       struct cfg80211_wifidirect_info cfg80211_wdinfo;
+       u32     setband;
+       struct wifidirect_info  wdinfo;
+
+#ifdef CONFIG_8723AU_P2P
+       struct wifi_display_info wfd_info;
+#endif /* CONFIG_8723AU_P2P */
+
+       void *HalData;
+       u32 hal_data_sz;
+       struct hal_ops  HalFunc;
+
+       s32     bDriverStopped;
+       s32     bSurpriseRemoved;
+       s32  bCardDisableWOHSM;
+
+       u32     IsrContent;
+       u32     ImrContent;
+
+       u8      EepromAddressSize;
+       u8      hw_init_completed;
+       u8      bDriverIsGoingToUnload;
+       u8      init_adpt_in_progress;
+       u8      bHaltInProgress;
+
+       void *cmdThread;
+       void *evtThread;
+       void *xmitThread;
+       void *recvThread;
+
+       void (*intf_start)(struct rtw_adapter *adapter);
+       void (*intf_stop)(struct rtw_adapter *adapter);
+
+       struct net_device *pnetdev;
+
+       /*  used by rtw_rereg_nd_name related function */
+       struct rereg_nd_name_data {
+               struct net_device *old_pnetdev;
+               char old_ifname[IFNAMSIZ];
+               u8 old_ips_mode;
+               u8 old_bRegUseLed;
+       } rereg_nd_name_priv;
+
+       int bup;
+       struct net_device_stats stats;
+       struct iw_statistics iwstats;
+       struct proc_dir_entry *dir_dev;/*  for proc directory */
+
+       struct wireless_dev *rtw_wdev;
+       int net_closed;
+
+       u8 bFWReady;
+       u8 bBTFWReady;
+       u8 bReadPortCancel;
+       u8 bWritePortCancel;
+       u8 bRxRSSIDisplay;
+       /* The driver will show the desired chan nor when this flag is 1. */
+       u8 bNotifyChannelChange;
+#ifdef CONFIG_8723AU_P2P
+       /* driver will show current P2P status when the  application reads it*/
+       u8 bShowGetP2PState;
+#endif
+       struct rtw_adapter *pbuddy_adapter;
+
+       /* extend to support multi interface */
+       /* IFACE_ID0 is equals to PRIMARY_ADAPTER */
+       /* IFACE_ID1 is equals to SECONDARY_ADAPTER */
+       u8 iface_id;
+
+#ifdef CONFIG_BR_EXT
+       _lock                                   br_ext_lock;
+       /* unsigned int                 macclone_completed; */
+       struct nat25_network_db_entry   *nethash[NAT25_HASH_SIZE];
+       int                             pppoe_connection_in_progress;
+       unsigned char                   pppoe_addr[MACADDRLEN];
+       unsigned char                   scdb_mac[MACADDRLEN];
+       unsigned char                   scdb_ip[4];
+       struct nat25_network_db_entry   *scdb_entry;
+       unsigned char                   br_mac[MACADDRLEN];
+       unsigned char                   br_ip[4];
+
+       struct br_ext_info              ethBrExtInfo;
+#endif /*  CONFIG_BR_EXT */
+
+       u8    fix_rate;
+
+       unsigned char     in_cta_test;
+
+};
+
+#define adapter_to_dvobj(adapter) (adapter->dvobj)
+
+int rtw_handle_dualmac23a(struct rtw_adapter *adapter, bool init);
+
+static inline u8 *myid(struct eeprom_priv *peepriv)
+{
+       return peepriv->mac_addr;
+}
+
+#endif /* __DRV_TYPES_H__ */
diff --git a/drivers/staging/rtl8723au/include/ethernet.h b/drivers/staging/rtl8723au/include/ethernet.h
new file mode 100644 (file)
index 0000000..39fc6df
--- /dev/null
@@ -0,0 +1,22 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ ******************************************************************************/
+/*! \file */
+#ifndef __INC_ETHERNET_H
+#define __INC_ETHERNET_H
+
+#define LLC_HEADER_SIZE                        6       /*  LLC Header Length */
+
+#endif /*  #ifndef __INC_ETHERNET_H */
diff --git a/drivers/staging/rtl8723au/include/hal_com.h b/drivers/staging/rtl8723au/include/hal_com.h
new file mode 100644 (file)
index 0000000..20f983c
--- /dev/null
@@ -0,0 +1,211 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __HAL_COMMON_H__
+#define __HAL_COMMON_H__
+
+/*  */
+/*        Rate Definition */
+/*  */
+/* CCK */
+#define        RATR_1M                                 0x00000001
+#define        RATR_2M                                 0x00000002
+#define        RATR_55M                                0x00000004
+#define        RATR_11M                                0x00000008
+/* OFDM */
+#define        RATR_6M                                 0x00000010
+#define        RATR_9M                                 0x00000020
+#define        RATR_12M                                0x00000040
+#define        RATR_18M                                0x00000080
+#define        RATR_24M                                0x00000100
+#define        RATR_36M                                0x00000200
+#define        RATR_48M                                0x00000400
+#define        RATR_54M                                0x00000800
+/* MCS 1 Spatial Stream */
+#define        RATR_MCS0                               0x00001000
+#define        RATR_MCS1                               0x00002000
+#define        RATR_MCS2                               0x00004000
+#define        RATR_MCS3                               0x00008000
+#define        RATR_MCS4                               0x00010000
+#define        RATR_MCS5                               0x00020000
+#define        RATR_MCS6                               0x00040000
+#define        RATR_MCS7                               0x00080000
+/* MCS 2 Spatial Stream */
+#define        RATR_MCS8                               0x00100000
+#define        RATR_MCS9                               0x00200000
+#define        RATR_MCS10                              0x00400000
+#define        RATR_MCS11                              0x00800000
+#define        RATR_MCS12                              0x01000000
+#define        RATR_MCS13                              0x02000000
+#define        RATR_MCS14                              0x04000000
+#define        RATR_MCS15                              0x08000000
+
+/* CCK */
+#define RATE_1M                                        BIT(0)
+#define RATE_2M                                        BIT(1)
+#define RATE_5_5M                              BIT(2)
+#define RATE_11M                               BIT(3)
+/* OFDM */
+#define RATE_6M                                        BIT(4)
+#define RATE_9M                                        BIT(5)
+#define RATE_12M                               BIT(6)
+#define RATE_18M                               BIT(7)
+#define RATE_24M                               BIT(8)
+#define RATE_36M                               BIT(9)
+#define RATE_48M                               BIT(10)
+#define RATE_54M                               BIT(11)
+/* MCS 1 Spatial Stream */
+#define RATE_MCS0                              BIT(12)
+#define RATE_MCS1                              BIT(13)
+#define RATE_MCS2                              BIT(14)
+#define RATE_MCS3                              BIT(15)
+#define RATE_MCS4                              BIT(16)
+#define RATE_MCS5                              BIT(17)
+#define RATE_MCS6                              BIT(18)
+#define RATE_MCS7                              BIT(19)
+/* MCS 2 Spatial Stream */
+#define RATE_MCS8                              BIT(20)
+#define RATE_MCS9                              BIT(21)
+#define RATE_MCS10                             BIT(22)
+#define RATE_MCS11                             BIT(23)
+#define RATE_MCS12                             BIT(24)
+#define RATE_MCS13                             BIT(25)
+#define RATE_MCS14                             BIT(26)
+#define RATE_MCS15                             BIT(27)
+
+/*  ALL CCK Rate */
+#define        RATE_ALL_CCK    (RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define        RATE_ALL_OFDM_AG                                \
+       (RATR_6M | RATR_9M | RATR_12M | RATR_18M | RATR_24M| \
+        RATR_36M|RATR_48M|RATR_54M)
+#define        RATE_ALL_OFDM_1SS                               \
+       (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 | RATR_MCS3 |        \
+        RATR_MCS4 | RATR_MCS5 | RATR_MCS6 | RATR_MCS7)
+#define        RATE_ALL_OFDM_2SS                               \
+       (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 | RATR_MCS11|       \
+        RATR_MCS12 | RATR_MCS13 | RATR_MCS14 | RATR_MCS15)
+
+/*------------------------------ Tx Desc definition Macro ------------------------*/
+/* pragma mark -- Tx Desc related definition. -- */
+/*  */
+/*  */
+/*     Rate */
+/*  */
+/*  CCK Rates, TxHT = 0 */
+#define DESC_RATE1M                            0x00
+#define DESC_RATE2M                            0x01
+#define DESC_RATE5_5M                          0x02
+#define DESC_RATE11M                           0x03
+
+/*  OFDM Rates, TxHT = 0 */
+#define DESC_RATE6M                            0x04
+#define DESC_RATE9M                            0x05
+#define DESC_RATE12M                           0x06
+#define DESC_RATE18M                           0x07
+#define DESC_RATE24M                           0x08
+#define DESC_RATE36M                           0x09
+#define DESC_RATE48M                           0x0a
+#define DESC_RATE54M                           0x0b
+
+/*  MCS Rates, TxHT = 1 */
+#define DESC_RATEMCS0                          0x0c
+#define DESC_RATEMCS1                          0x0d
+#define DESC_RATEMCS2                          0x0e
+#define DESC_RATEMCS3                          0x0f
+#define DESC_RATEMCS4                          0x10
+#define DESC_RATEMCS5                          0x11
+#define DESC_RATEMCS6                          0x12
+#define DESC_RATEMCS7                          0x13
+#define DESC_RATEMCS8                          0x14
+#define DESC_RATEMCS9                          0x15
+#define DESC_RATEMCS10                         0x16
+#define DESC_RATEMCS11                         0x17
+#define DESC_RATEMCS12                         0x18
+#define DESC_RATEMCS13                         0x19
+#define DESC_RATEMCS14                         0x1a
+#define DESC_RATEMCS15                         0x1b
+#define DESC_RATEMCS15_SG                      0x1c
+#define DESC_RATEMCS32                         0x20
+
+#define REG_P2P_CTWIN                                  0x0572 /*  1 Byte long (in unit of TU) */
+#define REG_NOA_DESC_SEL                               0x05CF
+#define REG_NOA_DESC_DURATION          0x05E0
+#define REG_NOA_DESC_INTERVAL                  0x05E4
+#define REG_NOA_DESC_START                     0x05E8
+#define REG_NOA_DESC_COUNT                     0x05EC
+
+#include "HalVerDef.h"
+void dump_chip_info23a(struct hal_version      ChipVersion);
+
+
+u8     /* return the final channel plan decision */
+hal_com_get_channel_plan23a(
+       struct rtw_adapter      *padapter,
+       u8                      hw_channel_plan,        /* channel plan from HW (efuse/eeprom) */
+       u8                      sw_channel_plan,        /* channel plan from SW (registry/module param) */
+       u8                      def_channel_plan,       /* channel plan used when the former two is invalid */
+       bool            AutoLoadFail
+       );
+
+u8     MRateToHwRate23a(u8 rate);
+
+void HalSetBrateCfg23a(struct rtw_adapter *padapter, u8 *mBratesOS);
+
+bool
+Hal_MappingOutPipe23a(struct rtw_adapter *pAdapter, u8 NumOutPipe);
+
+void hal_init_macaddr23a(struct rtw_adapter *adapter);
+
+void c2h_evt_clear23a(struct rtw_adapter *adapter);
+s32 c2h_evt_read23a(struct rtw_adapter *adapter, u8 *buf);
+
+void rtl8723a_set_ampdu_min_space(struct rtw_adapter *padapter, u8 MinSpacingToSet);
+void rtl8723a_set_ampdu_factor(struct rtw_adapter *padapter, u8 FactorToSet);
+void rtl8723a_set_acm_ctrl(struct rtw_adapter *padapter, u8 ctrl);
+void rtl8723a_set_media_status(struct rtw_adapter *padapter, u8 status);
+void rtl8723a_set_media_status1(struct rtw_adapter *padapter, u8 status);
+void rtl8723a_set_bcn_func(struct rtw_adapter *padapter, u8 val);
+void rtl8723a_check_bssid(struct rtw_adapter *padapter, u8 val);
+void rtl8723a_mlme_sitesurvey(struct rtw_adapter *padapter, u8 flag);
+void rtl8723a_on_rcr_am(struct rtw_adapter *padapter);
+void rtl8723a_off_rcr_am(struct rtw_adapter *padapter);
+void rtl8723a_set_slot_time(struct rtw_adapter *padapter, u8 slottime);
+void rtl8723a_ack_preamble(struct rtw_adapter *padapter, u8 bShortPreamble);
+void rtl8723a_set_sec_cfg(struct rtw_adapter *padapter, u8 sec);
+void rtl8723a_cam_empty_entry(struct rtw_adapter *padapter, u8 ucIndex);
+void rtl8723a_cam_invalid_all(struct rtw_adapter *padapter);
+void rtl8723a_cam_write(struct rtw_adapter *padapter, u32 val1, u32 val2);
+void rtl8723a_fifo_cleanup(struct rtw_adapter *padapter);
+void rtl8723a_set_apfm_on_mac(struct rtw_adapter *padapter, u8 val);
+void rtl8723a_bcn_valid(struct rtw_adapter *padapter);
+void rtl8723a_set_tx_pause(struct rtw_adapter *padapter, u8 pause);
+void rtl8723a_set_beacon_interval(struct rtw_adapter *padapter, u16 interval);
+void rtl8723a_set_resp_sifs(struct rtw_adapter *padapter,
+                           u8 r2t1, u8 r2t2, u8 t2t1, u8 t2t2);
+void rtl8723a_set_ac_param_vo(struct rtw_adapter *padapter, u32 vo);
+void rtl8723a_set_ac_param_vi(struct rtw_adapter *padapter, u32 vi);
+void rtl8723a_set_ac_param_be(struct rtw_adapter *padapter, u32 be);
+void rtl8723a_set_ac_param_bk(struct rtw_adapter *padapter, u32 bk);
+void rtl8723a_set_rxdma_agg_pg_th(struct rtw_adapter *padapter, u8 val);
+void rtl8723a_set_nav_upper(struct rtw_adapter *padapter, u32 usNavUpper);
+void rtl8723a_set_initial_gain(struct rtw_adapter *padapter, u32 rx_gain);
+
+void rtl8723a_odm_support_ability_write(struct rtw_adapter *padapter, u32 val);
+void rtl8723a_odm_support_ability_backup(struct rtw_adapter *padapter, u8 val);
+void rtl8723a_odm_support_ability_set(struct rtw_adapter *padapter, u32 val);
+void rtl8723a_odm_support_ability_clr(struct rtw_adapter *padapter, u32 val);
+
+void rtl8723a_set_rpwm(struct rtw_adapter *padapter, u8 val);
+
+#endif /* __HAL_COMMON_H__ */
diff --git a/drivers/staging/rtl8723au/include/hal_intf.h b/drivers/staging/rtl8723au/include/hal_intf.h
new file mode 100644 (file)
index 0000000..d183f4b
--- /dev/null
@@ -0,0 +1,392 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __HAL_INTF_H__
+#define __HAL_INTF_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+enum RTL871X_HCI_TYPE {
+       RTW_PCIE        = BIT0,
+       RTW_USB         = BIT1,
+       RTW_SDIO        = BIT2,
+       RTW_GSPI        = BIT3,
+};
+
+enum _CHIP_TYPE {
+       NULL_CHIP_TYPE,
+       RTL8712_8188S_8191S_8192S,
+       RTL8188C_8192C,
+       RTL8192D,
+       RTL8723A,
+       RTL8188E,
+       MAX_CHIP_TYPE
+};
+
+enum HW_VARIABLES {
+       HW_VAR_MEDIA_STATUS,
+       HW_VAR_MEDIA_STATUS1,
+       HW_VAR_SET_OPMODE,
+       HW_VAR_MAC_ADDR,
+       HW_VAR_BSSID,
+       HW_VAR_INIT_RTS_RATE,
+       HW_VAR_BASIC_RATE,
+       HW_VAR_TXPAUSE,
+       HW_VAR_BCN_FUNC,
+       HW_VAR_CORRECT_TSF,
+       HW_VAR_CHECK_BSSID,
+       HW_VAR_MLME_DISCONNECT,
+       HW_VAR_MLME_SITESURVEY,
+       HW_VAR_MLME_JOIN,
+       HW_VAR_ON_RCR_AM,
+       HW_VAR_OFF_RCR_AM,
+       HW_VAR_BEACON_INTERVAL,
+       HW_VAR_SLOT_TIME,
+       HW_VAR_RESP_SIFS,
+       HW_VAR_ACK_PREAMBLE,
+       HW_VAR_SEC_CFG,
+       HW_VAR_BCN_VALID,
+       HW_VAR_RF_TYPE,
+       HW_VAR_DM_FLAG,
+       HW_VAR_DM_FUNC_OP,
+       HW_VAR_DM_FUNC_SET,
+       HW_VAR_DM_FUNC_CLR,
+       HW_VAR_CAM_EMPTY_ENTRY,
+       HW_VAR_CAM_INVALID_ALL,
+       HW_VAR_CAM_WRITE,
+       HW_VAR_CAM_READ,
+       HW_VAR_AC_PARAM_VO,
+       HW_VAR_AC_PARAM_VI,
+       HW_VAR_AC_PARAM_BE,
+       HW_VAR_AC_PARAM_BK,
+       HW_VAR_ACM_CTRL,
+       HW_VAR_AMPDU_MIN_SPACE,
+       HW_VAR_AMPDU_FACTOR,
+       HW_VAR_RXDMA_AGG_PG_TH,
+       HW_VAR_SET_RPWM,
+       HW_VAR_H2C_FW_PWRMODE,
+       HW_VAR_H2C_FW_JOINBSSRPT,
+       HW_VAR_FWLPS_RF_ON,
+       HW_VAR_H2C_FW_P2P_PS_OFFLOAD,
+       HW_VAR_TDLS_WRCR,
+       HW_VAR_TDLS_INIT_CH_SEN,
+       HW_VAR_TDLS_RS_RCR,
+       HW_VAR_TDLS_DONE_CH_SEN,
+       HW_VAR_INITIAL_GAIN,
+       HW_VAR_TRIGGER_GPIO_0,
+       HW_VAR_BT_SET_COEXIST,
+       HW_VAR_BT_ISSUE_DELBA,
+       HW_VAR_CURRENT_ANTENNA,
+       HW_VAR_ANTENNA_DIVERSITY_LINK,
+       HW_VAR_ANTENNA_DIVERSITY_SELECT,
+       HW_VAR_SWITCH_EPHY_WoWLAN,
+       HW_VAR_EFUSE_BYTES,
+       HW_VAR_EFUSE_BT_BYTES,
+       HW_VAR_FIFO_CLEARN_UP,
+       HW_VAR_CHECK_TXBUF,
+       HW_VAR_APFM_ON_MAC, /* Auto FSM to Turn On, include clock, isolation, power control for MAC only */
+       /*  The valid upper nav range for the HW updating, if the true value is larger than the upper range, the HW won't update it. */
+       /*  Unit in microsecond. 0 means disable this function. */
+       HW_VAR_NAV_UPPER,
+       HW_VAR_RPT_TIMER_SETTING,
+       HW_VAR_TX_RPT_MAX_MACID,
+       HW_VAR_H2C_MEDIA_STATUS_RPT,
+       HW_VAR_CHK_HI_QUEUE_EMPTY,
+       HW_VAR_READ_LLT_TAB,
+};
+
+enum hal_def_variable {
+       HAL_DEF_UNDERCORATEDSMOOTHEDPWDB,
+       HAL_DEF_IS_SUPPORT_ANT_DIV,
+       HAL_DEF_CURRENT_ANTENNA,
+       HAL_DEF_DRVINFO_SZ,
+       HAL_DEF_MAX_RECVBUF_SZ,
+       HAL_DEF_RX_PACKET_OFFSET,
+       HAL_DEF_DBG_DUMP_RXPKT,/* for dbg */
+       HAL_DEF_DBG_DM_FUNC,/* for dbg */
+       HAL_DEF_RA_DECISION_RATE,
+       HAL_DEF_RA_SGI,
+       HAL_DEF_PT_PWR_STATUS,
+       HW_VAR_MAX_RX_AMPDU_FACTOR,
+       HW_DEF_RA_INFO_DUMP,
+       HAL_DEF_DBG_DUMP_TXPKT,
+       HW_DEF_FA_CNT_DUMP,
+       HW_DEF_ODM_DBG_FLAG,
+};
+
+enum hal_odm_variable {
+       HAL_ODM_STA_INFO,
+       HAL_ODM_P2P_STATE,
+       HAL_ODM_WIFI_DISPLAY_STATE,
+};
+
+enum hal_intf_ps_func {
+       HAL_USB_SELECT_SUSPEND,
+       HAL_MAX_ID,
+};
+
+struct hal_ops {
+       u32 (*hal_power_on)(struct rtw_adapter *padapter);
+       u32 (*hal_init)(struct rtw_adapter *padapter);
+       u32 (*hal_deinit)(struct rtw_adapter *padapter);
+
+       void (*free_hal_data)(struct rtw_adapter *padapter);
+
+       u32 (*inirp_init)(struct rtw_adapter *padapter);
+       u32 (*inirp_deinit)(struct rtw_adapter *padapter);
+
+       s32 (*init_xmit_priv)(struct rtw_adapter *padapter);
+       void (*free_xmit_priv)(struct rtw_adapter *padapter);
+
+       s32 (*init_recv_priv)(struct rtw_adapter *padapter);
+       void (*free_recv_priv)(struct rtw_adapter *padapter);
+
+       void (*InitSwLeds)(struct rtw_adapter *padapter);
+       void (*DeInitSwLeds)(struct rtw_adapter *padapter);
+
+       void (*dm_init)(struct rtw_adapter *padapter);
+       void (*dm_deinit)(struct rtw_adapter *padapter);
+       void (*read_chip_version)(struct rtw_adapter *padapter);
+
+       void (*init_default_value)(struct rtw_adapter *padapter);
+
+       void (*intf_chip_configure)(struct rtw_adapter *padapter);
+
+       void (*read_adapter_info)(struct rtw_adapter *padapter);
+
+       void (*enable_interrupt)(struct rtw_adapter *padapter);
+       void (*disable_interrupt)(struct rtw_adapter *padapter);
+       s32 (*interrupt_handler)(struct rtw_adapter *padapter);
+       void (*set_bwmode_handler)(struct rtw_adapter *padapter,
+                                  enum ht_channel_width Bandwidth, u8 Offset);
+       void (*set_channel_handler)(struct rtw_adapter *padapter, u8 channel);
+
+       void (*hal_dm_watchdog)(struct rtw_adapter *padapter);
+
+       void (*SetHwRegHandler)(struct rtw_adapter *padapter,
+                               u8 variable, u8 *val);
+       void (*GetHwRegHandler)(struct rtw_adapter *padapter,
+                               u8 variable, u8 *val);
+
+       u8 (*GetHalDefVarHandler)(struct rtw_adapter *padapter,
+                                 enum hal_def_variable eVariable,
+                                 void *pValue);
+       u8 (*SetHalDefVarHandler)(struct rtw_adapter *padapter,
+                                 enum hal_def_variable eVariable,
+                                 void *pValue);
+
+       void (*GetHalODMVarHandler)(struct rtw_adapter *padapter,
+                                   enum hal_odm_variable eVariable,
+                                   void *pValue1, bool bSet);
+       void (*SetHalODMVarHandler)(struct rtw_adapter *padapter,
+                                   enum hal_odm_variable eVariable,
+                                   void *pValue1, bool bSet);
+
+       void (*UpdateRAMaskHandler)(struct rtw_adapter *padapter,
+                                   u32 mac_id, u8 rssi_level);
+       void (*SetBeaconRelatedRegistersHandler)(struct rtw_adapter *padapter);
+
+       void (*Add_RateATid)(struct rtw_adapter *padapter, u32 bitmap,
+                            u8 arg, u8 rssi_level);
+       void (*run_thread)(struct rtw_adapter *padapter);
+       void (*cancel_thread)(struct rtw_adapter *padapter);
+
+       u8 (*interface_ps_func)(struct rtw_adapter *padapter,
+                               enum hal_intf_ps_func efunc_id, u8 *val);
+
+       s32 (*hal_xmit)(struct rtw_adapter *padapter,
+                       struct xmit_frame *pxmitframe);
+       s32 (*mgnt_xmit)(struct rtw_adapter *padapter,
+                        struct xmit_frame *pmgntframe);
+       s32 (*hal_xmitframe_enqueue)(struct rtw_adapter *padapter,
+                                    struct xmit_frame *pxmitframe);
+
+       u32 (*read_bbreg)(struct rtw_adapter *padapter, u32 RegAddr,
+                         u32 BitMask);
+       void (*write_bbreg)(struct rtw_adapter *padapter, u32 RegAddr,
+                           u32 BitMask, u32 Data);
+       u32 (*read_rfreg)(struct rtw_adapter *padapter, u32 eRFPath,
+                         u32 RegAddr, u32 BitMask);
+       void (*write_rfreg)(struct rtw_adapter *padapter, u32 eRFPath,
+                           u32 RegAddr, u32 BitMask, u32 Data);
+
+       void (*EfusePowerSwitch)(struct rtw_adapter *padapter, u8 bWrite,
+                                u8 PwrState);
+       void (*ReadEFuse)(struct rtw_adapter *padapter, u8 efuseType,
+                         u16 _offset, u16 _size_byte, u8 *pbuf);
+       void (*EFUSEGetEfuseDefinition)(struct rtw_adapter *padapter,
+                                       u8 efuseType, u8 type, void *pOut);
+       u16 (*EfuseGetCurrentSize)(struct rtw_adapter *padapter, u8 efuseType);
+       int (*Efuse_PgPacketRead23a)(struct rtw_adapter *padapter,
+                                    u8 offset, u8 *data);
+       int (*Efuse_PgPacketWrite23a)(struct rtw_adapter *padapter,
+                                     u8 offset, u8 word_en, u8 *data);
+       u8 (*Efuse_WordEnableDataWrite23a)(struct rtw_adapter *padapter,
+                                          u16 efuse_addr, u8 word_en,
+                                          u8 *data);
+       bool (*Efuse_PgPacketWrite23a_BT)(struct rtw_adapter *padapter,
+                                         u8 offset, u8 word_en, u8 *data);
+
+       void (*sreset_init_value23a)(struct rtw_adapter *padapter);
+       void (*sreset_reset_value23a)(struct rtw_adapter *padapter);
+       void (*silentreset)(struct rtw_adapter *padapter);
+       void (*sreset_xmit_status_check)(struct rtw_adapter *padapter);
+       void (*sreset_linked_status_check) (struct rtw_adapter *padapter);
+       u8 (*sreset_get_wifi_status23a)(struct rtw_adapter *padapter);
+       bool (*sreset_inprogress)(struct rtw_adapter *padapter);
+
+       void (*hal_notch_filter)(struct rtw_adapter *adapter, bool enable);
+       void (*hal_reset_security_engine)(struct rtw_adapter *adapter);
+       s32 (*c2h_handler)(struct rtw_adapter *padapter, struct c2h_evt_hdr *c2h_evt);
+       c2h_id_filter c2h_id_filter_ccx;
+};
+
+enum rt_eeprom_type {
+       EEPROM_93C46,
+       EEPROM_93C56,
+       EEPROM_BOOT_EFUSE,
+};
+
+
+
+#define RF_CHANGE_BY_INIT      0
+#define RF_CHANGE_BY_IPS       BIT28
+#define RF_CHANGE_BY_PS                BIT29
+#define RF_CHANGE_BY_HW                BIT30
+#define RF_CHANGE_BY_SW                BIT31
+
+enum hardware_type {
+       HARDWARE_TYPE_RTL8180,
+       HARDWARE_TYPE_RTL8185,
+       HARDWARE_TYPE_RTL8187,
+       HARDWARE_TYPE_RTL8188,
+       HARDWARE_TYPE_RTL8190P,
+       HARDWARE_TYPE_RTL8192E,
+       HARDWARE_TYPE_RTL819xU,
+       HARDWARE_TYPE_RTL8192SE,
+       HARDWARE_TYPE_RTL8192SU,
+       HARDWARE_TYPE_RTL8192CE,
+       HARDWARE_TYPE_RTL8192CU,
+       HARDWARE_TYPE_RTL8192DE,
+       HARDWARE_TYPE_RTL8192DU,
+       HARDWARE_TYPE_RTL8723AE,
+       HARDWARE_TYPE_RTL8723AU,
+       HARDWARE_TYPE_RTL8723AS,
+       HARDWARE_TYPE_RTL8188EE,
+       HARDWARE_TYPE_RTL8188EU,
+       HARDWARE_TYPE_RTL8188ES,
+       HARDWARE_TYPE_MAX,
+};
+
+#define GET_EEPROM_EFUSE_PRIV(adapter) (&adapter->eeprompriv)
+#define is_boot_from_eeprom(adapter) (adapter->eeprompriv.EepromOrEfuse)
+
+extern int rtw_ht_enable23A;
+extern int rtw_cbw40_enable23A;
+extern int rtw_ampdu_enable23A;/* for enable tx_ampdu */
+
+void rtw_hal_def_value_init23a(struct rtw_adapter *padapter);
+int pm_netdev_open23a(struct net_device *pnetdev, u8 bnormal);
+int rtw_resume_process23a(struct rtw_adapter *padapter);
+
+void   rtw_hal_free_data23a(struct rtw_adapter *padapter);
+
+void rtw_hal_dm_init23a(struct rtw_adapter *padapter);
+void rtw_hal_dm_deinit23a(struct rtw_adapter *padapter);
+void rtw_hal_sw_led_init23a(struct rtw_adapter *padapter);
+void rtw_hal_sw_led_deinit23a(struct rtw_adapter *padapter);
+
+u32 rtw_hal_power_on23a(struct rtw_adapter *padapter);
+uint rtw_hal_init23a(struct rtw_adapter *padapter);
+uint rtw_hal_deinit23a(struct rtw_adapter *padapter);
+void rtw_hal_stop(struct rtw_adapter *padapter);
+void rtw_hal_set_hwreg23a(struct rtw_adapter *padapter, u8 variable, u8 *val);
+void rtw23a_hal_get_hwreg(struct rtw_adapter *padapter, u8 variable, u8 *val);
+
+void rtw_hal_chip_configure23a(struct rtw_adapter *padapter);
+void rtw_hal_read_chip_info23a(struct rtw_adapter *padapter);
+void rtw_hal_read_chip_version23a(struct rtw_adapter *padapter);
+
+u8 rtw_hal_set_def_var23a(struct rtw_adapter *padapter,
+                         enum hal_def_variable eVariable,
+                         void *pValue);
+u8 rtw_hal_get_def_var23a(struct rtw_adapter *padapter,
+                         enum hal_def_variable eVariable,
+                         void *pValue);
+
+void rtw_hal_set_odm_var23a(struct rtw_adapter *padapter,
+                           enum hal_odm_variable eVariable,
+                           void *pValue1, bool bSet);
+void rtw_hal_get_odm_var23a(struct rtw_adapter *padapter,
+                           enum hal_odm_variable eVariable,
+                           void *pValue1, bool bSet);
+
+void rtw_hal_enable_interrupt23a(struct rtw_adapter *padapter);
+void rtw_hal_disable_interrupt23a(struct rtw_adapter *padapter);
+
+u32 rtw_hal_inirp_init23a(struct rtw_adapter *padapter);
+u32 rtw_hal_inirp_deinit23a(struct rtw_adapter *padapter);
+
+u8 rtw_hal_intf_ps_func23a(struct rtw_adapter *padapter,
+                          enum hal_intf_ps_func efunc_id, u8 *val);
+
+s32 rtw_hal_xmit23aframe_enqueue(struct rtw_adapter *padapter,
+                                struct xmit_frame *pxmitframe);
+s32 rtw_hal_xmit23a(struct rtw_adapter *padapter,
+                   struct xmit_frame *pxmitframe);
+s32 rtw_hal_mgnt_xmit23a(struct rtw_adapter *padapter,
+                        struct xmit_frame *pmgntframe);
+
+s32    rtw_hal_init23a_xmit_priv(struct rtw_adapter *padapter);
+void   rtw_hal_free_xmit_priv23a(struct rtw_adapter *padapter);
+
+s32    rtw_hal_init23a_recv_priv(struct rtw_adapter *padapter);
+void   rtw_hal_free_recv_priv23a(struct rtw_adapter *padapter);
+
+void rtw_hal_update_ra_mask23a(struct sta_info *psta, u8 rssi_level);
+void   rtw_hal_add_ra_tid23a(struct rtw_adapter *padapter, u32 bitmap, u8 arg, u8 rssi_level);
+void   rtw_hal_clone_data(struct rtw_adapter *dst_padapter, struct rtw_adapter *src_padapter);
+void   rtw_hal_start_thread23a(struct rtw_adapter *padapter);
+void   rtw_hal_stop_thread23a(struct rtw_adapter *padapter);
+
+void rtw_hal_bcn_related_reg_setting23a(struct rtw_adapter *padapter);
+
+u32    rtw_hal_read_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask);
+void   rtw_hal_write_bbreg23a(struct rtw_adapter *padapter, u32 RegAddr, u32 BitMask, u32 Data);
+u32    rtw_hal_read_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask);
+void   rtw_hal_write_rfreg23a(struct rtw_adapter *padapter, u32 eRFPath, u32 RegAddr, u32 BitMask, u32 Data);
+
+s32    rtw_hal_interrupt_handler23a(struct rtw_adapter *padapter);
+
+void   rtw_hal_set_bwmode23a(struct rtw_adapter *padapter,
+                          enum ht_channel_width Bandwidth, u8 Offset);
+void   rtw_hal_set_chan23a(struct rtw_adapter *padapter, u8 channel);
+void   rtw_hal_dm_watchdog23a(struct rtw_adapter *padapter);
+
+void rtw_hal_sreset_init23a(struct rtw_adapter *padapter);
+void rtw_hal_sreset_reset23a(struct rtw_adapter *padapter);
+void rtw_hal_sreset_reset23a_value23a(struct rtw_adapter *padapter);
+void rtw_hal_sreset_xmit_status_check23a(struct rtw_adapter *padapter);
+void rtw_hal_sreset_linked_status_check23a (struct rtw_adapter *padapter);
+u8   rtw_hal_sreset_get_wifi_status23a(struct rtw_adapter *padapter);
+bool rtw_hal_sreset_inprogress(struct rtw_adapter *padapter);
+
+void rtw_hal_notch_filter23a(struct rtw_adapter *adapter, bool enable);
+void rtw_hal_reset_security_engine23a(struct rtw_adapter *adapter);
+
+s32 rtw_hal_c2h_handler23a(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt);
+c2h_id_filter rtw_hal_c2h_id_filter_ccx23a(struct rtw_adapter *adapter);
+
+#endif /* __HAL_INTF_H__ */
diff --git a/drivers/staging/rtl8723au/include/ieee80211.h b/drivers/staging/rtl8723au/include/ieee80211.h
new file mode 100644 (file)
index 0000000..28e4ab2
--- /dev/null
@@ -0,0 +1,603 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __IEEE80211_H
+#define __IEEE80211_H
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include "linux/ieee80211.h"
+#include "wifi.h"
+
+#include <linux/wireless.h>
+
+#if (WIRELESS_EXT < 22)
+#error "Obsolete pre 2007 wireless extensions are not supported"
+#endif
+
+
+#define MGMT_QUEUE_NUM 5
+
+#ifdef CONFIG_8723AU_AP_MODE
+
+/* STA flags */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3)
+#define WLAN_STA_PERM BIT(4)
+#define WLAN_STA_AUTHORIZED BIT(5)
+#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
+#define WLAN_STA_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_PREAUTH BIT(8)
+#define WLAN_STA_WME BIT(9)
+#define WLAN_STA_MFP BIT(10)
+#define WLAN_STA_HT BIT(11)
+#define WLAN_STA_WPS BIT(12)
+#define WLAN_STA_MAYBE_WPS BIT(13)
+#define WLAN_STA_NONERP BIT(31)
+
+#endif
+
+#define IEEE_CMD_SET_WPA_PARAM                 1
+#define IEEE_CMD_SET_WPA_IE                            2
+#define IEEE_CMD_SET_ENCRYPTION                        3
+
+#define        IEEE_CRYPT_ALG_NAME_LEN                 16
+
+#define WPA_CIPHER_NONE                BIT(0)
+#define WPA_CIPHER_WEP40       BIT(1)
+#define WPA_CIPHER_WEP104 BIT(2)
+#define WPA_CIPHER_TKIP                BIT(3)
+#define WPA_CIPHER_CCMP                BIT(4)
+
+
+
+#define WPA_SELECTOR_LEN 4
+extern u8 RTW_WPA_OUI23A_TYPE[] ;
+extern u16 RTW_WPA_VERSION23A ;
+extern u8 WPA_AUTH_KEY_MGMT_NONE23A[];
+extern u8 WPA_AUTH_KEY_MGMT_UNSPEC_802_1X23A[];
+extern u8 WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X23A[];
+extern u8 WPA_CIPHER_SUITE_NONE23A[];
+extern u8 WPA_CIPHER_SUITE_WEP4023A[];
+extern u8 WPA_CIPHER_SUITE_TKIP23A[];
+extern u8 WPA_CIPHER_SUITE_WRAP23A[];
+extern u8 WPA_CIPHER_SUITE_CCMP23A[];
+extern u8 WPA_CIPHER_SUITE_WEP10423A[];
+
+
+#define RSN_HEADER_LEN 4
+#define RSN_SELECTOR_LEN 4
+
+extern u16 RSN_VERSION_BSD23A;
+extern u8 RSN_AUTH_KEY_MGMT_UNSPEC_802_1X23A[];
+extern u8 RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X23A[];
+extern u8 RSN_CIPHER_SUITE_NONE23A[];
+extern u8 RSN_CIPHER_SUITE_WEP4023A[];
+extern u8 RSN_CIPHER_SUITE_TKIP23A[];
+extern u8 RSN_CIPHER_SUITE_WRAP23A[];
+extern u8 RSN_CIPHER_SUITE_CCMP23A[];
+extern u8 RSN_CIPHER_SUITE_WEP10423A[];
+
+enum ratr_table_mode {
+       RATR_INX_WIRELESS_NGB = 0,      /*  BGN 40 Mhz 2SS 1SS */
+       RATR_INX_WIRELESS_NG = 1,       /*  GN or N */
+       RATR_INX_WIRELESS_NB = 2,       /*  BGN 20 Mhz 2SS 1SS  or BN */
+       RATR_INX_WIRELESS_N = 3,
+       RATR_INX_WIRELESS_GB = 4,
+       RATR_INX_WIRELESS_G = 5,
+       RATR_INX_WIRELESS_B = 6,
+       RATR_INX_WIRELESS_MC = 7,
+       RATR_INX_WIRELESS_AC_N = 8,
+};
+
+enum NETWORK_TYPE
+{
+    WIRELESS_INVALID = 0,
+    /* Sub-Element */
+    WIRELESS_11B = BIT(0), /*  tx: cck only , rx: cck only, hw: cck */
+    WIRELESS_11G = BIT(1), /*  tx: ofdm only, rx: ofdm & cck, hw: cck & ofdm */
+    WIRELESS_11A = BIT(2), /*  tx: ofdm only, rx: ofdm only, hw: ofdm only */
+    WIRELESS_11_24N = BIT(3), /*  tx: MCS only, rx: MCS & cck, hw: MCS & cck */
+    WIRELESS_11_5N = BIT(4), /*  tx: MCS only, rx: MCS & ofdm, hw: ofdm only */
+       /* WIRELESS_AUTO                = BIT(5), */
+       WIRELESS_AC             = BIT(6),
+
+    /* Combination */
+    WIRELESS_11BG = (WIRELESS_11B|WIRELESS_11G), /*  tx: cck & ofdm, rx: cck & ofdm & MCS, hw: cck & ofdm */
+    WIRELESS_11G_24N = (WIRELESS_11G|WIRELESS_11_24N), /*  tx: ofdm & MCS, rx: ofdm & cck & MCS, hw: cck & ofdm */
+    WIRELESS_11A_5N = (WIRELESS_11A|WIRELESS_11_5N), /*  tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */
+    WIRELESS_11BG_24N = (WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N), /*  tx: ofdm & cck & MCS, rx: ofdm & cck & MCS, hw: ofdm & cck */
+    WIRELESS_11AGN = (WIRELESS_11A|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N), /*  tx: ofdm & MCS, rx: ofdm & MCS, hw: ofdm only */
+    WIRELESS_11ABGN = (WIRELESS_11A|WIRELESS_11B|WIRELESS_11G|WIRELESS_11_24N|WIRELESS_11_5N),
+};
+
+#define SUPPORTED_24G_NETTYPE_MSK (WIRELESS_11B | WIRELESS_11G | WIRELESS_11_24N)
+#define SUPPORTED_5G_NETTYPE_MSK (WIRELESS_11A | WIRELESS_11_5N)
+
+#define IsSupported24G(NetType) ((NetType) & SUPPORTED_24G_NETTYPE_MSK ? true : false)
+#define IsSupported5G(NetType) ((NetType) & SUPPORTED_5G_NETTYPE_MSK ? true : false)
+
+#define IsEnableHWCCK(NetType) IsSupported24G(NetType)
+#define IsEnableHWOFDM(NetType) ((NetType) & (WIRELESS_11G|WIRELESS_11_24N|SUPPORTED_5G_NETTYPE_MSK) ? true : false)
+
+#define IsSupportedRxCCK(NetType) IsEnableHWCCK(NetType)
+#define IsSupportedRxOFDM(NetType) IsEnableHWOFDM(NetType)
+#define IsSupportedRxMCS(NetType) IsEnableHWOFDM(NetType)
+
+#define IsSupportedTxCCK(NetType) ((NetType) & (WIRELESS_11B) ? true : false)
+#define IsSupportedTxOFDM(NetType) ((NetType) & (WIRELESS_11G|WIRELESS_11A) ? true : false)
+#define IsSupportedTxMCS(NetType) ((NetType) & (WIRELESS_11_24N|WIRELESS_11_5N) ? true : false)
+
+
+struct ieee_param {
+       u32 cmd;
+       u8 sta_addr[ETH_ALEN];
+       union {
+               struct {
+                       u8 name;
+                       u32 value;
+               } wpa_param;
+               struct {
+                       u32 len;
+                       u8 reserved[32];
+                       u8 data[0];
+               } wpa_ie;
+               struct{
+                       int command;
+                       int reason_code;
+               } mlme;
+               struct {
+                       u8 alg[IEEE_CRYPT_ALG_NAME_LEN];
+                       u8 set_tx;
+                       u32 err;
+                       u8 idx;
+                       u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+                       u16 key_len;
+                       u8 key[0];
+               } crypt;
+#ifdef CONFIG_8723AU_AP_MODE
+               struct {
+                       u16 aid;
+                       u16 capability;
+                       int flags;
+                       u8 tx_supp_rates[16];
+                       struct ieee80211_ht_cap ht_cap;
+               } add_sta;
+               struct {
+                       u8      reserved[2];/* for set max_num_sta */
+                       u8      buf[0];
+               } bcn_ie;
+#endif
+
+       } u;
+};
+
+
+#define MIN_FRAG_THRESHOLD     256U
+#define        MAX_FRAG_THRESHOLD     2346U
+
+/* QoS,QOS */
+#define NORMAL_ACK                     0
+#define NO_ACK                         1
+#define NON_EXPLICIT_ACK       2
+#define BLOCK_ACK                      3
+
+/* IEEE 802.11 defines */
+
+#define P80211_OUI_LEN 3
+
+struct ieee80211_snap_hdr {
+
+        u8    dsap;   /* always 0xAA */
+        u8    ssap;   /* always 0xAA */
+        u8    ctrl;   /* always 0x03 */
+        u8    oui[P80211_OUI_LEN];    /* organizational universal id */
+
+} __attribute__ ((packed));
+
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define WLAN_FC_GET_TYPE(fc) ((fc) & IEEE80211_FCTL_FTYPE)
+#define WLAN_FC_GET_STYPE(fc) ((fc) & IEEE80211_FCTL_STYPE)
+
+#define WLAN_QC_GET_TID(qc) ((qc) & 0x0f)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & RTW_IEEE80211_SCTL_FRAG)
+#define WLAN_GET_SEQ_SEQ(seq)  ((seq) & RTW_IEEE80211_SCTL_SEQ)
+
+
+#define WLAN_REASON_JOIN_WRONG_CHANNEL       65534
+#define WLAN_REASON_EXPIRATION_CHK 65535
+
+
+
+#define IEEE80211_STATMASK_SIGNAL (1<<0)
+#define IEEE80211_STATMASK_RSSI (1<<1)
+#define IEEE80211_STATMASK_NOISE (1<<2)
+#define IEEE80211_STATMASK_RATE (1<<3)
+#define IEEE80211_STATMASK_WEMASK 0x7
+
+
+#define IEEE80211_CCK_MODULATION    (1<<0)
+#define IEEE80211_OFDM_MODULATION   (1<<1)
+
+#define IEEE80211_24GHZ_BAND     (1<<0)
+#define IEEE80211_52GHZ_BAND     (1<<1)
+
+#define IEEE80211_CCK_RATE_LEN                 4
+#define IEEE80211_NUM_OFDM_RATESLEN    8
+
+
+#define IEEE80211_CCK_RATE_1MB                 0x02
+#define IEEE80211_CCK_RATE_2MB                 0x04
+#define IEEE80211_CCK_RATE_5MB                 0x0B
+#define IEEE80211_CCK_RATE_11MB                        0x16
+#define IEEE80211_OFDM_RATE_LEN                        8
+#define IEEE80211_OFDM_RATE_6MB                        0x0C
+#define IEEE80211_OFDM_RATE_9MB                        0x12
+#define IEEE80211_OFDM_RATE_12MB               0x18
+#define IEEE80211_OFDM_RATE_18MB               0x24
+#define IEEE80211_OFDM_RATE_24MB               0x30
+#define IEEE80211_OFDM_RATE_36MB               0x48
+#define IEEE80211_OFDM_RATE_48MB               0x60
+#define IEEE80211_OFDM_RATE_54MB               0x6C
+#define IEEE80211_BASIC_RATE_MASK              0x80
+
+#define IEEE80211_CCK_RATE_1MB_MASK            (1<<0)
+#define IEEE80211_CCK_RATE_2MB_MASK            (1<<1)
+#define IEEE80211_CCK_RATE_5MB_MASK            (1<<2)
+#define IEEE80211_CCK_RATE_11MB_MASK           (1<<3)
+#define IEEE80211_OFDM_RATE_6MB_MASK           (1<<4)
+#define IEEE80211_OFDM_RATE_9MB_MASK           (1<<5)
+#define IEEE80211_OFDM_RATE_12MB_MASK          (1<<6)
+#define IEEE80211_OFDM_RATE_18MB_MASK          (1<<7)
+#define IEEE80211_OFDM_RATE_24MB_MASK          (1<<8)
+#define IEEE80211_OFDM_RATE_36MB_MASK          (1<<9)
+#define IEEE80211_OFDM_RATE_48MB_MASK          (1<<10)
+#define IEEE80211_OFDM_RATE_54MB_MASK          (1<<11)
+
+#define IEEE80211_CCK_RATES_MASK               0x0000000F
+#define IEEE80211_CCK_BASIC_RATES_MASK (IEEE80211_CCK_RATE_1MB_MASK | \
+       IEEE80211_CCK_RATE_2MB_MASK)
+#define IEEE80211_CCK_DEFAULT_RATES_MASK       (IEEE80211_CCK_BASIC_RATES_MASK | \
+        IEEE80211_CCK_RATE_5MB_MASK | \
+        IEEE80211_CCK_RATE_11MB_MASK)
+
+#define IEEE80211_OFDM_RATES_MASK              0x00000FF0
+#define IEEE80211_OFDM_BASIC_RATES_MASK        (IEEE80211_OFDM_RATE_6MB_MASK | \
+       IEEE80211_OFDM_RATE_12MB_MASK | \
+       IEEE80211_OFDM_RATE_24MB_MASK)
+#define IEEE80211_OFDM_DEFAULT_RATES_MASK      (IEEE80211_OFDM_BASIC_RATES_MASK | \
+       IEEE80211_OFDM_RATE_9MB_MASK  | \
+       IEEE80211_OFDM_RATE_18MB_MASK | \
+       IEEE80211_OFDM_RATE_36MB_MASK | \
+       IEEE80211_OFDM_RATE_48MB_MASK | \
+       IEEE80211_OFDM_RATE_54MB_MASK)
+#define IEEE80211_DEFAULT_RATES_MASK (IEEE80211_OFDM_DEFAULT_RATES_MASK | \
+                                IEEE80211_CCK_DEFAULT_RATES_MASK)
+
+#define IEEE80211_NUM_OFDM_RATES           8
+#define IEEE80211_NUM_CCK_RATES                    4
+#define IEEE80211_OFDM_SHIFT_MASK_A         4
+
+#define WEP_KEYS 4
+#define WEP_KEY_LEN 13
+
+
+
+/*
+
+ 802.11 data frame from AP
+
+      ,-------------------------------------------------------------------.
+Bytes |  2   |  2   |    6    |    6    |    6    |  2   | 0..2312 |   4  |
+      |------|------|---------|---------|---------|------|---------|------|
+Desc. | ctrl | dura |  DA/RA  |   TA    |    SA   | Sequ |  frame  |  fcs |
+      |      | tion | (BSSID) |         |         | ence |  data   |      |
+      `-------------------------------------------------------------------'
+
+Total: 28-2340 bytes
+
+*/
+
+struct ieee80211_header_data {
+       u16 frame_ctl;
+       u16 duration_id;
+       u8 addr1[6];
+       u8 addr2[6];
+       u8 addr3[6];
+       u16 seq_ctrl;
+};
+
+struct ieee80211_info_element_hdr {
+       u8 id;
+       u8 len;
+} __attribute__ ((packed));
+
+struct ieee80211_info_element {
+       u8 id;
+       u8 len;
+       u8 data[0];
+} __attribute__ ((packed));
+
+
+struct ieee80211_txb {
+       u8 nr_frags;
+       u8 encrypted;
+       u16 reserved;
+       u16 frag_size;
+       u16 payload_size;
+       struct sk_buff *fragments[0];
+};
+
+
+/* MAX_RATES_LENGTH needs to be 12.  The spec says 8, and many APs
+ * only use 8, and then use extended rates for the remaining supported
+ * rates.  Other APs, however, stick all of their supported rates on the
+ * main rates information element... */
+#define MAX_RATES_LENGTH                  ((u8)12)
+#define MAX_RATES_EX_LENGTH               ((u8)16)
+#define MAX_CHANNEL_NUMBER                 161
+
+#define MAX_WPA_IE_LEN (256)
+#define MAX_WPS_IE_LEN (512)
+#define MAX_P2P_IE_LEN (256)
+#define MAX_WFD_IE_LEN (128)
+
+#define IW_ESSID_MAX_SIZE 32
+
+/*
+join_res:
+-1: authentication fail
+-2: association fail
+> 0: TID
+*/
+
+#define DEFAULT_MAX_SCAN_AGE (15 * HZ)
+#define DEFAULT_FTS 2346
+#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
+#define MAC_ARG(x) ((u8*)(x))[0],((u8*)(x))[1],((u8*)(x))[2],((u8*)(x))[3],((u8*)(x))[4],((u8*)(x))[5]
+
+#define CFG_IEEE80211_RESERVE_FCS (1<<0)
+#define CFG_IEEE80211_COMPUTE_FCS (1<<1)
+
+#define MAXTID 16
+
+#define IEEE_A            (1<<0)
+#define IEEE_B            (1<<1)
+#define IEEE_G            (1<<2)
+#define IEEE_MODE_MASK    (IEEE_A|IEEE_B|IEEE_G)
+
+/* Baron move to ieee80211.c */
+int ieee80211_is_empty_essid23a(const char *essid, int essid_len);
+
+enum _PUBLIC_ACTION{
+       ACT_PUBLIC_BSSCOEXIST = 0, /*  20/40 BSS Coexistence */
+       ACT_PUBLIC_DSE_ENABLE = 1,
+       ACT_PUBLIC_DSE_DEENABLE = 2,
+       ACT_PUBLIC_DSE_REG_LOCATION = 3,
+       ACT_PUBLIC_EXT_CHL_SWITCH = 4,
+       ACT_PUBLIC_DSE_MSR_REQ = 5,
+       ACT_PUBLIC_DSE_MSR_RPRT = 6,
+       ACT_PUBLIC_MP = 7, /*  Measurement Pilot */
+       ACT_PUBLIC_DSE_PWR_CONSTRAINT = 8,
+       ACT_PUBLIC_VENDOR = 9, /*  for WIFI_DIRECT */
+       ACT_PUBLIC_GAS_INITIAL_REQ = 10,
+       ACT_PUBLIC_GAS_INITIAL_RSP = 11,
+       ACT_PUBLIC_GAS_COMEBACK_REQ = 12,
+       ACT_PUBLIC_GAS_COMEBACK_RSP = 13,
+       ACT_PUBLIC_TDLS_DISCOVERY_RSP = 14,
+       ACT_PUBLIC_LOCATION_TRACK = 15,
+       ACT_PUBLIC_MAX
+};
+
+#define WME_OUI_TYPE 2
+#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WME_VERSION 1
+
+
+#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+
+#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+
+/* Represent channel details, subset of ieee80211_channel */
+struct rtw_ieee80211_channel {
+       /* enum ieee80211_band band; */
+       /* u16 center_freq; */
+       u16 hw_value;
+       u32 flags;
+       /* int max_antenna_gain; */
+       /* int max_power; */
+       /* int max_reg_power; */
+       /* bool beacon_found; */
+       /* u32 orig_flags; */
+       /* int orig_mag; */
+       /* int orig_mpwr; */
+};
+
+#define CHAN_FMT \
+       /*"band:%d, "*/ \
+       /*"center_freq:%u, "*/ \
+       "hw_value:%u, " \
+       "flags:0x%08x" \
+       /*"max_antenna_gain:%d\n"*/ \
+       /*"max_power:%d\n"*/ \
+       /*"max_reg_power:%d\n"*/ \
+       /*"beacon_found:%u\n"*/ \
+       /*"orig_flags:0x%08x\n"*/ \
+       /*"orig_mag:%d\n"*/ \
+       /*"orig_mpwr:%d\n"*/
+
+#define CHAN_ARG(channel) \
+       /*(channel)->band*/ \
+       /*, (channel)->center_freq*/ \
+       (channel)->hw_value \
+       , (channel)->flags \
+       /*, (channel)->max_antenna_gain*/ \
+       /*, (channel)->max_power*/ \
+       /*, (channel)->max_reg_power*/ \
+       /*, (channel)->beacon_found*/ \
+       /*, (channel)->orig_flags*/ \
+       /*, (channel)->orig_mag*/ \
+       /*, (channel)->orig_mpwr*/ \
+
+/* Parsed Information Elements */
+struct rtw_ieee802_11_elems {
+       u8 *ssid;
+       u8 ssid_len;
+       u8 *supp_rates;
+       u8 supp_rates_len;
+       u8 *fh_params;
+       u8 fh_params_len;
+       u8 *ds_params;
+       u8 ds_params_len;
+       u8 *cf_params;
+       u8 cf_params_len;
+       u8 *tim;
+       u8 tim_len;
+       u8 *ibss_params;
+       u8 ibss_params_len;
+       u8 *challenge;
+       u8 challenge_len;
+       u8 *erp_info;
+       u8 erp_info_len;
+       u8 *ext_supp_rates;
+       u8 ext_supp_rates_len;
+       u8 *wpa_ie;
+       u8 wpa_ie_len;
+       u8 *rsn_ie;
+       u8 rsn_ie_len;
+       u8 *wme;
+       u8 wme_len;
+       u8 *wme_tspec;
+       u8 wme_tspec_len;
+       u8 *wps_ie;
+       u8 wps_ie_len;
+       u8 *power_cap;
+       u8 power_cap_len;
+       u8 *supp_channels;
+       u8 supp_channels_len;
+       u8 *mdie;
+       u8 mdie_len;
+       u8 *ftie;
+       u8 ftie_len;
+       u8 *timeout_int;
+       u8 timeout_int_len;
+       u8 *ht_capabilities;
+       u8 ht_capabilities_len;
+       u8 *ht_operation;
+       u8 ht_operation_len;
+       u8 *vendor_ht_cap;
+       u8 vendor_ht_cap_len;
+};
+
+enum parse_res {
+       ParseOK = 0,
+       ParseUnknown = 1,
+       ParseFailed = -1
+};
+
+enum parse_res rtw_ieee802_11_parse_elems23a(u8 *start, uint len,
+                               struct rtw_ieee802_11_elems *elems,
+                               int show_errors);
+
+u8 *rtw_set_fixed_ie23a(unsigned char *pbuf, unsigned int len, unsigned char *source, unsigned int *frlen);
+u8 *rtw_set_ie23a(u8 *pbuf, int index, uint len, u8 *source, uint *frlen);
+
+enum secondary_ch_offset {
+       SCN = 0, /* no secondary channel */
+       SCA = 1, /* secondary channel above */
+       SCB = 3,  /* secondary channel below */
+};
+u8 secondary_ch_offset_to_hal_ch_offset23a(u8 ch_offset);
+u8 hal_ch_offset_to_secondary_ch_offset23a(u8 ch_offset);
+u8 *rtw_set_ie23a_ch_switch(u8 *buf, u32 *buf_len, u8 ch_switch_mode, u8 new_ch, u8 ch_switch_cnt);
+u8 *rtw_set_ie23a_secondary_ch_offset(u8 *buf, u32 *buf_len, u8 secondary_ch_offset);
+u8 *rtw_set_ie23a_mesh_ch_switch_parm(u8 *buf, u32 *buf_len, u8 ttl, u8 flags, u16 reason, u16 precedence);
+
+u8 *rtw_get_ie23a(u8*pbuf, int index, int *len, int limit);
+u8 *rtw_get_ie23a_ex(u8 *in_ie, uint in_len, u8 eid, u8 *oui, u8 oui_len, u8 *ie, uint *ielen);
+int rtw_ies_remove_ie23a(u8 *ies, uint *ies_len, uint offset, u8 eid, u8 *oui, u8 oui_len);
+
+void rtw_set_supported_rate23a(u8* SupportedRates, uint mode) ;
+
+unsigned char *rtw_get_wpa_ie23a(unsigned char *pie, int *wpa_ie_len, int limit);
+unsigned char *rtw_get_wpa2_ie23a(unsigned char *pie, int *rsn_ie_len, int limit);
+int rtw_get_wpa_cipher_suite23a(u8 *s);
+int rtw_get_wpa2_cipher_suite23a(u8 *s);
+int rtw_parse_wpa_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x);
+int rtw_parse_wpa2_ie23a(u8* wpa_ie, int wpa_ie_len, int *group_cipher, int *pairwise_cipher, int *is_8021x);
+
+int rtw_get_sec_ie23a(u8 *in_ie,uint in_len,u8 *rsn_ie,u16 *rsn_len,u8 *wpa_ie,u16 *wpa_len);
+
+u8 rtw_is_wps_ie23a(u8 *ie_ptr, uint *wps_ielen);
+u8 *rtw_get_wps_ie23a(u8 *in_ie, uint in_len, u8 *wps_ie, uint *wps_ielen);
+u8 *rtw_get_wps_attr23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_attr, u32 *len_attr);
+u8 *rtw_get_wps_attr_content23a(u8 *wps_ie, uint wps_ielen, u16 target_attr_id ,u8 *buf_content, uint *len_content);
+
+/**
+ * for_each_ie - iterate over continuous IEs
+ * @ie:
+ * @buf:
+ * @buf_len:
+ */
+#define for_each_ie(ie, buf, buf_len) \
+       for (ie = (void*)buf; (((u8*)ie) - ((u8*)buf) + 1) < buf_len; ie = (void*)(((u8*)ie) + *(((u8*)ie)+1) + 2))
+
+void dump_ies23a(u8 *buf, u32 buf_len);
+void dump_wps_ie23a(u8 *ie, u32 ie_len);
+
+#ifdef CONFIG_8723AU_P2P
+void dump_p2p_ie23a(u8 *ie, u32 ie_len);
+u8 *rtw_get_p2p_ie23a(u8 *in_ie, int in_len, u8 *p2p_ie, uint *p2p_ielen);
+u8 *rtw_get_p2p_attr23a(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_attr, u32 *len_attr);
+u8 *rtw_get_p2p_attr23a_content(u8 *p2p_ie, uint p2p_ielen, u8 target_attr_id ,u8 *buf_content, uint *len_content);
+u32 rtw_set_p2p_attr_content23a(u8 *pbuf, u8 attr_id, u16 attr_len, u8 *pdata_attr);
+void rtw_wlan_bssid_ex_remove_p2p_attr23a(struct wlan_bssid_ex *bss_ex, u8 attr_id);
+#endif
+
+#ifdef CONFIG_8723AU_P2P
+int rtw_get_wfd_ie(u8 *in_ie, int in_len, u8 *wfd_ie, uint *wfd_ielen);
+int rtw_get_wfd_attr_content(u8 *wfd_ie, uint wfd_ielen, u8 target_attr_id ,u8 *attr_content, uint *attr_contentlen);
+#endif /*  CONFIG_8723AU_P2P */
+
+uint   rtw_get_rateset_len23a(u8       *rateset);
+
+struct registry_priv;
+int rtw_generate_ie23a(struct registry_priv *pregistrypriv);
+
+
+int rtw_get_bit_value_from_ieee_value23a(u8 val);
+
+uint rtw_is_cckrates_included23a(u8 *rate);
+
+uint rtw_is_cckratesonly_included23a(u8 *rate);
+
+int rtw_check_network_type23a(unsigned char *rate, int ratelen, int channel);
+
+void rtw_get_bcn_info23a(struct wlan_network *pnetwork);
+
+void rtw_macaddr_cfg23a(u8 *mac_addr);
+
+u16 rtw_mcs_rate23a(u8 rf_type, u8 bw_40MHz, u8 short_GI_20, u8 short_GI_40, unsigned char * MCS_rate);
+
+int rtw_action_frame_parse23a(const u8 *frame, u32 frame_len, u8* category, u8 *action);
+const char *action_public_str23a(u8 action);
+
+#endif /* IEEE80211_H */
diff --git a/drivers/staging/rtl8723au/include/ioctl_cfg80211.h b/drivers/staging/rtl8723au/include/ioctl_cfg80211.h
new file mode 100644 (file)
index 0000000..0eb9036
--- /dev/null
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __IOCTL_CFG80211_H__
+#define __IOCTL_CFG80211_H__
+
+struct rtw_wdev_invit_info {
+       u8 token;
+       u8 flags;
+       u8 status;
+       u8 req_op_ch;
+       u8 rsp_op_ch;
+};
+
+#define rtw_wdev_invit_info_init(invit_info) \
+       do { \
+               (invit_info)->token = 0; \
+               (invit_info)->flags = 0x00; \
+               (invit_info)->status = 0xff; \
+               (invit_info)->req_op_ch = 0; \
+               (invit_info)->rsp_op_ch = 0; \
+       } while (0)
+
+struct rtw_wdev_priv {
+       struct wireless_dev *rtw_wdev;
+
+       struct rtw_adapter *padapter;
+
+       struct cfg80211_scan_request *scan_request;
+       spinlock_t scan_req_lock;
+
+       struct net_device *pmon_ndev;/* for monitor interface */
+       char ifname_mon[IFNAMSIZ + 1]; /* name for monitor interface */
+
+       u8 p2p_enabled;
+
+       u8 provdisc_req_issued;
+
+       struct rtw_wdev_invit_info invit_info;
+
+       bool block;
+       bool power_mgmt;
+};
+
+#define wdev_to_priv(w) ((struct rtw_wdev_priv *)(wdev_priv(w)))
+
+#define wiphy_to_adapter(x)                                    \
+       (struct rtw_adapter *)(((struct rtw_wdev_priv *)        \
+       wiphy_priv(x))->padapter)
+
+#define wiphy_to_wdev(x)                                       \
+       (struct wireless_dev *)(((struct rtw_wdev_priv *)       \
+       wiphy_priv(x))->rtw_wdev)
+
+int rtw_wdev_alloc(struct rtw_adapter *padapter, struct device *dev);
+void rtw_wdev_free(struct wireless_dev *wdev);
+void rtw_wdev_unregister(struct wireless_dev *wdev);
+
+void rtw_cfg80211_init_wiphy(struct rtw_adapter *padapter);
+
+void rtw_cfg80211_surveydone_event_callback(struct rtw_adapter *padapter);
+
+void rtw_cfg80211_indicate_connect(struct rtw_adapter *padapter);
+void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter);
+void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv,
+                                    bool aborted);
+
+#ifdef CONFIG_8723AU_AP_MODE
+void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter,
+                                    u8 *pmgmt_frame, uint frame_len);
+void rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter,
+                                       unsigned char *da, unsigned short reason);
+#endif /* CONFIG_8723AU_AP_MODE */
+
+void rtw_cfg80211_issue_p2p_provision_request23a(struct rtw_adapter *padapter,
+                                             const u8 *buf, size_t len);
+void rtw_cfg80211_rx_p2p_action_public(struct rtw_adapter *padapter,
+                                      u8 *pmgmt_frame, uint frame_len);
+void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter,
+                               u8 *pmgmt_frame, uint frame_len);
+void rtw_cfg80211_rx_action(struct rtw_adapter *adapter, u8 *frame,
+                           uint frame_len, const char*msg);
+
+int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len,
+                                  int type);
+
+bool rtw_cfg80211_pwr_mgmt(struct rtw_adapter *adapter);
+
+#define rtw_cfg80211_rx_mgmt(adapter, freq, sig_dbm, buf, len, gfp)    \
+       cfg80211_rx_mgmt((adapter)->rtw_wdev, freq, sig_dbm, buf, len, 0, gfp)
+
+#define rtw_cfg80211_send_rx_assoc(adapter, bss, buf, len)             \
+       cfg80211_send_rx_assoc((adapter)->pnetdev, bss, buf, len)
+
+#define rtw_cfg80211_mgmt_tx_status(adapter, cookie, buf, len, ack, gfp) \
+       cfg80211_mgmt_tx_status((adapter)->rtw_wdev, cookie, buf,       \
+                               len, ack, gfp)
+
+#define rtw_cfg80211_ready_on_channel(adapter, cookie, chan,           \
+                                     channel_type, duration, gfp)      \
+       cfg80211_ready_on_channel((adapter)->rtw_wdev, cookie, chan,    \
+                                 duration, gfp)
+#define rtw_cfg80211_remain_on_channel_expired(adapter, cookie, chan,  \
+                                              chan_type, gfp)          \
+       cfg80211_remain_on_channel_expired((adapter)->rtw_wdev,         \
+                                          cookie, chan, gfp)
+
+#endif /* __IOCTL_CFG80211_H__ */
diff --git a/drivers/staging/rtl8723au/include/mlme_osdep.h b/drivers/staging/rtl8723au/include/mlme_osdep.h
new file mode 100644 (file)
index 0000000..b7132a9
--- /dev/null
@@ -0,0 +1,28 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef        __MLME_OSDEP_H_
+#define __MLME_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+void rtw_os_indicate_disconnect23a(struct rtw_adapter *adapter);
+void rtw_os_indicate_connect23a(struct rtw_adapter *adapter);
+void rtw_os_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted);
+void rtw_report_sec_ie23a(struct rtw_adapter *adapter, u8 authmode, u8 *sec_ie);
+
+void rtw_reset_securitypriv23a(struct rtw_adapter *adapter);
+
+#endif /* _MLME_OSDEP_H_ */
diff --git a/drivers/staging/rtl8723au/include/mp_custom_oid.h b/drivers/staging/rtl8723au/include/mp_custom_oid.h
new file mode 100644 (file)
index 0000000..da197cf
--- /dev/null
@@ -0,0 +1,342 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef        __CUSTOM_OID_H
+#define __CUSTOM_OID_H
+
+/*  0xFF818000 - 0xFF81802F            RTL8180 Mass Production Kit */
+/*  0xFF818500 - 0xFF81850F            RTL8185 Setup Utility */
+/*  0xFF818580 - 0xFF81858F            RTL8185 Phy Status Utility */
+
+/*  For Production Kit with Agilent Equipments */
+/*  in order to make our custom oids hopefully somewhat unique */
+/*  we will use 0xFF (indicating implementation specific OID) */
+/*                81(first byte of non zero Realtek unique identifier) */
+/*                80 (second byte of non zero Realtek unique identifier) */
+/*                XX (the custom OID number - providing 255 possible custom oids) */
+
+#define OID_RT_PRO_RESET_DUT           0xFF818000
+#define OID_RT_PRO_SET_DATA_RATE               0xFF818001
+#define OID_RT_PRO_START_TEST          0xFF818002
+#define OID_RT_PRO_STOP_TEST           0xFF818003
+#define OID_RT_PRO_SET_PREAMBLE                0xFF818004
+#define OID_RT_PRO_SET_SCRAMBLER               0xFF818005
+#define OID_RT_PRO_SET_FILTER_BB               0xFF818006
+#define OID_RT_PRO_SET_MANUAL_DIVERSITY_BB             0xFF818007
+#define OID_RT_PRO_SET_CHANNEL_DIRECT_CALL             0xFF818008
+#define OID_RT_PRO_SET_SLEEP_MODE_DIRECT_CALL          0xFF818009
+#define OID_RT_PRO_SET_WAKE_MODE_DIRECT_CALL           0xFF81800A
+
+#define OID_RT_PRO_SET_TX_ANTENNA_BB           0xFF81800D
+#define OID_RT_PRO_SET_ANTENNA_BB              0xFF81800E
+#define OID_RT_PRO_SET_CR_SCRAMBLER            0xFF81800F
+#define OID_RT_PRO_SET_CR_NEW_FILTER           0xFF818010
+#define OID_RT_PRO_SET_TX_POWER_CONTROL                0xFF818011
+#define OID_RT_PRO_SET_CR_TX_CONFIG            0xFF818012
+#define OID_RT_PRO_GET_TX_POWER_CONTROL                0xFF818013
+#define OID_RT_PRO_GET_CR_SIGNAL_QUALITY               0xFF818014
+#define OID_RT_PRO_SET_CR_SETPOINT             0xFF818015
+#define OID_RT_PRO_SET_INTEGRATOR              0xFF818016
+#define OID_RT_PRO_SET_SIGNAL_QUALITY          0xFF818017
+#define OID_RT_PRO_GET_INTEGRATOR              0xFF818018
+#define OID_RT_PRO_GET_SIGNAL_QUALITY          0xFF818019
+#define OID_RT_PRO_QUERY_EEPROM_TYPE           0xFF81801A
+#define OID_RT_PRO_WRITE_MAC_ADDRESS           0xFF81801B
+#define OID_RT_PRO_READ_MAC_ADDRESS            0xFF81801C
+#define OID_RT_PRO_WRITE_CIS_DATA              0xFF81801D
+#define OID_RT_PRO_READ_CIS_DATA               0xFF81801E
+#define OID_RT_PRO_WRITE_POWER_CONTROL         0xFF81801F
+#define OID_RT_PRO_READ_POWER_CONTROL          0xFF818020
+#define OID_RT_PRO_WRITE_EEPROM                0xFF818021
+#define OID_RT_PRO_READ_EEPROM         0xFF818022
+#define OID_RT_PRO_RESET_TX_PACKET_SENT                0xFF818023
+#define OID_RT_PRO_QUERY_TX_PACKET_SENT                0xFF818024
+#define OID_RT_PRO_RESET_RX_PACKET_RECEIVED            0xFF818025
+#define OID_RT_PRO_QUERY_RX_PACKET_RECEIVED            0xFF818026
+#define OID_RT_PRO_QUERY_RX_PACKET_CRC32_ERROR         0xFF818027
+#define OID_RT_PRO_QUERY_CURRENT_ADDRESS               0xFF818028
+#define OID_RT_PRO_QUERY_PERMANENT_ADDRESS             0xFF818029
+#define OID_RT_PRO_SET_PHILIPS_RF_PARAMETERS           0xFF81802A
+#define OID_RT_PRO_RECEIVE_PACKET              0xFF81802C
+/*  added by Owen on 04/08/03 for Cameo's request */
+#define OID_RT_PRO_WRITE_EEPROM_BYTE           0xFF81802D
+#define OID_RT_PRO_READ_EEPROM_BYTE            0xFF81802E
+#define OID_RT_PRO_SET_MODULATION              0xFF81802F
+/*  */
+
+#define OID_RT_DRIVER_OPTION           0xFF818080
+#define OID_RT_RF_OFF          0xFF818081
+#define OID_RT_AUTH_STATUS             0xFF818082
+
+/*  */
+#define OID_RT_PRO_SET_CONTINUOUS_TX           0xFF81800B
+#define OID_RT_PRO_SET_SINGLE_CARRIER_TX               0xFF81800C
+#define OID_RT_PRO_SET_CARRIER_SUPPRESSION_TX          0xFF81802B
+#define OID_RT_PRO_SET_SINGLE_TONE_TX          0xFF818043
+/*  */
+
+
+/*  by Owen for RTL8185 Phy Status Report Utility */
+#define OID_RT_UTILITYfalse_ALARM_COUNTERS             0xFF818580
+#define OID_RT_UTILITY_SELECT_DEBUG_MODE               0xFF818581
+#define OID_RT_UTILITY_SELECT_SUBCARRIER_NUMBER                0xFF818582
+#define OID_RT_UTILITY_GET_RSSI_STATUS         0xFF818583
+#define OID_RT_UTILITY_GET_FRAME_DETECTION_STATUS              0xFF818584
+#define OID_RT_UTILITY_GET_AGC_AND_FREQUENCY_OFFSET_ESTIMATION_STATUS  0xFF818585
+#define OID_RT_UTILITY_GET_CHANNEL_ESTIMATION_STATUS           0xFF818586
+
+/*  by Owen on 03/09/19-03/09/22 for RTL8185 */
+#define OID_RT_WIRELESS_MODE           0xFF818500
+#define OID_RT_SUPPORTED_RATES         0xFF818501
+#define OID_RT_DESIRED_RATES           0xFF818502
+#define OID_RT_WIRELESS_MODE_STARTING_ADHOC            0xFF818503
+/*  */
+
+#define OID_RT_GET_CONNECT_STATE               0xFF030001
+#define OID_RT_RESCAN          0xFF030002
+#define OID_RT_SET_KEY_LENGTH          0xFF030003
+#define OID_RT_SET_DEFAULT_KEY_ID              0xFF030004
+
+#define OID_RT_SET_CHANNEL             0xFF010182
+#define OID_RT_SET_SNIFFER_MODE                0xFF010183
+#define OID_RT_GET_SIGNAL_QUALITY              0xFF010184
+#define OID_RT_GET_SMALL_PACKET_CRC            0xFF010185
+#define OID_RT_GET_MIDDLE_PACKET_CRC           0xFF010186
+#define OID_RT_GET_LARGE_PACKET_CRC            0xFF010187
+#define OID_RT_GET_TX_RETRY            0xFF010188
+#define OID_RT_GET_RX_RETRY            0xFF010189
+#define OID_RT_PRO_SET_FW_DIG_STATE            0xFF01018A/* S */
+#define OID_RT_PRO_SET_FW_RA_STATE             0xFF01018B/* S */
+
+#define OID_RT_GET_RX_TOTAL_PACKET             0xFF010190
+#define OID_RT_GET_TX_BEACON_OK                0xFF010191
+#define OID_RT_GET_TX_BEACON_ERR               0xFF010192
+#define OID_RT_GET_RX_ICV_ERR          0xFF010193
+#define OID_RT_SET_ENCRYPTION_ALGORITHM                0xFF010194
+#define OID_RT_SET_NO_AUTO_RESCAN              0xFF010195
+#define OID_RT_GET_PREAMBLE_MODE               0xFF010196
+#define OID_RT_GET_DRIVER_UP_DELTA_TIME                0xFF010197
+#define OID_RT_GET_AP_IP               0xFF010198
+#define OID_RT_GET_CHANNELPLAN         0xFF010199
+#define OID_RT_SET_PREAMBLE_MODE               0xFF01019A
+#define OID_RT_SET_BCN_INTVL           0xFF01019B
+#define OID_RT_GET_RF_VENDER           0xFF01019C
+#define OID_RT_DEDICATE_PROBE          0xFF01019D
+#define OID_RT_PRO_RX_FILTER_PATTERN           0xFF01019E
+
+#define OID_RT_GET_DCST_CURRENT_THRESHOLD              0xFF01019F
+
+#define OID_RT_GET_CCA_ERR             0xFF0101A0
+#define OID_RT_GET_CCA_UPGRADE_THRESHOLD               0xFF0101A1
+#define OID_RT_GET_CCA_FALLBACK_THRESHOLD              0xFF0101A2
+
+#define OID_RT_GET_CCA_UPGRADE_EVALUATE_TIMES          0xFF0101A3
+#define OID_RT_GET_CCA_FALLBACK_EVALUATE_TIMES         0xFF0101A4
+
+/*  by Owen on 03/31/03 for Cameo's request */
+#define OID_RT_SET_RATE_ADAPTIVE               0xFF0101A5
+/*  */
+#define OID_RT_GET_DCST_EVALUATE_PERIOD                0xFF0101A5
+#define OID_RT_GET_DCST_TIME_UNIT_INDEX                0xFF0101A6
+#define OID_RT_GET_TOTAL_TX_BYTES              0xFF0101A7
+#define OID_RT_GET_TOTAL_RX_BYTES              0xFF0101A8
+#define OID_RT_CURRENT_TX_POWER_LEVEL          0xFF0101A9
+#define OID_RT_GET_ENC_KEY_MISMATCH_COUNT              0xFF0101AA
+#define OID_RT_GET_ENC_KEY_MATCH_COUNT         0xFF0101AB
+#define OID_RT_GET_CHANNEL             0xFF0101AC
+
+#define OID_RT_SET_CHANNELPLAN         0xFF0101AD
+#define OID_RT_GET_HARDWARE_RADIO_OFF          0xFF0101AE
+#define OID_RT_CHANNELPLAN_BY_COUNTRY          0xFF0101AF
+#define OID_RT_SCAN_AVAILABLE_BSSID            0xFF0101B0
+#define OID_RT_GET_HARDWARE_VERSION            0xFF0101B1
+#define OID_RT_GET_IS_ROAMING          0xFF0101B2
+#define OID_RT_GET_IS_PRIVACY          0xFF0101B3
+#define OID_RT_GET_KEY_MISMATCH                0xFF0101B4
+#define OID_RT_SET_RSSI_ROAM_TRAFFIC_TH                0xFF0101B5
+#define OID_RT_SET_RSSI_ROAM_SIGNAL_TH         0xFF0101B6
+#define OID_RT_RESET_LOG               0xFF0101B7
+#define OID_RT_GET_LOG         0xFF0101B8
+#define OID_RT_SET_INDICATE_HIDDEN_AP          0xFF0101B9
+#define OID_RT_GET_HEADER_FAIL         0xFF0101BA
+#define OID_RT_SUPPORTED_WIRELESS_MODE         0xFF0101BB
+#define OID_RT_GET_CHANNEL_LIST                0xFF0101BC
+#define OID_RT_GET_SCAN_IN_PROGRESS            0xFF0101BD
+#define OID_RT_GET_TX_INFO             0xFF0101BE
+#define OID_RT_RF_READ_WRITE_OFFSET            0xFF0101BF
+#define OID_RT_RF_READ_WRITE           0xFF0101C0
+
+/*  For Netgear request. 2005.01.13, by rcnjko. */
+#define OID_RT_FORCED_DATA_RATE                0xFF0101C1
+#define OID_RT_WIRELESS_MODE_FOR_SCAN_LIST     0xFF0101C2
+/*  For Netgear request. 2005.02.17, by rcnjko. */
+#define OID_RT_GET_BSS_WIRELESS_MODE           0xFF0101C3
+/*  For AZ project. 2005.06.27, by rcnjko. */
+#define OID_RT_SCAN_WITH_MAGIC_PACKET          0xFF0101C4
+
+/*  Vincent 8185MP */
+#define OID_RT_PRO_RX_FILTER           0xFF0111C0
+
+/* Andy TEST */
+/* define OID_RT_PRO_WRITE_REGISTRY            0xFF0111C1 */
+/* define OID_RT_PRO_READ_REGISTRY             0xFF0111C2 */
+#define OID_CE_USB_WRITE_REGISTRY              0xFF0111C1
+#define OID_CE_USB_READ_REGISTRY               0xFF0111C2
+
+
+#define OID_RT_PRO_SET_INITIAL_GAIN            0xFF0111C3
+#define OID_RT_PRO_SET_BB_RF_STANDBY_MODE              0xFF0111C4
+#define OID_RT_PRO_SET_BB_RF_SHUTDOWN_MODE             0xFF0111C5
+#define OID_RT_PRO_SET_TX_CHARGE_PUMP          0xFF0111C6
+#define OID_RT_PRO_SET_RX_CHARGE_PUMP          0xFF0111C7
+#define OID_RT_PRO_RF_WRITE_REGISTRY           0xFF0111C8
+#define OID_RT_PRO_RF_READ_REGISTRY            0xFF0111C9
+#define OID_RT_PRO_QUERY_RF_TYPE               0xFF0111CA
+
+/*  AP OID */
+#define OID_RT_AP_GET_ASSOCIATED_STATION_LIST          0xFF010300
+#define OID_RT_AP_GET_CURRENT_TIME_STAMP               0xFF010301
+#define OID_RT_AP_SWITCH_INTO_AP_MODE          0xFF010302
+#define OID_RT_AP_SET_DTIM_PERIOD              0xFF010303
+#define OID_RT_AP_SUPPORTED            0xFF010304      /*  Determine if driver supports AP mode. 2004.08.27, by rcnjko. */
+#define OID_RT_AP_SET_PASSPHRASE               0xFF010305      /*  Set WPA-PSK passphrase into authenticator. 2005.07.08, byrcnjko. */
+
+/*  8187MP. 2004.09.06, by rcnjko. */
+#define OID_RT_PRO8187_WI_POLL         0xFF818780
+#define OID_RT_PRO_WRITE_BB_REG                0xFF818781
+#define OID_RT_PRO_READ_BB_REG         0xFF818782
+#define OID_RT_PRO_WRITE_RF_REG                0xFF818783
+#define OID_RT_PRO_READ_RF_REG         0xFF818784
+
+/*  Meeting House. added by Annie, 2005-07-20. */
+#define OID_RT_MH_VENDER_ID            0xFFEDC100
+
+/* 8711 MP OID added 20051230. */
+#define OID_RT_PRO8711_JOIN_BSS                0xFF871100/* S */
+
+#define OID_RT_PRO_READ_REGISTER               0xFF871101 /* Q */
+#define OID_RT_PRO_WRITE_REGISTER              0xFF871102 /* S */
+
+#define OID_RT_PRO_BURST_READ_REGISTER         0xFF871103 /* Q */
+#define OID_RT_PRO_BURST_WRITE_REGISTER                0xFF871104 /* S */
+
+#define OID_RT_PRO_WRITE_TXCMD         0xFF871105 /* S */
+
+#define OID_RT_PRO_READ16_EEPROM               0xFF871106 /* Q */
+#define OID_RT_PRO_WRITE16_EEPROM              0xFF871107 /* S */
+
+#define OID_RT_PRO_H2C_SET_COMMAND             0xFF871108 /* S */
+#define OID_RT_PRO_H2C_QUERY_RESULT            0xFF871109 /* Q */
+
+#define OID_RT_PRO8711_WI_POLL         0xFF87110A /* Q */
+#define OID_RT_PRO8711_PKT_LOSS                0xFF87110B /* Q */
+#define OID_RT_RD_ATTRIB_MEM           0xFF87110C/* Q */
+#define OID_RT_WR_ATTRIB_MEM           0xFF87110D/* S */
+
+
+/* Method 2 for H2C/C2H */
+#define OID_RT_PRO_H2C_CMD_MODE                0xFF871110 /* S */
+#define OID_RT_PRO_H2C_CMD_RSP_MODE            0xFF871111 /* Q */
+#define OID_RT_PRO_H2C_CMD_EVENT_MODE          0xFF871112 /* S */
+#define OID_RT_PRO_WAIT_C2H_EVENT              0xFF871113 /* Q */
+#define OID_RT_PRO_RW_ACCESS_PROTOCOL_TEST             0xFF871114/* Q */
+
+#define OID_RT_PRO_SCSI_ACCESS_TEST            0xFF871115 /* Q, S */
+
+#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_OUT               0xFF871116 /* S */
+#define OID_RT_PRO_SCSI_TCPIPOFFLOAD_IN                0xFF871117 /* Q,S */
+#define OID_RT_RRO_RX_PKT_VIA_IOCTRL           0xFF871118 /* Q */
+#define OID_RT_RRO_RX_PKTARRAY_VIA_IOCTRL              0xFF871119 /* Q */
+
+#define OID_RT_RPO_SET_PWRMGT_TEST             0xFF87111A /* S */
+#define OID_RT_PRO_QRY_PWRMGT_TEST             0XFF87111B /* Q */
+#define OID_RT_RPO_ASYNC_RWIO_TEST             0xFF87111C /* S */
+#define OID_RT_RPO_ASYNC_RWIO_POLL             0xFF87111D /* Q */
+#define OID_RT_PRO_SET_RF_INTFS                0xFF87111E /* S */
+#define OID_RT_POLL_RX_STATUS          0xFF87111F /* Q */
+
+#define OID_RT_PRO_CFG_DEBUG_MESSAGE           0xFF871120 /* Q,S */
+#define OID_RT_PRO_SET_DATA_RATE_EX            0xFF871121/* S */
+#define OID_RT_PRO_SET_BASIC_RATE              0xFF871122/* S */
+#define OID_RT_PRO_READ_TSSI           0xFF871123/* S */
+#define OID_RT_PRO_SET_POWER_TRACKING          0xFF871124/* S */
+
+
+#define OID_RT_PRO_QRY_PWRSTATE                0xFF871150 /* Q */
+#define OID_RT_PRO_SET_PWRSTATE                0xFF871151 /* S */
+
+/* Method 2 , using workitem */
+#define OID_RT_SET_READ_REG            0xFF871181 /* S */
+#define OID_RT_SET_WRITE_REG           0xFF871182 /* S */
+#define OID_RT_SET_BURST_READ_REG              0xFF871183 /* S */
+#define OID_RT_SET_BURST_WRITE_REG             0xFF871184 /* S */
+#define OID_RT_SET_WRITE_TXCMD         0xFF871185 /* S */
+#define OID_RT_SET_READ16_EEPROM               0xFF871186 /* S */
+#define OID_RT_SET_WRITE16_EEPROM              0xFF871187 /* S */
+#define OID_RT_QRY_POLL_WKITEM         0xFF871188 /* Q */
+
+/* For SDIO INTERFACE only */
+#define OID_RT_PRO_SYNCPAGERW_SRAM             0xFF8711A0 /* Q, S */
+#define OID_RT_PRO_871X_DRV_EXT                0xFF8711A1
+
+/* For USB INTERFACE only */
+#define OID_RT_PRO_USB_VENDOR_REQ              0xFF8711B0 /* Q, S */
+#define OID_RT_PRO_SCSI_AUTO_TEST              0xFF8711B1 /* S */
+#define OID_RT_PRO_USB_MAC_AC_FIFO_WRITE               0xFF8711B2 /* S */
+#define OID_RT_PRO_USB_MAC_RX_FIFO_READ                0xFF8711B3 /* Q */
+#define OID_RT_PRO_USB_MAC_RX_FIFO_POLLING             0xFF8711B4 /* Q */
+
+#define OID_RT_PRO_H2C_SET_RATE_TABLE          0xFF8711FB /* S */
+#define OID_RT_PRO_H2C_GET_RATE_TABLE          0xFF8711FC /* S */
+#define OID_RT_PRO_H2C_C2H_LBK_TEST            0xFF8711FE
+
+#define OID_RT_PRO_ENCRYPTION_CTRL             0xFF871200 /* Q, S */
+#define OID_RT_PRO_ADD_STA_INFO                0xFF871201 /* S */
+#define OID_RT_PRO_DELE_STA_INFO               0xFF871202 /* S */
+#define OID_RT_PRO_QUERY_DR_VARIABLE           0xFF871203 /* Q */
+
+#define OID_RT_PRO_RX_PACKET_TYPE              0xFF871204 /* Q, S */
+
+#define OID_RT_PRO_READ_EFUSE          0xFF871205 /* Q */
+#define OID_RT_PRO_WRITE_EFUSE         0xFF871206 /* S */
+#define OID_RT_PRO_RW_EFUSE_PGPKT              0xFF871207 /* Q, S */
+#define OID_RT_GET_EFUSE_CURRENT_SIZE          0xFF871208 /* Q */
+
+#define OID_RT_SET_BANDWIDTH           0xFF871209 /* S */
+#define OID_RT_SET_CRYSTAL_CAP         0xFF87120A /* S */
+
+#define OID_RT_SET_RX_PACKET_TYPE              0xFF87120B /* S */
+
+#define OID_RT_GET_EFUSE_MAX_SIZE              0xFF87120C /* Q */
+
+#define OID_RT_PRO_SET_TX_AGC_OFFSET           0xFF87120D /* S */
+
+#define OID_RT_PRO_SET_PKT_TEST_MODE           0xFF87120E /* S */
+
+#define OID_RT_PRO_FOR_EVM_TEST_SETTING                0xFF87120F /* S */
+
+#define OID_RT_PRO_GET_THERMAL_METER           0xFF871210 /* Q */
+
+#define OID_RT_RESET_PHY_RX_PACKET_COUNT       0xFF871211 /* S */
+#define OID_RT_GET_PHY_RX_PACKET_RECEIVED      0xFF871212 /* Q */
+#define OID_RT_GET_PHY_RX_PACKET_CRC32_ERROR   0xFF871213 /* Q */
+
+#define OID_RT_SET_POWER_DOWN          0xFF871214 /* S */
+
+#define OID_RT_GET_POWER_MODE          0xFF871215 /* Q */
+
+#define OID_RT_PRO_EFUSE               0xFF871216 /* Q, S */
+#define OID_RT_PRO_EFUSE_MAP           0xFF871217 /* Q, S */
+
+#endif /* ifndef       __CUSTOM_OID_H */
diff --git a/drivers/staging/rtl8723au/include/odm.h b/drivers/staging/rtl8723au/include/odm.h
new file mode 100644 (file)
index 0000000..dfedfbb
--- /dev/null
@@ -0,0 +1,1205 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+
+#ifndef        __HALDMOUTSRC_H__
+#define __HALDMOUTSRC_H__
+
+/*  */
+/*  Definition */
+/*  */
+/*  */
+/*  2011/09/22 MH Define all team supprt ability. */
+/*  */
+
+/*  */
+/*  2011/09/22 MH Define for all teams. Please Define the constan in your precomp header. */
+/*  */
+/* define              DM_ODM_SUPPORT_AP                       0 */
+/* define              DM_ODM_SUPPORT_ADSL                     0 */
+/* define              DM_ODM_SUPPORT_CE                       0 */
+/* define              DM_ODM_SUPPORT_MP                       1 */
+
+#define        TP_MODE         0
+#define        RSSI_MODE               1
+#define        TRAFFIC_LOW     0
+#define        TRAFFIC_HIGH    1
+
+
+/*  */
+/* 3 Tx Power Tracking */
+/* 3============================================================ */
+#define                DPK_DELTA_MAPPING_NUM   13
+#define                index_mapping_HP_NUM    15
+
+
+/*  */
+/* 3 PSD Handler */
+/* 3============================================================ */
+
+#define        AFH_PSD         1       /* 0:normal PSD scan, 1: only do 20 pts PSD */
+#define        MODE_40M                0       /* 0:20M, 1:40M */
+#define        PSD_TH2         3
+#define        PSD_CHMIN               20   /*  Minimum channel number for BT AFH */
+#define        SIR_STEP_SIZE   3
+#define   Smooth_Size_1                5
+#define        Smooth_TH_1     3
+#define   Smooth_Size_2                10
+#define        Smooth_TH_2     4
+#define   Smooth_Size_3                20
+#define        Smooth_TH_3     4
+#define   Smooth_Step_Size 5
+#define        Adaptive_SIR    1
+#define        PSD_RESCAN              4
+#define        PSD_SCAN_INTERVAL       700 /* ms */
+
+/* 8723A High Power IGI Setting */
+#define DM_DIG_HIGH_PWR_IGI_LOWER_BOUND        0x22
+#define DM_DIG_Gmode_HIGH_PWR_IGI_LOWER_BOUND 0x28
+#define DM_DIG_HIGH_PWR_THRESHOLD      0x3a
+
+/*  LPS define */
+#define DM_DIG_FA_TH0_LPS                              4 /*  4 in lps */
+#define DM_DIG_FA_TH1_LPS                              15 /*  15 lps */
+#define DM_DIG_FA_TH2_LPS                              30 /*  30 lps */
+#define RSSI_OFFSET_DIG                                        0x05;
+
+/* ANT Test */
+#define                        ANTTESTALL              0x00            /* Ant A or B will be Testing */
+#define                ANTTESTA                0x01            /* Ant A will be Testing */
+#define                ANTTESTB                0x02            /* Ant B will be testing */
+
+
+/*  */
+/*  structure and define */
+/*  */
+
+/*  */
+/*  2011/09/20 MH Add for AP/ADSLpseudo DM structuer requirement. */
+/*  We need to remove to other position??? */
+/*  */
+struct rtl8723a_priv {
+       u8              temp;
+};
+
+
+struct  dig_t {
+       u8              Dig_Enable_Flag;
+       u8              Dig_Ext_Port_Stage;
+
+       int             RssiLowThresh;
+       int             RssiHighThresh;
+
+       u32             FALowThresh;
+       u32             FAHighThresh;
+
+       u8              CurSTAConnectState;
+       u8              PreSTAConnectState;
+       u8              CurMultiSTAConnectState;
+
+       u8              PreIGValue;
+       u8              CurIGValue;
+       u8              BackupIGValue;
+
+       s8              BackoffVal;
+       s8              BackoffVal_range_max;
+       s8              BackoffVal_range_min;
+       u8              rx_gain_range_max;
+       u8              rx_gain_range_min;
+       u8              Rssi_val_min;
+
+       u8              PreCCK_CCAThres;
+       u8              CurCCK_CCAThres;
+       u8              PreCCKPDState;
+       u8              CurCCKPDState;
+
+       u8              LargeFAHit;
+       u8              ForbiddenIGI;
+       u32             Recover_cnt;
+
+       u8              DIG_Dynamic_MIN_0;
+       u8              DIG_Dynamic_MIN_1;
+       bool            bMediaConnect_0;
+       bool            bMediaConnect_1;
+
+       u32             AntDiv_RSSI_max;
+       u32             RSSI_max;
+};
+
+struct dynamic_pwr_sav {
+       u8              PreCCAState;
+       u8              CurCCAState;
+
+       u8              PreRFState;
+       u8              CurRFState;
+
+       int                 Rssi_val_min;
+
+       u8              initialize;
+       u32             Reg874,RegC70,Reg85C,RegA74;
+};
+
+struct false_alarm_stats {
+       u32     Cnt_Parity_Fail;
+       u32     Cnt_Rate_Illegal;
+       u32     Cnt_Crc8_fail;
+       u32     Cnt_Mcs_fail;
+       u32     Cnt_Ofdm_fail;
+       u32     Cnt_Cck_fail;
+       u32     Cnt_all;
+       u32     Cnt_Fast_Fsync;
+       u32     Cnt_SB_Search_fail;
+       u32     Cnt_OFDM_CCA;
+       u32     Cnt_CCK_CCA;
+       u32     Cnt_CCA_all;
+       u32     Cnt_BW_USC;     /* Gary */
+       u32     Cnt_BW_LSC;     /* Gary */
+};
+
+struct pri_cca {
+       u8              PriCCA_flag;
+       u8              intf_flag;
+       u8              intf_type;
+       u8              DupRTS_flag;
+       u8              Monitor_flag;
+};
+
+struct rx_hp {
+       u8              RXHP_flag;
+       u8              PSD_func_trigger;
+       u8              PSD_bitmap_RXHP[80];
+       u8              Pre_IGI;
+       u8              Cur_IGI;
+       u8              Pre_pw_th;
+       u8              Cur_pw_th;
+       bool            First_time_enter;
+       bool            RXHP_enable;
+       u8              TP_Mode;
+       struct timer_list PSDTimer;
+};
+
+#define ASSOCIATE_ENTRY_NUM                                    32 /*  Max size of AsocEntry[]. */
+#define        ODM_ASSOCIATE_ENTRY_NUM                         ASSOCIATE_ENTRY_NUM
+
+/*  This indicates two different the steps. */
+/*  In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. */
+/*  In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK */
+/*  with original RSSI to determine if it is necessary to switch antenna. */
+#define SWAW_STEP_PEAK         0
+#define SWAW_STEP_DETERMINE    1
+
+#define        TP_MODE         0
+#define        RSSI_MODE               1
+#define        TRAFFIC_LOW     0
+#define        TRAFFIC_HIGH    1
+
+struct sw_ant_sw {
+       u8              try_flag;
+       s32             PreRSSI;
+       u8              CurAntenna;
+       u8              PreAntenna;
+       u8              RSSI_Trying;
+       u8              TestMode;
+       u8              bTriggerAntennaSwitch;
+       u8              SelectAntennaMap;
+       u8              RSSI_target;
+
+       /*  Before link Antenna Switch check */
+       u8              SWAS_NoLink_State;
+       u32             SWAS_NoLink_BK_Reg860;
+       bool            ANTA_ON;        /* To indicate Ant A is or not */
+       bool            ANTB_ON;        /* To indicate Ant B is on or not */
+
+       s32             RSSI_sum_A;
+       s32             RSSI_sum_B;
+       s32             RSSI_cnt_A;
+       s32             RSSI_cnt_B;
+
+       u64             lastTxOkCnt;
+       u64             lastRxOkCnt;
+       u64             TXByteCnt_A;
+       u64             TXByteCnt_B;
+       u64             RXByteCnt_A;
+       u64             RXByteCnt_B;
+       u8              TrafficLoad;
+       struct timer_list SwAntennaSwitchTimer;
+};
+
+struct edca_turbo {
+       bool bCurrentTurboEDCA;
+       bool bIsCurRDLState;
+       u32     prv_traffic_idx; /*  edca turbo */
+
+};
+
+struct odm_rate_adapt {
+       u8      Type;           /*  DM_Type_ByFW/DM_Type_ByDriver */
+       u8      HighRSSIThresh; /*  if RSSI > HighRSSIThresh    => RATRState is DM_RATR_STA_HIGH */
+       u8      LowRSSIThresh;  /*  if RSSI <= LowRSSIThresh    => RATRState is DM_RATR_STA_LOW */
+       u8      RATRState;      /*  Current RSSI level, DM_RATR_STA_HIGH/DM_RATR_STA_MIDDLE/DM_RATR_STA_LOW */
+       u32     LastRATR;       /*  RATR Register Content */
+};
+
+#define IQK_MAC_REG_NUM                4
+#define IQK_ADDA_REG_NUM               16
+#define IQK_BB_REG_NUM_MAX     10
+#define IQK_BB_REG_NUM         9
+#define HP_THERMAL_NUM         8
+
+#define AVG_THERMAL_NUM                8
+#define IQK_Matrix_REG_NUM     8
+#define IQK_Matrix_Settings_NUM        1+24+21
+
+#define                DM_Type_ByFW                    0
+#define                DM_Type_ByDriver                1
+
+/*  Declare for common info */
+
+struct odm_phy_info {
+       u8              RxPWDBAll;
+       u8              SignalQuality;   /*  in 0-100 index. */
+       u8              RxMIMOSignalQuality[RF_PATH_MAX]; /* EVM */
+       u8              RxMIMOSignalStrength[RF_PATH_MAX];/*  in 0~100 index */
+       s8              RxPower; /*  in dBm Translate from PWdB */
+       s8              RecvSignalPower;/*  Real power in dBm for this packet, no beautification and aggregation. Keep this raw info to be used for the other procedures. */
+       u8              BTRxRSSIPercentage;
+       u8              SignalStrength; /*  in 0-100 index. */
+       u8              RxPwr[RF_PATH_MAX];/* per-path's pwdb */
+       u8              RxSNR[RF_PATH_MAX];/* per-path's SNR */
+};
+
+
+struct odm_phy_dbg_info {
+       /* ODM Write,debug info */
+       s8              RxSNRdB[RF_PATH_MAX];
+       u64             NumQryPhyStatus;
+       u64             NumQryPhyStatusCCK;
+       u64             NumQryPhyStatusOFDM;
+       /* Others */
+       s32             RxEVM[RF_PATH_MAX];
+
+};
+
+struct odm_packet_info {
+       u8              Rate;
+       u8              StationID;
+       bool            bPacketMatchBSSID;
+       bool            bPacketToSelf;
+       bool            bPacketBeacon;
+};
+
+struct odm_mac_info {
+       u8      test;
+
+};
+
+
+enum {
+       /*  BB Team */
+       ODM_DIG                 = 0x00000001,
+       ODM_HIGH_POWER          = 0x00000002,
+       ODM_CCK_CCA_TH          = 0x00000004,
+       ODM_FA_STATISTICS       = 0x00000008,
+       ODM_RAMASK              = 0x00000010,
+       ODM_RSSI_MONITOR        = 0x00000020,
+       ODM_SW_ANTDIV           = 0x00000040,
+       ODM_HW_ANTDIV           = 0x00000080,
+       ODM_BB_PWRSV            = 0x00000100,
+       ODM_2TPATHDIV           = 0x00000200,
+       ODM_1TPATHDIV           = 0x00000400,
+       ODM_PSD2AFH             = 0x00000800
+};
+
+/*  */
+/*  2011/20/20 MH For MP driver RT_WLAN_STA =  struct sta_info */
+/*  Please declare below ODM relative info in your STA info structure. */
+/*  */
+struct odm_sta_info {
+       /*  Driver Write */
+       bool            bUsed;                          /*  record the sta status link or not? */
+       u8              IOTPeer;                        /*  Enum value. HT_IOT_PEER_E */
+
+       /*  ODM Write */
+       /* 1 PHY_STATUS_INFO */
+       u8              RSSI_Path[4];           /*  */
+       u8              RSSI_Ave;
+       u8              RXEVM[4];
+       u8              RXSNR[4];
+
+       /*  ODM Write */
+       /* 1 TX_INFO (may changed by IC) */
+
+       /*  */
+       /*      Please use compile flag to disable the structure for other IC except 88E. */
+       /*      Move To lower layer. */
+       /*  */
+       /*  ODM Write Wilson will handle this part(said by Luke.Lee) */
+};
+
+/*  */
+/*  2011/10/20 MH Define Common info enum for all team. */
+/*  */
+
+enum odm_cmninfo {
+       /*  Fixed value: */
+       /*  */
+
+       ODM_CMNINFO_PLATFORM = 0,
+       ODM_CMNINFO_ABILITY,                                    /*  enum odm_ability */
+       ODM_CMNINFO_INTERFACE,                          /*  enum odm_interface_def */
+       ODM_CMNINFO_MP_TEST_CHIP,
+       ODM_CMNINFO_IC_TYPE,                                    /*  enum odm_ic_type_def */
+       ODM_CMNINFO_CUT_VER,                                    /*  enum odm_cut_version */
+       ODM_CMNINFO_FAB_VER,                                    /*  enum odm_fab_version */
+       ODM_CMNINFO_RF_TYPE,                                    /*  enum rf_path_def or enum odm_rf_type? */
+       ODM_CMNINFO_BOARD_TYPE,                         /*  enum odm_board_type */
+       ODM_CMNINFO_EXT_LNA,                                    /*  true */
+       ODM_CMNINFO_EXT_PA,
+       ODM_CMNINFO_EXT_TRSW,
+       ODM_CMNINFO_PATCH_ID,                           /* CUSTOMER ID */
+       ODM_CMNINFO_BINHCT_TEST,
+       ODM_CMNINFO_BWIFI_TEST,
+       ODM_CMNINFO_SMART_CONCURRENT,
+
+
+       /*  */
+       /*  Dynamic value: */
+       /*  */
+       ODM_CMNINFO_MAC_PHY_MODE,                       /*  enum odm_mac_phy_mode */
+       ODM_CMNINFO_TX_UNI,
+       ODM_CMNINFO_RX_UNI,
+       ODM_CMNINFO_WM_MODE,                            /*  enum odm_wireless_mode */
+       ODM_CMNINFO_BAND,                                       /*  enum odm_band_type */
+       ODM_CMNINFO_SEC_CHNL_OFFSET,            /*  enum odm_sec_chnl_offset */
+       ODM_CMNINFO_SEC_MODE,                           /*  enum odm_security */
+       ODM_CMNINFO_BW,                                         /*  enum odm_band_width */
+       ODM_CMNINFO_CHNL,
+
+       ODM_CMNINFO_DMSP_GET_VALUE,
+       ODM_CMNINFO_BUDDY_ADAPTOR,
+       ODM_CMNINFO_DMSP_IS_MASTER,
+       ODM_CMNINFO_SCAN,
+       ODM_CMNINFO_POWER_SAVING,
+       ODM_CMNINFO_ONE_PATH_CCA,                       /*  enum odm_cca_path */
+       ODM_CMNINFO_DRV_STOP,
+       ODM_CMNINFO_PNP_IN,
+       ODM_CMNINFO_INIT_ON,
+       ODM_CMNINFO_ANT_TEST,
+       ODM_CMNINFO_NET_CLOSED,
+       ODM_CMNINFO_MP_MODE,
+
+       ODM_CMNINFO_WIFI_DIRECT,
+       ODM_CMNINFO_WIFI_DISPLAY,
+       ODM_CMNINFO_LINK,
+       ODM_CMNINFO_RSSI_MIN,
+       ODM_CMNINFO_DBG_COMP,                           /*  u64 */
+       ODM_CMNINFO_DBG_LEVEL,                          /*  u32 */
+       ODM_CMNINFO_RA_THRESHOLD_HIGH,          /*  u8 */
+       ODM_CMNINFO_RA_THRESHOLD_LOW,           /*  u8 */
+       ODM_CMNINFO_RF_ANTENNA_TYPE,            /*  u8 */
+       ODM_CMNINFO_BT_DISABLED,
+       ODM_CMNINFO_BT_OPERATION,
+       ODM_CMNINFO_BT_DIG,
+       ODM_CMNINFO_BT_BUSY,                                    /* Check Bt is using or not */
+       ODM_CMNINFO_BT_DISABLE_EDCA,
+
+       /*  */
+       /*  Dynamic ptr array hook itms. */
+       /*  */
+       ODM_CMNINFO_STA_STATUS,
+       ODM_CMNINFO_PHY_STATUS,
+       ODM_CMNINFO_MAC_STATUS,
+
+       ODM_CMNINFO_MAX,
+};
+
+/*  Define ODM support ability.  ODM_CMNINFO_ABILITY */
+enum {
+       /*  BB ODM section BIT 0-15 */
+       ODM_BB_DIG                              = BIT0,
+       ODM_BB_RA_MASK                          = BIT1,
+       ODM_BB_DYNAMIC_TXPWR                    = BIT2,
+       ODM_BB_FA_CNT                           = BIT3,
+       ODM_BB_RSSI_MONITOR                     = BIT4,
+       ODM_BB_CCK_PD                           = BIT5,
+       ODM_BB_ANT_DIV                          = BIT6,
+       ODM_BB_PWR_SAVE                         = BIT7,
+       ODM_BB_PWR_TRAIN                        = BIT8,
+       ODM_BB_RATE_ADAPTIVE                    = BIT9,
+       ODM_BB_PATH_DIV                         = BIT10,
+       ODM_BB_PSD                              = BIT11,
+       ODM_BB_RXHP                             = BIT12,
+
+       /*  MAC DM section BIT 16-23 */
+       ODM_MAC_EDCA_TURBO                      = BIT16,
+       ODM_MAC_EARLY_MODE                      = BIT17,
+
+       /*  RF ODM section BIT 24-31 */
+       ODM_RF_TX_PWR_TRACK                     = BIT24,
+       ODM_RF_RX_GAIN_TRACK                    = BIT25,
+       ODM_RF_CALIBRATION                      = BIT26,
+
+};
+
+/*     ODM_CMNINFO_INTERFACE */
+enum odm_interface_def {
+       ODM_ITRF_PCIE   =       0x1,
+       ODM_ITRF_USB    =       0x2,
+       ODM_ITRF_SDIO   =       0x4,
+       ODM_ITRF_ALL    =       0x7,
+};
+
+/*  ODM_CMNINFO_IC_TYPE */
+enum odm_ic_type_def {
+       ODM_RTL8192S    =       BIT0,
+       ODM_RTL8192C    =       BIT1,
+       ODM_RTL8192D    =       BIT2,
+       ODM_RTL8723A    =       BIT3,
+       ODM_RTL8188E    =       BIT4,
+       ODM_RTL8812     =       BIT5,
+       ODM_RTL8821     =       BIT6,
+};
+
+#define ODM_IC_11N_SERIES                      \
+       (ODM_RTL8192S|ODM_RTL8192C|ODM_RTL8192D|ODM_RTL8723A|ODM_RTL8188E)
+#define ODM_IC_11AC_SERIES             (ODM_RTL8812)
+
+/* ODM_CMNINFO_CUT_VER */
+enum odm_cut_version {
+       ODM_CUT_A               =       1,
+       ODM_CUT_B               =       2,
+       ODM_CUT_C               =       3,
+       ODM_CUT_D               =       4,
+       ODM_CUT_E               =       5,
+       ODM_CUT_F               =       6,
+       ODM_CUT_TEST            =       7,
+};
+
+/*  ODM_CMNINFO_FAB_VER */
+enum odm_fab_version {
+       ODM_TSMC        =       0,
+       ODM_UMC         =       1,
+};
+
+/*  ODM_CMNINFO_RF_TYPE */
+/*  For example 1T2R (A+AB = BIT0|BIT4|BIT5) */
+enum rf_path_def {
+       ODM_RF_TX_A     =       BIT0,
+       ODM_RF_TX_B     =       BIT1,
+       ODM_RF_TX_C     =       BIT2,
+       ODM_RF_TX_D     =       BIT3,
+       ODM_RF_RX_A     =       BIT4,
+       ODM_RF_RX_B     =       BIT5,
+       ODM_RF_RX_C     =       BIT6,
+       ODM_RF_RX_D     =       BIT7,
+};
+
+
+enum odm_rf_type {
+       ODM_1T1R        =       0,
+       ODM_1T2R        =       1,
+       ODM_2T2R        =       2,
+       ODM_2T3R        =       3,
+       ODM_2T4R        =       4,
+       ODM_3T3R        =       5,
+       ODM_3T4R        =       6,
+       ODM_4T4R        =       7,
+};
+
+/*  ODM Dynamic common info value definition */
+
+enum odm_mac_phy_mode {
+       ODM_SMSP        = 0,
+       ODM_DMSP        = 1,
+       ODM_DMDP        = 2,
+};
+
+
+enum odm_bt_coexist {
+       ODM_BT_BUSY             = 1,
+       ODM_BT_ON               = 2,
+       ODM_BT_OFF              = 3,
+       ODM_BT_NONE             = 4,
+};
+
+/*  ODM_CMNINFO_OP_MODE */
+enum odm_operation_mode {
+       ODM_NO_LINK             = BIT0,
+       ODM_LINK                = BIT1,
+       ODM_SCAN                = BIT2,
+       ODM_POWERSAVE           = BIT3,
+       ODM_AP_MODE             = BIT4,
+       ODM_CLIENT_MODE         = BIT5,
+       ODM_AD_HOC              = BIT6,
+       ODM_WIFI_DIRECT         = BIT7,
+       ODM_WIFI_DISPLAY        = BIT8,
+};
+
+/*  ODM_CMNINFO_WM_MODE */
+enum odm_wireless_mode {
+       ODM_WM_UNKNOW           = 0x0,
+       ODM_WM_B                = BIT0,
+       ODM_WM_G                = BIT1,
+       ODM_WM_A                = BIT2,
+       ODM_WM_N24G             = BIT3,
+       ODM_WM_N5G              = BIT4,
+       ODM_WM_AUTO             = BIT5,
+       ODM_WM_AC               = BIT6,
+};
+
+/*  ODM_CMNINFO_BAND */
+enum odm_band_type {
+       ODM_BAND_2_4G           = BIT0,
+       ODM_BAND_5G             = BIT1,
+
+};
+
+/*  ODM_CMNINFO_SEC_CHNL_OFFSET */
+enum odm_sec_chnl_offset {
+       ODM_DONT_CARE           = 0,
+       ODM_BELOW               = 1,
+       ODM_ABOVE               = 2
+};
+
+/*  ODM_CMNINFO_SEC_MODE */
+enum odm_security {
+       ODM_SEC_OPEN            = 0,
+       ODM_SEC_WEP40           = 1,
+       ODM_SEC_TKIP            = 2,
+       ODM_SEC_RESERVE         = 3,
+       ODM_SEC_AESCCMP         = 4,
+       ODM_SEC_WEP104          = 5,
+       ODM_WEP_WPA_MIXED       = 6, /*  WEP + WPA */
+       ODM_SEC_SMS4            = 7,
+};
+
+/*  ODM_CMNINFO_BW */
+enum odm_band_width {
+       ODM_BW20M               = 0,
+       ODM_BW40M               = 1,
+       ODM_BW80M               = 2,
+       ODM_BW160M              = 3,
+       ODM_BW10M               = 4,
+};
+
+/*  ODM_CMNINFO_CHNL */
+
+/*  ODM_CMNINFO_BOARD_TYPE */
+enum odm_board_type {
+       ODM_BOARD_NORMAL        = 0,
+       ODM_BOARD_HIGHPWR       = 1,
+       ODM_BOARD_MINICARD      = 2,
+       ODM_BOARD_SLIM          = 3,
+       ODM_BOARD_COMBO         = 4,
+
+};
+
+/*  ODM_CMNINFO_ONE_PATH_CCA */
+enum odm_cca_path {
+       ODM_CCA_2R                      = 0,
+       ODM_CCA_1R_A                    = 1,
+       ODM_CCA_1R_B                    = 2,
+};
+
+struct odm_ra_info {
+       u8 RateID;
+       u32 RateMask;
+       u32 RAUseRate;
+       u8 RateSGI;
+       u8 RssiStaRA;
+       u8 PreRssiStaRA;
+       u8 SGIEnable;
+       u8 DecisionRate;
+       u8 PreRate;
+       u8 HighestRate;
+       u8 LowestRate;
+       u32 NscUp;
+       u32 NscDown;
+       u16 RTY[5];
+       u32 TOTAL;
+       u16 DROP;
+       u8 Active;
+       u16 RptTime;
+       u8 RAWaitingCounter;
+       u8 RAPendingCounter;
+       u8 PTActive;  /*  on or off */
+       u8 PTTryState;  /*  0 trying state, 1 for decision state */
+       u8 PTStage;  /*  0~6 */
+       u8 PTStopCount; /* Stop PT counter */
+       u8 PTPreRate;  /*  if rate change do PT */
+       u8 PTPreRssi; /*  if RSSI change 5% do PT */
+       u8 PTModeSS;  /*  decide whitch rate should do PT */
+       u8 RAstage;  /*  StageRA, decide how many times RA will be done between PT */
+       u8 PTSmoothFactor;
+};
+
+struct iqk_matrix_regs_set {
+       bool    bIQKDone;
+       s32     Value[1][IQK_Matrix_REG_NUM];
+};
+
+struct odm_rf_cal_t {
+       /* for tx power tracking */
+
+       u32     RegA24; /*  for TempCCK */
+       s32     RegE94;
+       s32     RegE9C;
+       s32     RegEB4;
+       s32     RegEBC;
+
+       /* u8 bTXPowerTracking; */
+       u8              TXPowercount;
+       bool bTXPowerTrackingInit;
+       bool bTXPowerTracking;
+       u8              TxPowerTrackControl; /* for mp mode, turn off txpwrtracking as default */
+       u8              TM_Trigger;
+       u8              InternalPA5G[2];        /* pathA / pathB */
+
+       u8              ThermalMeter[2];    /*  ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */
+       u8              ThermalValue;
+       u8              ThermalValue_LCK;
+       u8              ThermalValue_IQK;
+       u8      ThermalValue_DPK;
+       u8      ThermalValue_AVG[AVG_THERMAL_NUM];
+       u8      ThermalValue_AVG_index;
+       u8      ThermalValue_RxGain;
+       u8      ThermalValue_Crystal;
+       u8      ThermalValue_DPKstore;
+       u8      ThermalValue_DPKtrack;
+       bool    TxPowerTrackingInProgress;
+       bool    bDPKenable;
+
+       bool    bReloadtxpowerindex;
+       u8      bRfPiEnable;
+       u32     TXPowerTrackingCallbackCnt; /* cosa add for debug */
+
+       u8      bCCKinCH14;
+       u8      CCK_index;
+       u8      OFDM_index[2];
+       bool bDoneTxpower;
+
+       u8      ThermalValue_HP[HP_THERMAL_NUM];
+       u8      ThermalValue_HP_index;
+       struct iqk_matrix_regs_set IQKMatrixRegSetting[IQK_Matrix_Settings_NUM];
+
+       u8      Delta_IQK;
+       u8      Delta_LCK;
+
+       /* for IQK */
+       u32     RegC04;
+       u32     Reg874;
+       u32     RegC08;
+       u32     RegB68;
+       u32     RegB6C;
+       u32     Reg870;
+       u32     Reg860;
+       u32     Reg864;
+
+       bool    bIQKInitialized;
+       bool bLCKInProgress;
+       bool    bAntennaDetected;
+       u32     ADDA_backup[IQK_ADDA_REG_NUM];
+       u32     IQK_MAC_backup[IQK_MAC_REG_NUM];
+       u32     IQK_BB_backup_recover[9];
+       u32     IQK_BB_backup[IQK_BB_REG_NUM];
+
+       /* for APK */
+       u32     APKoutput[2][2]; /* path A/B; output1_1a/output1_2a */
+       u8      bAPKdone;
+       u8      bAPKThermalMeterIgnore;
+       u8      bDPdone;
+       u8      bDPPathAOK;
+       u8      bDPPathBOK;
+};
+
+/*  ODM Dynamic common info value definition */
+struct odm_fat_t {
+       u8      Bssid[6];
+       u8      antsel_rx_keep_0;
+       u8      antsel_rx_keep_1;
+       u8      antsel_rx_keep_2;
+       u32     antSumRSSI[7];
+       u32     antRSSIcnt[7];
+       u32     antAveRSSI[7];
+       u8      FAT_State;
+       u32     TrainIdx;
+       u8      antsel_a[ODM_ASSOCIATE_ENTRY_NUM];
+       u8      antsel_b[ODM_ASSOCIATE_ENTRY_NUM];
+       u8      antsel_c[ODM_ASSOCIATE_ENTRY_NUM];
+       u32     MainAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM];
+       u32     AuxAnt_Sum[ODM_ASSOCIATE_ENTRY_NUM];
+       u32     MainAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM];
+       u32     AuxAnt_Cnt[ODM_ASSOCIATE_ENTRY_NUM];
+       u8      RxIdleAnt;
+       bool    bBecomeLinked;
+};
+
+enum fat_state {
+       FAT_NORMAL_STATE                = 0,
+       FAT_TRAINING_STATE              = 1,
+};
+
+enum ant_dif_type {
+       NO_ANTDIV                       = 0xFF,
+       CG_TRX_HW_ANTDIV                = 0x01,
+       CGCS_RX_HW_ANTDIV               = 0x02,
+       FIXED_HW_ANTDIV                 = 0x03,
+       CG_TRX_SMART_ANTDIV             = 0x04,
+       CGCS_RX_SW_ANTDIV               = 0x05,
+};
+
+/*  2011/09/22 MH Copy from SD4 defined structure. We use to support PHY DM integration. */
+struct dm_odm_t {
+       /* struct timer_list FastAntTrainingTimer; */
+       /*  */
+       /*      Add for different team use temporarily */
+       /*  */
+       struct rtw_adapter      *Adapter;               /*  For CE/NIC team */
+       struct rtl8723a_priv    *priv;                  /*  For AP/ADSL team */
+       /*  WHen you use Adapter or priv pointer, you must make sure the pointer is ready. */
+       bool                    odm_ready;
+
+       struct rtl8723a_priv fake_priv;
+
+       u64                     DebugComponents;
+       u32                     DebugLevel;
+
+/*  ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */
+       bool                    bCckHighPower;
+       u8                      RFPathRxEnable;         /*  ODM_CMNINFO_RFPATH_ENABLE */
+       u8                      ControlChannel;
+/*  ODM HANDLE, DRIVER NEEDS NOT TO HOOK------ */
+
+/* 1  COMMON INFORMATION */
+
+       /*  Init Value */
+/* HOOK BEFORE REG INIT----------- */
+       /*  ODM Support Ability DIG/RATR/TX_PWR_TRACK/ ¡K¡K = 1/2/3/¡K */
+       u32                     SupportAbility;
+       /*  ODM PCIE/USB/SDIO/GSPI = 0/1/2/3 */
+       u8                      SupportInterface;
+       /*  ODM composite or independent. Bit oriented/ 92C+92D+ .... or any other type = 1/2/3/... */
+       u32                     SupportICType;
+       /*  Cut Version TestChip/A-cut/B-cut... = 0/1/2/3/... */
+       u8                      CutVersion;
+       /*  Fab Version TSMC/UMC = 0/1 */
+       u8                      FabVersion;
+       /*  RF Type 4T4R/3T3R/2T2R/1T2R/1T1R/... */
+       u8                      RFType;
+       /*  Board Type Normal/HighPower/MiniCard/SLIM/Combo/... = 0/1/2/3/4/... */
+       u8                      BoardType;
+       /*  with external LNA  NO/Yes = 0/1 */
+       u8                      ExtLNA;
+       /*  with external PA  NO/Yes = 0/1 */
+       u8                      ExtPA;
+       /*  with external TRSW  NO/Yes = 0/1 */
+       u8                      ExtTRSW;
+       u8                      PatchID; /* Customer ID */
+       bool                    bInHctTest;
+       bool                    bWIFITest;
+
+       bool                    bDualMacSmartConcurrent;
+       u32                     BK_SupportAbility;
+       u8                      AntDivType;
+/* HOOK BEFORE REG INIT----------- */
+
+       /*  */
+       /*  Dynamic Value */
+       /*  */
+/*  POINTER REFERENCE----------- */
+
+       u8                      u8_temp;
+       bool                    bool_temp;
+       struct rtw_adapter      *PADAPTER_temp;
+
+       /*  MAC PHY Mode SMSP/DMSP/DMDP = 0/1/2 */
+       u8                      *pMacPhyMode;
+       /* TX Unicast byte count */
+       u64                     *pNumTxBytesUnicast;
+       /* RX Unicast byte count */
+       u64                     *pNumRxBytesUnicast;
+       /*  Wireless mode B/G/A/N = BIT0/BIT1/BIT2/BIT3 */
+       u8                      *pWirelessMode; /* enum odm_wireless_mode */
+       /*  Frequence band 2.4G/5G = 0/1 */
+       u8                      *pBandType;
+       /*  Secondary channel offset don't_care/below/above = 0/1/2 */
+       u8                      *pSecChOffset;
+       /*  Security mode Open/WEP/AES/TKIP = 0/1/2/3 */
+       u8                      *pSecurity;
+       /*  BW info 20M/40M/80M = 0/1/2 */
+       u8                      *pBandWidth;
+       /*  Central channel location Ch1/Ch2/.... */
+       u8                      *pChannel;      /* central channel number */
+       /*  Common info for 92D DMSP */
+
+       bool                    *pbGetValueFromOtherMac;
+       struct rtw_adapter      **pBuddyAdapter;
+       bool                    *pbMasterOfDMSP; /* MAC0: master, MAC1: slave */
+       /*  Common info for Status */
+       bool                    *pbScanInProcess;
+       bool                    *pbPowerSaving;
+       /*  CCA Path 2-path/path-A/path-B = 0/1/2; using enum odm_cca_path. */
+       u8                      *pOnePathCCA;
+       /* pMgntInfo->AntennaTest */
+       u8                      *pAntennaTest;
+       bool                    *pbNet_closed;
+/*  POINTER REFERENCE----------- */
+       /*  */
+/* CALL BY VALUE------------- */
+       bool                    bWIFI_Direct;
+       bool                    bWIFI_Display;
+       bool                    bLinked;
+       u8                      RSSI_Min;
+       u8                      InterfaceIndex; /*  Add for 92D  dual MAC: 0--Mac0 1--Mac1 */
+       bool            bIsMPChip;
+       bool                    bOneEntryOnly;
+       /*  Common info for BTDM */
+       bool                    bBtDisabled;                    /*  BT is disabled */
+       bool                    bBtHsOperation;         /*  BT HS mode is under progress */
+       u8                      btHsDigVal;                     /*  use BT rssi to decide the DIG value */
+       bool                    bBtDisableEdcaTurbo;    /*  Under some condition, don't enable the EDCA Turbo */
+       bool                    bBtBusy;                        /*  BT is busy. */
+/* CALL BY VALUE------------- */
+
+       /* 2 Define STA info. */
+       /*  _ODM_STA_INFO */
+       /*  2012/01/12 MH For MP, we need to reduce one array pointer for default port.?? */
+       struct sta_info *               pODM_StaInfo[ODM_ASSOCIATE_ENTRY_NUM];
+
+       /*  */
+       /*  2012/02/14 MH Add to share 88E ra with other SW team. */
+       /*  We need to colelct all support abilit to a proper area. */
+       /*  */
+       bool                            RaSupport88E;
+
+       /*  Define ........... */
+
+       /*  Latest packet phy info (ODM write) */
+       struct odm_phy_dbg_info  PhyDbgInfo;
+       /* PHY_INFO_88E         PhyInfo; */
+
+       /*  Latest packet phy info (ODM write) */
+       struct odm_mac_info             *pMacInfo;
+       /* MAC_INFO_88E         MacInfo; */
+
+       /*  Different Team independt structure?? */
+
+       /*  */
+       /* TX_RTP_CMN           TX_retrpo; */
+       /* TX_RTP_88E           TX_retrpo; */
+       /* TX_RTP_8195          TX_retrpo; */
+
+       /*  */
+       /* ODM Structure */
+       /*  */
+       struct odm_fat_t                DM_FatTable;
+       struct dig_t    DM_DigTable;
+       struct dynamic_pwr_sav          DM_PSTable;
+       struct pri_cca  DM_PriCCA;
+       struct rx_hp            DM_RXHP_Table;
+       struct false_alarm_stats        FalseAlmCnt;
+       struct false_alarm_stats        FlaseAlmCntBuddyAdapter;
+       struct sw_ant_sw                DM_SWAT_Table;
+       bool            RSSI_test;
+
+       struct edca_turbo               DM_EDCA_Table;
+       u32             WMMEDCA_BE;
+       /*  Copy from SD4 structure */
+       /*  */
+       /*  ================================================== */
+       /*  */
+
+       /* common */
+       bool                    *pbDriverStopped;
+       bool                    *pbDriverIsGoingToPnpSetPowerSleep;
+       bool                    *pinit_adpt_in_progress;
+
+       /* PSD */
+       bool                    bUserAssignLevel;
+       struct timer_list       PSDTimer;
+       u8                      RSSI_BT;                        /* come from BT */
+       bool                    bPSDinProcess;
+       bool                    bDMInitialGainEnable;
+
+       /* for rate adaptive, in fact,  88c/92c fw will handle this */
+       u8                      bUseRAMask;
+
+       struct odm_rate_adapt   RateAdaptive;
+
+
+       struct odm_rf_cal_t     RFCalibrateInfo;
+
+       /*  */
+       /*  TX power tracking */
+       /*  */
+       u8                      BbSwingIdxOfdm;
+       u8                      BbSwingIdxOfdmCurrent;
+       u8                      BbSwingIdxOfdmBase;
+       bool                    BbSwingFlagOfdm;
+       u8                      BbSwingIdxCck;
+       u8                      BbSwingIdxCckCurrent;
+       u8                      BbSwingIdxCckBase;
+       bool                    BbSwingFlagCck;
+       /*  */
+       /*  ODM system resource. */
+       /*  */
+
+       /*  ODM relative time. */
+       struct timer_list PathDivSwitchTimer;
+       /* 2011.09.27 add for Path Diversity */
+       struct timer_list CCKPathDiversityTimer;
+       struct timer_list FastAntTrainingTimer;
+
+       /*  ODM relative workitem. */
+};     /*  DM_Dynamic_Mechanism_Structure */
+
+enum odm_rf_content {
+       odm_radioa_txt = 0x1000,
+       odm_radiob_txt = 0x1001,
+       odm_radioc_txt = 0x1002,
+       odm_radiod_txt = 0x1003
+};
+
+enum odm_bb_config_type {
+    CONFIG_BB_PHY_REG,
+    CONFIG_BB_AGC_TAB,
+    CONFIG_BB_AGC_TAB_2G,
+    CONFIG_BB_AGC_TAB_5G,
+    CONFIG_BB_PHY_REG_PG,
+};
+
+/*  Status code */
+enum rt_status {
+       RT_STATUS_SUCCESS,
+       RT_STATUS_FAILURE,
+       RT_STATUS_PENDING,
+       RT_STATUS_RESOURCE,
+       RT_STATUS_INVALID_CONTEXT,
+       RT_STATUS_INVALID_PARAMETER,
+       RT_STATUS_NOT_SUPPORT,
+       RT_STATUS_OS_API_FAILED,
+};
+
+/* include "odm_function.h" */
+
+/* 3=========================================================== */
+/* 3 DIG */
+/* 3=========================================================== */
+
+enum dm_dig_op {
+       DIG_TYPE_THRESH_HIGH    = 0,
+       DIG_TYPE_THRESH_LOW     = 1,
+       DIG_TYPE_BACKOFF                = 2,
+       DIG_TYPE_RX_GAIN_MIN    = 3,
+       DIG_TYPE_RX_GAIN_MAX    = 4,
+       DIG_TYPE_ENABLE                 = 5,
+       DIG_TYPE_DISABLE                = 6,
+       DIG_OP_TYPE_MAX
+};
+
+#define                DM_DIG_THRESH_HIGH                      40
+#define                DM_DIG_THRESH_LOW                       35
+
+#define                DM_SCAN_RSSI_TH                         0x14 /* scan return issue for LC */
+
+
+#define                DM_FALSEALARM_THRESH_LOW        400
+#define                DM_FALSEALARM_THRESH_HIGH       1000
+
+#define                DM_DIG_MAX_NIC                          0x4e
+#define                DM_DIG_MIN_NIC                          0x1e
+
+#define                DM_DIG_MAX_AP                           0x32
+#define                DM_DIG_MIN_AP                           0x20
+
+#define                DM_DIG_MAX_NIC_HP                       0x46
+#define                DM_DIG_MIN_NIC_HP                       0x2e
+
+#define                DM_DIG_MAX_AP_HP                                0x42
+#define                DM_DIG_MIN_AP_HP                                0x30
+
+/* vivi 92c&92d has different definition, 20110504 */
+/* this is for 92c */
+#define                DM_DIG_FA_TH0                           0x200
+#define                DM_DIG_FA_TH1                           0x300
+#define                DM_DIG_FA_TH2                           0x400
+/* this is for 92d */
+#define                DM_DIG_FA_TH0_92D                       0x100
+#define                DM_DIG_FA_TH1_92D                       0x400
+#define                DM_DIG_FA_TH2_92D                       0x600
+
+#define                DM_DIG_BACKOFF_MAX                      12
+#define                DM_DIG_BACKOFF_MIN                      -4
+#define                DM_DIG_BACKOFF_DEFAULT          10
+
+/* 3=========================================================== */
+/* 3 AGC RX High Power Mode */
+/* 3=========================================================== */
+#define          LNA_Low_Gain_1                      0x64
+#define          LNA_Low_Gain_2                      0x5A
+#define          LNA_Low_Gain_3                      0x58
+
+#define          FA_RXHP_TH1                           5000
+#define          FA_RXHP_TH2                           1500
+#define          FA_RXHP_TH3                             800
+#define          FA_RXHP_TH4                             600
+#define          FA_RXHP_TH5                             500
+
+/* 3=========================================================== */
+/* 3 EDCA */
+/* 3=========================================================== */
+
+/* 3=========================================================== */
+/* 3 Dynamic Tx Power */
+/* 3=========================================================== */
+/* Dynamic Tx Power Control Threshold */
+#define                TX_POWER_NEAR_FIELD_THRESH_LVL2 74
+#define                TX_POWER_NEAR_FIELD_THRESH_LVL1 67
+#define                TX_POWER_NEAR_FIELD_THRESH_AP           0x3F
+
+#define                TxHighPwrLevel_Normal           0
+#define                TxHighPwrLevel_Level1           1
+#define                TxHighPwrLevel_Level2           2
+#define                TxHighPwrLevel_BT1                      3
+#define                TxHighPwrLevel_BT2                      4
+#define                TxHighPwrLevel_15                       5
+#define                TxHighPwrLevel_35                       6
+#define                TxHighPwrLevel_50                       7
+#define                TxHighPwrLevel_70                       8
+#define                TxHighPwrLevel_100                      9
+
+/* 3=========================================================== */
+/* 3 Rate Adaptive */
+/* 3=========================================================== */
+#define                DM_RATR_STA_INIT                        0
+#define                DM_RATR_STA_HIGH                        1
+#define                        DM_RATR_STA_MIDDLE              2
+#define                        DM_RATR_STA_LOW                 3
+
+/* 3=========================================================== */
+/* 3 BB Power Save */
+/* 3=========================================================== */
+
+
+enum dm_1r_cca {
+       CCA_1R =0,
+       CCA_2R = 1,
+       CCA_MAX = 2,
+};
+
+enum dm_rf_def {
+       RF_Save =0,
+       RF_Normal = 1,
+       RF_MAX = 2,
+};
+
+/* 3=========================================================== */
+/* 3 Antenna Diversity */
+/* 3=========================================================== */
+enum dm_swas {
+       Antenna_A = 1,
+       Antenna_B = 2,
+       Antenna_MAX = 3,
+};
+
+/*  Maximal number of antenna detection mechanism needs to perform, added by Roger, 2011.12.28. */
+#define        MAX_ANTENNA_DETECTION_CNT       10
+
+/*  */
+/*  Extern Global Variables. */
+/*  */
+#define        OFDM_TABLE_SIZE_92C     37
+#define        OFDM_TABLE_SIZE_92D     43
+#define        CCK_TABLE_SIZE          33
+
+extern u32 OFDMSwingTable23A[OFDM_TABLE_SIZE_92D];
+extern u8 CCKSwingTable_Ch1_Ch1323A[CCK_TABLE_SIZE][8];
+extern u8 CCKSwingTable_Ch1423A [CCK_TABLE_SIZE][8];
+
+
+
+/*  */
+/*  check Sta pointer valid or not */
+/*  */
+#define IS_STA_VALID(pSta)             (pSta)
+/*  20100514 Joseph: Add definition for antenna switching test after link. */
+/*  This indicates two different the steps. */
+/*  In SWAW_STEP_PEAK, driver needs to switch antenna and listen to the signal on the air. */
+/*  In SWAW_STEP_DETERMINE, driver just compares the signal captured in SWAW_STEP_PEAK */
+/*  with original RSSI to determine if it is necessary to switch antenna. */
+#define SWAW_STEP_PEAK         0
+#define SWAW_STEP_DETERMINE    1
+
+void ODM_Write_DIG23a(struct dm_odm_t *pDM_Odm,        u8      CurrentIGI);
+void ODM_Write_CCK_CCA_Thres23a(struct dm_odm_t *pDM_Odm, u8   CurCCK_CCAThres);
+
+void ODM_SetAntenna(struct dm_odm_t *pDM_Odm, u8 Antenna);
+
+
+#define dm_RF_Saving   ODM_RF_Saving23a
+void ODM_RF_Saving23a(struct dm_odm_t *pDM_Odm, u8 bForceInNormal);
+
+#define SwAntDivRestAfterLink  ODM_SwAntDivRestAfterLink
+void ODM_SwAntDivRestAfterLink(struct dm_odm_t *pDM_Odm);
+
+#define dm_CheckTXPowerTracking                ODM_TXPowerTrackingCheck23a
+void ODM_TXPowerTrackingCheck23a(struct dm_odm_t *pDM_Odm);
+
+bool ODM_RAStateCheck23a(struct dm_odm_t *pDM_Odm, s32 RSSI, bool bForceUpdate,
+                     u8 *pRATRState);
+
+
+#define dm_SWAW_RSSI_Check     ODM_SwAntDivChkPerPktRssi
+void ODM_SwAntDivChkPerPktRssi(struct dm_odm_t *pDM_Odm, u8 StationID,
+                              struct odm_phy_info *pPhyInfo);
+
+u32 ConvertTo_dB23a(u32 Value);
+
+u32 GetPSDData(struct dm_odm_t *pDM_Odm, unsigned int point, u8 initial_gain_psd);
+
+void odm_DIG23abyRSSI_LPS(struct dm_odm_t *pDM_Odm);
+
+u32 ODM_Get_Rate_Bitmap23a(struct dm_odm_t *pDM_Odm, u32 macid, u32 ra_mask, u8 rssi_level);
+
+
+void ODM23a_DMInit(struct dm_odm_t *pDM_Odm);
+
+void ODM_DMWatchdog23a(struct dm_odm_t *pDM_Odm); /*  For common use in the future */
+
+void ODM_CmnInfoInit23a(struct dm_odm_t *pDM_Odm, enum odm_cmninfo     CmnInfo, u32 Value);
+
+void ODM23a_CmnInfoHook(struct dm_odm_t *pDM_Odm, enum odm_cmninfo     CmnInfo, void *pValue);
+
+void ODM_CmnInfoPtrArrayHook23a(struct dm_odm_t *pDM_Odm, enum odm_cmninfo     CmnInfo, u16 Index, void *pValue);
+
+void ODM_CmnInfoUpdate23a(struct dm_odm_t *pDM_Odm, u32 CmnInfo, u64 Value);
+
+void ODM_InitAllTimers(struct dm_odm_t *pDM_Odm);
+
+void ODM_CancelAllTimers(struct dm_odm_t *pDM_Odm);
+
+void ODM_ReleaseAllTimers(struct dm_odm_t *pDM_Odm);
+
+void ODM_ResetIQKResult(struct dm_odm_t *pDM_Odm);
+
+void ODM_AntselStatistics_88C(struct dm_odm_t *pDM_Odm, u8 MacId, u32 PWDBAll, bool isCCKrate);
+
+void ODM_SingleDualAntennaDefaultSetting(struct dm_odm_t *pDM_Odm);
+
+bool ODM_SingleDualAntennaDetection(struct dm_odm_t *pDM_Odm, u8 mode);
+
+void odm_dtc(struct dm_odm_t *pDM_Odm);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/odm_HWConfig.h b/drivers/staging/rtl8723au/include/odm_HWConfig.h
new file mode 100644 (file)
index 0000000..147855c
--- /dev/null
@@ -0,0 +1,174 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+
+#ifndef        __HALHWOUTSRC_H__
+#define __HALHWOUTSRC_H__
+
+#include <Hal8723APhyCfg.h>
+
+/*  */
+/*  Definition */
+/*  */
+/*  */
+/*  */
+/*  CCK Rates, TxHT = 0 */
+#define DESC92C_RATE1M                                 0x00
+#define DESC92C_RATE2M                                 0x01
+#define DESC92C_RATE5_5M                               0x02
+#define DESC92C_RATE11M                                0x03
+
+/*  OFDM Rates, TxHT = 0 */
+#define DESC92C_RATE6M                                 0x04
+#define DESC92C_RATE9M                                 0x05
+#define DESC92C_RATE12M                                0x06
+#define DESC92C_RATE18M                                0x07
+#define DESC92C_RATE24M                                0x08
+#define DESC92C_RATE36M                                0x09
+#define DESC92C_RATE48M                                0x0a
+#define DESC92C_RATE54M                                0x0b
+
+/*  MCS Rates, TxHT = 1 */
+#define DESC92C_RATEMCS0                               0x0c
+#define DESC92C_RATEMCS1                               0x0d
+#define DESC92C_RATEMCS2                               0x0e
+#define DESC92C_RATEMCS3                               0x0f
+#define DESC92C_RATEMCS4                               0x10
+#define DESC92C_RATEMCS5                               0x11
+#define DESC92C_RATEMCS6                               0x12
+#define DESC92C_RATEMCS7                               0x13
+#define DESC92C_RATEMCS8                               0x14
+#define DESC92C_RATEMCS9                               0x15
+#define DESC92C_RATEMCS10                              0x16
+#define DESC92C_RATEMCS11                              0x17
+#define DESC92C_RATEMCS12                              0x18
+#define DESC92C_RATEMCS13                              0x19
+#define DESC92C_RATEMCS14                              0x1a
+#define DESC92C_RATEMCS15                              0x1b
+#define DESC92C_RATEMCS15_SG                   0x1c
+#define DESC92C_RATEMCS32                              0x20
+
+
+/*  */
+/*  structure and define */
+/*  */
+
+struct phy_rx_agc_info {
+       #ifdef __LITTLE_ENDIAN
+               u8      gain:7,trsw:1;
+       #else
+               u8      trsw:1,gain:7;
+       #endif
+};
+
+struct phy_status_rpt {
+       struct phy_rx_agc_info path_agc[RF_PATH_MAX];
+       u8      ch_corr[RF_PATH_MAX];
+       u8      cck_sig_qual_ofdm_pwdb_all;
+       u8      cck_agc_rpt_ofdm_cfosho_a;
+       u8      cck_rpt_b_ofdm_cfosho_b;
+       u8      rsvd_1;/* ch_corr_msb; */
+       u8      noise_power_db_msb;
+       u8      path_cfotail[RF_PATH_MAX];
+       u8      pcts_mask[RF_PATH_MAX];
+       s8      stream_rxevm[RF_PATH_MAX];
+       u8      path_rxsnr[RF_PATH_MAX];
+       u8      noise_power_db_lsb;
+       u8      rsvd_2[3];
+       u8      stream_csi[RF_PATH_MAX];
+       u8      stream_target_csi[RF_PATH_MAX];
+       s8      sig_evm;
+       u8      rsvd_3;
+
+#ifdef __LITTLE_ENDIAN
+       u8      antsel_rx_keep_2:1;     /* ex_intf_flg:1; */
+       u8      sgi_en:1;
+       u8      rxsc:2;
+       u8      idle_long:1;
+       u8      r_ant_train_en:1;
+       u8      ant_sel_b:1;
+       u8      ant_sel:1;
+#else  /*  _BIG_ENDIAN_ */
+       u8      ant_sel:1;
+       u8      ant_sel_b:1;
+       u8      r_ant_train_en:1;
+       u8      idle_long:1;
+       u8      rxsc:2;
+       u8      sgi_en:1;
+       u8      antsel_rx_keep_2:1;     /* ex_intf_flg:1; */
+#endif
+};
+
+
+struct phy_status_rpt_8195 {
+       struct phy_rx_agc_info path_agc[2];
+       u8      ch_num[2];
+       u8      cck_sig_qual_ofdm_pwdb_all;
+       u8      cck_agc_rpt_ofdm_cfosho_a;
+       u8      cck_bb_pwr_ofdm_cfosho_b;
+       u8    cck_rx_path;      /* CCK_RX_PATH [3:0] (with regA07[3:0] definition) */
+       u8      rsvd_1;
+       u8      path_cfotail[2];
+       u8      pcts_mask[2];
+       s8      stream_rxevm[2];
+       u8      path_rxsnr[2];
+       u8      rsvd_2[2];
+       u8      stream_snr[2];
+       u8      stream_csi[2];
+       u8      rsvd_3[2];
+       s8      sig_evm;
+       u8      rsvd_4;
+#ifdef __LITTLE_ENDIAN
+       u8      antidx_anta:3;
+       u8      antidx_antb:3;
+       u8      rsvd_5:2;
+#else  /*  _BIG_ENDIAN_ */
+       u8      rsvd_5:2;
+       u8      antidx_antb:3;
+       u8      antidx_anta:3;
+#endif
+};
+
+
+void odm_Init_RSSIForDM23a(struct dm_odm_t *pDM_Odm);
+
+void
+ODM_PhyStatusQuery23a(
+       struct dm_odm_t *pDM_Odm,
+       struct odm_phy_info *pPhyInfo,
+       u8 *                                            pPhyStatus,
+       struct odm_packet_info *pPktinfo
+       );
+
+void ODM_MacStatusQuery23a(struct dm_odm_t *pDM_Odm,
+       u8 *pMacStatus,
+       u8 MacID,
+       bool bPacketMatchBSSID,
+       bool bPacketToSelf,
+       bool bPacketBeacon
+);
+
+enum hal_status ODM_ConfigRFWithHeaderFile23a(struct dm_odm_t *pDM_Odm,
+       enum RF_RADIO_PATH      Content,
+       enum RF_RADIO_PATH      eRFPath
+);
+
+enum hal_status ODM_ConfigBBWithHeaderFile23a(struct dm_odm_t *pDM_Odm,
+       enum odm_bb_config_type         ConfigType
+);
+
+enum hal_status ODM_ConfigMACWithHeaderFile23a(struct dm_odm_t *pDM_Odm);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/odm_RegConfig8723A.h b/drivers/staging/rtl8723au/include/odm_RegConfig8723A.h
new file mode 100644 (file)
index 0000000..4ea579b
--- /dev/null
@@ -0,0 +1,34 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __INC_ODM_REGCONFIG_H_8723A
+#define __INC_ODM_REGCONFIG_H_8723A
+
+void odm_ConfigRFReg_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data,
+                          enum RF_RADIO_PATH RF_PATH, u32 RegAddr);
+
+void odm_ConfigRF_RadioA_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data);
+
+void odm_ConfigRF_RadioB_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Data);
+
+void odm_ConfigMAC_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u8 Data);
+
+void odm_ConfigBB_AGC_8723A(struct dm_odm_t *pDM_Odm, u32 Addr,
+                           u32 Bitmask, u32 Data);
+
+void odm_ConfigBB_PHY_REG_PG_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data);
+
+void odm_ConfigBB_PHY_8723A(struct dm_odm_t *pDM_Odm, u32 Addr, u32 Bitmask, u32 Data);
+
+#endif /*  end of SUPPORT */
diff --git a/drivers/staging/rtl8723au/include/odm_RegDefine11AC.h b/drivers/staging/rtl8723au/include/odm_RegDefine11AC.h
new file mode 100644 (file)
index 0000000..77b7ace
--- /dev/null
@@ -0,0 +1,49 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+#ifndef        __ODM_REGDEFINE11AC_H__
+#define __ODM_REGDEFINE11AC_H__
+
+/* 2 RF REG LIST */
+
+
+
+/* 2 BB REG LIST */
+/* PAGE 8 */
+/* PAGE 9 */
+#define        ODM_REG_OFDM_FA_RST_11AC                0x9A4
+/* PAGE A */
+#define        ODM_REG_CCK_CCA_11AC                            0xA0A
+#define        ODM_REG_CCK_FA_RST_11AC                 0xA2C
+#define        ODM_REG_CCK_FA_11AC                             0xA5C
+/* PAGE C */
+#define        ODM_REG_IGI_A_11AC                              0xC50
+/* PAGE E */
+#define        ODM_REG_IGI_B_11AC                              0xE50
+/* PAGE F */
+#define        ODM_REG_OFDM_FA_11AC                    0xF48
+
+
+/* 2 MAC REG LIST */
+
+
+
+
+/* DIG Related */
+#define        ODM_BIT_IGI_11AC                                0xFFFFFFFF
+
+
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/odm_RegDefine11N.h b/drivers/staging/rtl8723au/include/odm_RegDefine11N.h
new file mode 100644 (file)
index 0000000..2778215
--- /dev/null
@@ -0,0 +1,165 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+#ifndef        __ODM_REGDEFINE11N_H__
+#define __ODM_REGDEFINE11N_H__
+
+
+/* 2 RF REG LIST */
+#define        ODM_REG_RF_MODE_11N                     0x00
+#define        ODM_REG_RF_0B_11N                       0x0B
+#define        ODM_REG_CHNBW_11N                       0x18
+#define        ODM_REG_T_METER_11N                     0x24
+#define        ODM_REG_RF_25_11N                       0x25
+#define        ODM_REG_RF_26_11N                       0x26
+#define        ODM_REG_RF_27_11N                       0x27
+#define        ODM_REG_RF_2B_11N                       0x2B
+#define        ODM_REG_RF_2C_11N                       0x2C
+#define        ODM_REG_RXRF_A3_11N                     0x3C
+#define        ODM_REG_T_METER_92D_11N                 0x42
+#define        ODM_REG_T_METER_88E_11N                 0x42
+
+
+
+/* 2 BB REG LIST */
+/* PAGE 8 */
+#define        ODM_REG_BB_CTRL_11N                     0x800
+#define        ODM_REG_RF_PIN_11N                      0x804
+#define        ODM_REG_PSD_CTRL_11N                    0x808
+#define        ODM_REG_TX_ANT_CTRL_11N                 0x80C
+#define        ODM_REG_BB_PWR_SAV5_11N                 0x818
+#define        ODM_REG_CCK_RPT_FORMAT_11N              0x824
+#define        ODM_REG_RX_DEFUALT_A_11N                0x858
+#define        ODM_REG_RX_DEFUALT_B_11N                0x85A
+#define        ODM_REG_BB_PWR_SAV3_11N                 0x85C
+#define        ODM_REG_ANTSEL_CTRL_11N                 0x860
+#define        ODM_REG_RX_ANT_CTRL_11N                 0x864
+#define        ODM_REG_PIN_CTRL_11N                    0x870
+#define        ODM_REG_BB_PWR_SAV1_11N                 0x874
+#define        ODM_REG_ANTSEL_PATH_11N                 0x878
+#define        ODM_REG_BB_3WIRE_11N                    0x88C
+#define        ODM_REG_SC_CNT_11N                      0x8C4
+#define        ODM_REG_PSD_DATA_11N                    0x8B4
+/* PAGE 9 */
+#define        ODM_REG_ANT_MAPPING1_11N                0x914
+#define        ODM_REG_ANT_MAPPING2_11N                0x918
+/* PAGE A */
+#define        ODM_REG_CCK_ANTDIV_PARA1_11N            0xA00
+#define        ODM_REG_CCK_CCA_11N                     0xA0A
+#define        ODM_REG_CCK_ANTDIV_PARA2_11N            0xA0C
+#define        ODM_REG_CCK_ANTDIV_PARA3_11N            0xA10
+#define        ODM_REG_CCK_ANTDIV_PARA4_11N            0xA14
+#define        ODM_REG_CCK_FILTER_PARA1_11N            0xA22
+#define        ODM_REG_CCK_FILTER_PARA2_11N            0xA23
+#define        ODM_REG_CCK_FILTER_PARA3_11N            0xA24
+#define        ODM_REG_CCK_FILTER_PARA4_11N            0xA25
+#define        ODM_REG_CCK_FILTER_PARA5_11N            0xA26
+#define        ODM_REG_CCK_FILTER_PARA6_11N            0xA27
+#define        ODM_REG_CCK_FILTER_PARA7_11N            0xA28
+#define        ODM_REG_CCK_FILTER_PARA8_11N            0xA29
+#define        ODM_REG_CCK_FA_RST_11N                  0xA2C
+#define        ODM_REG_CCK_FA_MSB_11N                  0xA58
+#define        ODM_REG_CCK_FA_LSB_11N                  0xA5C
+#define        ODM_REG_CCK_CCA_CNT_11N                 0xA60
+#define        ODM_REG_BB_PWR_SAV4_11N                 0xA74
+/* PAGE B */
+#define        ODM_REG_LNA_SWITCH_11N                  0xB2C
+#define        ODM_REG_PATH_SWITCH_11N                 0xB30
+#define        ODM_REG_RSSI_CTRL_11N                   0xB38
+#define        ODM_REG_CONFIG_ANTA_11N                 0xB68
+#define        ODM_REG_RSSI_BT_11N                     0xB9C
+/* PAGE C */
+#define        ODM_REG_OFDM_FA_HOLDC_11N               0xC00
+#define        ODM_REG_RX_PATH_11N                     0xC04
+#define        ODM_REG_TRMUX_11N                       0xC08
+#define        ODM_REG_OFDM_FA_RSTC_11N                0xC0C
+#define        ODM_REG_RXIQI_MATRIX_11N                0xC14
+#define        ODM_REG_TXIQK_MATRIX_LSB1_11N           0xC4C
+#define        ODM_REG_IGI_A_11N                       0xC50
+#define        ODM_REG_ANTDIV_PARA2_11N                0xC54
+#define        ODM_REG_IGI_B_11N                       0xC58
+#define        ODM_REG_ANTDIV_PARA3_11N                0xC5C
+#define        ODM_REG_BB_PWR_SAV2_11N                 0xC70
+#define        ODM_REG_RX_OFF_11N                      0xC7C
+#define        ODM_REG_TXIQK_MATRIXA_11N               0xC80
+#define        ODM_REG_TXIQK_MATRIXB_11N               0xC88
+#define        ODM_REG_TXIQK_MATRIXA_LSB2_11N          0xC94
+#define        ODM_REG_TXIQK_MATRIXB_LSB2_11N          0xC9C
+#define        ODM_REG_RXIQK_MATRIX_LSB_11N            0xCA0
+#define        ODM_REG_ANTDIV_PARA1_11N                0xCA4
+#define        ODM_REG_OFDM_FA_TYPE1_11N               0xCF0
+/* PAGE D */
+#define        ODM_REG_OFDM_FA_RSTD_11N                0xD00
+#define        ODM_REG_OFDM_FA_TYPE2_11N               0xDA0
+#define        ODM_REG_OFDM_FA_TYPE3_11N               0xDA4
+#define        ODM_REG_OFDM_FA_TYPE4_11N               0xDA8
+/* PAGE E */
+#define        ODM_REG_TXAGC_A_6_18_11N                0xE00
+#define        ODM_REG_TXAGC_A_24_54_11N               0xE04
+#define        ODM_REG_TXAGC_A_1_MCS32_11N             0xE08
+#define        ODM_REG_TXAGC_A_MCS0_3_11N              0xE10
+#define        ODM_REG_TXAGC_A_MCS4_7_11N              0xE14
+#define        ODM_REG_TXAGC_A_MCS8_11_11N             0xE18
+#define        ODM_REG_TXAGC_A_MCS12_15_11N            0xE1C
+#define        ODM_REG_FPGA0_IQK_11N                   0xE28
+#define        ODM_REG_TXIQK_TONE_A_11N                0xE30
+#define        ODM_REG_RXIQK_TONE_A_11N                0xE34
+#define        ODM_REG_TXIQK_PI_A_11N                  0xE38
+#define        ODM_REG_RXIQK_PI_A_11N                  0xE3C
+#define        ODM_REG_TXIQK_11N                       0xE40
+#define        ODM_REG_RXIQK_11N                       0xE44
+#define        ODM_REG_IQK_AGC_PTS_11N                 0xE48
+#define        ODM_REG_IQK_AGC_RSP_11N                 0xE4C
+#define        ODM_REG_BLUETOOTH_11N                   0xE6C
+#define        ODM_REG_RX_WAIT_CCA_11N                 0xE70
+#define        ODM_REG_TX_CCK_RFON_11N                 0xE74
+#define        ODM_REG_TX_CCK_BBON_11N                 0xE78
+#define        ODM_REG_OFDM_RFON_11N                   0xE7C
+#define        ODM_REG_OFDM_BBON_11N                   0xE80
+#define ODM_REG_TX2RX_11N                      0xE84
+#define        ODM_REG_TX2TX_11N                       0xE88
+#define        ODM_REG_RX_CCK_11N                      0xE8C
+#define        ODM_REG_RX_OFDM_11N                     0xED0
+#define        ODM_REG_RX_WAIT_RIFS_11N                0xED4
+#define        ODM_REG_RX2RX_11N                       0xED8
+#define        ODM_REG_STANDBY_11N                     0xEDC
+#define        ODM_REG_SLEEP_11N                       0xEE0
+#define        ODM_REG_PMPD_ANAEN_11N                  0xEEC
+
+
+
+
+
+
+
+/* 2 MAC REG LIST */
+#define        ODM_REG_BB_RST_11N                      0x02
+#define        ODM_REG_ANTSEL_PIN_11N                  0x4C
+#define        ODM_REG_EARLY_MODE_11N                  0x4D0
+#define        ODM_REG_RSSI_MONITOR_11N                0x4FE
+#define        ODM_REG_EDCA_VO_11N                     0x500
+#define        ODM_REG_EDCA_VI_11N                     0x504
+#define        ODM_REG_EDCA_BE_11N                     0x508
+#define        ODM_REG_EDCA_BK_11N                     0x50C
+#define        ODM_REG_TXPAUSE_11N                     0x522
+#define        ODM_REG_RESP_TX_11N                     0x6D8
+#define        ODM_REG_ANT_TRAIN_PARA1_11N             0x7b0
+#define        ODM_REG_ANT_TRAIN_PARA2_11N             0x7b4
+
+
+/* DIG Related */
+#define        ODM_BIT_IGI_11N                         0x0000007F
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/odm_debug.h b/drivers/staging/rtl8723au/include/odm_debug.h
new file mode 100644 (file)
index 0000000..5bc51d0
--- /dev/null
@@ -0,0 +1,139 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+
+#ifndef        __ODM_DBG_H__
+#define __ODM_DBG_H__
+
+
+/*  */
+/*     Define the debug levels */
+/*  */
+/*     1.      DBG_TRACE and DBG_LOUD are used for normal cases. */
+/*     So that, they can help SW engineer to develope or trace states changed */
+/*     and also help HW enginner to trace every operation to and from HW, */
+/*     e.g IO, Tx, Rx. */
+/*  */
+/*     2.      DBG_WARNNING and DBG_SERIOUS are used for unusual or error cases, */
+/*     which help us to debug SW or HW. */
+/*  */
+/*  */
+/*  */
+/*     Never used in a call to ODM_RT_TRACE()! */
+/*  */
+#define ODM_DBG_OFF                                    1
+
+/*  */
+/*     Fatal bug. */
+/*     For example, Tx/Rx/IO locked up, OS hangs, memory access violation, */
+/*     resource allocation failed, unexpected HW behavior, HW BUG and so on. */
+/*  */
+#define ODM_DBG_SERIOUS                                2
+
+/*  */
+/*     Abnormal, rare, or unexpeted cases. */
+/*     For example, IRP/Packet/OID canceled, device suprisely unremoved and so on. */
+/*  */
+#define ODM_DBG_WARNING                                3
+
+/*  */
+/*     Normal case with useful information about current SW or HW state. */
+/*     For example, Tx/Rx descriptor to fill, Tx/Rx descriptor completed status, */
+/*     SW protocol state change, dynamic mechanism state change and so on. */
+/*  */
+#define ODM_DBG_LOUD                                   4
+
+/*  */
+/*     Normal case with detail execution flow or information. */
+/*  */
+#define ODM_DBG_TRACE                                  5
+
+/*  */
+/*  Define the tracing components */
+/*  */
+/*  */
+/* BB Functions */
+#define ODM_COMP_DIG                           BIT0
+#define ODM_COMP_RA_MASK                       BIT1
+#define ODM_COMP_DYNAMIC_TXPWR                 BIT2
+#define ODM_COMP_FA_CNT                                BIT3
+#define ODM_COMP_RSSI_MONITOR                  BIT4
+#define ODM_COMP_CCK_PD                                BIT5
+#define ODM_COMP_ANT_DIV                       BIT6
+#define ODM_COMP_PWR_SAVE                      BIT7
+#define ODM_COMP_PWR_TRAIN                     BIT8
+#define ODM_COMP_RATE_ADAPTIVE                 BIT9
+#define ODM_COMP_PATH_DIV                      BIT10
+#define ODM_COMP_PSD                           BIT11
+#define ODM_COMP_DYNAMIC_PRICCA                        BIT12
+#define ODM_COMP_RXHP                          BIT13
+/* MAC Functions */
+#define ODM_COMP_EDCA_TURBO                    BIT16
+#define ODM_COMP_EARLY_MODE                    BIT17
+/* RF Functions */
+#define ODM_COMP_TX_PWR_TRACK                  BIT24
+#define ODM_COMP_RX_GAIN_TRACK                 BIT25
+#define ODM_COMP_CALIBRATION                   BIT26
+/* Common Functions */
+#define ODM_COMP_COMMON                                BIT30
+#define ODM_COMP_INIT                          BIT31
+
+/*------------------------Export Macro Definition---------------------------*/
+       #define DbgPrint        printk
+       #define RT_PRINTK(fmt, args...) DbgPrint("%s(): " fmt, __func__, ## args);
+
+#ifndef ASSERT
+       #define ASSERT(expr)
+#endif
+
+#define ODM_RT_TRACE(pDM_Odm, comp, level, fmt)                                                        \
+               if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel))       \
+               {                                                                               \
+                       DbgPrint("[ODM-8723A] ");                                               \
+                       RT_PRINTK fmt;                                                          \
+               }
+
+#define ODM_RT_TRACE_F(pDM_Odm, comp, level, fmt)                                              \
+               if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel))       \
+               {                                                                               \
+                       RT_PRINTK fmt;                                                          \
+               }
+
+#define ODM_RT_ASSERT(pDM_Odm, expr, fmt)                                                      \
+               if(!(expr)) {                                                                   \
+                       DbgPrint("Assertion failed! %s at ......\n", #expr);                    \
+                       DbgPrint("      ......%s,%s,line=%d\n", __FILE__, __func__, __LINE__);\
+                       RT_PRINTK fmt;                                                          \
+                       ASSERT(false);                                                          \
+               }
+#define ODM_dbg_enter() { DbgPrint("==> %s\n", __func__); }
+#define ODM_dbg_exit() { DbgPrint("<== %s\n", __func__); }
+#define ODM_dbg_trace(str) { DbgPrint("%s:%s\n", __func__, str); }
+
+#define ODM_PRINT_ADDR(pDM_Odm, comp, level, title_str, ptr)                                           \
+                       if(((comp) & pDM_Odm->DebugComponents) && (level <= pDM_Odm->DebugLevel){       \
+                               int __i;                        \
+                               u8 *    __ptr = (u8 *)ptr;      \
+                               DbgPrint("[ODM] ");             \
+                               DbgPrint(title_str);            \
+                               DbgPrint(" ");                  \
+                               for (__i=0; __i < 6; __i++)     \
+                                       DbgPrint("%02X%s", __ptr[__i], (__i == 5) ? "" : "-");          \
+                               DbgPrint("\n");                 \
+                       }
+
+void ODM_InitDebugSetting23a(struct dm_odm_t *pDM_Odm);
+
+#endif /*  __ODM_DBG_H__ */
diff --git a/drivers/staging/rtl8723au/include/odm_interface.h b/drivers/staging/rtl8723au/include/odm_interface.h
new file mode 100644 (file)
index 0000000..f216b58
--- /dev/null
@@ -0,0 +1,131 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+
+#ifndef        __ODM_INTERFACE_H__
+#define __ODM_INTERFACE_H__
+
+
+
+/*  */
+/*  =========== Constant/Structure/Enum/... Define */
+/*  */
+
+
+
+/*  */
+/*  =========== Macro Define */
+/*  */
+
+#define _reg_all(_name)                        ODM_##_name
+#define _reg_ic(_name, _ic)            ODM_##_name##_ic
+#define _bit_all(_name)                        BIT_##_name
+#define _bit_ic(_name, _ic)            BIT_##_name##_ic
+
+/*  _cat: implemented by Token-Pasting Operator. */
+
+/*===================================
+
+#define ODM_REG_DIG_11N                0xC50
+#define ODM_REG_DIG_11AC       0xDDD
+
+ODM_REG(DIG,_pDM_Odm)
+=====================================*/
+
+#define _reg_11N(_name)                        ODM_REG_##_name##_11N
+#define _reg_11AC(_name)               ODM_REG_##_name##_11AC
+#define _bit_11N(_name)                        ODM_BIT_##_name##_11N
+#define _bit_11AC(_name)               ODM_BIT_##_name##_11AC
+
+#define _cat(_name, _ic_type, _func)                                                                   \
+       (                                                                                                                       \
+               ((_ic_type) & ODM_IC_11N_SERIES)? _func##_11N(_name):           \
+               _func##_11AC(_name)                                                                     \
+       )
+
+/*  _name: name of register or bit. */
+/*  Example: "ODM_REG(R_A_AGC_CORE1, pDM_Odm)" */
+/*         gets "ODM_R_A_AGC_CORE1" or "ODM_R_A_AGC_CORE1_8192C", depends on SupportICType. */
+#define ODM_REG(_name, _pDM_Odm)       _cat(_name, _pDM_Odm->SupportICType, _reg)
+#define ODM_BIT(_name, _pDM_Odm)       _cat(_name, _pDM_Odm->SupportICType, _bit)
+
+/*  */
+/*  2012/02/17 MH For non-MP compile pass only. Linux does not support workitem. */
+/*  Suggest HW team to use thread instead of workitem. Windows also support the feature. */
+/*  */
+typedef void (*RT_WORKITEM_CALL_BACK)(struct work_struct *pContext);
+
+/*  */
+/*  =========== Extern Variable ??? It should be forbidden. */
+/*  */
+
+
+/*  */
+/*  =========== EXtern Function Prototype */
+/*  */
+
+
+u8 ODM_Read1Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr);
+
+u16 ODM_Read2Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr);
+
+u32 ODM_Read4Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr);
+
+void ODM_Write1Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr, u8 Data);
+
+void ODM_Write2Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr, u16 Data);
+
+void ODM_Write4Byte(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 Data);
+
+void ODM_SetMACReg(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data);
+
+u32 ODM_GetMACReg(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 BitMask);
+
+void ODM_SetBBReg(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 BitMask, u32 Data);
+
+u32 ODM_GetBBReg(struct dm_odm_t *pDM_Odm, u32 RegAddr, u32 BitMask);
+
+void ODM_SetRFReg(struct dm_odm_t *pDM_Odm, enum RF_RADIO_PATH eRFPath,
+                 u32 RegAddr, u32 BitMask, u32 Data);
+
+u32 ODM_GetRFReg(struct dm_odm_t *pDM_Odm, enum RF_RADIO_PATH eRFPath,
+                u32 RegAddr, u32 BitMask);
+
+/*  Memory Relative Function. */
+void ODM_AllocateMemory(struct dm_odm_t *pDM_Odm, void **pPtr, u32 length);
+void ODM_FreeMemory(struct dm_odm_t *pDM_Odm, void *pPtr, u32 length);
+
+s32 ODM_CompareMemory(struct dm_odm_t *pDM_Odm, void *pBuf1, void *pBuf2, u32 length);
+
+/*  ODM MISC-spin lock relative API. */
+void ODM_AcquireSpinLock(struct dm_odm_t *pDM_Odm, enum rt_spinlock_type type);
+
+void ODM_ReleaseSpinLock(struct dm_odm_t *pDM_Odm, enum rt_spinlock_type type);
+
+/*  ODM MISC-workitem relative API. */
+void ODM_InitializeWorkItem(struct dm_odm_t *pDM_Odm, void *pRtWorkItem,
+                           RT_WORKITEM_CALL_BACK RtWorkItemCallback, void *pContext, const char *szID);
+
+/*  ODM Timer relative API. */
+void ODM_SetTimer(struct dm_odm_t *pDM_Odm, struct timer_list *pTimer, u32 msDelay);
+
+void ODM_ReleaseTimer(struct dm_odm_t *pDM_Odm, struct timer_list *pTimer);
+
+/*  ODM FW relative API. */
+u32 ODM_FillH2CCmd(u8 *pH2CBuffer, u32 H2CBufferLen, u32 CmdNum,
+                  u32 *pElementID, u32 *pCmdLen, u8 **pCmbBuffer,
+                  u8 *CmdStartSeq);
+
+#endif /*  __ODM_INTERFACE_H__ */
diff --git a/drivers/staging/rtl8723au/include/odm_precomp.h b/drivers/staging/rtl8723au/include/odm_precomp.h
new file mode 100644 (file)
index 0000000..f3fc2fa
--- /dev/null
@@ -0,0 +1,54 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+#ifndef        __ODM_PRECOMP_H__
+#define __ODM_PRECOMP_H__
+
+#include "odm_types.h"
+
+#define                TEST_FALG___            1
+
+/* 2 Config Flags and Structs - defined by each ODM Type */
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <hal_intf.h>
+
+
+/* 2 Hardware Parameter Files */
+#include "Hal8723UHWImg_CE.h"
+
+
+/* 2 OutSrc Header Files */
+
+#include "odm.h"
+#include "odm_HWConfig.h"
+#include "odm_debug.h"
+#include "odm_RegDefine11AC.h"
+#include "odm_RegDefine11N.h"
+
+#include "HalDMOutSrc8723A.h" /* for IQK,LCK,Power-tracking */
+#include "rtl8723a_hal.h"
+
+#include "odm_interface.h"
+#include "odm_reg.h"
+
+#include "HalHWImg8723A_MAC.h"
+#include "HalHWImg8723A_RF.h"
+#include "HalHWImg8723A_BB.h"
+#include "HalHWImg8723A_FW.h"
+#include "odm_RegConfig8723A.h"
+
+#endif /*  __ODM_PRECOMP_H__ */
diff --git a/drivers/staging/rtl8723au/include/odm_reg.h b/drivers/staging/rtl8723au/include/odm_reg.h
new file mode 100644 (file)
index 0000000..56191e9
--- /dev/null
@@ -0,0 +1,114 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+/*  */
+/*  File Name: odm_reg.h */
+/*  */
+/*  Description: */
+/*  */
+/*  This file is for general register definition. */
+/*  */
+/*  */
+/*  */
+#ifndef        __HAL_ODM_REG_H__
+#define __HAL_ODM_REG_H__
+
+/*  */
+/*  Register Definition */
+/*  */
+
+/* MAC REG */
+#define        ODM_BB_RESET                                    0x002
+#define        ODM_DUMMY                                               0x4fe
+#define        ODM_EDCA_VO_PARAM                       0x500
+#define        ODM_EDCA_VI_PARAM                       0x504
+#define        ODM_EDCA_BE_PARAM                       0x508
+#define        ODM_EDCA_BK_PARAM                       0x50C
+#define        ODM_TXPAUSE                                     0x522
+
+/* BB REG */
+#define        ODM_FPGA_PHY0_PAGE8                     0x800
+#define        ODM_PSD_SETTING                         0x808
+#define        ODM_AFE_SETTING                         0x818
+#define        ODM_TXAGC_B_6_18                                0x830
+#define        ODM_TXAGC_B_24_54                       0x834
+#define        ODM_TXAGC_B_MCS32_5                     0x838
+#define        ODM_TXAGC_B_MCS0_MCS3           0x83c
+#define        ODM_TXAGC_B_MCS4_MCS7           0x848
+#define        ODM_TXAGC_B_MCS8_MCS11          0x84c
+#define        ODM_ANALOG_REGISTER                     0x85c
+#define        ODM_RF_INTERFACE_OUTPUT         0x860
+#define        ODM_TXAGC_B_MCS12_MCS15 0x868
+#define        ODM_TXAGC_B_11_A_2_11           0x86c
+#define        ODM_AD_DA_LSB_MASK                      0x874
+#define        ODM_ENABLE_3_WIRE                       0x88c
+#define        ODM_PSD_REPORT                          0x8b4
+#define        ODM_R_ANT_SELECT                                0x90c
+#define        ODM_CCK_ANT_SELECT                      0xa07
+#define        ODM_CCK_PD_THRESH                       0xa0a
+#define        ODM_CCK_RF_REG1                         0xa11
+#define        ODM_CCK_MATCH_FILTER                    0xa20
+#define        ODM_CCK_RAKE_MAC                                0xa2e
+#define        ODM_CCK_CNT_RESET                       0xa2d
+#define        ODM_CCK_TX_DIVERSITY                    0xa2f
+#define        ODM_CCK_FA_CNT_MSB                      0xa5b
+#define        ODM_CCK_FA_CNT_LSB                      0xa5c
+#define        ODM_CCK_NEW_FUNCTION            0xa75
+#define        ODM_OFDM_PHY0_PAGE_C            0xc00
+#define        ODM_OFDM_RX_ANT                         0xc04
+#define        ODM_R_A_RXIQI                                   0xc14
+#define        ODM_R_A_AGC_CORE1                       0xc50
+#define        ODM_R_A_AGC_CORE2                       0xc54
+#define        ODM_R_B_AGC_CORE1                       0xc58
+#define        ODM_R_AGC_PAR                                   0xc70
+#define        ODM_R_HTSTF_AGC_PAR                     0xc7c
+#define        ODM_TX_PWR_TRAINING_A           0xc90
+#define        ODM_TX_PWR_TRAINING_B           0xc98
+#define        ODM_OFDM_FA_CNT1                                0xcf0
+#define        ODM_OFDM_PHY0_PAGE_D            0xd00
+#define        ODM_OFDM_FA_CNT2                                0xda0
+#define        ODM_OFDM_FA_CNT3                                0xda4
+#define        ODM_OFDM_FA_CNT4                                0xda8
+#define        ODM_TXAGC_A_6_18                                0xe00
+#define        ODM_TXAGC_A_24_54                       0xe04
+#define        ODM_TXAGC_A_1_MCS32                     0xe08
+#define        ODM_TXAGC_A_MCS0_MCS3           0xe10
+#define        ODM_TXAGC_A_MCS4_MCS7           0xe14
+#define        ODM_TXAGC_A_MCS8_MCS11          0xe18
+#define        ODM_TXAGC_A_MCS12_MCS15         0xe1c
+
+/* RF REG */
+#define        ODM_GAIN_SETTING                                0x00
+#define        ODM_CHANNEL                                     0x18
+
+/* Ant Detect Reg */
+#define        ODM_DPDT                                                0x300
+
+/* PSD Init */
+#define        ODM_PSDREG                                      0x808
+
+/* 92D Path Div */
+#define        PATHDIV_REG                                     0xB30
+#define        PATHDIV_TRI                                     0xBA0
+
+
+/*  */
+/*  Bitmap Definition */
+/*  */
+
+#define        BIT_FA_RESET                                    BIT0
+
+
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/odm_types.h b/drivers/staging/rtl8723au/include/odm_types.h
new file mode 100644 (file)
index 0000000..a866769
--- /dev/null
@@ -0,0 +1,36 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __ODM_TYPES_H__
+#define __ODM_TYPES_H__
+
+/*  Define Different SW team support */
+
+enum hal_status {
+       HAL_STATUS_SUCCESS,
+       HAL_STATUS_FAILURE,
+};
+
+enum rt_spinlock_type {
+       RT_TEMP =1,
+};
+
+#define SET_TX_DESC_ANTSEL_A_88E(__pTxDesc, __Value)           \
+       SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 24, 1, __Value)
+#define SET_TX_DESC_ANTSEL_B_88E(__pTxDesc, __Value)           \
+       SET_BITS_TO_LE_4BYTE(__pTxDesc+8, 25, 1, __Value)
+#define SET_TX_DESC_ANTSEL_C_88E(__pTxDesc, __Value)           \
+       SET_BITS_TO_LE_4BYTE(__pTxDesc+28, 29, 1, __Value)
+
+#endif /*  __ODM_TYPES_H__ */
diff --git a/drivers/staging/rtl8723au/include/osdep_intf.h b/drivers/staging/rtl8723au/include/osdep_intf.h
new file mode 100644 (file)
index 0000000..b603cf5
--- /dev/null
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+#ifndef __OSDEP_INTF_H_
+#define __OSDEP_INTF_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+int rtw_hw_suspend23a(struct rtw_adapter *padapter);
+int rtw_hw_resume23a(struct rtw_adapter *padapter);
+
+u8 rtw_init_drv_sw23a(struct rtw_adapter *padapter);
+u8 rtw_free_drv_sw23a(struct rtw_adapter *padapter);
+u8 rtw_reset_drv_sw23a(struct rtw_adapter *padapter);
+
+u32 rtw_start_drv_threads23a(struct rtw_adapter *padapter);
+void rtw_stop_drv_threads23a (struct rtw_adapter *padapter);
+void rtw_cancel_all_timer23a(struct rtw_adapter *padapter);
+
+int rtw_init_netdev23a_name23a(struct net_device *pnetdev, const char *ifname);
+struct net_device *rtw_init_netdev23a(struct rtw_adapter *padapter);
+
+u16 rtw_recv_select_queue23a(struct sk_buff *skb);
+
+void rtw_ips_dev_unload23a(struct rtw_adapter *padapter);
+
+int rtw_ips_pwr_up23a(struct rtw_adapter *padapter);
+void rtw_ips_pwr_down23a(struct rtw_adapter *padapter);
+
+int rtw_drv_register_netdev(struct rtw_adapter *padapter);
+void rtw_ndev_destructor(struct net_device *ndev);
+
+#endif /* _OSDEP_INTF_H_ */
diff --git a/drivers/staging/rtl8723au/include/osdep_service.h b/drivers/staging/rtl8723au/include/osdep_service.h
new file mode 100644 (file)
index 0000000..039bc72
--- /dev/null
@@ -0,0 +1,207 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __OSDEP_SERVICE_H_
+#define __OSDEP_SERVICE_H_
+
+#define _FAIL          0
+#define _SUCCESS       1
+#define RTW_RX_HANDLED 2
+
+#include <linux/version.h>
+#include <linux/spinlock.h>
+#include <linux/compiler.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kref.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/circ_buf.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+#include <asm/atomic.h>
+#include <asm/io.h>
+#include <linux/semaphore.h>
+#include <linux/sem.h>
+#include <linux/sched.h>
+#include <linux/etherdevice.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <linux/if_arp.h>
+#include <linux/rtnetlink.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>     /*  Necessary because we use the proc fs */
+#include <linux/interrupt.h>   /*  for struct tasklet_struct */
+#include <linux/ip.h>
+#include <linux/kthread.h>
+
+
+/*     #include <linux/ieee80211.h> */
+#include <net/ieee80211_radiotap.h>
+#include <net/cfg80211.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+
+struct rtw_adapter;
+struct c2h_evt_hdr;
+
+typedef s32 (*c2h_id_filter)(u8 id);
+
+struct rtw_queue {
+       struct  list_head       queue;
+       spinlock_t              lock;
+};
+
+static inline struct list_head *get_list_head(struct rtw_queue *queue)
+{
+       return (&queue->queue);
+}
+
+static inline int rtw_netif_queue_stopped(struct net_device *pnetdev)
+{
+       return (netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 0)) &&
+               netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 1)) &&
+               netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 2)) &&
+               netif_tx_queue_stopped(netdev_get_tx_queue(pnetdev, 3)) );
+}
+
+#ifndef BIT
+#define BIT(x) ( 1 << (x))
+#endif
+static inline u32 CHKBIT(u32 x)
+{
+       WARN_ON(x >= 32);
+       if (x >= 32)
+               return 0;
+       return BIT(x);
+}
+
+#define BIT0   0x00000001
+#define BIT1   0x00000002
+#define BIT2   0x00000004
+#define BIT3   0x00000008
+#define BIT4   0x00000010
+#define BIT5   0x00000020
+#define BIT6   0x00000040
+#define BIT7   0x00000080
+#define BIT8   0x00000100
+#define BIT9   0x00000200
+#define BIT10  0x00000400
+#define BIT11  0x00000800
+#define BIT12  0x00001000
+#define BIT13  0x00002000
+#define BIT14  0x00004000
+#define BIT15  0x00008000
+#define BIT16  0x00010000
+#define BIT17  0x00020000
+#define BIT18  0x00040000
+#define BIT19  0x00080000
+#define BIT20  0x00100000
+#define BIT21  0x00200000
+#define BIT22  0x00400000
+#define BIT23  0x00800000
+#define BIT24  0x01000000
+#define BIT25  0x02000000
+#define BIT26  0x04000000
+#define BIT27  0x08000000
+#define BIT28  0x10000000
+#define BIT29  0x20000000
+#define BIT30  0x40000000
+#define BIT31  0x80000000
+#define BIT32  0x0100000000
+#define BIT33  0x0200000000
+#define BIT34  0x0400000000
+#define BIT35  0x0800000000
+#define BIT36  0x1000000000
+
+int RTW_STATUS_CODE23a(int error_code);
+
+u8*    _rtw_vmalloc(u32 sz);
+u8*    _rtw_zvmalloc(u32 sz);
+void   _rtw_vmfree(u8 *pbuf, u32 sz);
+#define rtw_vmalloc(sz)                        _rtw_vmalloc((sz))
+#define rtw_zvmalloc(sz)                       _rtw_zvmalloc((sz))
+#define rtw_vmfree(pbuf, sz)           _rtw_vmfree((pbuf), (sz))
+
+extern unsigned char REALTEK_96B_IE23A[];
+extern unsigned char MCS_rate_2R23A[16];
+extern unsigned char RTW_WPA_OUI23A[];
+extern unsigned char WPA_TKIP_CIPHER23A[4];
+extern unsigned char RSN_TKIP_CIPHER23A[4];
+
+extern unsigned char   MCS_rate_2R23A[16];
+extern unsigned char   MCS_rate_1R23A[16];
+
+void   _rtw_init_queue23a(struct rtw_queue *pqueue);
+u32    _rtw_queue_empty23a(struct rtw_queue *pqueue);
+
+static inline u32 bitshift(u32 bitmask)
+{
+       u32 i;
+
+       for (i = 0; i <= 31; i++)
+               if (((bitmask>>i) &  0x1) == 1) break;
+
+       return i;
+}
+
+void rtw_suspend_lock_init(void);
+void rtw_suspend_lock_uninit(void);
+void rtw_lock_suspend(void);
+void rtw_unlock_suspend(void);
+
+
+#define NDEV_FMT "%s"
+#define NDEV_ARG(ndev) ndev->name
+#define ADPT_FMT "%s"
+#define ADPT_ARG(adapter) adapter->pnetdev->name
+#define FUNC_NDEV_FMT "%s(%s)"
+#define FUNC_NDEV_ARG(ndev) __func__, ndev->name
+#define FUNC_ADPT_FMT "%s(%s)"
+#define FUNC_ADPT_ARG(adapter) __func__, adapter->pnetdev->name
+
+#define rtw_signal_process(pid, sig) kill_pid(find_vpid((pid)),(sig), 1)
+
+u64 rtw_modular6423a(u64 x, u64 y);
+u64 rtw_division6423a(u64 x, u64 y);
+
+
+/* Macros for handling unaligned memory accesses */
+
+#define RTW_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
+                        ((u32) (a)[2]))
+
+
+struct rtw_cbuf {
+       u32 write;
+       u32 read;
+       u32 size;
+       void *bufs[0];
+};
+
+bool rtw_cbuf_full23a(struct rtw_cbuf *cbuf);
+bool rtw_cbuf_empty23a(struct rtw_cbuf *cbuf);
+bool rtw_cbuf_push23a(struct rtw_cbuf *cbuf, void *buf);
+void *rtw_cbuf_pop23a(struct rtw_cbuf *cbuf);
+struct rtw_cbuf *rtw_cbuf_alloc23a(u32 size);
+void rtw_cbuf_free(struct rtw_cbuf *cbuf);
+int rtw_change_ifname(struct rtw_adapter *padapter, const char *ifname);
+s32 c2h_evt_hdl(struct rtw_adapter *adapter, struct c2h_evt_hdr *c2h_evt, c2h_id_filter filter);
+void indicate_wx_scan_complete_event(struct rtw_adapter *padapter);
+u8 rtw_do_join23a(struct rtw_adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/recv_osdep.h b/drivers/staging/rtl8723au/include/recv_osdep.h
new file mode 100644 (file)
index 0000000..15c94b6
--- /dev/null
@@ -0,0 +1,45 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RECV_OSDEP_H_
+#define __RECV_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+int _rtw_init_recv_priv23a(struct recv_priv *precvpriv, struct rtw_adapter *padapter);
+void _rtw_free_recv_priv23a (struct recv_priv *precvpriv);
+
+int rtw_recv_entry23a(struct recv_frame *precv_frame);
+int rtw_recv_indicatepkt23a(struct rtw_adapter *adapter, struct recv_frame *precv_frame);
+void rtw_recv_returnpacket(struct net_device *cnxt, struct sk_buff *preturnedpkt);
+
+void rtw_hostapd_mlme_rx23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+void rtw_handle_tkip_mic_err23a(struct rtw_adapter *padapter, u8 bgroup);
+
+int    rtw_init_recv_priv(struct recv_priv *precvpriv, struct rtw_adapter *padapter);
+void rtw_free_recv_priv (struct recv_priv *precvpriv);
+
+int rtw_os_recv_resource_init(struct recv_priv *precvpriv, struct rtw_adapter *padapter);
+int rtw_os_recv_resource_alloc23a(struct rtw_adapter *padapter, struct recv_frame *precvframe);
+void rtw_os_recv_resource_free(struct recv_priv *precvpriv);
+
+int rtw_os_recvbuf_resource_alloc23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf);
+int rtw_os_recvbuf_resource_free23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf);
+
+void rtw_os_read_port23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf);
+
+void rtw_init_recv_timer23a(struct recv_reorder_ctrl *preorder_ctrl);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h b/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h
new file mode 100644 (file)
index 0000000..6d1edc6
--- /dev/null
@@ -0,0 +1,1672 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTL8723A_BT_COEXIST_H__
+#define __RTL8723A_BT_COEXIST_H__
+
+#include <drv_types.h>
+#include "odm_precomp.h"
+
+
+#define __BT_C__ 1
+#define __BT_HANDLEPACKET_C__ 1
+#define __BT_HCI_C__ 1
+#define __HALBTC87231ANT_C__ 1
+#define __HALBTC87232ANT_C__ 1
+#define __HALBTC8723_C__ 1
+#define __HALBTCCSR1ANT_C__ 1
+#define __HALBTCCSR2ANT_C__ 1
+#define __HALBTCOEXIST_C__ 1
+#define __HALBT_C__ 1
+
+#ifdef __BT_C__ /*  COMMON/BT.h */
+
+/*  HEADER/PlatformDef.h */
+enum rt_media_status {
+       RT_MEDIA_DISCONNECT     = 0,
+       RT_MEDIA_CONNECT        = 1
+};
+
+/*  ===== Below this line is sync from SD7 driver COMMON/BT.h ===== */
+
+#define        BT_TMP_BUF_SIZE         100
+
+void BT_SignalCompensation(struct rtw_adapter *padapter,
+                          u8 *rssi_wifi, u8 *rssi_bt);
+void BT_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType);
+void BT_WifiAssociateNotify(struct rtw_adapter *padapter, u8 action);
+void BT_WifiMediaStatusNotify(struct rtw_adapter *padapter,
+                             enum rt_media_status mstatus);
+void BT_SpecialPacketNotify(struct rtw_adapter * padapter);
+void BT_HaltProcess(struct rtw_adapter * padapter);
+void BT_LpsLeave(struct rtw_adapter * padapter);
+
+
+#define        BT_HsConnectionEstablished(Adapter)             false
+/*  ===== End of sync from SD7 driver COMMON/BT.h ===== */
+#endif /*  __BT_C__ */
+
+#ifdef __BT_HCI_C__ /*  COMMON/bt_hci.h */
+
+/*  HEADER/SecurityType.h */
+#define TKIP_ENC_KEY_POS               32              /* KEK_LEN+KEK_LEN) */
+#define MAXRSNIELEN                            256
+
+/*  COMMON/Protocol802_11.h */
+/*  */
+/*       802.11 Management frame Status Code field */
+/*  */
+struct octet_string {
+       u8              *Octet;
+       u16             Length;
+};
+
+
+/*  AES_CCMP specific */
+enum {
+       AESCCMP_BLK_SIZE                =   16,     /*  # octets in an AES block */
+       AESCCMP_MAX_PACKET              =   4*512,  /*  largest packet size */
+       AESCCMP_N_RESERVED              =   0,      /*  reserved nonce octet value */
+       AESCCMP_A_DATA                  =   0x40,   /*  the Adata bit in the flags */
+       AESCCMP_M_SHIFT                 =   3,      /*  how much to shift the 3-bit M field */
+       AESCCMP_L_SHIFT                 =   0,      /*  how much to shift the 3-bit L field */
+       AESCCMP_L_SIZE                  =   2,       /*  size of the l(m) length field (in octets) */
+       AESCCMP_OFFSET_SC               =       22,
+       AESCCMP_OFFSET_DURATION =       4,
+       AESCCMP_OFFSET_A2               =       10,
+       AESCCMP_OFFSET_A4               =       24,
+       AESCCMP_QC_TID_MASK             =       0x0f,
+       AESCCMP_BLK_SIZE_TOTAL  =   16*16,     /*  Added by Annie for CKIP AES MIC BSOD, 2006-08-17. */
+                                                                                       /*  16*8 < 4*60  Resove to 16*16 */
+};
+
+/*  Key Length */
+#define PMK_LEN                                32
+#define PTK_LEN_TKIP                   64
+#define GTK_LEN                                32
+#define KEY_NONCE_LEN                  32
+
+
+/*  COMMON/Dot11d.h */
+struct chnl_txpower_triple {
+       u8 FirstChnl;
+       u8 NumChnls;
+       s8 MaxTxPowerInDbm;
+};
+
+
+/*  ===== Below this line is sync from SD7 driver COMMON/bt_hci.h ===== */
+/*  The following is for BT 3.0 + HS HCI COMMAND ERRORS CODES */
+
+#define Max80211PALPDUSize                     1492
+#define Max80211AMPASSOCLen                    672
+#define MinGUserPrio                                   4
+#define MaxGUserPrio                                   7
+#define BEUserPrio0                                            0
+#define BEUserPrio1                                            3
+#define Max80211BeaconPeriod           2000
+#define ShortRangeModePowerMax         4
+
+#define BT_Default_Chnl                                        10
+#define ACLDataHeaderLen                               4
+
+#define BTTotalDataBlockNum                    0x100
+#define BTLocalBufNum                                  0x200
+#define BTMaxDataBlockLen                              0x800
+#define BTTOTALBANDWIDTH                               0x7530
+#define BTMAXBANDGUBANDWIDTH           0x4e20
+#define TmpLocalBufSize                                        0x100
+#define BTSynDataPacketLength                  0xff
+/*  */
+
+#define BTMaxAuthCount                                 5
+#define BTMaxAsocCount                                 5
+
+#define MAX_LOGICAL_LINK_NUM                   2       /* temporarily define */
+#define MAX_BT_ASOC_ENTRY_NUM          2       /* temporarily define */
+
+#define INVALID_PL_HANDLE                              0xff
+#define INVALID_ENTRY_NUM                              0xff
+/*  */
+
+#define CAM_BT_START_INDEX             (HALF_CAM_ENTRY - 4)   /*  MAX_BT_ASOC_ENTRY_NUM : 4 !!! */
+#define BT_HWCAM_STAR                  CAM_BT_START_INDEX  /*  We used  HALF_CAM_ENTRY ~ HALF_CAM_ENTRY -MAX_BT_ASOC_ENTRY_NUM */
+
+enum hci_status {
+       HCI_STATUS_SUCCESS                      = 0x00, /* Success */
+       HCI_STATUS_UNKNOW_HCI_CMD               = 0x01, /* Unknown HCI Command */
+       HCI_STATUS_UNKNOW_CONNECT_ID            = 0X02, /* Unknown Connection Identifier */
+       HCI_STATUS_HW_FAIL                      = 0X03, /* Hardware Failure */
+       HCI_STATUS_PAGE_TIMEOUT                 = 0X04, /* Page Timeout */
+       HCI_STATUS_AUTH_FAIL                    = 0X05, /* Authentication Failure */
+       HCI_STATUS_PIN_OR_KEY_MISSING           = 0X06, /* PIN or Key Missing */
+       HCI_STATUS_MEM_CAP_EXCEED               = 0X07, /* Memory Capacity Exceeded */
+       HCI_STATUS_CONNECT_TIMEOUT              = 0X08, /* Connection Timeout */
+       HCI_STATUS_CONNECT_LIMIT                = 0X09, /* Connection Limit Exceeded */
+       HCI_STATUS_SYN_CONNECT_LIMIT            = 0X0a, /* Synchronous Connection Limit To A Device Exceeded */
+       HCI_STATUS_ACL_CONNECT_EXISTS           = 0X0b, /* ACL Connection Already Exists */
+       HCI_STATUS_CMD_DISALLOW                 = 0X0c, /* Command Disallowed */
+       HCI_STATUS_CONNECT_RJT_LIMIT_RESOURCE   = 0X0d, /* Connection Rejected due to Limited Resources */
+       HCI_STATUS_CONNECT_RJT_SEC_REASON       = 0X0e, /* Connection Rejected Due To Security Reasons */
+       HCI_STATUS_CONNECT_RJT_UNACCEPT_BD_ADDR = 0X0f, /* Connection Rejected due to Unacceptable BD_ADDR */
+       HCI_STATUS_CONNECT_ACCEPT_TIMEOUT       = 0X10, /* Connection Accept Timeout Exceeded */
+       HCI_STATUS_UNSUPPORT_FEATURE_PARA_VALUE = 0X11, /* Unsupported Feature or Parameter Value */
+       HCI_STATUS_INVALID_HCI_CMD_PARA_VALUE   = 0X12, /* Invalid HCI Command Parameters */
+       HCI_STATUS_REMOTE_USER_TERMINATE_CONNECT = 0X13, /* Remote User Terminated Connection */
+       HCI_STATUS_REMOTE_DEV_TERMINATE_LOW_RESOURCE = 0X14, /* Remote Device Terminated Connection due to Low Resources */
+       HCI_STATUS_REMOTE_DEV_TERMINATE_CONNECT_POWER_OFF = 0X15, /* Remote Device Terminated Connection due to Power Off */
+       HCI_STATUS_CONNECT_TERMINATE_LOCAL_HOST = 0X16, /* Connection Terminated By Local Host */
+       HCI_STATUS_REPEATE_ATTEMPT              = 0X17, /* Repeated Attempts */
+       HCI_STATUS_PAIR_NOT_ALLOW               = 0X18, /* Pairing Not Allowed */
+       HCI_STATUS_UNKNOW_LMP_PDU               = 0X19, /* Unknown LMP PDU */
+       HCI_STATUS_UNSUPPORT_REMOTE_LMP_FEATURE = 0X1a, /* Unsupported Remote Feature / Unsupported LMP Feature */
+       HCI_STATUS_SOC_OFFSET_REJECT            = 0X1b, /* SCO Offset Rejected */
+       HCI_STATUS_SOC_INTERVAL_REJECT          = 0X1c, /* SCO Interval Rejected */
+       HCI_STATUS_SOC_AIR_MODE_REJECT          = 0X1d,/* SCO Air Mode Rejected */
+       HCI_STATUS_INVALID_LMP_PARA             = 0X1e, /* Invalid LMP Parameters */
+       HCI_STATUS_UNSPECIFIC_ERROR             = 0X1f, /* Unspecified Error */
+       HCI_STATUS_UNSUPPORT_LMP_PARA_VALUE     = 0X20, /* Unsupported LMP Parameter Value */
+       HCI_STATUS_ROLE_CHANGE_NOT_ALLOW        = 0X21, /* Role Change Not Allowed */
+       HCI_STATUS_LMP_RESPONSE_TIMEOUT         = 0X22, /* LMP Response Timeout */
+       HCI_STATUS_LMP_ERROR_TRANSACTION_COLLISION = 0X23, /* LMP Error Transaction Collision */
+       HCI_STATUS_LMP_PDU_NOT_ALLOW            = 0X24, /* LMP PDU Not Allowed */
+       HCI_STATUS_ENCRYPTION_MODE_NOT_ALLOW    = 0X25, /* Encryption Mode Not Acceptable */
+       HCI_STATUS_LINK_KEY_CAN_NOT_CHANGE      = 0X26, /* Link Key Can Not be Changed */
+       HCI_STATUS_REQUEST_QOS_NOT_SUPPORT      = 0X27, /* Requested QoS Not Supported */
+       HCI_STATUS_INSTANT_PASSED               = 0X28, /* Instant Passed */
+       HCI_STATUS_PAIRING_UNIT_KEY_NOT_SUPPORT = 0X29, /* Pairing With Unit Key Not Supported */
+       HCI_STATUS_DIFFERENT_TRANSACTION_COLLISION = 0X2a, /* Different Transaction Collision */
+       HCI_STATUS_RESERVE_1                    = 0X2b, /* Reserved */
+       HCI_STATUS_QOS_UNACCEPT_PARA            = 0X2c, /* QoS Unacceptable Parameter */
+       HCI_STATUS_QOS_REJECT                   = 0X2d, /* QoS Rejected */
+       HCI_STATUS_CHNL_CLASSIFICATION_NOT_SUPPORT = 0X2e, /* Channel Classification Not Supported */
+       HCI_STATUS_INSUFFICIENT_SECURITY        = 0X2f, /* Insufficient Security */
+       HCI_STATUS_PARA_OUT_OF_RANGE            = 0x30, /* Parameter Out Of Mandatory Range */
+       HCI_STATUS_RESERVE_2                    = 0X31, /* Reserved */
+       HCI_STATUS_ROLE_SWITCH_PENDING          = 0X32, /* Role Switch Pending */
+       HCI_STATUS_RESERVE_3                    = 0X33, /* Reserved */
+       HCI_STATUS_RESERVE_SOLT_VIOLATION       = 0X34, /* Reserved Slot Violation */
+       HCI_STATUS_ROLE_SWITCH_FAIL             = 0X35, /* Role Switch Failed */
+       HCI_STATUS_EXTEND_INQUIRY_RSP_TOO_LARGE = 0X36, /* Extended Inquiry Response Too Large */
+       HCI_STATUS_SEC_SIMPLE_PAIRING_NOT_SUPPORT = 0X37, /* Secure Simple Pairing Not Supported By Host. */
+       HCI_STATUS_HOST_BUSY_PAIRING            = 0X38, /* Host Busy - Pairing */
+       HCI_STATUS_CONNECT_REJ_NOT_SUIT_CHNL_FOUND = 0X39, /* Connection Rejected due to No Suitable Channel Found */
+       HCI_STATUS_CONTROLLER_BUSY              = 0X3a  /* CONTROLLER BUSY */
+};
+
+/*  */
+/*  The following is for BT 3.0 + HS HCI COMMAND */
+/*  */
+
+/* bit 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 */
+/*      |      OCF                                  |     OGF       | */
+/*  */
+
+/* OGF 0x01 */
+#define LINK_CONTROL_COMMANDS                  0x01
+enum link_control_commands {
+       HCI_INQUIRY                                     = 0x0001,
+       HCI_INQUIRY_CANCEL                              = 0x0002,
+       HCI_PERIODIC_INQUIRY_MODE                       = 0x0003,
+       HCI_EXIT_PERIODIC_INQUIRY_MODE                  = 0x0004,
+       HCI_CREATE_CONNECTION                           = 0x0005,
+       HCI_DISCONNECT                                  = 0x0006,
+       HCI_CREATE_CONNECTION_CANCEL                    = 0x0008,
+       HCI_ACCEPT_CONNECTIONREQUEST                    = 0x0009,
+       HCI_REJECT_CONNECTION_REQUEST                   = 0x000a,
+       HCI_LINK_KEY_REQUEST_REPLY                      = 0x000b,
+       HCI_LINK_KEY_REQUEST_NEGATIVE_REPLY             = 0x000c,
+       HCI_PIN_CODE_REQUEST_REPLY                      = 0x000d,
+       HCI_PIN_CODE_REQUEST_NEGATIVE_REPLY             = 0x000e,
+       HCI_CHANGE_CONNECTION_PACKET_TYPE               = 0x000f,
+       HCI_AUTHENTICATION_REQUESTED                    = 0x0011,
+       HCI_SET_CONNECTION_ENCRYPTION                   = 0x0013,
+       HCI_CHANGE_CONNECTION_LINK_KEY                  = 0x0015,
+       HCI_MASTER_LINK_KEY                             = 0x0017,
+       HCI_REMOTE_NAME_REQUEST                         = 0x0019,
+       HCI_REMOTE_NAME_REQUEST_CANCEL                  = 0x001a,
+       HCI_READ_REMOTE_SUPPORTED_FEATURES              = 0x001b,
+       HCI_READ_REMOTE_EXTENDED_FEATURES               = 0x001c,
+       HCI_READ_REMOTE_VERSION_INFORMATION             = 0x001d,
+       HCI_READ_CLOCK_OFFSET                           = 0x001f,
+       HCI_READ_LMP_HANDLE                             = 0x0020,
+       HCI_SETUP_SYNCHRONOUS_CONNECTION                = 0x0028,
+       HCI_ACCEPT_SYNCHRONOUS_CONNECTION_REQUEST       = 0x0029,
+       HCI_REJECT_SYNCHRONOUS_CONNECTION_REQUEST       = 0x002a,
+       HCI_IO_CAPABILITY_REQUEST_REPLY                 = 0x002b,
+       HCI_USER_CONFIRMATION_REQUEST_REPLY             = 0x002c,
+       HCI_USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY    = 0x002d,
+       HCI_USER_PASSKEY_REQUEST_REPLY                  = 0x002e,
+       HCI_USER_PASSKEY_REQUESTNEGATIVE_REPLY          = 0x002f,
+       HCI_REMOTE_OOB_DATA_REQUEST_REPLY               = 0x0030,
+       HCI_REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY      = 0x0033,
+       HCI_IO_CAPABILITY_REQUEST_NEGATIVE_REPLY        = 0x0034,
+       HCI_CREATE_PHYSICAL_LINK                        = 0x0035,
+       HCI_ACCEPT_PHYSICAL_LINK                        = 0x0036,
+       HCI_DISCONNECT_PHYSICAL_LINK                    = 0x0037,
+       HCI_CREATE_LOGICAL_LINK                         = 0x0038,
+       HCI_ACCEPT_LOGICAL_LINK                         = 0x0039,
+       HCI_DISCONNECT_LOGICAL_LINK                     = 0x003a,
+       HCI_LOGICAL_LINK_CANCEL                         = 0x003b,
+       HCI_FLOW_SPEC_MODIFY                            = 0x003c
+};
+
+/* OGF 0x02 */
+#define HOLD_MODE_COMMAND                              0x02
+enum hold_mode_command {
+       HCI_HOLD_MODE                                   = 0x0001,
+       HCI_SNIFF_MODE                                  = 0x0002,
+       HCI_EXIT_SNIFF_MODE                             = 0x0003,
+       HCI_PARK_STATE                                  = 0x0005,
+       HCI_EXIT_PARK_STATE                             = 0x0006,
+       HCI_QOS_SETUP                                   = 0x0007,
+       HCI_ROLE_DISCOVERY                              = 0x0009,
+       HCI_SWITCH_ROLE                                 = 0x000b,
+       HCI_READ_LINK_POLICY_SETTINGS                   = 0x000c,
+       HCI_WRITE_LINK_POLICY_SETTINGS                  = 0x000d,
+       HCI_READ_DEFAULT_LINK_POLICY_SETTINGS           = 0x000e,
+       HCI_WRITE_DEFAULT_LINK_POLICY_SETTINGS          = 0x000f,
+       HCI_FLOW_SPECIFICATION                          = 0x0010,
+       HCI_SNIFF_SUBRATING                             = 0x0011
+};
+
+/* OGF 0x03 */
+#define OGF_SET_EVENT_MASK_COMMAND                     0x03
+enum set_event_mask_command {
+       HCI_SET_EVENT_MASK                              = 0x0001,
+       HCI_RESET                                       = 0x0003,
+       HCI_SET_EVENT_FILTER                            = 0x0005,
+       HCI_FLUSH                                       = 0x0008,
+       HCI_READ_PIN_TYPE                               = 0x0009,
+       HCI_WRITE_PIN_TYPE                              = 0x000a,
+       HCI_CREATE_NEW_UNIT_KEY                         = 0x000b,
+       HCI_READ_STORED_LINK_KEY                        = 0x000d,
+       HCI_WRITE_STORED_LINK_KEY                       = 0x0011,
+       HCI_DELETE_STORED_LINK_KEY                      = 0x0012,
+       HCI_WRITE_LOCAL_NAME                            = 0x0013,
+       HCI_READ_LOCAL_NAME                             = 0x0014,
+       HCI_READ_CONNECTION_ACCEPT_TIMEOUT              = 0x0015,
+       HCI_WRITE_CONNECTION_ACCEPT_TIMEOUT             = 0x0016,
+       HCI_READ_PAGE_TIMEOUT                           = 0x0017,
+       HCI_WRITE_PAGE_TIMEOUT                          = 0x0018,
+       HCI_READ_SCAN_ENABLE                            = 0x0019,
+       HCI_WRITE_SCAN_ENABLE                           = 0x001a,
+       HCI_READ_PAGE_SCAN_ACTIVITY                     = 0x001b,
+       HCI_WRITE_PAGE_SCAN_ACTIVITY                    = 0x001c,
+       HCI_READ_INQUIRY_SCAN_ACTIVITY                  = 0x001d,
+       HCI_WRITE_INQUIRY_SCAN_ACTIVITY                 = 0x001e,
+       HCI_READ_AUTHENTICATION_ENABLE                  = 0x001f,
+       HCI_WRITE_AUTHENTICATION_ENABLE                 = 0x0020,
+       HCI_READ_CLASS_OF_DEVICE                        = 0x0023,
+       HCI_WRITE_CLASS_OF_DEVICE                       = 0x0024,
+       HCI_READ_VOICE_SETTING                          = 0x0025,
+       HCI_WRITE_VOICE_SETTING                         = 0x0026,
+       HCI_READ_AUTOMATIC_FLUSH_TIMEOUT                = 0x0027,
+       HCI_WRITE_AUTOMATIC_FLUSH_TIMEOUT               = 0x0028,
+       HCI_READ_NUM_BROADCAST_RETRANSMISSIONS          = 0x0029,
+       HCI_WRITE_NUM_BROADCAST_RETRANSMISSIONS         = 0x002a,
+       HCI_READ_HOLD_MODE_ACTIVITY                     = 0x002b,
+       HCI_WRITE_HOLD_MODE_ACTIVITY                    = 0x002c,
+       HCI_READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE        = 0x002e,
+       HCI_WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE       = 0x002f,
+       HCI_SET_CONTROLLER_TO_HOST_FLOW_CONTROL         = 0x0031,
+       HCI_HOST_BUFFER_SIZE                            = 0x0033,
+       HCI_HOST_NUMBER_OF_COMPLETED_PACKETS            = 0x0035,
+       HCI_READ_LINK_SUPERVISION_TIMEOUT               = 0x0036,
+       HCI_WRITE_LINK_SUPERVISION_TIMEOUT              = 0x0037,
+       HCI_READ_NUMBER_OF_SUPPORTED_IAC                = 0x0038,
+       HCI_READ_CURRENT_IAC_LAP                        = 0x0039,
+       HCI_WRITE_CURRENT_IAC_LAP                       = 0x003a,
+       HCI_READ_PAGE_SCAN_MODE                         = 0x003d,
+       HCI_WRITE_PAGE_SCAN_MODE                        = 0x003e,
+       HCI_SET_AFH_HOST_CHANNEL_CLASSIFICATION         = 0x003f,
+       HCI_READ_INQUIRY_SCAN_TYPE                      = 0x0042,
+       HCI_WRITE_INQUIRY_SCAN_TYPE                     = 0x0043,
+       HCI_READ_INQUIRY_MODE                           = 0x0044,
+       HCI_WRITE_INQUIRY_MODE                          = 0x0045,
+       HCI_READ_PAGE_SCAN_TYPE                         = 0x0046,
+       HCI_WRITE_PAGE_SCAN_TYPE                        = 0x0047,
+       HCI_READ_AFH_CHANNEL_ASSESSMENT_MODE            = 0x0048,
+       HCI_WRITE_AFH_CHANNEL_ASSESSMENT_MODE           = 0x0049,
+       HCI_READ_EXTENDED_INQUIRY_RESPONSE              = 0x0051,
+       HCI_WRITE_EXTENDED_INQUIRY_RESPONSE             = 0x0052,
+       HCI_REFRESH_ENCRYPTION_KEY                      = 0x0053,
+       HCI_READ_SIMPLE_PAIRING_MODE                    = 0x0055,
+       HCI_WRITE_SIMPLE_PAIRING_MODE                   = 0x0056,
+       HCI_READ_LOCAL_OOB_DATA                         = 0x0057,
+       HCI_READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL  = 0x0058,
+       HCI_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL          = 0x0059,
+       HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING       = 0x005a,
+       HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING      = 0x005b,
+       HCI_ENHANCED_FLUSH                              = 0x005f,
+       HCI_SEND_KEYPRESS_NOTIFICATION                  = 0x0060,
+       HCI_READ_LOGICAL_LINK_ACCEPT_TIMEOUT            = 0x0061,
+       HCI_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT           = 0x0062,
+       HCI_SET_EVENT_MASK_PAGE_2                       = 0x0063,
+       HCI_READ_LOCATION_DATA                          = 0x0064,
+       HCI_WRITE_LOCATION_DATA                         = 0x0065,
+       HCI_READ_FLOW_CONTROL_MODE                      = 0x0066,
+       HCI_WRITE_FLOW_CONTROL_MODE                     = 0x0067,
+       HCI_READ_ENHANCE_TRANSMIT_POWER_LEVEL           = 0x0068,
+       HCI_READ_BEST_EFFORT_FLUSH_TIMEOUT              = 0x0069,
+       HCI_WRITE_BEST_EFFORT_FLUSH_TIMEOUT             = 0x006a,
+       HCI_SHORT_RANGE_MODE                            = 0x006b
+};
+
+/* OGF 0x04 */
+#define OGF_INFORMATIONAL_PARAMETERS                   0x04
+enum informational_params {
+       HCI_READ_LOCAL_VERSION_INFORMATION              = 0x0001,
+       HCI_READ_LOCAL_SUPPORTED_COMMANDS               = 0x0002,
+       HCI_READ_LOCAL_SUPPORTED_FEATURES               = 0x0003,
+       HCI_READ_LOCAL_EXTENDED_FEATURES                = 0x0004,
+       HCI_READ_BUFFER_SIZE                            = 0x0005,
+       HCI_READ_BD_ADDR                                = 0x0009,
+       HCI_READ_DATA_BLOCK_SIZE                        = 0x000a
+};
+
+/* OGF 0x05 */
+#define OGF_STATUS_PARAMETERS                          0x05
+enum status_params {
+       HCI_READ_FAILED_CONTACT_COUNTER                 = 0x0001,
+       HCI_RESET_FAILED_CONTACT_COUNTER                = 0x0002,
+       HCI_READ_LINK_QUALITY                           = 0x0003,
+       HCI_READ_RSSI                                   = 0x0005,
+       HCI_READ_AFH_CHANNEL_MAP                        = 0x0006,
+       HCI_READ_CLOCK                                  = 0x0007,
+       HCI_READ_ENCRYPTION_KEY_SIZE                    = 0x0008,
+       HCI_READ_LOCAL_AMP_INFO                         = 0x0009,
+       HCI_READ_LOCAL_AMP_ASSOC                        = 0x000a,
+       HCI_WRITE_REMOTE_AMP_ASSOC                      = 0x000b
+};
+
+/* OGF 0x06 */
+#define OGF_TESTING_COMMANDS                           0x06
+enum testing_commands {
+       HCI_READ_LOOPBACK_MODE                          = 0x0001,
+       HCI_WRITE_LOOPBACK_MODE                         = 0x0002,
+       HCI_ENABLE_DEVICE_UNDER_TEST_MODE               = 0x0003,
+       HCI_WRITE_SIMPLE_PAIRING_DEBUG_MODE             = 0x0004,
+       HCI_ENABLE_AMP_RECEIVER_REPORTS                 = 0x0007,
+       HCI_AMP_TEST_END                                = 0x0008,
+       HCI_AMP_TEST_COMMAND                            = 0x0009
+};
+
+/* OGF 0x3f */
+#define OGF_EXTENSION                                  0X3f
+enum hci_extension_commands {
+       HCI_SET_ACL_LINK_DATA_FLOW_MODE                 = 0x0010,
+       HCI_SET_ACL_LINK_STATUS                         = 0x0020,
+       HCI_SET_SCO_LINK_STATUS                         = 0x0030,
+       HCI_SET_RSSI_VALUE                              = 0x0040,
+       HCI_SET_CURRENT_BLUETOOTH_STATUS                = 0x0041,
+
+       /* The following is for RTK8723 */
+       HCI_EXTENSION_VERSION_NOTIFY                    = 0x0100,
+       HCI_LINK_STATUS_NOTIFY                          = 0x0101,
+       HCI_BT_OPERATION_NOTIFY                         = 0x0102,
+       HCI_ENABLE_WIFI_SCAN_NOTIFY                     = 0x0103,
+
+
+       /* The following is for IVT */
+       HCI_WIFI_CURRENT_CHANNEL                        = 0x0300,
+       HCI_WIFI_CURRENT_BANDWIDTH                      = 0x0301,
+       HCI_WIFI_CONNECTION_STATUS                      = 0x0302,
+};
+
+enum bt_spec {
+       BT_SPEC_1_0_b                                   = 0x00,
+       BT_SPEC_1_1                                     = 0x01,
+       BT_SPEC_1_2                                     = 0x02,
+       BT_SPEC_2_0_EDR                                 = 0x03,
+       BT_SPEC_2_1_EDR                                 = 0x04,
+       BT_SPEC_3_0_HS                                  = 0x05,
+       BT_SPEC_4_0                                     = 0x06
+};
+
+/*  The following is for BT 3.0 + HS EVENTS */
+enum hci_event {
+       HCI_EVENT_INQUIRY_COMPLETE                      = 0x01,
+       HCI_EVENT_INQUIRY_RESULT                        = 0x02,
+       HCI_EVENT_CONNECTION_COMPLETE                   = 0x03,
+       HCI_EVENT_CONNECTION_REQUEST                    = 0x04,
+       HCI_EVENT_DISCONNECTION_COMPLETE                = 0x05,
+       HCI_EVENT_AUTHENTICATION_COMPLETE               = 0x06,
+       HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE          = 0x07,
+       HCI_EVENT_ENCRYPTION_CHANGE                     = 0x08,
+       HCI_EVENT_CHANGE_LINK_KEY_COMPLETE              = 0x09,
+       HCI_EVENT_MASTER_LINK_KEY_COMPLETE              = 0x0a,
+       HCI_EVENT_READ_REMOTE_SUPPORT_FEATURES_COMPLETE = 0x0b,
+       HCI_EVENT_READ_REMOTE_VER_INFO_COMPLETE         = 0x0c,
+       HCI_EVENT_QOS_SETUP_COMPLETE                    = 0x0d,
+       HCI_EVENT_COMMAND_COMPLETE                      = 0x0e,
+       HCI_EVENT_COMMAND_STATUS                        = 0x0f,
+       HCI_EVENT_HARDWARE_ERROR                        = 0x10,
+       HCI_EVENT_FLUSH_OCCRUED                         = 0x11,
+       HCI_EVENT_ROLE_CHANGE                           = 0x12,
+       HCI_EVENT_NUMBER_OF_COMPLETE_PACKETS            = 0x13,
+       HCI_EVENT_MODE_CHANGE                           = 0x14,
+       HCI_EVENT_RETURN_LINK_KEYS                      = 0x15,
+       HCI_EVENT_PIN_CODE_REQUEST                      = 0x16,
+       HCI_EVENT_LINK_KEY_REQUEST                      = 0x17,
+       HCI_EVENT_LINK_KEY_NOTIFICATION                 = 0x18,
+       HCI_EVENT_LOOPBACK_COMMAND                      = 0x19,
+       HCI_EVENT_DATA_BUFFER_OVERFLOW                  = 0x1a,
+       HCI_EVENT_MAX_SLOTS_CHANGE                      = 0x1b,
+       HCI_EVENT_READ_CLOCK_OFFSET_COMPLETE            = 0x1c,
+       HCI_EVENT_CONNECT_PACKET_TYPE_CHANGE            = 0x1d,
+       HCI_EVENT_QOS_VIOLATION                         = 0x1e,
+       HCI_EVENT_PAGE_SCAN_REPETITION_MODE_CHANGE      = 0x20,
+       HCI_EVENT_FLOW_SEPC_COMPLETE                    = 0x21,
+       HCI_EVENT_INQUIRY_RESULT_WITH_RSSI              = 0x22,
+       HCI_EVENT_READ_REMOTE_EXT_FEATURES_COMPLETE     = 0x23,
+       HCI_EVENT_SYNC_CONNECT_COMPLETE                 = 0x2c,
+       HCI_EVENT_SYNC_CONNECT_CHANGE                   = 0x2d,
+       HCI_EVENT_SNIFFER_SUBRATING                     = 0x2e,
+       HCI_EVENT_EXTENTED_INQUIRY_RESULT               = 0x2f,
+       HCI_EVENT_ENCRYPTION_KEY_REFLASH_COMPLETE       = 0x30,
+       HCI_EVENT_IO_CAPIBILITY_COMPLETE                = 0x31,
+       HCI_EVENT_IO_CAPIBILITY_RESPONSE                = 0x32,
+       HCI_EVENT_USER_CONFIRMTION_REQUEST              = 0x33,
+       HCI_EVENT_USER_PASSKEY_REQUEST                  = 0x34,
+       HCI_EVENT_REMOTE_OOB_DATA_REQUEST               = 0x35,
+       HCI_EVENT_SIMPLE_PAIRING_COMPLETE               = 0x36,
+       HCI_EVENT_LINK_SUPERVISION_TIMEOUT_CHANGE       = 0x38,
+       HCI_EVENT_ENHANCED_FLUSH_COMPLETE               = 0x39,
+       HCI_EVENT_USER_PASSKEY_NOTIFICATION             = 0x3b,
+       HCI_EVENT_KEYPRESS_NOTIFICATION                 = 0x3c,
+       HCI_EVENT_REMOTE_HOST_SUPPORT_FEATURES_NOTIFICATION     = 0x3d,
+       HCI_EVENT_PHY_LINK_COMPLETE                     = 0x40,
+       HCI_EVENT_CHANNEL_SELECT                        = 0x41,
+       HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE          = 0x42,
+       HCI_EVENT_PHY_LINK_LOSS_EARLY_WARNING           = 0x43,
+       HCI_EVENT_PHY_LINK_RECOVER                      = 0x44,
+       HCI_EVENT_LOGICAL_LINK_COMPLETE                 = 0x45,
+       HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE      = 0x46,
+       HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE             = 0x47,
+       HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS           = 0x48,
+       HCI_EVENT_AMP_START_TEST                        = 0x49,
+       HCI_EVENT_AMP_TEST_END                          = 0x4a,
+       HCI_EVENT_AMP_RECEIVER_REPORT                   = 0x4b,
+       HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE      = 0x4c,
+       HCI_EVENT_AMP_STATUS_CHANGE                     = 0x4d,
+       HCI_EVENT_EXTENSION_RTK                         = 0xfe,
+       HCI_EVENT_EXTENSION_MOTO                        = 0xff,
+};
+
+enum hci_extension_event_moto {
+       HCI_EVENT_GET_BT_RSSI                           = 0x01,
+};
+
+enum hci_extension_event {
+       HCI_EVENT_EXT_WIFI_SCAN_NOTIFY                  = 0x01,
+};
+
+enum hci_event_mask_page_2 {
+       EMP2_HCI_EVENT_PHY_LINK_COMPLETE                = 0x0000000000000001,
+       EMP2_HCI_EVENT_CHANNEL_SELECT                   = 0x0000000000000002,
+       EMP2_HCI_EVENT_DISCONNECT_PHY_LINK_COMPLETE     = 0x0000000000000004,
+       EMP2_HCI_EVENT_PHY_LINK_LOSS_EARLY_WARNING      = 0x0000000000000008,
+       EMP2_HCI_EVENT_PHY_LINK_RECOVER                 = 0x0000000000000010,
+       EMP2_HCI_EVENT_LOGICAL_LINK_COMPLETE            = 0x0000000000000020,
+       EMP2_HCI_EVENT_DISCONNECT_LOGICAL_LINK_COMPLETE = 0x0000000000000040,
+       EMP2_HCI_EVENT_FLOW_SPEC_MODIFY_COMPLETE        = 0x0000000000000080,
+       EMP2_HCI_EVENT_NUM_OF_COMPLETE_DATA_BLOCKS      = 0x0000000000000100,
+       EMP2_HCI_EVENT_AMP_START_TEST                   = 0x0000000000000200,
+       EMP2_HCI_EVENT_AMP_TEST_END                     = 0x0000000000000400,
+       EMP2_HCI_EVENT_AMP_RECEIVER_REPORT              = 0x0000000000000800,
+       EMP2_HCI_EVENT_SHORT_RANGE_MODE_CHANGE_COMPLETE = 0x0000000000001000,
+       EMP2_HCI_EVENT_AMP_STATUS_CHANGE                = 0x0000000000002000,
+};
+
+enum hci_state_machine {
+       HCI_STATE_STARTING                      = 0x01,
+       HCI_STATE_CONNECTING                    = 0x02,
+       HCI_STATE_AUTHENTICATING                = 0x04,
+       HCI_STATE_CONNECTED                     = 0x08,
+       HCI_STATE_DISCONNECTING                 = 0x10,
+       HCI_STATE_DISCONNECTED                  = 0x20
+};
+
+enum amp_assoc_structure_type {
+       AMP_MAC_ADDR                            = 0x01,
+       AMP_PREFERRED_CHANNEL_LIST              = 0x02,
+       AMP_CONNECTED_CHANNEL                   = 0x03,
+       AMP_80211_PAL_CAP_LIST                  = 0x04,
+       AMP_80211_PAL_VISION                    = 0x05,
+       AMP_RESERVED_FOR_TESTING                = 0x33
+};
+
+enum amp_btap_type {
+       AMP_BTAP_NONE,
+       AMP_BTAP_CREATOR,
+       AMP_BTAP_JOINER
+};
+
+enum hci_state_with_cmd {
+       STATE_CMD_CREATE_PHY_LINK,
+       STATE_CMD_ACCEPT_PHY_LINK,
+       STATE_CMD_DISCONNECT_PHY_LINK,
+       STATE_CMD_CONNECT_ACCEPT_TIMEOUT,
+       STATE_CMD_MAC_START_COMPLETE,
+       STATE_CMD_MAC_START_FAILED,
+       STATE_CMD_MAC_CONNECT_COMPLETE,
+       STATE_CMD_MAC_CONNECT_FAILED,
+       STATE_CMD_MAC_DISCONNECT_INDICATE,
+       STATE_CMD_MAC_CONNECT_CANCEL_INDICATE,
+       STATE_CMD_4WAY_FAILED,
+       STATE_CMD_4WAY_SUCCESSED,
+       STATE_CMD_ENTER_STATE,
+       STATE_CMD_NO_SUCH_CMD,
+};
+
+enum hci_service_type {
+       SERVICE_NO_TRAFFIC,
+       SERVICE_BEST_EFFORT,
+       SERVICE_GUARANTEE
+};
+
+enum hci_traffic_mode {
+       TRAFFIC_MODE_BEST_EFFORT                        = 0x00,
+       TRAFFIC_MODE_GUARANTEED_LATENCY                 = 0x01,
+       TRAFFIC_MODE_GUARANTEED_BANDWIDTH               = 0x02,
+       TRAFFIC_MODE_GUARANTEED_LATENCY_AND_BANDWIDTH   = 0x03
+};
+
+#define HCIOPCODE(_OCF, _OGF)          (_OGF<<10|_OCF)
+#define HCIOPCODELOW(_OCF, _OGF)       (u8)(HCIOPCODE(_OCF, _OGF)&0x00ff)
+#define HCIOPCODEHIGHT(_OCF, _OGF)     (u8)(HCIOPCODE(_OCF, _OGF)>>8)
+
+#define TWOBYTE_HIGHTBYTE(_DATA)       (u8)(_DATA>>8)
+#define TWOBYTE_LOWBYTE(_DATA)         (u8)(_DATA)
+
+enum amp_status {
+       AMP_STATUS_AVA_PHY_PWR_DWN              = 0x0,
+       AMP_STATUS_BT_USE_ONLY                  = 0x1,
+       AMP_STATUS_NO_CAPACITY_FOR_BT           = 0x2,
+       AMP_STATUS_LOW_CAPACITY_FOR_BT          = 0x3,
+       AMP_STATUS_MEDIUM_CAPACITY_FOR_BT       = 0x4,
+       AMP_STATUS_HIGH_CAPACITY_FOR_BT         = 0x5,
+       AMP_STATUS_FULL_CAPACITY_FOR_BT         = 0x6
+};
+
+enum bt_wpa_msg_type {
+       Type_BT_4way1st = 0,
+       Type_BT_4way2nd = 1,
+       Type_BT_4way3rd = 2,
+       Type_BT_4way4th = 3,
+       Type_BT_unknow  = 4
+};
+
+enum bt_connect_type {
+       BT_CONNECT_AUTH_REQ                     = 0x00,
+       BT_CONNECT_AUTH_RSP                     = 0x01,
+       BT_CONNECT_ASOC_REQ                     = 0x02,
+       BT_CONNECT_ASOC_RSP                     = 0x03,
+       BT_DISCONNECT                           = 0x04
+};
+
+enum bt_ll_service_type {
+       BT_LL_BE = 0x01,
+       BT_LL_GU = 0x02
+};
+
+enum bt_ll_flowspec {
+       BT_TX_BE_FS,                    /* TX best effort flowspec */
+       BT_RX_BE_FS,                    /* RX best effort flowspec */
+       BT_TX_GU_FS,                    /* TX guaranteed latency flowspec */
+       BT_RX_GU_FS,                    /* RX guaranteed latency flowspec */
+       BT_TX_BE_AGG_FS,                /* TX aggregated best effort flowspec */
+       BT_RX_BE_AGG_FS,                /* RX aggregated best effort flowspec */
+       BT_TX_GU_BW_FS,                 /* TX guaranteed bandwidth flowspec */
+       BT_RX_GU_BW_FS,                 /* RX guaranteed bandwidth flowspec */
+       BT_TX_GU_LARGE_FS,              /* TX guaranteed latency flowspec, for testing only */
+       BT_RX_GU_LARGE_FS,              /* RX guaranteed latency flowspec, for testing only */
+};
+
+enum bt_traffic_mode {
+       BT_MOTOR_EXT_BE         = 0x00, /* Best Effort. Default. for HCRP, PAN, SDP, RFCOMM-based profiles like FTP, OPP, SPP, DUN, etc. */
+       BT_MOTOR_EXT_GUL        = 0x01, /* Guaranteed Latency. This type of traffic is used e.g. for HID and AVRCP. */
+       BT_MOTOR_EXT_GUB        = 0X02, /* Guaranteed Bandwidth. */
+       BT_MOTOR_EXT_GULB       = 0X03  /* Guaranteed Latency and Bandwidth. for A2DP and VDP. */
+};
+
+enum bt_traffic_mode_profile {
+       BT_PROFILE_NONE,
+       BT_PROFILE_A2DP,
+       BT_PROFILE_PAN,
+       BT_PROFILE_HID,
+       BT_PROFILE_SCO
+};
+
+enum bt_link_role {
+       BT_LINK_MASTER  = 0,
+       BT_LINK_SLAVE   = 1
+};
+
+enum bt_state_wpa_auth {
+       STATE_WPA_AUTH_UNINITIALIZED,
+       STATE_WPA_AUTH_WAIT_PACKET_1, /*  Join */
+       STATE_WPA_AUTH_WAIT_PACKET_2, /*  Creat */
+       STATE_WPA_AUTH_WAIT_PACKET_3,
+       STATE_WPA_AUTH_WAIT_PACKET_4,
+       STATE_WPA_AUTH_SUCCESSED
+};
+
+#define BT_WPA_AUTH_TIMEOUT_PERIOD             1000
+#define BTMaxWPAAuthReTransmitCoun             5
+
+#define MAX_AMP_ASSOC_FRAG_LEN                 248
+#define TOTAL_ALLOCIATE_ASSOC_LEN                      1000
+
+struct hci_flow_spec {
+       u8                              Identifier;
+       u8                              ServiceType;
+       u16                             MaximumSDUSize;
+       u32                             SDUInterArrivalTime;
+       u32                             AccessLatency;
+       u32                             FlushTimeout;
+};
+
+struct hci_log_link_cmd_data {
+       u8                              BtPhyLinkhandle;
+       u16                             BtLogLinkhandle;
+       u8                              BtTxFlowSpecID;
+       struct hci_flow_spec            Tx_Flow_Spec;
+       struct hci_flow_spec            Rx_Flow_Spec;
+       u32                             TxPacketCount;
+       u32                             BestEffortFlushTimeout;
+
+       u8                              bLLCompleteEventIsSet;
+
+       u8                              bLLCancelCMDIsSetandComplete;
+};
+
+struct hci_phy_link_cmd_data {
+       /* Physical_Link_Handle */
+       u8                              BtPhyLinkhandle;
+
+       u16                             LinkSuperversionTimeout;
+
+       /* u16                          SuperTimeOutCnt; */
+
+       /* Dedicated_AMP_Key_Length */
+       u8                              BtAMPKeyLen;
+       /* Dedicated_AMP_Key_Type */
+       u8                              BtAMPKeyType;
+       /* Dedicated_AMP_Key */
+       u8                              BtAMPKey[PMK_LEN];
+};
+
+struct amp_assoc_structure {
+       /* TYPE ID */
+       u8                              TypeID;
+       /* Length */
+       u16                             Length;
+       /* Value */
+       u8                              Data[1];
+};
+
+struct amp_pref_chnl_regulatory {
+       u8                              reXId;
+       u8                              regulatoryClass;
+       u8                              coverageClass;
+};
+
+struct amp_assoc_cmd_data {
+       /* Physical_Link_Handle */
+       u8                              BtPhyLinkhandle;
+       /* Length_So_Far */
+       u16                             LenSoFar;
+
+       u16                             MaxRemoteASSOCLen;
+       /* AMP_ASSOC_Remaining_Length */
+       u16                             AMPAssocRemLen;
+       /* AMP_ASSOC_fragment */
+       void                            *AMPAssocfragment;
+};
+
+struct hci_link_info {
+       u16                             ConnectHandle;
+       u8                              IncomingTrafficMode;
+       u8                              OutgoingTrafficMode;
+       u8                              BTProfile;
+       u8                              BTCoreSpec;
+       s8                              BT_RSSI;
+       u8                              TrafficProfile;
+       u8                              linkRole;
+};
+
+struct hci_ext_config {
+       struct hci_link_info            linkInfo[MAX_BT_ASOC_ENTRY_NUM];
+       u8                              btOperationCode;
+       u16                             CurrentConnectHandle;
+       u8                              CurrentIncomingTrafficMode;
+       u8                              CurrentOutgoingTrafficMode;
+       s8                              MIN_BT_RSSI;
+       u8                              NumberOfHandle;
+       u8                              NumberOfSCO;
+       u8                              CurrentBTStatus;
+       u16                             HCIExtensionVer;
+
+       /* Bt coexist related */
+       u8                              btProfileCase;
+       u8                              btProfileAction;
+       u8                              bManualControl;
+       u8                              bBTBusy;
+       u8                              bBTA2DPBusy;
+       u8                              bEnableWifiScanNotify;
+
+       u8                              bHoldForBtOperation;
+       u32                             bHoldPeriodCnt;
+};
+
+struct hci_acl_packet_data {
+       u16                             ACLDataPacketLen;
+       u8                              SyncDataPacketLen;
+       u16                             TotalNumACLDataPackets;
+       u16                             TotalSyncNumDataPackets;
+};
+
+struct hci_phy_link_bss_info {
+       u16                             bdCap;  /*  capability information */
+};
+
+struct packet_irp_hcicmd_data {
+       u16             OCF:10;
+       u16             OGF:6;
+       u8              Length;
+       u8              Data[20];
+};
+
+struct bt_asoc_entry {
+       u8                                              bUsed;
+       u8                                              mAssoc;
+       u8                                              b4waySuccess;
+       u8                                              Bssid[6];
+       struct hci_phy_link_cmd_data            PhyLinkCmdData;
+
+       struct hci_log_link_cmd_data            LogLinkCmdData[MAX_LOGICAL_LINK_NUM];
+
+       struct hci_acl_packet_data                      ACLPacketsData;
+
+       struct amp_assoc_cmd_data               AmpAsocCmdData;
+       struct octet_string                             BTSsid;
+       u8                                              BTSsidBuf[33];
+
+       enum hci_status                                         PhyLinkDisconnectReason;
+
+       u8                                              bSendSupervisionPacket;
+       /* u8                                           CurrentSuervisionPacketSendNum; */
+       /* u8                                           LastSuervisionPacketSendNum; */
+       u32                                             NoRxPktCnt;
+       /* Is Creator or Joiner */
+       enum amp_btap_type                              AMPRole;
+
+       /* BT current state */
+       u8                                              BtCurrentState;
+       /* BT next state */
+       u8                                              BtNextState;
+
+       u8                                              bNeedPhysLinkCompleteEvent;
+
+       enum hci_status                                 PhysLinkCompleteStatus;
+
+       u8                                              BTRemoteMACAddr[6];
+
+       u32                                             BTCapability;
+
+       u8                                              SyncDataPacketLen;
+
+       u16                                             TotalSyncNumDataPackets;
+       u16                                             TotalNumACLDataPackets;
+
+       u8                                              ShortRangeMode;
+
+       u8                                              PTK[PTK_LEN_TKIP];
+       u8                                              GTK[GTK_LEN];
+       u8                                              ANonce[KEY_NONCE_LEN];
+       u8                                              SNonce[KEY_NONCE_LEN];
+       u64                                             KeyReplayCounter;
+       u8                                              WPAAuthReplayCount;
+       u8                                              AESKeyBuf[AESCCMP_BLK_SIZE_TOTAL];
+       u8                                              PMK[PMK_LEN];
+       enum bt_state_wpa_auth                  BTWPAAuthState;
+       s32                                             UndecoratedSmoothedPWDB;
+
+       /*  Add for HW security !! */
+       u8                                              HwCAMIndex;  /*  Cam index */
+       u8                                              bPeerQosSta;
+
+       u32                                             rxSuvpPktCnt;
+};
+
+struct bt_traffic_statistics {
+       u8                              bTxBusyTraffic;
+       u8                              bRxBusyTraffic;
+       u8                              bIdle;
+       u32                             TxPktCntInPeriod;
+       u32                             RxPktCntInPeriod;
+       u64                             TxPktLenInPeriod;
+       u64                             RxPktLenInPeriod;
+};
+
+struct bt_mgnt {
+       u8                              bBTConnectInProgress;
+       u8                              bLogLinkInProgress;
+       u8                              bPhyLinkInProgress;
+       u8                              bPhyLinkInProgressStartLL;
+       u8                              BtCurrentPhyLinkhandle;
+       u16                             BtCurrentLogLinkhandle;
+       u8                              CurrentConnectEntryNum;
+       u8                              DisconnectEntryNum;
+       u8                              CurrentBTConnectionCnt;
+       enum bt_connect_type            BTCurrentConnectType;
+       enum bt_connect_type            BTReceiveConnectPkt;
+       u8                              BTAuthCount;
+       u8                              BTAsocCount;
+       u8                              bStartSendSupervisionPkt;
+       u8                              BtOperationOn;
+       u8                              BTNeedAMPStatusChg;
+       u8                              JoinerNeedSendAuth;
+       struct hci_phy_link_bss_info    bssDesc;
+       struct hci_ext_config           ExtConfig;
+       u8                              bNeedNotifyAMPNoCap;
+       u8                              bCreateSpportQos;
+       u8                              bSupportProfile;
+       u8                              BTChannel;
+       u8                              CheckChnlIsSuit;
+       u8                              bBtScan;
+       u8                              btLogoTest;
+};
+
+struct bt_hci_dgb_info {
+       u32                             hciCmdCnt;
+       u32                             hciCmdCntUnknown;
+       u32                             hciCmdCntCreatePhyLink;
+       u32                             hciCmdCntAcceptPhyLink;
+       u32                             hciCmdCntDisconnectPhyLink;
+       u32                             hciCmdPhyLinkStatus;
+       u32                             hciCmdCntCreateLogLink;
+       u32                             hciCmdCntAcceptLogLink;
+       u32                             hciCmdCntDisconnectLogLink;
+       u32                             hciCmdCntReadLocalAmpAssoc;
+       u32                             hciCmdCntWriteRemoteAmpAssoc;
+       u32                             hciCmdCntSetAclLinkStatus;
+       u32                             hciCmdCntSetScoLinkStatus;
+       u32                             hciCmdCntExtensionVersionNotify;
+       u32                             hciCmdCntLinkStatusNotify;
+};
+
+struct bt_irp_dgb_info {
+       u32                             irpMJCreate;
+       /*  Io Control */
+       u32                             irpIoControl;
+       u32                             irpIoCtrlHciCmd;
+       u32                             irpIoCtrlHciEvent;
+       u32                             irpIoCtrlHciTxData;
+       u32                             irpIoCtrlHciRxData;
+       u32                             irpIoCtrlUnknown;
+
+       u32                             irpIoCtrlHciTxData1s;
+};
+
+struct bt_packet_dgb_info {
+       u32                             btPktTxProbReq;
+       u32                             btPktRxProbReq;
+       u32                             btPktRxProbReqFail;
+       u32                             btPktTxProbRsp;
+       u32                             btPktRxProbRsp;
+       u32                             btPktTxAuth;
+       u32                             btPktRxAuth;
+       u32                             btPktRxAuthButDrop;
+       u32                             btPktTxAssocReq;
+       u32                             btPktRxAssocReq;
+       u32                             btPktRxAssocReqButDrop;
+       u32                             btPktTxAssocRsp;
+       u32                             btPktRxAssocRsp;
+       u32                             btPktTxDisassoc;
+       u32                             btPktRxDisassoc;
+       u32                             btPktRxDeauth;
+       u32                             btPktTx4way1st;
+       u32                             btPktRx4way1st;
+       u32                             btPktTx4way2nd;
+       u32                             btPktRx4way2nd;
+       u32                             btPktTx4way3rd;
+       u32                             btPktRx4way3rd;
+       u32                             btPktTx4way4th;
+       u32                             btPktRx4way4th;
+       u32                             btPktTxLinkSuperReq;
+       u32                             btPktRxLinkSuperReq;
+       u32                             btPktTxLinkSuperRsp;
+       u32                             btPktRxLinkSuperRsp;
+       u32                             btPktTxData;
+       u32                             btPktRxData;
+};
+
+struct bt_dgb {
+       u8                              dbgCtrl;
+       u32                             dbgProfile;
+       struct bt_hci_dgb_info          dbgHciInfo;
+       struct bt_irp_dgb_info          dbgIrpInfo;
+       struct bt_packet_dgb_info       dbgBtPkt;
+};
+
+struct bt_hci_info {
+       /* 802.11 Pal version specifier */
+       u8                              BTPalVersion;
+       u16                             BTPalCompanyID;
+       u16                             BTPalsubversion;
+
+       /* Connected channel list */
+       u16                             BTConnectChnlListLen;
+       u8                              BTConnectChnllist[64];
+
+       /* Fail contact counter */
+       u16                             FailContactCount;
+
+       /* Event mask */
+       u64                             BTEventMask;
+       u64                             BTEventMaskPage2;
+
+       /* timeout var */
+       u16                             ConnAcceptTimeout;
+       u16                             LogicalAcceptTimeout;
+       u16                             PageTimeout;
+
+       u8                              LocationDomainAware;
+       u16                             LocationDomain;
+       u8                              LocationDomainOptions;
+       u8                              LocationOptions;
+
+       u8                              FlowControlMode;
+
+       /* Preferred channel list */
+       u16                             BtPreChnlListLen;
+       u8                              BTPreChnllist[64];
+
+       u16                             enFlush_LLH;    /* enhanced flush handle */
+       u16                             FLTO_LLH;               /* enhanced flush handle */
+
+       /*  */
+       /* Test command only. */
+       u8                              bInTestMode;
+       u8                              bTestIsEnd;
+       u8                              bTestNeedReport;
+       u8                              TestScenario;
+       u8                              TestReportInterval;
+       u8                              TestCtrType;
+       u32                             TestEventType;
+       u16                             TestNumOfFrame;
+       u16                             TestNumOfErrFrame;
+       u16                             TestNumOfBits;
+       u16                             TestNumOfErrBits;
+       /*  */
+};
+
+struct bt_traffic {
+       /*  Add for check replay data */
+       u8                                      LastRxUniFragNum;
+       u16                                     LastRxUniSeqNum;
+
+       /* s32                                  EntryMaxUndecoratedSmoothedPWDB; */
+       /* s32                                  EntryMinUndecoratedSmoothedPWDB; */
+
+       struct bt_traffic_statistics            Bt30TrafficStatistics;
+};
+
+#define RT_WORK_ITEM struct work_struct
+
+struct bt_security {
+       /*  WPA auth state
+        *  May need to remove to BTSecInfo ... 
+        * enum bt_state_wpa_auth BTWPAAuthState;
+        */
+       struct octet_string     RSNIE;
+       u8                      RSNIEBuf[MAXRSNIELEN];
+       u8                      bRegNoEncrypt;
+       u8                      bUsedHwEncrypt;
+};
+
+struct bt_30info {
+       struct rtw_adapter      *padapter;
+       struct bt_asoc_entry            BtAsocEntry[MAX_BT_ASOC_ENTRY_NUM];
+       struct bt_mgnt                          BtMgnt;
+       struct bt_dgb                           BtDbg;
+       struct bt_hci_info                      BtHciInfo;
+       struct bt_traffic                       BtTraffic;
+       struct bt_security                      BtSec;
+       RT_WORK_ITEM            HCICmdWorkItem;
+       struct timer_list BTHCICmdTimer;
+       RT_WORK_ITEM            BTPsDisableWorkItem;
+       RT_WORK_ITEM            BTConnectWorkItem;
+       struct timer_list BTHCIDiscardAclDataTimer;
+       struct timer_list BTHCIJoinTimeoutTimer;
+       struct timer_list BTTestSendPacketTimer;
+       struct timer_list BTDisconnectPhyLinkTimer;
+       struct timer_list BTBeaconTimer;
+       u8                              BTBeaconTmrOn;
+
+       struct timer_list BTPsDisableTimer;
+
+       void *                          pBtChnlList;
+};
+
+struct packet_irp_acl_data {
+       u16             Handle:12;
+       u16             PB_Flag:2;
+       u16             BC_Flag:2;
+       u16             Length;
+       u8              Data[1];
+};
+
+struct packet_irp_hcievent_data {
+       u8              EventCode;
+       u8              Length;
+       u8              Data[20];
+};
+
+struct common_triple {
+       u8 byte_1st;
+       u8 byte_2nd;
+       u8 byte_3rd;
+};
+
+#define COUNTRY_STR_LEN                3       /*  country string len = 3 */
+
+#define LOCAL_PMK      0
+
+enum hci_wifi_connect_status {
+       HCI_WIFI_NOT_CONNECTED                  = 0x0,
+       HCI_WIFI_CONNECTED                      = 0x1,
+       HCI_WIFI_CONNECT_IN_PROGRESS            = 0x2,
+};
+
+enum hci_ext_bp_operation {
+       HCI_BT_OP_NONE                          = 0x0,
+       HCI_BT_OP_INQUIRY_START                 = 0x1,
+       HCI_BT_OP_INQUIRY_FINISH                = 0x2,
+       HCI_BT_OP_PAGING_START                  = 0x3,
+       HCI_BT_OP_PAGING_SUCCESS                = 0x4,
+       HCI_BT_OP_PAGING_UNSUCCESS              = 0x5,
+       HCI_BT_OP_PAIRING_START                 = 0x6,
+       HCI_BT_OP_PAIRING_FINISH                = 0x7,
+       HCI_BT_OP_BT_DEV_ENABLE                 = 0x8,
+       HCI_BT_OP_BT_DEV_DISABLE                = 0x9,
+       HCI_BT_OP_MAX
+};
+
+/*     Function proto type */
+struct btdata_entry {
+       struct list_head        List;
+       void                    *pDataBlock;
+};
+
+#define BTHCI_SM_WITH_INFO(_Adapter, _StateToEnter, _StateCmd, _EntryNum)      \
+{                                                                              \
+       RTPRINT(FIOCTL, IOCTL_STATE, ("[BT state change] caused by ""%s"", line =%d\n", __FUNCTION__, __LINE__));                                                       \
+       BTHCI_StateMachine(_Adapter, _StateToEnter, _StateCmd, _EntryNum);\
+}
+
+void BTHCI_EventParse(struct rtw_adapter * padapter, void *pEvntData, u32 dataLen);
+#define BT_EventParse BTHCI_EventParse
+u8 BTHCI_HsConnectionEstablished(struct rtw_adapter * padapter);
+void BTHCI_UpdateBTProfileRTKToMoto(struct rtw_adapter * padapter);
+void BTHCI_WifiScanNotify(struct rtw_adapter * padapter, u8 scanType);
+void BTHCI_StateMachine(struct rtw_adapter * padapter, u8 StateToEnter, enum hci_state_with_cmd StateCmd, u8 EntryNum);
+void BTHCI_DisconnectPeer(struct rtw_adapter * padapter, u8 EntryNum);
+void BTHCI_EventNumOfCompletedDataBlocks(struct rtw_adapter * padapter);
+void BTHCI_EventAMPStatusChange(struct rtw_adapter * padapter, u8 AMP_Status);
+void BTHCI_DisconnectAll(struct rtw_adapter * padapter);
+enum hci_status BTHCI_HandleHCICMD(struct rtw_adapter * padapter, struct packet_irp_hcicmd_data *pHciCmd);
+
+/*  ===== End of sync from SD7 driver COMMON/bt_hci.h ===== */
+#endif /*  __BT_HCI_C__ */
+
+#ifdef __HALBTC87231ANT_C__ /*  HAL/BTCoexist/HalBtc87231Ant.h */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.h ===== */
+#define GET_BT_INFO(padapter)  (&GET_HAL_DATA(padapter)->BtInfo)
+
+#define        BTC_FOR_SCAN_START                              1
+#define        BTC_FOR_SCAN_FINISH                             0
+
+#define        BT_TXRX_CNT_THRES_1                             1200
+#define        BT_TXRX_CNT_THRES_2                             1400
+#define        BT_TXRX_CNT_THRES_3                             3000
+#define        BT_TXRX_CNT_LEVEL_0                             0       /*  < 1200 */
+#define        BT_TXRX_CNT_LEVEL_1                             1       /*  >= 1200 && < 1400 */
+#define        BT_TXRX_CNT_LEVEL_2                             2       /*  >= 1400 */
+#define        BT_TXRX_CNT_LEVEL_3                             3       /*  >= 3000 */
+
+enum bt_state_1ant {
+       BT_INFO_STATE_DISABLED                  = 0,
+       BT_INFO_STATE_NO_CONNECTION             = 1,
+       BT_INFO_STATE_CONNECT_IDLE              = 2,
+       BT_INFO_STATE_INQ_OR_PAG                = 3,
+       BT_INFO_STATE_ACL_ONLY_BUSY             = 4,
+       BT_INFO_STATE_SCO_ONLY_BUSY             = 5,
+       BT_INFO_STATE_ACL_SCO_BUSY              = 6,
+       BT_INFO_STATE_ACL_INQ_OR_PAG            = 7,
+       BT_INFO_STATE_MAX                       = 8
+};
+
+struct btdm_8723a_1ant {
+       u8              prePsTdma;
+       u8              curPsTdma;
+       u8              psTdmaDuAdjType;
+       u8              bPrePsTdmaOn;
+       u8              bCurPsTdmaOn;
+       u8              preWifiPara;
+       u8              curWifiPara;
+       u8              preCoexWifiCon;
+       u8              curCoexWifiCon;
+       u8              wifiRssiThresh;
+
+       u32             psTdmaMonitorCnt;
+       u32             psTdmaGlobalCnt;
+
+       /* DurationAdjust For SCO */
+       u32             psTdmaMonitorCntForSCO;
+       u8              psTdmaDuAdjTypeForSCO;
+       u8              RSSI_WiFi_Last;
+       u8              RSSI_BT_Last;
+
+       u8              bWiFiHalt;
+       u8              bRAChanged;
+};
+
+void BTDM_1AntSignalCompensation(struct rtw_adapter * padapter, u8 *rssi_wifi, u8 *rssi_bt);
+void BTDM_1AntForDhcp(struct rtw_adapter * padapter);
+void BTDM_1AntBtCoexist8723A(struct rtw_adapter * padapter);
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.h ===== */
+#endif /*  __HALBTC87231ANT_C__ */
+
+#ifdef __HALBTC87232ANT_C__ /*  HAL/BTCoexist/HalBtc87232Ant.h */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.h ===== */
+enum bt_2ant_bt_status {
+       BT_2ANT_BT_STATUS_IDLE                  = 0x0,
+       BT_2ANT_BT_STATUS_CONNECTED_IDLE        = 0x1,
+       BT_2ANT_BT_STATUS_NON_IDLE              = 0x2,
+       BT_2ANT_BT_STATUS_MAX
+};
+
+enum bt_2ant_coex_algo {
+       BT_2ANT_COEX_ALGO_UNDEFINED                     = 0x0,
+       BT_2ANT_COEX_ALGO_SCO                           = 0x1,
+       BT_2ANT_COEX_ALGO_HID                           = 0x2,
+       BT_2ANT_COEX_ALGO_A2DP                          = 0x3,
+       BT_2ANT_COEX_ALGO_PANEDR                        = 0x4,
+       BT_2ANT_COEX_ALGO_PANHS                         = 0x5,
+       BT_2ANT_COEX_ALGO_PANEDR_A2DP           = 0x6,
+       BT_2ANT_COEX_ALGO_PANEDR_HID            = 0x7,
+       BT_2ANT_COEX_ALGO_HID_A2DP_PANEDR       = 0x8,
+       BT_2ANT_COEX_ALGO_HID_A2DP                      = 0x9,
+       BT_2ANT_COEX_ALGO_HID_A2DP_PANHS        = 0xA,
+       BT_2ANT_COEX_ALGO_MAX                           = 0xB,
+};
+
+struct btdm_8723a_2ant {
+       u8      bPreDecBtPwr;
+       u8      bCurDecBtPwr;
+
+       u8      preWlanActHi;
+       u8      curWlanActHi;
+       u8      preWlanActLo;
+       u8      curWlanActLo;
+
+       u8      preFwDacSwingLvl;
+       u8      curFwDacSwingLvl;
+
+       u8      bPreRfRxLpfShrink;
+       u8      bCurRfRxLpfShrink;
+
+       u8      bPreLowPenaltyRa;
+       u8      bCurLowPenaltyRa;
+
+       u8      preBtRetryIndex;
+       u8      curBtRetryIndex;
+
+       u8      bPreDacSwingOn;
+       u32     preDacSwingLvl;
+       u8      bCurDacSwingOn;
+       u32     curDacSwingLvl;
+
+       u8      bPreAdcBackOff;
+       u8      bCurAdcBackOff;
+
+       u8      bPreAgcTableEn;
+       u8      bCurAgcTableEn;
+
+       u32     preVal0x6c0;
+       u32     curVal0x6c0;
+       u32     preVal0x6c8;
+       u32     curVal0x6c8;
+       u8      preVal0x6cc;
+       u8      curVal0x6cc;
+
+       u8      bCurIgnoreWlanAct;
+       u8      bPreIgnoreWlanAct;
+
+       u8      prePsTdma;
+       u8      curPsTdma;
+       u8      psTdmaDuAdjType;
+       u8      bPrePsTdmaOn;
+       u8      bCurPsTdmaOn;
+
+       u8      preAlgorithm;
+       u8      curAlgorithm;
+       u8      bResetTdmaAdjust;
+
+       u8      btStatus;
+};
+
+void BTDM_2AntBtCoexist8723A(struct rtw_adapter * padapter);
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.h ===== */
+#endif /*  __HALBTC87232ANT_C__ */
+
+#ifdef __HALBTC8723_C__ /*  HAL/BTCoexist/HalBtc8723.h */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== */
+
+#define        BT_Q_PKT_OFF            0
+#define        BT_Q_PKT_ON             1
+
+#define        BT_TX_PWR_OFF           0
+#define        BT_TX_PWR_ON            1
+
+/*  TDMA mode definition */
+#define        TDMA_2ANT                       0
+#define        TDMA_1ANT                       1
+#define        TDMA_NAV_OFF            0
+#define        TDMA_NAV_ON             1
+#define        TDMA_DAC_SWING_OFF      0
+#define        TDMA_DAC_SWING_ON       1
+
+#define        BT_RSSI_LEVEL_H 0
+#define        BT_RSSI_LEVEL_M 1
+#define        BT_RSSI_LEVEL_L 2
+
+/*  PTA mode related definition */
+#define        BT_PTA_MODE_OFF         0
+#define        BT_PTA_MODE_ON          1
+
+/*  Penalty Tx Rate Adaptive */
+#define        BT_TX_RATE_ADAPTIVE_NORMAL                      0
+#define        BT_TX_RATE_ADAPTIVE_LOW_PENALTY 1
+
+/*  RF Corner */
+#define        BT_RF_RX_LPF_CORNER_RESUME                      0
+#define        BT_RF_RX_LPF_CORNER_SHRINK                      1
+
+#define BT_INFO_ACL                    BIT(0)
+#define BT_INFO_SCO                    BIT(1)
+#define BT_INFO_INQ_PAG                BIT(2)
+#define BT_INFO_ACL_BUSY       BIT(3)
+#define BT_INFO_SCO_BUSY       BIT(4)
+#define BT_INFO_HID                    BIT(5)
+#define BT_INFO_A2DP           BIT(6)
+#define BT_INFO_FTP                    BIT(7)
+
+
+
+struct bt_coexist_8723a {
+       u32                                     highPriorityTx;
+       u32                                     highPriorityRx;
+       u32                                     lowPriorityTx;
+       u32                                     lowPriorityRx;
+       u8                                      btRssi;
+       u8                                      TotalAntNum;
+       u8                                      bC2hBtInfoSupport;
+       u8                                      c2hBtInfo;
+       u8                                      c2hBtInfoOriginal;
+       u8                                      prec2hBtInfo; /*  for 1Ant */
+       u8                                      bC2hBtInquiryPage;
+       unsigned long                           btInqPageStartTime; /*  for 2Ant */
+       u8                                      c2hBtProfile; /*  for 1Ant */
+       u8                                      btRetryCnt;
+       u8                                      btInfoExt;
+       u8                                      bC2hBtInfoReqSent;
+       u8                                      bForceFwBtInfo;
+       u8                                      bForceA2dpSink;
+       struct btdm_8723a_2ant                  btdm2Ant;
+       struct btdm_8723a_1ant                  btdm1Ant;
+};
+
+void BTDM_SetFwChnlInfo(struct rtw_adapter * padapter, enum rt_media_status mstatus);
+u8 BTDM_IsWifiConnectionExist(struct rtw_adapter * padapter);
+void BTDM_SetFw3a(struct rtw_adapter * padapter, u8 byte1, u8 byte2, u8 byte3, u8 byte4, u8 byte5);
+void BTDM_QueryBtInformation(struct rtw_adapter * padapter);
+void BTDM_SetSwRfRxLpfCorner(struct rtw_adapter * padapter, u8 type);
+void BTDM_SetSwPenaltyTxRateAdaptive(struct rtw_adapter * padapter, u8 raType);
+void BTDM_SetFwDecBtPwr(struct rtw_adapter * padapter, u8 bDecBtPwr);
+u8 BTDM_BtProfileSupport(struct rtw_adapter * padapter);
+void BTDM_LpsLeave(struct rtw_adapter * padapter);
+u8 BTDM_1Ant8723A(struct rtw_adapter * padapter);
+#define BT_1Ant BTDM_1Ant8723A
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== */
+#endif /*  __HALBTC8723_C__ */
+
+#ifdef __HALBTCCSR1ANT_C__ /*  HAL/BTCoexist/HalBtcCsr1Ant.h */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.h ===== */
+
+enum BT_A2DP_INDEX{
+       BT_A2DP_INDEX0          = 0,                    /*  32, 12; the most critical for BT */
+       BT_A2DP_INDEX1,                                 /*  12, 24 */
+       BT_A2DP_INDEX2,                                 /*  0, 0 */
+       BT_A2DP_INDEX_MAX
+};
+
+#define BT_A2DP_STATE_NOT_ENTERED              0
+#define BT_A2DP_STATE_DETECTING                1
+#define BT_A2DP_STATE_DETECTED                 2
+
+#define BTDM_ANT_BT_IDLE                               0
+#define BTDM_ANT_WIFI                                  1
+#define BTDM_ANT_BT                                            2
+
+
+void BTDM_SingleAnt(struct rtw_adapter * padapter, u8 bSingleAntOn, u8 bInterruptOn, u8 bMultiNAVOn);
+void BTDM_CheckBTIdleChange1Ant(struct rtw_adapter * padapter);
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.h ===== */
+#endif /*  __HALBTCCSR1ANT_C__ */
+
+#ifdef __HALBTCCSR2ANT_C__ /*  HAL/BTCoexist/HalBtcCsr2Ant.h */
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.h ===== */
+
+/*  */
+/*  For old core stack before v251 */
+/*  */
+#define BT_RSSI_STATE_NORMAL_POWER     BIT0
+#define BT_RSSI_STATE_AMDPU_OFF                BIT1
+#define BT_RSSI_STATE_SPECIAL_LOW      BIT2
+#define BT_RSSI_STATE_BG_EDCA_LOW      BIT3
+#define BT_RSSI_STATE_TXPOWER_LOW      BIT4
+
+#define        BT_DACSWING_OFF                         0
+#define        BT_DACSWING_M4                          1
+#define        BT_DACSWING_M7                          2
+#define        BT_DACSWING_M10                         3
+
+void BTDM_DiminishWiFi(struct rtw_adapter * Adapter, u8 bDACOn, u8 bInterruptOn, u8 DACSwingLevel, u8 bNAVOn);
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.h ===== */
+#endif /*  __HALBTCCSR2ANT_C__ */
+
+#ifdef __HALBTCOEXIST_C__ /*  HAL/BTCoexist/HalBtCoexist.h */
+
+/*  HEADER/TypeDef.h */
+#define MAX_FW_SUPPORT_MACID_NUM                       64
+
+/*  ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtCoexist.h ===== */
+
+#define        FW_VER_BT_REG                   62
+#define        FW_VER_BT_REG1          74
+#define        REG_BT_ACTIVE                   0x444
+#define        REG_BT_STATE                    0x448
+#define        REG_BT_POLLING1         0x44c
+#define        REG_BT_POLLING                  0x700
+
+#define        REG_BT_ACTIVE_OLD               0x488
+#define        REG_BT_STATE_OLD                0x48c
+#define        REG_BT_POLLING_OLD      0x490
+
+/*  The reg define is for 8723 */
+#define        REG_HIGH_PRIORITY_TXRX                  0x770
+#define        REG_LOW_PRIORITY_TXRX                   0x774
+
+#define BT_FW_COEX_THRESH_TOL                  6
+#define BT_FW_COEX_THRESH_20                           20
+#define BT_FW_COEX_THRESH_23                           23
+#define BT_FW_COEX_THRESH_25                           25
+#define BT_FW_COEX_THRESH_30                           30
+#define BT_FW_COEX_THRESH_35                           35
+#define BT_FW_COEX_THRESH_40                           40
+#define BT_FW_COEX_THRESH_45                           45
+#define BT_FW_COEX_THRESH_47                           47
+#define BT_FW_COEX_THRESH_50                           50
+#define BT_FW_COEX_THRESH_55                           55
+#define BT_FW_COEX_THRESH_65                           65
+
+#define BT_COEX_STATE_BT30                                     BIT(0)
+#define BT_COEX_STATE_WIFI_HT20                        BIT(1)
+#define BT_COEX_STATE_WIFI_HT40                        BIT(2)
+#define BT_COEX_STATE_WIFI_LEGACY                      BIT(3)
+
+#define BT_COEX_STATE_WIFI_RSSI_LOW            BIT(4)
+#define BT_COEX_STATE_WIFI_RSSI_MEDIUM BIT(5)
+#define BT_COEX_STATE_WIFI_RSSI_HIGH           BIT(6)
+#define BT_COEX_STATE_DEC_BT_POWER             BIT(7)
+
+#define BT_COEX_STATE_WIFI_IDLE                        BIT(8)
+#define BT_COEX_STATE_WIFI_UPLINK                      BIT(9)
+#define BT_COEX_STATE_WIFI_DOWNLINK            BIT(10)
+
+#define BT_COEX_STATE_BT_INQ_PAGE      BIT(11)
+#define BT_COEX_STATE_BT_IDLE                          BIT(12)
+#define BT_COEX_STATE_BT_UPLINK                        BIT(13)
+#define BT_COEX_STATE_BT_DOWNLINK              BIT(14)
+/*  */
+/*  Todo: Remove these definitions */
+#define BT_COEX_STATE_BT_PAN_IDLE                      BIT(15)
+#define BT_COEX_STATE_BT_PAN_UPLINK            BIT(16)
+#define BT_COEX_STATE_BT_PAN_DOWNLINK  BIT(17)
+#define BT_COEX_STATE_BT_A2DP_IDLE             BIT(18)
+/*  */
+#define BT_COEX_STATE_BT_RSSI_LOW                      BIT(19)
+
+#define BT_COEX_STATE_PROFILE_HID                      BIT(20)
+#define BT_COEX_STATE_PROFILE_A2DP             BIT(21)
+#define BT_COEX_STATE_PROFILE_PAN                      BIT(22)
+#define BT_COEX_STATE_PROFILE_SCO                      BIT(23)
+
+#define BT_COEX_STATE_WIFI_RSSI_1_LOW          BIT(24)
+#define BT_COEX_STATE_WIFI_RSSI_1_MEDIUM       BIT(25)
+#define BT_COEX_STATE_WIFI_RSSI_1_HIGH         BIT(26)
+
+#define BT_COEX_STATE_WIFI_RSSI_BEACON_LOW             BIT(27)
+#define BT_COEX_STATE_WIFI_RSSI_BEACON_MEDIUM          BIT(28)
+#define BT_COEX_STATE_WIFI_RSSI_BEACON_HIGH            BIT(29)
+
+
+#define BT_COEX_STATE_BTINFO_COMMON                            BIT30
+#define BT_COEX_STATE_BTINFO_B_HID_SCOESCO             BIT31
+#define BT_COEX_STATE_BTINFO_B_FTP_A2DP                        BIT32
+
+#define BT_COEX_STATE_BT_CNT_LEVEL_0                           BIT33
+#define BT_COEX_STATE_BT_CNT_LEVEL_1                           BIT34
+#define BT_COEX_STATE_BT_CNT_LEVEL_2                           BIT35
+#define BT_COEX_STATE_BT_CNT_LEVEL_3                           BIT36
+
+#define BT_RSSI_STATE_HIGH                                     0
+#define BT_RSSI_STATE_MEDIUM                           1
+#define BT_RSSI_STATE_LOW                                      2
+#define BT_RSSI_STATE_STAY_HIGH                        3
+#define BT_RSSI_STATE_STAY_MEDIUM                      4
+#define BT_RSSI_STATE_STAY_LOW                 5
+
+#define        BT_AGCTABLE_OFF                         0
+#define        BT_AGCTABLE_ON                          1
+
+#define        BT_BB_BACKOFF_OFF                       0
+#define        BT_BB_BACKOFF_ON                        1
+
+#define        BT_FW_NAV_OFF                           0
+#define        BT_FW_NAV_ON                            1
+
+#define        BT_COEX_MECH_NONE                       0
+#define        BT_COEX_MECH_SCO                        1
+#define        BT_COEX_MECH_HID                        2
+#define        BT_COEX_MECH_A2DP                       3
+#define        BT_COEX_MECH_PAN                        4
+#define        BT_COEX_MECH_HID_A2DP                   5
+#define        BT_COEX_MECH_HID_PAN                    6
+#define        BT_COEX_MECH_PAN_A2DP                   7
+#define        BT_COEX_MECH_HID_SCO_ESCO               8
+#define        BT_COEX_MECH_FTP_A2DP                   9
+#define        BT_COEX_MECH_COMMON                     10
+#define        BT_COEX_MECH_MAX                        11
+/*     BT Dbg Ctrl */
+#define        BT_DBG_PROFILE_NONE                     0
+#define        BT_DBG_PROFILE_SCO                      1
+#define        BT_DBG_PROFILE_HID                      2
+#define        BT_DBG_PROFILE_A2DP                     3
+#define        BT_DBG_PROFILE_PAN                      4
+#define        BT_DBG_PROFILE_HID_A2DP                 5
+#define        BT_DBG_PROFILE_HID_PAN                  6
+#define        BT_DBG_PROFILE_PAN_A2DP                 7
+#define        BT_DBG_PROFILE_MAX                      9
+
+struct bt_coexist_str {
+       u8                      BluetoothCoexist;
+       u8                      BT_Ant_Num;
+       u8                      BT_CoexistType;
+       u8                      BT_Ant_isolation;       /* 0:good, 1:bad */
+       u8                      bt_radiosharedtype;
+       u32                     Ratio_Tx;
+       u32                     Ratio_PRI;
+       u8                      bInitlized;
+       u32                     BtRfRegOrigin1E;
+       u32                     BtRfRegOrigin1F;
+       u8                      bBTBusyTraffic;
+       u8                      bBTTrafficModeSet;
+       u8                      bBTNonTrafficModeSet;
+       struct bt_traffic_statistics            BT21TrafficStatistics;
+       u64                     CurrentState;
+       u64                     PreviousState;
+       u8                      preRssiState;
+       u8                      preRssiState1;
+       u8                      preRssiStateBeacon;
+       u8                      bFWCoexistAllOff;
+       u8                      bSWCoexistAllOff;
+       u8                      bHWCoexistAllOff;
+       u8                      bBalanceOn;
+       u8                      bSingleAntOn;
+       u8                      bInterruptOn;
+       u8                      bMultiNAVOn;
+       u8                      PreWLANActH;
+       u8                      PreWLANActL;
+       u8                      WLANActH;
+       u8                      WLANActL;
+       u8                      A2DPState;
+       u8                      AntennaState;
+       u32                     lastBtEdca;
+       u16                     last_aggr_num;
+       u8                      bEDCAInitialized;
+       u8                      exec_cnt;
+       u8                      b8723aAgcTableOn;
+       u8                      b92DAgcTableOn;
+       struct bt_coexist_8723a halCoex8723;
+       u8                      btActiveZeroCnt;
+       u8                      bCurBtDisabled;
+       u8                      bPreBtDisabled;
+       u8                      bNeedToRoamForBtDisableEnable;
+       u8                      fw3aVal[5];
+};
+
+void BTDM_CheckAntSelMode(struct rtw_adapter * padapter);
+void BTDM_FwC2hBtRssi(struct rtw_adapter * padapter, u8 *tmpBuf);
+#define BT_FwC2hBtRssi BTDM_FwC2hBtRssi
+void BTDM_FwC2hBtInfo(struct rtw_adapter * padapter, u8 *tmpBuf, u8 length);
+#define BT_FwC2hBtInfo BTDM_FwC2hBtInfo
+void BTDM_DisplayBtCoexInfo(struct rtw_adapter * padapter);
+#define BT_DisplayBtCoexInfo BTDM_DisplayBtCoexInfo
+void BTDM_RejectAPAggregatedPacket(struct rtw_adapter * padapter, u8 bReject);
+u8 BTDM_IsHT40(struct rtw_adapter * padapter);
+u8 BTDM_Legacy(struct rtw_adapter * padapter);
+void BTDM_CheckWiFiState(struct rtw_adapter * padapter);
+s32 BTDM_GetRxSS(struct rtw_adapter * padapter);
+u8 BTDM_CheckCoexBcnRssiState(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1);
+u8 BTDM_CheckCoexRSSIState1(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1);
+u8 BTDM_CheckCoexRSSIState(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1);
+u8 BTDM_DisableEDCATurbo(struct rtw_adapter * padapter);
+#define BT_DisableEDCATurbo BTDM_DisableEDCATurbo
+void BTDM_Balance(struct rtw_adapter * padapter, u8 bBalanceOn, u8 ms0, u8 ms1);
+void BTDM_AGCTable(struct rtw_adapter * padapter, u8 type);
+void BTDM_BBBackOffLevel(struct rtw_adapter * padapter, u8 type);
+void BTDM_FWCoexAllOff(struct rtw_adapter * padapter);
+void BTDM_SWCoexAllOff(struct rtw_adapter * padapter);
+void BTDM_HWCoexAllOff(struct rtw_adapter * padapter);
+void BTDM_CoexAllOff(struct rtw_adapter * padapter);
+void BTDM_TurnOffBtCoexistBeforeEnterIPS(struct rtw_adapter * padapter);
+void BTDM_SignalCompensation(struct rtw_adapter * padapter, u8 *rssi_wifi, u8 *rssi_bt);
+void BTDM_Coexist(struct rtw_adapter * padapter);
+#define BT_CoexistMechanism BTDM_Coexist
+void BTDM_UpdateCoexState(struct rtw_adapter * padapter);
+u8 BTDM_IsSameCoexistState(struct rtw_adapter * padapter);
+void BTDM_PWDBMonitor(struct rtw_adapter * padapter);
+u8 BTDM_IsBTBusy(struct rtw_adapter * padapter);
+#define BT_IsBtBusy BTDM_IsBTBusy
+u8 BTDM_IsWifiBusy(struct rtw_adapter * padapter);
+u8 BTDM_IsCoexistStateChanged(struct rtw_adapter * padapter);
+u8 BTDM_IsWifiUplink(struct rtw_adapter * padapter);
+u8 BTDM_IsWifiDownlink(struct rtw_adapter * padapter);
+u8 BTDM_IsBTHSMode(struct rtw_adapter * padapter);
+u8 BTDM_IsBTUplink(struct rtw_adapter * padapter);
+u8 BTDM_IsBTDownlink(struct rtw_adapter * padapter);
+void BTDM_AdjustForBtOperation(struct rtw_adapter * padapter);
+void BTDM_ForHalt(struct rtw_adapter * padapter);
+void BTDM_WifiScanNotify(struct rtw_adapter * padapter, u8 scanType);
+void BTDM_WifiAssociateNotify(struct rtw_adapter * padapter, u8 action);
+void BTDM_MediaStatusNotify(struct rtw_adapter * padapter, enum rt_media_status mstatus);
+void BTDM_ForDhcp(struct rtw_adapter * padapter);
+void BTDM_ResetActionProfileState(struct rtw_adapter * padapter);
+void BTDM_SetBtCoexCurrAntNum(struct rtw_adapter * padapter, u8 antNum);
+#define BT_SetBtCoexCurrAntNum BTDM_SetBtCoexCurrAntNum
+u8 BTDM_IsActionSCO(struct rtw_adapter * padapter);
+u8 BTDM_IsActionHID(struct rtw_adapter * padapter);
+u8 BTDM_IsActionA2DP(struct rtw_adapter * padapter);
+u8 BTDM_IsActionPAN(struct rtw_adapter * padapter);
+u8 BTDM_IsActionHIDA2DP(struct rtw_adapter * padapter);
+u8 BTDM_IsActionHIDPAN(struct rtw_adapter * padapter);
+u8 BTDM_IsActionPANA2DP(struct rtw_adapter * padapter);
+u8 BTDM_IsBtDisabled(struct rtw_adapter * padapter);
+#define BT_IsBtDisabled BTDM_IsBtDisabled
+u32 BTDM_BtTxRxCounterH(struct rtw_adapter * padapter);
+u32 BTDM_BtTxRxCounterL(struct rtw_adapter * padapter);
+
+/*  ===== End of sync from SD7 driver HAL/BTCoexist/HalBtCoexist.h ===== */
+#endif /*  __HALBTCOEXIST_C__ */
+
+#ifdef __HALBT_C__ /*  HAL/HalBT.h */
+/*  ===== Below this line is sync from SD7 driver HAL/HalBT.h ===== */
+
+#define RTS_CTS_NO_LEN_LIMIT   0
+
+u8 HALBT_GetPGAntNum(struct rtw_adapter * padapter);
+#define BT_GetPGAntNum HALBT_GetPGAntNum
+void HALBT_SetKey(struct rtw_adapter * padapter, u8 EntryNum);
+void HALBT_RemoveKey(struct rtw_adapter * padapter, u8 EntryNum);
+void HALBT_InitBTVars8723A(struct rtw_adapter * padapter);
+#define HALBT_InitHalVars HALBT_InitBTVars8723A
+#define BT_InitHalVars HALBT_InitHalVars
+u8 HALBT_IsBTExist(struct rtw_adapter * padapter);
+#define BT_IsBtExist HALBT_IsBTExist
+u8 HALBT_BTChipType(struct rtw_adapter * padapter);
+void HALBT_InitHwConfig(struct rtw_adapter * padapter);
+#define BT_InitHwConfig HALBT_InitHwConfig
+void HALBT_SetRtsCtsNoLenLimit(struct rtw_adapter * padapter);
+
+/*  ===== End of sync from SD7 driver HAL/HalBT.c ===== */
+#endif /*  __HALBT_C__ */
+
+#define _bt_dbg_off_           0
+#define _bt_dbg_on_            1
+
+extern u32 BTCoexDbgLevel;
+
+
+
+#endif /*  __RTL8723A_BT_COEXIST_H__ */
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_cmd.h b/drivers/staging/rtl8723au/include/rtl8723a_cmd.h
new file mode 100644 (file)
index 0000000..8fccbfc
--- /dev/null
@@ -0,0 +1,160 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTL8723A_CMD_H__
+#define __RTL8723A_CMD_H__
+
+
+#define H2C_BT_FW_PATCH_LEN            3
+#define H2C_BT_PWR_FORCE_LEN           3
+
+enum cmd_msg_element_id
+{
+       NONE_CMDMSG_EID,
+       AP_OFFLOAD_EID = 0,
+       SET_PWRMODE_EID = 1,
+       JOINBSS_RPT_EID = 2,
+       RSVD_PAGE_EID = 3,
+       RSSI_4_EID = 4,
+       RSSI_SETTING_EID = 5,
+       MACID_CONFIG_EID = 6,
+       MACID_PS_MODE_EID = 7,
+       P2P_PS_OFFLOAD_EID = 8,
+       SELECTIVE_SUSPEND_ROF_CMD = 9,
+       BT_QUEUE_PKT_EID = 17,
+       BT_ANT_TDMA_EID = 20,
+       BT_2ANT_HID_EID = 21,
+       P2P_PS_CTW_CMD_EID = 32,
+       FORCE_BT_TX_PWR_EID = 33,
+       SET_TDMA_WLAN_ACT_TIME_EID = 34,
+       SET_BT_TX_RETRY_INDEX_EID = 35,
+       HID_PROFILE_ENABLE_EID = 36,
+       BT_IGNORE_WLAN_ACT_EID = 37,
+       BT_PTA_MANAGER_UPDATE_ENABLE_EID = 38,
+       DAC_SWING_VALUE_EID = 41,
+       TRADITIONAL_TDMA_EN_EID = 51,
+       H2C_BT_FW_PATCH = 54,
+       B_TYPE_TDMA_EID = 58,
+       SCAN_EN_EID = 59,
+       LOWPWR_LPS_EID = 71,
+       H2C_RESET_TSF = 75,
+       MAX_CMDMSG_EID
+};
+
+struct cmd_msg_parm {
+       u8 eid; /* element id */
+       u8 sz; /*  sz */
+       u8 buf[6];
+};
+
+struct setpwrmode_parm {
+       u8 Mode;
+       u8 SmartPS;
+       u8 AwakeInterval;       /*  unit: beacon interval */
+       u8 bAllQueueUAPSD;
+
+#define SETPM_LOWRXBCN                 BIT(0)
+#define SETPM_AUTOANTSWITCH            BIT(1)
+#define SETPM_PSALLOWBTHIGHPRI BIT(2)
+       u8 BcnAntMode;
+} __packed;
+
+struct H2C_SS_RFOFF_PARAM{
+       u8 ROFOn; /*  1: on, 0:off */
+       u16 gpio_period; /*  unit: 1024 us */
+}__attribute__ ((packed));
+
+
+struct joinbssrpt_parm {
+       u8 OpMode;      /*  enum rt_media_status */
+};
+
+struct rsvdpage_loc {
+       u8 LocProbeRsp;
+       u8 LocPsPoll;
+       u8 LocNullData;
+       u8 LocQosNull;
+       u8 LocBTQosNull;
+};
+
+struct P2P_PS_Offload_t {
+       u8 Offload_En:1;
+       u8 role:1; /*  1: Owner, 0: Client */
+       u8 CTWindow_En:1;
+       u8 NoA0_En:1;
+       u8 NoA1_En:1;
+       u8 AllStaSleep:1; /*  Only valid in Owner */
+       u8 discovery:1;
+       u8 rsvd:1;
+};
+
+struct P2P_PS_CTWPeriod_t {
+       u8 CTWPeriod;   /* TU */
+};
+
+#define B_TDMA_EN                      BIT(0)
+#define B_TDMA_FIXANTINBT              BIT(1)
+#define B_TDMA_TXPSPOLL                        BIT(2)
+#define B_TDMA_VAL870                  BIT(3)
+#define B_TDMA_AUTOWAKEUP              BIT(4)
+#define B_TDMA_NOPS                    BIT(5)
+#define B_TDMA_WLANHIGHPRI             BIT(6)
+
+struct b_type_tdma_parm {
+       u8 option;
+
+       u8 TBTTOnPeriod;
+       u8 MedPeriod;
+       u8 rsvd30;
+} __packed;
+
+struct scan_en_parm {
+       u8 En;
+} __packed;
+
+/*  BT_PWR */
+#define SET_H2CCMD_BT_PWR_IDX(__pH2CCmd, __Value)                                                      SET_BITS_TO_LE_1BYTE_8BIT(__pH2CCmd, 0, 8, __Value)
+
+/*  BT_FW_PATCH */
+#define SET_H2CCMD_BT_FW_PATCH_ENABLE(__pH2CCmd, __Value)                                      SET_BITS_TO_LE_4BYTE(__pH2CCmd, 0, 8, __Value) /*       SET_BITS_TO_LE_1BYTE(__pH2CCmd, 0, 8, __Value) */
+#define SET_H2CCMD_BT_FW_PATCH_SIZE(__pH2CCmd, __Value)                                                SET_BITS_TO_LE_4BYTE(__pH2CCmd, 8, 16, __Value) /*      SET_BITS_TO_LE_2BYTE((__pH2CCmd)+1, 0, 16, __Value) */
+
+struct lowpwr_lps_parm{
+       u8 bcn_count:4;
+       u8 tb_bcn_threshold:3;
+       u8 enable:1;
+       u8 bcn_interval;
+       u8 drop_threshold;
+       u8 max_early_period;
+       u8 max_bcn_timeout_period;
+} __packed;
+
+
+/*  host message to firmware cmd */
+void rtl8723a_set_FwPwrMode_cmd(struct rtw_adapter * padapter, u8 Mode);
+void rtl8723a_set_FwJoinBssReport_cmd(struct rtw_adapter * padapter, u8 mstatus);
+#ifdef CONFIG_8723AU_BT_COEXIST
+void rtl8723a_set_BTCoex_AP_mode_FwRsvdPkt_cmd(struct rtw_adapter * padapter);
+#endif
+u8 rtl8723a_set_rssi_cmd(struct rtw_adapter * padapter, u8 *param);
+u8 rtl8723a_set_raid_cmd(struct rtw_adapter * padapter, u32 mask, u8 arg);
+void rtl8723a_add_rateatid(struct rtw_adapter * padapter, u32 bitmap, u8 arg, u8 rssi_level);
+
+#ifdef CONFIG_8723AU_P2P
+void rtl8723a_set_p2p_ps_offload_cmd(struct rtw_adapter * padapter, u8 p2p_ps_state);
+#endif /* CONFIG_8723AU_P2P */
+
+void CheckFwRsvdPageContent23a(struct rtw_adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_dm.h b/drivers/staging/rtl8723au/include/rtl8723a_dm.h
new file mode 100644 (file)
index 0000000..47e887f
--- /dev/null
@@ -0,0 +1,144 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTL8723A_DM_H__
+#define __RTL8723A_DM_H__
+/*  */
+/*  Description: */
+/*  */
+/*  This file is for 8723A dynamic mechanism only */
+/*  */
+/*  */
+/*  */
+#define DYNAMIC_FUNC_BT BIT(0)
+
+enum{
+       UP_LINK,
+       DOWN_LINK,
+};
+/*  */
+/*  structure and define */
+/*  */
+
+/*  duplicate code,will move to ODM ######### */
+#define IQK_MAC_REG_NUM                4
+#define IQK_ADDA_REG_NUM               16
+#define IQK_BB_REG_NUM                 9
+#define HP_THERMAL_NUM         8
+/*  duplicate code,will move to ODM ######### */
+struct dm_priv
+{
+       u8      DM_Type;
+       u8      DMFlag;
+       u8      InitDMFlag;
+       u32     InitODMFlag;
+
+       /*  Upper and Lower Signal threshold for Rate Adaptive*/
+       int     UndecoratedSmoothedPWDB;
+       int     UndecoratedSmoothedCCK;
+       int     EntryMinUndecoratedSmoothedPWDB;
+       int     EntryMaxUndecoratedSmoothedPWDB;
+       int     MinUndecoratedPWDBForDM;
+       int     LastMinUndecoratedPWDBForDM;
+
+       s32     UndecoratedSmoothedBeacon;
+       #ifdef CONFIG_8723AU_BT_COEXIST
+       s32 BT_EntryMinUndecoratedSmoothedPWDB;
+       s32 BT_EntryMaxUndecoratedSmoothedPWDB;
+       #endif
+
+       /* for High Power */
+       u8 bDynamicTxPowerEnable;
+       u8 LastDTPLvl;
+       u8 DynamicTxHighPowerLvl;/* Add by Jacken Tx Power Control for Near/Far Range 2008/03/06 */
+
+       /* for tx power tracking */
+       u8      bTXPowerTracking;
+       u8      TXPowercount;
+       u8      bTXPowerTrackingInit;
+       u8      TxPowerTrackControl;    /* for mp mode, turn off txpwrtracking as default */
+       u8      TM_Trigger;
+
+       u8      ThermalMeter[2];                                /*  ThermalMeter, index 0 for RFIC0, and 1 for RFIC1 */
+       u8      ThermalValue;
+       u8      ThermalValue_LCK;
+       u8      ThermalValue_IQK;
+       u8      ThermalValue_DPK;
+
+       u8      bRfPiEnable;
+
+       /* for APK */
+       u32     APKoutput[2][2];        /* path A/B; output1_1a/output1_2a */
+       u8      bAPKdone;
+       u8      bAPKThermalMeterIgnore;
+       u8      bDPdone;
+       u8      bDPPathAOK;
+       u8      bDPPathBOK;
+
+       /* for IQK */
+       u32     RegC04;
+       u32     Reg874;
+       u32     RegC08;
+       u32     RegB68;
+       u32     RegB6C;
+       u32     Reg870;
+       u32     Reg860;
+       u32     Reg864;
+       u32     ADDA_backup[IQK_ADDA_REG_NUM];
+       u32     IQK_MAC_backup[IQK_MAC_REG_NUM];
+       u32     IQK_BB_backup_recover[9];
+       u32     IQK_BB_backup[IQK_BB_REG_NUM];
+       u8      PowerIndex_backup[6];
+
+       u8      bCCKinCH14;
+
+       u8      CCK_index;
+       u8      OFDM_index[2];
+
+       u8      bDoneTxpower;
+       u8      CCK_index_HP;
+       u8      OFDM_index_HP[2];
+       u8      ThermalValue_HP[HP_THERMAL_NUM];
+       u8      ThermalValue_HP_index;
+
+       /* for TxPwrTracking */
+       s32     RegE94;
+       s32     RegE9C;
+       s32     RegEB4;
+       s32     RegEBC;
+
+       u32     TXPowerTrackingCallbackCnt;     /* cosa add for debug */
+
+       u32     prv_traffic_idx; /*  edca turbo */
+
+       s32     OFDM_Pkt_Cnt;
+       u8      RSSI_Select;
+/*     u8      DIG_Dynamic_MIN ; */
+/*  duplicate code,will move to ODM ######### */
+       /*  Add for Reading Initial Data Rate SEL Register 0x484 during watchdog. Using for fill tx desc. 2011.3.21 by Thomas */
+       u8      INIDATA_RATE[32];
+};
+
+
+/*  */
+/*  function prototype */
+/*  */
+
+void rtl8723a_init_dm_priv(struct rtw_adapter *padapter);
+void rtl8723a_deinit_dm_priv(struct rtw_adapter *padapter);
+
+void rtl8723a_InitHalDm(struct rtw_adapter *padapter);
+void rtl8723a_HalDmWatchDog(struct rtw_adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_hal.h b/drivers/staging/rtl8723au/include/rtl8723a_hal.h
new file mode 100644 (file)
index 0000000..c20248b
--- /dev/null
@@ -0,0 +1,575 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTL8723A_HAL_H__
+#define __RTL8723A_HAL_H__
+
+#include "rtl8723a_spec.h"
+#include "rtl8723a_pg.h"
+#include "Hal8723APhyReg.h"
+#include "Hal8723APhyCfg.h"
+#include "rtl8723a_rf.h"
+#ifdef CONFIG_8723AU_BT_COEXIST
+#include "rtl8723a_bt-coexist.h"
+#endif
+#include "rtl8723a_dm.h"
+#include "rtl8723a_recv.h"
+#include "rtl8723a_xmit.h"
+#include "rtl8723a_cmd.h"
+#include "rtl8723a_sreset.h"
+#include "rtw_efuse.h"
+
+#include "odm_precomp.h"
+
+
+/* 2TODO: We should define 8192S firmware related macro settings here!! */
+#define RTL819X_DEFAULT_RF_TYPE                        RF_1T2R
+#define RTL819X_TOTAL_RF_PATH                          2
+
+/* TODO:  The following need to check!! */
+#define RTL8723_FW_UMC_IMG                             "rtl8192CU\\rtl8723fw.bin"
+#define RTL8723_FW_UMC_B_IMG                   "rtl8192CU\\rtl8723fw_B.bin"
+#define RTL8723_PHY_REG                                        "rtl8723S\\PHY_REG_1T.txt"
+#define RTL8723_PHY_RADIO_A                            "rtl8723S\\radio_a_1T.txt"
+#define RTL8723_PHY_RADIO_B                            "rtl8723S\\radio_b_1T.txt"
+#define RTL8723_AGC_TAB                                        "rtl8723S\\AGC_TAB_1T.txt"
+#define RTL8723_PHY_MACREG                             "rtl8723S\\MAC_REG.txt"
+#define RTL8723_PHY_REG_PG                             "rtl8723S\\PHY_REG_PG.txt"
+#define RTL8723_PHY_REG_MP                             "rtl8723S\\PHY_REG_MP.txt"
+
+/*  */
+/*             RTL8723S From header */
+/*  */
+
+/*  Fw Array */
+#define Rtl8723_FwImageArray                           Rtl8723UFwImgArray
+#define Rtl8723_FwUMCBCutImageArrayWithBT              Rtl8723UFwUMCBCutImgArrayWithBT
+#define Rtl8723_FwUMCBCutImageArrayWithoutBT   Rtl8723UFwUMCBCutImgArrayWithoutBT
+
+#define Rtl8723_ImgArrayLength                         Rtl8723UImgArrayLength
+#define Rtl8723_UMCBCutImgArrayWithBTLength            Rtl8723UUMCBCutImgArrayWithBTLength
+#define Rtl8723_UMCBCutImgArrayWithoutBTLength Rtl8723UUMCBCutImgArrayWithoutBTLength
+
+#define Rtl8723_PHY_REG_Array_PG                       Rtl8723UPHY_REG_Array_PG
+#define Rtl8723_PHY_REG_Array_PGLength         Rtl8723UPHY_REG_Array_PGLength
+
+#define Rtl8723_FwUMCBCutMPImageArray          Rtl8723SFwUMCBCutMPImgAr
+#define Rtl8723_UMCBCutMPImgArrayLength                Rtl8723SUMCBCutMPImgArrayLength
+
+#define DRVINFO_SZ                             4 /*  unit is 8bytes */
+#define PageNum_128(_Len)              (u32)(((_Len)>>7) + ((_Len)&0x7F ? 1:0))
+
+#define FW_8723A_SIZE                  0x8000
+#define FW_8723A_START_ADDRESS 0x1000
+#define FW_8723A_END_ADDRESS           0x1FFF /* 0x5FFF */
+
+#define MAX_PAGE_SIZE                  4096    /*  @ page : 4k bytes */
+
+#define IS_FW_HEADER_EXIST(_pFwHdr)    ((le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x92C0 ||\
+                                                                       (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x88C0 ||\
+                                                                       (le16_to_cpu(_pFwHdr->Signature)&0xFFF0) == 0x2300)
+
+/*  */
+/*  This structure must be cared byte-ordering */
+/*  */
+/*  Added by tynli. 2009.12.04. */
+struct rt_8723a_firmware_hdr {
+       /*  8-byte alinment required */
+
+       /*  LONG WORD 0 ---- */
+       u16             Signature;      /*  92C0: test chip; 92C, 88C0: test chip; 88C1: MP A-cut; 92C1: MP A-cut */
+       u8              Category;       /*  AP/NIC and USB/PCI */
+       u8              Function;       /*  Reserved for different FW function indcation, for further use when driver needs to download different FW in different conditions */
+       u16             Version;                /*  FW Version */
+       u8              Subversion;     /*  FW Subversion, default 0x00 */
+       u16             Rsvd1;
+
+
+       /*  LONG WORD 1 ---- */
+       u8              Month;  /*  Release time Month field */
+       u8              Date;   /*  Release time Date field */
+       u8              Hour;   /*  Release time Hour field */
+       u8              Minute; /*  Release time Minute field */
+       u16             RamCodeSize;    /*  The size of RAM code */
+       u16             Rsvd2;
+
+       /*  LONG WORD 2 ---- */
+       u32             SvnIdx; /*  The SVN entry index */
+       u32             Rsvd3;
+
+       /*  LONG WORD 3 ---- */
+       u32             Rsvd4;
+       u32             Rsvd5;
+};
+
+#define DRIVER_EARLY_INT_TIME          0x05
+#define BCN_DMA_ATIME_INT_TIME         0x02
+
+
+/*  BK, BE, VI, VO, HCCA, MANAGEMENT, COMMAND, HIGH, BEACON. */
+#define MAX_TX_QUEUE           9
+
+#define TX_SELE_HQ                     BIT(0)          /*  High Queue */
+#define TX_SELE_LQ                     BIT(1)          /*  Low Queue */
+#define TX_SELE_NQ                     BIT(2)          /*  Normal Queue */
+
+/*  Note: We will divide number of page equally for each queue other than public queue! */
+#define TX_TOTAL_PAGE_NUMBER   0xF8
+#define TX_PAGE_BOUNDARY               (TX_TOTAL_PAGE_NUMBER + 1)
+
+/*  For Normal Chip Setting */
+/*  (HPQ + LPQ + NPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER */
+#define NORMAL_PAGE_NUM_PUBQ   0xE7
+#define NORMAL_PAGE_NUM_HPQ            0x0C
+#define NORMAL_PAGE_NUM_LPQ            0x02
+#define NORMAL_PAGE_NUM_NPQ            0x02
+
+/*  For Test Chip Setting */
+/*  (HPQ + LPQ + PUBQ) shall be TX_TOTAL_PAGE_NUMBER */
+#define TEST_PAGE_NUM_PUBQ             0x7E
+
+/*  For Test Chip Setting */
+#define WMM_TEST_TX_TOTAL_PAGE_NUMBER  0xF5
+#define WMM_TEST_TX_PAGE_BOUNDARY              (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) /* F6 */
+
+#define WMM_TEST_PAGE_NUM_PUBQ         0xA3
+#define WMM_TEST_PAGE_NUM_HPQ          0x29
+#define WMM_TEST_PAGE_NUM_LPQ          0x29
+
+/*  Note: For Normal Chip Setting, modify later */
+#define WMM_NORMAL_TX_TOTAL_PAGE_NUMBER        0xF5
+#define WMM_NORMAL_TX_PAGE_BOUNDARY            (WMM_TEST_TX_TOTAL_PAGE_NUMBER + 1) /* F6 */
+
+#define WMM_NORMAL_PAGE_NUM_PUBQ       0xB0
+#define WMM_NORMAL_PAGE_NUM_HPQ                0x29
+#define WMM_NORMAL_PAGE_NUM_LPQ                0x1C
+#define WMM_NORMAL_PAGE_NUM_NPQ                0x1C
+
+
+/*  */
+/*     Chip specific */
+/*  */
+#define CHIP_BONDING_IDENTIFIER(_value)        (((_value)>>22)&0x3)
+#define CHIP_BONDING_92C_1T2R                  0x1
+#define CHIP_BONDING_88C_USB_MCARD             0x2
+#define CHIP_BONDING_88C_USB_HP                        0x1
+
+#include "HalVerDef.h"
+#include "hal_com.h"
+
+/*  */
+/*     Channel Plan */
+/*  */
+enum ChannelPlan
+{
+       CHPL_FCC        = 0,
+       CHPL_IC         = 1,
+       CHPL_ETSI       = 2,
+       CHPL_SPAIN      = 3,
+       CHPL_FRANCE     = 4,
+       CHPL_MKK        = 5,
+       CHPL_MKK1       = 6,
+       CHPL_ISRAEL     = 7,
+       CHPL_TELEC      = 8,
+       CHPL_GLOBAL     = 9,
+       CHPL_WORLD      = 10,
+};
+
+#define EFUSE_REAL_CONTENT_LEN         512
+#define EFUSE_MAP_LEN                          128
+#define EFUSE_MAX_SECTION                      16
+#define EFUSE_IC_ID_OFFSET                     506     /* For some inferiority IC purpose. added by Roger, 2009.09.02. */
+#define AVAILABLE_EFUSE_ADDR(addr)     (addr < EFUSE_REAL_CONTENT_LEN)
+/*  */
+/*  <Roger_Notes> */
+/*  To prevent out of boundary programming case, */
+/*  leave 1byte and program full section */
+/*  9bytes + 1byt + 5bytes and pre 1byte. */
+/*  For worst case: */
+/*  | 1byte|----8bytes----|1byte|--5bytes--| */
+/*  |         |            Reserved(14bytes)         | */
+/*  */
+
+/*  PG data exclude header, dummy 6 bytes frome CP test and reserved 1byte. */
+#define EFUSE_OOB_PROTECT_BYTES                        15
+
+#define EFUSE_REAL_CONTENT_LEN_8723A   512
+#define EFUSE_MAP_LEN_8723A                            256
+#define EFUSE_MAX_SECTION_8723A                        32
+
+/*  */
+/*                     EFUSE for BT definition */
+/*  */
+#define EFUSE_BT_REAL_BANK_CONTENT_LEN 512
+#define EFUSE_BT_REAL_CONTENT_LEN              1536    /*  512*3 */
+#define EFUSE_BT_MAP_LEN                               1024    /*  1k bytes */
+#define EFUSE_BT_MAX_SECTION                   128             /*  1024/8 */
+
+#define EFUSE_PROTECT_BYTES_BANK               16
+
+/*  */
+/*  <Roger_Notes> For RTL8723 WiFi/BT/GPS multi-function configuration. 2010.10.06. */
+/*  */
+enum RT_MULTI_FUNC {
+       RT_MULTI_FUNC_NONE = 0x00,
+       RT_MULTI_FUNC_WIFI = 0x01,
+       RT_MULTI_FUNC_BT = 0x02,
+       RT_MULTI_FUNC_GPS = 0x04,
+};
+
+/*  */
+/*  <Roger_Notes> For RTL8723 WiFi PDn/GPIO polarity control configuration. 2010.10.08. */
+/*  */
+enum RT_POLARITY_CTL {
+       RT_POLARITY_LOW_ACT = 0,
+       RT_POLARITY_HIGH_ACT = 1,
+};
+
+/*  For RTL8723 regulator mode. by tynli. 2011.01.14. */
+enum RT_REGULATOR_MODE {
+       RT_SWITCHING_REGULATOR = 0,
+       RT_LDO_REGULATOR = 1,
+};
+
+/*  Description: Determine the types of C2H events that are the same in driver and Fw. */
+/*  Fisrt constructed by tynli. 2009.10.09. */
+enum {
+       C2H_DBG = 0,
+       C2H_TSF = 1,
+       C2H_AP_RPT_RSP = 2,
+       C2H_CCX_TX_RPT = 3,     /*  The FW notify the report of the specific tx packet. */
+       C2H_BT_RSSI = 4,
+       C2H_BT_OP_MODE = 5,
+       C2H_EXT_RA_RPT = 6,
+       C2H_HW_INFO_EXCH = 10,
+       C2H_C2H_H2C_TEST = 11,
+       C2H_BT_INFO = 12,
+       C2H_BT_MP_INFO = 15,
+       MAX_C2HEVENT
+};
+
+struct hal_data_8723a {
+       struct hal_version              VersionID;
+       enum rt_customer_id CustomerID;
+
+       u16     FirmwareVersion;
+       u16     FirmwareVersionRev;
+       u16     FirmwareSubVersion;
+       u16     FirmwareSignature;
+
+       /* current WIFI_PHY values */
+       u32     ReceiveConfig;
+       enum WIRELESS_MODE              CurrentWirelessMode;
+       enum ht_channel_width   CurrentChannelBW;
+       u8      CurrentChannel;
+       u8      nCur40MhzPrimeSC;/*  Control channel sub-carrier */
+
+       u16     BasicRateSet;
+
+       /* rf_ctrl */
+       u8      rf_chip;
+       u8      rf_type;
+       u8      NumTotalRFPath;
+
+       u8      BoardType;
+       u8      CrystalCap;
+       /*  */
+       /*  EEPROM setting. */
+       /*  */
+       u8      EEPROMVersion;
+       u16     EEPROMVID;
+       u16     EEPROMPID;
+       u16     EEPROMSVID;
+       u16     EEPROMSDID;
+       u8      EEPROMCustomerID;
+       u8      EEPROMSubCustomerID;
+       u8      EEPROMRegulatory;
+       u8      EEPROMThermalMeter;
+       u8      EEPROMBluetoothCoexist;
+       u8      EEPROMBluetoothType;
+       u8      EEPROMBluetoothAntNum;
+       u8      EEPROMBluetoothAntIsolation;
+       u8      EEPROMBluetoothRadioShared;
+
+       u8      bTXPowerDataReadFromEEPORM;
+       u8      bAPKThermalMeterIgnore;
+
+       u8      bIQKInitialized;
+       u8      bAntennaDetected;
+
+       u8      TxPwrLevelCck[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+       u8      TxPwrLevelHT40_1S[RF_PATH_MAX][CHANNEL_MAX_NUMBER];     /*  For HT 40MHZ pwr */
+       u8      TxPwrLevelHT40_2S[RF_PATH_MAX][CHANNEL_MAX_NUMBER];     /*  For HT 40MHZ pwr */
+       u8      TxPwrHt20Diff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];/*  HT 20<->40 Pwr diff */
+       u8      TxPwrLegacyHtDiff[RF_PATH_MAX][CHANNEL_MAX_NUMBER];/*  For HT<->legacy pwr diff */
+       /*  For power group */
+       u8      PwrGroupHT20[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+       u8      PwrGroupHT40[RF_PATH_MAX][CHANNEL_MAX_NUMBER];
+
+       u8      LegacyHTTxPowerDiff;/*  Legacy to HT rate power diff */
+
+       /*  Read/write are allow for following hardware information variables */
+       u8      framesync;
+       u32     framesyncC34;
+       u8      framesyncMonitor;
+       u8      DefaultInitialGain[4];
+       u8      pwrGroupCnt;
+       u32     MCSTxPowerLevelOriginalOffset[7][16];
+       u32     CCKTxPowerLevelOriginalOffset;
+
+       u32     AntennaTxPath;                                  /*  Antenna path Tx */
+       u32     AntennaRxPath;                                  /*  Antenna path Rx */
+       u8      ExternalPA;
+
+       u8      bLedOpenDrain; /*  Support Open-drain arrangement for controlling the LED. Added by Roger, 2009.10.16. */
+
+       u8      b1x1RecvCombine;        /*  for 1T1R receive combining */
+
+       /*  For EDCA Turbo mode */
+
+       u32     AcParam_BE; /* Original parameter for BE, use for EDCA turbo. */
+
+       /* vivi, for tx power tracking, 20080407 */
+       /* u16  TSSI_13dBm; */
+       /* u32  Pwr_Track; */
+       /*  The current Tx Power Level */
+       u8      CurrentCckTxPwrIdx;
+       u8      CurrentOfdm24GTxPwrIdx;
+
+       struct bb_reg_define    PHYRegDef[4];   /* Radio A/B/C/D */
+
+       bool            bRFPathRxEnable[4];     /*  We support 4 RF path now. */
+
+       u32     RfRegChnlVal[2];
+
+       u8      bCckHighPower;
+
+       /* RDG enable */
+       bool     bRDGEnable;
+
+       /* for host message to fw */
+       u8      LastHMEBoxNum;
+
+       u8      fw_ractrl;
+       u8      RegTxPause;
+       /*  Beacon function related global variable. */
+       u32     RegBcnCtrlVal;
+       u8      RegFwHwTxQCtrl;
+       u8      RegReg542;
+
+       struct dm_priv  dmpriv;
+       struct dm_odm_t         odmpriv;
+       struct sreset_priv srestpriv;
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       u8                              bBTMode;
+       /*  BT only. */
+       struct bt_30info                BtInfo;
+       /*  For bluetooth co-existance */
+       struct bt_coexist_str   bt_coexist;
+#endif
+
+       u8      bDumpRxPkt;/* for debug */
+       u8      FwRsvdPageStartOffset; /* 2010.06.23. Added by tynli. Reserve page start offset except beacon in TxQ. */
+
+       /*  2010/08/09 MH Add CU power down mode. */
+       u8      pwrdown;
+
+       /*  Add for dual MAC  0--Mac0 1--Mac1 */
+       u32     interfaceIndex;
+
+       u8      OutEpQueueSel;
+       u8      OutEpNumber;
+
+       /*  2010/12/10 MH Add for USB aggreation mode dynamic shceme. */
+       bool            UsbRxHighSpeedMode;
+
+       /*  2010/11/22 MH Add for slim combo debug mode selective. */
+       /*  This is used for fix the drawback of CU TSMC-A/UMC-A cut. HW auto suspend ability. Close BT clock. */
+       bool            SlimComboDbg;
+
+       /*  */
+       /*  Add For EEPROM Efuse switch and  Efuse Shadow map Setting */
+       /*  */
+       u8                      EepromOrEfuse;
+       u16                     EfuseUsedBytes;
+       u16                     BTEfuseUsedBytes;
+
+       /*  Interrupt relatd register information. */
+       u32                     SysIntrStatus;
+       u32                     SysIntrMask;
+
+       /*  */
+       /*  2011/02/23 MH Add for 8723 mylti function definition. The define should be moved to an */
+       /*  independent file in the future. */
+       /*  */
+       /* 8723-----------------------------------------*/
+       enum RT_MULTI_FUNC      MultiFunc; /*  For multi-function consideration. */
+       enum RT_POLARITY_CTL    PolarityCtl; /*  For Wifi PDn Polarity control. */
+       enum RT_REGULATOR_MODE  RegulatorMode; /*  switching regulator or LDO */
+       /* 8723-----------------------------------------
+        *  2011/02/23 MH Add for 8723 mylti function definition. The define should be moved to an */
+       /*  independent file in the future. */
+
+       bool                            bMACFuncEnable;
+
+#ifdef CONFIG_8723AU_P2P
+       struct P2P_PS_Offload_t p2p_ps_offload;
+#endif
+
+
+       /*  */
+       /*  For USB Interface HAL related */
+       /*  */
+       u32     UsbBulkOutSize;
+
+       /*  Interrupt related register information. */
+       u32     IntArray[2];
+       u32     IntrMask[2];
+
+       /*  */
+       /*  For SDIO Interface HAL related */
+       /*  */
+
+       /*  Auto FSM to Turn On, include clock, isolation, power control for MAC only */
+       u8                      bMacPwrCtrlOn;
+
+};
+
+#define GET_HAL_DATA(__pAdapter)       ((struct hal_data_8723a *)((__pAdapter)->HalData))
+#define GET_RF_TYPE(priv)                      (GET_HAL_DATA(priv)->rf_type)
+
+#define INCLUDE_MULTI_FUNC_BT(_Adapter)                (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_BT)
+#define INCLUDE_MULTI_FUNC_GPS(_Adapter)       (GET_HAL_DATA(_Adapter)->MultiFunc & RT_MULTI_FUNC_GPS)
+
+struct rxreport_8723a {
+       u32 pktlen:14;
+       u32 crc32:1;
+       u32 icverr:1;
+       u32 drvinfosize:4;
+       u32 security:3;
+       u32 qos:1;
+       u32 shift:2;
+       u32 physt:1;
+       u32 swdec:1;
+       u32 ls:1;
+       u32 fs:1;
+       u32 eor:1;
+       u32 own:1;
+
+       u32 macid:5;
+       u32 tid:4;
+       u32 hwrsvd:4;
+       u32 amsdu:1;
+       u32 paggr:1;
+       u32 faggr:1;
+       u32 a1fit:4;
+       u32 a2fit:4;
+       u32 pam:1;
+       u32 pwr:1;
+       u32 md:1;
+       u32 mf:1;
+       u32 type:2;
+       u32 mc:1;
+       u32 bc:1;
+
+       u32 seq:12;
+       u32 frag:4;
+       u32 nextpktlen:14;
+       u32 nextind:1;
+       u32 rsvd0831:1;
+
+       u32 rxmcs:6;
+       u32 rxht:1;
+       u32 gf:1;
+       u32 splcp:1;
+       u32 bw:1;
+       u32 htc:1;
+       u32 eosp:1;
+       u32 bssidfit:2;
+       u32 rsvd1214:16;
+       u32 unicastwake:1;
+       u32 magicwake:1;
+
+       u32 pattern0match:1;
+       u32 pattern1match:1;
+       u32 pattern2match:1;
+       u32 pattern3match:1;
+       u32 pattern4match:1;
+       u32 pattern5match:1;
+       u32 pattern6match:1;
+       u32 pattern7match:1;
+       u32 pattern8match:1;
+       u32 pattern9match:1;
+       u32 patternamatch:1;
+       u32 patternbmatch:1;
+       u32 patterncmatch:1;
+       u32 rsvd1613:19;
+
+       u32 tsfl;
+
+       u32 bassn:12;
+       u32 bavld:1;
+       u32 rsvd2413:19;
+};
+
+/*  rtl8723a_hal_init.c */
+s32 rtl8723a_FirmwareDownload(struct rtw_adapter *padapter);
+void rtl8723a_FirmwareSelfReset(struct rtw_adapter *padapter);
+void rtl8723a_InitializeFirmwareVars(struct rtw_adapter *padapter);
+
+void rtl8723a_InitAntenna_Selection(struct rtw_adapter *padapter);
+void rtl8723a_DeinitAntenna_Selection(struct rtw_adapter *padapter);
+void rtl8723a_CheckAntenna_Selection(struct rtw_adapter *padapter);
+void rtl8723a_init_default_value(struct rtw_adapter *padapter);
+
+s32 InitLLTTable23a(struct rtw_adapter *padapter, u32 boundary);
+
+s32 CardDisableHWSM(struct rtw_adapter *padapter, u8 resetMCU);
+s32 CardDisableWithoutHWSM(struct rtw_adapter *padapter);
+
+/*  EFuse */
+u8 GetEEPROMSize8723A(struct rtw_adapter *padapter);
+void Hal_InitPGData(struct rtw_adapter *padapter, u8 *PROMContent);
+void Hal_EfuseParseIDCode(struct rtw_adapter *padapter, u8 *hwinfo);
+void Hal_EfuseParsetxpowerinfo_8723A(struct rtw_adapter *padapter, u8 *PROMContent, bool AutoLoadFail);
+void Hal_EfuseParseBTCoexistInfo_8723A(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail);
+void Hal_EfuseParseEEPROMVer(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail);
+void rtl8723a_EfuseParseChnlPlan(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail);
+void Hal_EfuseParseCustomerID(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail);
+void Hal_EfuseParseAntennaDiversity(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail);
+void Hal_EfuseParseRateIndicationOption(struct rtw_adapter *padapter, u8 *hwinfo, bool AutoLoadFail);
+void Hal_EfuseParseXtal_8723A(struct rtw_adapter *pAdapter, u8 *hwinfo, u8 AutoLoadFail);
+void Hal_EfuseParseThermalMeter_8723A(struct rtw_adapter *padapter, u8 *hwinfo, u8 AutoLoadFail);
+
+void Hal_InitChannelPlan23a(struct rtw_adapter *padapter);
+
+void rtl8723a_set_hal_ops(struct hal_ops *pHalFunc);
+void SetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val);
+void GetHwReg8723A(struct rtw_adapter *padapter, u8 variable, u8 *val);
+#ifdef CONFIG_8723AU_BT_COEXIST
+void rtl8723a_SingleDualAntennaDetection(struct rtw_adapter *padapter);
+#endif
+
+/*  register */
+void SetBcnCtrlReg23a(struct rtw_adapter *padapter, u8 SetBits, u8 ClearBits);
+void rtl8723a_InitBeaconParameters(struct rtw_adapter *padapter);
+
+void rtl8723a_clone_haldata(struct rtw_adapter *dst_adapter, struct rtw_adapter *src_adapter);
+void rtl8723a_start_thread(struct rtw_adapter *padapter);
+void rtl8723a_stop_thread(struct rtw_adapter *padapter);
+
+s32 c2h_id_filter_ccx_8723a(u8 id);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_led.h b/drivers/staging/rtl8723au/include/rtl8723a_led.h
new file mode 100644 (file)
index 0000000..1623d18
--- /dev/null
@@ -0,0 +1,30 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTL8723A_LED_H__
+#define __RTL8723A_LED_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+/*  */
+/*  Interface to manipulate LED objects. */
+/*  */
+void rtl8723au_InitSwLeds(struct rtw_adapter *padapter);
+void rtl8723au_DeInitSwLeds(struct rtw_adapter *padapter);
+void SwLedOn23a(struct rtw_adapter *padapter, struct led_8723a * pLed);
+void SwLedOff23a(struct rtw_adapter *padapter, struct led_8723a * pLed);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_pg.h b/drivers/staging/rtl8723au/include/rtl8723a_pg.h
new file mode 100644 (file)
index 0000000..5c2ec44
--- /dev/null
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTL8723A_PG_H__
+#define __RTL8723A_PG_H__
+
+/*                     EEPROM/Efuse PG Offset for 8723E/8723U/8723S */
+#define EEPROM_CCK_TX_PWR_INX_8723A                    0x10
+#define EEPROM_HT40_1S_TX_PWR_INX_8723A                0x16
+#define EEPROM_HT20_TX_PWR_INX_DIFF_8723A      0x1C
+#define EEPROM_OFDM_TX_PWR_INX_DIFF_8723A      0x1F
+#define EEPROM_HT40_MAX_PWR_OFFSET_8723A       0x22
+#define EEPROM_HT20_MAX_PWR_OFFSET_8723A       0x25
+
+#define EEPROM_ChannelPlan_8723A                       0x28
+#define EEPROM_TSSI_A_8723A                                    0x29
+#define EEPROM_THERMAL_METER_8723A                     0x2A
+#define RF_OPTION1_8723A                                       0x2B
+#define RF_OPTION2_8723A                                       0x2C
+#define RF_OPTION3_8723A                                       0x2D
+#define RF_OPTION4_8723A                                       0x2E
+#define EEPROM_VERSION_8723A                           0x30
+#define EEPROM_CustomID_8723A                          0x31
+#define EEPROM_SubCustomID_8723A                       0x32
+#define EEPROM_XTAL_K_8723A                                    0x33
+#define EEPROM_Chipset_8723A                           0x34
+
+/*  RTL8723AE */
+#define EEPROM_VID_8723AE                                      0x49
+#define EEPROM_DID_8723AE                                      0x4B
+#define EEPROM_SVID_8723AE                                     0x4D
+#define EEPROM_SMID_8723AE                                     0x4F
+#define EEPROM_MAC_ADDR_8723AE                         0x67
+
+/*  RTL8723AU */
+#define EEPROM_MAC_ADDR_8723AU                         0xC6
+#define EEPROM_VID_8723AU                                      0xB7
+#define EEPROM_PID_8723AU                                      0xB9
+
+/*  RTL8723AS */
+#define EEPROM_MAC_ADDR_8723AS                         0xAA
+
+/*                     EEPROM/Efuse Value Type */
+#define EETYPE_TX_PWR                                          0x0
+
+/*                     EEPROM/Efuse Default Value */
+#define EEPROM_Default_CrystalCap_8723A                0x20
+
+
+/*        EEPROM/EFUSE data structure definition. */
+#define        MAX_CHNL_GROUP          3+9
+
+struct txpowerinfo {
+       u8 CCKIndex[RF_PATH_MAX][MAX_CHNL_GROUP];
+       u8 HT40_1SIndex[RF_PATH_MAX][MAX_CHNL_GROUP];
+       u8 HT40_2SIndexDiff[RF_PATH_MAX][MAX_CHNL_GROUP];
+       u8 HT20IndexDiff[RF_PATH_MAX][MAX_CHNL_GROUP];
+       u8 OFDMIndexDiff[RF_PATH_MAX][MAX_CHNL_GROUP];
+       u8 HT40MaxOffset[RF_PATH_MAX][MAX_CHNL_GROUP];
+       u8 HT20MaxOffset[RF_PATH_MAX][MAX_CHNL_GROUP];
+       u8 TSSI_A[3];
+       u8 TSSI_B[3];
+       u8 TSSI_A_5G[3];                /* 5GL/5GM/5GH */
+       u8 TSSI_B_5G[3];
+};
+
+enum bt_ant_num {
+       Ant_x2  = 0,
+       Ant_x1  = 1
+};
+
+enum bt_cotype {
+       BT_2Wire                = 0,
+       BT_ISSC_3Wire           = 1,
+       BT_Accel                = 2,
+       BT_CSR_BC4              = 3,
+       BT_CSR_BC8              = 4,
+       BT_RTL8756              = 5,
+       BT_RTL8723A             = 6
+};
+
+enum bt_radioshared {
+       BT_Radio_Shared         = 0,
+       BT_Radio_Individual     = 1,
+};
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_recv.h b/drivers/staging/rtl8723au/include/rtl8723a_recv.h
new file mode 100644 (file)
index 0000000..6bf6904
--- /dev/null
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTL8723A_RECV_H__
+#define __RTL8723A_RECV_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define NR_RECVBUFF (4)
+
+#define NR_PREALLOC_RECV_SKB (8)
+
+#define RECV_BLK_SZ 512
+#define RECV_BLK_CNT 16
+#define RECV_BLK_TH RECV_BLK_CNT
+
+#define MAX_RECVBUF_SZ (15360) /*  15k < 16k */
+
+#define RECV_BULK_IN_ADDR              0x80
+#define RECV_INT_IN_ADDR               0x81
+
+#define PHY_RSSI_SLID_WIN_MAX                          100
+#define PHY_LINKQUALITY_SLID_WIN_MAX           20
+
+
+struct phy_stat
+{
+       unsigned int phydw0;
+       unsigned int phydw1;
+       unsigned int phydw2;
+       unsigned int phydw3;
+       unsigned int phydw4;
+       unsigned int phydw5;
+       unsigned int phydw6;
+       unsigned int phydw7;
+};
+
+/*  Rx smooth factor */
+#define        Rx_Smooth_Factor (20)
+
+struct interrupt_msg_format {
+       unsigned int C2H_MSG0;
+       unsigned int C2H_MSG1;
+       unsigned int C2H_MSG2;
+       unsigned int C2H_MSG3;
+       unsigned int HISR; /*  from HISR Reg0x124, read to clear */
+       unsigned int HISRE;/*  from HISRE Reg0x12c, read to clear */
+       unsigned int  MSG_EX;
+};
+
+void rtl8723au_init_recvbuf(struct rtw_adapter *padapter, struct recv_buf *precvbuf);
+int    rtl8723au_init_recv_priv(struct rtw_adapter * padapter);
+void rtl8723au_free_recv_priv(struct rtw_adapter * padapter);
+void rtl8723a_process_phy_info(struct rtw_adapter *padapter, void *prframe);
+void update_recvframe_attrib(struct recv_frame *precvframe, struct recv_stat *prxstat);
+void update_recvframe_phyinfo(struct recv_frame *precvframe, struct phy_stat *pphy_info);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_rf.h b/drivers/staging/rtl8723au/include/rtl8723a_rf.h
new file mode 100644 (file)
index 0000000..166a45f
--- /dev/null
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTL8723A_RF_H__
+#define __RTL8723A_RF_H__
+
+/*--------------------------Define Parameters-------------------------------*/
+
+/*  */
+/*  For RF 6052 Series */
+/*  */
+#define                RF6052_MAX_TX_PWR                       0x3F
+#define                RF6052_MAX_REG                          0x3F
+#define                RF6052_MAX_PATH                         2
+/*--------------------------Define Parameters-------------------------------*/
+
+
+/*------------------------------Define structure----------------------------*/
+
+/*------------------------------Define structure----------------------------*/
+
+
+/*------------------------Export global variable----------------------------*/
+/*------------------------Export global variable----------------------------*/
+
+/*------------------------Export Marco Definition---------------------------*/
+
+/*------------------------Export Marco Definition---------------------------*/
+
+
+/*--------------------------Exported Function prototype---------------------*/
+
+/*  */
+/*  RF RL6052 Series API */
+/*  */
+void rtl8723a_phy_rf6052set_bw(struct rtw_adapter *Adapter,
+                              enum ht_channel_width Bandwidth);
+void rtl823a_phy_rf6052setccktxpower(struct rtw_adapter *Adapter,
+                                     u8* pPowerlevel);
+void rtl8723a_PHY_RF6052SetOFDMTxPower(struct rtw_adapter *Adapter,
+                                      u8* pPowerLevel, u8 Channel);
+
+/*--------------------------Exported Function prototype---------------------*/
+
+int    PHY_RF6052_Config8723A(struct rtw_adapter *Adapter);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_spec.h b/drivers/staging/rtl8723au/include/rtl8723a_spec.h
new file mode 100644 (file)
index 0000000..3595c27
--- /dev/null
@@ -0,0 +1,2158 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ *******************************************************************************/
+#ifndef __RTL8723A_SPEC_H__
+#define __RTL8723A_SPEC_H__
+
+/*  */
+/*  */
+/*     0x0000h ~ 0x00FFh       System Configuration */
+/*  */
+/*  */
+#define REG_SYS_ISO_CTRL               0x0000
+#define REG_SYS_FUNC_EN                        0x0002
+#define REG_APS_FSMCO                  0x0004
+#define REG_SYS_CLKR                   0x0008
+#define REG_9346CR                     0x000A
+#define REG_EE_VPD                     0x000C
+#define REG_AFE_MISC                   0x0010
+#define REG_SPS0_CTRL                  0x0011
+#define REG_SPS_OCP_CFG                        0x0018
+#define REG_RSV_CTRL                   0x001C
+#define REG_RF_CTRL                    0x001F
+#define REG_LDOA15_CTRL                        0x0020
+#define REG_LDOV12D_CTRL               0x0021
+#define REG_LDOHCI12_CTRL              0x0022
+#define REG_LPLDO_CTRL                 0x0023
+#define REG_AFE_XTAL_CTRL              0x0024
+#define REG_AFE_PLL_CTRL               0x0028
+#define REG_MAC_PHY_CTRL               0x002c
+#define REG_EFUSE_CTRL                 0x0030
+#define REG_EFUSE_TEST                 0x0034
+#define REG_PWR_DATA                   0x0038
+#define REG_CAL_TIMER                  0x003C
+#define REG_ACLK_MON                   0x003E
+#define REG_GPIO_MUXCFG                        0x0040
+#define REG_GPIO_IO_SEL                        0x0042
+#define REG_MAC_PINMUX_CFG             0x0043
+#define REG_GPIO_PIN_CTRL              0x0044
+#define REG_GPIO_INTM                  0x0048
+#define REG_LEDCFG0                    0x004C
+#define REG_LEDCFG1                    0x004D
+#define REG_LEDCFG2                    0x004E
+#define REG_LEDCFG3                    0x004F
+#define REG_LEDCFG                     REG_LEDCFG2
+#define REG_FSIMR                      0x0050
+#define REG_FSISR                      0x0054
+#define REG_HSIMR                      0x0058
+#define REG_HSISR                      0x005c
+ /*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Pin Control. */
+#define REG_GPIO_PIN_CTRL_2            0x0060
+ /*  RTL8723 WIFI/BT/GPS Multi-Function GPIO Select. */
+#define REG_GPIO_IO_SEL_2              0x0062
+ /*  RTL8723 WIFI/BT/GPS Multi-Function control source. */
+#define REG_MULTI_FUNC_CTRL            0x0068
+#define REG_MCUFWDL                    0x0080
+#define REG_HMEBOX_EXT_0               0x0088
+#define REG_HMEBOX_EXT_1               0x008A
+#define REG_HMEBOX_EXT_2               0x008C
+#define REG_HMEBOX_EXT_3               0x008E
+       /*  Host suspend counter on FPGA platform */
+#define REG_HOST_SUSP_CNT              0x00BC
+       /*  Efuse access protection for RTL8723 */
+#define REG_EFUSE_ACCESS               0x00CF
+#define REG_BIST_SCAN                  0x00D0
+#define REG_BIST_RPT                   0x00D4
+#define REG_BIST_ROM_RPT               0x00D8
+#define REG_USB_SIE_INTF               0x00E0
+#define REG_PCIE_MIO_INTF              0x00E4
+#define REG_PCIE_MIO_INTD              0x00E8
+#define REG_HPON_FSM                   0x00EC
+#define REG_SYS_CFG                    0x00F0
+#define REG_GPIO_OUTSTS                        0x00F4  /*  For RTL8723 only. */
+
+/*  */
+/*  */
+/*     0x0100h ~ 0x01FFh       MACTOP General Configuration */
+/*  */
+/*  */
+#define REG_CR                         0x0100
+#define REG_PBP                                0x0104
+#define REG_TRXDMA_CTRL                        0x010C
+#define REG_TRXFF_BNDY                 0x0114
+#define REG_TRXFF_STATUS               0x0118
+#define REG_RXFF_PTR                   0x011C
+#define REG_HIMR                       0x0120
+#define REG_HISR                       0x0124
+#define REG_HIMRE                      0x0128
+#define REG_HISRE                      0x012C
+#define REG_CPWM                       0x012F
+#define REG_FWIMR                      0x0130
+#define REG_FWISR                      0x0134
+#define REG_PKTBUF_DBG_CTRL            0x0140
+#define REG_PKTBUF_DBG_DATA_L          0x0144
+#define REG_PKTBUF_DBG_DATA_H          0x0148
+
+#define REG_TC0_CTRL                   0x0150
+#define REG_TC1_CTRL                   0x0154
+#define REG_TC2_CTRL                   0x0158
+#define REG_TC3_CTRL                   0x015C
+#define REG_TC4_CTRL                   0x0160
+#define REG_TCUNIT_BASE                        0x0164
+#define REG_MBIST_START                        0x0174
+#define REG_MBIST_DONE                 0x0178
+#define REG_MBIST_FAIL                 0x017C
+#define REG_C2HEVT_MSG_NORMAL          0x01A0
+#define REG_C2HEVT_CLEAR               0x01AF
+#define REG_C2HEVT_MSG_TEST            0x01B8
+#define REG_MCUTST_1                   0x01c0
+#define REG_FMETHR                     0x01C8
+#define REG_HMETFR                     0x01CC
+#define REG_HMEBOX_0                   0x01D0
+#define REG_HMEBOX_1                   0x01D4
+#define REG_HMEBOX_2                   0x01D8
+#define REG_HMEBOX_3                   0x01DC
+
+#define REG_LLT_INIT                   0x01E0
+#define REG_BB_ACCEESS_CTRL            0x01E8
+#define REG_BB_ACCESS_DATA             0x01EC
+
+
+/*  */
+/*  */
+/*     0x0200h ~ 0x027Fh       TXDMA Configuration */
+/*  */
+/*  */
+#define REG_RQPN                       0x0200
+#define REG_FIFOPAGE                   0x0204
+#define REG_TDECTRL                    0x0208
+#define REG_TXDMA_OFFSET_CHK           0x020C
+#define REG_TXDMA_STATUS               0x0210
+#define REG_RQPN_NPQ                   0x0214
+
+/*  */
+/*  */
+/*     0x0280h ~ 0x02FFh       RXDMA Configuration */
+/*  */
+/*  */
+#define REG_RXDMA_AGG_PG_TH            0x0280
+#define REG_RXPKT_NUM                  0x0284
+#define REG_RXDMA_STATUS               0x0288
+
+
+/*  */
+/*  */
+/*     0x0300h ~ 0x03FFh       PCIe */
+/*  */
+/*  */
+#define        REG_PCIE_CTRL_REG               0x0300
+#define        REG_INT_MIG                     0x0304  /*  Interrupt Migration */
+       /*  TX Beacon Descriptor Address */
+#define        REG_BCNQ_DESA                   0x0308
+       /*  TX High Queue Descriptor Address */
+#define        REG_HQ_DESA                     0x0310
+       /*  TX Manage Queue Descriptor Address */
+#define        REG_MGQ_DESA                    0x0318
+       /*  TX VO Queue Descriptor Address */
+#define        REG_VOQ_DESA                    0x0320
+       /*  TX VI Queue Descriptor Address */
+#define        REG_VIQ_DESA                    0x0328
+       /*  TX BE Queue Descriptor Address */
+#define        REG_BEQ_DESA                    0x0330
+       /*  TX BK Queue Descriptor Address */
+#define        REG_BKQ_DESA                    0x0338
+       /*  RX Queue    Descriptor Address */
+#define        REG_RX_DESA                     0x0340
+       /*  Backdoor REG for Access Configuration */
+#define        REG_DBI                         0x0348
+       /*  MDIO for Access PCIE PHY */
+#define        REG_MDIO                        0x0354
+       /*  Debug Selection Register */
+#define        REG_DBG_SEL                     0x0360
+       /* PCIe RPWM */
+#define        REG_PCIE_HRPWM                  0x0361
+       /* PCIe CPWM */
+#define        REG_PCIE_HCPWM                  0x0363
+       /*  UART        Control */
+#define        REG_UART_CTRL                   0x0364
+       /*  UART TX Descriptor Address */
+#define        REG_UART_TX_DESA                0x0370
+       /*  UART Rx Descriptor Address */
+#define        REG_UART_RX_DESA                0x0378
+
+
+/*  spec version 11 */
+/*  */
+/*  */
+/*     0x0400h ~ 0x047Fh       Protocol Configuration */
+/*  */
+/*  */
+#define REG_VOQ_INFORMATION            0x0400
+#define REG_VIQ_INFORMATION            0x0404
+#define REG_BEQ_INFORMATION            0x0408
+#define REG_BKQ_INFORMATION            0x040C
+#define REG_MGQ_INFORMATION            0x0410
+#define REG_HGQ_INFORMATION            0x0414
+#define REG_BCNQ_INFORMATION           0x0418
+
+
+#define REG_CPU_MGQ_INFORMATION                0x041C
+#define REG_FWHW_TXQ_CTRL              0x0420
+#define REG_HWSEQ_CTRL                 0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY         0x0424
+#define REG_TXPKTBUF_MGQ_BDNY          0x0425
+#define REG_LIFETIME_EN                        0x0426
+#define REG_MULTI_BCNQ_OFFSET          0x0427
+#define REG_SPEC_SIFS                  0x0428
+#define REG_RL                         0x042A
+#define REG_DARFRC                     0x0430
+#define REG_RARFRC                     0x0438
+#define REG_RRSR                       0x0440
+#define REG_ARFR0                      0x0444
+#define REG_ARFR1                      0x0448
+#define REG_ARFR2                      0x044C
+#define REG_ARFR3                      0x0450
+#define REG_AGGLEN_LMT                 0x0458
+#define REG_AMPDU_MIN_SPACE            0x045C
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD    0x045D
+#define REG_FAST_EDCA_CTRL             0x0460
+#define REG_RD_RESP_PKT_TH             0x0463
+#define REG_INIRTS_RATE_SEL            0x0480
+#define REG_INIDATA_RATE_SEL           0x0484
+
+
+#define REG_POWER_STATUS               0x04A4
+#define REG_POWER_STAGE1               0x04B4
+#define REG_POWER_STAGE2               0x04B8
+#define REG_PKT_VO_VI_LIFE_TIME                0x04C0
+#define REG_PKT_BE_BK_LIFE_TIME                0x04C2
+#define REG_STBC_SETTING               0x04C4
+#define REG_PROT_MODE_CTRL             0x04C8
+#define REG_MAX_AGGR_NUM               0x04CA
+#define REG_RTS_MAX_AGGR_NUM           0x04CB
+#define REG_BAR_MODE_CTRL              0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT                0x04CF
+#define REG_NQOS_SEQ                   0x04DC
+#define REG_QOS_SEQ                    0x04DE
+#define REG_NEED_CPU_HANDLE            0x04E0
+#define REG_PKT_LOSE_RPT               0x04E1
+#define REG_PTCL_ERR_STATUS            0x04E2
+#define REG_DUMMY                      0x04FC
+
+
+
+/*  */
+/*  */
+/*     0x0500h ~ 0x05FFh       EDCA Configuration */
+/*  */
+/*  */
+#define REG_EDCA_VO_PARAM              0x0500
+#define REG_EDCA_VI_PARAM              0x0504
+#define REG_EDCA_BE_PARAM              0x0508
+#define REG_EDCA_BK_PARAM              0x050C
+#define REG_BCNTCFG                    0x0510
+#define REG_PIFS                       0x0512
+#define REG_RDG_PIFS                   0x0513
+#define REG_SIFS_CCK                   0x0514
+#define REG_SIFS_OFDM                  0x0516
+#define REG_SIFS_CTX                   0x0514
+#define REG_SIFS_TRX                   0x0516
+#define REG_TSFTR_SYN_OFFSET           0x0518
+#define REG_AGGR_BREAK_TIME            0x051A
+#define REG_SLOT                       0x051B
+#define REG_TX_PTCL_CTRL               0x0520
+#define REG_TXPAUSE                    0x0522
+#define REG_DIS_TXREQ_CLR              0x0523
+#define REG_RD_CTRL                    0x0524
+#define REG_TBTT_PROHIBIT              0x0540
+#define REG_RD_NAV_NXT                 0x0544
+#define REG_NAV_PROT_LEN               0x0546
+#define REG_BCN_CTRL                   0x0550
+#define REG_BCN_CTRL_1                 0x0551
+#define REG_MBID_NUM                   0x0552
+#define REG_DUAL_TSF_RST               0x0553
+       /*  The same as REG_MBSSID_BCN_SPACE */
+#define REG_BCN_INTERVAL               0x0554
+#define REG_MBSSID_BCN_SPACE           0x0554
+#define REG_DRVERLYINT                 0x0558
+#define REG_BCNDMATIM                  0x0559
+#define REG_ATIMWND                    0x055A
+#define REG_BCN_MAX_ERR                        0x055D
+#define REG_RXTSF_OFFSET_CCK           0x055E
+#define REG_RXTSF_OFFSET_OFDM          0x055F
+#define REG_TSFTR                      0x0560
+#define REG_TSFTR1                     0x0568
+#define REG_INIT_TSFTR                 0x0564
+#define REG_ATIMWND_1                  0x0570
+#define REG_PSTIMER                    0x0580
+#define REG_TIMER0                     0x0584
+#define REG_TIMER1                     0x0588
+#define REG_ACMHWCTRL                  0x05C0
+#define REG_ACMRSTCTRL                 0x05C1
+#define REG_ACMAVG                     0x05C2
+#define REG_VO_ADMTIME                 0x05C4
+#define REG_VI_ADMTIME                 0x05C6
+#define REG_BE_ADMTIME                 0x05C8
+#define REG_EDCA_RANDOM_GEN            0x05CC
+#define REG_SCH_TXCMD                  0x05D0
+
+/* define REG_FW_TSF_SYNC_CNT          0x04A0 */
+#define REG_FW_RESET_TSF_CNT_1         0x05FC
+#define REG_FW_RESET_TSF_CNT_0         0x05FD
+#define REG_FW_BCN_DIS_CNT             0x05FE
+
+/*  */
+/*  */
+/*     0x0600h ~ 0x07FFh       WMAC Configuration */
+/*  */
+/*  */
+#define REG_APSD_CTRL                  0x0600
+#define REG_BWOPMODE                   0x0603
+#define REG_TCR                                0x0604
+#define REG_RCR                                0x0608
+#define REG_RX_PKT_LIMIT               0x060C
+#define REG_RX_DLK_TIME                        0x060D
+#define REG_RX_DRVINFO_SZ              0x060F
+
+#define REG_MACID                      0x0610
+#define REG_BSSID                      0x0618
+#define REG_MAR                                0x0620
+#define REG_MBIDCAMCFG                 0x0628
+
+#define REG_USTIME_EDCA                        0x0638
+#define REG_MAC_SPEC_SIFS              0x063A
+
+/*  20100719 Joseph: Hardware register definition change. (HW datasheet v54) */
+       /*  [15:8]SIFS_R2T_OFDM, [7:0]SIFS_R2T_CCK */
+#define REG_R2T_SIFS                   0x063C
+       /*  [15:8]SIFS_T2T_OFDM, [7:0]SIFS_T2T_CCK */
+#define REG_T2T_SIFS                   0x063E
+#define REG_ACKTO                      0x0640
+#define REG_CTS2TO                     0x0641
+#define REG_EIFS                       0x0642
+
+/* WMA, BA, CCX */
+#define REG_NAV_CTRL                   0x0650
+#define REG_BACAMCMD                   0x0654
+#define REG_BACAMCONTENT               0x0658
+#define REG_LBDLY                      0x0660
+#define REG_FWDLY                      0x0661
+#define REG_RXERR_RPT                  0x0664
+#define REG_WMAC_TRXPTCL_CTL           0x0668
+
+
+/*  Security */
+#define REG_CAMCMD                     0x0670
+#define REG_CAMWRITE                   0x0674
+#define REG_CAMREAD                    0x0678
+#define REG_CAMDBG                     0x067C
+#define REG_SECCFG                     0x0680
+
+/*  Power */
+#define REG_WOW_CTRL                   0x0690
+#define REG_PSSTATUS                   0x0691
+#define REG_PS_RX_INFO                 0x0692
+#define REG_LPNAV_CTRL                 0x0694
+#define REG_WKFMCAM_CMD                        0x0698
+#define REG_WKFMCAM_RWD                        0x069C
+#define REG_RXFLTMAP0                  0x06A0
+#define REG_RXFLTMAP1                  0x06A2
+#define REG_RXFLTMAP2                  0x06A4
+#define REG_BCN_PSR_RPT                        0x06A8
+#define REG_CALB32K_CTRL               0x06AC
+#define REG_PKT_MON_CTRL               0x06B4
+#define REG_BT_COEX_TABLE              0x06C0
+#define REG_WMAC_RESP_TXINFO           0x06D8
+
+#define REG_MACID1                     0x0700
+#define REG_BSSID1                     0x0708
+
+
+/*  */
+/*  */
+/*     0xFE00h ~ 0xFE55h       USB Configuration */
+/*  */
+/*  */
+#define REG_USB_INFO                   0xFE17
+#define REG_USB_SPECIAL_OPTION         0xFE55
+#define REG_USB_DMA_AGG_TO             0xFE5B
+#define REG_USB_AGG_TO                 0xFE5C
+#define REG_USB_AGG_TH                 0xFE5D
+
+/*  For test chip */
+#define REG_TEST_USB_TXQS              0xFE48
+#define REG_TEST_SIE_VID               0xFE60          /*  0xFE60~0xFE61 */
+#define REG_TEST_SIE_PID               0xFE62          /*  0xFE62~0xFE63 */
+#define REG_TEST_SIE_OPTIONAL          0xFE64
+#define REG_TEST_SIE_CHIRP_K           0xFE65
+#define REG_TEST_SIE_PHY               0xFE66          /*  0xFE66~0xFE6B */
+#define REG_TEST_SIE_MAC_ADDR          0xFE70          /*  0xFE70~0xFE75 */
+#define REG_TEST_SIE_STRING            0xFE80          /*  0xFE80~0xFEB9 */
+
+
+/*  For normal chip */
+#define REG_NORMAL_SIE_VID             0xFE60          /*  0xFE60~0xFE61 */
+#define REG_NORMAL_SIE_PID             0xFE62          /*  0xFE62~0xFE63 */
+#define REG_NORMAL_SIE_OPTIONAL                0xFE64
+#define REG_NORMAL_SIE_EP              0xFE65          /*  0xFE65~0xFE67 */
+#define REG_NORMAL_SIE_PHY             0xFE68          /*  0xFE68~0xFE6B */
+#define REG_NORMAL_SIE_OPTIONAL2       0xFE6C
+#define REG_NORMAL_SIE_GPS_EP          0xFE6D          /*  RTL8723 only */
+#define REG_NORMAL_SIE_MAC_ADDR                0xFE70          /*  0xFE70~0xFE75 */
+#define REG_NORMAL_SIE_STRING          0xFE80          /*  0xFE80~0xFEDF */
+
+
+/*  */
+/*  */
+/*     Redifine 8192C register definition for compatibility */
+/*  */
+/*  */
+
+/*  TODO: use these definition when using REG_xxx naming rule. */
+/*  NOTE: DO NOT Remove these definition. Use later. */
+
+       /*  System Isolation Interface Control. */
+#define        SYS_ISO_CTRL                    REG_SYS_ISO_CTRL
+       /*  System Function Enable. */
+#define        SYS_FUNC_EN                     REG_SYS_FUNC_EN
+#define        SYS_CLK                         REG_SYS_CLKR
+       /*  93C46/93C56 Command Register. */
+#define        CR9346                          REG_9346CR
+       /*  E-Fuse Control. */
+#define        EFUSE_CTRL                      REG_EFUSE_CTRL
+       /*  E-Fuse Test. */
+#define        EFUSE_TEST                      REG_EFUSE_TEST
+       /*  Media Status register */
+#define        MSR                             (REG_CR + 2)
+#define        ISR                             REG_HISR
+       /*  Timing Sync Function Timer Register. */
+#define        TSFR                            REG_TSFTR
+
+       /*  MAC ID Register, Offset 0x0050-0x0053 */
+#define        MACIDR0                         REG_MACID
+       /*  MAC ID Register, Offset 0x0054-0x0055 */
+#define        MACIDR4                         (REG_MACID + 4)
+
+#define        PBP                             REG_PBP
+
+       /*  Redifine MACID register, to compatible prior ICs. */
+#define        IDR0                            MACIDR0
+#define        IDR4                            MACIDR4
+
+
+/*  */
+/*  9. Security Control Registers      (Offset: ) */
+/*  */
+       /* IN 8190 Data Sheet is called CAMcmd */
+#define        RWCAM                           REG_CAMCMD
+       /*  Software write CAM input content */
+#define        WCAMI                           REG_CAMWRITE
+       /*  Software read/write CAM config */
+#define        RCAMO                           REG_CAMREAD
+#define        CAMDBG                          REG_CAMDBG
+       /* Security Configuration Register */
+#define        SECR                            REG_SECCFG
+
+/*  Unused register */
+#define        UnusedRegister                  0x1BF
+#define        DCAM                            UnusedRegister
+#define        PSR                             UnusedRegister
+#define        BBAddr                          UnusedRegister
+#define        PhyDataR                        UnusedRegister
+
+#define        InvalidBBRFValue                0x12345678
+
+/*  Min Spacing related settings. */
+#define        MAX_MSS_DENSITY_2T              0x13
+#define        MAX_MSS_DENSITY_1T              0x0A
+
+/*  */
+/* 8192C Cmd9346CR bits                        (Offset 0xA, 16bit) */
+/*  */
+        /*  EEPROM enable when set 1 */
+#define        CmdEEPROM_En                    BIT5
+       /*  System EEPROM select, 0: boot from E-FUSE,
+           1: The EEPROM used is 9346 */
+#define        CmdEERPOMSEL                    BIT4
+#define        Cmd9346CR_9356SEL               BIT4
+#define        AutoLoadEEPROM                  (CmdEEPROM_En|CmdEERPOMSEL)
+#define        AutoLoadEFUSE                   CmdEEPROM_En
+
+/*  */
+/* 8192C GPIO MUX Configuration Register (offset 0x40, 4 byte) */
+/*  */
+#define        GPIOSEL_GPIO                    0
+#define        GPIOSEL_ENBT                    BIT5
+
+/*  */
+/*        8192C GPIO PIN Control Register (offset 0x44, 4 byte) */
+/*  */
+       /*  GPIO pins input value */
+#define        GPIO_IN                         REG_GPIO_PIN_CTRL
+       /*  GPIO pins output value */
+#define        GPIO_OUT                        (REG_GPIO_PIN_CTRL+1)
+       /*  GPIO pins output enable when a bit is set to "1";
+           otherwise, input is configured. */
+#define        GPIO_IO_SEL                     (REG_GPIO_PIN_CTRL+2)
+#define        GPIO_MOD                        (REG_GPIO_PIN_CTRL+3)
+
+/*  */
+/* 8192C (MSR) Media Status Register   (Offset 0x4C, 8 bits) */
+/*  */
+/*
+Network Type
+00: No link
+01: Link in ad hoc network
+10: Link in infrastructure network
+11: AP mode
+Default: 00b.
+*/
+#define        MSR_NOLINK                      0x00
+#define        MSR_ADHOC                       0x01
+#define        MSR_INFRA                       0x02
+#define        MSR_AP                          0x03
+
+/*  */
+/*  6. Adaptive Control Registers  (Offset: 0x0160 - 0x01CF) */
+/*  */
+/*  */
+/* 8192C Response Rate Set Register    (offset 0x181, 24bits) */
+/*  */
+#define        RRSR_RSC_OFFSET                 21
+#define        RRSR_SHORT_OFFSET               23
+#define        RRSR_RSC_BW_40M                 0x600000
+#define        RRSR_RSC_UPSUBCHNL              0x400000
+#define        RRSR_RSC_LOWSUBCHNL             0x200000
+#define        RRSR_SHORT                      0x800000
+#define        RRSR_1M                         BIT0
+#define        RRSR_2M                         BIT1
+#define        RRSR_5_5M                       BIT2
+#define        RRSR_11M                        BIT3
+#define        RRSR_6M                         BIT4
+#define        RRSR_9M                         BIT5
+#define        RRSR_12M                        BIT6
+#define        RRSR_18M                        BIT7
+#define        RRSR_24M                        BIT8
+#define        RRSR_36M                        BIT9
+#define        RRSR_48M                        BIT10
+#define        RRSR_54M                        BIT11
+#define        RRSR_MCS0                       BIT12
+#define        RRSR_MCS1                       BIT13
+#define        RRSR_MCS2                       BIT14
+#define        RRSR_MCS3                       BIT15
+#define        RRSR_MCS4                       BIT16
+#define        RRSR_MCS5                       BIT17
+#define        RRSR_MCS6                       BIT18
+#define        RRSR_MCS7                       BIT19
+#define        BRSR_AckShortPmb                BIT23
+/*  CCK ACK: use Short Preamble or not */
+
+/*  */
+/* 8192C BW_OPMODE bits                        (Offset 0x203, 8bit) */
+/*  */
+#define        BW_OPMODE_20MHZ                 BIT2
+#define        BW_OPMODE_5G                    BIT1
+#define        BW_OPMODE_11J                   BIT0
+
+
+/*  */
+/* 8192C CAM Config Setting (offset 0x250, 1 byte) */
+/*  */
+#define        CAM_VALID                       BIT15
+#define        CAM_NOTVALID                    0x0000
+#define        CAM_USEDK                       BIT5
+
+#define        CAM_CONTENT_COUNT               8
+
+#define        CAM_NONE                        0x0
+#define        CAM_WEP40                       0x01
+#define        CAM_TKIP                        0x02
+#define        CAM_AES                         0x04
+#define        CAM_WEP104                      0x05
+
+#define        TOTAL_CAM_ENTRY                 32
+#define        HALF_CAM_ENTRY                  16
+
+#define        CAM_CONFIG_USEDK                true
+#define        CAM_CONFIG_NO_USEDK             false
+
+#define        CAM_WRITE                       BIT16
+#define        CAM_READ                        0x00000000
+#define        CAM_POLLINIG                    BIT31
+
+#define        SCR_UseDK                       0x01
+#define        SCR_TxSecEnable                 0x02
+#define        SCR_RxSecEnable                 0x04
+
+
+/*  */
+/*  12. Host Interrupt Status Registers         (Offset: 0x0300 - 0x030F) */
+/*  */
+/*  */
+/* 8190 IMR/ISR bits                   (offset 0xfd,  8bits) */
+/*  */
+#define        IMR8190_DISABLED                0x0
+/*  IMR DW0 Bit 0-31 */
+
+#define        IMR_BCNDMAINT6                  BIT31   /*  Beacon DMA Interrupt 6 */
+#define        IMR_BCNDMAINT5                  BIT30   /*  Beacon DMA Interrupt 5 */
+#define        IMR_BCNDMAINT4                  BIT29   /*  Beacon DMA Interrupt 4 */
+#define        IMR_BCNDMAINT3                  BIT28   /*  Beacon DMA Interrupt 3 */
+#define        IMR_BCNDMAINT2                  BIT27   /*  Beacon DMA Interrupt 2 */
+#define        IMR_BCNDMAINT1                  BIT26   /*  Beacon DMA Interrupt 1 */
+#define        IMR_BCNDOK8                     BIT25   /*  Beacon Queue DMA OK
+                                                   Interrupt 8 */
+#define        IMR_BCNDOK7                     BIT24   /*  Beacon Queue DMA OK
+                                                   Interrupt 7 */
+#define        IMR_BCNDOK6                     BIT23   /*  Beacon Queue DMA OK
+                                                   Interrupt 6 */
+#define        IMR_BCNDOK5                     BIT22   /*  Beacon Queue DMA OK
+                                                   Interrupt 5 */
+#define        IMR_BCNDOK4                     BIT21   /*  Beacon Queue DMA OK
+                                                   Interrupt 4 */
+#define        IMR_BCNDOK3                     BIT20   /*  Beacon Queue DMA OK
+                                                   Interrupt 3 */
+#define        IMR_BCNDOK2                     BIT19   /*  Beacon Queue DMA OK
+                                                   Interrupt 2 */
+#define        IMR_BCNDOK1                     BIT18   /*  Beacon Queue DMA OK
+                                                   Interrupt 1 */
+#define        IMR_TIMEOUT2                    BIT17   /*  Timeout interrupt 2 */
+#define        IMR_TIMEOUT1                    BIT16   /*  Timeout interrupt 1 */
+#define        IMR_TXFOVW                      BIT15   /*  Transmit FIFO Overflow */
+#define        IMR_PSTIMEOUT                   BIT14   /*  Power save time out
+                                                   interrupt */
+#define        IMR_BcnInt                      BIT13   /*  Beacon DMA Interrupt 0 */
+#define        IMR_RXFOVW                      BIT12   /*  Receive FIFO Overflow */
+#define        IMR_RDU                         BIT11   /*  Receive Descriptor
+                                                   Unavailable */
+#define        IMR_ATIMEND                     BIT10   /*  For 92C,ATIM Window
+                                                   End Interrupt */
+#define        IMR_BDOK                        BIT9    /*  Beacon Queue DMA OK
+                                                   Interrup */
+#define        IMR_HIGHDOK                     BIT8    /*  High Queue DMA OK
+                                                   Interrupt */
+#define        IMR_TBDOK                       BIT7    /*  Transmit Beacon OK
+                                                   interrup */
+#define        IMR_MGNTDOK                     BIT6    /*  Management Queue DMA OK
+                                                   Interrupt */
+#define        IMR_TBDER                       BIT5    /*  For 92C,Transmit Beacon
+                                                   Error Interrupt */
+#define        IMR_BKDOK                       BIT4    /*  AC_BK DMA OK Interrupt */
+#define        IMR_BEDOK                       BIT3    /*  AC_BE DMA OK Interrupt */
+#define        IMR_VIDOK                       BIT2    /*  AC_VI DMA OK Interrupt */
+#define        IMR_VODOK                       BIT1    /*  AC_VO DMA Interrupt */
+#define        IMR_ROK                         BIT0    /*  Receive DMA OK Interrupt */
+
+#define        IMR_RX_MASK                     (IMR_ROK|IMR_RDU|IMR_RXFOVW)
+#define        IMR_TX_MASK                     (IMR_VODOK|IMR_VIDOK|IMR_BEDOK| \
+                                        IMR_BKDOK|IMR_MGNTDOK|IMR_HIGHDOK| \
+                                        IMR_BDOK)
+
+/*  13. Host Interrupt Status Extension Register (Offset: 0x012C-012Eh) */
+#define        IMR_BcnInt_E                    BIT12
+#define        IMR_TXERR                       BIT11
+#define        IMR_RXERR                       BIT10
+#define        IMR_C2HCMD                      BIT9
+#define        IMR_CPWM                        BIT8
+/* RSVD [2-7] */
+#define        IMR_OCPINT                      BIT1
+#define        IMR_WLANOFF                     BIT0
+
+
+/*        8192C EEPROM/EFUSE share register definition. */
+
+/*  Default Value for EEPROM or EFUSE!!! */
+#define EEPROM_Default_TSSI                    0x0
+#define EEPROM_Default_TxPowerDiff             0x0
+#define EEPROM_Default_CrystalCap              0x5
+ /*  Default: 2X2, RTL8192CE(QFPN68) */
+#define EEPROM_Default_BoardType               0x02
+#define EEPROM_Default_TxPower                 0x1010
+#define EEPROM_Default_HT2T_TxPwr              0x10
+
+#define EEPROM_Default_LegacyHTTxPowerDiff     0x3
+#define EEPROM_Default_ThermalMeter            0x12
+
+#define EEPROM_Default_AntTxPowerDiff          0x0
+#define EEPROM_Default_TxPwDiff_CrystalCap     0x5
+#define EEPROM_Default_TxPowerLevel            0x22
+#define EEPROM_Default_HT40_2SDiff             0x0
+       /*  HT20<->40 default Tx Power Index Difference */
+#define EEPROM_Default_HT20_Diff               2
+#define EEPROM_Default_LegacyHTTxPowerDiff     0x3
+#define EEPROM_Default_HT40_PwrMaxOffset       0
+#define EEPROM_Default_HT20_PwrMaxOffset       0
+
+/*  For debug */
+#define EEPROM_Default_PID                     0x1234
+#define EEPROM_Default_VID                     0x5678
+#define EEPROM_Default_CustomerID              0xAB
+#define EEPROM_Default_SubCustomerID           0xCD
+#define EEPROM_Default_Version                 0
+
+#define EEPROM_CHANNEL_PLAN_FCC                        0x0
+#define EEPROM_CHANNEL_PLAN_IC                 0x1
+#define EEPROM_CHANNEL_PLAN_ETSI               0x2
+#define EEPROM_CHANNEL_PLAN_SPAIN              0x3
+#define EEPROM_CHANNEL_PLAN_FRANCE             0x4
+#define EEPROM_CHANNEL_PLAN_MKK                        0x5
+#define EEPROM_CHANNEL_PLAN_MKK1               0x6
+#define EEPROM_CHANNEL_PLAN_ISRAEL             0x7
+#define EEPROM_CHANNEL_PLAN_TELEC              0x8
+#define EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN      0x9
+#define EEPROM_CHANNEL_PLAN_WORLD_WIDE_13      0xA
+#define EEPROM_CHANNEL_PLAN_NCC                        0xB
+#define EEPROM_USB_OPTIONAL1                   0xE
+#define EEPROM_CHANNEL_PLAN_BY_HW_MASK         0x80
+
+
+#define EEPROM_CID_DEFAULT                     0x0
+#define EEPROM_CID_TOSHIBA                     0x4
+ /*  CCX test. By Bruce, 2009-02-25. */
+#define EEPROM_CID_CCX                         0x10
+#define EEPROM_CID_QMI                         0x0D
+ /*  added by chiyoko for dtm, 20090108 */
+#define EEPROM_CID_WHQL                                0xFE
+
+
+#define        RTL_EEPROM_ID                           0x8129
+
+#define        SUPPORT_HW_RADIO_DETECT(pHalData)               \
+       (pHalData->BoardType == BOARD_MINICARD ||       \
+       pHalData->BoardType == BOARD_USB_SOLO ||        \
+       pHalData->BoardType == BOARD_USB_COMBO)
+
+/*  */
+/*  EEPROM address for Test chip */
+/*  */
+#define EEPROM_TEST_USB_OPT            0x0E
+#define EEPROM_TEST_CHIRP_K            0x0F
+#define EEPROM_TEST_EP_SETTING         0x0E
+#define EEPROM_TEST_USB_PHY            0x10
+
+
+/*  */
+/*  EEPROM address for Normal chip */
+/*  */
+#define EEPROM_NORMAL_USB_OPT          0x0E
+#define EEPROM_NORMAL_CHIRP_K          0x0E    /*  Changed */
+#define EEPROM_NORMAL_EP_SETTING       0x0F    /*  Changed */
+#define EEPROM_NORMAL_USB_PHY          0x12    /*  Changed */
+
+enum {
+       BOARD_USB_DONGLE = 0,   /*  USB dongle */
+       BOARD_USB_High_PA = 1,  /*  USB dongle with high power PA */
+       BOARD_MINICARD = 2,     /*  Minicard */
+       BOARD_USB_SOLO = 3,     /*  USB solo-Slim module */
+       BOARD_USB_COMBO = 4,    /*  USB Combo-Slim module */
+};
+
+/*  Test chip and normal chip common define */
+/*  */
+/*  EEPROM address for both */
+/*  */
+#define EEPROM_ID0                     0x00
+#define EEPROM_ID1                     0x01
+#define EEPROM_RTK_RSV1                        0x02
+#define EEPROM_RTK_RSV2                        0x03
+#define EEPROM_RTK_RSV3                        0x04
+#define EEPROM_RTK_RSV4                        0x05
+#define EEPROM_RTK_RSV5                        0x06
+#define EEPROM_DBG_SEL                 0x07
+#define EEPROM_RTK_RSV6                        0x08
+#define EEPROM_VID                     0x0A
+#define EEPROM_PID                     0x0C
+
+#define EEPROM_MAC_ADDR                        0x16
+#define EEPROM_STRING                  0x1C
+#define EEPROM_SUBCUSTOMER_ID          0x59
+#define EEPROM_CCK_TX_PWR_INX          0x5A
+#define EEPROM_HT40_1S_TX_PWR_INX      0x60
+#define EEPROM_HT40_2S_TX_PWR_INX_DIFF 0x66
+#define EEPROM_HT20_TX_PWR_INX_DIFF    0x69
+#define EEPROM_OFDM_TX_PWR_INX_DIFF    0x6C
+#define EEPROM_HT40_MAX_PWR_OFFSET     0x6F
+#define EEPROM_HT20_MAX_PWR_OFFSET     0x72
+
+#define EEPROM_CHANNEL_PLAN            0x75
+#define EEPROM_TSSI_A                  0x76
+#define EEPROM_TSSI_B                  0x77
+#define EEPROM_THERMAL_METER           0x78
+#define EEPROM_RF_OPT1                 0x79
+#define EEPROM_RF_OPT2                 0x7A
+#define EEPROM_RF_OPT3                 0x7B
+#define EEPROM_RF_OPT4                 0x7C
+#define EEPROM_VERSION                 0x7E
+#define EEPROM_CUSTOMER_ID             0x7F
+
+        /* 0x0: RTL8188SU, 0x1: RTL8191SU, 0x2: RTL8192SU, 0x3: RTL8191GU */
+#define EEPROM_BoardType               0x54
+       /* 0x5C-0x76, Tx Power index. */
+#define EEPROM_TxPwIndex               0x5C
+       /*  Difference of gain index between legacy and high throughput OFDM. */
+#define EEPROM_PwDiff                  0x67
+       /*  CCK Tx Power */
+#define EEPROM_TxPowerCCK              0x5A
+
+/*  2009/02/09 Cosa Add for SD3 requirement */
+       /*  HT20 Tx Power Index Difference */
+#define EEPROM_TX_PWR_HT20_DIFF                0x6e
+       /*  HT20<->40 default Tx Power Index Difference */
+#define DEFAULT_HT20_TXPWR_DIFF                2
+       /*  OFDM Tx Power Index Difference */
+#define EEPROM_TX_PWR_OFDM_DIFF                0x71
+
+       /*  Power diff for channel group */
+#define EEPROM_TxPWRGroup              0x73
+       /*  Check if power safety is need */
+#define EEPROM_Regulatory              0x79
+
+       /*  92cu, 0x7E[4] */
+#define EEPROM_BLUETOOTH_COEXIST       0x7E
+#define EEPROM_NORMAL_BoardType                EEPROM_RF_OPT1  /* 7:5] */
+#define BOARD_TYPE_NORMAL_MASK         0xE0
+#define BOARD_TYPE_TEST_MASK           0x0F
+       /* BIT0 1 for build-in module, 0 for external dongle */
+#define EEPROM_EASY_REPLACEMENT                0x50
+/*  */
+/* EPROM content definitions */
+/*  */
+#define OS_LINK_SPEED                  BIT(5)
+
+#define BOARD_TYPE_MASK                        0xF
+
+#define BT_COEXISTENCE                 BIT(4)
+#define BT_CO_SHIFT                    4
+
+#define EP_NUMBER_MASK                 0x30    /* bit 4:5 0Eh */
+#define EP_NUMBER_SHIFT                        4
+
+
+#define USB_PHY_PARA_SIZE              5
+
+
+/*  */
+/*     \14EEPROM default value definitions */
+/*  */
+/*  Use 0xABCD instead of 0x8192 for debug */
+#define EEPROM_DEF_ID_0                        0xCD    /*  Byte 0x00 */
+#define EEPROM_DEF_ID_1                        0xAB    /*  Byte 0x01 */
+
+#define EEPROM_DEF_RTK_RSV_A3          0x74    /*  Byte 0x03 */
+#define EEPROM_DEF_RTK_RSV_A4          0x6D    /*  Byte 0x04 */
+#define EEPROM_DEF_RTK_RSV_A8          0xFF    /*  Byte 0x08 */
+
+#define EEPROM_DEF_VID_0               0x0A    /*  Byte 0x0A */
+#define EEPROM_DEF_VID_1               0x0B
+
+#define EEPROM_DEF_PID_0               0x92    /*  Byte 0x0C */
+#define EEPROM_DEF_PID_1               0x81
+
+
+#define EEPROM_TEST_DEF_USB_OPT                0x80    /*  Byte 0x0E */
+#define EEPROM_NORMAL_DEF_USB_OPT      0x00    /*  Byte 0x0E */
+
+#define EEPROM_DEF_CHIRPK              0x15    /*  Byte 0x0F */
+
+#define EEPROM_DEF_USB_PHY_0           0x85    /*  Byte 0x10 */
+#define EEPROM_DEF_USB_PHY_1           0x62    /*  Byte 0x11 */
+#define EEPROM_DEF_USB_PHY_2           0x9E    /*  Byte 0x12 */
+#define EEPROM_DEF_USB_PHY_3           0x06    /*  Byte 0x13 */
+
+#define EEPROM_DEF_TSSI_A              0x09    /*  Byte 0x78 */
+#define EEPROM_DEF_TSSI_B              0x09    /*  Byte 0x79 */
+
+
+#define EEPROM_DEF_THERMAL_METER       0x12    /*  Byte 0x7A */
+
+       /*  Check if power safety spec is need */
+#define RF_OPTION1                     0x79
+#define RF_OPTION2                     0x7A
+#define RF_OPTION3                     0x7B
+#define RF_OPTION4                     0x7C
+
+
+#define        EEPROM_USB_SN                   BIT(0)
+#define        EEPROM_USB_REMOTE_WAKEUP        BIT(1)
+#define        EEPROM_USB_DEVICE_PWR           BIT(2)
+#define        EEPROM_EP_NUMBER                (BIT(3)|BIT(4))
+
+/*===================================================================
+=====================================================================
+Here the register defines are for 92C. When the define is as same with 92C,
+we will use the 92C's define for the consistency
+So the following defines for 92C is not entire!!!!!!
+=====================================================================
+=====================================================================*/
+/*
+Based on Datasheet V33---090401
+Register Summary
+Current IOREG MAP
+0x0000h ~ 0x00FFh   System Configuration (256 Bytes)
+0x0100h ~ 0x01FFh   MACTOP General Configuration (256 Bytes)
+0x0200h ~ 0x027Fh   TXDMA Configuration (128 Bytes)
+0x0280h ~ 0x02FFh   RXDMA Configuration (128 Bytes)
+0x0300h ~ 0x03FFh   PCIE EMAC Reserved Region (256 Bytes)
+0x0400h ~ 0x04FFh   Protocol Configuration (256 Bytes)
+0x0500h ~ 0x05FFh   EDCA Configuration (256 Bytes)
+0x0600h ~ 0x07FFh   WMAC Configuration (512 Bytes)
+0x2000h ~ 0x3FFFh   8051 FW Download Region (8196 Bytes)
+*/
+
+/*  */
+/* 8192C (RCR) Receive Configuration Register  (Offset 0x608, 32 bits) */
+/*  */
+#define        RCR_APPFCS                      BIT31 /* WMAC append FCS after payload*/
+#define        RCR_APP_MIC                     BIT30
+#define        RCR_APP_PHYSTS                  BIT28
+#define        RCR_APP_ICV                     BIT29
+#define        RCR_APP_PHYST_RXFF              BIT28
+#define        RCR_APP_BA_SSN                  BIT27 /* Accept BA SSN */
+#define        RCR_ENMBID                      BIT24 /* Enable Multiple BssId. */
+#define        RCR_LSIGEN                      BIT23
+#define        RCR_MFBEN                       BIT22
+#define        RCR_HTC_LOC_CTRL                BIT14 /* MFC<--HTC=1 MFC-->HTC=0 */
+#define        RCR_AMF                         BIT13 /* Accept management type frame */
+#define        RCR_ACF                         BIT12 /* Accept control type frame */
+#define        RCR_ADF                         BIT11 /* Accept data type frame */
+#define        RCR_AICV                        BIT9  /* Accept ICV error packet */
+#define        RCR_ACRC32                      BIT8  /* Accept CRC32 error packet */
+#define        RCR_CBSSID_BCN                  BIT7  /* Accept BSSID match packet
+                                                (Rx beacon, probe rsp) */
+#define        RCR_CBSSID_DATA                 BIT6  /* Accept BSSID match packet
+                                                (Data) */
+#define        RCR_CBSSID                      RCR_CBSSID_DATA /* Accept BSSID match
+                                                          packet */
+#define        RCR_APWRMGT                     BIT5  /* Accept power management
+                                                packet */
+#define        RCR_ADD3                        BIT4  /* Accept address 3 match
+                                                packet */
+#define        RCR_AB                          BIT3  /* Accept broadcast packet */
+#define        RCR_AM                          BIT2  /* Accept multicast packet */
+#define        RCR_APM                         BIT1  /* Accept physical match packet */
+#define        RCR_AAP                         BIT0  /* Accept all unicast packet */
+#define        RCR_MXDMA_OFFSET                8
+#define        RCR_FIFO_OFFSET                 13
+
+
+
+/*  */
+/* 8192c USB specific Regsiter Offset and Content definition, */
+/* 2009.08.18, added by vivi. for merge 92c and 92C into one driver */
+/*  */
+/* define APS_FSMCO                    0x0004  same with 92Ce */
+#define RSV_CTRL                       0x001C
+#define RD_CTRL                                0x0524
+
+/*  */
+/*  */
+/*     0xFE00h ~ 0xFE55h       USB Configuration */
+/*  */
+/*  */
+#define REG_USB_INFO                   0xFE17
+#define REG_USB_SPECIAL_OPTION         0xFE55
+#define REG_USB_DMA_AGG_TO             0xFE5B
+#define REG_USB_AGG_TO                 0xFE5C
+#define REG_USB_AGG_TH                 0xFE5D
+
+#define REG_USB_VID                    0xFE60
+#define REG_USB_PID                    0xFE62
+#define REG_USB_OPTIONAL               0xFE64
+#define REG_USB_CHIRP_K                        0xFE65
+#define REG_USB_PHY                    0xFE66
+#define REG_USB_MAC_ADDR               0xFE70
+
+#define REG_USB_HRPWM                  0xFE58
+#define REG_USB_HCPWM                  0xFE57
+
+#define        InvalidBBRFValue                0x12345678
+
+/*  */
+/*        8192C Regsiter Bit and Content definition */
+/*  */
+/*  */
+/*  */
+/*     0x0000h ~ 0x00FFh       System Configuration */
+/*  */
+/*  */
+
+/* 2 SPS0_CTRL */
+#define SW18_FPWM                      BIT(3)
+
+
+/* 2 SYS_ISO_CTRL */
+#define ISO_MD2PP                      BIT(0)
+#define ISO_UA2USB                     BIT(1)
+#define ISO_UD2CORE                    BIT(2)
+#define ISO_PA2PCIE                    BIT(3)
+#define ISO_PD2CORE                    BIT(4)
+#define ISO_IP2MAC                     BIT(5)
+#define ISO_DIOP                       BIT(6)
+#define ISO_DIOE                       BIT(7)
+#define ISO_EB2CORE                    BIT(8)
+#define ISO_DIOR                       BIT(9)
+
+#define PWC_EV25V                      BIT(14)
+#define PWC_EV12V                      BIT(15)
+
+
+/* 2 SYS_FUNC_EN */
+#define FEN_BBRSTB                     BIT(0)
+#define FEN_BB_GLB_RSTn                        BIT(1)
+#define FEN_USBA                       BIT(2)
+#define FEN_UPLL                       BIT(3)
+#define FEN_USBD                       BIT(4)
+#define FEN_DIO_PCIE                   BIT(5)
+#define FEN_PCIEA                      BIT(6)
+#define FEN_PPLL                       BIT(7)
+#define FEN_PCIED                      BIT(8)
+#define FEN_DIOE                       BIT(9)
+#define FEN_CPUEN                      BIT(10)
+#define FEN_DCORE                      BIT(11)
+#define FEN_ELDR                       BIT(12)
+#define FEN_DIO_RF                     BIT(13)
+#define FEN_HWPDN                      BIT(14)
+#define FEN_MREGEN                     BIT(15)
+
+/* 2 APS_FSMCO */
+#define PFM_LDALL                      BIT(0)
+#define PFM_ALDN                       BIT(1)
+#define PFM_LDKP                       BIT(2)
+#define PFM_WOWL                       BIT(3)
+#define EnPDN                          BIT(4)
+#define PDN_PL                         BIT(5)
+#define APFM_ONMAC                     BIT(8)
+#define APFM_OFF                       BIT(9)
+#define APFM_RSM                       BIT(10)
+#define AFSM_HSUS                      BIT(11)
+#define AFSM_PCIE                      BIT(12)
+#define APDM_MAC                       BIT(13)
+#define APDM_HOST                      BIT(14)
+#define APDM_HPDN                      BIT(15)
+#define RDY_MACON                      BIT(16)
+#define SUS_HOST                       BIT(17)
+#define ROP_ALD                                BIT(20)
+#define ROP_PWR                                BIT(21)
+#define ROP_SPS                                BIT(22)
+#define SOP_MRST                       BIT(25)
+#define SOP_FUSE                       BIT(26)
+#define SOP_ABG                                BIT(27)
+#define SOP_AMB                                BIT(28)
+#define SOP_RCK                                BIT(29)
+#define SOP_A8M                                BIT(30)
+#define XOP_BTCK                       BIT(31)
+
+/* 2 SYS_CLKR */
+#define ANAD16V_EN                     BIT(0)
+#define ANA8M                          BIT(1)
+#define MACSLP                         BIT(4)
+#define LOADER_CLK_EN                  BIT(5)
+#define _80M_SSC_DIS                   BIT(7)
+#define _80M_SSC_EN_HO                 BIT(8)
+#define PHY_SSC_RSTB                   BIT(9)
+#define SEC_CLK_EN                     BIT(10)
+#define MAC_CLK_EN                     BIT(11)
+#define SYS_CLK_EN                     BIT(12)
+#define RING_CLK_EN                    BIT(13)
+
+
+/* 2 9346CR */
+
+
+#define                EEDO                    BIT(0)
+#define                EEDI                    BIT(1)
+#define                EESK                    BIT(2)
+#define                EECS                    BIT(3)
+/* define      EERPROMSEL              BIT(4) */
+/* define      EEPROM_EN               BIT(5) */
+#define                BOOT_FROM_EEPROM        BIT(4)
+#define                EEPROM_EN               BIT(5)
+#define                EEM0                    BIT(6)
+#define                EEM1                    BIT(7)
+
+
+/* 2 AFE_MISC */
+#define AFE_BGEN                       BIT(0)
+#define AFE_MBEN                       BIT(1)
+#define MAC_ID_EN                      BIT(7)
+
+
+/* 2 SPS0_CTRL */
+
+
+/* 2 SPS_OCP_CFG */
+
+
+/* 2 RSV_CTRL */
+#define WLOCK_ALL                      BIT(0)
+#define WLOCK_00                       BIT(1)
+#define WLOCK_04                       BIT(2)
+#define WLOCK_08                       BIT(3)
+#define WLOCK_40                       BIT(4)
+#define R_DIS_PRST_0                   BIT(5)
+#define R_DIS_PRST_1                   BIT(6)
+#define LOCK_ALL_EN                    BIT(7)
+
+/* 2 RF_CTRL */
+#define RF_EN                          BIT(0)
+#define RF_RSTB                                BIT(1)
+#define RF_SDMRSTB                     BIT(2)
+
+
+
+/* 2 LDOA15_CTRL */
+#define LDA15_EN                       BIT(0)
+#define LDA15_STBY                     BIT(1)
+#define LDA15_OBUF                     BIT(2)
+#define LDA15_REG_VOS                  BIT(3)
+#define _LDA15_VOADJ(x)                        (((x) & 0x7) << 4)
+
+
+
+/* 2 LDOV12D_CTRL */
+#define LDV12_EN                       BIT(0)
+#define LDV12_SDBY                     BIT(1)
+#define LPLDO_HSM                      BIT(2)
+#define LPLDO_LSM_DIS                  BIT(3)
+#define _LDV12_VADJ(x)                 (((x) & 0xF) << 4)
+
+
+/* 2 AFE_XTAL_CTRL */
+#define XTAL_EN                                BIT(0)
+#define XTAL_BSEL                      BIT(1)
+#define _XTAL_BOSC(x)                  (((x) & 0x3) << 2)
+#define _XTAL_CADJ(x)                  (((x) & 0xF) << 4)
+#define XTAL_GATE_USB                  BIT(8)
+#define _XTAL_USB_DRV(x)               (((x) & 0x3) << 9)
+#define XTAL_GATE_AFE                  BIT(11)
+#define _XTAL_AFE_DRV(x)               (((x) & 0x3) << 12)
+#define XTAL_RF_GATE                   BIT(14)
+#define _XTAL_RF_DRV(x)                        (((x) & 0x3) << 15)
+#define XTAL_GATE_DIG                  BIT(17)
+#define _XTAL_DIG_DRV(x)               (((x) & 0x3) << 18)
+#define XTAL_BT_GATE                   BIT(20)
+#define _XTAL_BT_DRV(x)                        (((x) & 0x3) << 21)
+#define _XTAL_GPIO(x)                  (((x) & 0x7) << 23)
+
+
+#define CKDLY_AFE                      BIT(26)
+#define CKDLY_USB                      BIT(27)
+#define CKDLY_DIG                      BIT(28)
+#define CKDLY_BT                       BIT(29)
+
+
+/* 2 AFE_PLL_CTRL */
+#define APLL_EN                                BIT(0)
+#define APLL_320_EN                    BIT(1)
+#define APLL_FREF_SEL                  BIT(2)
+#define APLL_EDGE_SEL                  BIT(3)
+#define APLL_WDOGB                     BIT(4)
+#define APLL_LPFEN                     BIT(5)
+
+#define APLL_REF_CLK_13MHZ             0x1
+#define APLL_REF_CLK_19_2MHZ           0x2
+#define APLL_REF_CLK_20MHZ             0x3
+#define APLL_REF_CLK_25MHZ             0x4
+#define APLL_REF_CLK_26MHZ             0x5
+#define APLL_REF_CLK_38_4MHZ           0x6
+#define APLL_REF_CLK_40MHZ             0x7
+
+#define APLL_320EN                     BIT(14)
+#define APLL_80EN                      BIT(15)
+#define APLL_1MEN                      BIT(24)
+
+
+/* 2 EFUSE_CTRL */
+#define ALD_EN                         BIT(18)
+#define EF_PD                          BIT(19)
+#define EF_FLAG                                BIT(31)
+
+/* 2 EFUSE_TEST (For RTL8723 partially) */
+#define EF_TRPT                                BIT(7)
+       /*  00: Wifi Efuse, 01: BT Efuse0, 10: BT Efuse1, 11: BT Efuse2 */
+#define EF_CELL_SEL                    (BIT(8)|BIT(9))
+#define LDOE25_EN                      BIT(31)
+#define EFUSE_SEL(x)                   (((x) & 0x3) << 8)
+#define EFUSE_SEL_MASK                 0x300
+#define EFUSE_WIFI_SEL_0               0x0
+#define EFUSE_BT_SEL_0                 0x1
+#define EFUSE_BT_SEL_1                 0x2
+#define EFUSE_BT_SEL_2                 0x3
+
+#define EFUSE_ACCESS_ON                        0x69    /*  For RTL8723 only. */
+#define EFUSE_ACCESS_OFF               0x00    /*  For RTL8723 only. */
+
+/* 2 PWR_DATA */
+
+/* 2 CAL_TIMER */
+
+/* 2 ACLK_MON */
+#define RSM_EN                         BIT(0)
+#define Timer_EN                       BIT(4)
+
+
+/* 2 GPIO_MUXCFG */
+#define TRSW0EN                                BIT(2)
+#define TRSW1EN                                BIT(3)
+#define EROM_EN                                BIT(4)
+#define EnBT                           BIT(5)
+#define EnUart                         BIT(8)
+#define Uart_910                       BIT(9)
+#define EnPMAC                         BIT(10)
+#define SIC_SWRST                      BIT(11)
+#define EnSIC                          BIT(12)
+#define SIC_23                         BIT(13)
+#define EnHDP                          BIT(14)
+#define SIC_LBK                                BIT(15)
+
+/* 2 GPIO_PIN_CTRL */
+
+/*  GPIO BIT */
+#define HAL_8192C_HW_GPIO_WPS_BIT      BIT(2)
+
+/* 2 GPIO_INTM */
+
+/* 2 LEDCFG */
+#define LED0PL                         BIT(4)
+#define LED0DIS                                BIT(7)
+#define LED1DIS                                BIT(15)
+#define LED1PL                         BIT(12)
+
+#define  SECCAM_CLR                    BIT(30)
+
+
+/* 2 FSIMR */
+
+/* 2 FSISR */
+
+
+/* 2 8051FWDL */
+/* 2 MCUFWDL */
+#define MCUFWDL_EN                     BIT(0)
+#define MCUFWDL_RDY                    BIT(1)
+#define FWDL_ChkSum_rpt                        BIT(2)
+#define MACINI_RDY                     BIT(3)
+#define BBINI_RDY                      BIT(4)
+#define RFINI_RDY                      BIT(5)
+#define WINTINI_RDY                    BIT(6)
+#define CPRST                          BIT(23)
+
+/* 2REG_HPON_FSM */
+#define BOND92CE_1T2R_CFG              BIT(22)
+
+
+/* 2 REG_SYS_CFG */
+#define XCLK_VLD                       BIT(0)
+#define ACLK_VLD                       BIT(1)
+#define UCLK_VLD                       BIT(2)
+#define PCLK_VLD                       BIT(3)
+#define PCIRSTB                                BIT(4)
+#define V15_VLD                                BIT(5)
+#define TRP_B15V_EN                    BIT(7)
+#define SIC_IDLE                       BIT(8)
+#define BD_MAC2                                BIT(9)
+#define BD_MAC1                                BIT(10)
+#define IC_MACPHY_MODE                 BIT(11)
+#define CHIP_VER                       (BIT(12)|BIT(13)|BIT(14)|BIT(15))
+#define BT_FUNC                                BIT(16)
+#define VENDOR_ID                      BIT(19)
+#define PAD_HWPD_IDN                   BIT(22)
+#define TRP_VAUX_EN                    BIT(23)
+#define TRP_BT_EN                      BIT(24)
+#define BD_PKG_SEL                     BIT(25)
+#define BD_HCI_SEL                     BIT(26)
+#define TYPE_ID                                BIT(27)
+
+#define CHIP_VER_RTL_MASK              0xF000  /* Bit 12 ~ 15 */
+#define CHIP_VER_RTL_SHIFT             12
+
+/* 2REG_GPIO_OUTSTS (For RTL8723 only) */
+#define        EFS_HCI_SEL                     (BIT(0)|BIT(1))
+#define        PAD_HCI_SEL                     (BIT(2)|BIT(3))
+#define        HCI_SEL                         (BIT(4)|BIT(5))
+#define        PKG_SEL_HCI                     BIT(6)
+#define        FEN_GPS                         BIT(7)
+#define        FEN_BT                          BIT(8)
+#define        FEN_WL                          BIT(9)
+#define        FEN_PCI                         BIT(10)
+#define        FEN_USB                         BIT(11)
+#define        BTRF_HWPDN_N                    BIT(12)
+#define        WLRF_HWPDN_N                    BIT(13)
+#define        PDN_BT_N                        BIT(14)
+#define        PDN_GPS_N                       BIT(15)
+#define        BT_CTL_HWPDN                    BIT(16)
+#define        GPS_CTL_HWPDN                   BIT(17)
+#define        PPHY_SUSB                       BIT(20)
+#define        UPHY_SUSB                       BIT(21)
+#define        PCI_SUSEN                       BIT(22)
+#define        USB_SUSEN                       BIT(23)
+#define        RF_RL_ID                        (BIT(31)|BIT(30)|BIT(29)|BIT(28))
+
+/*  */
+/*  */
+/*     0x0100h ~ 0x01FFh       MACTOP General Configuration */
+/*  */
+/*  */
+
+
+/* 2 Function Enable Registers */
+/* 2 CR */
+
+#define REG_LBMODE                     (REG_CR + 3)
+
+
+#define HCI_TXDMA_EN                   BIT(0)
+#define HCI_RXDMA_EN                   BIT(1)
+#define TXDMA_EN                       BIT(2)
+#define RXDMA_EN                       BIT(3)
+#define PROTOCOL_EN                    BIT(4)
+#define SCHEDULE_EN                    BIT(5)
+#define MACTXEN                                BIT(6)
+#define MACRXEN                                BIT(7)
+#define ENSWBCN                                BIT(8)
+#define ENSEC                          BIT(9)
+
+/*  Network type */
+#define _NETTYPE(x)                    (((x) & 0x3) << 16)
+#define MASK_NETTYPE                   0x30000
+#define NT_NO_LINK                     0x0
+#define NT_LINK_AD_HOC                 0x1
+#define NT_LINK_AP                     0x2
+#define NT_AS_AP                       0x3
+
+#define _LBMODE(x)                     (((x) & 0xF) << 24)
+#define MASK_LBMODE                    0xF000000
+#define LOOPBACK_NORMAL                        0x0
+#define LOOPBACK_IMMEDIATELY           0xB
+#define LOOPBACK_MAC_DELAY             0x3
+#define LOOPBACK_PHY                   0x1
+#define LOOPBACK_DMA                   0x7
+
+
+/* 2 PBP - Page Size Register */
+#define GET_RX_PAGE_SIZE(value)                ((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value)                (((value) & 0xF0) >> 4)
+#define _PSRX_MASK                     0xF
+#define _PSTX_MASK                     0xF0
+#define _PSRX(x)                       (x)
+#define _PSTX(x)                       ((x) << 4)
+
+#define PBP_64                         0x0
+#define PBP_128                                0x1
+#define PBP_256                                0x2
+#define PBP_512                                0x3
+#define PBP_1024                       0x4
+
+
+/* 2 TX/RXDMA */
+#define RXDMA_ARBBW_EN                 BIT(0)
+#define RXSHFT_EN                      BIT(1)
+#define RXDMA_AGG_EN                   BIT(2)
+#define QS_VO_QUEUE                    BIT(8)
+#define QS_VI_QUEUE                    BIT(9)
+#define QS_BE_QUEUE                    BIT(10)
+#define QS_BK_QUEUE                    BIT(11)
+#define QS_MANAGER_QUEUE               BIT(12)
+#define QS_HIGH_QUEUE                  BIT(13)
+
+#define HQSEL_VOQ                      BIT(0)
+#define HQSEL_VIQ                      BIT(1)
+#define HQSEL_BEQ                      BIT(2)
+#define HQSEL_BKQ                      BIT(3)
+#define HQSEL_MGTQ                     BIT(4)
+#define HQSEL_HIQ                      BIT(5)
+
+/*  For normal driver, 0x10C */
+#define _TXDMA_HIQ_MAP(x)              (((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x)              (((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x)              (((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x)              (((x)&0x3) << 8 )
+#define _TXDMA_VIQ_MAP(x)              (((x)&0x3) << 6 )
+#define _TXDMA_VOQ_MAP(x)              (((x)&0x3) << 4 )
+
+#define QUEUE_LOW                      1
+#define QUEUE_NORMAL                   2
+#define QUEUE_HIGH                     3
+
+
+
+/* 2 TRXFF_BNDY */
+
+
+/* 2 LLT_INIT */
+#define _LLT_NO_ACTIVE                 0x0
+#define _LLT_WRITE_ACCESS              0x1
+#define _LLT_READ_ACCESS               0x2
+
+#define _LLT_INIT_DATA(x)              ((x) & 0xFF)
+#define _LLT_INIT_ADDR(x)              (((x) & 0xFF) << 8)
+#define _LLT_OP(x)                     (((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x)               (((x) >> 30) & 0x3)
+
+
+/* 2 BB_ACCESS_CTRL */
+#define BB_WRITE_READ_MASK             (BIT(31) | BIT(30))
+#define BB_WRITE_EN                    BIT(30)
+#define BB_READ_EN                     BIT(31)
+/* define BB_ADDR_MASK                 0xFFF */
+/* define _BB_ADDR(x)                  ((x) & BB_ADDR_MASK) */
+
+/*  */
+/*  */
+/*     0x0200h ~ 0x027Fh       TXDMA Configuration */
+/*  */
+/*  */
+/* 2 RQPN */
+#define _HPQ(x)                                ((x) & 0xFF)
+#define _LPQ(x)                                (((x) & 0xFF) << 8)
+#define _PUBQ(x)                       (((x) & 0xFF) << 16)
+       /*  NOTE: in RQPN_NPQ register */
+#define _NPQ(x)                                ((x) & 0xFF)
+
+
+#define HPQ_PUBLIC_DIS                 BIT(24)
+#define LPQ_PUBLIC_DIS                 BIT(25)
+#define LD_RQPN                                BIT(31)
+
+
+/* 2 TDECTRL */
+#define BCN_VALID                      BIT(16)
+#define BCN_HEAD(x)                    (((x) & 0xFF) << 8)
+#define        BCN_HEAD_MASK                   0xFF00
+
+/* 2 TDECTL */
+#define BLK_DESC_NUM_SHIFT             4
+#define BLK_DESC_NUM_MASK              0xF
+
+
+/* 2 TXDMA_OFFSET_CHK */
+#define DROP_DATA_EN                   BIT(9)
+
+/*  */
+/*  */
+/*     0x0400h ~ 0x047Fh       Protocol Configuration */
+/*  */
+/*  */
+/* 2 FWHW_TXQ_CTRL */
+#define EN_AMPDU_RTY_NEW               BIT(7)
+
+/* 2 INIRTSMCS_SEL */
+#define _INIRTSMCS_SEL(x)              ((x) & 0x3F)
+
+
+/* 2 SPEC SIFS */
+#define _SPEC_SIFS_CCK(x)              ((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x)             (((x) & 0xFF) << 8)
+
+
+/* 2 RRSR */
+
+#define RATE_REG_BITMAP_ALL            0xFFFFF
+
+#define _RRSC_BITMAP(x)                        ((x) & 0xFFFFF)
+
+#define _RRSR_RSC(x)                   (((x) & 0x3) << 21)
+#define RRSR_RSC_RESERVED              0x0
+#define RRSR_RSC_UPPER_SUBCHANNEL      0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL      0x2
+#define RRSR_RSC_DUPLICATE_MODE                0x3
+
+
+/* 2 ARFR */
+#define USE_SHORT_G1                   BIT(20)
+
+/* 2 AGGLEN_LMT_L */
+#define _AGGLMT_MCS0(x)                        ((x) & 0xF)
+#define _AGGLMT_MCS1(x)                        (((x) & 0xF) << 4)
+#define _AGGLMT_MCS2(x)                        (((x) & 0xF) << 8)
+#define _AGGLMT_MCS3(x)                        (((x) & 0xF) << 12)
+#define _AGGLMT_MCS4(x)                        (((x) & 0xF) << 16)
+#define _AGGLMT_MCS5(x)                        (((x) & 0xF) << 20)
+#define _AGGLMT_MCS6(x)                        (((x) & 0xF) << 24)
+#define _AGGLMT_MCS7(x)                        (((x) & 0xF) << 28)
+
+
+/* 2 RL */
+#define        RETRY_LIMIT_SHORT_SHIFT         8
+#define        RETRY_LIMIT_LONG_SHIFT          0
+
+
+/* 2 DARFRC */
+#define _DARF_RC1(x)                   ((x) & 0x1F)
+#define _DARF_RC2(x)                   (((x) & 0x1F) << 8)
+#define _DARF_RC3(x)                   (((x) & 0x1F) << 16)
+#define _DARF_RC4(x)                   (((x) & 0x1F) << 24)
+/*  NOTE: shift starting from address (DARFRC + 4) */
+#define _DARF_RC5(x)                   ((x) & 0x1F)
+#define _DARF_RC6(x)                   (((x) & 0x1F) << 8)
+#define _DARF_RC7(x)                   (((x) & 0x1F) << 16)
+#define _DARF_RC8(x)                   (((x) & 0x1F) << 24)
+
+
+/* 2 RARFRC */
+#define _RARF_RC1(x)                   ((x) & 0x1F)
+#define _RARF_RC2(x)                   (((x) & 0x1F) << 8)
+#define _RARF_RC3(x)                   (((x) & 0x1F) << 16)
+#define _RARF_RC4(x)                   (((x) & 0x1F) << 24)
+/*  NOTE: shift starting from address (RARFRC + 4) */
+#define _RARF_RC5(x)                   ((x) & 0x1F)
+#define _RARF_RC6(x)                   (((x) & 0x1F) << 8)
+#define _RARF_RC7(x)                   (((x) & 0x1F) << 16)
+#define _RARF_RC8(x)                   (((x) & 0x1F) << 24)
+
+
+/*  */
+/*  */
+/*     0x0500h ~ 0x05FFh       EDCA Configuration */
+/*  */
+/*  */
+
+
+
+/* 2 EDCA setting */
+#define AC_PARAM_TXOP_LIMIT_OFFSET     16
+#define AC_PARAM_ECW_MAX_OFFSET                12
+#define AC_PARAM_ECW_MIN_OFFSET                8
+#define AC_PARAM_AIFS_OFFSET           0
+
+
+/* 2 EDCA_VO_PARAM */
+#define _AIFS(x)                       (x)
+#define _ECW_MAX_MIN(x)                        ((x) << 8)
+#define _TXOP_LIMIT(x)                 ((x) << 16)
+
+
+#define _BCNIFS(x)                     ((x) & 0xFF)
+#define _BCNECW(x)                     (((x) & 0xF))<< 8)
+
+
+#define _LRL(x)                                ((x) & 0x3F)
+#define _SRL(x)                                (((x) & 0x3F) << 8)
+
+
+/* 2 SIFS_CCK */
+#define _SIFS_CCK_CTX(x)               ((x) & 0xFF)
+#define _SIFS_CCK_TRX(x)               (((x) & 0xFF) << 8);
+
+
+/* 2 SIFS_OFDM */
+#define _SIFS_OFDM_CTX(x)              ((x) & 0xFF)
+#define _SIFS_OFDM_TRX(x)              (((x) & 0xFF) << 8);
+
+
+/* 2 TBTT PROHIBIT */
+#define _TBTT_PROHIBIT_HOLD(x)         (((x) & 0xFF) << 8)
+
+
+/* 2 REG_RD_CTRL */
+#define DIS_EDCA_CNT_DWN               BIT(11)
+
+
+/* 2 BCN_CTRL */
+#define EN_MBSSID                      BIT(1)
+#define EN_TXBCN_RPT                   BIT(2)
+#define        EN_BCN_FUNCTION                 BIT(3)
+#define DIS_TSF_UPDATE                 BIT(3)
+
+/*  The same function but different bit field. */
+#define        DIS_TSF_UDT0_NORMAL_CHIP        BIT(4)
+#define        DIS_TSF_UDT0_TEST_CHIP          BIT(5)
+
+/* 2 ACMHWCTRL */
+#define        AcmHw_HwEn                      BIT(0)
+#define        AcmHw_BeqEn                     BIT(1)
+#define        AcmHw_ViqEn                     BIT(2)
+#define        AcmHw_VoqEn                     BIT(3)
+#define        AcmHw_BeqStatus                 BIT(4)
+#define        AcmHw_ViqStatus                 BIT(5)
+#define        AcmHw_VoqStatus                 BIT(6)
+
+
+
+/*  */
+/*  */
+/*     0x0600h ~ 0x07FFh       WMAC Configuration */
+/*  */
+/*  */
+
+/* 2 APSD_CTRL */
+#define APSDOFF                                BIT(6)
+#define APSDOFF_STATUS                 BIT(7)
+
+
+/* 2 BWOPMODE */
+#define BW_20MHZ                       BIT(2)
+
+
+#define RATE_BITMAP_ALL                        0xFFFFF
+
+/*  Only use CCK 1M rate for ACK */
+#define RATE_RRSR_CCK_ONLY_1M          0xFFFF1
+
+/* 2 TCR */
+#define TSFRST                         BIT(0)
+#define DIS_GCLK                       BIT(1)
+#define PAD_SEL                                BIT(2)
+#define PWR_ST                         BIT(6)
+#define PWRBIT_OW_EN                   BIT(7)
+#define ACRC                           BIT(8)
+#define CFENDFORM                      BIT(9)
+#define ICV                            BIT(10)
+
+
+
+/* 2 RCR */
+#define AAP                            BIT(0)
+#define APM                            BIT(1)
+#define AM                             BIT(2)
+#define AB                             BIT(3)
+#define ADD3                           BIT(4)
+#define APWRMGT                                BIT(5)
+#define CBSSID                         BIT(6)
+#define CBSSID_BCN                     BIT(7)
+#define ACRC32                         BIT(8)
+#define AICV                           BIT(9)
+#define ADF                            BIT(11)
+#define ACF                            BIT(12)
+#define AMF                            BIT(13)
+#define HTC_LOC_CTRL                   BIT(14)
+#define UC_DATA_EN                     BIT(16)
+#define BM_DATA_EN                     BIT(17)
+#define MFBEN                          BIT(22)
+#define LSIGEN                         BIT(23)
+#define EnMBID                         BIT(24)
+#define APP_BASSN                      BIT(27)
+#define APP_PHYSTS                     BIT(28)
+#define APP_ICV                                BIT(29)
+#define APP_MIC                                BIT(30)
+#define APP_FCS                                BIT(31)
+
+/* 2 RX_PKT_LIMIT */
+
+/* 2 RX_DLK_TIME */
+
+/* 2 MBIDCAMCFG */
+
+
+
+/* 2 AMPDU_MIN_SPACE */
+#define _MIN_SPACE(x)                  ((x) & 0x7)
+#define _SHORT_GI_PADDING(x)           (((x) & 0x1F) << 3)
+
+
+/* 2 RXERR_RPT */
+#define RXERR_TYPE_OFDM_PPDU           0
+#define RXERR_TYPE_OFDMfalse_ALARM     1
+#define        RXERR_TYPE_OFDM_MPDU_OK         2
+#define RXERR_TYPE_OFDM_MPDU_FAIL      3
+#define RXERR_TYPE_CCK_PPDU            4
+#define RXERR_TYPE_CCKfalse_ALARM      5
+#define RXERR_TYPE_CCK_MPDU_OK         6
+#define RXERR_TYPE_CCK_MPDU_FAIL       7
+#define RXERR_TYPE_HT_PPDU             8
+#define RXERR_TYPE_HTfalse_ALARM       9
+#define RXERR_TYPE_HT_MPDU_TOTAL       10
+#define RXERR_TYPE_HT_MPDU_OK          11
+#define RXERR_TYPE_HT_MPDU_FAIL                12
+#define RXERR_TYPE_RX_FULL_DROP                15
+
+#define RXERR_COUNTER_MASK             0xFFFFF
+#define RXERR_RPT_RST                  BIT(27)
+#define _RXERR_RPT_SEL(type)           ((type) << 28)
+
+
+/* 2 SECCFG */
+#define        SCR_TxUseDK                     BIT(0)  /* Force Tx Use Default Key */
+#define        SCR_RxUseDK                     BIT(1)  /* Force Rx Use Default Key */
+#define        SCR_TxEncEnable                 BIT(2)  /* Enable Tx Encryption */
+#define        SCR_RxDecEnable                 BIT(3)  /* Enable Rx Decryption */
+#define        SCR_SKByA2                      BIT(4)  /* Search kEY BY A2 */
+#define        SCR_NoSKMC                      BIT(5)  /* No Key Search Multicast */
+
+
+
+/*  */
+/*  */
+/*     0xFE00h ~ 0xFE55h       USB Configuration */
+/*  */
+/*  */
+
+/* 2 USB Information (0xFE17) */
+#define USB_IS_HIGH_SPEED              0
+#define USB_IS_FULL_SPEED              1
+#define USB_SPEED_MASK                 BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK         0xF
+#define USB_NORMAL_SIE_EP_SHIFT                4
+
+#define USB_TEST_EP_MASK               0x30
+#define USB_TEST_EP_SHIFT              4
+
+/* 2 Special Option */
+#define USB_AGG_EN                     BIT(3)
+
+
+/* 2REG_C2HEVT_CLEAR */
+       /*  Set by driver and notify FW that the driver has read the
+           C2H command message */
+#define C2H_EVT_HOST_CLOSE             0x00
+       /*  Set by FW indicating that FW had set the C2H command message
+           and it's not yet read by driver. */
+#define C2H_EVT_FW_CLOSE               0xFF
+
+
+/* 2REG_MULTI_FUNC_CTRL(For RTL8723 Only) */
+       /*  Enable GPIO[9] as WiFi HW PDn source */
+#define        WL_HWPDN_EN                     BIT0
+       /*  WiFi HW PDn polarity control */
+#define        WL_HWPDN_SL                     BIT1
+       /*  WiFi function enable */
+#define        WL_FUNC_EN                      BIT2
+       /*  Enable GPIO[9] as WiFi RF HW PDn source */
+#define        WL_HWROF_EN                     BIT3
+       /*  Enable GPIO[11] as BT HW PDn source */
+#define        BT_HWPDN_EN                     BIT16
+       /*  BT HW PDn polarity control */
+#define        BT_HWPDN_SL                     BIT17
+       /*  BT function enable */
+#define        BT_FUNC_EN                      BIT18
+       /*  Enable GPIO[11] as BT/GPS RF HW PDn source */
+#define        BT_HWROF_EN                     BIT19
+       /*  Enable GPIO[10] as GPS HW PDn source */
+#define        GPS_HWPDN_EN                    BIT20
+       /*  GPS HW PDn polarity control */
+#define        GPS_HWPDN_SL                    BIT21
+       /*  GPS function enable */
+#define        GPS_FUNC_EN                     BIT22
+
+/* 3 REG_LIFECTRL_CTRL */
+#define        HAL92C_EN_PKT_LIFE_TIME_BK      BIT3
+#define        HAL92C_EN_PKT_LIFE_TIME_BE      BIT2
+#define        HAL92C_EN_PKT_LIFE_TIME_VI      BIT1
+#define        HAL92C_EN_PKT_LIFE_TIME_VO      BIT0
+
+#define        HAL92C_MSDU_LIFE_TIME_UNIT      128     /*  in us, said by Tim. */
+
+/*  */
+/*  General definitions */
+/*  */
+
+#define LAST_ENTRY_OF_TX_PKT_BUFFER    255
+
+#define POLLING_LLT_THRESHOLD          20
+#define POLLING_READY_TIMEOUT_COUNT    1000
+
+/*  Min Spacing related settings. */
+#define        MAX_MSS_DENSITY_2T              0x13
+#define        MAX_MSS_DENSITY_1T              0x0A
+
+/*  */
+/*     8723A Regsiter offset definition */
+/*  */
+#define HAL_8723A_NAV_UPPER_UNIT       128             /*  micro-second */
+
+/*  */
+/*  */
+/*     0x0000h ~ 0x00FFh       System Configuration */
+/*  */
+/*  */
+#define REG_SYSON_REG_LOCK             0x001C
+
+
+/*  */
+/*  */
+/*     0x0100h ~ 0x01FFh       MACTOP General Configuration */
+/*  */
+/*  */
+#define REG_FTIMR                      0x0138
+
+
+/*  */
+/*  */
+/*     0x0200h ~ 0x027Fh       TXDMA Configuration */
+/*  */
+/*  */
+
+
+/*  */
+/*  */
+/*     0x0280h ~ 0x02FFh       RXDMA Configuration */
+/*  */
+/*  */
+
+
+/*  */
+/*  */
+/*     0x0300h ~ 0x03FFh       PCIe */
+/*  */
+/*  */
+
+
+/*  */
+/*  */
+/*     0x0400h ~ 0x047Fh       Protocol Configuration */
+/*  */
+/*  */
+#define REG_EARLY_MODE_CONTROL         0x4D0
+
+
+/*  */
+/*  */
+/*     0x0500h ~ 0x05FFh       EDCA Configuration */
+/*  */
+/*  */
+
+/* 2 BCN_CTRL */
+#define DIS_ATIM                       BIT(0)
+#define DIS_BCNQ_SUB                   BIT(1)
+#define DIS_TSF_UDT                    BIT(4)
+
+
+/*  */
+/*  */
+/*     0x0600h ~ 0x07FFh       WMAC Configuration */
+/*  */
+/*  */
+/*  */
+/*  Note: */
+/*     The NAV upper value is very important to WiFi 11n 5.2.3 NAV test.
+ *     The default value is always too small, but the WiFi TestPlan test
+ *     by 25,000 microseconds of NAV through sending CTS in the air. We
+ *     must update this value greater than 25,000 microseconds to pass the
+ *     item.
+*      The offset of NAV_UPPER in 8192C Spec is incorrect, and the offset
+*      should be 0x0652. Commented by SD1 Scott. */
+/*  By Bruce, 2011-07-18. */
+/*  */
+#define        REG_NAV_UPPER                   0x0652  /*  unit of 128 */
+
+
+/*  */
+/*     8723 Regsiter Bit and Content definition */
+/*  */
+
+/*  */
+/*  */
+/*     0x0000h ~ 0x00FFh       System Configuration */
+/*  */
+/*  */
+
+/* 2 SPS0_CTRL */
+
+/* 2 SYS_ISO_CTRL */
+
+/* 2 SYS_FUNC_EN */
+
+/* 2 APS_FSMCO */
+#define EN_WLON                                BIT(16)
+
+/* 2 SYS_CLKR */
+
+/* 2 9346CR */
+
+/* 2 AFE_MISC */
+
+/* 2 SPS0_CTRL */
+
+/* 2 SPS_OCP_CFG */
+
+/* 2 SYSON_REG_LOCK */
+#define WLOCK_ALL                      BIT(0)
+#define WLOCK_00                       BIT(1)
+#define WLOCK_04                       BIT(2)
+#define WLOCK_08                       BIT(3)
+#define WLOCK_40                       BIT(4)
+#define WLOCK_1C_B6                    BIT(5)
+#define R_DIS_PRST_1                   BIT(6)
+#define LOCK_ALL_EN                    BIT(7)
+
+/* 2 RF_CTRL */
+
+/* 2 LDOA15_CTRL */
+
+/* 2 LDOV12D_CTRL */
+
+/* 2 AFE_XTAL_CTRL */
+
+/* 2 AFE_PLL_CTRL */
+
+/* 2 EFUSE_CTRL */
+
+/* 2 EFUSE_TEST (For RTL8723 partially) */
+
+/* 2 PWR_DATA */
+
+/* 2 CAL_TIMER */
+
+/* 2 ACLK_MON */
+
+/* 2 GPIO_MUXCFG */
+
+/* 2 GPIO_PIN_CTRL */
+
+/* 2 GPIO_INTM */
+
+/* 2 LEDCFG */
+
+/* 2 FSIMR */
+
+/* 2 FSISR */
+
+/* 2 HSIMR */
+/*  8723 Host System Interrupt Mask Register (offset 0x58, 32 byte) */
+#define HSIMR_GPIO12_0_INT_EN          BIT(0)
+#define HSIMR_SPS_OCP_INT_EN           BIT(5)
+#define HSIMR_RON_INT_EN               BIT(6)
+#define HSIMR_PDNINT_EN                        BIT(7)
+#define HSIMR_GPIO9_INT_EN             BIT(25)
+
+/* 2 HSISR */
+/*  8723 Host System Interrupt Status Register (offset 0x5C, 32 byte) */
+#define HSISR_GPIO12_0_INT             BIT(0)
+#define HSISR_SPS_OCP_INT              BIT(5)
+#define HSISR_RON_INT                  BIT(6)
+#define HSISR_PDNINT                   BIT(7)
+#define        HSISR_GPIO9_INT                 BIT(25)
+
+/*  interrupt mask which needs to clear */
+#define MASK_HSISR_CLEAR               (HSISR_GPIO12_0_INT | \
+                                        HSISR_SPS_OCP_INT | \
+                                        HSISR_RON_INT | \
+                                        HSISR_PDNINT | \
+                                        HSISR_GPIO9_INT)
+
+/* 2 MCUFWDL */
+#define RAM_DL_SEL                     BIT7    /*  1:RAM, 0:ROM */
+
+/* 2 HPON_FSM */
+
+/* 2 SYS_CFG */
+#define RTL_ID                         BIT(23) /*  TestChip ID,
+                                                   1:Test(RLE); 0:MP(RL) */
+#define SPS_SEL                                BIT(24) /*  1:LDO regulator mode;
+                                                   0:Switching regulator mode*/
+
+
+/*  */
+/*  */
+/*     0x0100h ~ 0x01FFh       MACTOP General Configuration */
+/*  */
+/*  */
+
+/* 2 Function Enable Registers */
+
+/* 2 CR */
+#define CALTMR_EN                      BIT(10)
+
+/* 2 PBP - Page Size Register */
+
+/* 2 TX/RXDMA */
+
+/* 2 TRXFF_BNDY */
+
+/* 2 LLT_INIT */
+
+/* 2 BB_ACCESS_CTRL */
+
+
+/*  */
+/*  */
+/*     0x0200h ~ 0x027Fh       TXDMA Configuration */
+/*  */
+/*  */
+
+/* 2 RQPN */
+
+/* 2 TDECTRL */
+
+/* 2 TDECTL */
+
+/* 2 TXDMA_OFFSET_CHK */
+
+
+/*  */
+/*  */
+/*     0x0400h ~ 0x047Fh       Protocol Configuration */
+/*  */
+/*  */
+
+/* 2 FWHW_TXQ_CTRL */
+
+/* 2 INIRTSMCS_SEL */
+
+/* 2 SPEC SIFS */
+
+/* 2 RRSR */
+
+/* 2 ARFR */
+
+/* 2 AGGLEN_LMT_L */
+
+/* 2 RL */
+
+/* 2 DARFRC */
+
+/* 2 RARFRC */
+
+
+/*  */
+/*  */
+/*     0x0500h ~ 0x05FFh       EDCA Configuration */
+/*  */
+/*  */
+
+/* 2 EDCA setting */
+
+/* 2 EDCA_VO_PARAM */
+
+/* 2 SIFS_CCK */
+
+/* 2 SIFS_OFDM */
+
+/* 2 TBTT PROHIBIT */
+
+/* 2 REG_RD_CTRL */
+
+/* 2 BCN_CTRL */
+
+/* 2 ACMHWCTRL */
+
+
+/*  */
+/*  */
+/*     0x0600h ~ 0x07FFh       WMAC Configuration */
+/*  */
+/*  */
+
+/* 2 APSD_CTRL */
+
+/* 2 BWOPMODE */
+
+/* 2 TCR */
+
+/* 2 RCR */
+
+/* 2 RX_PKT_LIMIT */
+
+/* 2 RX_DLK_TIME */
+
+/* 2 MBIDCAMCFG */
+
+/* 2 AMPDU_MIN_SPACE */
+
+/* 2 RXERR_RPT */
+
+/* 2 SECCFG */
+
+
+/*  */
+/*  */
+/*     0xFE00h ~ 0xFE55h       RTL8723 SDIO Configuration */
+/*  */
+/*  */
+
+/*  I/O bus domain address mapping */
+#define WLAN_IOREG_BASE                        0x10260000
+#define FIRMWARE_FIFO_BASE             0x10270000
+#define TX_HIQ_BASE                    0x10310000
+#define TX_MIQ_BASE                    0x10320000
+#define TX_LOQ_BASE                    0x10330000
+#define RX_RX0FF_BASE                  0x10340000
+
+/*  SDIO host local register space mapping. */
+#define WLAN_IOREG_MSK                 0x7FFF
+#define WLAN_FIFO_MSK                  0x1FFF  /*  Aggregation Length[12:0] */
+#define WLAN_RX0FF_MSK                 0x0003
+
+#define WLAN_RX0FF_DEVICE_ID           7       /*  0b[16], 111b[15:13] */
+#define WLAN_IOREG_DEVICE_ID           8       /*  1b[16] */
+
+/*  8723 EFUSE */
+#define HWSET_MAX_SIZE                 256
+
+
+/* USB interrupt */
+#define        UHIMR_TIMEOUT2                  BIT31
+#define        UHIMR_TIMEOUT1                  BIT30
+#define        UHIMR_PSTIMEOUT                 BIT29
+#define        UHIMR_GTINT4                    BIT28
+#define        UHIMR_GTINT3                    BIT27
+#define        UHIMR_TXBCNERR                  BIT26
+#define        UHIMR_TXBCNOK                   BIT25
+#define        UHIMR_TSF_BIT32_TOGGLE          BIT24
+#define        UHIMR_BCNDMAINT3                BIT23
+#define        UHIMR_BCNDMAINT2                BIT22
+#define        UHIMR_BCNDMAINT1                BIT21
+#define        UHIMR_BCNDMAINT0                BIT20
+#define        UHIMR_BCNDOK3                   BIT19
+#define        UHIMR_BCNDOK2                   BIT18
+#define        UHIMR_BCNDOK1                   BIT17
+#define        UHIMR_BCNDOK0                   BIT16
+#define        UHIMR_HSISR_IND                 BIT15
+#define        UHIMR_BCNDMAINT_E               BIT14
+/* RSVD        BIT13 */
+#define        UHIMR_CTW_END                   BIT12
+/* RSVD        BIT11 */
+#define        UHIMR_C2HCMD                    BIT10
+#define        UHIMR_CPWM2                     BIT9
+#define        UHIMR_CPWM                      BIT8
+#define        UHIMR_HIGHDOK                   BIT7    /*  High Queue DMA OK
+                                                   Interrupt */
+#define        UHIMR_MGNTDOK                   BIT6    /*  Management Queue DMA OK
+                                                   Interrupt */
+#define        UHIMR_BKDOK                     BIT5    /*  AC_BK DMA OK Interrupt */
+#define        UHIMR_BEDOK                     BIT4    /*  AC_BE DMA OK Interrupt */
+#define        UHIMR_VIDOK                     BIT3    /*  AC_VI DMA OK Interrupt */
+#define        UHIMR_VODOK                     BIT2    /*  AC_VO DMA Interrupt */
+#define        UHIMR_RDU                       BIT1    /*  Receive Descriptor
+                                                   Unavailable */
+#define        UHIMR_ROK                       BIT0    /*  Receive DMA OK Interrupt */
+
+/*  USB Host Interrupt Status Extension bit */
+#define        UHIMR_BCNDMAINT7                BIT23
+#define        UHIMR_BCNDMAINT6                BIT22
+#define        UHIMR_BCNDMAINT5                BIT21
+#define        UHIMR_BCNDMAINT4                BIT20
+#define        UHIMR_BCNDOK7                   BIT19
+#define        UHIMR_BCNDOK6                   BIT18
+#define        UHIMR_BCNDOK5                   BIT17
+#define        UHIMR_BCNDOK4                   BIT16
+/*  bit14-15: RSVD */
+#define        UHIMR_ATIMEND_E                 BIT13
+#define        UHIMR_ATIMEND                   BIT12
+#define        UHIMR_TXERR                     BIT11
+#define        UHIMR_RXERR                     BIT10
+#define        UHIMR_TXFOVW                    BIT9
+#define        UHIMR_RXFOVW                    BIT8
+/*  bit2-7: RSVD */
+#define        UHIMR_OCPINT                    BIT1
+/*  bit0: RSVD */
+
+#define        REG_USB_HIMR                    0xFE38
+#define        REG_USB_HIMRE                   0xFE3C
+#define        REG_USB_HISR                    0xFE78
+#define        REG_USB_HISRE                   0xFE7C
+
+#define        USB_INTR_CPWM_OFFSET            16
+#define        USB_INTR_CONTENT_HISR_OFFSET    48
+#define        USB_INTR_CONTENT_HISRE_OFFSET   52
+#define        USB_INTR_CONTENT_LENGTH         56
+#define        USB_C2H_CMDID_OFFSET            0
+#define        USB_C2H_SEQ_OFFSET              1
+#define        USB_C2H_EVENT_OFFSET            2
+/*  */
+/*     General definitions */
+/*  */
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_sreset.h b/drivers/staging/rtl8723au/include/rtl8723a_sreset.h
new file mode 100644 (file)
index 0000000..82af6a2
--- /dev/null
@@ -0,0 +1,25 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef _RTL8723A_SRESET_H_
+#define _RTL8723A_SRESET_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_sreset.h>
+
+void rtl8723a_sreset_xmit_status_check(struct rtw_adapter *padapter);
+void rtl8723a_sreset_linked_status_check(struct rtw_adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_xmit.h b/drivers/staging/rtl8723au/include/rtl8723a_xmit.h
new file mode 100644 (file)
index 0000000..3b6fdc3
--- /dev/null
@@ -0,0 +1,229 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTL8723A_XMIT_H__
+#define __RTL8723A_XMIT_H__
+
+/*  */
+/*  Queue Select Value in TxDesc */
+/*  */
+#define QSLT_BK                                                        0x2/* 0x01 */
+#define QSLT_BE                                                        0x0
+#define QSLT_VI                                                        0x5/* 0x4 */
+#define QSLT_VO                                                        0x7/* 0x6 */
+#define QSLT_BEACON                                            0x10
+#define QSLT_HIGH                                              0x11
+#define QSLT_MGNT                                              0x12
+#define QSLT_CMD                                               0x13
+
+/*  */
+/* defined for TX DESC Operation */
+/*  */
+
+#define MAX_TID (15)
+
+/* OFFSET 0 */
+#define OFFSET_SZ      0
+#define OFFSET_SHT     16
+#define BMC            BIT(24)
+#define LSG            BIT(26)
+#define FSG            BIT(27)
+#define OWN            BIT(31)
+
+
+/* OFFSET 4 */
+#define PKT_OFFSET_SZ  0
+#define BK             BIT(6)
+#define QSEL_SHT       8
+#define Rate_ID_SHT    16
+#define NAVUSEHDR      BIT(20)
+#define PKT_OFFSET_SHT 26
+#define HWPC           BIT(31)
+
+/* OFFSET 8 */
+#define AGG_EN         BIT(29)
+
+/* OFFSET 12 */
+#define SEQ_SHT                16
+
+/* OFFSET 16 */
+#define QoS            BIT(6)
+#define HW_SEQ_EN      BIT(7)
+#define USERATE                BIT(8)
+#define DISDATAFB      BIT(10)
+#define DATA_SHORT     BIT(24)
+#define DATA_BW                BIT(25)
+
+/* OFFSET 20 */
+#define SGI            BIT(6)
+
+struct txdesc_8723a {
+       u32 pktlen:16;
+       u32 offset:8;
+       u32 bmc:1;
+       u32 htc:1;
+       u32 ls:1;
+       u32 fs:1;
+       u32 linip:1;
+       u32 noacm:1;
+       u32 gf:1;
+       u32 own:1;
+
+       u32 macid:5;
+       u32 agg_en:1;
+       u32 bk:1;
+       u32 rd_en:1;
+       u32 qsel:5;
+       u32 rd_nav_ext:1;
+       u32 lsig_txop_en:1;
+       u32 pifs:1;
+       u32 rate_id:4;
+       u32 navusehdr:1;
+       u32 en_desc_id:1;
+       u32 sectype:2;
+       u32 rsvd0424:2;
+       u32 pkt_offset:5;       /*  unit: 8 bytes */
+       u32 rsvd0431:1;
+
+       u32 rts_rc:6;
+       u32 data_rc:6;
+       u32 rsvd0812:2;
+       u32 bar_rty_th:2;
+       u32 rsvd0816:1;
+       u32 morefrag:1;
+       u32 raw:1;
+       u32 ccx:1;
+       u32 ampdu_density:3;
+       u32 bt_null:1;
+       u32 ant_sel_a:1;
+       u32 ant_sel_b:1;
+       u32 tx_ant_cck:2;
+       u32 tx_antl:2;
+       u32 tx_ant_ht:2;
+
+       u32 nextheadpage:8;
+       u32 tailpage:8;
+       u32 seq:12;
+       u32 cpu_handle:1;
+       u32 tag1:1;
+       u32 trigger_int:1;
+       u32 hwseq_en:1;
+
+       u32 rtsrate:5;
+       u32 ap_dcfe:1;
+       u32 hwseq_sel:2;
+       u32 userate:1;
+       u32 disrtsfb:1;
+       u32 disdatafb:1;
+       u32 cts2self:1;
+       u32 rtsen:1;
+       u32 hw_rts_en:1;
+       u32 port_id:1;
+       u32 rsvd1615:3;
+       u32 wait_dcts:1;
+       u32 cts2ap_en:1;
+       u32 data_sc:2;
+       u32 data_stbc:2;
+       u32 data_short:1;
+       u32 data_bw:1;
+       u32 rts_short:1;
+       u32 rts_bw:1;
+       u32 rts_sc:2;
+       u32 vcs_stbc:2;
+
+       u32 datarate:6;
+       u32 sgi:1;
+       u32 try_rate:1;
+       u32 data_ratefb_lmt:5;
+       u32 rts_ratefb_lmt:4;
+       u32 rty_lmt_en:1;
+       u32 data_rt_lmt:6;
+       u32 usb_txagg_num:8;
+
+       u32 txagg_a:5;
+       u32 txagg_b:5;
+       u32 use_max_len:1;
+       u32 max_agg_num:5;
+       u32 mcsg1_max_len:4;
+       u32 mcsg2_max_len:4;
+       u32 mcsg3_max_len:4;
+       u32 mcs7_sgi_max_len:4;
+
+       u32 checksum:16;        /*  TxBuffSize(PCIe)/CheckSum(USB) */
+       u32 mcsg4_max_len:4;
+       u32 mcsg5_max_len:4;
+       u32 mcsg6_max_len:4;
+       u32 mcs15_sgi_max_len:4;
+};
+
+#define txdesc_set_ccx_sw_8723a(txdesc, value) \
+       do { \
+               ((struct txdesc_8723a *)(txdesc))->mcsg4_max_len = (((value)>>8) & 0x0f); \
+               ((struct txdesc_8723a *)(txdesc))->mcs15_sgi_max_len= (((value)>>4) & 0x0f); \
+               ((struct txdesc_8723a *)(txdesc))->mcsg6_max_len = ((value) & 0x0f); \
+       } while (0)
+
+struct txrpt_ccx_8723a {
+       /* offset 0 */
+       u8 tag1:1;
+       u8 rsvd:4;
+       u8 int_bt:1;
+       u8 int_tri:1;
+       u8 int_ccx:1;
+
+       /* offset 1 */
+       u8 mac_id:5;
+       u8 pkt_drop:1;
+       u8 pkt_ok:1;
+       u8 bmc:1;
+
+       /* offset 2 */
+       u8 retry_cnt:6;
+       u8 lifetime_over:1;
+       u8 retry_over:1;
+
+       /* offset 3 */
+       u8 ccx_qtime0;
+       u8 ccx_qtime1;
+
+       /* offset 5 */
+       u8 final_data_rate;
+
+       /* offset 6 */
+       u8 sw1:4;
+       u8 qsel:4;
+
+       /* offset 7 */
+       u8 sw0;
+};
+
+#define txrpt_ccx_sw_8723a(txrpt_ccx) ((txrpt_ccx)->sw0 + ((txrpt_ccx)->sw1<<8))
+#define txrpt_ccx_qtime_8723a(txrpt_ccx) ((txrpt_ccx)->ccx_qtime0+((txrpt_ccx)->ccx_qtime1<<8))
+
+void dump_txrpt_ccx_8723a(void *buf);
+void handle_txrpt_ccx_8723a(struct rtw_adapter *adapter, void *buf);
+void rtl8723a_update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem);
+void rtl8723a_fill_fake_txdesc(struct rtw_adapter *padapter, u8 *pDesc, u32 BufferLen, u8 IsPsPoll, u8 IsBTQosNull);
+
+s32    rtl8723au_hal_xmitframe_enqueue(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe);
+s32 rtl8723au_xmit_buf_handler(struct rtw_adapter *padapter);
+#define hal_xmit_handler rtl8723au_xmit_buf_handler
+s32    rtl8723au_init_xmit_priv(struct rtw_adapter * padapter);
+void   rtl8723au_free_xmit_priv(struct rtw_adapter * padapter);
+s32 rtl8723au_hal_xmit(struct rtw_adapter *padapter, struct xmit_frame *pxmitframe);
+s32 rtl8723au_mgnt_xmit(struct rtw_adapter *padapter, struct xmit_frame *pmgntframe);
+s32 rtl8723au_xmitframe_complete(struct rtw_adapter *padapter, struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf);
+
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtw_ap.h b/drivers/staging/rtl8723au/include/rtw_ap.h
new file mode 100644 (file)
index 0000000..76f82d6
--- /dev/null
@@ -0,0 +1,55 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTW_AP_H_
+#define __RTW_AP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+#ifdef CONFIG_8723AU_AP_MODE
+
+/* external function */
+void rtw_indicate_sta_assoc_event23a(struct rtw_adapter *padapter, struct sta_info *psta);
+void rtw_indicate_sta_disassoc_event23a(struct rtw_adapter *padapter, struct sta_info *psta);
+
+void init_mlme_ap_info23a(struct rtw_adapter *padapter);
+void free_mlme_ap_info23a(struct rtw_adapter *padapter);
+/* void update_BCNTIM(struct rtw_adapter *padapter); */
+void rtw_add_bcn_ie(struct rtw_adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index, u8 *data, u8 len);
+void rtw_remove_bcn_ie(struct rtw_adapter *padapter, struct wlan_bssid_ex *pnetwork, u8 index);
+void update_beacon23a(struct rtw_adapter *padapter, u8 ie_id, u8 *oui, u8 tx);
+void add_RATid23a(struct rtw_adapter *padapter, struct sta_info *psta, u8 rssi_level);
+void expire_timeout_chk23a(struct rtw_adapter *padapter);
+void update_sta_info23a_apmode23a(struct rtw_adapter *padapter, struct sta_info *psta);
+int rtw_check_beacon_data23a(struct rtw_adapter *padapter, u8 *pbuf,  int len);
+void rtw_ap_restore_network(struct rtw_adapter *padapter);
+void rtw_set_macaddr_acl23a(struct rtw_adapter *padapter, int mode);
+int rtw_acl_add_sta23a(struct rtw_adapter *padapter, u8 *addr);
+int rtw_acl_remove_sta23a(struct rtw_adapter *padapter, u8 *addr);
+
+void associated_clients_update23a(struct rtw_adapter *padapter, u8 updated);
+void bss_cap_update_on_sta_join23a(struct rtw_adapter *padapter, struct sta_info *psta);
+u8 bss_cap_update_on_sta_leave23a(struct rtw_adapter *padapter, struct sta_info *psta);
+void sta_info_update23a(struct rtw_adapter *padapter, struct sta_info *psta);
+void ap_sta_info_defer_update23a(struct rtw_adapter *padapter, struct sta_info *psta);
+u8 ap_free_sta23a(struct rtw_adapter *padapter, struct sta_info *psta, bool active, u16 reason);
+int rtw_sta_flush23a(struct rtw_adapter *padapter);
+int rtw_ap_inform_ch_switch23a(struct rtw_adapter *padapter, u8 new_ch, u8 ch_offset);
+void start_ap_mode23a(struct rtw_adapter *padapter);
+void stop_ap_mode23a(struct rtw_adapter *padapter);
+#endif /* end of CONFIG_8723AU_AP_MODE */
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtw_cmd.h b/drivers/staging/rtl8723au/include/rtw_cmd.h
new file mode 100644 (file)
index 0000000..f9caa3e
--- /dev/null
@@ -0,0 +1,835 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTW_CMD_H_
+#define __RTW_CMD_H_
+
+#include <wlan_bssdef.h>
+#include <rtw_rf.h>
+#include <rtw_led.h>
+
+#define C2H_MEM_SZ (16*1024)
+
+#include <osdep_service.h>
+#include <ieee80211.h> /*  <ieee80211/ieee80211.h> */
+
+
+#define FREE_CMDOBJ_SZ 128
+
+#define MAX_CMDSZ      1024
+#define MAX_RSPSZ      512
+#define MAX_EVTSZ      1024
+
+#define CMDBUFF_ALIGN_SZ 512
+
+struct cmd_obj {
+       struct rtw_adapter *padapter;
+       u16     cmdcode;
+       u8      res;
+       u8      *parmbuf;
+       u32     cmdsz;
+       u8      *rsp;
+       u32     rspsz;
+       /* struct semaphore             cmd_sem; */
+       struct list_head        list;
+};
+
+struct cmd_priv {
+       struct semaphore        cmd_queue_sema;
+       /* struct semaphore     cmd_done_sema; */
+       struct semaphore        terminate_cmdthread_sema;
+       struct rtw_queue        cmd_queue;
+       u8      cmd_seq;
+       u8      *cmd_buf;       /* shall be non-paged, and 4 bytes aligned */
+       u8      *cmd_allocated_buf;
+       u8      *rsp_buf;       /* shall be non-paged, and 4 bytes aligned */
+       u8      *rsp_allocated_buf;
+       u32     cmd_issued_cnt;
+       u32     cmd_done_cnt;
+       u32     rsp_cnt;
+       u8 cmdthd_running;
+       struct rtw_adapter *padapter;
+};
+
+#define C2H_QUEUE_MAX_LEN 10
+
+struct evt_priv {
+       struct work_struct c2h_wk;
+       bool c2h_wk_alive;
+       struct rtw_cbuf *c2h_queue;
+
+       atomic_t event_seq;
+       u8      *evt_buf;       /* shall be non-paged, and 4 bytes aligned */
+       u8      *evt_allocated_buf;
+       u32     evt_done_cnt;
+};
+
+#define init_h2fwcmd_w_parm_no_rsp(pcmd, pparm, code) \
+do {\
+       INIT_LIST_HEAD(&pcmd->list);\
+       pcmd->cmdcode = code;\
+       pcmd->parmbuf = (u8 *)(pparm);\
+       pcmd->cmdsz = sizeof (*pparm);\
+       pcmd->rsp = NULL;\
+       pcmd->rspsz = 0;\
+} while(0)
+
+struct c2h_evt_hdr {
+       u8 id:4;
+       u8 plen:4;
+       u8 seq;
+       u8 payload[0];
+};
+
+#define c2h_evt_exist(c2h_evt) ((c2h_evt)->id || (c2h_evt)->plen)
+
+u32 rtw_enqueue_cmd23a(struct cmd_priv *pcmdpriv, struct cmd_obj *obj);
+void rtw_free_cmd_obj23a(struct cmd_obj *pcmd);
+
+int rtw_cmd_thread23a(void *context);
+
+int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv);
+void rtw_free_cmd_priv23a (struct cmd_priv *pcmdpriv);
+
+u32 rtw_init_evt_priv23a (struct evt_priv *pevtpriv);
+void rtw_free_evt_priv23a (struct evt_priv *pevtpriv);
+void rtw_cmd_clr_isr23a(struct cmd_priv *pcmdpriv);
+void rtw_evt_notify_isr(struct evt_priv *pevtpriv);
+#ifdef CONFIG_8723AU_P2P
+u8 p2p_protocol_wk_cmd23a(struct rtw_adapter*padapter, int intCmdType );
+#endif /* CONFIG_8723AU_P2P */
+
+enum rtw_drvextra_cmd_id
+{
+       NONE_WK_CID,
+       DYNAMIC_CHK_WK_CID,
+       DM_CTRL_WK_CID,
+       PBC_POLLING_WK_CID,
+       POWER_SAVING_CTRL_WK_CID,/* IPS,AUTOSuspend */
+       LPS_CTRL_WK_CID,
+       ANT_SELECT_WK_CID,
+       P2P_PS_WK_CID,
+       P2P_PROTO_WK_CID,
+       CHECK_HIQ_WK_CID,/* for softap mode, check hi queue if empty */
+       C2H_WK_CID,
+       RTP_TIMER_CFG_WK_CID,
+       MAX_WK_CID
+};
+
+enum LPS_CTRL_TYPE
+{
+       LPS_CTRL_SCAN=0,
+       LPS_CTRL_JOINBSS=1,
+       LPS_CTRL_CONNECT=2,
+       LPS_CTRL_DISCONNECT=3,
+       LPS_CTRL_SPECIAL_PACKET=4,
+       LPS_CTRL_LEAVE=5,
+};
+
+enum RFINTFS {
+       SWSI,
+       HWSI,
+       HWPI,
+};
+
+/*
+Caller Mode: Infra, Ad-HoC(C)
+
+Notes: To enter USB suspend mode
+
+Command Mode
+
+*/
+struct usb_suspend_parm {
+       u32 action;/*  1: sleep, 0:resume */
+};
+
+/*
+Caller Mode: Infra, Ad-HoC
+
+Notes: To join a known BSS.
+
+Command-Event Mode
+
+*/
+
+/*
+Caller Mode: Infra, Ad-HoC(C)
+
+Notes: To disconnect the current associated BSS
+
+Command Mode
+
+*/
+struct disconnect_parm {
+       u32 deauth_timeout_ms;
+};
+
+struct setopmode_parm {
+       u8      mode;
+       u8      rsvd[3];
+};
+
+/*
+Caller Mode: AP, Ad-HoC, Infra
+
+Notes: To ask RTL8711 performing site-survey
+
+Command-Event Mode
+
+*/
+
+#define RTW_SSID_SCAN_AMOUNT 9 /*  for WEXT_CSCAN_AMOUNT 9 */
+#define RTW_CHANNEL_SCAN_AMOUNT (14+37)
+struct sitesurvey_parm {
+       int scan_mode;  /* active: 1, passive: 0 */
+       u8 ssid_num;
+       u8 ch_num;
+       struct cfg80211_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+       struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To set the auth type of RTL8711. open/shared/802.1x
+
+Command Mode
+
+*/
+struct setauth_parm {
+       u8 mode;  /* 0: legacy open, 1: legacy shared 2: 802.1x */
+       u8 _1x;   /* 0: PSK, 1: TLS */
+       u8 rsvd[2];
+};
+
+/*
+Caller Mode: Infra
+
+a. algorithm: wep40, wep104, tkip & aes
+b. keytype: grp key/unicast key
+c. key contents
+
+when shared key ==> keyid is the camid
+when 802.1x ==> keyid [0:1] ==> grp key
+when 802.1x ==> keyid > 2 ==> unicast key
+
+*/
+struct setkey_parm {
+       u8      algorithm;      /*  encryption algorithm, could be none, wep40, TKIP, CCMP, wep104 */
+       u8      keyid;
+       u8      grpkey;         /*  1: this is the grpkey for 802.1x. 0: this is the unicast key for 802.1x */
+       u8      set_tx;         /*  1: main tx key for wep. 0: other key. */
+       u8      key[16];        /*  this could be 40 or 104 */
+};
+
+/*
+When in AP or Ad-Hoc mode, this is used to
+allocate an sw/hw entry for a newly associated sta.
+
+Command
+
+when shared key ==> algorithm/keyid
+
+*/
+struct set_stakey_parm {
+       u8      addr[ETH_ALEN];
+       u8      algorithm;
+       u8      id;/*  currently for erasing cam entry if algorithm == _NO_PRIVACY_ */
+       u8      key[16];
+};
+
+struct set_stakey_rsp {
+       u8      addr[ETH_ALEN];
+       u8      keyid;
+       u8      rsvd;
+};
+
+/*
+Caller Ad-Hoc/AP
+
+Command -Rsp(AID == CAMID) mode
+
+This is to force fw to add an sta_data entry per driver's request.
+
+FW will write an cam entry associated with it.
+
+*/
+struct set_assocsta_parm {
+       u8      addr[ETH_ALEN];
+};
+
+struct set_assocsta_rsp {
+       u8      cam_id;
+       u8      rsvd[3];
+};
+
+/*
+       Caller Ad-Hoc/AP
+
+       Command mode
+
+       This is to force fw to del an sta_data entry per driver's request
+
+       FW will invalidate the cam entry associated with it.
+
+*/
+struct del_assocsta_parm {
+       u8      addr[ETH_ALEN];
+};
+
+/*
+Caller Mode: AP/Ad-HoC(M)
+
+Notes: To notify fw that given staid has changed its power state
+
+Command Mode
+
+*/
+struct setstapwrstate_parm {
+       u8      staid;
+       u8      status;
+       u8      hwaddr[6];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To setup the basic rate of RTL8711
+
+Command Mode
+
+*/
+struct setbasicrate_parm {
+       u8      basicrates[NumRates];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To read the current basic rate
+
+Command-Rsp Mode
+
+*/
+struct getbasicrate_parm {
+       u32 rsvd;
+};
+
+struct getbasicrate_rsp {
+       u8 basicrates[NumRates];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To setup the data rate of RTL8711
+
+Command Mode
+
+*/
+struct setdatarate_parm {
+       u8      mac_id;
+       u8      datarates[NumRates];
+};
+
+/*
+Caller Mode: Any
+
+Notes: To read the current data rate
+
+Command-Rsp Mode
+
+*/
+struct getdatarate_parm {
+       u32 rsvd;
+};
+
+struct getdatarate_rsp {
+       u8 datarates[NumRates];
+};
+
+
+/*
+Caller Mode: Any
+AP: AP can use the info for the contents of beacon frame
+Infra: STA can use the info when sitesurveying
+Ad-HoC(M): Like AP
+Ad-HoC(C): Like STA
+
+
+Notes: To set the phy capability of the NIC
+
+Command Mode
+
+*/
+
+struct setphyinfo_parm {
+       struct regulatory_class class_sets[NUM_REGULATORYS];
+       u8      status;
+};
+
+struct getphyinfo_parm {
+       u32 rsvd;
+};
+
+struct getphyinfo_rsp {
+       struct regulatory_class class_sets[NUM_REGULATORYS];
+       u8      status;
+};
+
+/*
+Caller Mode: Any
+
+Notes: To set the channel/modem/band
+This command will be used when channel/modem/band is changed.
+
+Command Mode
+
+*/
+struct setphy_parm {
+       u8      rfchannel;
+       u8      modem;
+};
+
+/*
+Caller Mode: Any
+
+Notes: To get the current setting of channel/modem/band
+
+Command-Rsp Mode
+
+*/
+struct getphy_parm {
+       u32 rsvd;
+};
+
+struct getphy_rsp {
+       u8      rfchannel;
+       u8      modem;
+};
+
+struct readBB_parm {
+       u8      offset;
+};
+
+struct readBB_rsp {
+       u8      value;
+};
+
+struct readTSSI_parm {
+       u8      offset;
+};
+
+struct readTSSI_rsp {
+       u8      value;
+};
+
+struct writeBB_parm {
+       u8      offset;
+       u8      value;
+};
+
+struct readRF_parm {
+       u8      offset;
+};
+
+struct readRF_rsp {
+       u32     value;
+};
+
+struct writeRF_parm {
+       u32     offset;
+       u32     value;
+};
+
+struct getrfintfs_parm {
+       u8      rfintfs;
+};
+
+struct Tx_Beacon_param
+{
+       struct wlan_bssid_ex network;
+};
+
+/*  CMD param Formart for driver extra cmd handler */
+struct drvextra_cmd_parm {
+       int ec_id; /* extra cmd id */
+       int type_size; /*  Can use this field as the type id or command size */
+       unsigned char *pbuf;
+};
+
+/*------------------- Below are used for RF/BB tunning ---------------------*/
+
+struct setantenna_parm {
+       u8      tx_antset;
+       u8      rx_antset;
+       u8      tx_antenna;
+       u8      rx_antenna;
+};
+
+struct enrateadaptive_parm {
+       u32     en;
+};
+
+struct settxagctbl_parm {
+       u32     txagc[MAX_RATES_LENGTH];
+};
+
+struct gettxagctbl_parm {
+       u32 rsvd;
+};
+
+struct gettxagctbl_rsp {
+       u32     txagc[MAX_RATES_LENGTH];
+};
+
+struct setagcctrl_parm {
+       u32     agcctrl;                /*  0: pure hw, 1: fw */
+};
+
+struct setssup_parm    {
+       u32     ss_ForceUp[MAX_RATES_LENGTH];
+};
+
+struct getssup_parm    {
+       u32 rsvd;
+};
+
+struct getssup_rsp     {
+       u8      ss_ForceUp[MAX_RATES_LENGTH];
+};
+
+struct setssdlevel_parm        {
+       u8      ss_DLevel[MAX_RATES_LENGTH];
+};
+
+struct getssdlevel_parm        {
+       u32 rsvd;
+};
+
+struct getssdlevel_rsp {
+       u8      ss_DLevel[MAX_RATES_LENGTH];
+};
+
+struct setssulevel_parm        {
+       u8      ss_ULevel[MAX_RATES_LENGTH];
+};
+
+struct getssulevel_parm        {
+       u32 rsvd;
+};
+
+struct getssulevel_rsp {
+       u8      ss_ULevel[MAX_RATES_LENGTH];
+};
+
+struct setcountjudge_parm {
+       u8      count_judge[MAX_RATES_LENGTH];
+};
+
+struct getcountjudge_parm {
+       u32 rsvd;
+};
+
+struct getcountjudge_rsp {
+       u8      count_judge[MAX_RATES_LENGTH];
+};
+
+struct setratable_parm {
+       u8 ss_ForceUp[NumRates];
+       u8 ss_ULevel[NumRates];
+       u8 ss_DLevel[NumRates];
+       u8 count_judge[NumRates];
+};
+
+struct getratable_parm {
+                uint rsvd;
+};
+
+struct getratable_rsp {
+        u8 ss_ForceUp[NumRates];
+        u8 ss_ULevel[NumRates];
+        u8 ss_DLevel[NumRates];
+        u8 count_judge[NumRates];
+};
+
+/* to get TX,RX retry count */
+struct gettxretrycnt_parm{
+       unsigned int rsvd;
+};
+struct gettxretrycnt_rsp{
+       unsigned long tx_retrycnt;
+};
+
+struct getrxretrycnt_parm{
+       unsigned int rsvd;
+};
+struct getrxretrycnt_rsp{
+       unsigned long rx_retrycnt;
+};
+
+/* to get BCNOK,BCNERR count */
+struct getbcnokcnt_parm{
+       unsigned int rsvd;
+};
+struct getbcnokcnt_rsp{
+       unsigned long  bcnokcnt;
+};
+
+struct getbcnerrcnt_parm{
+       unsigned int rsvd;
+};
+struct getbcnerrcnt_rsp{
+       unsigned long bcnerrcnt;
+};
+
+/*  to get current TX power level */
+struct getcurtxpwrlevel_parm{
+       unsigned int rsvd;
+};
+
+struct getcurtxpwrlevel_rsp{
+       unsigned short tx_power;
+};
+
+struct setprobereqextraie_parm {
+       unsigned char e_id;
+       unsigned char ie_len;
+       unsigned char ie[0];
+};
+
+struct setassocreqextraie_parm {
+       unsigned char e_id;
+       unsigned char ie_len;
+       unsigned char ie[0];
+};
+
+struct setproberspextraie_parm {
+       unsigned char e_id;
+       unsigned char ie_len;
+       unsigned char ie[0];
+};
+
+struct setassocrspextraie_parm {
+       unsigned char e_id;
+       unsigned char ie_len;
+       unsigned char ie[0];
+};
+
+struct addBaReq_parm {
+       unsigned int tid;
+       u8      addr[ETH_ALEN];
+};
+
+/*H2C Handler index: 46 */
+struct set_ch_parm {
+       u8 ch;
+       u8 bw;
+       u8 ch_offset;
+};
+
+/*H2C Handler index: 59 */
+struct SetChannelPlan_param {
+       u8 channel_plan;
+};
+
+/*H2C Handler index: 60 */
+struct LedBlink_param {
+       struct led_8723a *pLed;
+};
+
+/*H2C Handler index: 61 */
+struct SetChannelSwitch_param {
+       u8 new_ch_no;
+};
+
+/*H2C Handler index: 62 */
+struct TDLSoption_param {
+       u8 addr[ETH_ALEN];
+       u8 option;
+};
+
+#define GEN_CMD_CODE(cmd)      cmd ## _CMD_
+
+
+/*
+
+Result:
+0x00: success
+0x01: sucess, and check Response.
+0x02: cmd ignored due to duplicated sequcne number
+0x03: cmd dropped due to invalid cmd code
+0x04: reserved.
+
+*/
+
+#define H2C_RSP_OFFSET                 512
+
+#define H2C_SUCCESS                    0x00
+#define H2C_SUCCESS_RSP                        0x01
+#define H2C_DUPLICATED                 0x02
+#define H2C_DROPPED                    0x03
+#define H2C_PARAMETERS_ERROR           0x04
+#define H2C_REJECTED                   0x05
+#define H2C_CMD_OVERFLOW               0x06
+#define H2C_RESERVED                   0x07
+
+u8 rtw_setassocsta_cmd(struct rtw_adapter  *padapter, u8 *mac_addr);
+u8 rtw_setstandby_cmd(struct rtw_adapter *padapter, uint action);
+u8 rtw_sitesurvey_cmd23a(struct rtw_adapter  *padapter, struct cfg80211_ssid *ssid, int ssid_num, struct rtw_ieee80211_channel *ch, int ch_num);
+u8 rtw_createbss_cmd23a(struct rtw_adapter  *padapter);
+u8 rtw_createbss_cmd23a_ex(struct rtw_adapter  *padapter, unsigned char *pbss, unsigned int sz);
+u8 rtw_setphy_cmd(struct rtw_adapter  *padapter, u8 modem, u8 ch);
+u8 rtw_setstakey_cmd23a(struct rtw_adapter  *padapter, u8 *psta, u8 unicast_key);
+u8 rtw_clearstakey_cmd23a(struct rtw_adapter *padapter, u8 *psta, u8 entry, u8 enqueue);
+u8 rtw_joinbss_cmd23a(struct rtw_adapter  *padapter, struct wlan_network* pnetwork);
+u8 rtw_disassoc_cmd23a(struct rtw_adapter *padapter, u32 deauth_timeout_ms, bool enqueue);
+u8 rtw_setopmode_cmd23a(struct rtw_adapter  *padapter, enum ndis_802_11_net_infra networktype);
+u8 rtw_setdatarate_cmd(struct rtw_adapter  *padapter, u8 *rateset);
+u8 rtw_setbasicrate_cmd(struct rtw_adapter  *padapter, u8 *rateset);
+u8 rtw_setbbreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 val);
+u8 rtw_setrfreg_cmd(struct rtw_adapter * padapter, u8 offset, u32 val);
+u8 rtw_getbbreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 * pval);
+u8 rtw_getrfreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 * pval);
+u8 rtw_setrfintfs_cmd(struct rtw_adapter  *padapter, u8 mode);
+u8 rtw_setrttbl_cmd(struct rtw_adapter  *padapter, struct setratable_parm *prate_table);
+u8 rtw_getrttbl_cmd(struct rtw_adapter  *padapter, struct getratable_rsp *pval);
+
+u8 rtw_gettssi_cmd(struct rtw_adapter  *padapter, u8 offset,u8 *pval);
+u8 rtw_setfwdig_cmd(struct rtw_adapter*padapter, u8 type);
+u8 rtw_setfwra_cmd(struct rtw_adapter*padapter, u8 type);
+
+u8 rtw_addbareq_cmd23a(struct rtw_adapter*padapter, u8 tid, u8 *addr);
+
+u8 rtw_dynamic_chk_wk_cmd23a(struct rtw_adapter *adapter);
+
+u8 rtw_lps_ctrl_wk_cmd23a(struct rtw_adapter*padapter, u8 lps_ctrl_type, u8 enqueue);
+
+u8 rtw_ps_cmd23a(struct rtw_adapter*padapter);
+
+#ifdef CONFIG_8723AU_AP_MODE
+u8 rtw_chk_hi_queue_cmd23a(struct rtw_adapter*padapter);
+#endif
+
+u8 rtw_set_ch_cmd23a(struct rtw_adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue);
+u8 rtw_set_chplan_cmd(struct rtw_adapter*padapter, u8 chplan, u8 enqueue);
+u8 rtw_led_blink_cmd(struct rtw_adapter*padapter, struct led_8723a *pLed);
+u8 rtw_set_csa_cmd(struct rtw_adapter*padapter, u8 new_ch_no);
+u8 rtw_tdls_cmd(struct rtw_adapter*padapter, u8 *addr, u8 option);
+
+u8 rtw_c2h_wk_cmd23a(struct rtw_adapter *padapter, u8 *c2h_evt);
+
+u8 rtw_drvextra_cmd_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf);
+
+void rtw_survey_cmd_callback23a(struct rtw_adapter  *padapter, struct cmd_obj *pcmd);
+void rtw_disassoc_cmd23a_callback(struct rtw_adapter  *padapter, struct cmd_obj *pcmd);
+void rtw_joinbss_cmd23a_callback(struct rtw_adapter  *padapter, struct cmd_obj *pcmd);
+void rtw_createbss_cmd23a_callback(struct rtw_adapter  *padapter, struct cmd_obj *pcmd);
+void rtw_getbbrfreg_cmdrsp_callback23a(struct rtw_adapter  *padapter, struct cmd_obj *pcmd);
+void rtw_readtssi_cmdrsp_callback(struct rtw_adapter*  padapter,  struct cmd_obj *pcmd);
+
+void rtw_setstaKey_cmdrsp_callback23a(struct rtw_adapter  *padapter,  struct cmd_obj *pcmd);
+void rtw_setassocsta_cmdrsp_callback23a(struct rtw_adapter  *padapter,  struct cmd_obj *pcmd);
+void rtw_getrttbl_cmdrsp_callback(struct rtw_adapter  *padapter,  struct cmd_obj *pcmd);
+
+struct _cmd_callback {
+       u32     cmd_code;
+       void (*callback)(struct rtw_adapter  *padapter, struct cmd_obj *cmd);
+};
+
+enum rtw_h2c_cmd {
+       GEN_CMD_CODE(_Read_MACREG) ,    /*0*/
+       GEN_CMD_CODE(_Write_MACREG) ,
+       GEN_CMD_CODE(_Read_BBREG) ,
+       GEN_CMD_CODE(_Write_BBREG) ,
+       GEN_CMD_CODE(_Read_RFREG) ,
+       GEN_CMD_CODE(_Write_RFREG) , /*5*/
+       GEN_CMD_CODE(_Read_EEPROM) ,
+       GEN_CMD_CODE(_Write_EEPROM) ,
+       GEN_CMD_CODE(_Read_EFUSE) ,
+       GEN_CMD_CODE(_Write_EFUSE) ,
+
+       GEN_CMD_CODE(_Read_CAM) ,       /*10*/
+       GEN_CMD_CODE(_Write_CAM) ,
+       GEN_CMD_CODE(_setBCNITV),
+       GEN_CMD_CODE(_setMBIDCFG),
+       GEN_CMD_CODE(_JoinBss),   /*14*/
+       GEN_CMD_CODE(_DisConnect) , /*15*/
+       GEN_CMD_CODE(_CreateBss) ,
+       GEN_CMD_CODE(_SetOpMode) ,
+       GEN_CMD_CODE(_SiteSurvey),  /*18*/
+       GEN_CMD_CODE(_SetAuth) ,
+
+       GEN_CMD_CODE(_SetKey) , /*20*/
+       GEN_CMD_CODE(_SetStaKey) ,
+       GEN_CMD_CODE(_SetAssocSta) ,
+       GEN_CMD_CODE(_DelAssocSta) ,
+       GEN_CMD_CODE(_SetStaPwrState) ,
+       GEN_CMD_CODE(_SetBasicRate) , /*25*/
+       GEN_CMD_CODE(_GetBasicRate) ,
+       GEN_CMD_CODE(_SetDataRate) ,
+       GEN_CMD_CODE(_GetDataRate) ,
+       GEN_CMD_CODE(_SetPhyInfo) ,
+
+       GEN_CMD_CODE(_GetPhyInfo) ,     /*30*/
+       GEN_CMD_CODE(_SetPhy) ,
+       GEN_CMD_CODE(_GetPhy) ,
+       GEN_CMD_CODE(_readRssi) ,
+       GEN_CMD_CODE(_readGain) ,
+       GEN_CMD_CODE(_SetAtim) , /*35*/
+       GEN_CMD_CODE(_SetPwrMode) ,
+       GEN_CMD_CODE(_JoinbssRpt),
+       GEN_CMD_CODE(_SetRaTable) ,
+       GEN_CMD_CODE(_GetRaTable) ,
+
+       GEN_CMD_CODE(_GetCCXReport), /*40*/
+       GEN_CMD_CODE(_GetDTMReport),
+       GEN_CMD_CODE(_GetTXRateStatistics),
+       GEN_CMD_CODE(_SetUsbSuspend),
+       GEN_CMD_CODE(_SetH2cLbk),
+       GEN_CMD_CODE(_AddBAReq) , /*45*/
+       GEN_CMD_CODE(_SetChannel), /*46*/
+       GEN_CMD_CODE(_SetTxPower),
+       GEN_CMD_CODE(_SwitchAntenna),
+       GEN_CMD_CODE(_SetCrystalCap),
+       GEN_CMD_CODE(_SetSingleCarrierTx), /*50*/
+
+       GEN_CMD_CODE(_SetSingleToneTx),/*51*/
+       GEN_CMD_CODE(_SetCarrierSuppressionTx),
+       GEN_CMD_CODE(_SetContinuousTx),
+       GEN_CMD_CODE(_SwitchBandwidth), /*54*/
+       GEN_CMD_CODE(_TX_Beacon), /*55*/
+
+       GEN_CMD_CODE(_Set_MLME_EVT), /*56*/
+       GEN_CMD_CODE(_Set_Drv_Extra), /*57*/
+       GEN_CMD_CODE(_Set_H2C_MSG), /*58*/
+
+       GEN_CMD_CODE(_SetChannelPlan), /*59*/
+       GEN_CMD_CODE(_LedBlink), /*60*/
+
+       GEN_CMD_CODE(_SetChannelSwitch), /*61*/
+       GEN_CMD_CODE(_TDLS), /*62*/
+
+       MAX_H2CCMD
+};
+
+#define _GetBBReg_CMD_         _Read_BBREG_CMD_
+#define _SetBBReg_CMD_         _Write_BBREG_CMD_
+#define _GetRFReg_CMD_         _Read_RFREG_CMD_
+#define _SetRFReg_CMD_         _Write_RFREG_CMD_
+
+extern struct _cmd_callback    rtw_cmd_callback[];
+
+#endif /*  _CMD_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_debug.h b/drivers/staging/rtl8723au/include/rtw_debug.h
new file mode 100644 (file)
index 0000000..a69d6e2
--- /dev/null
@@ -0,0 +1,192 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_DEBUG_H__
+#define __RTW_DEBUG_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define _drv_always_                   1
+#define _drv_emerg_                    2
+#define _drv_alert_                    3
+#define _drv_err_                      4
+#define        _drv_warning_                   5
+#define _drv_notice_                   6
+#define _drv_info_                     7
+#define        _drv_debug_                     8
+
+#define _module_rtl871x_xmit_c_                BIT(0)
+#define _module_xmit_osdep_c_          BIT(1)
+#define _module_rtl871x_recv_c_                BIT(2)
+#define _module_recv_osdep_c_          BIT(3)
+#define _module_rtl871x_mlme_c_                BIT(4)
+#define _module_mlme_osdep_c_          BIT(5)
+#define _module_rtl871x_sta_mgt_c_     BIT(6)
+#define _module_rtl871x_cmd_c_         BIT(7)
+#define _module_cmd_osdep_c_           BIT(8)
+#define _module_rtl871x_io_c_          BIT(9)
+#define _module_io_osdep_c_            BIT(10)
+#define _module_os_intfs_c_            BIT(11)
+#define _module_rtl871x_security_c_    BIT(12)
+#define _module_rtl871x_eeprom_c_      BIT(13)
+#define _module_hal_init_c_            BIT(14)
+#define _module_hci_hal_init_c_                BIT(15)
+#define _module_rtl871x_ioctl_c_       BIT(16)
+#define _module_rtl871x_ioctl_set_c_   BIT(17)
+#define _module_rtl871x_ioctl_query_c_ BIT(18)
+#define _module_rtl871x_pwrctrl_c_     BIT(19)
+#define _module_hci_intfs_c_           BIT(20)
+#define _module_hci_ops_c_             BIT(21)
+#define _module_osdep_service_c_       BIT(22)
+#define _module_mp_                    BIT(23)
+#define _module_hci_ops_os_c_          BIT(24)
+#define _module_rtl871x_ioctl_os_c     BIT(25)
+#define _module_rtl8712_cmd_c_         BIT(26)
+#define        _module_rtl8192c_xmit_c_        BIT(28)
+#define _module_hal_xmit_c_            BIT(28) /* duplication intentional */
+#define _module_efuse_                 BIT(29)
+#define _module_rtl8712_recv_c_                BIT(30)
+#define _module_rtl8712_led_c_         BIT(31)
+
+#undef _MODULE_DEFINE_
+
+#if defined _RTW_XMIT_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_xmit_c_
+#elif defined _XMIT_OSDEP_C_
+       #define _MODULE_DEFINE_ _module_xmit_osdep_c_
+#elif defined _RTW_RECV_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_recv_c_
+#elif defined _RECV_OSDEP_C_
+       #define _MODULE_DEFINE_ _module_recv_osdep_c_
+#elif defined _RTW_MLME_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_mlme_c_
+#elif defined _MLME_OSDEP_C_
+       #define _MODULE_DEFINE_ _module_mlme_osdep_c_
+#elif defined _RTW_MLME_EXT_C_
+       #define _MODULE_DEFINE_ 1
+#elif defined _RTW_STA_MGT_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_sta_mgt_c_
+#elif defined _RTW_CMD_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_cmd_c_
+#elif defined _CMD_OSDEP_C_
+       #define _MODULE_DEFINE_ _module_cmd_osdep_c_
+#elif defined _RTW_IO_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_io_c_
+#elif defined _IO_OSDEP_C_
+       #define _MODULE_DEFINE_ _module_io_osdep_c_
+#elif defined _OS_INTFS_C_
+       #define _MODULE_DEFINE_ _module_os_intfs_c_
+#elif defined _RTW_SECURITY_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_security_c_
+#elif defined _RTW_EEPROM_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_eeprom_c_
+#elif defined _HAL_INTF_C_
+       #define _MODULE_DEFINE_ _module_hal_init_c_
+#elif (defined _HCI_HAL_INIT_C_) || (defined _SDIO_HALINIT_C_)
+       #define _MODULE_DEFINE_ _module_hci_hal_init_c_
+#elif defined _RTL871X_IOCTL_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_ioctl_c_
+#elif defined _RTL871X_IOCTL_SET_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_ioctl_set_c_
+#elif defined _RTL871X_IOCTL_QUERY_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_ioctl_query_c_
+#elif defined _RTL871X_PWRCTRL_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_pwrctrl_c_
+#elif defined _RTW_PWRCTRL_C_
+       #define _MODULE_DEFINE_ 1
+#elif defined _HCI_INTF_C_
+       #define _MODULE_DEFINE_ _module_hci_intfs_c_
+#elif defined _HCI_OPS_C_
+       #define _MODULE_DEFINE_ _module_hci_ops_c_
+#elif defined _SDIO_OPS_C_
+       #define _MODULE_DEFINE_ 1
+#elif defined _OSDEP_HCI_INTF_C_
+       #define _MODULE_DEFINE_ _module_hci_intfs_c_
+#elif defined _OSDEP_SERVICE_C_
+       #define _MODULE_DEFINE_ _module_osdep_service_c_
+#elif defined _HCI_OPS_OS_C_
+       #define _MODULE_DEFINE_ _module_hci_ops_os_c_
+#elif defined _RTL871X_IOCTL_LINUX_C_
+       #define _MODULE_DEFINE_ _module_rtl871x_ioctl_os_c
+#elif defined _RTL8712_CMD_C_
+       #define _MODULE_DEFINE_ _module_rtl8712_cmd_c_
+#elif defined _RTL8192C_XMIT_C_
+       #define _MODULE_DEFINE_ 1
+#elif defined _RTL8723AS_XMIT_C_
+       #define _MODULE_DEFINE_ 1
+#elif defined _RTL8712_RECV_C_
+       #define _MODULE_DEFINE_ _module_rtl8712_recv_c_
+#elif defined _RTL8192CU_RECV_C_
+       #define _MODULE_DEFINE_ _module_rtl8712_recv_c_
+#elif defined _RTL871X_MLME_EXT_C_
+       #define _MODULE_DEFINE_ _module_mlme_osdep_c_
+#elif defined _RTW_MP_C_
+       #define _MODULE_DEFINE_ _module_mp_
+#elif defined _RTW_MP_IOCTL_C_
+       #define _MODULE_DEFINE_ _module_mp_
+#elif defined _RTW_EFUSE_C_
+       #define _MODULE_DEFINE_ _module_efuse_
+#endif
+
+#define DRIVER_PREFIX  "RTL8723AU: "
+#define DEBUG_LEVEL    (_drv_err_)
+#define DBG_8723A_LEVEL(_level, fmt, arg...)                           \
+       do {                                                            \
+               if (_level <= GlobalDebugLevel23A)                              \
+                       pr_info(DRIVER_PREFIX"ERROR " fmt, ##arg);\
+       } while (0)
+
+#define DBG_8723A(...)                                                 \
+       do {                                                            \
+               if (_drv_err_ <= GlobalDebugLevel23A)                   \
+                       pr_info(DRIVER_PREFIX __VA_ARGS__);             \
+       } while (0)
+
+#define MSG_8723A(...)                                                 \
+       do {                                                            \
+               if (_drv_err_ <= GlobalDebugLevel23A)                   \
+                       pr_info(DRIVER_PREFIX __VA_ARGS__);             \
+       } while (0)
+
+extern u32 GlobalDebugLevel23A;
+
+
+#define RT_TRACE(_Comp, _Level, Fmt)                                   \
+do {                                                                   \
+       if (_Level <= GlobalDebugLevel23A) {                            \
+               pr_info("%s [0x%08x,%d]", DRIVER_PREFIX,                \
+                        (unsigned int)_Comp, _Level);                  \
+               pr_info Fmt;                                            \
+       }                                                               \
+} while (0)
+
+#define RT_PRINT_DATA(_Comp, _Level, _TitleString, _HexData,           \
+                     _HexDataLen)                                      \
+       if (_Level <= GlobalDebugLevel23A) {                            \
+               int __i;                                                \
+               u8      *ptr = (u8 *)_HexData;                          \
+               pr_info("%s", DRIVER_PREFIX);                           \
+               pr_info(_TitleString);                                  \
+               for (__i = 0; __i < (int)_HexDataLen; __i++) {          \
+                       printk("%02X%s", ptr[__i],                      \
+                              (((__i + 1) % 4) == 0) ? "  " : " ");    \
+                       if (((__i + 1) % 16) == 0)                      \
+                               printk("\n");                           \
+               }                                                       \
+               printk("\n");                                           \
+       }
+
+#endif /* __RTW_DEBUG_H__ */
diff --git a/drivers/staging/rtl8723au/include/rtw_eeprom.h b/drivers/staging/rtl8723au/include/rtw_eeprom.h
new file mode 100644 (file)
index 0000000..d008f03
--- /dev/null
@@ -0,0 +1,135 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTW_EEPROM_H__
+#define __RTW_EEPROM_H__
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define        RTL8712_EEPROM_ID                       0x8712
+/* define      EEPROM_MAX_SIZE                 256 */
+
+#define        HWSET_MAX_SIZE_512              512
+#define        EEPROM_MAX_SIZE                 HWSET_MAX_SIZE_512
+
+#define        CLOCK_RATE                                      50                      /* 100us */
+
+/*  EEPROM opcodes */
+#define EEPROM_READ_OPCODE             06
+#define EEPROM_WRITE_OPCODE            05
+#define EEPROM_ERASE_OPCODE            07
+#define EEPROM_EWEN_OPCODE             19      /*  Erase/write enable */
+#define EEPROM_EWDS_OPCODE             16      /*  Erase/write disable */
+
+/* Country codes */
+#define USA                                                    0x555320
+#define EUROPE                                         0x1 /* temp, should be provided later */
+#define JAPAN                                          0x2 /* temp, should be provided later */
+
+#define        EEPROM_CID_DEFAULT                      0x0
+#define        EEPROM_CID_ALPHA                                0x1
+#define        EEPROM_CID_Senao                                0x3
+#define        EEPROM_CID_NetCore                              0x5
+#define        EEPROM_CID_CAMEO                                0X8
+#define        EEPROM_CID_SITECOM                              0x9
+#define        EEPROM_CID_COREGA                               0xB
+#define        EEPROM_CID_EDIMAX_BELKIN                0xC
+#define        EEPROM_CID_SERCOMM_BELKIN               0xE
+#define        EEPROM_CID_CAMEO1                               0xF
+#define        EEPROM_CID_WNC_COREGA           0x12
+#define        EEPROM_CID_CLEVO                                0x13
+#define        EEPROM_CID_WHQL                         0xFE /*  added by chiyoko for dtm, 20090108 */
+
+/*  */
+/*  Customer ID, note that: */
+/*  This variable is initiailzed through EEPROM or registry, */
+/*  however, its definition may be different with that in EEPROM for */
+/*  EEPROM size consideration. So, we have to perform proper translation between them. */
+/*  Besides, CustomerID of registry has precedence of that of EEPROM. */
+/*  defined below. 060703, by rcnjko. */
+/*  */
+enum rt_customer_id
+{
+       RT_CID_DEFAULT = 0,
+       RT_CID_8187_ALPHA0 = 1,
+       RT_CID_8187_SERCOMM_PS = 2,
+       RT_CID_8187_HW_LED = 3,
+       RT_CID_8187_NETGEAR = 4,
+       RT_CID_WHQL = 5,
+       RT_CID_819x_CAMEO  = 6,
+       RT_CID_819x_RUNTOP = 7,
+       RT_CID_819x_Senao = 8,
+       RT_CID_TOSHIBA = 9,     /*  Merge by Jacken, 2008/01/31. */
+       RT_CID_819x_Netcore = 10,
+       RT_CID_Nettronix = 11,
+       RT_CID_DLINK = 12,
+       RT_CID_PRONET = 13,
+       RT_CID_COREGA = 14,
+       RT_CID_CHINA_MOBILE = 15,
+       RT_CID_819x_ALPHA = 16,
+       RT_CID_819x_Sitecom = 17,
+       RT_CID_CCX = 18, /*  It's set under CCX logo test and isn't demanded for CCX functions, but for test behavior like retry limit and tx report. By Bruce, 2009-02-17. */
+       RT_CID_819x_Lenovo = 19,
+       RT_CID_819x_QMI = 20,
+       RT_CID_819x_Edimax_Belkin = 21,
+       RT_CID_819x_Sercomm_Belkin = 22,
+       RT_CID_819x_CAMEO1 = 23,
+       RT_CID_819x_MSI = 24,
+       RT_CID_819x_Acer = 25,
+       RT_CID_819x_AzWave_ASUS = 26,
+       RT_CID_819x_AzWave = 27, /*  For AzWave in PCIe, The ID is AzWave use and not only Asus */
+       RT_CID_819x_HP = 28,
+       RT_CID_819x_WNC_COREGA = 29,
+       RT_CID_819x_Arcadyan_Belkin = 30,
+       RT_CID_819x_SAMSUNG = 31,
+       RT_CID_819x_CLEVO = 32,
+       RT_CID_819x_DELL = 33,
+       RT_CID_819x_PRONETS = 34,
+       RT_CID_819x_Edimax_ASUS = 35,
+       RT_CID_819x_CAMEO_NETGEAR = 36,
+       RT_CID_PLANEX = 37,
+       RT_CID_CC_C = 38,
+       RT_CID_819x_Xavi = 39,
+       RT_CID_819x_FUNAI_TV = 40,
+       RT_CID_819x_ALPHA_WD=41,
+};
+
+struct eeprom_priv {
+       u8              bautoload_fail_flag;
+       u8              bloadfile_fail_flag;
+       u8              bloadmac_fail_flag;
+       /* u8           bempty; */
+       /* u8           sys_config; */
+       u8              mac_addr[6];    /* PermanentAddress */
+       /* u8           config0; */
+       u16             channel_plan;
+       /* u8           country_string[3]; */
+       /* u8           tx_power_b[15]; */
+       /* u8           tx_power_g[15]; */
+       /* u8           tx_power_a[201]; */
+
+       u8              EepromOrEfuse;
+
+       u8              efuse_eeprom_data[HWSET_MAX_SIZE_512]; /* 92C:256bytes, 88E:512bytes, we use union set (512bytes) */
+};
+
+void eeprom_write16(struct rtw_adapter *padapter, u16 reg, u16 data);
+u16 eeprom_read16(struct rtw_adapter *padapter, u16 reg);
+void read_eeprom_content(struct rtw_adapter *padapter);
+void eeprom_read_sz(struct rtw_adapter * padapter, u16 reg,u8* data, u32 sz);
+
+void read_eeprom_content_by_attrib(struct rtw_adapter *padapter);
+
+#endif  /* __RTL871X_EEPROM_H__ */
diff --git a/drivers/staging/rtl8723au/include/rtw_efuse.h b/drivers/staging/rtl8723au/include/rtw_efuse.h
new file mode 100644 (file)
index 0000000..a775505
--- /dev/null
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_EFUSE_H__
+#define __RTW_EFUSE_H__
+
+#include <osdep_service.h>
+
+#define        EFUSE_ERROE_HANDLE              1
+
+#define        PG_STATE_HEADER                 0x01
+#define        PG_STATE_WORD_0         0x02
+#define        PG_STATE_WORD_1         0x04
+#define        PG_STATE_WORD_2         0x08
+#define        PG_STATE_WORD_3         0x10
+#define        PG_STATE_DATA                   0x20
+
+#define        PG_SWBYTE_H                     0x01
+#define        PG_SWBYTE_L                     0x02
+
+#define        PGPKT_DATA_SIZE         8
+
+#define        EFUSE_WIFI                              0
+#define        EFUSE_BT                                1
+
+enum _EFUSE_DEF_TYPE {
+       TYPE_EFUSE_MAX_SECTION                          = 0,
+       TYPE_EFUSE_REAL_CONTENT_LEN                     = 1,
+       TYPE_AVAILABLE_EFUSE_BYTES_BANK         = 2,
+       TYPE_AVAILABLE_EFUSE_BYTES_TOTAL        = 3,
+       TYPE_EFUSE_MAP_LEN                                      = 4,
+       TYPE_EFUSE_PROTECT_BYTES_BANK           = 5,
+       TYPE_EFUSE_CONTENT_LEN_BANK                     = 6,
+};
+
+/* E-Fuse */
+#define EFUSE_MAP_SIZE      256
+
+#define EFUSE_MAX_SIZE      512
+/* end of E-Fuse */
+
+#define                EFUSE_MAX_MAP_LEN               256
+#define                EFUSE_MAX_HW_SIZE               512
+#define                EFUSE_MAX_SECTION_BASE  16
+
+#define EXT_HEADER(header) ((header & 0x1F ) == 0x0F)
+#define ALL_WORDS_DISABLED(wde)        ((wde & 0x0F) == 0x0F)
+#define GET_HDR_OFFSET_2_0(header) ( (header & 0xE0) >> 5)
+
+#define                EFUSE_REPEAT_THRESHOLD_                 3
+
+/*  */
+/*     The following is for BT Efuse definition */
+/*  */
+#define                EFUSE_BT_MAX_MAP_LEN            1024
+#define                EFUSE_MAX_BANK                  4
+#define                EFUSE_MAX_BT_BANK               (EFUSE_MAX_BANK-1)
+/*  */
+/*--------------------------Define Parameters-------------------------------*/
+#define                EFUSE_MAX_WORD_UNIT                     4
+
+/*------------------------------Define structure----------------------------*/
+struct pg_pkt_struct {
+       u8 offset;
+       u8 word_en;
+       u8 data[8];
+       u8 word_cnts;
+};
+
+/*------------------------Export global variable----------------------------*/
+
+u8     efuse_GetCurrentSize23a(struct rtw_adapter *padapter, u16 *size);
+u16    efuse_GetMaxSize23a(struct rtw_adapter *padapter);
+u8     rtw_efuse_access23a(struct rtw_adapter *padapter, u8 bRead, u16 start_addr, u16 cnts, u8 *data);
+u8     rtw_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data);
+u8     rtw_efuse_map_write(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data);
+u8     rtw_BT_efuse_map_read23a(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data);
+u8     rtw_BT_efuse_map_write(struct rtw_adapter *padapter, u16 addr, u16 cnts, u8 *data);
+
+u16    Efuse_GetCurrentSize23a(struct rtw_adapter *pAdapter, u8 efuseType);
+u8     Efuse_CalculateWordCnts23a(u8 word_en);
+void   ReadEFuseByte23a(struct rtw_adapter *Adapter, u16 _offset, u8 *pbuf);
+void   EFUSE_GetEfuseDefinition23a(struct rtw_adapter *pAdapter, u8 efuseType, u8 type, void *pOut);
+u8     efuse_OneByteRead23a(struct rtw_adapter *pAdapter, u16 addr, u8 *data);
+u8     efuse_OneByteWrite23a(struct rtw_adapter *pAdapter, u16 addr, u8 data);
+
+void   Efuse_PowerSwitch23a(struct rtw_adapter *pAdapter,u8    bWrite,u8        PwrState);
+int    Efuse_PgPacketRead23a(struct rtw_adapter *pAdapter, u8 offset, u8 *data);
+int    Efuse_PgPacketWrite23a(struct rtw_adapter *pAdapter, u8 offset, u8 word_en, u8 *data);
+void   efuse_WordEnableDataRead23a(u8 word_en, u8 *sourdata, u8 *targetdata);
+u8     Efuse_WordEnableDataWrite23a(struct rtw_adapter *pAdapter, u16 efuse_addr, u8 word_en, u8 *data);
+
+u8     EFUSE_Read1Byte23a(struct rtw_adapter *pAdapter, u16 Address);
+void   EFUSE_ShadowMapUpdate23a(struct rtw_adapter *pAdapter, u8 efuseType);
+void   EFUSE_ShadowRead23a(struct rtw_adapter *pAdapter, u8 Type, u16 Offset, u32 *Value);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtw_event.h b/drivers/staging/rtl8723au/include/rtw_event.h
new file mode 100644 (file)
index 0000000..bb20640
--- /dev/null
@@ -0,0 +1,114 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef _RTW_EVENT_H_
+#define _RTW_EVENT_H_
+
+#include <osdep_service.h>
+
+#include <wlan_bssdef.h>
+
+/*
+Used to report a bss has been scanned
+
+*/
+struct survey_event    {
+       struct wlan_bssid_ex bss;
+};
+
+/*
+Used to report that the requested site survey has been done.
+
+bss_cnt indicates the number of bss that has been reported.
+
+
+*/
+struct surveydone_event {
+       unsigned int    bss_cnt;
+
+};
+
+/*
+Used to report the link result of joinning the given bss
+
+
+join_res:
+-1: authentication fail
+-2: association fail
+> 0: TID
+
+*/
+struct joinbss_event {
+       struct  wlan_network    network;
+};
+
+/*
+Used to report a given STA has joinned the created BSS.
+It is used in AP/Ad-HoC(M) mode.
+
+
+*/
+struct stassoc_event {
+       unsigned char macaddr[6];
+       unsigned char rsvd[2];
+       int    cam_id;
+
+};
+
+struct stadel_event {
+ unsigned char macaddr[6];
+ unsigned char rsvd[2]; /* for reason */
+ int mac_id;
+};
+
+struct addba_event
+{
+       unsigned int tid;
+};
+
+#define GEN_EVT_CODE(event)    event ## _EVT_
+
+struct fwevent {
+       u32     parmsize;
+       void (*event_callback)(struct rtw_adapter *dev, u8 *pbuf);
+};
+
+
+#define C2HEVENT_SZ                    32
+
+struct event_node{
+       unsigned char *node;
+       unsigned char evt_code;
+       unsigned short evt_sz;
+       volatile int    *caller_ff_tail;
+       int     caller_ff_sz;
+};
+
+struct c2hevent_queue {
+       volatile int    head;
+       volatile int    tail;
+       struct  event_node      nodes[C2HEVENT_SZ];
+       unsigned char   seq;
+};
+
+#define NETWORK_QUEUE_SZ       4
+
+struct network_queue {
+       volatile int    head;
+       volatile int    tail;
+       struct wlan_bssid_ex networks[NETWORK_QUEUE_SZ];
+};
+
+
+#endif /*  _WLANEVENT_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_ht.h b/drivers/staging/rtl8723au/include/rtw_ht.h
new file mode 100644 (file)
index 0000000..7fe0aa4
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef _RTW_HT_H_
+#define _RTW_HT_H_
+
+#include <osdep_service.h>
+#include "linux/ieee80211.h"
+#include "wifi.h"
+
+struct ht_priv
+{
+       u32     ht_option;
+       u32     ampdu_enable;/* for enable Tx A-MPDU */
+       /* u8   baddbareq_issued[16]; */
+       u32     tx_amsdu_enable;/* for enable Tx A-MSDU */
+       u32     tx_amdsu_maxlen; /*  1: 8k, 0:4k ; default:8k, for tx */
+       u32     rx_ampdu_maxlen; /* for rx reordering ctrl win_sz, updated when join_callback. */
+
+       u8      bwmode;/*  */
+       u8      ch_offset;/* PRIME_CHNL_OFFSET */
+       u8      sgi;/* short GI */
+
+       /* for processing Tx A-MPDU */
+       u8      agg_enable_bitmap;
+       /* u8   ADDBA_retry_count; */
+       u8      candidate_tid_bitmap;
+
+       struct ieee80211_ht_cap ht_cap;
+};
+
+#endif /* _RTL871X_HT_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_io.h b/drivers/staging/rtl8723au/include/rtw_io.h
new file mode 100644 (file)
index 0000000..8d39d80
--- /dev/null
@@ -0,0 +1,416 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+#ifndef _RTW_IO_H_
+#define _RTW_IO_H_
+
+#include <osdep_service.h>
+#include <osdep_intf.h>
+
+#include <asm/byteorder.h>
+#include <linux/semaphore.h>
+#include <linux/list.h>
+/* include <linux/smp_lock.h> */
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+
+#define rtw_usb_buffer_alloc(dev, size, dma) usb_alloc_coherent((dev), (size), (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL), (dma))
+#define rtw_usb_buffer_free(dev, size, addr, dma) usb_free_coherent((dev), (size), (addr), (dma))
+
+#define NUM_IOREQ              8
+
+#define MAX_PROT_SZ    (64-16)
+
+#define _IOREADY                       0
+#define _IO_WAIT_COMPLETE   1
+#define _IO_WAIT_RSP        2
+
+/*  IO COMMAND TYPE */
+#define _IOSZ_MASK_            (0x7F)
+#define _IO_WRITE_             BIT(7)
+#define _IO_FIXED_             BIT(8)
+#define _IO_BURST_             BIT(9)
+#define _IO_BYTE_              BIT(10)
+#define _IO_HW_                        BIT(11)
+#define _IO_WORD_              BIT(12)
+#define _IO_SYNC_              BIT(13)
+#define _IO_CMDMASK_   (0x1F80)
+
+
+/*
+       For prompt mode accessing, caller shall free io_req
+       Otherwise, io_handler will free io_req
+*/
+
+
+
+/*  IO STATUS TYPE */
+#define _IO_ERR_               BIT(2)
+#define _IO_SUCCESS_   BIT(1)
+#define _IO_DONE_              BIT(0)
+
+
+#define IO_RD32                        (_IO_SYNC_ | _IO_WORD_)
+#define IO_RD16                        (_IO_SYNC_ | _IO_HW_)
+#define IO_RD8                 (_IO_SYNC_ | _IO_BYTE_)
+
+#define IO_RD32_ASYNC  (_IO_WORD_)
+#define IO_RD16_ASYNC  (_IO_HW_)
+#define IO_RD8_ASYNC   (_IO_BYTE_)
+
+#define IO_WR32                        (_IO_WRITE_ | _IO_SYNC_ | _IO_WORD_)
+#define IO_WR16                        (_IO_WRITE_ | _IO_SYNC_ | _IO_HW_)
+#define IO_WR8                 (_IO_WRITE_ | _IO_SYNC_ | _IO_BYTE_)
+
+#define IO_WR32_ASYNC  (_IO_WRITE_ | _IO_WORD_)
+#define IO_WR16_ASYNC  (_IO_WRITE_ | _IO_HW_)
+#define IO_WR8_ASYNC   (_IO_WRITE_ | _IO_BYTE_)
+
+/*
+
+       Only Sync. burst accessing is provided.
+
+*/
+
+#define IO_WR_BURST(x)         (_IO_WRITE_ | _IO_SYNC_ | _IO_BURST_ | ( (x) & _IOSZ_MASK_))
+#define IO_RD_BURST(x)         (_IO_SYNC_ | _IO_BURST_ | ( (x) & _IOSZ_MASK_))
+
+
+
+/* below is for the intf_option bit defition... */
+
+#define _INTF_ASYNC_   BIT(0)  /* support async io */
+
+struct intf_priv;
+struct intf_hdl;
+struct io_queue;
+
+struct _io_ops
+{
+               u8 (*_read8)(struct intf_hdl *pintfhdl, u32 addr);
+               u16 (*_read16)(struct intf_hdl *pintfhdl, u32 addr);
+               u32 (*_read32)(struct intf_hdl *pintfhdl, u32 addr);
+
+               int (*_write8)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+               int (*_write16)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+               int (*_write32)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+               int (*_writeN)(struct intf_hdl *pintfhdl, u32 addr, u32 length, u8 *pdata);
+
+               int (*_write8_async)(struct intf_hdl *pintfhdl, u32 addr, u8 val);
+               int (*_write16_async)(struct intf_hdl *pintfhdl, u32 addr, u16 val);
+               int (*_write32_async)(struct intf_hdl *pintfhdl, u32 addr, u32 val);
+
+               void (*_read_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+               void (*_write_mem)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *pmem);
+
+               void (*_sync_irp_protocol_rw)(struct io_queue *pio_q);
+
+               u32 (*_read_interrupt)(struct intf_hdl *pintfhdl, u32 addr);
+
+               u32 (*_read_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, struct recv_buf *rbuf);
+               u32 (*_write_port)(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, struct xmit_buf *pmem);
+
+               u32 (*_write_scsi)(struct intf_hdl *pintfhdl,u32 cnt, u8 *pmem);
+
+               void (*_read_port_cancel)(struct intf_hdl *pintfhdl);
+               void (*_write_port_cancel)(struct intf_hdl *pintfhdl);
+
+};
+
+struct io_req {
+       struct list_head        list;
+       u32     addr;
+       volatile u32    val;
+       u32     command;
+       u32     status;
+       u8      *pbuf;
+       struct semaphore        sema;
+
+       void (*_async_io_callback)(struct rtw_adapter *padater, struct io_req *pio_req, u8 *cnxt);
+       u8 *cnxt;
+};
+
+struct intf_hdl {
+       struct rtw_adapter *padapter;
+       struct dvobj_priv *pintf_dev;/*         pointer to &(padapter->dvobjpriv); */
+
+       struct _io_ops  io_ops;
+
+};
+
+struct reg_protocol_rd {
+
+#ifdef __LITTLE_ENDIAN
+
+       /* DW1 */
+       u32             NumOfTrans:4;
+       u32             Reserved1:4;
+       u32             Reserved2:24;
+       /* DW2 */
+       u32             ByteCount:7;
+       u32             WriteEnable:1;          /* 0:read, 1:write */
+       u32             FixOrContinuous:1;      /* 0:continuous, 1: Fix */
+       u32             BurstMode:1;
+       u32             Byte1Access:1;
+       u32             Byte2Access:1;
+       u32             Byte4Access:1;
+       u32             Reserved3:3;
+       u32             Reserved4:16;
+       /* DW3 */
+       u32             BusAddress;
+       /* DW4 */
+       /* u32          Value; */
+#else
+
+
+/* DW1 */
+       u32 Reserved1  :4;
+       u32 NumOfTrans :4;
+
+       u32 Reserved2  :24;
+
+       /* DW2 */
+       u32 WriteEnable : 1;
+       u32 ByteCount :7;
+
+
+       u32 Reserved3 : 3;
+       u32 Byte4Access : 1;
+
+       u32 Byte2Access : 1;
+       u32 Byte1Access : 1;
+       u32 BurstMode :1 ;
+       u32 FixOrContinuous : 1;
+
+       u32 Reserved4 : 16;
+
+       /* DW3 */
+       u32             BusAddress;
+
+       /* DW4 */
+       /* u32          Value; */
+
+#endif
+
+};
+
+
+struct reg_protocol_wt {
+
+
+#ifdef __LITTLE_ENDIAN
+
+       /* DW1 */
+       u32             NumOfTrans:4;
+       u32             Reserved1:4;
+       u32             Reserved2:24;
+       /* DW2 */
+       u32             ByteCount:7;
+       u32             WriteEnable:1;          /* 0:read, 1:write */
+       u32             FixOrContinuous:1;      /* 0:continuous, 1: Fix */
+       u32             BurstMode:1;
+       u32             Byte1Access:1;
+       u32             Byte2Access:1;
+       u32             Byte4Access:1;
+       u32             Reserved3:3;
+       u32             Reserved4:16;
+       /* DW3 */
+       u32             BusAddress;
+       /* DW4 */
+       u32             Value;
+
+#else
+       /* DW1 */
+       u32 Reserved1  :4;
+       u32 NumOfTrans :4;
+
+       u32 Reserved2  :24;
+
+       /* DW2 */
+       u32 WriteEnable : 1;
+       u32 ByteCount :7;
+
+       u32 Reserved3 : 3;
+       u32 Byte4Access : 1;
+
+       u32 Byte2Access : 1;
+       u32 Byte1Access : 1;
+       u32 BurstMode :1 ;
+       u32 FixOrContinuous : 1;
+
+       u32 Reserved4 : 16;
+
+       /* DW3 */
+       u32             BusAddress;
+
+       /* DW4 */
+       u32             Value;
+
+#endif
+
+};
+
+
+
+/*
+Below is the data structure used by _io_handler
+
+*/
+
+struct io_queue {
+       spinlock_t      lock;
+       struct list_head free_ioreqs;
+       struct list_head pending;               /* The io_req list that will be served in the single protocol read/write. */
+       struct list_head processing;
+       u8      *free_ioreqs_buf; /*  4-byte aligned */
+       u8      *pallocated_free_ioreqs_buf;
+       struct  intf_hdl        intf;
+};
+
+struct io_priv{
+
+       struct rtw_adapter *padapter;
+
+       struct intf_hdl intf;
+
+};
+
+uint ioreq_flush(struct rtw_adapter *adapter, struct io_queue *ioqueue);
+void sync_ioreq_enqueue(struct io_req *preq,struct io_queue *ioqueue);
+uint sync_ioreq_flush(struct rtw_adapter *adapter, struct io_queue *ioqueue);
+
+uint free_ioreq(struct io_req *preq, struct io_queue *pio_queue);
+struct io_req *alloc_ioreq(struct io_queue *pio_q);
+
+uint register_intf_hdl(u8 *dev, struct intf_hdl *pintfhdl);
+void unregister_intf_hdl(struct intf_hdl *pintfhdl);
+
+void _rtw_attrib_read(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void _rtw_attrib_write(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+
+u8 _rtw_read823a(struct rtw_adapter *adapter, u32 addr);
+u16 _rtw_read1623a(struct rtw_adapter *adapter, u32 addr);
+u32 _rtw_read3223a(struct rtw_adapter *adapter, u32 addr);
+void _rtw_read_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+void _rtw_read_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct recv_buf *rbuf);
+void _rtw_read_port23a_cancel(struct rtw_adapter *adapter);
+
+int _rtw_write823a(struct rtw_adapter *adapter, u32 addr, u8 val);
+int _rtw_write1623a(struct rtw_adapter *adapter, u32 addr, u16 val);
+int _rtw_write3223a(struct rtw_adapter *adapter, u32 addr, u32 val);
+int _rtw_writeN23a(struct rtw_adapter *adapter, u32 addr, u32 length, u8 *pdata);
+
+int _rtw_write823a_async23a(struct rtw_adapter *adapter, u32 addr, u8 val);
+int _rtw_write1623a_async(struct rtw_adapter *adapter, u32 addr, u16 val);
+int _rtw_write3223a_async23a(struct rtw_adapter *adapter, u32 addr, u32 val);
+
+void _rtw_write_mem23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
+u32 _rtw_write_port23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct xmit_buf *pmem);
+u32 _rtw_write_port23a_and_wait23a(struct rtw_adapter *adapter, u32 addr, u32 cnt, struct xmit_buf *pmem, int timeout_ms);
+void _rtw_write_port23a_cancel(struct rtw_adapter *adapter);
+
+#ifdef DBG_IO
+bool match_read_sniff_ranges(u16 addr, u16 len);
+bool match_write_sniff_ranges(u16 addr, u16 len);
+
+u8 dbg_rtw_read823a(struct rtw_adapter *adapter, u32 addr, const char *caller, const int line);
+u16 dbg_rtw_read1623a(struct rtw_adapter *adapter, u32 addr, const char *caller, const int line);
+u32 dbg_rtw_read3223a(struct rtw_adapter *adapter, u32 addr, const char *caller, const int line);
+
+int dbg_rtw_write823a(struct rtw_adapter *adapter, u32 addr, u8 val, const char *caller, const int line);
+int dbg_rtw_write1623a(struct rtw_adapter *adapter, u32 addr, u16 val, const char *caller, const int line);
+int dbg_rtw_write3223a(struct rtw_adapter *adapter, u32 addr, u32 val, const char *caller, const int line);
+int dbg_rtw_writeN23a(struct rtw_adapter *adapter, u32 addr ,u32 length , u8 *data, const char *caller, const int line);
+
+#define rtw_read8(adapter, addr) dbg_rtw_read823a((adapter), (addr), __FUNCTION__, __LINE__)
+#define rtw_read16(adapter, addr) dbg_rtw_read1623a((adapter), (addr), __FUNCTION__, __LINE__)
+#define rtw_read32(adapter, addr) dbg_rtw_read3223a((adapter), (addr), __FUNCTION__, __LINE__)
+#define rtw_read_mem(adapter, addr, cnt, mem) _rtw_read_mem23a((adapter), (addr), (cnt), (mem))
+#define rtw_read_port(adapter, addr, cnt, mem) _rtw_read_port23a((adapter), (addr), (cnt), (mem))
+#define rtw_read_port_cancel(adapter) _rtw_read_port23a_cancel((adapter))
+
+#define  rtw_write8(adapter, addr, val) dbg_rtw_write823a((adapter), (addr), (val), __FUNCTION__, __LINE__)
+#define  rtw_write16(adapter, addr, val) dbg_rtw_write1623a((adapter), (addr), (val), __FUNCTION__, __LINE__)
+#define  rtw_write32(adapter, addr, val) dbg_rtw_write3223a((adapter), (addr), (val), __FUNCTION__, __LINE__)
+#define  rtw_writeN(adapter, addr, length, data) dbg_rtw_writeN23a((adapter), (addr), (length), (data), __FUNCTION__, __LINE__)
+
+#define rtw_write8_async(adapter, addr, val) _rtw_write823a_async23a((adapter), (addr), (val))
+#define rtw_write16_async(adapter, addr, val) _rtw_write1623a_async((adapter), (addr), (val))
+#define rtw_write32_async(adapter, addr, val) _rtw_write3223a_async23a((adapter), (addr), (val))
+
+#define rtw_write_mem(adapter, addr, cnt, mem) _rtw_write_mem23a((adapter), addr, cnt, mem)
+#define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port23a(adapter, addr, cnt, mem)
+#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) _rtw_write_port23a_and_wait23a((adapter), (addr), (cnt), (mem), (timeout_ms))
+#define rtw_write_port_cancel(adapter) _rtw_write_port23a_cancel(adapter)
+#else /* DBG_IO */
+#define rtw_read8(adapter, addr) _rtw_read823a((adapter), (addr))
+#define rtw_read16(adapter, addr) _rtw_read1623a((adapter), (addr))
+#define rtw_read32(adapter, addr) _rtw_read3223a((adapter), (addr))
+#define rtw_read_mem(adapter, addr, cnt, mem) _rtw_read_mem23a((adapter), (addr), (cnt), (mem))
+#define rtw_read_port(adapter, addr, cnt, mem) _rtw_read_port23a((adapter), (addr), (cnt), (mem))
+#define rtw_read_port_cancel(adapter) _rtw_read_port23a_cancel((adapter))
+
+#define  rtw_write8(adapter, addr, val) _rtw_write823a((adapter), (addr), (val))
+#define  rtw_write16(adapter, addr, val) _rtw_write1623a((adapter), (addr), (val))
+#define  rtw_write32(adapter, addr, val) _rtw_write3223a((adapter), (addr), (val))
+#define  rtw_writeN(adapter, addr, length, data) _rtw_writeN23a((adapter), (addr), (length), (data))
+
+#define rtw_write8_async(adapter, addr, val) _rtw_write823a_async23a((adapter), (addr), (val))
+#define rtw_write16_async(adapter, addr, val) _rtw_write1623a_async((adapter), (addr), (val))
+#define rtw_write32_async(adapter, addr, val) _rtw_write3223a_async23a((adapter), (addr), (val))
+
+#define rtw_write_mem(adapter, addr, cnt, mem) _rtw_write_mem23a((adapter), (addr), (cnt), (mem))
+#define rtw_write_port(adapter, addr, cnt, mem) _rtw_write_port23a((adapter), (addr), (cnt), (mem))
+#define rtw_write_port_and_wait(adapter, addr, cnt, mem, timeout_ms) _rtw_write_port23a_and_wait23a((adapter), (addr), (cnt), (mem), (timeout_ms))
+#define rtw_write_port_cancel(adapter) _rtw_write_port23a_cancel((adapter))
+#endif /* DBG_IO */
+
+void rtw_write_scsi(struct rtw_adapter *adapter, u32 cnt, u8 *pmem);
+
+/* ioreq */
+void ioreq_read8(struct rtw_adapter *adapter, u32 addr, u8 *pval);
+void ioreq_read16(struct rtw_adapter *adapter, u32 addr, u16 *pval);
+void ioreq_read32(struct rtw_adapter *adapter, u32 addr, u32 *pval);
+void ioreq_write8(struct rtw_adapter *adapter, u32 addr, u8 val);
+void ioreq_write16(struct rtw_adapter *adapter, u32 addr, u16 val);
+void ioreq_write32(struct rtw_adapter *adapter, u32 addr, u32 val);
+
+int rtw_init_io_priv23a(struct rtw_adapter *padapter, void (*set_intf_ops)(struct _io_ops *pops));
+
+uint alloc_io_queue(struct rtw_adapter *adapter);
+void free_io_queue(struct rtw_adapter *adapter);
+void async_bus_io(struct io_queue *pio_q);
+void bus_sync_io(struct io_queue *pio_q);
+u32 _ioreq2rwmem(struct io_queue *pio_q);
+void dev_power_down(struct rtw_adapter * Adapter, u8 bpwrup);
+
+#define PlatformEFIOWrite1Byte(_a,_b,_c)               \
+       rtw_write8(_a,_b,_c)
+#define PlatformEFIOWrite2Byte(_a,_b,_c)               \
+       rtw_write16(_a,_b,_c)
+#define PlatformEFIOWrite4Byte(_a,_b,_c)               \
+       rtw_write32(_a,_b,_c)
+
+#define PlatformEFIORead1Byte(_a,_b)           \
+               rtw_read8(_a,_b)
+#define PlatformEFIORead2Byte(_a,_b)           \
+               rtw_read16(_a,_b)
+#define PlatformEFIORead4Byte(_a,_b)           \
+               rtw_read32(_a,_b)
+
+#endif /* _RTL8711_IO_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_ioctl.h b/drivers/staging/rtl8723au/include/rtw_ioctl.h
new file mode 100644 (file)
index 0000000..629eec8
--- /dev/null
@@ -0,0 +1,26 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef _RTW_IOCTL_H_
+#define _RTW_IOCTL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+#if defined(CONFIG_WIRELESS_EXT)
+extern struct iw_handler_def  rtw_handlers_def;
+#endif
+
+#endif /*  #ifndef __INC_CEINFO_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_ioctl_set.h b/drivers/staging/rtl8723au/include/rtw_ioctl_set.h
new file mode 100644 (file)
index 0000000..18ad2a8
--- /dev/null
@@ -0,0 +1,39 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTW_IOCTL_SET_H_
+#define __RTW_IOCTL_SET_H_
+
+#include <drv_types.h>
+
+
+struct bssid_info {
+       unsigned char  BSSID[6];
+       u8  PMKID[16];
+};
+
+u8 rtw_set_802_11_authentication_mode23a(struct rtw_adapter *pdapter,
+                                     enum ndis_802_11_auth_mode authmode);
+u8 rtw_set_802_11_add_wep23a(struct rtw_adapter * padapter,
+                         struct ndis_802_11_wep *wep);
+u8 rtw_set_802_11_bssid23a_list_scan(struct rtw_adapter *padapter,
+                                 struct cfg80211_ssid *pssid, int ssid_max_num);
+u8 rtw_set_802_11_infrastructure_mode23a(struct rtw_adapter *padapter,
+                                     enum ndis_802_11_net_infra networktype);
+u8 rtw_set_802_11_ssid23a(struct rtw_adapter * padapter, struct cfg80211_ssid * ssid);
+
+u16 rtw_get_cur_max_rate23a(struct rtw_adapter *adapter);
+s32 FillH2CCmd(struct rtw_adapter *padapter, u8 ElementID, u32 CmdLen, u8 *pCmdBuffer);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtw_led.h b/drivers/staging/rtl8723au/include/rtw_led.h
new file mode 100644 (file)
index 0000000..c071da5
--- /dev/null
@@ -0,0 +1,181 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTW_LED_H_
+#define __RTW_LED_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define MSECS(t)        (HZ * ((t) / 1000) + (HZ * ((t) % 1000)) / 1000)
+
+#define LED_BLINK_NORMAL_INTERVAL      100
+#define LED_BLINK_SLOWLY_INTERVAL      200
+#define LED_BLINK_LONG_INTERVAL        400
+
+#define LED_BLINK_NO_LINK_INTERVAL_ALPHA               1000
+#define LED_BLINK_LINK_INTERVAL_ALPHA                  500             /* 500 */
+#define LED_BLINK_SCAN_INTERVAL_ALPHA          180     /* 150 */
+#define LED_BLINK_FASTER_INTERVAL_ALPHA                50
+#define LED_BLINK_WPS_SUCESS_INTERVAL_ALPHA    5000
+
+#define LED_BLINK_NORMAL_INTERVAL_NETTRONIX  100
+#define LED_BLINK_SLOWLY_INTERVAL_NETTRONIX  2000
+
+#define LED_BLINK_SLOWLY_INTERVAL_PORNET 1000
+#define LED_BLINK_NORMAL_INTERVAL_PORNET 100
+
+#define LED_BLINK_FAST_INTERVAL_BITLAND 30
+
+/*  060403, rcnjko: Customized for AzWave. */
+#define LED_CM2_BLINK_ON_INTERVAL                      250
+#define LED_CM2_BLINK_OFF_INTERVAL             4750
+
+#define LED_CM8_BLINK_INTERVAL                 500             /* for QMI */
+#define LED_CM8_BLINK_OFF_INTERVAL     3750    /* for QMI */
+
+/*  080124, lanhsin: Customized for RunTop */
+#define LED_RunTop_BLINK_INTERVAL                      300
+
+/*  060421, rcnjko: Customized for Sercomm Printer Server case. */
+#define LED_CM3_BLINK_INTERVAL                         1500
+
+enum led_ctl_mode {
+       LED_CTL_POWER_ON = 1,
+       LED_CTL_LINK = 2,
+       LED_CTL_NO_LINK = 3,
+       LED_CTL_TX = 4,
+       LED_CTL_RX = 5,
+       LED_CTL_SITE_SURVEY = 6,
+       LED_CTL_POWER_OFF = 7,
+       LED_CTL_START_TO_LINK = 8,
+       LED_CTL_START_WPS = 9,
+       LED_CTL_STOP_WPS = 10,
+       LED_CTL_START_WPS_BOTTON = 11, /* added for runtop */
+       LED_CTL_STOP_WPS_FAIL = 12, /* added for ALPHA */
+       LED_CTL_STOP_WPS_FAIL_OVERLAP = 13, /* added for BELKIN */
+       LED_CTL_CONNECTION_NO_TRANSFER = 14,
+};
+
+enum led_state_872x {
+       LED_UNKNOWN = 0,
+       RTW_LED_ON = 1,
+       RTW_LED_OFF = 2,
+       LED_BLINK_NORMAL = 3,
+       LED_BLINK_SLOWLY = 4,
+       LED_BLINK_POWER_ON = 5,
+       LED_BLINK_SCAN = 6, /*  LED is blinking during scanning period, the # of times to blink is depend on time for scanning. */
+       LED_BLINK_NO_LINK = 7, /*  LED is blinking during no link state. */
+       LED_BLINK_StartToBlink = 8,/*  Customzied for Sercomm Printer Server case */
+       LED_BLINK_TXRX = 9,
+       LED_BLINK_WPS = 10,     /*  LED is blinkg during WPS communication */
+       LED_BLINK_WPS_STOP = 11,        /* for ALPHA */
+       LED_BLINK_WPS_STOP_OVERLAP = 12,        /* for BELKIN */
+       LED_BLINK_RUNTOP = 13, /*  Customized for RunTop */
+       LED_BLINK_CAMEO = 14,
+       LED_BLINK_XAVI = 15,
+       LED_BLINK_ALWAYS_ON = 16,
+};
+
+enum led_pin_8723a {
+       LED_PIN_NULL = 0,
+       LED_PIN_LED0 = 1,
+       LED_PIN_LED1 = 2,
+       LED_PIN_LED2 = 3,
+       LED_PIN_GPIO0 = 4,
+};
+
+struct led_8723a {
+       struct rtw_adapter                              *padapter;
+
+       enum led_pin_8723a              LedPin; /*  Identify how to implement this SW led. */
+       enum led_state_872x             CurrLedState; /*  Current LED state. */
+       enum led_state_872x             BlinkingLedState; /*  Next state for blinking, either RTW_LED_ON or RTW_LED_OFF are. */
+
+       u8                                      bLedOn; /*  true if LED is ON, false if LED is OFF. */
+
+       u8                                      bLedBlinkInProgress; /*  true if it is blinking, false o.w.. */
+
+       u8                                      bLedWPSBlinkInProgress;
+
+       u32                                     BlinkTimes; /*  Number of times to toggle led state for blinking. */
+
+       struct timer_list                       BlinkTimer; /*  Timer object for led blinking. */
+
+       u8                                      bSWLedCtrl;
+
+       /*  ALPHA, added by chiyoko, 20090106 */
+       u8                                      bLedNoLinkBlinkInProgress;
+       u8                                      bLedLinkBlinkInProgress;
+       u8                                      bLedStartToLinkBlinkInProgress;
+       u8                                      bLedScanBlinkInProgress;
+
+       struct work_struct                      BlinkWorkItem; /*  Workitem used by BlinkTimer to manipulate H/W to blink LED. */
+};
+
+#define IS_LED_WPS_BLINKING(_LED_871x) (((struct led_8723a *)_LED_871x)->CurrLedState==LED_BLINK_WPS \
+                                       || ((struct led_8723a *)_LED_871x)->CurrLedState==LED_BLINK_WPS_STOP \
+                                       || ((struct led_8723a *)_LED_871x)->bLedWPSBlinkInProgress)
+
+#define IS_LED_BLINKING(_LED_871x)     (((struct led_8723a *)_LED_871x)->bLedWPSBlinkInProgress \
+                                       ||((struct led_8723a *)_LED_871x)->bLedScanBlinkInProgress)
+
+/*  */
+/*  LED customization. */
+/*  */
+
+enum led_strategy_8723a {
+       SW_LED_MODE0 = 0, /*  SW control 1 LED via GPIO0. It is default option. */
+       SW_LED_MODE1= 1, /*  2 LEDs, through LED0 and LED1. For ALPHA. */
+       SW_LED_MODE2 = 2, /*  SW control 1 LED via GPIO0, customized for AzWave 8187 minicard. */
+       SW_LED_MODE3 = 3, /*  SW control 1 LED via GPIO0, customized for Sercomm Printer Server case. */
+       SW_LED_MODE4 = 4, /* for Edimax / Belkin */
+       SW_LED_MODE5 = 5, /* for Sercomm / Belkin */
+       SW_LED_MODE6 = 6, /* for 88CU minicard, porting from ce SW_LED_MODE7 */
+       HW_LED = 50, /*  HW control 2 LEDs, LED0 and LED1 (there are 4 different control modes, see MAC.CONFIG1 for details.) */
+       LED_ST_NONE = 99,
+};
+
+void LedControl871x23a(struct rtw_adapter *padapter, enum led_ctl_mode LedAction);
+
+struct led_priv{
+       /* add for led controll */
+       struct led_8723a                        SwLed0;
+       struct led_8723a                        SwLed1;
+       enum led_strategy_8723a LedStrategy;
+       u8                                      bRegUseLed;
+       void (*LedControlHandler)(struct rtw_adapter *padapter, enum led_ctl_mode LedAction);
+       /* add for led controll */
+};
+
+#define rtw_led_control(adapter, LedAction)
+
+void BlinkWorkItemCallback23a(struct work_struct *work);
+
+void ResetLedStatus23a(struct led_8723a *pLed);
+
+void
+InitLed871x23a(
+       struct rtw_adapter *padapter,
+       struct led_8723a *pLed,
+       enum led_pin_8723a      LedPin
+);
+
+void
+DeInitLed871x23a(struct led_8723a *pLed);
+
+/* hal... */
+void BlinkHandler23a(struct led_8723a *pLed);
+
+#endif /* __RTW_LED_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_mlme.h b/drivers/staging/rtl8723au/include/rtw_mlme.h
new file mode 100644 (file)
index 0000000..31f96f3
--- /dev/null
@@ -0,0 +1,624 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ *
+ ******************************************************************************/
+#ifndef __RTW_MLME_H_
+#define __RTW_MLME_H_
+
+#include <osdep_service.h>
+#include <mlme_osdep.h>
+#include <drv_types.h>
+#include <wlan_bssdef.h>
+
+#define        MAX_BSS_CNT     128
+#define   MAX_JOIN_TIMEOUT     6500
+
+/* Increase the scanning timeout because of increasing the SURVEY_TO value. */
+
+#define        SCANNING_TIMEOUT        8000
+
+#define        SCAN_INTERVAL   (30) /*  unit:2sec, 30*2 = 60sec */
+
+#define        SCANQUEUE_LIFETIME 20 /*  unit:sec */
+
+#define        WIFI_NULL_STATE         0x00000000
+
+#define        WIFI_ASOC_STATE         0x00000001 /*  Under Linked state.*/
+#define        WIFI_REASOC_STATE       0x00000002
+#define        WIFI_SLEEP_STATE        0x00000004
+#define        WIFI_STATION_STATE      0x00000008
+
+#define        WIFI_AP_STATE           0x00000010
+#define        WIFI_ADHOC_STATE        0x00000020
+#define   WIFI_ADHOC_MASTER_STATE      0x00000040
+#define   WIFI_UNDER_LINKING   0x00000080
+
+#define        WIFI_UNDER_WPS          0x00000100
+#define        WIFI_STA_ALIVE_CHK_STATE        0x00000400
+/* to indicate the station is under site surveying */
+#define        WIFI_SITE_MONITOR       0x00000800
+
+#define        WIFI_MP_STATE           0x00010000
+#define        WIFI_MP_CTX_BACKGROUND  0x00020000      /*  in continous tx background */
+#define        WIFI_MP_CTX_ST          0x00040000      /*  in continous tx with single-tone */
+#define        WIFI_MP_CTX_BACKGROUND_PENDING  0x00080000      /*  pending in continous tx background due to out of skb */
+#define        WIFI_MP_CTX_CCK_HW      0x00100000      /*  in continous tx */
+#define        WIFI_MP_CTX_CCK_CS      0x00200000      /*  in continous tx with carrier suppression */
+#define   WIFI_MP_LPBK_STATE   0x00400000
+
+#define _FW_UNDER_LINKING      WIFI_UNDER_LINKING
+#define _FW_LINKED             WIFI_ASOC_STATE
+#define _FW_UNDER_SURVEY       WIFI_SITE_MONITOR
+
+
+enum dot11AuthAlgrthmNum {
+       dot11AuthAlgrthm_Open = 0,
+       dot11AuthAlgrthm_Shared,
+       dot11AuthAlgrthm_8021X,
+       dot11AuthAlgrthm_Auto,
+       dot11AuthAlgrthm_MaxNum
+};
+
+/*  Scan type including active and passive scan. */
+enum rt_scan_type {
+       SCAN_PASSIVE,
+       SCAN_ACTIVE,
+       SCAN_MIX,
+};
+
+enum {
+       GHZ24_50 = 0,
+       GHZ_50,
+       GHZ_24,
+};
+
+enum SCAN_RESULT_TYPE {
+       SCAN_RESULT_P2P_ONLY = 0,       /*      Will return all the P2P devices. */
+       SCAN_RESULT_ALL = 1,            /*      Will return all the scanned device, include AP. */
+       SCAN_RESULT_WFD_TYPE = 2        /*      Will just return the correct WFD device. */
+                                       /*      If this device is Miracast sink device, it will just return all the Miracast source devices. */
+};
+
+/*
+
+there are several "locks" in mlme_priv,
+since mlme_priv is a shared resource between many threads,
+like ISR/Call-Back functions, the OID handlers, and even timer functions.
+
+
+Each _queue has its own locks, already.
+Other items are protected by mlme_priv.lock.
+
+To avoid possible dead lock, any thread trying to modifiying mlme_priv
+SHALL not lock up more than one locks at a time!
+*/
+
+#define traffic_threshold      10
+#define        traffic_scan_period     500
+
+struct sitesurvey_ctrl {
+       u64     last_tx_pkts;
+       uint    last_rx_pkts;
+       int     traffic_busy;
+       struct timer_list       sitesurvey_ctrl_timer;
+};
+
+struct rt_link_detect {
+       u32     NumTxOkInPeriod;
+       u32     NumRxOkInPeriod;
+       u32     NumRxUnicastOkInPeriod;
+       bool    bBusyTraffic;
+       bool    bTxBusyTraffic;
+       bool    bRxBusyTraffic;
+       bool    bHigherBusyTraffic; /*  For interrupt migration purpose. */
+       bool    bHigherBusyRxTraffic; /*  We may disable Tx interrupt according as Rx traffic. */
+       bool    bHigherBusyTxTraffic; /*  We may disable Tx interrupt according as Tx traffic. */
+};
+
+struct profile_info {
+       u8      ssidlen;
+       u8      ssid[IEEE80211_MAX_SSID_LEN];
+       u8      peermac[ETH_ALEN];
+};
+
+struct tx_invite_req_info {
+       u8      token;
+       u8      benable;
+       u8      go_ssid[IEEE80211_MAX_SSID_LEN];
+       u8      ssidlen;
+       u8      go_bssid[ETH_ALEN];
+       u8      peer_macaddr[ETH_ALEN];
+       u8      operating_ch;   /* This information will be set by using the p2p_set op_ch = x */
+       u8      peer_ch;        /* The listen channel for peer P2P device */
+
+};
+
+struct tx_invite_resp_info {
+       u8      token;  /*      Used to record the dialog token of p2p invitation request frame. */
+};
+
+#ifdef CONFIG_8723AU_P2P
+
+struct wifi_display_info {
+       u16     wfd_enable;             /* Enable/Disable the WFD function. */
+       u16     rtsp_ctrlport;          /* TCP port number at which the this WFD device listens for RTSP messages */
+       u16     peer_rtsp_ctrlport;     /* TCP port number at which the peer WFD device listens for RTSP messages */
+                                       /* This filed should be filled when receiving the gropu negotiation request */
+
+       u8      peer_session_avail;     /* WFD session is available or not for the peer wfd device. */
+                                       /* This variable will be set when sending the provisioning discovery request to peer WFD device. */
+                                       /* And this variable will be reset when it is read by using the iwpriv p2p_get wfd_sa command. */
+       u8      ip_address[4];
+       u8      peer_ip_address[4];
+       u8      wfd_pc;         /* WFD preferred connection */
+                               /* 0 -> Prefer to use the P2P for WFD connection on peer side. */
+                               /* 1 -> Prefer to use the TDLS for WFD connection on peer side. */
+
+       u8      wfd_device_type;/* WFD Device Type */
+                               /* 0 -> WFD Source Device */
+                               /* 1 -> WFD Primary Sink Device */
+       enum    SCAN_RESULT_TYPE scan_result_type;      /* Used when P2P is enable. This parameter will impact the scan result. */
+};
+#endif /* CONFIG_8723AU_P2P */
+
+struct tx_provdisc_req_info {
+       u16     wps_config_method_request;      /* Used when sending the provisioning request frame */
+       u16     peer_channel_num[2];            /* The channel number which the receiver stands. */
+       struct  cfg80211_ssid ssid;
+       u8      peerDevAddr[ETH_ALEN];  /* Peer device address */
+       u8      peerIFAddr[ETH_ALEN];           /* Peer interface address */
+       u8      benable;                        /* This provision discovery request frame is trigger to send or not */
+};
+
+struct rx_provdisc_req_info {  /* When peer device issue prov_disc_req first, we should store the following informations */
+       u8      peerDevAddr[ETH_ALEN];          /*      Peer device address */
+       u8      strconfig_method_desc_of_prov_disc_req[4];      /*      description for the config method located in the provisioning discovery request frame. */
+                                                                                                                                       /*      The UI must know this information to know which config method the remote p2p device is requiring. */
+};
+
+struct tx_nego_req_info {
+       u16     peer_channel_num[2];    /* The channel number which the receiver stands. */
+       u8      peerDevAddr[ETH_ALEN];/* Peer device address */
+       u8      benable;                /* This negoitation request frame is trigger to send or not */
+};
+
+struct group_id_info {
+       u8 go_device_addr[ETH_ALEN]; /*The GO's device address of P2P group */
+       u8 ssid[IEEE80211_MAX_SSID_LEN]; /* The SSID of this P2P group */
+};
+
+struct scan_limit_info {
+       u8      scan_op_ch_only;        /* When this flag is set, the driver should just scan the operation channel */
+       u8      operation_ch[2];        /* Store the operation channel of invitation request frame */
+};
+
+struct cfg80211_wifidirect_info {
+       struct timer_list               remain_on_ch_timer;
+       u8              restore_channel;
+       struct ieee80211_channel        remain_on_ch_channel;
+       enum nl80211_channel_type       remain_on_ch_type;
+       u64     remain_on_ch_cookie;
+       bool is_ro_ch;
+};
+
+struct wifidirect_info {
+       struct rtw_adapter      *padapter;
+       struct timer_list       find_phase_timer;
+       struct timer_list       restore_p2p_state_timer;
+
+       /*      Used to do the scanning. After confirming the peer is availalble, the driver transmits the P2P frame to peer. */
+       struct timer_list       pre_tx_scan_timer;
+       struct timer_list       reset_ch_sitesurvey;
+       struct timer_list       reset_ch_sitesurvey2;   /*      Just for resetting the scan limit function by using p2p nego */
+       struct tx_provdisc_req_info     tx_prov_disc_info;
+       struct rx_provdisc_req_info rx_prov_disc_info;
+       struct tx_invite_req_info       invitereq_info;
+       struct profile_info     profileinfo[P2P_MAX_PERSISTENT_GROUP_NUM];      /*      Store the profile information of persistent group */
+       struct tx_invite_resp_info      inviteresp_info;
+       struct tx_nego_req_info nego_req_info;
+       struct group_id_info    groupid_info;   /*      Store the group id information when doing the group negotiation handshake. */
+       struct scan_limit_info  rx_invitereq_info;      /*      Used for get the limit scan channel from the Invitation procedure */
+       struct scan_limit_info  p2p_info;               /*      Used for get the limit scan channel from the P2P negotiation handshake */
+#ifdef CONFIG_8723AU_P2P
+       struct wifi_display_info        *wfd_info;
+#endif
+       enum P2P_ROLE   role;
+       enum P2P_STATE  pre_p2p_state;
+       enum P2P_STATE  p2p_state;
+       u8      device_addr[ETH_ALEN];  /*      The device address should be the mac address of this device. */
+       u8      interface_addr[ETH_ALEN];
+       u8      social_chan[4];
+       u8      listen_channel;
+       u8      operating_channel;
+       u8      listen_dwell;           /*      This value should be between 1 and 3 */
+       u8      support_rate[8];
+       u8      p2p_wildcard_ssid[P2P_WILDCARD_SSID_LEN];
+       u8      intent;         /*      should only include the intent value. */
+       u8      p2p_peer_interface_addr[ETH_ALEN];
+       u8      p2p_peer_device_addr[ETH_ALEN];
+       u8      peer_intent;    /*      Included the intent value and tie breaker value. */
+       u8      device_name[WPS_MAX_DEVICE_NAME_LEN];   /*      Device name for displaying on searching device screen */
+       u8      device_name_len;
+       u8      profileindex;   /*      Used to point to the index of profileinfo array */
+       u8      peer_operating_ch;
+       u8      find_phase_state_exchange_cnt;
+       u16     device_password_id_for_nego;    /*      The device password ID for group negotation */
+       u8      negotiation_dialog_token;
+       /*      SSID information for group negotitation */
+       u8 nego_ssid[IEEE80211_MAX_SSID_LEN];
+       u8 nego_ssidlen;
+       u8 p2p_group_ssid[IEEE80211_MAX_SSID_LEN];
+       u8 p2p_group_ssid_len;
+       u8      persistent_supported;   /*      Flag to know the persistent function should be supported or not. */
+                                       /*      In the Sigma test, the Sigma will provide this enable from the sta_set_p2p CAPI. */
+                                       /*      0: disable */
+                                       /*      1: enable */
+       u8      session_available;      /*      Flag to set the WFD session available to enable or disable "by Sigma" */
+                                       /*      In the Sigma test, the Sigma will disable the session available by using the sta_preset CAPI. */
+                                       /*      0: disable */
+                                       /*      1: enable */
+
+       u8      wfd_tdls_enable;        /*      Flag to enable or disable the TDLS by WFD Sigma */
+                                       /*      0: disable */
+                                       /*      1: enable */
+       u8      wfd_tdls_weaksec;       /*      Flag to enable or disable the weak security function for TDLS by WFD Sigma */
+                               /*      0: disable */
+                               /*      In this case, the driver can't issue the tdsl setup request frame. */
+                               /*      1: enable */
+                               /*      In this case, the driver can issue the tdls setup request frame */
+                               /*      even the current security is weak security. */
+
+       enum    P2P_WPSINFO             ui_got_wps_info;                        /*      This field will store the WPS value (PIN value or PBC) that UI had got from the user. */
+       u16     supported_wps_cm;                       /*      This field describes the WPS config method which this driver supported. */
+                                                                                                               /*      The value should be the combination of config method defined in page104 of WPS v2.0 spec. */
+       uint    channel_list_attr_len;          /*      This field will contain the length of body of P2P Channel List attribute of group negotitation response frame. */
+       u8      channel_list_attr[100];         /*      This field will contain the body of P2P Channel List attribute of group negotitation response frame. */
+                                                                                                               /*      We will use the channel_cnt and channel_list fields when constructing the group negotitation confirm frame. */
+#ifdef CONFIG_8723AU_P2P
+       enum P2P_PS_MODE        p2p_ps_mode; /*  indicate p2p ps mode */
+       enum P2P_PS_STATE       p2p_ps_state; /*  indicate p2p ps state */
+       u8      noa_index; /*  Identifies and instance of Notice of Absence timing. */
+       u8      ctwindow; /*  Client traffic window. A period of time in TU after TBTT. */
+       u8      opp_ps; /*  opportunistic power save. */
+       u8      noa_num; /*  number of NoA descriptor in P2P IE. */
+       u8      noa_count[P2P_MAX_NOA_NUM]; /*  Count for owner, Type of client. */
+       u32     noa_duration[P2P_MAX_NOA_NUM]; /*  Max duration for owner, preferred or min acceptable duration for client. */
+       u32     noa_interval[P2P_MAX_NOA_NUM]; /*  Length of interval for owner, preferred or max acceptable interval of client. */
+       u32     noa_start_time[P2P_MAX_NOA_NUM]; /*  schedule expressed in terms of the lower 4 bytes of the TSF timer. */
+#endif /*  CONFIG_8723AU_P2P */
+};
+
+struct tdls_ss_record {        /* signal strength record */
+       u8      macaddr[ETH_ALEN];
+       u8      RxPWDBAll;
+       u8      is_tdls_sta;    /*  true: direct link sta, false: else */
+};
+
+struct tdls_info {
+       u8      ap_prohibited;
+       uint    setup_state;
+       u8      sta_cnt;
+       /* 1:tdls sta == (NUM_STA-1), reach max direct link no; 0: else; */
+       u8      sta_maximum;
+       struct tdls_ss_record   ss_record;
+       u8      macid_index;    /* macid entry that is ready to write */
+       /* cam entry that is trying to clear, using it in direct link teardown*/
+       u8      clear_cam;
+       u8      ch_sensing;
+       u8      cur_channel;
+       u8      candidate_ch;
+       u8      collect_pkt_num[MAX_CHANNEL_NUM];
+       spinlock_t      cmd_lock;
+       spinlock_t      hdl_lock;
+       u8      watchdog_count;
+       u8      dev_discovered;         /* WFD_TDLS: for sigma test */
+       u8      enable;
+#ifdef CONFIG_8723AU_P2P
+       struct wifi_display_info                *wfd_info;
+#endif
+};
+
+struct mlme_priv {
+       spinlock_t      lock;
+       int     fw_state;
+       u8 bScanInProcess;
+       u8      to_join; /* flag */
+       u8 to_roaming; /*  roaming trying times */
+
+       struct rtw_adapter *nic_hdl;
+
+       u8      not_indic_disco;
+       struct rtw_queue        scanned_queue;
+
+       struct cfg80211_ssid assoc_ssid;
+       u8      assoc_bssid[6];
+
+       struct wlan_network     cur_network;
+
+       /* uint wireless_mode; no used, remove it */
+
+       u32     scan_interval;
+
+       struct timer_list assoc_timer;
+
+       uint assoc_by_bssid;
+       uint assoc_by_rssi;
+
+       struct timer_list scan_to_timer;
+
+       struct timer_list set_scan_deny_timer;
+       atomic_t set_scan_deny; /* 0: allowed, 1: deny */
+
+       struct qos_priv qospriv;
+
+       /* Number of non-HT AP/stations */
+       int num_sta_no_ht;
+
+       int num_FortyMHzIntolerant;
+
+       struct ht_priv  htpriv;
+
+       struct rt_link_detect LinkDetectInfo;
+       struct timer_list dynamic_chk_timer; /* dynamic/periodic check timer */
+
+       u8      key_mask; /* use for ips to set wep key after ips_leave23a */
+       u8      acm_mask; /*  for wmm acm mask */
+       u8      ChannelPlan;
+       enum rt_scan_type scan_mode; /*  active: 1, passive: 0 */
+
+       u8 *wps_probe_req_ie;
+       u32 wps_probe_req_ie_len;
+       u8 *assoc_req;
+       u32 assoc_req_len;
+       u32 assoc_rsp_len;
+       u8 *assoc_rsp;
+       u32 wps_assoc_resp_ie_len;
+       u8 *wps_assoc_resp_ie;
+       u8 *wps_probe_resp_ie;
+       u32 wps_probe_resp_ie_len;
+       u8 *wps_beacon_ie;
+       u32 wps_beacon_ie_len;
+       u32 p2p_go_probe_resp_ie_len; /* for GO */
+       u32 p2p_assoc_req_ie_len;
+       u8 *p2p_beacon_ie;
+       u8 *p2p_probe_req_ie;
+       u8 *p2p_probe_resp_ie;
+       u8 *p2p_go_probe_resp_ie; /* for GO */
+       u8 *p2p_assoc_req_ie;
+       u32 p2p_beacon_ie_len;
+       u32 p2p_probe_req_ie_len;
+       u32 p2p_probe_resp_ie_len;
+       u8 *wfd_assoc_req_ie;
+       u32 wfd_assoc_req_ie_len;
+
+#ifdef CONFIG_8723AU_AP_MODE
+       /* Number of associated Non-ERP stations (i.e., stations using 802.11b
+        * in 802.11g BSS) */
+       int num_sta_non_erp;
+
+       /* Number of associated stations that do not support Short Slot Time */
+       int num_sta_no_short_slot_time;
+
+       /* Number of associated stations that do not support Short Preamble */
+       int num_sta_no_short_preamble;
+
+       int olbc; /* Overlapping Legacy BSS Condition */
+
+       /* Number of HT associated stations that do not support greenfield */
+       int num_sta_ht_no_gf;
+
+       /* Number of associated non-HT stations */
+       /* int num_sta_no_ht; */
+
+       /* Number of HT associated stations 20 MHz */
+       int num_sta_ht_20mhz;
+
+       /* Overlapping BSS information */
+       int olbc_ht;
+
+       u16 ht_op_mode;
+
+       spinlock_t      bcn_update_lock;
+       u8              update_bcn;
+
+#endif /* ifdef CONFIG_8723AU_AP_MODE */
+
+       u8 *wfd_beacon_ie;
+       u8 *wfd_probe_req_ie;
+       u8 *wfd_probe_resp_ie;
+       u8 *wfd_go_probe_resp_ie; /* for GO */
+
+       u32 wfd_beacon_ie_len;
+       u32 wfd_probe_req_ie_len;
+       u32 wfd_probe_resp_ie_len;
+       u32 wfd_go_probe_resp_ie_len; /* for GO */
+};
+
+#ifdef CONFIG_8723AU_AP_MODE
+
+struct hostapd_priv {
+       struct rtw_adapter *padapter;
+};
+
+int hostapd_mode_init(struct rtw_adapter *padapter);
+void hostapd_mode_unload(struct rtw_adapter *padapter);
+#endif
+
+void rtw_joinbss_event_prehandle23a(struct rtw_adapter *adapter, u8 *pbuf);
+void rtw_survey_event_cb23a(struct rtw_adapter *adapter, u8 *pbuf);
+void rtw_surveydone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf);
+void rtw23a_joinbss_event_cb(struct rtw_adapter *adapter, u8 *pbuf);
+void rtw_stassoc_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf);
+void rtw_stadel_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf);
+void rtw_atimdone_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf);
+void rtw_cpwm_event_callback23a(struct rtw_adapter *adapter, u8 *pbuf);
+
+
+int event_thread(void *context);
+void rtw23a_join_to_handler(unsigned long);
+
+void rtw_free_network_queue23a(struct rtw_adapter *adapter, u8 isfreeall);
+int rtw_init_mlme_priv23a(struct rtw_adapter *adapter);
+
+void rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv);
+
+int rtw_select_and_join_from_scanned_queue23a(struct mlme_priv *pmlmepriv);
+int rtw_set_key23a(struct rtw_adapter *adapter,
+               struct security_priv *psecuritypriv, int keyid, u8 set_tx);
+int rtw_set_auth23a(struct rtw_adapter *adapter,
+                struct security_priv *psecuritypriv);
+
+static inline u8 *get_bssid(struct mlme_priv *pmlmepriv)
+{      /* if sta_mode:pmlmepriv->cur_network.network.MacAddress => bssid */
+       /*  if adhoc_mode:pmlmepriv->cur_network.network.MacAddress => ibss mac address */
+       return pmlmepriv->cur_network.network.MacAddress;
+}
+
+static inline int check_fwstate(struct mlme_priv *pmlmepriv, int state)
+{
+       if (pmlmepriv->fw_state & state)
+               return true;
+
+       return false;
+}
+
+static inline int get_fwstate(struct mlme_priv *pmlmepriv)
+{
+       return pmlmepriv->fw_state;
+}
+
+/*
+ * No Limit on the calling context,
+ * therefore set it to be the critical section...
+ *
+ * ### NOTE:#### (!!!!)
+ * MUST TAKE CARE THAT BEFORE CALLING THIS FUNC, YOU SHOULD HAVE LOCKED pmlmepriv->lock
+ */
+static inline void set_fwstate(struct mlme_priv *pmlmepriv, int state)
+{
+       pmlmepriv->fw_state |= state;
+       /* FOR HW integration */
+       if (_FW_UNDER_SURVEY == state)
+               pmlmepriv->bScanInProcess = true;
+}
+
+static inline void _clr_fwstate_(struct mlme_priv *pmlmepriv, int state)
+{
+       pmlmepriv->fw_state &= ~state;
+       /* FOR HW integration */
+       if (_FW_UNDER_SURVEY == state)
+               pmlmepriv->bScanInProcess = false;
+}
+
+/*
+ * No Limit on the calling context,
+ * therefore set it to be the critical section...
+ */
+static inline void clr_fwstate(struct mlme_priv *pmlmepriv, int state)
+{
+       spin_lock_bh(&pmlmepriv->lock);
+       if (check_fwstate(pmlmepriv, state) == true)
+               pmlmepriv->fw_state ^= state;
+       spin_unlock_bh(&pmlmepriv->lock);
+}
+
+static inline void clr_fwstate_ex(struct mlme_priv *pmlmepriv, int state)
+{
+       spin_lock_bh(&pmlmepriv->lock);
+       _clr_fwstate_(pmlmepriv, state);
+       spin_unlock_bh(&pmlmepriv->lock);
+}
+
+u16 rtw_get_capability23a(struct wlan_bssid_ex *bss);
+void rtw_update_scanned_network23a(struct rtw_adapter *adapter,
+                               struct wlan_bssid_ex *target);
+void rtw_disconnect_hdl23a_under_linked(struct rtw_adapter *adapter,
+                                    struct sta_info *psta, u8 free_assoc);
+void rtw_generate_random_ibss23a(u8 *pibss);
+struct wlan_network *rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr);
+struct wlan_network *rtw_get_oldest_wlan_network23a(struct rtw_queue *scanned_queue);
+
+void rtw_free_assoc_resources23a(struct rtw_adapter *adapter,
+                             int lock_scanned_queue);
+void rtw_indicate_disconnect23a(struct rtw_adapter *adapter);
+void rtw_indicate_connect23a(struct rtw_adapter *adapter);
+void rtw_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted);
+void rtw_scan_abort23a(struct rtw_adapter *adapter);
+
+int rtw_restruct_sec_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie,
+                       uint in_len);
+int rtw_restruct_wmm_ie23a(struct rtw_adapter *adapter, u8 *in_ie, u8 *out_ie,
+                       uint in_len, uint initial_out_len);
+void rtw_init_registrypriv_dev_network23a(struct rtw_adapter *adapter);
+
+void rtw_update_registrypriv_dev_network23a(struct rtw_adapter *adapter);
+
+void rtw_get_encrypt_decrypt_from_registrypriv23a(struct rtw_adapter *adapter);
+
+void rtw_scan_timeout_handler23a(unsigned long data);
+
+void rtw_dynamic_check_timer_handler(unsigned long data);
+bool rtw_is_scan_deny(struct rtw_adapter *adapter);
+void rtw_clear_scan_deny(struct rtw_adapter *adapter);
+void rtw_set_scan_deny_timer_hdl(unsigned long data);
+void rtw_set_scan_deny(struct rtw_adapter *adapter, u32 ms);
+
+int _rtw_init_mlme_priv23a(struct rtw_adapter *padapter);
+
+void rtw23a_free_mlme_priv_ie_data(struct mlme_priv *pmlmepriv);
+
+void _rtw_free_mlme_priv23a(struct mlme_priv *pmlmepriv);
+
+struct wlan_network *rtw_alloc_network(struct mlme_priv *pmlmepriv);
+
+void _rtw_free_network23a(struct mlme_priv *pmlmepriv,
+                      struct wlan_network *pnetwork, u8 isfreeall);
+void _rtw_free_network23a_nolock23a(struct mlme_priv *pmlmepriv,
+                             struct wlan_network *pnetwork);
+
+struct wlan_network *_rtw_find_network23a(struct rtw_queue *scanned_queue, u8 *addr);
+
+void _rtw_free_network23a_queue23a(struct rtw_adapter *padapter, u8 isfreeall);
+
+int rtw_if_up23a(struct rtw_adapter *padapter);
+
+int rtw_linked_check(struct rtw_adapter *padapter);
+
+u8 *rtw_get_capability23a_from_ie(u8 *ie);
+u8 *rtw_get_timestampe_from_ie23a(u8 *ie);
+u8 *rtw_get_beacon_interval23a_from_ie(u8 *ie);
+
+
+void rtw_joinbss_reset23a(struct rtw_adapter *padapter);
+
+unsigned int rtw_restructure_ht_ie23a(struct rtw_adapter *padapter, u8 *in_ie,
+                                  u8 *out_ie, uint in_len, uint *pout_len);
+void rtw_update_ht_cap23a(struct rtw_adapter *padapter,
+                      u8 *pie, uint ie_len);
+void rtw_issue_addbareq_cmd23a(struct rtw_adapter *padapter,
+                           struct xmit_frame *pxmitframe);
+
+int rtw_is_same_ibss23a(struct rtw_adapter *adapter,
+                    struct wlan_network *pnetwork);
+int is_same_network23a(struct wlan_bssid_ex *src, struct wlan_bssid_ex *dst);
+
+void _rtw23a_roaming(struct rtw_adapter *adapter,
+                 struct wlan_network *tgt_network);
+void rtw23a_roaming(struct rtw_adapter *adapter,
+                struct wlan_network *tgt_network);
+void rtw_set_roaming(struct rtw_adapter *adapter, u8 to_roaming);
+u8 rtw_to_roaming(struct rtw_adapter *adapter);
+void rtw_stassoc_hw_rpt23a(struct rtw_adapter *adapter, struct sta_info *psta);
+
+#endif /* __RTL871X_MLME_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h
new file mode 100644 (file)
index 0000000..0aaf0d5
--- /dev/null
@@ -0,0 +1,780 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTW_MLME_EXT_H_
+#define __RTW_MLME_EXT_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wlan_bssdef.h>
+
+
+/*     Commented by Albert 20101105 */
+/*     Increase the SURVEY_TO value from 100 to 150  ( 100ms to 150ms ) */
+/*     The Realtek 8188CE SoftAP will spend around 100ms to send the probe response after receiving the probe request. */
+/*     So, this driver tried to extend the dwell time for each scanning channel. */
+/*     This will increase the chance to receive the probe response from SoftAP. */
+
+#define SURVEY_TO              (100)
+#define REAUTH_TO              (300) /* 50) */
+#define REASSOC_TO             (300) /* 50) */
+/* define DISCONNECT_TO        (3000) */
+#define ADDBA_TO                       (2000)
+
+#define LINKED_TO (1) /* unit:2 sec, 1x2=2 sec */
+
+#define REAUTH_LIMIT   (4)
+#define REASSOC_LIMIT  (4)
+#define READDBA_LIMIT  (2)
+
+#define ROAMING_LIMIT  8
+
+#define        DYNAMIC_FUNC_DISABLE                    (0x0)
+
+/*  ====== enum odm_ability ======== */
+/*  BB ODM section BIT 0-15 */
+#define        DYNAMIC_BB_DIG                          BIT(0)
+#define        DYNAMIC_BB_RA_MASK                      BIT(1)
+#define        DYNAMIC_BB_DYNAMIC_TXPWR        BIT(2)
+#define        DYNAMIC_BB_BB_FA_CNT                    BIT(3)
+
+#define                DYNAMIC_BB_RSSI_MONITOR         BIT(4)
+#define                DYNAMIC_BB_CCK_PD                       BIT(5)
+#define                DYNAMIC_BB_ANT_DIV                      BIT(6)
+#define                DYNAMIC_BB_PWR_SAVE                     BIT(7)
+#define                DYNAMIC_BB_PWR_TRAIN                    BIT(8)
+#define                DYNAMIC_BB_RATE_ADAPTIVE                BIT(9)
+#define                DYNAMIC_BB_PATH_DIV                     BIT(10)
+#define                DYNAMIC_BB_PSD                          BIT(11)
+
+/*  MAC DM section BIT 16-23 */
+#define                DYNAMIC_MAC_struct edca_turboURBO               BIT(16)
+#define                DYNAMIC_MAC_EARLY_MODE          BIT(17)
+
+/*  RF ODM section BIT 24-31 */
+#define                DYNAMIC_RF_TX_PWR_TRACK         BIT(24)
+#define                DYNAMIC_RF_RX_GAIN_TRACK                BIT(25)
+#define                DYNAMIC_RF_CALIBRATION          BIT(26)
+
+#define                DYNAMIC_ALL_FUNC_ENABLE         0xFFFFFFF
+
+#define _HW_STATE_NOLINK_              0x00
+#define _HW_STATE_ADHOC_               0x01
+#define _HW_STATE_STATION_     0x02
+#define _HW_STATE_AP_                  0x03
+
+
+#define                _1M_RATE_       0
+#define                _2M_RATE_       1
+#define                _5M_RATE_       2
+#define                _11M_RATE_      3
+#define                _6M_RATE_       4
+#define                _9M_RATE_       5
+#define                _12M_RATE_      6
+#define                _18M_RATE_      7
+#define                _24M_RATE_      8
+#define                _36M_RATE_      9
+#define                _48M_RATE_      10
+#define                _54M_RATE_      11
+
+
+extern unsigned char RTW_WPA_OUI23A[];
+extern unsigned char WMM_OUI23A[];
+extern unsigned char WPS_OUI23A[];
+extern unsigned char WFD_OUI23A[];
+extern unsigned char P2P_OUI23A[];
+
+extern unsigned char WMM_INFO_OUI23A[];
+extern unsigned char WMM_PARA_OUI23A[];
+
+
+/*  */
+/*  Channel Plan Type. */
+/*  Note: */
+/*     We just add new channel plan when the new channel plan is different from any of the following */
+/*     channel plan. */
+/*     If you just wnat to customize the acitions(scan period or join actions) about one of the channel plan, */
+/*     customize them in struct rt_channel_info in the RT_CHANNEL_LIST. */
+/*  */
+enum  { /* _RT_CHANNEL_DOMAIN */
+       /*  old channel plan mapping ===== */
+       RT_CHANNEL_DOMAIN_FCC = 0x00,
+       RT_CHANNEL_DOMAIN_IC = 0x01,
+       RT_CHANNEL_DOMAIN_ETSI = 0x02,
+       RT_CHANNEL_DOMAIN_SPAIN = 0x03,
+       RT_CHANNEL_DOMAIN_FRANCE = 0x04,
+       RT_CHANNEL_DOMAIN_MKK = 0x05,
+       RT_CHANNEL_DOMAIN_MKK1 = 0x06,
+       RT_CHANNEL_DOMAIN_ISRAEL = 0x07,
+       RT_CHANNEL_DOMAIN_TELEC = 0x08,
+       RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN = 0x09,
+       RT_CHANNEL_DOMAIN_WORLD_WIDE_13 = 0x0A,
+       RT_CHANNEL_DOMAIN_TAIWAN = 0x0B,
+       RT_CHANNEL_DOMAIN_CHINA = 0x0C,
+       RT_CHANNEL_DOMAIN_SINGAPORE_INDIA_MEXICO = 0x0D,
+       RT_CHANNEL_DOMAIN_KOREA = 0x0E,
+       RT_CHANNEL_DOMAIN_TURKEY = 0x0F,
+       RT_CHANNEL_DOMAIN_JAPAN = 0x10,
+       RT_CHANNEL_DOMAIN_FCC_NO_DFS = 0x11,
+       RT_CHANNEL_DOMAIN_JAPAN_NO_DFS = 0x12,
+       RT_CHANNEL_DOMAIN_WORLD_WIDE_5G = 0x13,
+       RT_CHANNEL_DOMAIN_TAIWAN_NO_DFS = 0x14,
+
+       /*  new channel plan mapping, (2GDOMAIN_5GDOMAIN) ===== */
+       RT_CHANNEL_DOMAIN_WORLD_NULL = 0x20,
+       RT_CHANNEL_DOMAIN_ETSI1_NULL = 0x21,
+       RT_CHANNEL_DOMAIN_FCC1_NULL = 0x22,
+       RT_CHANNEL_DOMAIN_MKK1_NULL = 0x23,
+       RT_CHANNEL_DOMAIN_ETSI2_NULL = 0x24,
+       RT_CHANNEL_DOMAIN_FCC1_FCC1 = 0x25,
+       RT_CHANNEL_DOMAIN_WORLD_ETSI1 = 0x26,
+       RT_CHANNEL_DOMAIN_MKK1_MKK1 = 0x27,
+       RT_CHANNEL_DOMAIN_WORLD_KCC1 = 0x28,
+       RT_CHANNEL_DOMAIN_WORLD_FCC2 = 0x29,
+       RT_CHANNEL_DOMAIN_WORLD_FCC3 = 0x30,
+       RT_CHANNEL_DOMAIN_WORLD_FCC4 = 0x31,
+       RT_CHANNEL_DOMAIN_WORLD_FCC5 = 0x32,
+       RT_CHANNEL_DOMAIN_WORLD_FCC6 = 0x33,
+       RT_CHANNEL_DOMAIN_FCC1_FCC7 = 0x34,
+       RT_CHANNEL_DOMAIN_WORLD_ETSI2 = 0x35,
+       RT_CHANNEL_DOMAIN_WORLD_ETSI3 = 0x36,
+       RT_CHANNEL_DOMAIN_MKK1_MKK2 = 0x37,
+       RT_CHANNEL_DOMAIN_MKK1_MKK3 = 0x38,
+       RT_CHANNEL_DOMAIN_FCC1_NCC1 = 0x39,
+       RT_CHANNEL_DOMAIN_FCC1_NCC2 = 0x40,
+       RT_CHANNEL_DOMAIN_GLOBAL_DOAMIN_2G = 0x41,
+       /*  Add new channel plan above this line=============== */
+       RT_CHANNEL_DOMAIN_MAX,
+       RT_CHANNEL_DOMAIN_REALTEK_DEFINE = 0x7F,
+};
+
+enum { /* _RT_CHANNEL_DOMAIN_2G */
+       RT_CHANNEL_DOMAIN_2G_WORLD = 0x00,              /* Worldwird 13 */
+       RT_CHANNEL_DOMAIN_2G_ETSI1 = 0x01,              /* Europe */
+       RT_CHANNEL_DOMAIN_2G_FCC1 = 0x02,               /* US */
+       RT_CHANNEL_DOMAIN_2G_MKK1 = 0x03,               /* Japan */
+       RT_CHANNEL_DOMAIN_2G_ETSI2 = 0x04,              /* France */
+       RT_CHANNEL_DOMAIN_2G_NULL = 0x05,
+       /*  Add new channel plan above this line=============== */
+       RT_CHANNEL_DOMAIN_2G_MAX,
+};
+
+enum { /* _RT_CHANNEL_DOMAIN_5G */
+       RT_CHANNEL_DOMAIN_5G_NULL = 0x00,
+       RT_CHANNEL_DOMAIN_5G_ETSI1 = 0x01,              /* Europe */
+       RT_CHANNEL_DOMAIN_5G_ETSI2 = 0x02,              /* Australia, New Zealand */
+       RT_CHANNEL_DOMAIN_5G_ETSI3 = 0x03,              /* Russia */
+       RT_CHANNEL_DOMAIN_5G_FCC1 = 0x04,               /* US */
+       RT_CHANNEL_DOMAIN_5G_FCC2 = 0x05,               /* FCC o/w DFS Channels */
+       RT_CHANNEL_DOMAIN_5G_FCC3 = 0x06,               /* India, Mexico */
+       RT_CHANNEL_DOMAIN_5G_FCC4 = 0x07,               /* Venezuela */
+       RT_CHANNEL_DOMAIN_5G_FCC5 = 0x08,               /* China */
+       RT_CHANNEL_DOMAIN_5G_FCC6 = 0x09,               /* Israel */
+       RT_CHANNEL_DOMAIN_5G_FCC7_IC1 = 0x0A,   /* US, Canada */
+       RT_CHANNEL_DOMAIN_5G_KCC1 = 0x0B,               /* Korea */
+       RT_CHANNEL_DOMAIN_5G_MKK1 = 0x0C,               /* Japan */
+       RT_CHANNEL_DOMAIN_5G_MKK2 = 0x0D,               /* Japan (W52, W53) */
+       RT_CHANNEL_DOMAIN_5G_MKK3 = 0x0E,               /* Japan (W56) */
+       RT_CHANNEL_DOMAIN_5G_NCC1 = 0x0F,               /* Taiwan */
+       RT_CHANNEL_DOMAIN_5G_NCC2 = 0x10,               /* Taiwan o/w DFS */
+       /*  Add new channel plan above this line=============== */
+       /*  Driver Self Defined ===== */
+       RT_CHANNEL_DOMAIN_5G_FCC = 0x11,
+       RT_CHANNEL_DOMAIN_5G_JAPAN_NO_DFS = 0x12,
+       RT_CHANNEL_DOMAIN_5G_FCC4_NO_DFS = 0x13,
+       RT_CHANNEL_DOMAIN_5G_MAX,
+};
+
+#define rtw_is_channel_plan_valid(chplan) (chplan<RT_CHANNEL_DOMAIN_MAX || chplan == RT_CHANNEL_DOMAIN_REALTEK_DEFINE)
+
+struct rt_channel_plan {
+       unsigned char   Channel[MAX_CHANNEL_NUM];
+       unsigned char   Len;
+};
+
+struct rt_channel_plan_2g {
+       unsigned char   Channel[MAX_CHANNEL_NUM_2G];
+       unsigned char   Len;
+};
+
+struct rt_channel_plan_5g {
+       unsigned char   Channel[MAX_CHANNEL_NUM_5G];
+       unsigned char   Len;
+};
+
+struct rt_channel_plan_map {
+       unsigned char   Index2G;
+       unsigned char   Index5G;
+};
+
+enum Associated_AP {
+       atherosAP       = 0,
+       broadcomAP      = 1,
+       ciscoAP         = 2,
+       marvellAP       = 3,
+       ralinkAP        = 4,
+       realtekAP       = 5,
+       airgocapAP      = 6,
+       unknownAP       = 7,
+       maxAP,
+};
+
+enum { /* HT_IOT_PEER_E */
+       HT_IOT_PEER_UNKNOWN             = 0,
+       HT_IOT_PEER_REALTEK             = 1,
+       HT_IOT_PEER_REALTEK_92SE        = 2,
+       HT_IOT_PEER_BROADCOM            = 3,
+       HT_IOT_PEER_RALINK              = 4,
+       HT_IOT_PEER_ATHEROS             = 5,
+       HT_IOT_PEER_CISCO               = 6,
+       HT_IOT_PEER_MERU                = 7,
+       HT_IOT_PEER_MARVELL             = 8,
+       HT_IOT_PEER_REALTEK_SOFTAP      = 9,/*  peer is RealTek SOFT_AP, by Bohn, 2009.12.17 */
+       HT_IOT_PEER_SELF_SOFTAP         = 10, /*  Self is SoftAP */
+       HT_IOT_PEER_AIRGO               = 11,
+       HT_IOT_PEER_INTEL               = 12,
+       HT_IOT_PEER_RTK_APCLIENT        = 13,
+       HT_IOT_PEER_REALTEK_81XX        = 14,
+       HT_IOT_PEER_REALTEK_WOW         = 15,
+       HT_IOT_PEER_TENDA               = 16,
+       HT_IOT_PEER_MAX                 = 17
+};
+
+enum SCAN_STATE {
+       SCAN_DISABLE = 0,
+       SCAN_START = 1,
+       SCAN_TXNULL = 2,
+       SCAN_PROCESS = 3,
+       SCAN_COMPLETE = 4,
+       SCAN_STATE_MAX,
+};
+
+struct mlme_handler {
+       char *str;
+       unsigned int (*func)(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+};
+
+struct action_handler {
+       unsigned int   num;
+       char* str;
+       unsigned int (*func)(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+};
+
+struct ss_res
+{
+       int     state;
+       int     bss_cnt;
+       int     channel_idx;
+       int     scan_mode;
+       u8 ssid_num;
+       u8 ch_num;
+       struct cfg80211_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+       struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
+};
+
+/* define AP_MODE                              0x0C */
+/* define STATION_MODE 0x08 */
+/* define AD_HOC_MODE          0x04 */
+/* define NO_LINK_MODE 0x00 */
+
+#define                WIFI_FW_NULL_STATE                      _HW_STATE_NOLINK_
+#define        WIFI_FW_STATION_STATE           _HW_STATE_STATION_
+#define        WIFI_FW_AP_STATE                                _HW_STATE_AP_
+#define        WIFI_FW_ADHOC_STATE                     _HW_STATE_ADHOC_
+
+#define        WIFI_FW_AUTH_NULL                       0x00000100
+#define        WIFI_FW_AUTH_STATE                      0x00000200
+#define        WIFI_FW_AUTH_SUCCESS                    0x00000400
+
+#define        WIFI_FW_ASSOC_STATE                     0x00002000
+#define        WIFI_FW_ASSOC_SUCCESS           0x00004000
+
+#define        WIFI_FW_LINKING_STATE           (WIFI_FW_AUTH_NULL | WIFI_FW_AUTH_STATE | WIFI_FW_AUTH_SUCCESS |WIFI_FW_ASSOC_STATE)
+
+struct FW_Sta_Info {
+       struct sta_info *psta;
+       u32     status;
+       u32     rx_pkt;
+       u32     retry;
+       unsigned char SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
+};
+
+/*
+ * Usage:
+ * When one iface acted as AP mode and the other iface is STA mode and scanning,
+ * it should switch back to AP's operating channel periodically.
+ * Parameters info:
+ * When the driver scanned RTW_SCAN_NUM_OF_CH channels, it would switch back to AP's operating channel for
+ * RTW_STAY_AP_CH_MILLISECOND * SURVEY_TO milliseconds.
+ * Example:
+ * For chip supports 2.4G + 5GHz and AP mode is operating in channel 1,
+ * RTW_SCAN_NUM_OF_CH is 8, RTW_STAY_AP_CH_MILLISECOND is 3 and SURVEY_TO is 100.
+ * When it's STA mode gets set_scan command,
+ * it would
+ * 1. Doing the scan on channel 1.2.3.4.5.6.7.8
+ * 2. Back to channel 1 for 300 milliseconds
+ * 3. Go through doing site survey on channel 9.10.11.36.40.44.48.52
+ * 4. Back to channel 1 for 300 milliseconds
+ * 5. ... and so on, till survey done.
+ */
+
+struct mlme_ext_info
+{
+       u32     state;
+       u32     reauth_count;
+       u32     reassoc_count;
+       u32     link_count;
+       u32     auth_seq;
+       u32     auth_algo;      /*  802.11 auth, could be open, shared, auto */
+       u32     authModeToggle;
+       u32     enc_algo;/* encrypt algorithm; */
+       u32     key_index;      /*  this is only valid for legendary wep, 0~3 for key id. */
+       u32     iv;
+       u8      chg_txt[128];
+       u16     aid;
+       u16     bcn_interval;
+       u16     capability;
+       u8      assoc_AP_vendor;
+       u8      slotTime;
+       u8      preamble_mode;
+       u8      WMM_enable;
+       u8      ERP_enable;
+       u8      ERP_IE;
+       u8      HT_enable;
+       u8      HT_caps_enable;
+       u8      HT_info_enable;
+       u8      HT_protection;
+       u8      turboMode_cts2self;
+       u8      turboMode_rtsen;
+       u8      SM_PS;
+       u8      agg_enable_bitmap;
+       u8      ADDBA_retry_count;
+       u8      candidate_tid_bitmap;
+       u8      dialogToken;
+       /*  Accept ADDBA Request */
+       bool bAcceptAddbaReq;
+       u8      bwmode_updated;
+       u8      hidden_ssid_mode;
+
+       struct ADDBA_request            ADDBA_req;
+       struct WMM_para_element WMM_param;
+       struct HT_caps_element  HT_caps;
+       struct HT_info_element          HT_info;
+       struct wlan_bssid_ex                    network;/* join network or bss_network, if in ap mode, it is the same to cur_network.network */
+       struct FW_Sta_Info              FW_sta_info[NUM_STA];
+};
+
+/*  The channel information about this channel including joining, scanning, and power constraints. */
+struct rt_channel_info {
+       u8              ChannelNum;             /*  The channel number. */
+       enum rt_scan_type ScanType;             /*  Scan type such as passive or active scan. */
+};
+
+int rtw_ch_set_search_ch23a(struct rt_channel_info *ch_set, const u32 ch);
+
+/*  P2P_MAX_REG_CLASSES - Maximum number of regulatory classes */
+#define P2P_MAX_REG_CLASSES 10
+
+/*  P2P_MAX_REG_CLASS_CHANNELS - Maximum number of channels per regulatory class */
+#define P2P_MAX_REG_CLASS_CHANNELS 20
+
+/*   struct p2p_channels - List of supported channels */
+struct p2p_channels {
+       /*  struct p2p_reg_class - Supported regulatory class */
+       struct p2p_reg_class {
+               /*  reg_class - Regulatory class (IEEE 802.11-2007, Annex J) */
+               u8 reg_class;
+
+               /*  channel - Supported channels */
+               u8 channel[P2P_MAX_REG_CLASS_CHANNELS];
+
+               /*  channels - Number of channel entries in use */
+               size_t channels;
+       } reg_class[P2P_MAX_REG_CLASSES];
+
+       /*  reg_classes - Number of reg_class entries in use */
+       size_t reg_classes;
+};
+
+struct p2p_oper_class_map {
+       enum hw_mode {IEEE80211G,IEEE80211A} mode;
+       u8 op_class;
+       u8 min_chan;
+       u8 max_chan;
+       u8 inc;
+       enum {
+               BW20, BW40PLUS, BW40MINUS
+       } bw;
+};
+
+struct mlme_ext_priv {
+       struct rtw_adapter      *padapter;
+       u8      mlmeext_init;
+       atomic_t                event_seq;
+       u16     mgnt_seq;
+
+       /* struct fw_priv       fwpriv; */
+
+       unsigned char   cur_channel;
+       unsigned char   cur_bwmode;
+       unsigned char   cur_ch_offset;/* PRIME_CHNL_OFFSET */
+       unsigned char   cur_wireless_mode;      /*  NETWORK_TYPE */
+
+       unsigned char   max_chan_nums;
+       struct rt_channel_info          channel_set[MAX_CHANNEL_NUM];
+       struct p2p_channels channel_list;
+       unsigned char   basicrate[NumRates];
+       unsigned char   datarate[NumRates];
+
+       struct ss_res           sitesurvey_res;
+       struct mlme_ext_info    mlmext_info;/* for sta/adhoc mode, including current scanning/connecting/connected related info. */
+                                                     /* for ap mode, network includes ap's cap_info */
+       struct timer_list               survey_timer;
+       struct timer_list               link_timer;
+       u16                     chan_scan_time;
+
+       u8      scan_abort;
+       u8      tx_rate; /*  TXRATE when USERATE is set. */
+
+       u32     retry; /* retry for issue probereq */
+
+       u64 TSFValue;
+
+       unsigned char bstart_bss;
+       u8 update_channel_plan_by_ap_done;
+       /* recv_decache check for Action_public frame */
+       u8 action_public_dialog_token;
+       u16      action_public_rxseq;
+       u8 active_keep_alive_check;
+};
+
+int init_mlme_ext_priv23a(struct rtw_adapter* padapter);
+int init_hw_mlme_ext23a(struct rtw_adapter *padapter);
+void free_mlme_ext_priv23a (struct mlme_ext_priv *pmlmeext);
+void init_mlme_ext_timer23a(struct rtw_adapter *padapter);
+void init_addba_retry_timer23a(struct sta_info *psta);
+struct xmit_frame *alloc_mgtxmitframe23a(struct xmit_priv *pxmitpriv);
+
+unsigned char networktype_to_raid23a(unsigned char network_type);
+u8 judge_network_type23a(struct rtw_adapter *padapter, unsigned char *rate,
+                     int ratelen);
+void get_rate_set23a(struct rtw_adapter *padapter, unsigned char *pbssrate,
+                 int *bssrate_len);
+void UpdateBrateTbl23a(struct rtw_adapter *padapter,u8 *mBratesOS);
+void Update23aTblForSoftAP(u8 *bssrateset, u32 bssratelen);
+
+void Save_DM_Func_Flag23a(struct rtw_adapter *padapter);
+void Restore_DM_Func_Flag23a(struct rtw_adapter *padapter);
+void Switch_DM_Func23a(struct rtw_adapter *padapter, unsigned long mode, u8 enable);
+
+void Set_MSR23a(struct rtw_adapter *padapter, u8 type);
+
+u8 rtw_get_oper_ch23a(struct rtw_adapter *adapter);
+void rtw_set_oper_ch23a(struct rtw_adapter *adapter, u8 ch);
+u8 rtw_get_oper_bw23a(struct rtw_adapter *adapter);
+void rtw_set_oper_bw23a(struct rtw_adapter *adapter, u8 bw);
+u8 rtw_get_oper_ch23aoffset(struct rtw_adapter *adapter);
+void rtw_set_oper_ch23aoffset23a(struct rtw_adapter *adapter, u8 offset);
+
+void set_channel_bwmode23a(struct rtw_adapter *padapter, unsigned char channel,
+                       unsigned char channel_offset, unsigned short bwmode);
+void SelectChannel23a(struct rtw_adapter *padapter, unsigned char channel);
+void SetBWMode23a(struct rtw_adapter *padapter, unsigned short bwmode,
+              unsigned char channel_offset);
+
+unsigned int decide_wait_for_beacon_timeout23a(unsigned int bcn_interval);
+
+void write_cam23a(struct rtw_adapter *padapter, u8 entry, u16 ctrl,
+              u8 *mac, u8 *key);
+void clear_cam_entry23a(struct rtw_adapter *padapter, u8 entry);
+
+void invalidate_cam_all23a(struct rtw_adapter *padapter);
+void CAM_empty_entry23a(struct rtw_adapter *Adapter, u8 ucIndex);
+
+int allocate_fw_sta_entry23a(struct rtw_adapter *padapter);
+void flush_all_cam_entry23a(struct rtw_adapter *padapter);
+
+bool IsLegal5GChannel(struct rtw_adapter *Adapter, u8 channel);
+
+void site_survey23a(struct rtw_adapter *padapter);
+u8 collect_bss_info23a(struct rtw_adapter *padapter,
+                   struct recv_frame *precv_frame,
+                   struct wlan_bssid_ex *bssid);
+void update_network23a(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
+                   struct rtw_adapter *padapter, bool update_ie);
+
+int get_bsstype23a(unsigned short capability);
+u8 *get_my_bssid23a(struct wlan_bssid_ex *pnetwork);
+u16 get_beacon_interval23a(struct wlan_bssid_ex *bss);
+
+int is_client_associated_to_ap23a(struct rtw_adapter *padapter);
+int is_client_associated_to_ibss23a(struct rtw_adapter *padapter);
+int is_IBSS_empty23a(struct rtw_adapter *padapter);
+
+unsigned char check_assoc_AP23a(u8 *pframe, uint len);
+
+int WMM_param_handler23a(struct rtw_adapter *padapter,
+                     struct ndis_802_11_var_ies *pIE);
+#ifdef CONFIG_8723AU_P2P
+int WFD_info_handler(struct rtw_adapter *padapter,
+                    struct ndis_802_11_var_ies *pIE);
+#endif
+void WMMOnAssocRsp23a(struct rtw_adapter *padapter);
+
+void HT_caps_handler23a(struct rtw_adapter *padapter,
+                    struct ndis_802_11_var_ies *pIE);
+void HT_info_handler23a(struct rtw_adapter *padapter,
+                    struct ndis_802_11_var_ies *pIE);
+void HTOnAssocRsp23a(struct rtw_adapter *padapter);
+
+void ERP_IE_handler23a(struct rtw_adapter *padapter,
+                   struct ndis_802_11_var_ies *pIE);
+void VCS_update23a(struct rtw_adapter *padapter, struct sta_info *psta);
+
+void update_beacon23a_info(struct rtw_adapter *padapter, u8 *pframe, uint len,
+                       struct sta_info *psta);
+int rtw_check_bcn_info23a(struct rtw_adapter *Adapter, u8 *pframe, u32 packet_len);
+void update_IOT_info23a(struct rtw_adapter *padapter);
+void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap);
+void update_wireless_mode23a(struct rtw_adapter * padapter);
+void update_tx_basic_rate23a(struct rtw_adapter *padapter, u8 modulation);
+void update_bmc_sta_support_rate23a(struct rtw_adapter *padapter, u32 mac_id);
+int update_sta_support_rate23a(struct rtw_adapter *padapter, u8* pvar_ie,
+                           uint var_ie_len, int cam_idx);
+
+/* for sta/adhoc mode */
+void update_sta_info23a(struct rtw_adapter *padapter, struct sta_info *psta);
+unsigned int update_basic_rate23a(unsigned char *ptn, unsigned int ptn_sz);
+unsigned int update_supported_rate23a(unsigned char *ptn, unsigned int ptn_sz);
+unsigned int update_MSC_rate23a(struct HT_caps_element *pHT_caps);
+void Update_RA_Entry23a(struct rtw_adapter *padapter, struct sta_info *psta);
+void set_sta_rate23a(struct rtw_adapter *padapter, struct sta_info *psta);
+
+unsigned int receive_disconnect23a(struct rtw_adapter *padapter,
+                               unsigned char *MacAddr, unsigned short reason);
+
+unsigned char get_highest_rate_idx23a(u32 mask);
+int support_short_GI23a(struct rtw_adapter *padapter,
+                    struct HT_caps_element *pHT_caps);
+unsigned int is_ap_in_tkip23a(struct rtw_adapter *padapter);
+unsigned int is_ap_in_wep23a(struct rtw_adapter *padapter);
+unsigned int should_forbid_n_rate23a(struct rtw_adapter *padapter);
+
+void report_join_res23a(struct rtw_adapter *padapter, int res);
+void report_survey_event23a(struct rtw_adapter *padapter,
+                        struct recv_frame *precv_frame);
+void report_surveydone_event23a(struct rtw_adapter *padapter);
+void report_del_sta_event23a(struct rtw_adapter *padapter,
+                         unsigned char *MacAddr, unsigned short reason);
+void report_add_sta_event23a(struct rtw_adapter *padapter,
+                         unsigned char *MacAddr, int cam_idx);
+
+void beacon_timing_control23a(struct rtw_adapter *padapter);
+u8 set_tx_beacon_cmd23a(struct rtw_adapter*padapter);
+unsigned int setup_beacon_frame(struct rtw_adapter *padapter,
+                               unsigned char *beacon_frame);
+void update_mgnt_tx_rate23a(struct rtw_adapter *padapter, u8 rate);
+void update_mgntframe_attrib23a(struct rtw_adapter *padapter,
+                            struct pkt_attrib *pattrib);
+void dump_mgntframe23a(struct rtw_adapter *padapter,
+                   struct xmit_frame *pmgntframe);
+s32 dump_mgntframe23a_and_wait(struct rtw_adapter *padapter,
+                           struct xmit_frame *pmgntframe, int timeout_ms);
+s32 dump_mgntframe23a_and_wait_ack23a(struct rtw_adapter *padapter,
+                               struct xmit_frame *pmgntframe);
+
+#ifdef CONFIG_8723AU_P2P
+void issue_probersp23a_p2p23a(struct rtw_adapter *padapter, unsigned char *da);
+void issue_p2p_provision_request23a(struct rtw_adapter *padapter, u8 *pssid,
+                                u8 ussidlen, u8* pdev_raddr);
+void issue_p2p_GO_request23a(struct rtw_adapter *padapter, u8* raddr);
+void issue23a_probereq_p2p(struct rtw_adapter *padapter, u8 *da);
+int issue23a_probereq_p2p_ex(struct rtw_adapter *adapter, u8 *da, int try_cnt,
+                         int wait_ms);
+void issue_p2p_invitation_response23a(struct rtw_adapter *padapter, u8* raddr,
+                                  u8 dialogToken, u8 success);
+void issue_p2p_invitation_request23a(struct rtw_adapter *padapter, u8* raddr);
+#endif /* CONFIG_8723AU_P2P */
+void issue_beacon23a(struct rtw_adapter *padapter, int timeout_ms);
+void issue_probersp23a(struct rtw_adapter *padapter, unsigned char *da,
+                   u8 is_valid_p2p_probereq);
+void issue_assocreq23a(struct rtw_adapter *padapter);
+void issue_asocrsp23a(struct rtw_adapter *padapter, unsigned short status,
+                  struct sta_info *pstat, int pkt_type);
+void issue_auth23a(struct rtw_adapter *padapter, struct sta_info *psta,
+               unsigned short status);
+void issue_probereq23a(struct rtw_adapter *padapter, struct cfg80211_ssid *pssid,
+                   u8 *da);
+s32 issue_probereq23a_ex23a(struct rtw_adapter *padapter, struct cfg80211_ssid *pssid,
+                     u8 *da, int try_cnt, int wait_ms);
+int issue_nulldata23a(struct rtw_adapter *padapter, unsigned char *da,
+                  unsigned int power_mode, int try_cnt, int wait_ms);
+int issue_qos_nulldata23a(struct rtw_adapter *padapter, unsigned char *da, u16 tid,
+                      int try_cnt, int wait_ms);
+int issue_deauth23a(struct rtw_adapter *padapter, unsigned char *da,
+                unsigned short reason);
+int issue_deauth23a_ex23a(struct rtw_adapter *padapter, u8 *da, unsigned short reason,
+                   int try_cnt, int wait_ms);
+void issue_action_spct_ch_switch23a(struct rtw_adapter *padapter, u8 *ra,
+                                u8 new_ch, u8 ch_offset);
+void issue_action_BA23a(struct rtw_adapter *padapter, unsigned char *raddr,
+                    unsigned char action, unsigned short status);
+unsigned int send_delba23a(struct rtw_adapter *padapter, u8 initiator, u8 *addr);
+unsigned int send_beacon23a(struct rtw_adapter *padapter);
+
+void start_clnt_assoc23a(struct rtw_adapter *padapter);
+void start_clnt_auth23a(struct rtw_adapter *padapter);
+void start_clnt_join23a(struct rtw_adapter *padapter);
+void start_create_ibss23a(struct rtw_adapter *padapter);
+
+unsigned int OnAssocReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAssocRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnProbeReq23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnProbeRsp23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int DoReserved23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnBeacon23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAtim23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnDisassoc23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAuth23aClient23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnDeAuth23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAction23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+
+unsigned int on_action_spct23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAction23a_qos(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAction23a_dls(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAction23a_back23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int on_action_public23a(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAction23a_ht(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAction23a_wmm(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+unsigned int OnAction23a_p2p(struct rtw_adapter *padapter, struct recv_frame *precv_frame);
+
+
+void mlmeext_joinbss_event_callback23a(struct rtw_adapter *padapter, int join_res);
+void mlmeext_sta_del_event_callback23a(struct rtw_adapter *padapter);
+void mlmeext_sta_add_event_callback23a(struct rtw_adapter *padapter, struct sta_info *psta);
+
+void linked_status_chk23a(struct rtw_adapter *padapter);
+
+#define set_survey_timer(mlmeext, ms) \
+       /*DBG_8723A("%s set_survey_timer(%p, %d)\n", __FUNCTION__, (mlmeext), (ms));*/ \
+       mod_timer(&mlmeext->survey_timer, jiffies + msecs_to_jiffies(ms));
+
+#define set_link_timer(mlmeext, ms) \
+       /*DBG_8723A("%s set_link_timer(%p, %d)\n", __FUNCTION__, (mlmeext), (ms));*/ \
+       mod_timer(&mlmeext->link_timer, jiffies + msecs_to_jiffies(ms));
+
+int cckrates_included23a(unsigned char *rate, int ratelen);
+int cckratesonly_included23a(unsigned char *rate, int ratelen);
+
+void process_addba_req23a(struct rtw_adapter *padapter, u8 *paddba_req, u8 *addr);
+
+void update_TSF23a(struct mlme_ext_priv *pmlmeext, u8 *pframe, uint len);
+void correct_TSF23a(struct rtw_adapter *padapter, struct mlme_ext_priv *pmlmeext);
+
+struct cmd_hdl {
+       uint    parmsize;
+       u8 (*h2cfuns)(struct rtw_adapter *padapter, u8 *pbuf);
+};
+
+
+u8 read_macreg_hdl(struct rtw_adapter *padapter, u8 *pbuf);
+u8 write_macreg_hdl(struct rtw_adapter *padapter, u8 *pbuf);
+u8 read_bbreg_hdl(struct rtw_adapter *padapter, u8 *pbuf);
+u8 write_bbreg_hdl(struct rtw_adapter *padapter, u8 *pbuf);
+u8 read_rfreg_hdl(struct rtw_adapter *padapter, u8 *pbuf);
+u8 write_rfreg_hdl(struct rtw_adapter *padapter, u8 *pbuf);
+
+
+u8 NULL_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 join_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 disconnect_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 createbss_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 setopmode_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 sitesurvey_cmd_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 setauth_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 setkey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 set_stakey_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 set_assocsta_hdl(struct rtw_adapter *padapter, u8 *pbuf);
+u8 del_assocsta_hdl(struct rtw_adapter *padapter, u8 *pbuf);
+u8 add_ba_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf);
+
+u8 mlme_evt_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf);
+u8 h2c_msg_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf);
+u8 tx_beacon_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf);
+u8 set_ch_hdl23a(struct rtw_adapter *padapter, u8 *pbuf);
+u8 set_chplan_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf);
+u8 led_blink_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf);
+u8 set_csa_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf);  /* Kurt: Handling DFS channel switch announcement ie. */
+u8 tdls_hdl23a(struct rtw_adapter *padapter, unsigned char *pbuf);
+
+#define GEN_DRV_CMD_HANDLER(size, cmd) {size, &cmd ## _hdl23a},
+#define GEN_MLME_EXT_HANDLER(size, cmd)        {size, cmd},
+
+struct C2HEvent_Header {
+#ifdef __LITTLE_ENDIAN
+
+       unsigned int len:16;
+       unsigned int ID:8;
+       unsigned int seq:8;
+
+#elif defined(__BIG_ENDIAN)
+
+       unsigned int seq:8;
+       unsigned int ID:8;
+       unsigned int len:16;
+
+#else
+
+#  error "Must be LITTLE or BIG Endian"
+
+#endif
+
+       unsigned int rsvd;
+};
+
+void rtw_dummy_event_callback23a(struct rtw_adapter *adapter , u8 *pbuf);
+void rtw23a_fwdbg_event_callback(struct rtw_adapter *adapter , u8 *pbuf);
+
+enum rtw_c2h_event {
+       GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/
+       GEN_EVT_CODE(_Read_BBREG),
+       GEN_EVT_CODE(_Read_RFREG),
+       GEN_EVT_CODE(_Read_EEPROM),
+       GEN_EVT_CODE(_Read_EFUSE),
+       GEN_EVT_CODE(_Read_CAM),                        /*5*/
+       GEN_EVT_CODE(_Get_BasicRate),
+       GEN_EVT_CODE(_Get_DataRate),
+       GEN_EVT_CODE(_Survey),   /*8*/
+       GEN_EVT_CODE(_SurveyDone),       /*9*/
+
+       GEN_EVT_CODE(_JoinBss) , /*10*/
+       GEN_EVT_CODE(_AddSTA),
+       GEN_EVT_CODE(_DelSTA),
+       GEN_EVT_CODE(_AtimDone) ,
+       GEN_EVT_CODE(_TX_Report),
+       GEN_EVT_CODE(_CCX_Report),                      /*15*/
+       GEN_EVT_CODE(_DTM_Report),
+       GEN_EVT_CODE(_TX_Rate_Statistics),
+       GEN_EVT_CODE(_C2HLBK),
+       GEN_EVT_CODE(_FWDBG),
+       GEN_EVT_CODE(_C2HFEEDBACK),               /*20*/
+       GEN_EVT_CODE(_ADDBA),
+       GEN_EVT_CODE(_C2HBCN),
+       GEN_EVT_CODE(_ReportPwrState),          /* filen: only for PCIE, USB */
+       GEN_EVT_CODE(_CloseRF),                         /* filen: only for PCIE, work around ASPM */
+       MAX_C2HEVT
+};
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtw_p2p.h b/drivers/staging/rtl8723au/include/rtw_p2p.h
new file mode 100644 (file)
index 0000000..93fdc65
--- /dev/null
@@ -0,0 +1,158 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTW_P2P_H_
+#define __RTW_P2P_H_
+
+#include <drv_types.h>
+
+u32 build_beacon_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_probe_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_prov_disc_request_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf,
+                                  u8 *pssid, u8 ussidlen, u8 *pdev_raddr);
+u32 build_assoc_resp_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf,
+                           u8 status_code);
+u32 build_deauth_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pbuf);
+#ifdef CONFIG_8723AU_P2P
+u32 build_probe_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_probe_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf,
+                           u8 tunneled);
+u32 build_beacon_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_nego_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_nego_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_nego_confirm_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_invitation_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_invitation_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_assoc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_assoc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_provdisc_req_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+u32 build_provdisc_resp_wfd_ie(struct wifidirect_info *pwdinfo, u8 *pbuf);
+#endif /* CONFIG_8723AU_P2P */
+
+u32 process_probe_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe,
+                            uint len);
+u32 process_assoc_req_p2p_ie23a(struct wifidirect_info *pwdinfo, u8 *pframe,
+                            uint len, struct sta_info *psta);
+u32 process_p2p_devdisc_req23a(struct wifidirect_info *pwdinfo, u8 *pframe,
+                           uint len);
+u32 process_p2p_devdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe,
+                            uint len);
+u8 process_p2p_provdisc_req23a(struct wifidirect_info *pwdinfo, u8 *pframe,
+                           uint len);
+u8 process_p2p_provdisc_resp23a(struct wifidirect_info *pwdinfo, u8 *pframe);
+u8 process_p2p_group_negotation_req23a(struct wifidirect_info *pwdinfo,
+                                   u8 *pframe, uint len);
+u8 process_p2p_group_negotation_resp23a(struct wifidirect_info *pwdinfo,
+                                    u8 *pframe, uint len);
+u8 process_p2p_group_negotation_confirm23a(struct wifidirect_info *pwdinfo,
+                                       u8 *pframe, uint len);
+u8 process_p2p_presence_req23a(struct wifidirect_info *pwdinfo,
+                           u8 *pframe, uint len);
+
+void p2p_protocol_wk_hdl23a(struct rtw_adapter *padapter, int cmdtype);
+
+#ifdef CONFIG_8723AU_P2P
+void   process_p2p_ps_ie23a(struct rtw_adapter *padapter, u8 *IEs, u32 IELength);
+void   p2p_ps_wk_hdl23a(struct rtw_adapter *padapter, u8 p2p_ps_state);
+u8 p2p_ps_wk_cmd23a(struct rtw_adapter *padapter, u8 p2p_ps_state, u8 enqueue);
+#endif /*  CONFIG_8723AU_P2P */
+
+void rtw_init_cfg80211_wifidirect_info(struct rtw_adapter *padapter);
+int rtw_p2p_check_frames(struct rtw_adapter *padapter, const u8 *buf,
+                        u32 len, u8 tx);
+void rtw_append_wfd_ie(struct rtw_adapter *padapter, u8 *buf, u32 *len);
+
+void reset_global_wifidirect_info23a(struct rtw_adapter *padapter);
+int rtw_init_wifi_display_info(struct rtw_adapter *padapter);
+void rtw_init_wifidirect_timers23a(struct rtw_adapter *padapter);
+void rtw_init_wifidirect_addrs23a(struct rtw_adapter *padapter, u8 *dev_addr,
+                              u8 *iface_addr);
+void init_wifidirect_info23a(struct rtw_adapter *padapter, enum P2P_ROLE role);
+int rtw_p2p_enable23a(struct rtw_adapter *padapter, enum P2P_ROLE role);
+
+static inline void _rtw_p2p_set_state(struct wifidirect_info *wdinfo,
+                                     enum P2P_STATE state)
+{
+       if (wdinfo->p2p_state != state) {
+               /* wdinfo->pre_p2p_state = wdinfo->p2p_state; */
+               wdinfo->p2p_state = state;
+       }
+}
+
+static inline void _rtw_p2p_set_pre_state(struct wifidirect_info *wdinfo,
+                                         enum P2P_STATE state)
+{
+       if (wdinfo->pre_p2p_state != state)
+               wdinfo->pre_p2p_state = state;
+}
+
+static inline void _rtw_p2p_set_role(struct wifidirect_info *wdinfo,
+                                    enum P2P_ROLE role)
+{
+       if (wdinfo->role != role)
+               wdinfo->role = role;
+}
+
+static inline int _rtw_p2p_state(struct wifidirect_info *wdinfo)
+{
+       return wdinfo->p2p_state;
+}
+
+static inline int _rtw_p2p_pre_state(struct wifidirect_info *wdinfo)
+{
+       return wdinfo->pre_p2p_state;
+}
+
+static inline int _rtw_p2p_role(struct wifidirect_info *wdinfo)
+{
+       return wdinfo->role;
+}
+
+static inline bool _rtw_p2p_chk_state(struct wifidirect_info *wdinfo,
+                                     enum P2P_STATE state)
+{
+       return wdinfo->p2p_state == state;
+}
+
+static inline bool _rtw_p2p_chk_role(struct wifidirect_info *wdinfo,
+                                    enum P2P_ROLE role)
+{
+       return wdinfo->role == role;
+}
+
+#define rtw_p2p_set_state(wdinfo, state) _rtw_p2p_set_state(wdinfo, state)
+#define rtw_p2p_set_pre_state(wdinfo, state)                   \
+       _rtw_p2p_set_pre_state(wdinfo, state)
+#define rtw_p2p_set_role(wdinfo, role) _rtw_p2p_set_role(wdinfo, role)
+
+#define rtw_p2p_state(wdinfo) _rtw_p2p_state(wdinfo)
+#define rtw_p2p_pre_state(wdinfo) _rtw_p2p_pre_state(wdinfo)
+#define rtw_p2p_role(wdinfo) _rtw_p2p_role(wdinfo)
+#define rtw_p2p_chk_state(wdinfo, state) _rtw_p2p_chk_state(wdinfo, state)
+#define rtw_p2p_chk_role(wdinfo, role) _rtw_p2p_chk_role(wdinfo, role)
+
+#define rtw_p2p_findphase_ex_set(wdinfo, value) \
+       ((wdinfo)->find_phase_state_exchange_cnt = (value))
+
+/* is this find phase exchange for social channel scan? */
+#define rtw_p2p_findphase_ex_is_social(wdinfo)                 \
+       ((wdinfo)->find_phase_state_exchange_cnt >=             \
+        P2P_FINDPHASE_EX_SOCIAL_FIRST)
+
+/* should we need find phase exchange anymore? */
+#define rtw_p2p_findphase_ex_is_needed(wdinfo) \
+       ((wdinfo)->find_phase_state_exchange_cnt < P2P_FINDPHASE_EX_MAX && \
+       (wdinfo)->find_phase_state_exchange_cnt != P2P_FINDPHASE_EX_NONE)
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtw_pwrctrl.h b/drivers/staging/rtl8723au/include/rtw_pwrctrl.h
new file mode 100644 (file)
index 0000000..e0da87d
--- /dev/null
@@ -0,0 +1,265 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTW_PWRCTRL_H_
+#define __RTW_PWRCTRL_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define FW_PWR0                0
+#define FW_PWR1                1
+#define FW_PWR2                2
+#define FW_PWR3                3
+
+
+#define HW_PWR0                7
+#define HW_PWR1                6
+#define HW_PWR2                2
+#define HW_PWR3                0
+#define HW_PWR4                8
+
+#define FW_PWRMSK      0x7
+
+
+#define XMIT_ALIVE     BIT(0)
+#define RECV_ALIVE     BIT(1)
+#define CMD_ALIVE      BIT(2)
+#define EVT_ALIVE      BIT(3)
+
+enum Power_Mgnt {
+       PS_MODE_ACTIVE  = 0,
+       PS_MODE_MIN,
+       PS_MODE_MAX,
+       PS_MODE_DTIM,
+       PS_MODE_VOIP,
+       PS_MODE_UAPSD_WMM,
+       PS_MODE_UAPSD,
+       PS_MODE_IBSS,
+       PS_MODE_WWLAN,
+       PM_Radio_Off,
+       PM_Card_Disable,
+       PS_MODE_NUM
+};
+
+
+/* BIT[2:0] = HW state
+ * BIT[3] = Protocol PS state,  0: active, 1: sleep state
+ * BIT[4] = sub-state
+ */
+
+#define PS_DPS                 BIT(0)
+#define PS_LCLK                        (PS_DPS)
+#define PS_RF_OFF              BIT(1)
+#define PS_ALL_ON              BIT(2)
+#define PS_ST_ACTIVE           BIT(3)
+
+#define PS_ISR_ENABLE          BIT(4)
+#define PS_IMR_ENABLE          BIT(5)
+#define PS_ACK                 BIT(6)
+#define PS_TOGGLE              BIT(7)
+
+#define PS_STATE_MASK          (0x0F)
+#define PS_STATE_HW_MASK       (0x07)
+#define PS_SEQ_MASK            (0xc0)
+
+#define PS_STATE(x)            (PS_STATE_MASK & (x))
+#define PS_STATE_HW(x) (PS_STATE_HW_MASK & (x))
+#define PS_SEQ(x)              (PS_SEQ_MASK & (x))
+
+#define PS_STATE_S0            (PS_DPS)
+#define PS_STATE_S1            (PS_LCLK)
+#define PS_STATE_S2            (PS_RF_OFF)
+#define PS_STATE_S3            (PS_ALL_ON)
+#define PS_STATE_S4            ((PS_ST_ACTIVE) | (PS_ALL_ON))
+
+
+#define PS_IS_RF_ON(x) ((x) & (PS_ALL_ON))
+#define PS_IS_ACTIVE(x)        ((x) & (PS_ST_ACTIVE))
+#define CLR_PS_STATE(x)        ((x) = ((x) & (0xF0)))
+
+
+struct reportpwrstate_parm {
+       unsigned char mode;
+       unsigned char state; /* the CPWM value */
+       unsigned short rsvd;
+};
+
+#define LPS_DELAY_TIME (1*HZ) /*  1 sec */
+
+#define EXE_PWR_NONE           0x01
+#define EXE_PWR_IPS            0x02
+#define EXE_PWR_LPS            0x04
+
+/*  RF state. */
+enum rt_rf_power_state {
+       rf_on,          /*  RF is on after RFSleep or RFOff */
+       rf_sleep,       /*  802.11 Power Save mode */
+       rf_off,         /*  HW/SW Radio OFF or Inactive Power Save */
+       /* Add the new RF state above this line===== */
+       rf_max
+};
+
+/*  RF Off Level for IPS or HW/SW radio off */
+#define        RT_RF_OFF_LEVL_ASPM             BIT(0)  /*  PCI ASPM */
+#define        RT_RF_OFF_LEVL_CLK_REQ          BIT(1)  /*  PCI clock request */
+#define        RT_RF_OFF_LEVL_PCI_D3           BIT(2)  /*  PCI D3 mode */
+/* NIC halt, re-init hw params */
+#define        RT_RF_OFF_LEVL_HALT_NIC         BIT(3)
+/*  FW free, re-download the FW */
+#define        RT_RF_OFF_LEVL_FREE_FW          BIT(4)
+#define        RT_RF_OFF_LEVL_FW_32K           BIT(5)  /*  FW in 32k */
+/*  Always enable ASPM and Clock Req in initialization. */
+#define        RT_RF_PS_LEVEL_ALWAYS_ASPM      BIT(6)
+/*  When LPS is on, disable 2R if no packet is received or transmittd. */
+#define        RT_RF_LPS_DISALBE_2R            BIT(30)
+#define        RT_RF_LPS_LEVEL_ASPM            BIT(31) /*  LPS with ASPM */
+
+#define        RT_IN_PS_LEVEL(ppsc, _PS_FLAG)                          \
+       ((ppsc->cur_ps_level & _PS_FLAG) ? true : false)
+#define        RT_CLEAR_PS_LEVEL(ppsc, _PS_FLAG)                       \
+       (ppsc->cur_ps_level &= (~(_PS_FLAG)))
+#define        RT_SET_PS_LEVEL(ppsc, _PS_FLAG)                         \
+       (ppsc->cur_ps_level |= _PS_FLAG)
+
+
+enum {
+       PSBBREG_RF0 = 0,
+       PSBBREG_RF1,
+       PSBBREG_RF2,
+       PSBBREG_AFE0,
+       PSBBREG_TOTALCNT
+};
+
+enum { /*  for ips_mode */
+       IPS_NONE = 0,
+       IPS_NORMAL,
+       IPS_LEVEL_2,
+};
+
+struct pwrctrl_priv {
+       struct semaphore lock;
+       volatile u8 rpwm; /* requested power state for fw */
+       volatile u8 cpwm; /* fw current power state. updated when 1.
+                          * read from HCPWM 2. driver lowers power level
+                          */
+       volatile u8 tog; /*  toggling */
+       volatile u8 cpwm_tog; /*  toggling */
+
+       u8      pwr_mode;
+       u8      smart_ps;
+       u8      bcn_ant_mode;
+
+       u32     alives;
+       struct work_struct cpwm_event;
+       u8      bpower_saving;
+
+       u8      b_hw_radio_off;
+       u8      reg_rfoff;
+       u8      reg_pdnmode; /* powerdown mode */
+       u32     rfoff_reason;
+
+       /* RF OFF Level */
+       u32     cur_ps_level;
+       u32     reg_rfps_level;
+
+       uint    ips_enter23a_cnts;
+       uint    ips_leave23a_cnts;
+
+       u8      ips_mode;
+       u8      ips_mode_req; /*  used to accept the mode setting request */
+       uint bips_processing;
+       unsigned long ips_deny_time; /* deny IPS when system time is smaller */
+       u8 ps_processing; /* used to mark whether in rtw_ps_processor23a */
+
+       u8      bLeisurePs;
+       u8      LpsIdleCount;
+       u8      power_mgnt;
+       u8      bFwCurrentInPSMode;
+       unsigned long   DelayLPSLastTimeStamp;
+       u8      btcoex_rfon;
+       s32             pnp_current_pwr_state;
+       u8              pnp_bstop_trx;
+
+       u8              bInternalAutoSuspend;
+       u8              bInSuspend;
+#ifdef CONFIG_8723AU_BT_COEXIST
+       u8              bAutoResume;
+       u8              autopm_cnt;
+#endif
+       u8              bSupportRemoteWakeup;
+       struct timer_list       pwr_state_check_timer;
+       int             pwr_state_check_interval;
+       u8              pwr_state_check_cnts;
+
+       int             ps_flag;
+
+       enum rt_rf_power_state  rf_pwrstate;/* cur power state */
+       enum rt_rf_power_state  change_rfpwrstate;
+
+       u8      wepkeymask;
+       u8      bHWPowerdown;/* if support hw power down */
+       u8      bHWPwrPindetect;
+       u8      bkeepfwalive;
+       u8      brfoffbyhw;
+       unsigned long PS_BBRegBackup[PSBBREG_TOTALCNT];
+};
+
+#define rtw_get_ips_mode_req(pwrctrlpriv) \
+       ((pwrctrlpriv)->ips_mode_req)
+
+#define rtw_ips_mode_req(pwrctrlpriv, ips_mode) \
+       ((pwrctrlpriv)->ips_mode_req = (ips_mode))
+
+#define RTW_PWR_STATE_CHK_INTERVAL 2000
+
+#define _rtw_set_pwr_state_check_timer(pwrctrlpriv, ms) \
+       (mod_timer(&pwrctrlpriv->pwr_state_check_timer, jiffies +       \
+                 msecs_to_jiffies(ms)))
+
+#define rtw_set_pwr_state_check_timer(pwrctrlpriv)     \
+       (_rtw_set_pwr_state_check_timer((pwrctrlpriv),  \
+                        (pwrctrlpriv)->pwr_state_check_interval))
+
+void rtw_init_pwrctrl_priv23a(struct rtw_adapter *adapter);
+void rtw_free_pwrctrl_priv(struct rtw_adapter *adapter);
+
+void rtw_set_ps_mode23a(struct rtw_adapter *padapter, u8 ps_mode,
+                    u8 smart_ps, u8 bcn_ant_mode);
+void rtw_set_rpwm23a(struct rtw_adapter *padapter, u8 val8);
+void LeaveAllPowerSaveMode23a(struct rtw_adapter *adapter);
+void ips_enter23a(struct rtw_adapter *padapter);
+int ips_leave23a(struct rtw_adapter *padapter);
+
+void rtw_ps_processor23a(struct rtw_adapter *padapter);
+
+enum rt_rf_power_state RfOnOffDetect23a(struct rtw_adapter *adapter);
+
+s32 LPS_RF_ON_check23a(struct rtw_adapter *padapter, u32 delay_ms);
+void LPS_Enter23a(struct rtw_adapter *padapter);
+void LPS_Leave23a(struct rtw_adapter *padapter);
+
+u8 rtw_interface_ps_func23a(struct rtw_adapter *padapter,
+                        enum hal_intf_ps_func efunc_id, u8 *val);
+void rtw_set_ips_deny23a(struct rtw_adapter *padapter, u32 ms);
+int _rtw_pwr_wakeup23a(struct rtw_adapter *padapter, u32 ips_deffer_ms,
+                   const char *caller);
+#define rtw_pwr_wakeup(adapter) _rtw_pwr_wakeup23a(adapter,            \
+        RTW_PWR_STATE_CHK_INTERVAL, __func__)
+#define rtw_pwr_wakeup_ex(adapter, ips_deffer_ms)                      \
+        _rtw_pwr_wakeup23a(adapter, ips_deffer_ms, __func__)
+int rtw_pm_set_ips23a(struct rtw_adapter *padapter, u8 mode);
+int rtw_pm_set_lps23a(struct rtw_adapter *padapter, u8 mode);
+
+#endif  /* __RTL871X_PWRCTRL_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_qos.h b/drivers/staging/rtl8723au/include/rtw_qos.h
new file mode 100644 (file)
index 0000000..68fc5ba
--- /dev/null
@@ -0,0 +1,26 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+#ifndef _RTW_QOS_H_
+#define _RTW_QOS_H_
+
+#include <osdep_service.h>
+
+struct qos_priv        {
+       /* bit mask option: u-apsd, s-apsd, ts, block ack... */
+       unsigned int      qos_option;
+};
+
+#endif /* _RTL871X_QOS_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_recv.h b/drivers/staging/rtl8723au/include/rtw_recv.h
new file mode 100644 (file)
index 0000000..d1866a6
--- /dev/null
@@ -0,0 +1,318 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef _RTW_RECV_H_
+#define _RTW_RECV_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <Hal8723APhyCfg.h>
+
+#define NR_RECVFRAME           256
+
+#define MAX_RXFRAME_CNT                512
+#define MAX_RX_NUMBLKS         (32)
+#define RECVFRAME_HDR_ALIGN    128
+
+#define SNAP_SIZE sizeof(struct ieee80211_snap_hdr)
+
+#define MAX_SUBFRAME_COUNT     64
+
+/* for Rx reordering buffer control */
+struct recv_reorder_ctrl {
+       struct rtw_adapter      *padapter;
+       u8 enable;
+       u16 indicate_seq;/* wstart_b, init_value=0xffff */
+       u16 wend_b;
+       u8 wsize_b;
+       struct rtw_queue pending_recvframe_queue;
+       struct timer_list reordering_ctrl_timer;
+};
+
+struct stainfo_rxcache {
+       u16     tid_rxseq[16];
+/*
+       unsigned short  tid0_rxseq;
+       unsigned short  tid1_rxseq;
+       unsigned short  tid2_rxseq;
+       unsigned short  tid3_rxseq;
+       unsigned short  tid4_rxseq;
+       unsigned short  tid5_rxseq;
+       unsigned short  tid6_rxseq;
+       unsigned short  tid7_rxseq;
+       unsigned short  tid8_rxseq;
+       unsigned short  tid9_rxseq;
+       unsigned short  tid10_rxseq;
+       unsigned short  tid11_rxseq;
+       unsigned short  tid12_rxseq;
+       unsigned short  tid13_rxseq;
+       unsigned short  tid14_rxseq;
+       unsigned short  tid15_rxseq;
+*/
+};
+
+struct smooth_rssi_data {
+       u32     elements[100];  /* array to store values */
+       u32     index;                  /* index to current array to store */
+       u32     total_num;              /* num of valid elements */
+       u32     total_val;              /* sum of valid elements */
+};
+
+struct signal_stat {
+       u8      update_req;             /* used to indicate */
+       u8      avg_val;                /* avg of valid elements */
+       u32     total_num;              /* num of valid elements */
+       u32     total_val;              /* sum of valid elements */
+};
+
+struct phy_info {
+       u8              RxPWDBAll;
+       u8              SignalQuality;   /*  in 0-100 index. */
+       u8              RxMIMOSignalQuality[RF_PATH_MAX]; /* EVM */
+       u8              RxMIMOSignalStrength[RF_PATH_MAX];/* 0~100 */
+       s8              RxPower; /*  in dBm Translate from PWdB */
+       /* Real power in dBm for this packet, no beautification and aggregation.
+        * Keep this raw info to be used for the other procedures.
+        */
+       s8              RecvSignalPower;
+       u8              BTRxRSSIPercentage;
+       u8              SignalStrength; /*  in 0-100 index. */
+       u8              RxPwr[RF_PATH_MAX];/* per-path's pwdb */
+       u8              RxSNR[RF_PATH_MAX];/* per-path's SNR */
+};
+
+
+struct rx_pkt_attrib   {
+       u16     pkt_len;
+       u8      physt;
+       u8      drvinfo_sz;
+       u8      shift_sz;
+       u8      hdrlen; /* the WLAN Header Len */
+       u8      to_fr_ds;
+       u8      amsdu;
+       u8      qos;
+       u8      priority;
+       u8      pw_save;
+       u8      mdata;
+       u16     seq_num;
+       u8      frag_num;
+       u8      mfrag;
+       u8      order;
+       u8      privacy; /* in frame_ctrl field */
+       u8      bdecrypted;
+       /* when 0 indicate no encrypt. when non-zero, indicate the algorith */
+       u8      encrypt;
+       u8      iv_len;
+       u8      icv_len;
+       u8      crc_err;
+       u8      icv_err;
+
+       u16 eth_type;
+
+       u8      dst[ETH_ALEN];
+       u8      src[ETH_ALEN];
+       u8      ta[ETH_ALEN];
+       u8      ra[ETH_ALEN];
+       u8      bssid[ETH_ALEN];
+
+       u8 ack_policy;
+
+       u8      tcpchk_valid; /*  0: invalid, 1: valid */
+       u8      ip_chkrpt; /* 0: incorrect, 1: correct */
+       u8      tcp_chkrpt; /* 0: incorrect, 1: correct */
+       u8      key_index;
+
+       u8      mcs_rate;
+       u8      rxht;
+       u8      sgi;
+       u8      pkt_rpt_type;
+       u32     MacIDValidEntry[2];     /*  64 bits present 64 entry. */
+       struct phy_info phy_info;
+};
+
+/* These definition is used for Rx packet reordering. */
+#define SN_LESS(a, b)          (((a-b) & 0x800) != 0)
+#define SN_EQUAL(a, b)         (a == b)
+#define REORDER_WAIT_TIME      (50) /*  (ms) */
+
+#define RECVBUFF_ALIGN_SZ 8
+
+#define RXDESC_SIZE    24
+#define RXDESC_OFFSET RXDESC_SIZE
+
+struct recv_stat {
+       unsigned int rxdw0;
+       unsigned int rxdw1;
+       unsigned int rxdw2;
+       unsigned int rxdw3;
+       unsigned int rxdw4;
+       unsigned int rxdw5;
+};
+
+/* accesser of recv_priv: rtw_recv_entry23a(dispatch / passive level); \
+ * recv_thread(passive) ; returnpkt(dispatch) ; halt(passive) ;
+ *
+ * using enter_critical section to protect
+ */
+struct recv_priv {
+       spinlock_t      lock;
+
+       struct rtw_queue        free_recv_queue;
+       struct rtw_queue        recv_pending_queue;
+       struct rtw_queue        uc_swdec_pending_queue;
+
+       void *pallocated_frame_buf;
+
+       uint free_recvframe_cnt;
+
+       struct rtw_adapter      *adapter;
+
+       u32     bIsAnyNonBEPkts;
+       u64     rx_bytes;
+       u64     rx_pkts;
+       u64     rx_drop;
+       u64     last_rx_bytes;
+
+       uint  rx_icv_err;
+       uint  rx_largepacket_crcerr;
+       uint  rx_smallpacket_crcerr;
+       uint  rx_middlepacket_crcerr;
+
+       /* u8 *pallocated_urb_buf; */
+       struct semaphore allrxreturnevt;
+       uint    ff_hwaddr;
+       u8      rx_pending_cnt;
+
+       struct urb *int_in_urb;
+
+       u8      *int_in_buf;
+
+       struct tasklet_struct irq_prepare_beacon_tasklet;
+       struct tasklet_struct recv_tasklet;
+       struct sk_buff_head free_recv_skb_queue;
+       struct sk_buff_head rx_skb_queue;
+       u8 *precv_buf;
+       struct rtw_queue        free_recv_buf_queue;
+       u32     free_recv_buf_queue_cnt;
+
+       /* For display the phy informatiom */
+       u8 is_signal_dbg;       /*  for debug */
+       u8 signal_strength_dbg; /*  for debug */
+       s8 rssi;
+       s8 rxpwdb;
+       u8 signal_strength;
+       u8 signal_qual;
+       u8 noise;
+       int RxSNRdB[2];
+       s8 RxRssi[2];
+       int FalseAlmCnt_all;
+
+       struct timer_list signal_stat_timer;
+       u32 signal_stat_sampling_interval;
+       /* u32 signal_stat_converging_constant; */
+       struct signal_stat signal_qual_data;
+       struct signal_stat signal_strength_data;
+};
+
+#define rtw_set_signal_stat_timer(recvpriv)                    \
+        mod_timer(&(recvpriv)->signal_stat_timer, jiffies +    \
+                  msecs_to_jiffies((recvpriv)->signal_stat_sampling_interval))
+
+struct sta_recv_priv {
+       spinlock_t      lock;
+       int     option;
+
+       /* struct rtw_queue     blk_strms[MAX_RX_NUMBLKS]; */
+       struct rtw_queue defrag_q;       /* keeping the fragment frame until defrag */
+
+       struct  stainfo_rxcache rxcache;
+
+       /* uint sta_rx_bytes; */
+       /* uint sta_rx_pkts; */
+       /* uint sta_rx_fail; */
+
+};
+
+
+struct recv_buf {
+       struct list_head list;
+
+       struct rtw_adapter *adapter;
+
+       struct urb *purb;
+       struct sk_buff *pskb;
+};
+
+/*     head  ----->
+ *
+ *             data  ----->
+ *
+ *                     payload
+ *
+ *             tail  ----->
+ *
+ *     end   ----->
+ *
+ *     len = (unsigned int )(tail - data);
+ *
+ */
+struct recv_frame {
+       struct list_head        list;
+       struct sk_buff *pkt;
+
+       struct rtw_adapter  *adapter;
+
+       struct rx_pkt_attrib attrib;
+
+       struct sta_info *psta;
+
+       /* for A-MPDU Rx reordering buffer control */
+       struct recv_reorder_ctrl *preorder_ctrl;
+};
+
+/* get a free recv_frame from pfree_recv_queue */
+struct recv_frame *rtw_alloc_recvframe23a(struct rtw_queue *pfree_recv_queue);
+int rtw_free_recvframe23a(struct recv_frame *precvframe, struct rtw_queue *pfree_recv_queue);
+
+int rtw_enqueue_recvframe23a(struct recv_frame *precvframe, struct rtw_queue *queue);
+
+void rtw_free_recvframe23a_queue(struct rtw_queue *pframequeue, struct rtw_queue *pfree_recv_queue);
+u32 rtw_free_uc_swdec_pending_queue23a(struct rtw_adapter *adapter);
+
+int rtw_enqueue_recvbuf23a_to_head(struct recv_buf *precvbuf, struct rtw_queue *queue);
+int rtw_enqueue_recvbuf23a(struct recv_buf *precvbuf, struct rtw_queue *queue);
+struct recv_buf *rtw_dequeue_recvbuf23a(struct rtw_queue *queue);
+
+void rtw_reordering_ctrl_timeout_handler23a(unsigned long pcontext);
+
+static inline s32 translate_percentage_to_dbm(u32 SignalStrengthIndex)
+{
+       s32     SignalPower; /*  in dBm. */
+
+       /*  Translate to dBm (x=0.5y-95). */
+       SignalPower = (s32)((SignalStrengthIndex + 1) >> 1);
+       SignalPower -= 95;
+
+       return SignalPower;
+}
+
+
+struct sta_info;
+
+void _rtw_init_sta_recv_priv23a(struct sta_recv_priv *psta_recvpriv);
+
+void mgt_dispatcher23a(struct rtw_adapter *padapter,
+                   struct recv_frame *precv_frame);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtw_rf.h b/drivers/staging/rtl8723au/include/rtw_rf.h
new file mode 100644 (file)
index 0000000..91a0a22
--- /dev/null
@@ -0,0 +1,113 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef        __RTW_RF_H_
+#define __RTW_RF_H_
+
+#include <rtw_cmd.h>
+
+#define OFDM_PHY               1
+#define MIXED_PHY              2
+#define CCK_PHY                        3
+
+#define NumRates               (13)
+
+/*  slot time for 11g */
+#define SHORT_SLOT_TIME                        9
+#define NON_SHORT_SLOT_TIME            20
+
+/*  We now define the max channels in each channel plan. */
+#define        MAX_CHANNEL_NUM_2G      14
+#define        MAX_CHANNEL_NUM_5G      24
+#define        MAX_CHANNEL_NUM         38/* 14+24 */
+
+/* define NUM_REGULATORYS      21 */
+#define NUM_REGULATORYS        1
+
+/* Country codes */
+#define USA            0x555320
+#define EUROPE         0x1 /* temp, should be provided later */
+#define JAPAN          0x2 /* temp, should be provided later */
+
+struct regulatory_class {
+       u32     starting_freq;                                  /* MHz, */
+       u8      channel_set[MAX_CHANNEL_NUM];
+       u8      channel_cck_power[MAX_CHANNEL_NUM];/* dbm */
+       u8      channel_ofdm_power[MAX_CHANNEL_NUM];/* dbm */
+       u8      txpower_limit;                                  /* dbm */
+       u8      channel_spacing;                                /* MHz */
+       u8      modem;
+};
+
+enum {
+       cESS            = 0x0001,
+       cIBSS           = 0x0002,
+       cPollable       = 0x0004,
+       cPollReq        = 0x0008,
+       cPrivacy        = 0x0010,
+       cShortPreamble  = 0x0020,
+       cPBCC           = 0x0040,
+       cChannelAgility = 0x0080,
+       cSpectrumMgnt   = 0x0100,
+       cQos            = 0x0200,       /*  For HCCA, use with CF-Pollable and CF-PollReq */
+       cShortSlotTime  = 0x0400,
+       cAPSD           = 0x0800,
+       cRM             = 0x1000,       /*  RRM (Radio Request Measurement) */
+       cDSSS_OFDM      = 0x2000,
+       cDelayedBA      = 0x4000,
+       cImmediateBA    = 0x8000,
+};
+
+enum {
+       PREAMBLE_LONG   = 1,
+       PREAMBLE_AUTO   = 2,
+       PREAMBLE_SHORT  = 3,
+};
+
+/*  Bandwidth Offset */
+#define HAL_PRIME_CHNL_OFFSET_DONT_CARE        0
+#define HAL_PRIME_CHNL_OFFSET_LOWER    1
+#define HAL_PRIME_CHNL_OFFSET_UPPER    2
+
+/*  Represent Channel Width in HT Capabilities */
+enum ht_channel_width {
+       HT_CHANNEL_WIDTH_20 = 0,
+       HT_CHANNEL_WIDTH_40 = 1,
+       HT_CHANNEL_WIDTH_80 = 2,
+       HT_CHANNEL_WIDTH_160 = 3,
+       HT_CHANNEL_WIDTH_10 = 4,
+};
+
+/*  */
+/*  Represent Extention Channel Offset in HT Capabilities */
+/*  This is available only in 40Mhz mode. */
+/*  */
+enum {
+       HT_EXTCHNL_OFFSET_NO_EXT = 0,
+       HT_EXTCHNL_OFFSET_UPPER = 1,
+       HT_EXTCHNL_OFFSET_NO_DEF = 2,
+       HT_EXTCHNL_OFFSET_LOWER = 3,
+};
+
+/* 2007/11/15 MH Define different RF type. */
+enum {
+       RF_1T2R = 0,
+       RF_2T4R = 1,
+       RF_2T2R = 2,
+       RF_1T1R = 3,
+       RF_2T2R_GREEN = 4,
+       RF_819X_MAX_TYPE = 5,
+};
+
+#endif /* _RTL8711_RF_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_security.h b/drivers/staging/rtl8723au/include/rtw_security.h
new file mode 100644 (file)
index 0000000..75bbb93
--- /dev/null
@@ -0,0 +1,357 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __RTW_SECURITY_H_
+#define __RTW_SECURITY_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+
+#define _NO_PRIVACY_           0x0
+#define _WEP40_                        0x1
+#define _TKIP_                 0x2
+#define _TKIP_WTMIC_           0x3
+#define _AES_                  0x4
+#define _WEP104_               0x5
+#define _WEP_WPA_MIXED_        0x07  /*  WEP + WPA */
+#define _SMS4_                 0x06
+
+#define is_wep_enc(alg) (((alg) == _WEP40_) || ((alg) == _WEP104_))
+
+#define _WPA_IE_ID_    0xdd
+#define _WPA2_IE_ID_   0x30
+
+#define SHA256_MAC_LEN 32
+#define AES_BLOCK_SIZE 16
+#define AES_PRIV_SIZE (4 * 44)
+
+enum ENCRYP_PROTOCOL {
+       ENCRYP_PROTOCOL_OPENSYS,   /* open system */
+       ENCRYP_PROTOCOL_WEP,       /* WEP */
+       ENCRYP_PROTOCOL_WPA,       /* WPA */
+       ENCRYP_PROTOCOL_WPA2,      /* WPA2 */
+       ENCRYP_PROTOCOL_MAX
+};
+
+#ifndef Ndis802_11AuthModeWPA2
+#define Ndis802_11AuthModeWPA2 (Ndis802_11AuthModeWPANone + 1)
+#endif
+
+#ifndef Ndis802_11AuthModeWPA2PSK
+#define Ndis802_11AuthModeWPA2PSK (Ndis802_11AuthModeWPANone + 2)
+#endif
+
+union pn48 {
+       u64     val;
+
+#ifdef __LITTLE_ENDIAN
+
+struct {
+       u8 TSC0;
+       u8 TSC1;
+       u8 TSC2;
+       u8 TSC3;
+       u8 TSC4;
+       u8 TSC5;
+       u8 TSC6;
+       u8 TSC7;
+} _byte_;
+
+#elif defined(__BIG_ENDIAN)
+
+struct {
+       u8 TSC7;
+       u8 TSC6;
+       u8 TSC5;
+       u8 TSC4;
+       u8 TSC3;
+       u8 TSC2;
+       u8 TSC1;
+       u8 TSC0;
+} _byte_;
+#else
+#error Need BIG or LITTLE endian
+
+#endif
+
+};
+
+union Keytype {
+       u8   skey[16];
+       u32    lkey[4];
+};
+
+
+struct rt_pmkid_list {
+       u8      bUsed;
+       u8      Bssid[6];
+       u8      PMKID[16];
+       u8      SsidBuf[33];
+       u8      *ssid_octet;
+       u16     ssid_length;
+};
+
+struct security_priv {
+       u32       dot11AuthAlgrthm;     /*  802.11 auth, could be open, shared,
+                                        * 8021x and authswitch */
+       u32       dot11PrivacyAlgrthm;  /* This specifies the privacy for
+                                        * shared auth. algorithm.
+                                        */
+       /* WEP */
+       u32       dot11PrivacyKeyIndex; /*  this is only valid for legendary
+                                        * wep, 0~3 for key id. (tx key index)
+                                        */
+       union Keytype dot11DefKey[4];   /*  this is only valid for def. key */
+       u32     dot11DefKeylen[4];
+
+       u32 dot118021XGrpPrivacy;       /* specify the privacy algthm.
+                                        * used for Grp key
+                                        */
+       u32     dot118021XGrpKeyid;     /*  key id used for Grp Key
+                                        * (tx key index)
+                                        */
+       union Keytype   dot118021XGrpKey[4];/* 802.1x Grp Key, inx0 and inx1 */
+       union Keytype   dot118021XGrptxmickey[4];
+       union Keytype   dot118021XGrprxmickey[4];
+       union pn48      dot11Grptxpn;           /* PN48 used for Grp Key xmit.*/
+       union pn48      dot11Grprxpn;           /* PN48 used for Grp Key recv.*/
+
+#ifdef CONFIG_8723AU_AP_MODE
+       /* extend security capabilities for AP_MODE */
+       unsigned int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */
+       unsigned int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */
+       unsigned int wpa_group_cipher;
+       unsigned int wpa2_group_cipher;
+       unsigned int wpa_pairwise_cipher;
+       unsigned int wpa2_pairwise_cipher;
+#endif
+
+       u8 wps_ie[MAX_WPS_IE_LEN];/* added in assoc req */
+       int wps_ie_len;
+       u8      binstallGrpkey;
+       u8      busetkipkey;
+       u8      bcheck_grpkey;
+       u8      bgrpkey_handshake;
+       s32     hw_decrypted;
+       u32 ndisauthtype;       /*  enum ndis_802_11_auth_mode */
+       u32 ndisencryptstatus;  /*  NDIS_802_11_ENCRYPTION_STATUS */
+       struct wlan_bssid_ex sec_bss;  /* for joinbss (h2c buffer) usage */
+       struct ndis_802_11_wep ndiswep;
+       u8 assoc_info[600];
+       u8 szofcapability[256]; /* for wpa2 usage */
+       u8 oidassociation[512]; /* for wpa/wpa2 usage */
+       u8 authenticator_ie[256];  /* store ap security information element */
+       u8 supplicant_ie[256];  /* store sta security information element */
+
+       /* for tkip countermeasure */
+       unsigned long last_mic_err_time;
+       u8      btkip_countermeasure;
+       u8      btkip_wait_report;
+       unsigned long btkip_countermeasure_time;
+
+       /*  For WPA2 Pre-Authentication. */
+       struct rt_pmkid_list PMKIDList[NUM_PMKID_CACHE];
+       u8 PMKIDIndex;
+       u8 bWepDefaultKeyIdxSet;
+};
+
+struct sha256_state {
+       u64 length;
+       u32 state[8], curlen;
+       u8 buf[64];
+};
+
+#define GET_ENCRY_ALGO(psecuritypriv, psta, encry_algo, bmcst)\
+do {\
+       switch (psecuritypriv->dot11AuthAlgrthm) {\
+       case dot11AuthAlgrthm_Open:\
+       case dot11AuthAlgrthm_Shared:\
+       case dot11AuthAlgrthm_Auto:\
+               encry_algo = (u8)psecuritypriv->dot11PrivacyAlgrthm;\
+               break;\
+       case dot11AuthAlgrthm_8021X:\
+               if (bmcst)\
+                       encry_algo = (u8)psecuritypriv->dot118021XGrpPrivacy;\
+               else\
+                       encry_algo = (u8)psta->dot118021XPrivacy;\
+               break;\
+       }       \
+} while (0)
+
+#define GET_TKIP_PN(iv, dot11txpn)\
+do {\
+       dot11txpn._byte_.TSC0 = iv[2];\
+       dot11txpn._byte_.TSC1 = iv[0];\
+       dot11txpn._byte_.TSC2 = iv[4];\
+       dot11txpn._byte_.TSC3 = iv[5];\
+       dot11txpn._byte_.TSC4 = iv[6];\
+       dot11txpn._byte_.TSC5 = iv[7];\
+} while (0)
+
+#define ROL32(A, n)  (((A) << (n)) | (((A)>>(32-(n)))  & ((1UL << (n)) - 1)))
+#define ROR32(A, n)  ROL32((A), 32-(n))
+
+struct mic_data {
+       u32  K0, K1;         /*  Key */
+       u32  L, R;           /*  Current state */
+       u32  M;              /*  Message accumulator (single word) */
+       u32     nBytesInM;      /*  # bytes in M */
+};
+
+extern const u32 Te0[256];
+extern const u32 Te1[256];
+extern const u32 Te2[256];
+extern const u32 Te3[256];
+extern const u32 Te4[256];
+extern const u32 Td0[256];
+extern const u32 Td1[256];
+extern const u32 Td2[256];
+extern const u32 Td3[256];
+extern const u32 Td4[256];
+extern const u32 rcon[10];
+extern const u8 Td4s[256];
+extern const u8 rcons[10];
+
+#define RCON(i) (rcons[(i)] << 24)
+
+static inline u32 rotr(u32 val, int bits)
+{
+       return (val >> bits) | (val << (32 - bits));
+}
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
+#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
+#define TE3(i) rotr(Te0[(i) & 0xff], 24)
+#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
+#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
+#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
+#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
+#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
+#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
+#define TD3(i) rotr(Td0[(i) & 0xff], 24)
+#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
+#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
+#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
+#define TD44(i) (Td4s[(i) & 0xff])
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
+#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
+#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
+
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
+                       ((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+
+#define PUTU32(ct, st) { \
+(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
+(ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+
+#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
+                        (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
+
+#define WPA_PUT_LE16(a, val)                   \
+       do {                                    \
+               (a)[1] = ((u16) (val)) >> 8;    \
+               (a)[0] = ((u16) (val)) & 0xff;  \
+       } while (0)
+
+#define WPA_PUT_BE32(a, val)                                   \
+       do {                                                    \
+               (a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff);   \
+               (a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff);   \
+               (a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff);    \
+               (a)[3] = (u8) (((u32) (val)) & 0xff);           \
+       } while (0)
+
+#define WPA_PUT_BE64(a, val)                           \
+       do {                                            \
+               (a)[0] = (u8) (((u64) (val)) >> 56);    \
+               (a)[1] = (u8) (((u64) (val)) >> 48);    \
+               (a)[2] = (u8) (((u64) (val)) >> 40);    \
+               (a)[3] = (u8) (((u64) (val)) >> 32);    \
+               (a)[4] = (u8) (((u64) (val)) >> 24);    \
+               (a)[5] = (u8) (((u64) (val)) >> 16);    \
+               (a)[6] = (u8) (((u64) (val)) >> 8);     \
+               (a)[7] = (u8) (((u64) (val)) & 0xff);   \
+       } while (0)
+
+/* ===== start - public domain SHA256 implementation ===== */
+
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+/* the K array */
+static const unsigned long K[64] = {
+       0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+       0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+       0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+       0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+       0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+       0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+       0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+       0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+       0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+       0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+       0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+       0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+       0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+/* Various logical functions */
+#define RORc(x, y) \
+(((((unsigned long)(x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
+((unsigned long)(x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define Ch(x, y, z)     (z ^ (x & (y ^ z)))
+#define Maj(x, y, z)    (((x | y) & z) | (x & y))
+#define S(x, n)         RORc((x), (n))
+#define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+void rtw_secmicsetkey23a(struct mic_data *pmicdata, u8 *key);
+void rtw_secmicappend23abyte23a(struct mic_data *pmicdata, u8 b);
+void rtw_secmicappend23a(struct mic_data *pmicdata, u8 *src, u32 nbBytes);
+void rtw_secgetmic23a(struct mic_data *pmicdata, u8 *dst);
+
+void rtw_seccalctkipmic23a(u8 *key, u8 *header, u8 *data, u32 data_len,
+                       u8 *Miccode, u8 priorityi);
+
+u32 rtw_aes_encrypt23a(struct rtw_adapter *padapter,
+                   struct xmit_frame *pxmitframe);
+u32 rtw_tkip_encrypt23a(struct rtw_adapter *padapter,
+                    struct xmit_frame *pxmitframe);
+void rtw_wep_encrypt23a(struct rtw_adapter *padapter,
+                    struct xmit_frame *pxmitframe);
+u32 rtw_aes_decrypt23a(struct rtw_adapter *padapter,
+                   struct recv_frame *precvframe);
+u32 rtw_tkip_decrypt23a(struct rtw_adapter *padapter,
+                    struct recv_frame *precvframe);
+void rtw_wep_decrypt23a(struct rtw_adapter *padapter, struct recv_frame *precvframe);
+
+void rtw_use_tkipkey_handler23a(void *FunctionContext);
+
+#endif /* __RTL871X_SECURITY_H_ */
diff --git a/drivers/staging/rtl8723au/include/rtw_sreset.h b/drivers/staging/rtl8723au/include/rtw_sreset.h
new file mode 100644 (file)
index 0000000..4c52372
--- /dev/null
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef _RTW_SRESET_C_
+#define _RTW_SRESET_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+enum {
+       SRESET_TGP_NULL = 0,
+       SRESET_TGP_XMIT_STATUS = 1,
+       SRESET_TGP_LINK_STATUS = 2,
+};
+
+struct sreset_priv {
+       struct mutex    silentreset_mutex;
+       u8      silent_reset_inprogress;
+       u8      Wifi_Error_Status;
+       unsigned long last_tx_time;
+       unsigned long last_tx_complete_time;
+
+       s32 dbg_trigger_point;
+};
+
+#include <rtl8723a_hal.h>
+
+#define        WIFI_STATUS_SUCCESS             0
+#define        USB_VEN_REQ_CMD_FAIL    BIT0
+#define        USB_READ_PORT_FAIL              BIT1
+#define        USB_WRITE_PORT_FAIL             BIT2
+#define        WIFI_MAC_TXDMA_ERROR    BIT3
+#define   WIFI_TX_HANG                         BIT4
+#define        WIFI_RX_HANG                            BIT5
+#define                WIFI_IF_NOT_EXIST                       BIT6
+
+void sreset_init_value23a(struct rtw_adapter *padapter);
+void sreset_reset_value23a(struct rtw_adapter *padapter);
+u8 sreset_get_wifi_status23a(struct rtw_adapter *padapter);
+void sreset_set_wifi_error_status23a(struct rtw_adapter *padapter, u32 status);
+void sreset_set_trigger_point(struct rtw_adapter *padapter, s32 tgp);
+bool sreset_inprogress(struct rtw_adapter *padapter);
+void sreset_reset(struct rtw_adapter *padapter);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/rtw_version.h b/drivers/staging/rtl8723au/include/rtw_version.h
new file mode 100644 (file)
index 0000000..c947733
--- /dev/null
@@ -0,0 +1 @@
+#define DRIVERVERSION  "v4.1.6_7336.20130426"
diff --git a/drivers/staging/rtl8723au/include/rtw_xmit.h b/drivers/staging/rtl8723au/include/rtw_xmit.h
new file mode 100644 (file)
index 0000000..65a33a0
--- /dev/null
@@ -0,0 +1,407 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef _RTW_XMIT_H_
+#define _RTW_XMIT_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#define MAX_XMITBUF_SZ         2048
+#define NR_XMITBUFF            4
+
+#define XMITBUF_ALIGN_SZ       512
+
+/*  xmit extension buff defination */
+#define MAX_XMIT_EXTBUF_SZ     1536
+#define NR_XMIT_EXTBUFF                32
+
+#define MAX_NUMBLKS            1
+
+#define XMIT_VO_QUEUE          0
+#define XMIT_VI_QUEUE          1
+#define XMIT_BE_QUEUE          2
+#define XMIT_BK_QUEUE          3
+
+#define VO_QUEUE_INX           0
+#define VI_QUEUE_INX           1
+#define BE_QUEUE_INX           2
+#define BK_QUEUE_INX           3
+#define BCN_QUEUE_INX          4
+#define MGT_QUEUE_INX          5
+#define HIGH_QUEUE_INX         6
+#define TXCMD_QUEUE_INX                7
+
+#define HW_QUEUE_ENTRY         8
+
+#define WEP_IV(pattrib_iv, dot11txpn, keyidx)                          \
+do {                                                                   \
+       pattrib_iv[0] = dot11txpn._byte_.TSC0;                          \
+       pattrib_iv[1] = dot11txpn._byte_.TSC1;                          \
+       pattrib_iv[2] = dot11txpn._byte_.TSC2;                          \
+       pattrib_iv[3] = ((keyidx & 0x3) << 6);                          \
+       dot11txpn.val = (dot11txpn.val == 0xffffff) ? 0 :               \
+                        (dot11txpn.val+1);                             \
+} while (0)
+
+#define TKIP_IV(pattrib_iv, dot11txpn, keyidx)                         \
+do {                                                                   \
+       pattrib_iv[0] = dot11txpn._byte_.TSC1;                          \
+       pattrib_iv[1] = (dot11txpn._byte_.TSC1 | 0x20) & 0x7f;          \
+       pattrib_iv[2] = dot11txpn._byte_.TSC0;                          \
+       pattrib_iv[3] = BIT(5) | ((keyidx & 0x3)<<6);                   \
+       pattrib_iv[4] = dot11txpn._byte_.TSC2;                          \
+       pattrib_iv[5] = dot11txpn._byte_.TSC3;                          \
+       pattrib_iv[6] = dot11txpn._byte_.TSC4;                          \
+       pattrib_iv[7] = dot11txpn._byte_.TSC5;                          \
+       dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 :        \
+                                        (dot11txpn.val+1);             \
+} while (0)
+
+#define AES_IV(pattrib_iv, dot11txpn, keyidx)\
+do {                                                                   \
+       pattrib_iv[0] = dot11txpn._byte_.TSC0;                          \
+       pattrib_iv[1] = dot11txpn._byte_.TSC1;                          \
+       pattrib_iv[2] = 0;                                              \
+       pattrib_iv[3] = BIT(5) | ((keyidx & 0x3) << 6);                 \
+       pattrib_iv[4] = dot11txpn._byte_.TSC2;                          \
+       pattrib_iv[5] = dot11txpn._byte_.TSC3;                          \
+       pattrib_iv[6] = dot11txpn._byte_.TSC4;                          \
+       pattrib_iv[7] = dot11txpn._byte_.TSC5;                          \
+       dot11txpn.val = dot11txpn.val == 0xffffffffffffULL ? 0 :        \
+                                        (dot11txpn.val+1);             \
+} while (0)
+
+#define HWXMIT_ENTRY   4
+
+#define TXDESC_SIZE 32
+
+#define PACKET_OFFSET_SZ 8
+#define TXDESC_OFFSET (TXDESC_SIZE + PACKET_OFFSET_SZ)
+
+struct tx_desc {
+       /* DWORD 0 */
+       unsigned int txdw0;
+       unsigned int txdw1;
+       unsigned int txdw2;
+       unsigned int txdw3;
+       unsigned int txdw4;
+       unsigned int txdw5;
+       unsigned int txdw6;
+       unsigned int txdw7;
+};
+
+union txdesc {
+       struct tx_desc txdesc;
+       unsigned int value[TXDESC_SIZE>>2];
+};
+
+struct hw_xmit {
+       struct rtw_queue *sta_queue;
+       int     accnt;
+};
+
+/* reduce size */
+struct pkt_attrib {
+       u8      type;
+       u8      subtype;
+       u8      bswenc;
+       u8      dhcp_pkt;
+       u16     ether_type;
+       u16     seqnum;
+       u16     pkt_hdrlen;     /* the original 802.3 pkt header len */
+       u16     hdrlen;         /* the WLAN Header Len */
+       u32     pktlen;         /* the original 802.3 pkt raw_data len */
+       u32     last_txcmdsz;
+       u8      nr_frags;
+       u8      encrypt;        /* when 0 indicate no encrypt. */
+       u8      iv_len;
+       u8      icv_len;
+       u8      iv[18];
+       u8      icv[16];
+       u8      priority;
+       u8      ack_policy;
+       u8      mac_id;
+       u8      vcs_mode;       /* virtual carrier sense method */
+       u8      dst[ETH_ALEN];
+       u8      src[ETH_ALEN];
+       u8      ta[ETH_ALEN];
+       u8      ra[ETH_ALEN];
+       u8      key_idx;
+       u8      qos_en;
+       u8      ht_en;
+       u8      raid;/* rate adpative id */
+       u8      bwmode;
+       u8      ch_offset;/* PRIME_CHNL_OFFSET */
+       u8      sgi;/* short GI */
+       u8      ampdu_en;/* tx ampdu enable */
+       u8      mdata;/* more data bit */
+       u8      pctrl;/* per packet txdesc control enable */
+       u8      triggered;/* for ap mode handling Power Saving sta */
+       u8      qsel;
+       u8      eosp;
+       u8      rate;
+       u8      retry_ctrl;
+       struct sta_info *psta;
+};
+
+#define WLANHDR_OFFSET         64
+
+#define NULL_FRAMETAG          0x0
+#define DATA_FRAMETAG          0x01
+#define L2_FRAMETAG            0x02
+#define MGNT_FRAMETAG          0x03
+#define AMSDU_FRAMETAG         0x04
+
+#define EII_FRAMETAG           0x05
+#define IEEE8023_FRAMETAG      0x06
+
+#define MP_FRAMETAG            0x07
+
+#define TXAGG_FRAMETAG         0x08
+
+struct  submit_ctx {
+       u32 timeout_ms; /* <0: not synchronous, 0: wait forever,
+                        * >0: up to ms waiting
+                        */
+       int status; /* status for operation */
+       struct completion done;
+};
+
+enum {
+       RTW_SCTX_SUBMITTED = -1,
+       RTW_SCTX_DONE_SUCCESS = 0,
+       RTW_SCTX_DONE_UNKNOWN,
+       RTW_SCTX_DONE_TIMEOUT,
+       RTW_SCTX_DONE_BUF_ALLOC,
+       RTW_SCTX_DONE_BUF_FREE,
+       RTW_SCTX_DONE_WRITE_PORT_ERR,
+       RTW_SCTX_DONE_TX_DESC_NA,
+       RTW_SCTX_DONE_TX_DENY,
+       RTW_SCTX_DONE_CCX_PKT_FAIL,
+       RTW_SCTX_DONE_DRV_STOP,
+       RTW_SCTX_DONE_DEV_REMOVE,
+};
+
+void rtw_sctx_init23a(struct submit_ctx *sctx, int timeout_ms);
+int rtw_sctx_wait23a(struct submit_ctx *sctx);
+void rtw23a_sctx_done_err(struct submit_ctx **sctx, int status);
+void rtw_sctx_done23a(struct submit_ctx **sctx);
+
+struct xmit_buf {
+       struct list_head list, list2;
+       struct rtw_adapter *padapter;
+
+       u8 *pallocated_buf;
+       u8 *pbuf;
+       void *priv_data;
+
+       u16 ext_tag; /*  0: Normal xmitbuf, 1: extension xmitbuf. */
+       u16 flags;
+       u32 alloc_sz;
+       u32  len;
+       struct submit_ctx *sctx;
+       u32     ff_hwaddr;
+       struct urb *pxmit_urb[8];
+       u8 bpending[8];
+       int last[8];
+#if defined(DBG_XMIT_BUF) || defined(DBG_XMIT_BUF_EXT)
+       u8 no;
+#endif
+};
+
+struct xmit_frame {
+       struct list_head        list;
+       struct pkt_attrib attrib;
+       struct sk_buff *pkt;
+       int     frame_tag;
+       struct rtw_adapter *padapter;
+       u8      *buf_addr;
+       struct xmit_buf *pxmitbuf;
+
+       s8      pkt_offset;
+
+       u8 ack_report;
+
+       u8 ext_tag; /* 0:data, 1:mgmt */
+};
+
+struct tx_servq {
+       struct list_head        tx_pending;
+       struct rtw_queue        sta_pending;
+       int qcnt;
+};
+
+struct sta_xmit_priv {
+       spinlock_t      lock;
+       int     option;
+       int     apsd_setting;   /* When bit mask is on, the associated edca
+                                * queue supports APSD.
+                                */
+       struct tx_servq be_q;                   /* priority == 0,3 */
+       struct tx_servq bk_q;                   /* priority == 1,2 */
+       struct tx_servq vi_q;                   /* priority == 4,5 */
+       struct tx_servq vo_q;                   /* priority == 6,7 */
+       struct list_head legacy_dz;
+       struct list_head apsd;
+       u16 txseq_tid[16];
+};
+
+struct hw_txqueue {
+       volatile int head;
+       volatile int tail;
+       volatile int free_sz;   /* in units of 64 bytes */
+       volatile int free_cmdsz;
+       volatile int txsz[8];
+       uint    ff_hwaddr;
+       uint    cmd_hwaddr;
+       int     ac_tag;
+};
+
+struct agg_pkt_info {
+       u16 offset;
+       u16 pkt_len;
+};
+
+struct xmit_priv {
+       spinlock_t      lock;
+
+       struct semaphore        xmit_sema;
+       struct semaphore        terminate_xmitthread_sema;
+
+       struct rtw_queue        be_pending;
+       struct rtw_queue        bk_pending;
+       struct rtw_queue        vi_pending;
+       struct rtw_queue        vo_pending;
+       struct rtw_queue        bm_pending;
+
+       u8 *pallocated_frame_buf;
+       u8 *pxmit_frame_buf;
+       uint free_xmitframe_cnt;
+       struct rtw_queue        free_xmit_queue;
+
+       u8 *xframe_ext_alloc_addr;
+       u8 *xframe_ext;
+       uint free_xframe_ext_cnt;
+       struct rtw_queue free_xframe_ext_queue;
+
+       uint    frag_len;
+
+       struct rtw_adapter      *adapter;
+
+       u8   vcs_setting;
+       u8      vcs;
+       u8      vcs_type;
+
+       u64     tx_bytes;
+       u64     tx_pkts;
+       u64     tx_drop;
+       u64     last_tx_bytes;
+       u64     last_tx_pkts;
+
+       struct hw_xmit *hwxmits;
+       u8      hwxmit_entry;
+
+       u8      wmm_para_seq[4];/* sequence for wmm ac parameter strength from
+                                * large to small. it's value is 0->vo, 1->vi,
+                                * 2->be, 3->bk.
+                                */
+
+       struct semaphore        tx_retevt;/* all tx return event; */
+       u8              txirp_cnt;/*  */
+
+       struct tasklet_struct xmit_tasklet;
+       /* per AC pending irp */
+       int beq_cnt;
+       int bkq_cnt;
+       int viq_cnt;
+       int voq_cnt;
+
+       struct rtw_queue free_xmitbuf_queue;
+       struct list_head xmitbuf_list;          /* track buffers for cleanup */
+       struct rtw_queue pending_xmitbuf_queue;
+       uint free_xmitbuf_cnt;
+
+       struct rtw_queue free_xmit_extbuf_queue;
+       struct list_head xmitextbuf_list;       /* track buffers for cleanup */
+       uint free_xmit_extbuf_cnt;
+
+       u16     nqos_ssn;
+       int     ack_tx;
+       struct mutex ack_tx_mutex;
+       struct submit_ctx ack_tx_ops;
+       spinlock_t lock_sctx;
+};
+
+struct xmit_buf *rtw_alloc_xmitbuf23a_ext(struct xmit_priv *pxmitpriv);
+s32 rtw_free_xmitbuf_ext23a(struct xmit_priv *pxmitpriv,
+                        struct xmit_buf *pxmitbuf);
+
+struct xmit_buf *rtw_alloc_xmitbuf23a(struct xmit_priv *pxmitpriv);
+s32 rtw_free_xmitbuf23a(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf);
+
+void rtw_count_tx_stats23a(struct rtw_adapter *padapter,
+                       struct xmit_frame *pxmitframe, int sz);
+void rtw_update_protection23a(struct rtw_adapter *padapter, u8 *ie, uint ie_len);
+s32 rtw_make_wlanhdr23a(struct rtw_adapter *padapter, u8 *hdr,
+                    struct pkt_attrib *pattrib);
+s32 rtw_put_snap23a(u8 *data, u16 h_proto);
+struct xmit_frame *rtw_alloc_xmitframe23a(struct xmit_priv *pxmitpriv);
+struct xmit_frame *rtw_alloc_xmitframe23a_ext(struct xmit_priv *pxmitpriv);
+struct xmit_frame *rtw_alloc_xmitframe23a_once(struct xmit_priv *pxmitpriv);
+s32 rtw_free_xmitframe23a(struct xmit_priv *pxmitpriv,
+                      struct xmit_frame *pxmitframe);
+void rtw_free_xmitframe_queue23a(struct xmit_priv *pxmitpriv, struct rtw_queue *pframequeue);
+struct tx_servq *rtw_get_sta_pending23a(struct rtw_adapter *padapter,
+                                    struct sta_info *psta, int up, u8 *ac);
+s32 rtw_xmitframe_enqueue23a(struct rtw_adapter *padapter,
+                            struct xmit_frame *pxmitframe);
+struct xmit_frame *rtw_dequeue_xframe23a(struct xmit_priv *pxmitpriv,
+                                     struct hw_xmit *phwxmit_i, int entry);
+s32 rtw_xmit23a_classifier(struct rtw_adapter *padapter,
+                       struct xmit_frame *pxmitframe);
+u32 rtw_calculate_wlan_pkt_size_by_attribue23a(struct pkt_attrib *pattrib);
+#define rtw_wlan_pkt_size(f) rtw_calculate_wlan_pkt_size_by_attribue23a(&f->attrib)
+s32 rtw_xmitframe_coalesce23a(struct rtw_adapter *padapter, struct sk_buff *pkt,
+                             struct xmit_frame *pxmitframe);
+s32 _rtw_init_hw_txqueue(struct hw_txqueue *phw_txqueue, u8 ac_tag);
+void _rtw_init_sta_xmit_priv23a(struct sta_xmit_priv *psta_xmitpriv);
+
+s32 rtw_txframes_pending23a(struct rtw_adapter *padapter);
+s32 rtw_txframes_sta_ac_pending23a(struct rtw_adapter *padapter,
+                               struct pkt_attrib *pattrib);
+void rtw_init_hwxmits23a(struct hw_xmit *phwxmit, int entry);
+s32 _rtw_init_xmit_priv23a(struct xmit_priv *pxmitpriv,
+                       struct rtw_adapter *padapter);
+void _rtw_free_xmit_priv23a(struct xmit_priv *pxmitpriv);
+void rtw_alloc_hwxmits23a(struct rtw_adapter *padapter);
+void rtw_free_hwxmits23a(struct rtw_adapter *padapter);
+int rtw_xmit23a(struct rtw_adapter *padapter, struct sk_buff *pkt);
+#if defined(CONFIG_8723AU_AP_MODE)
+int xmitframe_enqueue_for_sleeping_sta23a(struct rtw_adapter *padapter,
+                                      struct xmit_frame *pxmitframe);
+void stop_sta_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta);
+void wakeup_sta_to_xmit23a(struct rtw_adapter *padapter, struct sta_info *psta);
+void xmit_delivery_enabled_frames23a(struct rtw_adapter *padapter,
+                                 struct sta_info *psta);
+#endif
+u8     qos_acm23a(u8 acm_mask, u8 priority);
+u32    rtw_get_ff_hwaddr23a(struct xmit_frame  *pxmitframe);
+int rtw_ack_tx_wait23a(struct xmit_priv *pxmitpriv, u32 timeout_ms);
+void rtw_ack_tx_done23a(struct xmit_priv *pxmitpriv, int status);
+
+/* include after declaring struct xmit_buf, in order to avoid warning */
+#include <xmit_osdep.h>
+
+#endif /* _RTL871X_XMIT_H_ */
diff --git a/drivers/staging/rtl8723au/include/sta_info.h b/drivers/staging/rtl8723au/include/sta_info.h
new file mode 100644 (file)
index 0000000..ffbc9e3
--- /dev/null
@@ -0,0 +1,385 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __STA_INFO_H_
+#define __STA_INFO_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <wifi.h>
+
+#define IBSS_START_MAC_ID      2
+#define NUM_STA 32
+#define NUM_ACL 16
+
+
+/* if mode ==0, then the sta is allowed once the addr is hit. */
+/* if mode ==1, then the sta is rejected once the addr is non-hit. */
+struct rtw_wlan_acl_node {
+       struct list_head        list;
+       u8       addr[ETH_ALEN];
+       u8       valid;
+};
+
+/* mode=0, disable */
+/* mode=1, accept unless in deny list */
+/* mode=2, deny unless in accept list */
+struct wlan_acl_pool {
+       int mode;
+       int num;
+       struct rtw_wlan_acl_node aclnode[NUM_ACL];
+       struct rtw_queue        acl_node_q;
+};
+
+struct rssi_sta  {
+       s32     UndecoratedSmoothedPWDB;
+       s32     UndecoratedSmoothedCCK;
+       s32     UndecoratedSmoothedOFDM;
+       u64     PacketMap;
+       u8      ValidBit;
+};
+
+struct stainfo_stats   {
+       u64 rx_mgnt_pkts;
+               u64 rx_beacon_pkts;
+               u64 rx_probereq_pkts;
+               u64 rx_probersp_pkts;
+               u64 rx_probersp_bm_pkts;
+               u64 rx_probersp_uo_pkts;
+       u64 rx_ctrl_pkts;
+       u64 rx_data_pkts;
+
+       u64     last_rx_mgnt_pkts;
+               u64 last_rx_beacon_pkts;
+               u64 last_rx_probereq_pkts;
+               u64 last_rx_probersp_pkts;
+               u64 last_rx_probersp_bm_pkts;
+               u64 last_rx_probersp_uo_pkts;
+       u64     last_rx_ctrl_pkts;
+       u64     last_rx_data_pkts;
+
+       u64     rx_bytes;
+       u64     rx_drops;
+
+       u64     tx_pkts;
+       u64     tx_bytes;
+       u64  tx_drops;
+
+};
+
+struct sta_info {
+       spinlock_t      lock;
+       struct list_head        list; /* free_sta_queue */
+       struct list_head        hash_list; /* sta_hash */
+       struct rtw_adapter *padapter;
+
+       struct sta_xmit_priv sta_xmitpriv;
+       struct sta_recv_priv sta_recvpriv;
+
+       struct rtw_queue sleep_q;
+       unsigned int sleepq_len;
+
+       uint state;
+       uint aid;
+       uint mac_id;
+       uint qos_option;
+       u8      hwaddr[ETH_ALEN];
+
+       uint    ieee8021x_blocked;      /* 0: allowed, 1:blocked */
+       uint    dot118021XPrivacy; /* aes, tkip... */
+       union Keytype   dot11tkiptxmickey;
+       union Keytype   dot11tkiprxmickey;
+       union Keytype   dot118021x_UncstKey;
+       union pn48              dot11txpn;                      /*  PN48 used for Unicast xmit. */
+       union pn48              dot11rxpn;                      /*  PN48 used for Unicast recv. */
+
+
+       u8      bssrateset[16];
+       u32     bssratelen;
+       s32  rssi;
+       s32     signal_quality;
+
+       u8      cts2self;
+       u8      rtsen;
+
+       u8      raid;
+       u8      init_rate;
+       u32     ra_mask;
+       u8      wireless_mode;  /*  NETWORK_TYPE */
+       struct stainfo_stats sta_stats;
+
+       /* for A-MPDU TX, ADDBA timeout check */
+       struct timer_list addba_retry_timer;
+
+       /* for A-MPDU Rx reordering buffer control */
+       struct recv_reorder_ctrl recvreorder_ctrl[16];
+
+       /* for A-MPDU Tx */
+       /* unsigned char                ampdu_txen_bitmap; */
+       u16     BA_starting_seqctrl[16];
+
+       struct ht_priv  htpriv;
+
+       /* Notes: */
+       /* STA_Mode: */
+       /* curr_network(mlme_priv/security_priv/qos/ht) + sta_info: (STA & AP) CAP/INFO */
+       /* scan_q: AP CAP/INFO */
+
+       /* AP_Mode: */
+       /* curr_network(mlme_priv/security_priv/qos/ht) : AP CAP/INFO */
+       /* sta_info: (AP & STA) CAP/INFO */
+
+       struct list_head asoc_list;
+       struct list_head auth_list;
+
+       unsigned int expire_to;
+       unsigned int auth_seq;
+       unsigned int authalg;
+       unsigned char chg_txt[128];
+
+       u16 capability;
+       int flags;
+
+       int dot8021xalg;/* 0:disable, 1:psk, 2:802.1x */
+       int wpa_psk;/* 0:disable, bit(0): WPA, bit(1):WPA2 */
+       int wpa_group_cipher;
+       int wpa2_group_cipher;
+       int wpa_pairwise_cipher;
+       int wpa2_pairwise_cipher;
+
+       u8 bpairwise_key_installed;
+
+       u8 wpa_ie[32];
+
+       u8 nonerp_set;
+       u8 no_short_slot_time_set;
+       u8 no_short_preamble_set;
+       u8 no_ht_gf_set;
+       u8 no_ht_set;
+       u8 ht_20mhz_set;
+
+       unsigned int tx_ra_bitmap;
+       u8 qos_info;
+
+       u8 max_sp_len;
+       u8 uapsd_bk;/* BIT(0): Delivery enabled, BIT(1): Trigger enabled */
+       u8 uapsd_be;
+       u8 uapsd_vi;
+       u8 uapsd_vo;
+
+       u8 has_legacy_ac;
+       unsigned int sleepq_ac_len;
+
+       /* p2p priv data */
+       u8 is_p2p_device;
+       u8 p2p_status_code;
+
+       u8 keep_alive_trycnt;
+
+       /* p2p client info */
+       u8 dev_addr[ETH_ALEN];
+       u8 dev_cap;
+       u16 config_methods;
+       u8 primary_dev_type[8];
+       u8 num_of_secdev_type;
+       u8 secdev_types_list[32];/*  32/8 == 4; */
+       u16 dev_name_len;
+       u8 dev_name[32];
+       u8 *passoc_req;
+       u32 assoc_req_len;
+
+       /* for DM */
+       struct rssi_sta  rssi_stat;
+
+       /*  */
+       /*  ================ODM Relative Info======================= */
+       /*  Please be care, dont declare too much structure here. It will cost memory * STA support num. */
+       /*  */
+       /*  */
+       /*  2011/10/20 MH Add for ODM STA info. */
+       /*  */
+       /*  Driver Write */
+       u8              bValid;                         /*  record the sta status link or not? */
+       u8              IOTPeer;                        /*  Enum value. HT_IOT_PEER_E */
+       u8              rssi_level;                     /* for Refresh RA mask */
+       /*  ODM Write */
+       /* 1 PHY_STATUS_INFO */
+       u8              RSSI_Path[4];           /*  */
+       u8              RSSI_Ave;
+       u8              RXEVM[4];
+       u8              RXSNR[4];
+
+       /*  ODM Write */
+       /* 1 TX_INFO (may changed by IC) */
+       /*  ================ODM Relative Info======================= */
+       /*  */
+
+       /* To store the sequence number of received management frame */
+       u16 RxMgmtFrameSeqNum;
+};
+
+#define sta_rx_pkts(sta) \
+       (sta->sta_stats.rx_mgnt_pkts \
+       + sta->sta_stats.rx_ctrl_pkts \
+       + sta->sta_stats.rx_data_pkts)
+
+#define sta_last_rx_pkts(sta) \
+       (sta->sta_stats.last_rx_mgnt_pkts \
+       + sta->sta_stats.last_rx_ctrl_pkts \
+       + sta->sta_stats.last_rx_data_pkts)
+
+#define sta_rx_data_pkts(sta) \
+       (sta->sta_stats.rx_data_pkts)
+
+#define sta_last_rx_data_pkts(sta) \
+       (sta->sta_stats.last_rx_data_pkts)
+
+#define sta_rx_mgnt_pkts(sta) \
+       (sta->sta_stats.rx_mgnt_pkts)
+
+#define sta_last_rx_mgnt_pkts(sta) \
+       (sta->sta_stats.last_rx_mgnt_pkts)
+
+#define sta_rx_beacon_pkts(sta) \
+       (sta->sta_stats.rx_beacon_pkts)
+
+#define sta_last_rx_beacon_pkts(sta) \
+       (sta->sta_stats.last_rx_beacon_pkts)
+
+#define sta_rx_probereq_pkts(sta) \
+       (sta->sta_stats.rx_probereq_pkts)
+
+#define sta_last_rx_probereq_pkts(sta) \
+       (sta->sta_stats.last_rx_probereq_pkts)
+
+#define sta_rx_probersp_pkts(sta) \
+       (sta->sta_stats.rx_probersp_pkts)
+
+#define sta_last_rx_probersp_pkts(sta) \
+       (sta->sta_stats.last_rx_probersp_pkts)
+
+#define sta_rx_probersp_bm_pkts(sta) \
+       (sta->sta_stats.rx_probersp_bm_pkts)
+
+#define sta_last_rx_probersp_bm_pkts(sta) \
+       (sta->sta_stats.last_rx_probersp_bm_pkts)
+
+#define sta_rx_probersp_uo_pkts(sta) \
+       (sta->sta_stats.rx_probersp_uo_pkts)
+
+#define sta_last_rx_probersp_uo_pkts(sta) \
+       (sta->sta_stats.last_rx_probersp_uo_pkts)
+
+#define sta_update_last_rx_pkts(sta) \
+       do { \
+               sta->sta_stats.last_rx_mgnt_pkts = sta->sta_stats.rx_mgnt_pkts; \
+               sta->sta_stats.last_rx_beacon_pkts = sta->sta_stats.rx_beacon_pkts; \
+               sta->sta_stats.last_rx_probereq_pkts = sta->sta_stats.rx_probereq_pkts; \
+               sta->sta_stats.last_rx_probersp_pkts = sta->sta_stats.rx_probersp_pkts; \
+               sta->sta_stats.last_rx_probersp_bm_pkts = sta->sta_stats.rx_probersp_bm_pkts; \
+               sta->sta_stats.last_rx_probersp_uo_pkts = sta->sta_stats.rx_probersp_uo_pkts; \
+               sta->sta_stats.last_rx_ctrl_pkts = sta->sta_stats.rx_ctrl_pkts; \
+               sta->sta_stats.last_rx_data_pkts = sta->sta_stats.rx_data_pkts; \
+       } while (0)
+
+#define STA_RX_PKTS_ARG(sta) \
+       sta->sta_stats.rx_mgnt_pkts \
+       , sta->sta_stats.rx_ctrl_pkts \
+       , sta->sta_stats.rx_data_pkts
+
+#define STA_LAST_RX_PKTS_ARG(sta) \
+       sta->sta_stats.last_rx_mgnt_pkts, \
+       sta->sta_stats.last_rx_ctrl_pkts, \
+       sta->sta_stats.last_rx_data_pkts
+
+#define STA_RX_PKTS_DIFF_ARG(sta) \
+       sta->sta_stats.rx_mgnt_pkts - sta->sta_stats.last_rx_mgnt_pkts, \
+       sta->sta_stats.rx_ctrl_pkts - sta->sta_stats.last_rx_ctrl_pkts, \
+       sta->sta_stats.rx_data_pkts - sta->sta_stats.last_rx_data_pkts
+
+#define STA_PKTS_FMT "(m:%llu, c:%llu, d:%llu)"
+
+struct sta_priv {
+       u8 *pallocated_stainfo_buf;
+       u8 *pstainfo_buf;
+       struct rtw_queue        free_sta_queue;
+
+       spinlock_t sta_hash_lock;
+       struct list_head   sta_hash[NUM_STA];
+       int asoc_sta_count;
+       struct rtw_queue sleep_q;
+       struct rtw_queue wakeup_q;
+
+       struct rtw_adapter *padapter;
+       struct list_head asoc_list;
+       struct list_head auth_list;
+       spinlock_t asoc_list_lock;
+       spinlock_t auth_list_lock;
+       u8 asoc_list_cnt;
+       u8 auth_list_cnt;
+
+       unsigned int auth_to;  /* sec, time to expire in authenticating. */
+       unsigned int assoc_to; /* sec, time to expire before associating. */
+       unsigned int expire_to; /* sec , time to expire after associated. */
+
+       /* pointers to STA info; based on allocated AID or NULL if AID free
+        * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
+        * and so on
+        */
+       struct sta_info *sta_aid[NUM_STA];
+
+       u16 sta_dz_bitmap;/* only support 15 stations, staion aid bitmap
+                          * for sleeping sta. */
+       u16 tim_bitmap;/* only support 15 stations,
+                       * aid=0~15 mapping bit0~bit15 */
+
+       u16 max_num_sta;
+
+       struct wlan_acl_pool acl_list;
+};
+
+static inline u32 wifi_mac_hash(u8 *mac)
+{
+       u32 x;
+
+       x = mac[0];
+       x = (x << 2) ^ mac[1];
+       x = (x << 2) ^ mac[2];
+       x = (x << 2) ^ mac[3];
+       x = (x << 2) ^ mac[4];
+       x = (x << 2) ^ mac[5];
+
+       x ^= x >> 8;
+       x  = x & (NUM_STA - 1);
+
+       return x;
+}
+
+u32    _rtw_init_sta_priv23a(struct sta_priv *pstapriv);
+u32    _rtw_free_sta_priv23a(struct sta_priv *pstapriv);
+
+#define stainfo_offset_valid(offset) (offset < NUM_STA && offset >= 0)
+int rtw_stainfo_offset23a(struct sta_priv *stapriv, struct sta_info *sta);
+struct sta_info *rtw_get_stainfo23a_by_offset23a(struct sta_priv *stapriv,
+                                          int offset);
+
+struct sta_info *rtw_alloc_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr);
+u32 rtw_free_stainfo23a(struct rtw_adapter *padapter, struct sta_info *psta);
+void rtw_free_all_stainfo23a(struct rtw_adapter *padapter);
+struct sta_info *rtw_get_stainfo23a(struct sta_priv *pstapriv, u8 *hwaddr);
+u32 rtw_init_bcmc_stainfo23a(struct rtw_adapter *padapter);
+struct sta_info *rtw_get_bcmc_stainfo23a(struct rtw_adapter *padapter);
+u8 rtw_access_ctrl23a(struct rtw_adapter *padapter, u8 *mac_addr);
+
+#endif /* _STA_INFO_H_ */
diff --git a/drivers/staging/rtl8723au/include/usb_hal.h b/drivers/staging/rtl8723au/include/usb_hal.h
new file mode 100644 (file)
index 0000000..4edec3b
--- /dev/null
@@ -0,0 +1,20 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __USB_HAL_H__
+#define __USB_HAL_H__
+
+int rtl8723au_set_hal_ops(struct rtw_adapter *padapter);
+
+#endif /* __USB_HAL_H__ */
diff --git a/drivers/staging/rtl8723au/include/usb_ops.h b/drivers/staging/rtl8723au/include/usb_ops.h
new file mode 100644 (file)
index 0000000..55d1380
--- /dev/null
@@ -0,0 +1,97 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __USB_OPS_H_
+#define __USB_OPS_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <osdep_intf.h>
+#include <usb_ops_linux.h>
+
+#define REALTEK_USB_VENQT_READ         0xC0
+#define REALTEK_USB_VENQT_WRITE                0x40
+#define REALTEK_USB_VENQT_CMD_REQ      0x05
+#define REALTEK_USB_VENQT_CMD_IDX      0x00
+
+enum {
+       VENDOR_WRITE = 0x00,
+       VENDOR_READ = 0x01,
+};
+
+#define ALIGNMENT_UNIT                         16
+#define MAX_VENDOR_REQ_CMD_SIZE        254             /* 8188cu SIE Support */
+#define MAX_USB_IO_CTL_SIZE    (MAX_VENDOR_REQ_CMD_SIZE +ALIGNMENT_UNIT)
+
+#define rtw_usb_control_msg(dev, pipe, request, requesttype, value,    \
+                           index, data, size, timeout_ms)              \
+       usb_control_msg((dev), (pipe), (request), (requesttype),        \
+                       (value), (index), (data), (size), (timeout_ms))
+#define rtw_usb_bulk_msg(usb_dev, pipe, data, len, actual_length, timeout_ms) \
+       usb_bulk_msg((usb_dev), (pipe), (data), (len), (actual_length), \
+                    (timeout_ms))
+
+void rtl8723au_set_hw_type(struct rtw_adapter *padapter);
+#define hal_set_hw_type rtl8723au_set_hw_type
+
+void rtl8723au_set_intf_ops(struct _io_ops *pops);
+#define usb_set_intf_ops rtl8723au_set_intf_ops
+
+void rtl8723au_recv_tasklet(void *priv);
+
+void rtl8723au_xmit_tasklet(void *priv);
+
+/* Increase and check if the continual_urb_error of this @param dvobjprive is
+ * larger than MAX_CONTINUAL_URB_ERR. Return result
+ */
+static inline int rtw_inc_and_chk_continual_urb_error(struct dvobj_priv *dvobj)
+{
+       int ret = false;
+       int value;
+
+       value = atomic_inc_return(&dvobj->continual_urb_error);
+       if (value > MAX_CONTINUAL_URB_ERR) {
+               DBG_8723A("[dvobj:%p][ERROR] continual_urb_error:%d > %d\n",
+                         dvobj, value, MAX_CONTINUAL_URB_ERR);
+               ret = true;
+       }
+       return ret;
+}
+
+/* Set the continual_urb_error of this @param dvobjprive to 0 */
+static inline void rtw_reset_continual_urb_error(struct dvobj_priv *dvobj)
+{
+       atomic_set(&dvobj->continual_urb_error, 0);
+}
+
+#define USB_HIGH_SPEED_BULK_SIZE       512
+#define USB_FULL_SPEED_BULK_SIZE       64
+
+static inline u8 rtw_usb_bulk_size_boundary(struct rtw_adapter *padapter,
+                                           int buf_len)
+{
+       u8 rst = true;
+       struct dvobj_priv *pdvobjpriv = adapter_to_dvobj(padapter);
+
+       if (pdvobjpriv->ishighspeed)
+               rst = (0 == (buf_len) % USB_HIGH_SPEED_BULK_SIZE) ?
+                     true : false;
+       else
+               rst = (0 == (buf_len) % USB_FULL_SPEED_BULK_SIZE) ?
+                     true : false;
+       return rst;
+}
+
+
+#endif /* __USB_OPS_H_ */
diff --git a/drivers/staging/rtl8723au/include/usb_ops_linux.h b/drivers/staging/rtl8723au/include/usb_ops_linux.h
new file mode 100644 (file)
index 0000000..8f5c59e
--- /dev/null
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __USB_OPS_LINUX_H__
+#define __USB_OPS_LINUX_H__
+
+#define VENDOR_CMD_MAX_DATA_LEN        254
+
+#define RTW_USB_CONTROL_MSG_TIMEOUT_TEST       10/* ms */
+#define RTW_USB_CONTROL_MSG_TIMEOUT    500/* ms */
+
+#define MAX_USBCTRL_VENDORREQ_TIMES    10
+
+#define RTW_USB_BULKOUT_TIMEOUT        5000/* ms */
+
+#define _usbctrl_vendorreq_async_callback(urb, regs)           \
+       _usbctrl_vendorreq_async_callback(urb)
+#define usb_write_mem23a_complete(purb, regs)  usb_write_mem23a_complete(purb)
+#define usb_write_port23a_complete(purb, regs) usb_write_port23a_complete(purb)
+#define usb_read_port_complete(purb, regs)     usb_read_port_complete(purb)
+#define usb_read_interrupt_complete(purb, regs)                        \
+       usb_read_interrupt_complete(purb)
+
+unsigned int ffaddr2pipehdl23a(struct dvobj_priv *pdvobj, u32 addr);
+
+void usb_read_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem);
+void usb_write_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem);
+
+void usb_read_port_cancel23a(struct intf_hdl *pintfhdl);
+
+u32 usb_write_port23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+                  struct xmit_buf *wmem);
+void usb_write_port23a_cancel(struct intf_hdl *pintfhdl);
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/usb_osintf.h b/drivers/staging/rtl8723au/include/usb_osintf.h
new file mode 100644 (file)
index 0000000..4608766
--- /dev/null
@@ -0,0 +1,24 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __USB_OSINTF_H
+#define __USB_OSINTF_H
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <usb_vendor_req.h>
+
+#define USBD_HALTED(_status) ((u32)(_status) >> 30 == 3)
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/usb_vendor_req.h b/drivers/staging/rtl8723au/include/usb_vendor_req.h
new file mode 100644 (file)
index 0000000..eb4508e
--- /dev/null
@@ -0,0 +1,31 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef _USB_VENDOR_REQUEST_H_
+#define _USB_VENDOR_REQUEST_H_
+
+/* 4   Set/Get Register related wIndex/Data */
+#define        RT_USB_RESET_MASK_OFF           0
+#define        RT_USB_RESET_MASK_ON            1
+#define        RT_USB_SLEEP_MASK_OFF           0
+#define        RT_USB_SLEEP_MASK_ON            1
+#define        RT_USB_LDO_ON                   1
+#define        RT_USB_LDO_OFF                  0
+
+/* 4   Set/Get SYSCLK related  wValue or Data */
+#define        RT_USB_SYSCLK_32KHZ             0
+#define        RT_USB_SYSCLK_40MHZ             1
+#define        RT_USB_SYSCLK_60MHZ             2
+
+#endif
diff --git a/drivers/staging/rtl8723au/include/wifi.h b/drivers/staging/rtl8723au/include/wifi.h
new file mode 100644 (file)
index 0000000..b5034c6
--- /dev/null
@@ -0,0 +1,707 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef _WIFI_H_
+#define _WIFI_H_
+
+#define P80211CAPTURE_VERSION  0x80211001
+
+/*  This value is tested by WiFi 11n Test Plan 5.2.3.
+ *  This test verifies the WLAN NIC can update the NAV through sending
+ *  the CTS with large duration.
+ */
+#define        WiFiNavUpperUs          30000   /*  30 ms */
+
+enum WIFI_FRAME_TYPE {
+       WIFI_MGT_TYPE  =        (0),
+       WIFI_CTRL_TYPE =        (BIT(2)),
+       WIFI_DATA_TYPE =        (BIT(3)),
+       WIFI_QOS_DATA_TYPE      = (BIT(7)|BIT(3)),      /*  QoS Data */
+};
+
+enum WIFI_FRAME_SUBTYPE {
+       /*  below is for mgt frame */
+       WIFI_ASSOCREQ = (0 | WIFI_MGT_TYPE),
+       WIFI_ASSOCRSP = (BIT(4) | WIFI_MGT_TYPE),
+       WIFI_REASSOCREQ = (BIT(5) | WIFI_MGT_TYPE),
+       WIFI_REASSOCRSP = (BIT(5) | BIT(4) | WIFI_MGT_TYPE),
+       WIFI_PROBEREQ = (BIT(6) | WIFI_MGT_TYPE),
+       WIFI_PROBERSP = (BIT(6) | BIT(4) | WIFI_MGT_TYPE),
+       WIFI_BEACON = (BIT(7) | WIFI_MGT_TYPE),
+       WIFI_ATIM = (BIT(7) | BIT(4) | WIFI_MGT_TYPE),
+       WIFI_DISASSOC = (BIT(7) | BIT(5) | WIFI_MGT_TYPE),
+       WIFI_AUTH = (BIT(7) | BIT(5) | BIT(4) | WIFI_MGT_TYPE),
+       WIFI_DEAUTH = (BIT(7) | BIT(6) | WIFI_MGT_TYPE),
+       WIFI_ACTION = (BIT(7) | BIT(6) | BIT(4) | WIFI_MGT_TYPE),
+
+       /*  below is for control frame */
+       WIFI_PSPOLL = (BIT(7) | BIT(5) | WIFI_CTRL_TYPE),
+       WIFI_RTS = (BIT(7) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE),
+       WIFI_CTS = (BIT(7) | BIT(6) | WIFI_CTRL_TYPE),
+       WIFI_ACK = (BIT(7) | BIT(6) | BIT(4) | WIFI_CTRL_TYPE),
+       WIFI_CFEND = (BIT(7) | BIT(6) | BIT(5) | WIFI_CTRL_TYPE),
+       WIFI_CFEND_CFACK = (BIT(7) | BIT(6) | BIT(5) | BIT(4) | WIFI_CTRL_TYPE),
+
+       /*  below is for data frame */
+       WIFI_DATA = (0 | WIFI_DATA_TYPE),
+       WIFI_DATA_CFACK = (BIT(4) | WIFI_DATA_TYPE),
+       WIFI_DATA_CFPOLL = (BIT(5) | WIFI_DATA_TYPE),
+       WIFI_DATA_CFACKPOLL = (BIT(5) | BIT(4) | WIFI_DATA_TYPE),
+       WIFI_DATA_NULL = (BIT(6) | WIFI_DATA_TYPE),
+       WIFI_CF_ACK = (BIT(6) | BIT(4) | WIFI_DATA_TYPE),
+       WIFI_CF_POLL = (BIT(6) | BIT(5) | WIFI_DATA_TYPE),
+       WIFI_CF_ACKPOLL = (BIT(6) | BIT(5) | BIT(4) | WIFI_DATA_TYPE),
+       WIFI_QOS_DATA_NULL = (BIT(6) | WIFI_QOS_DATA_TYPE),
+};
+
+
+enum WIFI_REG_DOMAIN {
+       DOMAIN_FCC              = 1,
+       DOMAIN_IC               = 2,
+       DOMAIN_ETSI             = 3,
+       DOMAIN_SPAIN            = 4,
+       DOMAIN_FRANCE           = 5,
+       DOMAIN_MKK              = 6,
+       DOMAIN_ISRAEL           = 7,
+       DOMAIN_MKK1             = 8,
+       DOMAIN_MKK2             = 9,
+       DOMAIN_MKK3             = 10,
+       DOMAIN_MAX
+};
+
+
+#define SetToDs(pbuf)  \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_TODS))
+
+#define SetFrDs(pbuf)  \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_FROMDS))
+
+#define get_tofr_ds(pframe)    ((ieee80211_has_tods(pframe) << 1) | \
+                                ieee80211_has_fromds(pframe))
+
+#define SetMFrag(pbuf) \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREFRAGS))
+
+#define ClearMFrag(pbuf)       \
+       (*(unsigned short *)(pbuf) &= (~cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)))
+
+#define SetRetry(pbuf) \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_RETRY))
+
+#define SetPwrMgt(pbuf)        \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PM))
+
+#define SetMData(pbuf) \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_MOREDATA))
+
+#define SetPrivacy(pbuf)       \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16(IEEE80211_FCTL_PROTECTED))
+
+#define SetFrameType(pbuf, type)       \
+       do {    \
+               *(unsigned short *)(pbuf) &= __constant_cpu_to_le16(~(BIT(3) | BIT(2))); \
+               *(unsigned short *)(pbuf) |= __constant_cpu_to_le16(type); \
+       } while (0)
+
+#define SetFrameSubType(pbuf, type) \
+       do {    \
+               *(unsigned short *)(pbuf) &= cpu_to_le16(~(BIT(7) | BIT(6) | BIT(5) | BIT(4) | BIT(3) | BIT(2))); \
+               *(unsigned short *)(pbuf) |= cpu_to_le16(type); \
+       } while (0)
+
+#define GetTupleCache(pbuf)    (cpu_to_le16(*(unsigned short *)((unsigned long)(pbuf) + 22)))
+
+#define SetFragNum(pbuf, num) \
+       do {    \
+               *(unsigned short *)((unsigned long)(pbuf) + 22) = \
+                       ((*(unsigned short *)((unsigned long)(pbuf) + 22)) & le16_to_cpu(~(0x000f))) | \
+                       cpu_to_le16(0x0f & (num));     \
+       } while (0)
+
+#define SetSeqNum(pbuf, num) \
+       do {    \
+               *(unsigned short *)((unsigned long)(pbuf) + 22) = \
+                       ((*(unsigned short *)((unsigned long)(pbuf) + 22)) & le16_to_cpu((unsigned short)0x000f)) | \
+                       le16_to_cpu((unsigned short)(0xfff0 & (num << 4))); \
+       } while (0)
+
+#define SetDuration(pbuf, dur) \
+       (*(unsigned short *)((unsigned long)(pbuf) + 2) =               \
+        cpu_to_le16(0xffff & (dur)))
+
+#define SetPriority(pbuf, tid) \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16(tid & 0xf))
+
+#define SetEOSP(pbuf, eosp)    \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16((eosp & 1) << 4))
+
+#define SetAckpolicy(pbuf, ack)        \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16((ack & 3) << 5))
+
+#define SetAMsdu(pbuf, amsdu)  \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16((amsdu & 1) << 7))
+
+#define GetAid(pbuf)                                                   \
+       (cpu_to_le16(*(unsigned short *)((unsigned long)(pbuf) + 2)) &  \
+        0x3fff)
+
+#define GetTid(pbuf)                                                   \
+       (cpu_to_le16(*(unsigned short *)((unsigned long)(pbuf) +        \
+        (((ieee80211_has_tods(pbuf)<<1) |                              \
+        ieee80211_has_fromds(pbuf)) == 3 ? 30 : 24))) & 0x000f)
+
+static inline unsigned char *get_hdr_bssid(unsigned char *pframe)
+{
+       unsigned char   *sa;
+       unsigned int    to_fr_ds;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) pframe;
+
+       to_fr_ds = (ieee80211_has_tods(hdr->frame_control) << 1) |
+                   ieee80211_has_fromds(hdr->frame_control);
+
+       switch (to_fr_ds) {
+       case 0x00:      /*  ToDs=0, FromDs=0 */
+               sa = hdr->addr3;
+               break;
+       case 0x01:      /*  ToDs=0, FromDs=1 */
+               sa = hdr->addr2;
+               break;
+       case 0x02:      /*  ToDs=1, FromDs=0 */
+               sa = hdr->addr1;
+               break;
+       case 0x03:      /*  ToDs=1, FromDs=1 */
+               sa = hdr->addr1;
+               break;
+       default:
+               sa = NULL; /*  */
+               break;
+       }
+       return sa;
+}
+
+/*-----------------------------------------------------------------------------
+                       Below is for the security related definition
+------------------------------------------------------------------------------*/
+#define _RESERVED_FRAME_TYPE_          0
+#define _SKB_FRAME_TYPE_               2
+#define _PRE_ALLOCMEM_                 1
+#define _PRE_ALLOCHDR_                 3
+#define _PRE_ALLOCLLCHDR_              4
+#define _PRE_ALLOCICVHDR_              5
+#define _PRE_ALLOCMICHDR_              6
+
+#define _SIFSTIME_                                     \
+       ((priv->pmib->dot11BssType.net_work_type & WIRELESS_11A) ? 16 : 10)
+#define _ACKCTSLNG_                    14      /* 14 bytes long, including crclng */
+#define _CRCLNG_                       4
+
+#define _ASOCREQ_IE_OFFSET_            4       /*  excluding wlan_hdr */
+#define        _ASOCRSP_IE_OFFSET_             6
+#define _REASOCREQ_IE_OFFSET_          10
+#define _REASOCRSP_IE_OFFSET_          6
+#define _PROBEREQ_IE_OFFSET_           0
+#define        _PROBERSP_IE_OFFSET_            12
+#define _AUTH_IE_OFFSET_               6
+#define _DEAUTH_IE_OFFSET_             0
+#define _BEACON_IE_OFFSET_             12
+#define _PUBLIC_ACTION_IE_OFFSET_      8
+
+#define _FIXED_IE_LENGTH_              _BEACON_IE_OFFSET_
+
+#define _SSID_IE_                      0
+#define _SUPPORTEDRATES_IE_            1
+#define _DSSET_IE_                     3
+#define _TIM_IE_                       5
+#define _IBSS_PARA_IE_                 6
+#define _COUNTRY_IE_                   7
+#define _CHLGETXT_IE_                  16
+#define _SUPPORTED_CH_IE_              36
+#define _CH_SWTICH_ANNOUNCE_   37      /* Secondary Channel Offset */
+#define _RSN_IE_2_                     48
+#define _SSN_IE_1_                     221
+#define _ERPINFO_IE_                   42
+#define _EXT_SUPPORTEDRATES_IE_                50
+
+#define _HT_CAPABILITY_IE_             45
+#define _FTIE_                         55
+#define _TIMEOUT_ITVL_IE_              56
+#define _SRC_IE_                       59
+#define _HT_EXTRA_INFO_IE_             61
+#define _HT_ADD_INFO_IE_               61 /* _HT_EXTRA_INFO_IE_ */
+
+
+#define        EID_BSSCoexistence              72 /*  20/40 BSS Coexistence */
+#define        EID_BSSIntolerantChlReport      73
+#define _RIC_Descriptor_IE_            75
+
+#define _LINK_ID_IE_           101
+#define _CH_SWITCH_TIMING_     104
+#define _PTI_BUFFER_STATUS_    106
+#define _EXT_CAP_IE_           127
+#define _VENDOR_SPECIFIC_IE_   221
+
+#define        _RESERVED47_            47
+
+/* ---------------------------------------------------------------------------
+                                       Below is the fixed elements...
+-----------------------------------------------------------------------------*/
+#define _AUTH_ALGM_NUM_                2
+#define _AUTH_SEQ_NUM_         2
+#define _BEACON_ITERVAL_       2
+#define _CAPABILITY_           2
+#define _CURRENT_APADDR_       6
+#define _LISTEN_INTERVAL_      2
+#define _ASOC_ID_              2
+#define _STATUS_CODE_          2
+#define _TIMESTAMP_            8
+
+#define AUTH_ODD_TO            0
+#define AUTH_EVEN_TO           1
+
+#define WLAN_ETHCONV_ENCAP     1
+#define WLAN_ETHCONV_RFC1042   2
+#define WLAN_ETHCONV_8021h     3
+
+#define cap_ESS                BIT(0)
+#define cap_IBSS       BIT(1)
+#define cap_CFPollable BIT(2)
+#define cap_CFRequest  BIT(3)
+#define cap_Privacy    BIT(4)
+#define cap_ShortPremble BIT(5)
+#define cap_PBCC       BIT(6)
+#define cap_ChAgility  BIT(7)
+#define cap_SpecMgmt   BIT(8)
+#define cap_QoS                BIT(9)
+#define cap_ShortSlot  BIT(10)
+
+/*-----------------------------------------------------------------------------
+                               Below is the definition for 802.11i / 802.1x
+------------------------------------------------------------------------------*/
+#define _IEEE8021X_MGT_                        1       /*  WPA */
+#define _IEEE8021X_PSK_                        2       /*  WPA with pre-shared key */
+
+/*
+#define _NO_PRIVACY_                   0
+#define _WEP_40_PRIVACY_               1
+#define _TKIP_PRIVACY_                 2
+#define _WRAP_PRIVACY_                 3
+#define _CCMP_PRIVACY_                 4
+#define _WEP_104_PRIVACY_              5
+#define _WEP_WPA_MIXED_PRIVACY_ 6      WEP + WPA
+*/
+
+/*-----------------------------------------------------------------------------
+                               Below is the definition for WMM
+------------------------------------------------------------------------------*/
+#define _WMM_IE_Length_                                7  /*  for WMM STA */
+#define _WMM_Para_Element_Length_              24
+
+
+/*-----------------------------------------------------------------------------
+                               Below is the definition for 802.11n
+------------------------------------------------------------------------------*/
+
+#define SetOrderBit(pbuf)                                              \
+       (*(unsigned short *)(pbuf) |= cpu_to_le16(_ORDER_))
+
+#define GetOrderBit(pbuf)              \
+       (((*(unsigned short *)(pbuf)) & le16_to_cpu(_ORDER_)) != 0)
+
+
+/* struct rtw_ieee80211_ht_cap - HT additional information
+ *
+ * This structure refers to "HT information element" as
+ * described in 802.11n draft section 7.3.2.53
+ */
+struct ieee80211_ht_addt_info {
+       unsigned char   control_chan;
+       unsigned char   ht_param;
+       unsigned short  operation_mode;
+       unsigned short  stbc_param;
+       unsigned char   basic_set[16];
+} __packed;
+
+struct HT_caps_element {
+       union {
+               struct {
+                       unsigned short  HT_caps_info;
+                       unsigned char   AMPDU_para;
+                       unsigned char   MCS_rate[16];
+                       unsigned short  HT_ext_caps;
+                       unsigned int    Beamforming_caps;
+                       unsigned char   ASEL_caps;
+               } HT_cap_element;
+               unsigned char HT_cap[26];
+       } u;
+} __packed;
+
+struct HT_info_element {
+       unsigned char   primary_channel;
+       unsigned char   infos[5];
+       unsigned char   MCS_rate[16];
+}  __packed;
+
+struct AC_param {
+       unsigned char           ACI_AIFSN;
+       unsigned char           CW;
+       unsigned short  TXOP_limit;
+}  __packed;
+
+struct WMM_para_element {
+       unsigned char           QoS_info;
+       unsigned char           reserved;
+       struct AC_param ac_param[4];
+}  __packed;
+
+struct ADDBA_request {
+       unsigned char           dialog_token;
+       unsigned short  BA_para_set;
+       unsigned short  BA_timeout_value;
+       unsigned short  BA_starting_seqctrl;
+}  __packed;
+
+
+#define OP_MODE_PURE                    0
+#define OP_MODE_MAY_BE_LEGACY_STAS      1
+#define OP_MODE_20MHZ_HT_STA_ASSOCED    2
+#define OP_MODE_MIXED                   3
+
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK       ((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE          ((u8) BIT(0))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW          ((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH          ((u8) BIT(2))
+#define HT_INFO_HT_PARAM_RIFS_MODE                     ((u8) BIT(3))
+#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY              ((u8) BIT(4))
+#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY      ((u8) BIT(5))
+
+#define HT_INFO_OPERATION_MODE_OP_MODE_MASK    \
+               ((u16) (0x0001 | 0x0002))
+#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET          0
+#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT     ((u8) BIT(2))
+#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT    ((u8) BIT(3))
+#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT      ((u8) BIT(4))
+
+#define HT_INFO_STBC_PARAM_DUAL_BEACON         ((u16) BIT(6))
+#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT   ((u16) BIT(7))
+#define HT_INFO_STBC_PARAM_SECONDARY_BCN       ((u16) BIT(8))
+#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED   ((u16) BIT(9))
+#define HT_INFO_STBC_PARAM_PCO_ACTIVE          ((u16) BIT(10))
+#define HT_INFO_STBC_PARAM_PCO_PHASE           ((u16) BIT(11))
+
+
+
+/*     ===============WPS Section=============== */
+/*     For WPSv1.0 */
+#define WPSOUI                                 0x0050f204
+/*     WPS attribute ID */
+#define WPS_ATTR_VER1                          0x104A
+#define WPS_ATTR_SIMPLE_CONF_STATE             0x1044
+#define WPS_ATTR_RESP_TYPE                     0x103B
+#define WPS_ATTR_UUID_E                                0x1047
+#define WPS_ATTR_MANUFACTURER                  0x1021
+#define WPS_ATTR_MODEL_NAME                    0x1023
+#define WPS_ATTR_MODEL_NUMBER                  0x1024
+#define WPS_ATTR_SERIAL_NUMBER                 0x1042
+#define WPS_ATTR_PRIMARY_DEV_TYPE              0x1054
+#define WPS_ATTR_SEC_DEV_TYPE_LIST             0x1055
+#define WPS_ATTR_DEVICE_NAME                   0x1011
+#define WPS_ATTR_CONF_METHOD                   0x1008
+#define WPS_ATTR_RF_BANDS                      0x103C
+#define WPS_ATTR_DEVICE_PWID                   0x1012
+#define WPS_ATTR_REQUEST_TYPE                  0x103A
+#define WPS_ATTR_ASSOCIATION_STATE             0x1002
+#define WPS_ATTR_CONFIG_ERROR                  0x1009
+#define WPS_ATTR_VENDOR_EXT                    0x1049
+#define WPS_ATTR_SELECTED_REGISTRAR            0x1041
+
+/*     Value of WPS attribute "WPS_ATTR_DEVICE_NAME */
+#define WPS_MAX_DEVICE_NAME_LEN                        32
+
+/*     Value of WPS Request Type Attribute */
+#define WPS_REQ_TYPE_ENROLLEE_INFO_ONLY                0x00
+#define WPS_REQ_TYPE_ENROLLEE_OPEN_8021X       0x01
+#define WPS_REQ_TYPE_REGISTRAR                 0x02
+#define WPS_REQ_TYPE_WLAN_MANAGER_REGISTRAR    0x03
+
+/*     Value of WPS Response Type Attribute */
+#define WPS_RESPONSE_TYPE_INFO_ONLY            0x00
+#define WPS_RESPONSE_TYPE_8021X                        0x01
+#define WPS_RESPONSE_TYPE_REGISTRAR            0x02
+#define WPS_RESPONSE_TYPE_AP                   0x03
+
+/*     Value of WPS WiFi Simple Configuration State Attribute */
+#define WPS_WSC_STATE_NOT_CONFIG               0x01
+#define WPS_WSC_STATE_CONFIG                   0x02
+
+/*     Value of WPS Version Attribute */
+#define WPS_VERSION_1                          0x10
+
+/*     Value of WPS Configuration Method Attribute */
+#define WPS_CONFIG_METHOD_FLASH                        0x0001
+#define WPS_CONFIG_METHOD_ETHERNET             0x0002
+#define WPS_CONFIG_METHOD_LABEL                        0x0004
+#define WPS_CONFIG_METHOD_DISPLAY              0x0008
+#define WPS_CONFIG_METHOD_E_NFC                        0x0010
+#define WPS_CONFIG_METHOD_I_NFC                        0x0020
+#define WPS_CONFIG_METHOD_NFC                  0x0040
+#define WPS_CONFIG_METHOD_PBC                  0x0080
+#define WPS_CONFIG_METHOD_KEYPAD               0x0100
+#define WPS_CONFIG_METHOD_VPBC                 0x0280
+#define WPS_CONFIG_METHOD_PPBC                 0x0480
+#define WPS_CONFIG_METHOD_VDISPLAY             0x2008
+#define WPS_CONFIG_METHOD_PDISPLAY             0x4008
+
+/*     Value of Category ID of WPS Primary Device Type Attribute */
+#define WPS_PDT_CID_DISPLAYS                   0x0007
+#define WPS_PDT_CID_MULIT_MEDIA                        0x0008
+#define WPS_PDT_CID_RTK_WIDI                   WPS_PDT_CID_MULIT_MEDIA
+
+/*     Value of Sub Category ID of WPS Primary Device Type Attribute */
+#define WPS_PDT_SCID_MEDIA_SERVER              0x0005
+#define WPS_PDT_SCID_RTK_DMP                   WPS_PDT_SCID_MEDIA_SERVER
+
+/*     Value of Device Password ID */
+#define WPS_DPID_PIN                           0x0000
+#define WPS_DPID_USER_SPEC                     0x0001
+#define WPS_DPID_MACHINE_SPEC                  0x0002
+#define WPS_DPID_REKEY                         0x0003
+#define WPS_DPID_PBC                           0x0004
+#define WPS_DPID_REGISTRAR_SPEC                        0x0005
+
+/*     Value of WPS RF Bands Attribute */
+#define WPS_RF_BANDS_2_4_GHZ                   0x01
+#define WPS_RF_BANDS_5_GHZ                     0x02
+
+/*     Value of WPS Association State Attribute */
+#define WPS_ASSOC_STATE_NOT_ASSOCIATED         0x00
+#define WPS_ASSOC_STATE_CONNECTION_SUCCESS     0x01
+#define WPS_ASSOC_STATE_CONFIGURATION_FAILURE  0x02
+#define WPS_ASSOC_STATE_ASSOCIATION_FAILURE    0x03
+#define WPS_ASSOC_STATE_IP_FAILURE             0x04
+
+/*     =====================P2P Section===================== */
+/*     For P2P */
+#define        P2POUI                                  0x506F9A09
+
+/*     P2P Attribute ID */
+#define        P2P_ATTR_STATUS                         0x00
+#define        P2P_ATTR_MINOR_REASON_CODE              0x01
+#define        P2P_ATTR_CAPABILITY                     0x02
+#define        P2P_ATTR_DEVICE_ID                      0x03
+#define        P2P_ATTR_GO_INTENT                      0x04
+#define        P2P_ATTR_CONF_TIMEOUT                   0x05
+#define        P2P_ATTR_LISTEN_CH                      0x06
+#define        P2P_ATTR_GROUP_BSSID                    0x07
+#define        P2P_ATTR_EX_LISTEN_TIMING               0x08
+#define        P2P_ATTR_INTENTED_IF_ADDR               0x09
+#define        P2P_ATTR_MANAGEABILITY                  0x0A
+#define        P2P_ATTR_CH_LIST                        0x0B
+#define        P2P_ATTR_NOA                            0x0C
+#define        P2P_ATTR_DEVICE_INFO                    0x0D
+#define        P2P_ATTR_GROUP_INFO                     0x0E
+#define        P2P_ATTR_GROUP_ID                       0x0F
+#define        P2P_ATTR_INTERFACE                      0x10
+#define        P2P_ATTR_OPERATING_CH                   0x11
+#define        P2P_ATTR_INVITATION_FLAGS               0x12
+
+/*     Value of Status Attribute */
+#define        P2P_STATUS_SUCCESS                      0x00
+#define        P2P_STATUS_FAIL_INFO_UNAVAILABLE        0x01
+#define        P2P_STATUS_FAIL_INCOMPATIBLE_PARAM      0x02
+#define        P2P_STATUS_FAIL_LIMIT_REACHED           0x03
+#define        P2P_STATUS_FAIL_INVALID_PARAM           0x04
+#define        P2P_STATUS_FAIL_REQUEST_UNABLE          0x05
+#define        P2P_STATUS_FAIL_PREVOUS_PROTO_ERR       0x06
+#define        P2P_STATUS_FAIL_NO_COMMON_CH            0x07
+#define        P2P_STATUS_FAIL_UNKNOWN_P2PGROUP        0x08
+#define        P2P_STATUS_FAIL_BOTH_GOINTENT_15        0x09
+#define        P2P_STATUS_FAIL_INCOMPATIBLE_PROVSION   0x0A
+#define        P2P_STATUS_FAIL_USER_REJECT             0x0B
+
+/*     Value of Inviation Flags Attribute */
+#define        P2P_INVITATION_FLAGS_PERSISTENT         BIT(0)
+
+#define        DMP_P2P_DEVCAP_SUPPORT  (P2P_DEVCAP_SERVICE_DISCOVERY | \
+                                P2P_DEVCAP_CLIENT_DISCOVERABILITY | \
+                                P2P_DEVCAP_CONCURRENT_OPERATION | \
+                                P2P_DEVCAP_INVITATION_PROC)
+
+#define        DMP_P2P_GRPCAP_SUPPORT  (P2P_GRPCAP_INTRABSS)
+
+/*     Value of Device Capability Bitmap */
+#define        P2P_DEVCAP_SERVICE_DISCOVERY            BIT(0)
+#define        P2P_DEVCAP_CLIENT_DISCOVERABILITY       BIT(1)
+#define        P2P_DEVCAP_CONCURRENT_OPERATION         BIT(2)
+#define        P2P_DEVCAP_INFRA_MANAGED                BIT(3)
+#define        P2P_DEVCAP_DEVICE_LIMIT                 BIT(4)
+#define        P2P_DEVCAP_INVITATION_PROC              BIT(5)
+
+/*     Value of Group Capability Bitmap */
+#define        P2P_GRPCAP_GO                           BIT(0)
+#define        P2P_GRPCAP_PERSISTENT_GROUP             BIT(1)
+#define        P2P_GRPCAP_GROUP_LIMIT                  BIT(2)
+#define        P2P_GRPCAP_INTRABSS                     BIT(3)
+#define        P2P_GRPCAP_CROSS_CONN                   BIT(4)
+#define        P2P_GRPCAP_PERSISTENT_RECONN            BIT(5)
+#define        P2P_GRPCAP_GROUP_FORMATION              BIT(6)
+
+/*     P2P Public Action Frame ( Management Frame ) */
+#define        P2P_PUB_ACTION_ACTION                   0x09
+
+/*     P2P Public Action Frame Type */
+#define        P2P_GO_NEGO_REQ                         0
+#define        P2P_GO_NEGO_RESP                        1
+#define        P2P_GO_NEGO_CONF                        2
+#define        P2P_INVIT_REQ                           3
+#define        P2P_INVIT_RESP                          4
+#define        P2P_DEVDISC_REQ                         5
+#define        P2P_DEVDISC_RESP                        6
+#define        P2P_PROVISION_DISC_REQ                  7
+#define        P2P_PROVISION_DISC_RESP                 8
+
+/*     P2P Action Frame Type */
+#define        P2P_NOTICE_OF_ABSENCE                   0
+#define        P2P_PRESENCE_REQUEST                    1
+#define        P2P_PRESENCE_RESPONSE                   2
+#define        P2P_GO_DISC_REQUEST                     3
+
+
+#define        P2P_MAX_PERSISTENT_GROUP_NUM            10
+
+#define        P2P_PROVISIONING_SCAN_CNT               3
+
+#define        P2P_WILDCARD_SSID_LEN                   7
+
+#define        P2P_FINDPHASE_EX_NONE                   0       /*  default value, used when: (1)p2p disabed or (2)p2p enabled but only do 1 scan phase */
+#define        P2P_FINDPHASE_EX_FULL                   1       /*  used when p2p enabled and want to do 1 scan phase and P2P_FINDPHASE_EX_MAX-1 find phase */
+#define        P2P_FINDPHASE_EX_SOCIAL_FIRST           (P2P_FINDPHASE_EX_FULL+1)
+#define        P2P_FINDPHASE_EX_MAX                                    4
+#define        P2P_FINDPHASE_EX_SOCIAL_LAST            P2P_FINDPHASE_EX_MAX
+
+#define        P2P_PROVISION_TIMEOUT                   5000    /*5 sec timeout for sending the provision discovery request */
+#define        P2P_CONCURRENT_PROVISION_TIMEOUT        3000    /*3 sec timeout for sending the provision discovery request under concurrent mode */
+#define        P2P_GO_NEGO_TIMEOUT                     5000    /*5 sec timeout for receiving the group negotation response */
+#define        P2P_CONCURRENT_GO_NEGO_TIMEOUT          3000    /*3 sec timeout for sending the negotiation request under concurrent mode */
+#define        P2P_TX_PRESCAN_TIMEOUT                  100     /*100ms */
+#define        P2P_INVITE_TIMEOUT                      5000    /*5 sec timeout for sending the invitation request */
+#define        P2P_CONCURRENT_INVITE_TIMEOUT           3000    /*3 sec timeout for sending the invitation request under concurrent mode */
+#define        P2P_RESET_SCAN_CH                       25000   /*25 sec t/o to reset the scan channel ( based on channel plan ) */
+#define        P2P_MAX_INTENT                          15
+
+#define        P2P_MAX_NOA_NUM                         2
+
+/*     WPS Configuration Method */
+#define        WPS_CM_NONE                                     0x0000
+#define        WPS_CM_LABEL                                    0x0004
+#define        WPS_CM_DISPLYA                                  0x0008
+#define        WPS_CM_EXTERNAL_NFC_TOKEN                       0x0010
+#define        WPS_CM_INTEGRATED_NFC_TOKEN                     0x0020
+#define        WPS_CM_NFC_INTERFACE                            0x0040
+#define        WPS_CM_PUSH_BUTTON                              0x0080
+#define        WPS_CM_KEYPAD                                   0x0100
+#define        WPS_CM_SW_PUHS_BUTTON                           0x0280
+#define        WPS_CM_HW_PUHS_BUTTON                           0x0480
+#define        WPS_CM_SW_DISPLAY_PIN                           0x2008
+#define        WPS_CM_LCD_DISPLAY_PIN                          0x4008
+
+enum P2P_ROLE {
+       P2P_ROLE_DISABLE = 0,
+       P2P_ROLE_DEVICE = 1,
+       P2P_ROLE_CLIENT = 2,
+       P2P_ROLE_GO = 3
+};
+
+enum P2P_STATE {
+       P2P_STATE_NONE = 0,                     /*P2P disable */
+       P2P_STATE_IDLE = 1,                     /*P2P had enabled and do nothing */
+       P2P_STATE_LISTEN = 2,                   /*In pure listen state */
+       P2P_STATE_SCAN = 3,                     /*In scan phase */
+       P2P_STATE_FIND_PHASE_LISTEN = 4,        /*In the listen state of find phase */
+       P2P_STATE_FIND_PHASE_SEARCH = 5,        /*In the search state of find phase */
+       P2P_STATE_TX_PROVISION_DIS_REQ = 6,     /*In P2P provisioning discovery */
+       P2P_STATE_RX_PROVISION_DIS_RSP = 7,
+       P2P_STATE_RX_PROVISION_DIS_REQ = 8,
+       P2P_STATE_GONEGO_ING = 9,               /*Doing the group owner negoitation handshake */
+       P2P_STATE_GONEGO_OK = 10,               /*finish the group negoitation handshake with success */
+       P2P_STATE_GONEGO_FAIL = 11,             /*finish the group negoitation handshake with failure */
+       P2P_STATE_RECV_INVITE_REQ_MATCH = 12,   /*receiving the P2P Inviation request and match with the profile. */
+       P2P_STATE_PROVISIONING_ING = 13,        /*Doing the P2P WPS */
+       P2P_STATE_PROVISIONING_DONE = 14,       /*Finish the P2P WPS */
+       P2P_STATE_TX_INVITE_REQ = 15,           /*Transmit the P2P Invitation request */
+       P2P_STATE_RX_INVITE_RESP_OK = 16,       /*Receiving the P2P Invitation response */
+       P2P_STATE_RECV_INVITE_REQ_DISMATCH = 17,/*receiving the P2P Inviation request and dismatch with the profile. */
+       P2P_STATE_RECV_INVITE_REQ_GO = 18,      /*receiving the P2P Inviation request and this wifi is GO. */
+       P2P_STATE_RECV_INVITE_REQ_JOIN = 19,    /*receiving the P2P Inviation request to join an existing P2P Group. */
+       P2P_STATE_RX_INVITE_RESP_FAIL = 20,     /*receiving the P2P Inviation response with failure */
+       P2P_STATE_RX_INFOR_NOREADY = 21,        /*receiving p2p negotiation response with information is not available */
+       P2P_STATE_TX_INFOR_NOREADY = 22,        /*sending p2p negotiation response with information is not available */
+};
+
+enum P2P_WPSINFO {
+       P2P_NO_WPSINFO                          = 0,
+       P2P_GOT_WPSINFO_PEER_DISPLAY_PIN        = 1,
+       P2P_GOT_WPSINFO_SELF_DISPLAY_PIN        = 2,
+       P2P_GOT_WPSINFO_PBC                     = 3,
+};
+
+#define        P2P_PRIVATE_IOCTL_SET_LEN               64
+
+enum P2P_PROTO_WK_ID {
+       P2P_FIND_PHASE_WK = 0,
+       P2P_RESTORE_STATE_WK = 1,
+       P2P_PRE_TX_PROVDISC_PROCESS_WK = 2,
+       P2P_PRE_TX_NEGOREQ_PROCESS_WK = 3,
+       P2P_PRE_TX_INVITEREQ_PROCESS_WK = 4,
+       P2P_AP_P2P_CH_SWITCH_PROCESS_WK = 5,
+       P2P_RO_CH_WK = 6,
+};
+
+#ifdef CONFIG_8723AU_P2P
+enum P2P_PS_STATE {
+       P2P_PS_DISABLE = 0,
+       P2P_PS_ENABLE = 1,
+       P2P_PS_SCAN = 2,
+       P2P_PS_SCAN_DONE = 3,
+       P2P_PS_ALLSTASLEEP = 4, /*  for P2P GO */
+};
+
+enum P2P_PS_MODE {
+       P2P_PS_NONE = 0,
+       P2P_PS_CTWINDOW = 1,
+       P2P_PS_NOA       = 2,
+       P2P_PS_MIX = 3, /*  CTWindow and NoA */
+};
+#endif /*  CONFIG_8723AU_P2P */
+
+/*     =====================WFD Section===================== */
+/*     For Wi-Fi Display */
+#define        WFD_ATTR_DEVICE_INFO                    0x00
+#define        WFD_ATTR_ASSOC_BSSID                    0x01
+#define        WFD_ATTR_COUPLED_SINK_INFO      0x06
+#define        WFD_ATTR_LOCAL_IP_ADDR          0x08
+#define        WFD_ATTR_SESSION_INFO           0x09
+#define        WFD_ATTR_ALTER_MAC                      0x0a
+
+/*     For WFD Device Information Attribute */
+#define        WFD_DEVINFO_SOURCE                                      0x0000
+#define        WFD_DEVINFO_PSINK                                       0x0001
+#define        WFD_DEVINFO_SSINK                                       0x0002
+#define        WFD_DEVINFO_DUAL                                        0x0003
+
+#define        WFD_DEVINFO_SESSION_AVAIL                       0x0010
+#define        WFD_DEVINFO_WSD                                         0x0040
+#define        WFD_DEVINFO_PC_TDLS                                     0x0080
+#define        WFD_DEVINFO_HDCP_SUPPORT                        0x0100
+
+#endif /*  _WIFI_H_ */
diff --git a/drivers/staging/rtl8723au/include/wlan_bssdef.h b/drivers/staging/rtl8723au/include/wlan_bssdef.h
new file mode 100644 (file)
index 0000000..92287eb
--- /dev/null
@@ -0,0 +1,215 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __WLAN_BSSDEF_H__
+#define __WLAN_BSSDEF_H__
+
+
+#define MAX_IE_SZ      768
+
+
+#define NDIS_802_11_LENGTH_RATES        8
+#define NDIS_802_11_LENGTH_RATES_EX     16
+
+enum ndis_802_11_net_type {
+       Ndis802_11FH,
+       Ndis802_11DS,
+       Ndis802_11OFDM5,
+       Ndis802_11OFDM24,
+       Ndis802_11NetworkTypeMax    /*  just an upper bound */
+};
+
+struct ndis_802_11_configuration_fh {
+       u32           Length;             /*  Length of structure */
+       u32           HopPattern;         /*  As defined by 802.11, MSB set */
+       u32           HopSet;             /*  to one if non-802.11 */
+       u32           DwellTime;          /*  units are Kusec */
+};
+
+
+/*
+       FW will only save the channel number in DSConfig.
+       ODI Handler will convert the channel number to freq. number.
+*/
+struct ndis_802_11_config {
+       u32           Length;             /*  Length of structure */
+       u32           BeaconPeriod;       /*  units are Kusec */
+       u32           ATIMWindow;         /*  units are Kusec */
+       u32           DSConfig;           /*  Frequency, units are kHz */
+       struct ndis_802_11_configuration_fh    FHConfig;
+};
+
+enum ndis_802_11_net_infra {
+       Ndis802_11IBSS,
+       Ndis802_11Infrastructure,
+       Ndis802_11AutoUnknown,
+       Ndis802_11InfrastructureMax,     /*  Not a real value, defined as upper bound */
+       Ndis802_11APMode
+};
+
+struct ndis_802_11_fixed_ies {
+       u8  Timestamp[8];
+       u16  BeaconInterval;
+       u16  Capabilities;
+};
+
+struct ndis_802_11_var_ies {
+       u8  ElementID;
+       u8  Length;
+       u8  data[1];
+};
+
+/* Length is the 4 bytes multiples of the sum of
+ * sizeof(6 * sizeof(unsigned char)) + 2 + sizeof(struct ndis_802_11_ssid) +
+ * sizeof(u32) + sizeof(long) + sizeof(enum ndis_802_11_net_type) +
+ * sizeof(struct ndis_802_11_config) + sizeof(sizeof(unsigned char) *
+ * NDIS_802_11_LENGTH_RATES_EX) + IELength
+ *
+ * Except the IELength, all other fields are fixed length. Therefore,
+ * we can define a macro to present the partial sum.
+ */
+
+enum ndis_802_11_auth_mode {
+       Ndis802_11AuthModeOpen,
+       Ndis802_11AuthModeShared,
+       Ndis802_11AuthModeAutoSwitch,
+       Ndis802_11AuthModeWPA,
+       Ndis802_11AuthModeWPAPSK,
+       Ndis802_11AuthModeWPANone,
+       dis802_11AuthModeMax       /*  upper bound */
+};
+
+enum  {
+       Ndis802_11WEPEnabled,
+       Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
+       Ndis802_11WEPDisabled,
+       Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
+       Ndis802_11WEPKeyAbsent,
+       Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
+       Ndis802_11WEPNotSupported,
+       Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
+       Ndis802_11Encryption2Enabled,
+       Ndis802_11Encryption2KeyAbsent,
+       Ndis802_11Encryption3Enabled,
+       Ndis802_11Encryption3KeyAbsent,
+};
+
+/*  Key mapping keys require a BSSID */
+struct ndis_802_11_key {
+       u32 Length;             /*  Length of this structure */
+       u32 KeyIndex;
+       u32 KeyLength;          /*  length of key in bytes */
+       unsigned char BSSID[6];
+       unsigned long long KeyRSC;
+       u8 KeyMaterial[32]; /*  variable length depending on above field */
+};
+
+struct ndis_802_11_wep {
+       u32     Length;        /*  Length of this structure */
+       u32     KeyIndex;      /*  0 is the per-client key, 1-N are global */
+       u32     KeyLength;     /*  length of key in bytes */
+       u8     KeyMaterial[16];/*  variable length depending on above field */
+};
+
+enum NDIS_802_11_STATUS_TYPE {
+       Ndis802_11StatusType_Authentication,
+       Ndis802_11StatusType_MediaStreamMode,
+       Ndis802_11StatusType_PMKID_CandidateList,
+       Ndis802_11StatusTypeMax    /*  not a real type, just an upper bound */
+};
+
+/*  mask for authentication/integrity fields */
+#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS        0x0f
+#define NDIS_802_11_AUTH_REQUEST_REAUTH                        0x01
+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE             0x02
+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR                0x06
+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR           0x0E
+
+/*  MIC check time, 60 seconds. */
+#define MIC_CHECK_TIME 60000000
+
+#ifndef Ndis802_11APMode
+#define Ndis802_11APMode (Ndis802_11InfrastructureMax+1)
+#endif
+
+struct wlan_phy_info {
+       u8      SignalStrength;/* in percentage) */
+       u8      SignalQuality;/* in percentage) */
+       u8      Optimum_antenna;  /* for Antenna diversity */
+       u8      Reserved_0;
+};
+
+struct wlan_bcn_info {
+       /* these infor get from rtw_get_encrypt_info when
+        *       * translate scan to UI */
+       u8 encryp_protocol;/* ENCRYP_PROTOCOL_E: OPEN/WEP/WPA/WPA2 */
+       int group_cipher; /* WPA/WPA2 group cipher */
+       int pairwise_cipher;/* WPA/WPA2/WEP pairwise cipher */
+       int is_8021x;
+
+       /* bwmode 20/40 and ch_offset UP/LOW */
+       unsigned short  ht_cap_info;
+       unsigned char   ht_info_infos_0;
+};
+
+struct wlan_bssid_ex {
+       u32  Length;
+       u8 MacAddress[ETH_ALEN];
+       u16 reserved;
+       struct cfg80211_ssid Ssid;
+       u32  Privacy;
+       long  Rssi;/* in dBM, raw data , get from PHY) */
+       enum ndis_802_11_net_type  NetworkTypeInUse;
+       struct ndis_802_11_config  Configuration;
+       enum ndis_802_11_net_infra  InfrastructureMode;
+       unsigned char SupportedRates[NDIS_802_11_LENGTH_RATES_EX];
+       struct wlan_phy_info    PhyInfo;
+       u32  IELength;
+       u8  IEs[MAX_IE_SZ]; /* timestamp, beacon interval, and capability info*/
+} __packed;
+
+static inline uint get_wlan_bssid_ex_sz(struct wlan_bssid_ex *bss)
+{
+       return sizeof(struct wlan_bssid_ex) - MAX_IE_SZ + bss->IELength;
+}
+
+struct wlan_network {
+       struct list_head        list;
+       int     network_type;   /* refer to ieee80211.h for 11A/B/G */
+       /*  set to fixed when not to be removed as site-surveying */
+       int     fixed;
+       unsigned long   last_scanned; /* timestamp for the network */
+       int     aid;            /* will only be valid when a BSS is joined. */
+       int     join_res;
+       struct wlan_bssid_ex    network; /* must be the last item */
+       struct wlan_bcn_info    BcnInfo;
+};
+
+enum VRTL_CARRIER_SENSE {
+       DISABLE_VCS,
+       ENABLE_VCS,
+       AUTO_VCS
+};
+
+enum VCS_TYPE {
+       NONE_VCS,
+       RTS_CTS,
+       CTS_TO_SELF
+};
+
+/* john */
+#define NUM_PRE_AUTH_KEY 16
+#define NUM_PMKID_CACHE NUM_PRE_AUTH_KEY
+
+#endif /* ifndef WLAN_BSSDEF_H_ */
diff --git a/drivers/staging/rtl8723au/include/xmit_osdep.h b/drivers/staging/rtl8723au/include/xmit_osdep.h
new file mode 100644 (file)
index 0000000..0eca53e
--- /dev/null
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#ifndef __XMIT_OSDEP_H_
+#define __XMIT_OSDEP_H_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+struct pkt_file {
+       struct sk_buff *pkt;
+       __kernel_size_t pkt_len; /* the remainder length of the open_file */
+       unsigned char *cur_buffer;
+       u8 *buf_start;
+       u8 *cur_addr;
+       __kernel_size_t buf_len;
+};
+
+
+#define NR_XMITFRAME   256
+
+struct xmit_priv;
+struct pkt_attrib;
+struct sta_xmit_priv;
+struct xmit_frame;
+struct xmit_buf;
+
+int rtw_xmit23a_entry23a(struct sk_buff *pkt, struct net_device *pnetdev);
+
+void rtw_os_xmit_schedule23a(struct rtw_adapter *padapter);
+
+int rtw_os_xmit_resource_alloc23a(struct rtw_adapter *padapter,
+                              struct xmit_buf *pxmitbuf, u32 alloc_sz);
+void rtw_os_xmit_resource_free23a(struct rtw_adapter *padapter,
+                              struct xmit_buf *pxmitbuf);
+uint rtw_remainder_len23a(struct pkt_file *pfile);
+void _rtw_open_pktfile23a(struct sk_buff *pkt, struct pkt_file *pfile);
+uint _rtw_pktfile_read23a(struct pkt_file *pfile, u8 *rmem, uint rlen);
+int rtw_endofpktfile23a(struct pkt_file *pfile);
+
+void rtw_os_pkt_complete23a(struct rtw_adapter *padapter, struct sk_buff *pkt);
+void rtw_os_xmit_complete23a(struct rtw_adapter *padapter,
+                         struct xmit_frame *pxframe);
+int netdev_open23a(struct net_device *pnetdev);
+
+#endif /* __XMIT_OSDEP_H_ */
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
new file mode 100644 (file)
index 0000000..50840b9
--- /dev/null
@@ -0,0 +1,4532 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define  _IOCTL_CFG80211_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <rtw_ioctl_set.h>
+#include <xmit_osdep.h>
+
+#include "ioctl_cfg80211.h"
+#include <linux/version.h>
+
+#define RTW_MAX_MGMT_TX_CNT 8
+
+#define RTW_MAX_REMAIN_ON_CHANNEL_DURATION 65535       /* ms */
+#define RTW_MAX_NUM_PMKIDS 4
+
+#define RTW_CH_MAX_2G_CHANNEL               14 /* Max channel in 2G band */
+
+static const u32 rtw_cipher_suites[] = {
+       WLAN_CIPHER_SUITE_WEP40,
+       WLAN_CIPHER_SUITE_WEP104,
+       WLAN_CIPHER_SUITE_TKIP,
+       WLAN_CIPHER_SUITE_CCMP,
+};
+
+#define RATETAB_ENT(_rate, _rateid, _flags) {                  \
+       .bitrate        = (_rate),                              \
+       .hw_value       = (_rateid),                            \
+       .flags          = (_flags),                             \
+}
+
+#define CHAN2G(_channel, _freq, _flags) {                      \
+       .band                   = IEEE80211_BAND_2GHZ,          \
+       .center_freq            = (_freq),                      \
+       .hw_value               = (_channel),                   \
+       .flags                  = (_flags),                     \
+       .max_antenna_gain       = 0,                            \
+       .max_power              = 30,                           \
+}
+
+#define CHAN5G(_channel, _flags) {                             \
+       .band                   = IEEE80211_BAND_5GHZ,          \
+       .center_freq            = 5000 + (5 * (_channel)),      \
+       .hw_value               = (_channel),                   \
+       .flags                  = (_flags),                     \
+       .max_antenna_gain       = 0,                            \
+       .max_power              = 30,                           \
+}
+
+static struct ieee80211_rate rtw_rates[] = {
+       RATETAB_ENT(10, 0x1, 0),
+       RATETAB_ENT(20, 0x2, 0),
+       RATETAB_ENT(55, 0x4, 0),
+       RATETAB_ENT(110, 0x8, 0),
+       RATETAB_ENT(60, 0x10, 0),
+       RATETAB_ENT(90, 0x20, 0),
+       RATETAB_ENT(120, 0x40, 0),
+       RATETAB_ENT(180, 0x80, 0),
+       RATETAB_ENT(240, 0x100, 0),
+       RATETAB_ENT(360, 0x200, 0),
+       RATETAB_ENT(480, 0x400, 0),
+       RATETAB_ENT(540, 0x800, 0),
+};
+
+#define rtw_a_rates            (rtw_rates + 4)
+#define RTW_A_RATES_NUM        8
+#define rtw_g_rates            (rtw_rates + 0)
+#define RTW_G_RATES_NUM        12
+
+#define RTW_2G_CHANNELS_NUM 14
+#define RTW_5G_CHANNELS_NUM 37
+
+static struct ieee80211_channel rtw_2ghz_channels[] = {
+       CHAN2G(1, 2412, 0),
+       CHAN2G(2, 2417, 0),
+       CHAN2G(3, 2422, 0),
+       CHAN2G(4, 2427, 0),
+       CHAN2G(5, 2432, 0),
+       CHAN2G(6, 2437, 0),
+       CHAN2G(7, 2442, 0),
+       CHAN2G(8, 2447, 0),
+       CHAN2G(9, 2452, 0),
+       CHAN2G(10, 2457, 0),
+       CHAN2G(11, 2462, 0),
+       CHAN2G(12, 2467, 0),
+       CHAN2G(13, 2472, 0),
+       CHAN2G(14, 2484, 0),
+};
+
+static struct ieee80211_channel rtw_5ghz_a_channels[] = {
+       CHAN5G(34, 0), CHAN5G(36, 0),
+       CHAN5G(38, 0), CHAN5G(40, 0),
+       CHAN5G(42, 0), CHAN5G(44, 0),
+       CHAN5G(46, 0), CHAN5G(48, 0),
+       CHAN5G(52, 0), CHAN5G(56, 0),
+       CHAN5G(60, 0), CHAN5G(64, 0),
+       CHAN5G(100, 0), CHAN5G(104, 0),
+       CHAN5G(108, 0), CHAN5G(112, 0),
+       CHAN5G(116, 0), CHAN5G(120, 0),
+       CHAN5G(124, 0), CHAN5G(128, 0),
+       CHAN5G(132, 0), CHAN5G(136, 0),
+       CHAN5G(140, 0), CHAN5G(149, 0),
+       CHAN5G(153, 0), CHAN5G(157, 0),
+       CHAN5G(161, 0), CHAN5G(165, 0),
+       CHAN5G(184, 0), CHAN5G(188, 0),
+       CHAN5G(192, 0), CHAN5G(196, 0),
+       CHAN5G(200, 0), CHAN5G(204, 0),
+       CHAN5G(208, 0), CHAN5G(212, 0),
+       CHAN5G(216, 0),
+};
+
+static void rtw_2g_channels_init(struct ieee80211_channel *channels)
+{
+       memcpy((void *)channels, (void *)rtw_2ghz_channels,
+              sizeof(struct ieee80211_channel) * RTW_2G_CHANNELS_NUM);
+}
+
+static void rtw_5g_channels_init(struct ieee80211_channel *channels)
+{
+       memcpy((void *)channels, (void *)rtw_5ghz_a_channels,
+              sizeof(struct ieee80211_channel) * RTW_5G_CHANNELS_NUM);
+}
+
+static void rtw_2g_rates_init(struct ieee80211_rate *rates)
+{
+       memcpy(rates, rtw_g_rates,
+              sizeof(struct ieee80211_rate) * RTW_G_RATES_NUM);
+}
+
+static void rtw_5g_rates_init(struct ieee80211_rate *rates)
+{
+       memcpy(rates, rtw_a_rates,
+              sizeof(struct ieee80211_rate) * RTW_A_RATES_NUM);
+}
+
+static struct ieee80211_supported_band *
+rtw_spt_band_alloc(enum ieee80211_band band)
+{
+       struct ieee80211_supported_band *spt_band = NULL;
+       int n_channels, n_bitrates;
+
+       if (band == IEEE80211_BAND_2GHZ) {
+               n_channels = RTW_2G_CHANNELS_NUM;
+               n_bitrates = RTW_G_RATES_NUM;
+       } else if (band == IEEE80211_BAND_5GHZ) {
+               n_channels = RTW_5G_CHANNELS_NUM;
+               n_bitrates = RTW_A_RATES_NUM;
+       } else {
+               goto exit;
+       }
+       spt_band = kzalloc(sizeof(struct ieee80211_supported_band) +
+                          sizeof(struct ieee80211_channel) * n_channels +
+                          sizeof(struct ieee80211_rate) * n_bitrates,
+                          GFP_KERNEL);
+       if (!spt_band)
+               goto exit;
+
+       spt_band->channels =
+               (struct ieee80211_channel *)(((u8 *) spt_band) +
+                                            sizeof(struct
+                                                   ieee80211_supported_band));
+       spt_band->bitrates =
+               (struct ieee80211_rate *)(((u8 *) spt_band->channels) +
+                                         sizeof(struct ieee80211_channel) *
+                                         n_channels);
+       spt_band->band = band;
+       spt_band->n_channels = n_channels;
+       spt_band->n_bitrates = n_bitrates;
+
+       if (band == IEEE80211_BAND_2GHZ) {
+               rtw_2g_channels_init(spt_band->channels);
+               rtw_2g_rates_init(spt_band->bitrates);
+       } else if (band == IEEE80211_BAND_5GHZ) {
+               rtw_5g_channels_init(spt_band->channels);
+               rtw_5g_rates_init(spt_band->bitrates);
+       }
+
+       /* spt_band.ht_cap */
+
+exit:
+       return spt_band;
+}
+
+static const struct ieee80211_txrx_stypes
+rtw_cfg80211_default_mgmt_stypes[NUM_NL80211_IFTYPES] = {
+       [NL80211_IFTYPE_ADHOC] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4)
+       },
+       [NL80211_IFTYPE_STATION] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                     BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
+       [NL80211_IFTYPE_AP] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                     BIT(IEEE80211_STYPE_AUTH >> 4) |
+                     BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                     BIT(IEEE80211_STYPE_ACTION >> 4)
+       },
+       [NL80211_IFTYPE_AP_VLAN] = {
+               /* copy AP */
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                     BIT(IEEE80211_STYPE_AUTH >> 4) |
+                     BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                     BIT(IEEE80211_STYPE_ACTION >> 4)
+       },
+       [NL80211_IFTYPE_P2P_CLIENT] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ACTION >> 4) |
+                     BIT(IEEE80211_STYPE_PROBE_REQ >> 4)
+       },
+       [NL80211_IFTYPE_P2P_GO] = {
+               .tx = 0xffff,
+               .rx = BIT(IEEE80211_STYPE_ASSOC_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_REASSOC_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_PROBE_REQ >> 4) |
+                     BIT(IEEE80211_STYPE_DISASSOC >> 4) |
+                     BIT(IEEE80211_STYPE_AUTH >> 4) |
+                     BIT(IEEE80211_STYPE_DEAUTH >> 4) |
+                     BIT(IEEE80211_STYPE_ACTION >> 4)
+       },
+};
+
+#define MAX_BSSINFO_LEN 1000
+static int rtw_cfg80211_inform_bss(struct rtw_adapter *padapter,
+                                  struct wlan_network *pnetwork)
+{
+       int ret = 0;
+       struct ieee80211_channel *notify_channel;
+       struct cfg80211_bss *bss;
+       /* struct ieee80211_supported_band *band; */
+       u16 channel;
+       u32 freq;
+       u64 notify_timestamp;
+       u16 notify_capability;
+       u16 notify_interval;
+       u8 *notify_ie;
+       size_t notify_ielen;
+       s32 notify_signal;
+       u8 buf[MAX_BSSINFO_LEN], *pbuf;
+       size_t len, bssinf_len = 0;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       u8 bc_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+       struct wireless_dev *wdev = padapter->rtw_wdev;
+       struct wiphy *wiphy = wdev->wiphy;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       /* DBG_8723A("%s\n", __func__); */
+
+       bssinf_len =
+               pnetwork->network.IELength + sizeof(struct ieee80211_hdr_3addr);
+       if (bssinf_len > MAX_BSSINFO_LEN) {
+               DBG_8723A("%s IE Length too long > %d byte\n", __func__,
+                         MAX_BSSINFO_LEN);
+               goto exit;
+       }
+
+       channel = pnetwork->network.Configuration.DSConfig;
+       if (channel <= RTW_CH_MAX_2G_CHANNEL)
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_2GHZ);
+       else
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_5GHZ);
+
+       notify_channel = ieee80211_get_channel(wiphy, freq);
+
+       /* rtw_get_timestampe_from_ie23a() */
+       notify_timestamp = jiffies_to_msecs(jiffies) * 1000;    /* uSec */
+
+       notify_interval =
+           le16_to_cpu(*(u16 *)
+                       rtw_get_beacon_interval23a_from_ie(pnetwork->network.IEs));
+       notify_capability =
+           le16_to_cpu(*(u16 *)
+                       rtw_get_capability23a_from_ie(pnetwork->network.IEs));
+
+       notify_ie = pnetwork->network.IEs + _FIXED_IE_LENGTH_;
+       notify_ielen = pnetwork->network.IELength - _FIXED_IE_LENGTH_;
+
+       /* We've set wiphy's signal_type as CFG80211_SIGNAL_TYPE_MBM:
+        *  signal strength in mBm (100*dBm)
+        */
+       if (check_fwstate(pmlmepriv, _FW_LINKED) &&
+           is_same_network23a(&pmlmepriv->cur_network.network,
+                           &pnetwork->network)) {
+               notify_signal = 100 * translate_percentage_to_dbm(padapter->recvpriv.signal_strength);  /* dbm */
+       } else {
+               notify_signal = 100 * translate_percentage_to_dbm(pnetwork->network.PhyInfo.SignalStrength);    /* dbm */
+       }
+       pbuf = buf;
+
+       pwlanhdr = (struct ieee80211_hdr *)pbuf;
+       fctrl = &pwlanhdr->frame_control;
+       *(fctrl) = 0;
+
+       SetSeqNum(pwlanhdr, 0);
+
+       if (pnetwork->network.reserved == 1) {  /*  WIFI_BEACON */
+               memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
+               SetFrameSubType(pbuf, WIFI_BEACON);
+       } else {
+               memcpy(pwlanhdr->addr1, myid(&padapter->eeprompriv), ETH_ALEN);
+               SetFrameSubType(pbuf, WIFI_PROBERSP);
+       }
+
+       memcpy(pwlanhdr->addr2, pnetwork->network.MacAddress, ETH_ALEN);
+       memcpy(pwlanhdr->addr3, pnetwork->network.MacAddress, ETH_ALEN);
+
+       pbuf += sizeof(struct ieee80211_hdr_3addr);
+       len = sizeof(struct ieee80211_hdr_3addr);
+
+       memcpy(pbuf, pnetwork->network.IEs, pnetwork->network.IELength);
+       len += pnetwork->network.IELength;
+
+       bss = cfg80211_inform_bss_frame(wiphy, notify_channel,
+                                       (struct ieee80211_mgmt *)buf, len,
+                                       notify_signal, GFP_ATOMIC);
+
+       if (unlikely(!bss)) {
+               DBG_8723A("rtw_cfg80211_inform_bss error\n");
+               return -EINVAL;
+       }
+
+       cfg80211_put_bss(wiphy, bss);
+
+exit:
+       return ret;
+}
+
+void rtw_cfg80211_indicate_connect(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wlan_network *cur_network = &pmlmepriv->cur_network;
+       struct wireless_dev *pwdev = padapter->rtw_wdev;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif
+
+       DBG_8723A("%s(padapter =%p)\n", __func__, padapter);
+
+       if (pwdev->iftype != NL80211_IFTYPE_STATION &&
+           pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return;
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+               return;
+
+#ifdef CONFIG_8723AU_P2P
+       if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+               rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+               rtw_p2p_set_role(pwdinfo, P2P_ROLE_CLIENT);
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+               DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =%d\n",
+                         __func__, rtw_p2p_role(pwdinfo),
+                         rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo));
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       if (rtw_to_roaming(padapter) > 0) {
+               struct wiphy *wiphy = pwdev->wiphy;
+               struct ieee80211_channel *notify_channel;
+               u32 freq;
+               u16 channel = cur_network->network.Configuration.DSConfig;
+
+               if (channel <= RTW_CH_MAX_2G_CHANNEL)
+                       freq =
+                           ieee80211_channel_to_frequency(channel,
+                                                          IEEE80211_BAND_2GHZ);
+               else
+                       freq =
+                           ieee80211_channel_to_frequency(channel,
+                                                          IEEE80211_BAND_5GHZ);
+
+               notify_channel = ieee80211_get_channel(wiphy, freq);
+
+               DBG_8723A("%s call cfg80211_roamed\n", __func__);
+               cfg80211_roamed(padapter->pnetdev, notify_channel,
+                               cur_network->network.MacAddress,
+                               pmlmepriv->assoc_req +
+                               sizeof(struct ieee80211_hdr_3addr) + 2,
+                               pmlmepriv->assoc_req_len -
+                               sizeof(struct ieee80211_hdr_3addr) - 2,
+                               pmlmepriv->assoc_rsp +
+                               sizeof(struct ieee80211_hdr_3addr) + 6,
+                               pmlmepriv->assoc_rsp_len -
+                               sizeof(struct ieee80211_hdr_3addr) - 6,
+                               GFP_ATOMIC);
+       } else {
+               cfg80211_connect_result(padapter->pnetdev,
+                                       cur_network->network.MacAddress,
+                                       pmlmepriv->assoc_req +
+                                       sizeof(struct ieee80211_hdr_3addr) + 2,
+                                       pmlmepriv->assoc_req_len -
+                                       sizeof(struct ieee80211_hdr_3addr) - 2,
+                                       pmlmepriv->assoc_rsp +
+                                       sizeof(struct ieee80211_hdr_3addr) + 6,
+                                       pmlmepriv->assoc_rsp_len -
+                                       sizeof(struct ieee80211_hdr_3addr) - 6,
+                                       WLAN_STATUS_SUCCESS, GFP_ATOMIC);
+       }
+}
+
+void rtw_cfg80211_indicate_disconnect(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct wireless_dev *pwdev = padapter->rtw_wdev;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif
+
+       DBG_8723A("%s(padapter =%p)\n", __func__, padapter);
+
+       if (pwdev->iftype != NL80211_IFTYPE_STATION &&
+           pwdev->iftype != NL80211_IFTYPE_P2P_CLIENT)
+               return;
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
+               return;
+
+#ifdef CONFIG_8723AU_P2P
+       if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+               del_timer_sync(&pwdinfo->find_phase_timer);
+               del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+               del_timer_sync(&pwdinfo->pre_tx_scan_timer);
+
+               rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+               rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+
+               DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state =%d\n",
+                         __func__, rtw_p2p_role(pwdinfo),
+                         rtw_p2p_state(pwdinfo), rtw_p2p_pre_state(pwdinfo));
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       if (!padapter->mlmepriv.not_indic_disco) {
+               if (check_fwstate(&padapter->mlmepriv, WIFI_UNDER_LINKING)) {
+                       cfg80211_connect_result(padapter->pnetdev, NULL, NULL,
+                                               0, NULL, 0,
+                                               WLAN_STATUS_UNSPECIFIED_FAILURE,
+                                               GFP_ATOMIC);
+               } else {
+                       cfg80211_disconnected(padapter->pnetdev, 0, NULL,
+                                             0, GFP_ATOMIC);
+               }
+       }
+}
+
+#ifdef CONFIG_8723AU_AP_MODE
+static u8 set_pairwise_key(struct rtw_adapter *padapter, struct sta_info *psta)
+{
+       struct cmd_obj *ph2c;
+       struct set_stakey_parm *psetstakey_para;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       u8 res = _SUCCESS;
+
+       ph2c = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       if (ph2c == NULL) {
+               res = _FAIL;
+               goto exit;
+       }
+
+       psetstakey_para = kzalloc(sizeof(struct set_stakey_parm), GFP_KERNEL);
+       if (psetstakey_para == NULL) {
+               kfree(ph2c);
+               res = _FAIL;
+               goto exit;
+       }
+
+       init_h2fwcmd_w_parm_no_rsp(ph2c, psetstakey_para, _SetStaKey_CMD_);
+
+       psetstakey_para->algorithm = (u8) psta->dot118021XPrivacy;
+
+       memcpy(psetstakey_para->addr, psta->hwaddr, ETH_ALEN);
+
+       memcpy(psetstakey_para->key, &psta->dot118021x_UncstKey, 16);
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, ph2c);
+
+exit:
+       return res;
+}
+
+static int set_group_key(struct rtw_adapter *padapter, u8 *key, u8 alg,
+                        int keyid)
+{
+       u8 keylen;
+       struct cmd_obj *pcmd;
+       struct setkey_parm *psetkeyparm;
+       struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
+       int res = _SUCCESS;
+
+       DBG_8723A("%s\n", __func__);
+
+       pcmd = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
+       if (!pcmd) {
+               res = _FAIL;
+               goto exit;
+       }
+       psetkeyparm = kzalloc(sizeof(struct setkey_parm), GFP_KERNEL);
+       if (!psetkeyparm) {
+               kfree(pcmd);
+               res = _FAIL;
+               goto exit;
+       }
+
+       psetkeyparm->keyid = (u8) keyid;
+       if (is_wep_enc(alg))
+               padapter->mlmepriv.key_mask |= CHKBIT(psetkeyparm->keyid);
+
+       psetkeyparm->algorithm = alg;
+
+       psetkeyparm->set_tx = 1;
+
+       switch (alg) {
+       case _WEP40_:
+               keylen = 5;
+               break;
+       case _WEP104_:
+               keylen = 13;
+               break;
+       case _TKIP_:
+       case _TKIP_WTMIC_:
+       case _AES_:
+       default:
+               keylen = 16;
+       }
+
+       memcpy(&psetkeyparm->key[0], key, keylen);
+
+       pcmd->cmdcode = _SetKey_CMD_;
+       pcmd->parmbuf = (u8 *) psetkeyparm;
+       pcmd->cmdsz = (sizeof(struct setkey_parm));
+       pcmd->rsp = NULL;
+       pcmd->rspsz = 0;
+
+       INIT_LIST_HEAD(&pcmd->list);
+
+       res = rtw_enqueue_cmd23a(pcmdpriv, pcmd);
+
+exit:
+       return res;
+}
+
+static int set_wep_key(struct rtw_adapter *padapter, u8 *key, u8 keylen,
+                      int keyid)
+{
+       u8 alg;
+
+       switch (keylen) {
+       case 5:
+               alg = _WEP40_;
+               break;
+       case 13:
+               alg = _WEP104_;
+               break;
+       default:
+               alg = _NO_PRIVACY_;
+       }
+
+       return set_group_key(padapter, key, alg, keyid);
+}
+
+static int rtw_cfg80211_ap_set_encryption(struct net_device *dev,
+                                         struct ieee_param *param,
+                                         u32 param_len)
+{
+       int ret = 0;
+       u32 wep_key_idx, wep_key_len;
+       struct sta_info *psta = NULL, *pbcmc_sta = NULL;
+       struct rtw_adapter *padapter = netdev_priv(dev);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+
+       DBG_8723A("%s\n", __func__);
+
+       param->u.crypt.err = 0;
+       param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+       /* sizeof(struct ieee_param) = 64 bytes; */
+       /* if (param_len !=  (u32) ((u8 *) param->u.crypt.key -
+          (u8 *) param) + param->u.crypt.key_len) */
+       if (param_len != sizeof(struct ieee_param) + param->u.crypt.key_len) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       if (is_broadcast_ether_addr(param->sta_addr)) {
+               if (param->u.crypt.idx >= WEP_KEYS) {
+                       ret = -EINVAL;
+                       goto exit;
+               }
+       } else {
+               psta = rtw_get_stainfo23a(pstapriv, param->sta_addr);
+               if (!psta) {
+                       /* ret = -EINVAL; */
+                       DBG_8723A("rtw_set_encryption(), sta has already "
+                                 "been removed or never been added\n");
+                       goto exit;
+               }
+       }
+
+       if (strcmp(param->u.crypt.alg, "none") == 0 && (psta == NULL)) {
+               /* todo:clear default encryption keys */
+
+               DBG_8723A("clear default encryption keys, keyid =%d\n",
+                         param->u.crypt.idx);
+
+               goto exit;
+       }
+
+       if (strcmp(param->u.crypt.alg, "WEP") == 0 && (psta == NULL)) {
+               DBG_8723A("r871x_set_encryption, crypt.alg = WEP\n");
+
+               wep_key_idx = param->u.crypt.idx;
+               wep_key_len = param->u.crypt.key_len;
+
+               DBG_8723A("r871x_set_encryption, wep_key_idx =%d, len =%d\n",
+                         wep_key_idx, wep_key_len);
+
+               if ((wep_key_idx >= WEP_KEYS) || (wep_key_len <= 0)) {
+                       ret = -EINVAL;
+                       goto exit;
+               }
+
+               if (wep_key_len > 0) {
+                       wep_key_len = wep_key_len <= 5 ? 5 : 13;
+               }
+
+               if (psecuritypriv->bWepDefaultKeyIdxSet == 0) {
+                       /* wep default key has not been set, so use
+                          this key index as default key. */
+
+                       psecuritypriv->ndisencryptstatus =
+                               Ndis802_11Encryption1Enabled;
+                       psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+                       psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+
+                       if (wep_key_len == 13) {
+                               psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+                               psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+                       }
+
+                       psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
+               }
+
+               memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0],
+                      param->u.crypt.key, wep_key_len);
+
+               psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len;
+
+               set_wep_key(padapter, param->u.crypt.key, wep_key_len,
+                           wep_key_idx);
+
+               goto exit;
+
+       }
+
+       if (!psta && check_fwstate(pmlmepriv, WIFI_AP_STATE)) { /*  group key */
+               if (param->u.crypt.set_tx == 0) {       /* group key */
+                       if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+                               DBG_8723A("%s, set group_key, WEP\n",
+                                         __func__);
+
+                               memcpy(psecuritypriv->
+                                      dot118021XGrpKey[param->u.crypt.idx].
+                                      skey, param->u.crypt.key,
+                                      (param->u.crypt.key_len >
+                                       16 ? 16 : param->u.crypt.key_len));
+
+                               psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+                               if (param->u.crypt.key_len == 13) {
+                                       psecuritypriv->dot118021XGrpPrivacy =
+                                           _WEP104_;
+                               }
+
+                       } else if (strcmp(param->u.crypt.alg, "TKIP") == 0) {
+                               DBG_8723A("%s, set group_key, TKIP\n",
+                                         __func__);
+
+                               psecuritypriv->dot118021XGrpPrivacy = _TKIP_;
+
+                               memcpy(psecuritypriv->
+                                      dot118021XGrpKey[param->u.crypt.idx].
+                                      skey, param->u.crypt.key,
+                                      (param->u.crypt.key_len >
+                                       16 ? 16 : param->u.crypt.key_len));
+
+                               /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
+                               /* set mic key */
+                               memcpy(psecuritypriv->
+                                      dot118021XGrptxmickey[param->u.crypt.
+                                                            idx].skey,
+                                      &param->u.crypt.key[16], 8);
+                               memcpy(psecuritypriv->
+                                      dot118021XGrprxmickey[param->u.crypt.
+                                                            idx].skey,
+                                      &param->u.crypt.key[24], 8);
+
+                               psecuritypriv->busetkipkey = true;
+
+                       } else if (strcmp(param->u.crypt.alg, "CCMP") == 0) {
+                               DBG_8723A("%s, set group_key, CCMP\n",
+                                         __func__);
+
+                               psecuritypriv->dot118021XGrpPrivacy = _AES_;
+
+                               memcpy(psecuritypriv->
+                                      dot118021XGrpKey[param->u.crypt.idx].
+                                      skey, param->u.crypt.key,
+                                      (param->u.crypt.key_len >
+                                       16 ? 16 : param->u.crypt.key_len));
+                       } else {
+                               DBG_8723A("%s, set group_key, none\n",
+                                         __func__);
+
+                               psecuritypriv->dot118021XGrpPrivacy =
+                                   _NO_PRIVACY_;
+                       }
+
+                       psecuritypriv->dot118021XGrpKeyid = param->u.crypt.idx;
+
+                       psecuritypriv->binstallGrpkey = true;
+
+                       psecuritypriv->dot11PrivacyAlgrthm =
+                               psecuritypriv->dot118021XGrpPrivacy;
+
+                       set_group_key(padapter, param->u.crypt.key,
+                                     psecuritypriv->dot118021XGrpPrivacy,
+                                     param->u.crypt.idx);
+
+                       pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter);
+                       if (pbcmc_sta) {
+                               pbcmc_sta->ieee8021x_blocked = false;
+                               /* rx will use bmc_sta's dot118021XPrivacy */
+                               pbcmc_sta->dot118021XPrivacy =
+                                       psecuritypriv->dot118021XGrpPrivacy;
+
+                       }
+
+               }
+
+               goto exit;
+       }
+
+       if (psecuritypriv->dot11AuthAlgrthm ==
+           dot11AuthAlgrthm_8021X && psta) {   /*  psk/802_1x */
+               if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+                       if (param->u.crypt.set_tx == 1) {
+                               /* pairwise key */
+                               memcpy(psta->dot118021x_UncstKey.skey,
+                                      param->u.crypt.key,
+                                      (param->u.crypt.key_len >
+                                       16 ? 16 : param->u.crypt.key_len));
+
+                               if (!strcmp(param->u.crypt.alg, "WEP")) {
+                                       DBG_8723A("%s, set pairwise key, WEP\n",
+                                                 __func__);
+
+                                       psta->dot118021XPrivacy = _WEP40_;
+                                       if (param->u.crypt.key_len == 13) {
+                                               psta->dot118021XPrivacy =
+                                                       _WEP104_;
+                                       }
+                               } else if (!strcmp(param->u.crypt.alg, "TKIP")) {
+                                       DBG_8723A("%s, set pairwise key, "
+                                                 "TKIP\n", __func__);
+
+                                       psta->dot118021XPrivacy = _TKIP_;
+
+                                       /* DEBUG_ERR("set key length :param->u.crypt.key_len =%d\n", param->u.crypt.key_len); */
+                                       /* set mic key */
+                                       memcpy(psta->dot11tkiptxmickey.skey,
+                                              &param->u.crypt.key[16], 8);
+                                       memcpy(psta->dot11tkiprxmickey.skey,
+                                              &param->u.crypt.key[24], 8);
+
+                                       psecuritypriv->busetkipkey = true;
+
+                               } else if (!strcmp(param->u.crypt.alg, "CCMP")) {
+
+                                       DBG_8723A("%s, set pairwise key, "
+                                                 "CCMP\n", __func__);
+
+                                       psta->dot118021XPrivacy = _AES_;
+                               } else {
+                                       DBG_8723A("%s, set pairwise key, "
+                                                 "none\n", __func__);
+
+                                       psta->dot118021XPrivacy = _NO_PRIVACY_;
+                               }
+
+                               set_pairwise_key(padapter, psta);
+
+                               psta->ieee8021x_blocked = false;
+
+                               psta->bpairwise_key_installed = true;
+                       } else {        /* group key??? */
+                               if (!strcmp(param->u.crypt.alg, "WEP")) {
+                                       memcpy(psecuritypriv->
+                                              dot118021XGrpKey[param->u.crypt.
+                                                               idx].skey,
+                                              param->u.crypt.key,
+                                              (param->u.crypt.key_len >
+                                               16 ? 16 : param->u.crypt.
+                                               key_len));
+
+                                       psecuritypriv->dot118021XGrpPrivacy =
+                                               _WEP40_;
+                                       if (param->u.crypt.key_len == 13) {
+                                               psecuritypriv->
+                                                   dot118021XGrpPrivacy =
+                                                       _WEP104_;
+                                       }
+                               } else if (!strcmp(param->u.crypt.alg, "TKIP")) {
+                                       psecuritypriv->dot118021XGrpPrivacy =
+                                           _TKIP_;
+
+                                       memcpy(psecuritypriv->
+                                              dot118021XGrpKey[param->u.crypt.
+                                                               idx].skey,
+                                              param->u.crypt.key,
+                                              (param->u.crypt.key_len >
+                                               16 ? 16 : param->u.crypt.
+                                               key_len));
+
+                                       /* DEBUG_ERR("set key length :param->u"
+                                          ".crypt.key_len =%d\n",
+                                          param->u.crypt.key_len); */
+                                       /* set mic key */
+                                       memcpy(psecuritypriv->
+                                              dot118021XGrptxmickey[param->u.
+                                                                    crypt.idx].
+                                              skey, &param->u.crypt.key[16],
+                                              8);
+                                       memcpy(psecuritypriv->
+                                              dot118021XGrprxmickey[param->u.
+                                                                    crypt.idx].
+                                              skey, &param->u.crypt.key[24],
+                                              8);
+
+                                       psecuritypriv->busetkipkey = true;
+
+                               } else if (!strcmp(param->u.crypt.alg, "CCMP")) {
+                                       psecuritypriv->dot118021XGrpPrivacy =
+                                               _AES_;
+
+                                       memcpy(psecuritypriv->
+                                              dot118021XGrpKey[param->u.crypt.
+                                                               idx].skey,
+                                              param->u.crypt.key,
+                                              (param->u.crypt.key_len >
+                                               16 ? 16 : param->u.crypt.
+                                               key_len));
+                               } else {
+                                       psecuritypriv->dot118021XGrpPrivacy =
+                                               _NO_PRIVACY_;
+                               }
+
+                               psecuritypriv->dot118021XGrpKeyid =
+                                       param->u.crypt.idx;
+
+                               psecuritypriv->binstallGrpkey = true;
+
+                               psecuritypriv->dot11PrivacyAlgrthm =
+                                       psecuritypriv->dot118021XGrpPrivacy;
+
+                               set_group_key(padapter, param->u.crypt.key,
+                                             psecuritypriv->
+                                             dot118021XGrpPrivacy,
+                                             param->u.crypt.idx);
+
+                               pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter);
+                               if (pbcmc_sta) {
+                                       /* rx will use bmc_sta's
+                                          dot118021XPrivacy */
+                                       pbcmc_sta->ieee8021x_blocked = false;
+                                       pbcmc_sta->dot118021XPrivacy = psecuritypriv->dot118021XGrpPrivacy;
+                               }
+                       }
+               }
+       }
+
+exit:
+
+       return ret;
+
+}
+#endif
+
+static int rtw_cfg80211_set_encryption(struct net_device *dev,
+                                      struct ieee_param *param, u32 param_len)
+{
+       int ret = 0;
+       u32 wep_key_idx, wep_key_len;
+       struct rtw_adapter *padapter = netdev_priv(dev);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif /* CONFIG_8723AU_P2P */
+
+
+
+       DBG_8723A("%s\n", __func__);
+
+       param->u.crypt.err = 0;
+       param->u.crypt.alg[IEEE_CRYPT_ALG_NAME_LEN - 1] = '\0';
+
+       if (param_len <
+           (u32) ((u8 *) param->u.crypt.key - (u8 *) param) +
+           param->u.crypt.key_len) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       if (is_broadcast_ether_addr(param->sta_addr)) {
+               if (param->u.crypt.idx >= WEP_KEYS) {
+                       ret = -EINVAL;
+                       goto exit;
+               }
+       } else {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       if (strcmp(param->u.crypt.alg, "WEP") == 0) {
+               RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_,
+                        ("wpa_set_encryption, crypt.alg = WEP\n"));
+               DBG_8723A("wpa_set_encryption, crypt.alg = WEP\n");
+
+               wep_key_idx = param->u.crypt.idx;
+               wep_key_len = param->u.crypt.key_len;
+
+               if ((wep_key_idx > WEP_KEYS) || (wep_key_len <= 0)) {
+                       ret = -EINVAL;
+                       goto exit;
+               }
+
+               if (psecuritypriv->bWepDefaultKeyIdxSet == 0) {
+                       /* wep default key has not been set, so use this
+                          key index as default key. */
+
+                       wep_key_len = wep_key_len <= 5 ? 5 : 13;
+
+                       psecuritypriv->ndisencryptstatus =
+                               Ndis802_11Encryption1Enabled;
+                       psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+                       psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+
+                       if (wep_key_len == 13) {
+                               psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+                               psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+                       }
+
+                       psecuritypriv->dot11PrivacyKeyIndex = wep_key_idx;
+               }
+
+               memcpy(&psecuritypriv->dot11DefKey[wep_key_idx].skey[0],
+                      param->u.crypt.key, wep_key_len);
+
+               psecuritypriv->dot11DefKeylen[wep_key_idx] = wep_key_len;
+
+               rtw_set_key23a(padapter, psecuritypriv, wep_key_idx, 0);
+
+               goto exit;
+       }
+
+       if (padapter->securitypriv.dot11AuthAlgrthm ==
+           dot11AuthAlgrthm_8021X) {   /*  802_1x */
+               struct sta_info *psta, *pbcmc_sta;
+               struct sta_priv *pstapriv = &padapter->stapriv;
+
+               if (check_fwstate(pmlmepriv,
+                                 WIFI_STATION_STATE | WIFI_MP_STATE)) {
+                       /* sta mode */
+                       psta = rtw_get_stainfo23a(pstapriv, get_bssid(pmlmepriv));
+                       if (psta == NULL) {
+                               DBG_8723A("%s, : Obtain Sta_info fail\n",
+                                         __func__);
+                       } else {
+                               /* Jeff: don't disable ieee8021x_blocked
+                                  while clearing key */
+                               if (strcmp(param->u.crypt.alg, "none") != 0)
+                                       psta->ieee8021x_blocked = false;
+
+                               if ((padapter->securitypriv.ndisencryptstatus ==
+                                    Ndis802_11Encryption2Enabled) ||
+                                   (padapter->securitypriv.ndisencryptstatus ==
+                                    Ndis802_11Encryption3Enabled)) {
+                                       psta->dot118021XPrivacy =
+                                               padapter->securitypriv.
+                                               dot11PrivacyAlgrthm;
+                               }
+
+                               if (param->u.crypt.set_tx == 1) {
+                                       /* pairwise key */
+                                       DBG_8723A("%s, : param->u.crypt.set_tx"
+                                                 " == 1\n", __func__);
+
+                                       memcpy(psta->dot118021x_UncstKey.skey,
+                                              param->u.crypt.key,
+                                              (param->u.crypt.key_len >
+                                               16 ? 16 : param->u.crypt.
+                                               key_len));
+
+                                       if (strcmp(param->u.crypt.alg,
+                                                  "TKIP") == 0) {
+                                               memcpy(psta->dot11tkiptxmickey.
+                                                      skey,
+                                                      &param->u.crypt.key[16],
+                                                      8);
+                                               memcpy(psta->dot11tkiprxmickey.
+                                                      skey,
+                                                      &param->u.crypt.key[24],
+                                                      8);
+
+                                               padapter->securitypriv.
+                                                       busetkipkey = false;
+                                       }
+                                       DBG_8723A(" ~~~~set sta key:unicastkey\n");
+
+                                       rtw_setstakey_cmd23a(padapter,
+                                                         (unsigned char *)psta,
+                                                         true);
+                               } else {        /* group key */
+                                       memcpy(padapter->securitypriv.
+                                              dot118021XGrpKey[param->u.crypt.
+                                                               idx].skey,
+                                              param->u.crypt.key,
+                                              (param->u.crypt.key_len >
+                                               16 ? 16 : param->u.crypt.
+                                               key_len));
+                                       memcpy(padapter->securitypriv.
+                                              dot118021XGrptxmickey[param->u.
+                                                                    crypt.idx].
+                                              skey, &param->u.crypt.key[16],
+                                              8);
+                                       memcpy(padapter->securitypriv.
+                                              dot118021XGrprxmickey[param->u.
+                                                                    crypt.idx].
+                                              skey, &param->u.crypt.key[24],
+                                              8);
+                                       padapter->securitypriv.binstallGrpkey =
+                                           true;
+                                       /* DEBUG_ERR((" param->u.crypt.key_len"
+                                          "=%d\n", param->u.crypt.key_len)); */
+                                       DBG_8723A
+                                           (" ~~~~set sta key:groupkey\n");
+
+                                       padapter->securitypriv.
+                                           dot118021XGrpKeyid =
+                                               param->u.crypt.idx;
+
+                                       rtw_set_key23a(padapter,
+                                                   &padapter->securitypriv,
+                                                   param->u.crypt.idx, 1);
+#ifdef CONFIG_8723AU_P2P
+                                       if (rtw_p2p_chk_state
+                                           (pwdinfo,
+                                            P2P_STATE_PROVISIONING_ING)) {
+                                               rtw_p2p_set_state(pwdinfo,
+                                                                 P2P_STATE_PROVISIONING_DONE);
+                                       }
+#endif /* CONFIG_8723AU_P2P */
+
+                               }
+                       }
+
+                       pbcmc_sta = rtw_get_bcmc_stainfo23a(padapter);
+                       if (pbcmc_sta) {
+                               /* Jeff: don't disable ieee8021x_blocked
+                                  while clearing key */
+                               if (strcmp(param->u.crypt.alg, "none") != 0)
+                                       pbcmc_sta->ieee8021x_blocked = false;
+
+                               if ((padapter->securitypriv.ndisencryptstatus ==
+                                    Ndis802_11Encryption2Enabled) ||
+                                   (padapter->securitypriv.ndisencryptstatus ==
+                                    Ndis802_11Encryption3Enabled)) {
+                                       pbcmc_sta->dot118021XPrivacy =
+                                           padapter->securitypriv.
+                                           dot11PrivacyAlgrthm;
+                               }
+                       }
+               } else if (check_fwstate(pmlmepriv, WIFI_ADHOC_STATE)) {        /* adhoc mode */
+               }
+       }
+
+exit:
+
+       DBG_8723A("%s, ret =%d\n", __func__, ret);
+
+
+
+       return ret;
+}
+
+static int cfg80211_rtw_add_key(struct wiphy *wiphy, struct net_device *ndev,
+                               u8 key_index, bool pairwise,
+                               const u8 *mac_addr, struct key_params *params)
+{
+       char *alg_name;
+       u32 param_len;
+       struct ieee_param *param = NULL;
+       int ret = 0;
+       struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy);
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       DBG_8723A(FUNC_NDEV_FMT " adding key for %pM\n", FUNC_NDEV_ARG(ndev),
+                 mac_addr);
+       DBG_8723A("cipher = 0x%x\n", params->cipher);
+       DBG_8723A("key_len = 0x%x\n", params->key_len);
+       DBG_8723A("seq_len = 0x%x\n", params->seq_len);
+       DBG_8723A("key_index =%d\n", key_index);
+       DBG_8723A("pairwise =%d\n", pairwise);
+
+       param_len = sizeof(struct ieee_param) + params->key_len;
+       param = kzalloc(param_len, GFP_KERNEL);
+       if (param == NULL)
+               return -1;
+
+       param->cmd = IEEE_CMD_SET_ENCRYPTION;
+       memset(param->sta_addr, 0xff, ETH_ALEN);
+
+       switch (params->cipher) {
+       case IW_AUTH_CIPHER_NONE:
+               /* todo: remove key */
+               /* remove = 1; */
+               alg_name = "none";
+               break;
+       case WLAN_CIPHER_SUITE_WEP40:
+       case WLAN_CIPHER_SUITE_WEP104:
+               alg_name = "WEP";
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               alg_name = "TKIP";
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               alg_name = "CCMP";
+               break;
+
+       default:
+               ret = -ENOTSUPP;
+               goto addkey_end;
+       }
+
+       strncpy((char *)param->u.crypt.alg, alg_name, IEEE_CRYPT_ALG_NAME_LEN);
+
+       if (!mac_addr || is_broadcast_ether_addr(mac_addr)) {
+               param->u.crypt.set_tx = 0;      /* for wpa/wpa2 group key */
+       } else {
+               param->u.crypt.set_tx = 1;      /* for wpa/wpa2 pairwise key */
+       }
+
+       /* param->u.crypt.idx = key_index - 1; */
+       param->u.crypt.idx = key_index;
+
+       if (params->seq_len && params->seq) {
+               memcpy(param->u.crypt.seq, params->seq, params->seq_len);
+       }
+
+       if (params->key_len && params->key) {
+               param->u.crypt.key_len = params->key_len;
+               memcpy(param->u.crypt.key, params->key, params->key_len);
+       }
+
+       if (check_fwstate(pmlmepriv, WIFI_STATION_STATE)) {
+               ret = rtw_cfg80211_set_encryption(ndev, param, param_len);
+       } else if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+#ifdef CONFIG_8723AU_AP_MODE
+               if (mac_addr)
+                       memcpy(param->sta_addr, (void *)mac_addr, ETH_ALEN);
+
+               ret = rtw_cfg80211_ap_set_encryption(ndev, param, param_len);
+#endif
+       } else {
+               DBG_8723A("error! fw_state = 0x%x, iftype =%d\n",
+                         pmlmepriv->fw_state, rtw_wdev->iftype);
+
+       }
+
+addkey_end:
+       kfree(param);
+
+       return ret;
+}
+
+static int
+cfg80211_rtw_get_key(struct wiphy *wiphy, struct net_device *ndev,
+                    u8 key_index, bool pairwise, const u8 *mac_addr,
+                    void *cookie,
+                    void (*callback) (void *cookie, struct key_params *))
+{
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+       return 0;
+}
+
+static int cfg80211_rtw_del_key(struct wiphy *wiphy, struct net_device *ndev,
+                               u8 key_index, bool pairwise,
+                               const u8 *mac_addr)
+{
+       struct rtw_adapter *padapter = netdev_priv(ndev);
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+       DBG_8723A(FUNC_NDEV_FMT " key_index =%d\n", FUNC_NDEV_ARG(ndev),
+                 key_index);
+
+       if (key_index == psecuritypriv->dot11PrivacyKeyIndex) {
+               /* clear the flag of wep default key set. */
+               psecuritypriv->bWepDefaultKeyIdxSet = 0;
+       }
+
+       return 0;
+}
+
+static int cfg80211_rtw_set_default_key(struct wiphy *wiphy,
+                                       struct net_device *ndev, u8 key_index,
+                                       bool unicast, bool multicast)
+{
+       struct rtw_adapter *padapter = netdev_priv(ndev);
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+       DBG_8723A(FUNC_NDEV_FMT " key_index =%d"
+                 ", unicast =%d, multicast =%d.\n", FUNC_NDEV_ARG(ndev),
+                 key_index, unicast, multicast);
+
+       if ((key_index < WEP_KEYS) &&
+           ((psecuritypriv->dot11PrivacyAlgrthm == _WEP40_) ||
+            (psecuritypriv->dot11PrivacyAlgrthm == _WEP104_))) {
+               /* set wep default key */
+               psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+
+               psecuritypriv->dot11PrivacyKeyIndex = key_index;
+
+               psecuritypriv->dot11PrivacyAlgrthm = _WEP40_;
+               psecuritypriv->dot118021XGrpPrivacy = _WEP40_;
+               if (psecuritypriv->dot11DefKeylen[key_index] == 13) {
+                       psecuritypriv->dot11PrivacyAlgrthm = _WEP104_;
+                       psecuritypriv->dot118021XGrpPrivacy = _WEP104_;
+               }
+
+               /* set the flag to represent that wep default key
+                  has been set */
+               psecuritypriv->bWepDefaultKeyIdxSet = 1;
+       }
+
+       return 0;
+}
+
+static int cfg80211_rtw_get_station(struct wiphy *wiphy,
+                                   struct net_device *ndev,
+                                   u8 *mac, struct station_info *sinfo)
+{
+       int ret = 0;
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct sta_info *psta = NULL;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+
+       sinfo->filled = 0;
+
+       if (!mac) {
+               DBG_8723A(FUNC_NDEV_FMT " mac ==%p\n", FUNC_NDEV_ARG(ndev), mac);
+               ret = -ENOENT;
+               goto exit;
+       }
+
+       psta = rtw_get_stainfo23a(pstapriv, mac);
+       if (psta == NULL) {
+               DBG_8723A("%s, sta_info is null\n", __func__);
+               ret = -ENOENT;
+               goto exit;
+       }
+#ifdef CONFIG_DEBUG_CFG80211
+       DBG_8723A(FUNC_NDEV_FMT " mac =" MAC_FMT "\n", FUNC_NDEV_ARG(ndev),
+                 MAC_ARG(mac));
+#endif
+
+       /* for infra./P2PClient mode */
+       if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) &&
+           check_fwstate(pmlmepriv, _FW_LINKED)) {
+               struct wlan_network *cur_network = &pmlmepriv->cur_network;
+
+               if (memcmp(mac, cur_network->network.MacAddress, ETH_ALEN)) {
+                       DBG_8723A("%s, mismatch bssid =" MAC_FMT "\n", __func__,
+                                 MAC_ARG(cur_network->network.MacAddress));
+                       ret = -ENOENT;
+                       goto exit;
+               }
+
+               sinfo->filled |= STATION_INFO_SIGNAL;
+               sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv.
+                                                           signal_strength);
+
+               sinfo->filled |= STATION_INFO_TX_BITRATE;
+               sinfo->txrate.legacy = rtw_get_cur_max_rate23a(padapter);
+
+               sinfo->filled |= STATION_INFO_RX_PACKETS;
+               sinfo->rx_packets = sta_rx_data_pkts(psta);
+
+               sinfo->filled |= STATION_INFO_TX_PACKETS;
+               sinfo->tx_packets = psta->sta_stats.tx_pkts;
+       }
+
+       /* for Ad-Hoc/AP mode */
+       if ((check_fwstate(pmlmepriv, WIFI_ADHOC_STATE) ||
+            check_fwstate(pmlmepriv, WIFI_ADHOC_MASTER_STATE) ||
+            check_fwstate(pmlmepriv, WIFI_AP_STATE)) &&
+           check_fwstate(pmlmepriv, _FW_LINKED)
+           ) {
+               /* TODO: should acquire station info... */
+       }
+
+exit:
+       return ret;
+}
+
+static int cfg80211_rtw_change_iface(struct wiphy *wiphy,
+                                    struct net_device *ndev,
+                                    enum nl80211_iftype type, u32 *flags,
+                                    struct vif_params *params)
+{
+       enum nl80211_iftype old_type;
+       enum ndis_802_11_net_infra networkType;
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wireless_dev *rtw_wdev = wiphy_to_wdev(wiphy);
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+#endif
+       int ret = 0;
+       u8 change = false;
+
+       DBG_8723A(FUNC_NDEV_FMT " call netdev_open23a\n", FUNC_NDEV_ARG(ndev));
+       if (netdev_open23a(ndev) != 0) {
+               ret = -EPERM;
+               goto exit;
+       }
+
+       if (_FAIL == rtw_pwr_wakeup(padapter)) {
+               ret = -EPERM;
+               goto exit;
+       }
+
+       old_type = rtw_wdev->iftype;
+       DBG_8723A(FUNC_NDEV_FMT " old_iftype =%d, new_iftype =%d\n",
+                 FUNC_NDEV_ARG(ndev), old_type, type);
+
+       if (old_type != type) {
+               change = true;
+               pmlmeext->action_public_rxseq = 0xffff;
+               pmlmeext->action_public_dialog_token = 0xff;
+       }
+
+       switch (type) {
+       case NL80211_IFTYPE_ADHOC:
+               networkType = Ndis802_11IBSS;
+               break;
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_STATION:
+               networkType = Ndis802_11Infrastructure;
+#ifdef CONFIG_8723AU_P2P
+               if (change && rtw_p2p_chk_role(pwdinfo, P2P_ROLE_GO)) {
+                       del_timer_sync(&pwdinfo->find_phase_timer);
+                       del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+                       del_timer_sync(&pwdinfo->pre_tx_scan_timer);
+
+                       /* it means remove GO and change mode from AP(GO)
+                          to station(P2P DEVICE) */
+                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_DEVICE);
+                       rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+
+                       DBG_8723A("%s, role =%d, p2p_state =%d, pre_p2p_state ="
+                                 "%d\n", __func__, rtw_p2p_role(pwdinfo),
+                                 rtw_p2p_state(pwdinfo),
+                                 rtw_p2p_pre_state(pwdinfo));
+               }
+#endif /* CONFIG_8723AU_P2P */
+               break;
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_AP:
+               networkType = Ndis802_11APMode;
+#ifdef CONFIG_8723AU_P2P
+               if (change && !rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+                       /* it means P2P Group created, we will be GO
+                          and change mode from  P2P DEVICE to AP(GO) */
+                       rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+               }
+#endif /* CONFIG_8723AU_P2P */
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       rtw_wdev->iftype = type;
+
+       if (rtw_set_802_11_infrastructure_mode23a(padapter, networkType) == false) {
+               rtw_wdev->iftype = old_type;
+               ret = -EPERM;
+               goto exit;
+       }
+
+       rtw_setopmode_cmd23a(padapter, networkType);
+
+exit:
+       return ret;
+}
+
+void rtw_cfg80211_indicate_scan_done(struct rtw_wdev_priv *pwdev_priv,
+                                    bool aborted)
+{
+       spin_lock_bh(&pwdev_priv->scan_req_lock);
+       if (pwdev_priv->scan_request != NULL) {
+#ifdef CONFIG_DEBUG_CFG80211
+               DBG_8723A("%s with scan req\n", __func__);
+#endif
+               if (pwdev_priv->scan_request->wiphy !=
+                   pwdev_priv->rtw_wdev->wiphy)
+                       DBG_8723A("error wiphy compare\n");
+               else
+                       cfg80211_scan_done(pwdev_priv->scan_request, aborted);
+
+               pwdev_priv->scan_request = NULL;
+       } else {
+#ifdef CONFIG_DEBUG_CFG80211
+               DBG_8723A("%s without scan req\n", __func__);
+#endif
+       }
+       spin_unlock_bh(&pwdev_priv->scan_req_lock);
+}
+
+void rtw_cfg80211_surveydone_event_callback(struct rtw_adapter *padapter)
+{
+       struct list_head *plist, *phead, *ptmp;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct rtw_queue *queue = &pmlmepriv->scanned_queue;
+       struct wlan_network *pnetwork;
+
+#ifdef CONFIG_DEBUG_CFG80211
+       DBG_8723A("%s\n", __func__);
+#endif
+
+       spin_lock_bh(&pmlmepriv->scanned_queue.lock);
+
+       phead = get_list_head(queue);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               pnetwork = container_of(plist, struct wlan_network, list);
+
+               /* report network only if the current channel set
+                  contains the channel to which this network belongs */
+               if (rtw_ch_set_search_ch23a
+                   (padapter->mlmeextpriv.channel_set,
+                    pnetwork->network.Configuration.DSConfig) >= 0)
+                       rtw_cfg80211_inform_bss(padapter, pnetwork);
+       }
+
+       spin_unlock_bh(&pmlmepriv->scanned_queue.lock);
+
+       /* call this after other things have been done */
+       rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev),
+                                       false);
+}
+
+static int rtw_cfg80211_set_probe_req_wpsp2pie(struct rtw_adapter *padapter,
+                                              char *buf, int len)
+{
+       int ret = 0;
+       uint wps_ielen = 0;
+       u8 *wps_ie;
+#ifdef CONFIG_8723AU_P2P
+       u32 p2p_ielen = 0;
+       u8 *p2p_ie;
+       u32 wfd_ielen = 0;
+#endif
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+#ifdef CONFIG_DEBUG_CFG80211
+       DBG_8723A("%s, ielen =%d\n", __func__, len);
+#endif
+
+       if (len > 0) {
+               wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen);
+               if (wps_ie) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("probe_req_wps_ielen =%d\n", wps_ielen);
+#endif
+                       if (pmlmepriv->wps_probe_req_ie) {
+                               pmlmepriv->wps_probe_req_ie_len = 0;
+                               kfree(pmlmepriv->wps_probe_req_ie);
+                               pmlmepriv->wps_probe_req_ie = NULL;
+                       }
+
+                       pmlmepriv->wps_probe_req_ie =
+                               kmalloc(wps_ielen, GFP_KERNEL);
+                       if (pmlmepriv->wps_probe_req_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               return -EINVAL;
+                       }
+                       memcpy(pmlmepriv->wps_probe_req_ie, wps_ie, wps_ielen);
+                       pmlmepriv->wps_probe_req_ie_len = wps_ielen;
+               }
+#ifdef CONFIG_8723AU_P2P
+               p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen);
+               if (p2p_ie) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("probe_req_p2p_ielen =%d\n", p2p_ielen);
+#endif
+
+                       if (pmlmepriv->p2p_probe_req_ie) {
+                               pmlmepriv->p2p_probe_req_ie_len = 0;
+                               kfree(pmlmepriv->p2p_probe_req_ie);
+                               pmlmepriv->p2p_probe_req_ie = NULL;
+                       }
+
+                       pmlmepriv->p2p_probe_req_ie =
+                               kmalloc(p2p_ielen, GFP_KERNEL);
+                       if (pmlmepriv->p2p_probe_req_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               return -EINVAL;
+
+                       }
+                       memcpy(pmlmepriv->p2p_probe_req_ie, p2p_ie, p2p_ielen);
+                       pmlmepriv->p2p_probe_req_ie_len = p2p_ielen;
+               }
+#endif /* CONFIG_8723AU_P2P */
+
+               /* buf += p2p_ielen; */
+               /* len -= p2p_ielen; */
+
+#ifdef CONFIG_8723AU_P2P
+               if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("probe_req_wfd_ielen =%d\n", wfd_ielen);
+#endif
+
+                       if (pmlmepriv->wfd_probe_req_ie) {
+                               pmlmepriv->wfd_probe_req_ie_len = 0;
+                               kfree(pmlmepriv->wfd_probe_req_ie);
+                               pmlmepriv->wfd_probe_req_ie = NULL;
+                       }
+
+                       pmlmepriv->wfd_probe_req_ie =
+                               kmalloc(wfd_ielen, GFP_KERNEL);
+                       if (pmlmepriv->wfd_probe_req_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               return -EINVAL;
+
+                       }
+                       rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_req_ie,
+                                      &pmlmepriv->wfd_probe_req_ie_len);
+               }
+#endif /* CONFIG_8723AU_P2P */
+
+       }
+
+       return ret;
+}
+
+static int cfg80211_rtw_scan(struct wiphy *wiphy,
+                            struct cfg80211_scan_request *request)
+{
+       int i;
+       u8 _status = false;
+       int ret = 0;
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct cfg80211_ssid ssid[RTW_SSID_SCAN_AMOUNT];
+       struct rtw_ieee80211_channel ch[RTW_CHANNEL_SCAN_AMOUNT];
+       struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev);
+       struct cfg80211_ssid *ssids = request->ssids;
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       int social_channel = 0;
+#endif /* CONFIG_8723AU_P2P */
+       bool need_indicate_scan_done = false;
+
+#ifdef CONFIG_DEBUG_CFG80211
+       DBG_8723A(FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter));
+#endif
+
+       spin_lock_bh(&pwdev_priv->scan_req_lock);
+       pwdev_priv->scan_request = request;
+       spin_unlock_bh(&pwdev_priv->scan_req_lock);
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+
+#ifdef CONFIG_DEBUG_CFG80211
+               DBG_8723A("%s under WIFI_AP_STATE\n", __func__);
+#endif
+               /* need_indicate_scan_done = true; */
+               /* goto check_need_indicate_scan_done; */
+       }
+
+       if (rtw_pwr_wakeup(padapter) == _FAIL) {
+               need_indicate_scan_done = true;
+               goto check_need_indicate_scan_done;
+       }
+#ifdef CONFIG_8723AU_P2P
+       if (!memcmp(ssids->ssid, "DIRECT-", 7) &&
+           rtw_get_p2p_ie23a((u8 *) request->ie, request->ie_len, NULL, NULL)) {
+               if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+                       rtw_p2p_enable23a(padapter, P2P_ROLE_DEVICE);
+                       wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = true;
+               } else {
+                       rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__,
+                                 rtw_p2p_role(pwdinfo),
+                                 rtw_p2p_state(pwdinfo));
+#endif
+               }
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+
+               if (request->n_channels == 3 &&
+                   request->channels[0]->hw_value == 1 &&
+                   request->channels[1]->hw_value == 6 &&
+                   request->channels[2]->hw_value == 11)
+                       social_channel = 1;
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       if (request->ie && request->ie_len > 0) {
+               rtw_cfg80211_set_probe_req_wpsp2pie(padapter,
+                                                   (u8 *) request->ie,
+                                                   request->ie_len);
+       }
+
+       if (pmlmepriv->LinkDetectInfo.bBusyTraffic == true) {
+               DBG_8723A("%s, bBusyTraffic == true\n", __func__);
+               need_indicate_scan_done = true;
+               goto check_need_indicate_scan_done;
+       }
+       if (rtw_is_scan_deny(padapter)) {
+               DBG_8723A(FUNC_ADPT_FMT ": scan deny\n",
+                         FUNC_ADPT_ARG(padapter));
+               need_indicate_scan_done = true;
+               goto check_need_indicate_scan_done;
+       }
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING) ==
+           true) {
+               DBG_8723A("%s, fwstate = 0x%x\n", __func__, pmlmepriv->fw_state);
+               need_indicate_scan_done = true;
+               goto check_need_indicate_scan_done;
+       }
+#ifdef CONFIG_8723AU_P2P
+       if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE) &&
+           !rtw_p2p_chk_state(pwdinfo, P2P_STATE_IDLE)) {
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_FIND_PHASE_SEARCH);
+               rtw_free_network_queue23a(padapter, true);
+
+               if (social_channel == 0)
+                       rtw_p2p_findphase_ex_set(pwdinfo,
+                                                P2P_FINDPHASE_EX_NONE);
+               else
+                       rtw_p2p_findphase_ex_set(pwdinfo,
+                                                P2P_FINDPHASE_EX_SOCIAL_LAST);
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       memset(ssid, 0, sizeof(struct cfg80211_ssid) * RTW_SSID_SCAN_AMOUNT);
+       /* parsing request ssids, n_ssids */
+       for (i = 0; i < request->n_ssids && i < RTW_SSID_SCAN_AMOUNT; i++) {
+#ifdef CONFIG_DEBUG_CFG80211
+               DBG_8723A("ssid =%s, len =%d\n", ssids[i].ssid,
+                         ssids[i].ssid_len);
+#endif
+               memcpy(ssid[i].ssid, ssids[i].ssid, ssids[i].ssid_len);
+               ssid[i].ssid_len = ssids[i].ssid_len;
+       }
+
+       /* parsing channels, n_channels */
+       memset(ch, 0,
+              sizeof(struct rtw_ieee80211_channel) * RTW_CHANNEL_SCAN_AMOUNT);
+
+       if (request->n_channels == 1) {
+               for (i = 0; i < request->n_channels &&
+                    i < RTW_CHANNEL_SCAN_AMOUNT; i++) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A(FUNC_ADPT_FMT CHAN_FMT "\n",
+                                 FUNC_ADPT_ARG(padapter),
+                                 CHAN_ARG(request->channels[i]));
+#endif
+                       ch[i].hw_value = request->channels[i]->hw_value;
+                       ch[i].flags = request->channels[i]->flags;
+               }
+       }
+
+       spin_lock_bh(&pmlmepriv->lock);
+       if (request->n_channels == 1) {
+               memcpy(&ch[1], &ch[0], sizeof(struct rtw_ieee80211_channel));
+               memcpy(&ch[2], &ch[0], sizeof(struct rtw_ieee80211_channel));
+               _status = rtw_sitesurvey_cmd23a(padapter, ssid,
+                                            RTW_SSID_SCAN_AMOUNT, ch, 3);
+       } else {
+               _status = rtw_sitesurvey_cmd23a(padapter, ssid,
+                                            RTW_SSID_SCAN_AMOUNT, NULL, 0);
+       }
+       spin_unlock_bh(&pmlmepriv->lock);
+
+       if (_status == false)
+               ret = -1;
+
+check_need_indicate_scan_done:
+       if (need_indicate_scan_done)
+               rtw_cfg80211_surveydone_event_callback(padapter);
+       return ret;
+}
+
+static int cfg80211_rtw_set_wiphy_params(struct wiphy *wiphy, u32 changed)
+{
+       DBG_8723A("%s\n", __func__);
+       return 0;
+}
+
+static int cfg80211_rtw_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
+                                 struct cfg80211_ibss_params *params)
+{
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+       return 0;
+}
+
+static int cfg80211_rtw_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
+{
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+       return 0;
+}
+
+static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv,
+                                       u32 wpa_version)
+{
+       DBG_8723A("%s, wpa_version =%d\n", __func__, wpa_version);
+
+       if (!wpa_version) {
+               psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
+               return 0;
+       }
+
+       if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) {
+               psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK;
+       }
+
+/*
+       if (wpa_version & NL80211_WPA_VERSION_2)
+       {
+               psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPA2PSK;
+       }
+*/
+
+       return 0;
+}
+
+static int rtw_cfg80211_set_auth_type(struct security_priv *psecuritypriv,
+                                     enum nl80211_auth_type sme_auth_type)
+{
+       DBG_8723A("%s, nl80211_auth_type =%d\n", __func__, sme_auth_type);
+
+       switch (sme_auth_type) {
+       case NL80211_AUTHTYPE_AUTOMATIC:
+               psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Auto;
+
+               break;
+       case NL80211_AUTHTYPE_OPEN_SYSTEM:
+               psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+
+               if (psecuritypriv->ndisauthtype > Ndis802_11AuthModeWPA)
+                       psecuritypriv->dot11AuthAlgrthm =
+                               dot11AuthAlgrthm_8021X;
+               break;
+       case NL80211_AUTHTYPE_SHARED_KEY:
+               psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Shared;
+
+               psecuritypriv->ndisencryptstatus = Ndis802_11Encryption1Enabled;
+               break;
+       default:
+               psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+               /* return -ENOTSUPP; */
+       }
+
+       return 0;
+}
+
+static int rtw_cfg80211_set_cipher(struct security_priv *psecuritypriv,
+                                  u32 cipher, bool ucast)
+{
+       u32 ndisencryptstatus = Ndis802_11EncryptionDisabled;
+
+       u32 *profile_cipher = ucast ? &psecuritypriv->dot11PrivacyAlgrthm :
+           &psecuritypriv->dot118021XGrpPrivacy;
+
+       DBG_8723A("%s, ucast =%d, cipher = 0x%x\n", __func__, ucast, cipher);
+
+       if (!cipher) {
+               *profile_cipher = _NO_PRIVACY_;
+               psecuritypriv->ndisencryptstatus = ndisencryptstatus;
+               return 0;
+       }
+
+       switch (cipher) {
+       case IW_AUTH_CIPHER_NONE:
+               *profile_cipher = _NO_PRIVACY_;
+               ndisencryptstatus = Ndis802_11EncryptionDisabled;
+               break;
+       case WLAN_CIPHER_SUITE_WEP40:
+               *profile_cipher = _WEP40_;
+               ndisencryptstatus = Ndis802_11Encryption1Enabled;
+               break;
+       case WLAN_CIPHER_SUITE_WEP104:
+               *profile_cipher = _WEP104_;
+               ndisencryptstatus = Ndis802_11Encryption1Enabled;
+               break;
+       case WLAN_CIPHER_SUITE_TKIP:
+               *profile_cipher = _TKIP_;
+               ndisencryptstatus = Ndis802_11Encryption2Enabled;
+               break;
+       case WLAN_CIPHER_SUITE_CCMP:
+               *profile_cipher = _AES_;
+               ndisencryptstatus = Ndis802_11Encryption3Enabled;
+               break;
+       default:
+               DBG_8723A("Unsupported cipher: 0x%x\n", cipher);
+               return -ENOTSUPP;
+       }
+
+       if (ucast)
+               psecuritypriv->ndisencryptstatus = ndisencryptstatus;
+
+       return 0;
+}
+
+static int rtw_cfg80211_set_key_mgt(struct security_priv *psecuritypriv,
+                                   u32 key_mgt)
+{
+       DBG_8723A("%s, key_mgt = 0x%x\n", __func__, key_mgt);
+
+       if (key_mgt == WLAN_AKM_SUITE_8021X)
+               psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+       else if (key_mgt == WLAN_AKM_SUITE_PSK)
+               psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_8021X;
+       else
+               DBG_8723A("Invalid key mgt: 0x%x\n", key_mgt);
+
+       return 0;
+}
+
+static int rtw_cfg80211_set_wpa_ie(struct rtw_adapter *padapter, const u8 *pie,
+                                  size_t ielen)
+{
+       u8 *buf = NULL, *pos = NULL;
+       int group_cipher = 0, pairwise_cipher = 0;
+       int ret = 0;
+       int wpa_ielen = 0;
+       int wpa2_ielen = 0;
+       u8 *pwpa, *pwpa2;
+       u8 null_addr[] = { 0, 0, 0, 0, 0, 0 };
+       int i;
+
+       if (!pie || !ielen) {
+               /* Treat this as normal case, but need to clear
+                  WIFI_UNDER_WPS */
+               _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+               goto exit;
+       }
+       if (ielen > MAX_WPA_IE_LEN + MAX_WPS_IE_LEN + MAX_P2P_IE_LEN) {
+               ret = -EINVAL;
+               goto exit;
+       }
+       buf = kzalloc(ielen, GFP_KERNEL);
+       if (buf == NULL) {
+               ret = -ENOMEM;
+               goto exit;
+       }
+       memcpy(buf, pie, ielen);
+
+       /* dump */
+       DBG_8723A("set wpa_ie(length:%zu):\n", ielen);
+       for (i = 0; i < ielen; i = i + 8)
+               DBG_8723A("0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x 0x%.2x\n",
+                         buf[i], buf[i + 1],
+                         buf[i + 2], buf[i + 3], buf[i + 4],
+                         buf[i + 5], buf[i + 6], buf[i + 7]);
+       pos = buf;
+       if (ielen < RSN_HEADER_LEN) {
+               RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_err_,
+                        ("Ie len too short %d\n", (int)ielen));
+               ret = -1;
+               goto exit;
+       }
+
+       pwpa = rtw_get_wpa_ie23a(buf, &wpa_ielen, ielen);
+       if (pwpa && wpa_ielen > 0) {
+               if (rtw_parse_wpa_ie23a(pwpa, wpa_ielen + 2, &group_cipher,
+                                    &pairwise_cipher, NULL) == _SUCCESS) {
+                       padapter->securitypriv.dot11AuthAlgrthm =
+                               dot11AuthAlgrthm_8021X;
+                       padapter->securitypriv.ndisauthtype =
+                               Ndis802_11AuthModeWPAPSK;
+                       memcpy(padapter->securitypriv.supplicant_ie, &pwpa[0],
+                              wpa_ielen + 2);
+
+                       DBG_8723A("got wpa_ie, wpa_ielen:%u\n", wpa_ielen);
+               }
+       }
+
+       pwpa2 = rtw_get_wpa2_ie23a(buf, &wpa2_ielen, ielen);
+       if (pwpa2 && wpa2_ielen > 0) {
+               if (rtw_parse_wpa2_ie23a (pwpa2, wpa2_ielen + 2, &group_cipher,
+                                      &pairwise_cipher, NULL) == _SUCCESS) {
+                       padapter->securitypriv.dot11AuthAlgrthm =
+                               dot11AuthAlgrthm_8021X;
+                       padapter->securitypriv.ndisauthtype =
+                               Ndis802_11AuthModeWPA2PSK;
+                       memcpy(padapter->securitypriv.supplicant_ie, &pwpa2[0],
+                              wpa2_ielen + 2);
+
+                       DBG_8723A("got wpa2_ie, wpa2_ielen:%u\n", wpa2_ielen);
+               }
+       }
+
+       if (group_cipher == 0) {
+               group_cipher = WPA_CIPHER_NONE;
+       }
+       if (pairwise_cipher == 0) {
+               pairwise_cipher = WPA_CIPHER_NONE;
+       }
+
+       switch (group_cipher) {
+       case WPA_CIPHER_NONE:
+               padapter->securitypriv.dot118021XGrpPrivacy = _NO_PRIVACY_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11EncryptionDisabled;
+               break;
+       case WPA_CIPHER_WEP40:
+               padapter->securitypriv.dot118021XGrpPrivacy = _WEP40_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11Encryption1Enabled;
+               break;
+       case WPA_CIPHER_TKIP:
+               padapter->securitypriv.dot118021XGrpPrivacy = _TKIP_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11Encryption2Enabled;
+               break;
+       case WPA_CIPHER_CCMP:
+               padapter->securitypriv.dot118021XGrpPrivacy = _AES_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11Encryption3Enabled;
+               break;
+       case WPA_CIPHER_WEP104:
+               padapter->securitypriv.dot118021XGrpPrivacy = _WEP104_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11Encryption1Enabled;
+               break;
+       }
+
+       switch (pairwise_cipher) {
+       case WPA_CIPHER_NONE:
+               padapter->securitypriv.dot11PrivacyAlgrthm = _NO_PRIVACY_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11EncryptionDisabled;
+               break;
+       case WPA_CIPHER_WEP40:
+               padapter->securitypriv.dot11PrivacyAlgrthm = _WEP40_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11Encryption1Enabled;
+               break;
+       case WPA_CIPHER_TKIP:
+               padapter->securitypriv.dot11PrivacyAlgrthm = _TKIP_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11Encryption2Enabled;
+               break;
+       case WPA_CIPHER_CCMP:
+               padapter->securitypriv.dot11PrivacyAlgrthm = _AES_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11Encryption3Enabled;
+               break;
+       case WPA_CIPHER_WEP104:
+               padapter->securitypriv.dot11PrivacyAlgrthm = _WEP104_;
+               padapter->securitypriv.ndisencryptstatus =
+                       Ndis802_11Encryption1Enabled;
+               break;
+       }
+
+       {                       /* handle wps_ie */
+               uint wps_ielen;
+               u8 *wps_ie;
+
+               wps_ie = rtw_get_wps_ie23a(buf, ielen, NULL, &wps_ielen);
+               if (wps_ie && wps_ielen > 0) {
+                       DBG_8723A("got wps_ie, wps_ielen:%u\n", wps_ielen);
+                       padapter->securitypriv.wps_ie_len =
+                               wps_ielen <
+                               MAX_WPS_IE_LEN ? wps_ielen : MAX_WPS_IE_LEN;
+                       memcpy(padapter->securitypriv.wps_ie, wps_ie,
+                              padapter->securitypriv.wps_ie_len);
+                       set_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS);
+               } else {
+                       _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+               }
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       {                       /* check p2p_ie for assoc req; */
+               uint p2p_ielen = 0;
+               u8 *p2p_ie;
+               struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+               p2p_ie = rtw_get_p2p_ie23a(buf, ielen, NULL, &p2p_ielen);
+               if (p2p_ie) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("%s p2p_assoc_req_ielen =%d\n", __func__,
+                                 p2p_ielen);
+#endif
+
+                       if (pmlmepriv->p2p_assoc_req_ie) {
+                               pmlmepriv->p2p_assoc_req_ie_len = 0;
+                               kfree(pmlmepriv->p2p_assoc_req_ie);
+                               pmlmepriv->p2p_assoc_req_ie = NULL;
+                       }
+
+                       pmlmepriv->p2p_assoc_req_ie =
+                               kmalloc(p2p_ielen, GFP_KERNEL);
+                       if (pmlmepriv->p2p_assoc_req_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               goto exit;
+                       }
+                       memcpy(pmlmepriv->p2p_assoc_req_ie, p2p_ie, p2p_ielen);
+                       pmlmepriv->p2p_assoc_req_ie_len = p2p_ielen;
+               }
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+#ifdef CONFIG_8723AU_P2P
+       {                       /* check wfd_ie for assoc req; */
+               uint wfd_ielen = 0;
+               struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+               if (rtw_get_wfd_ie(buf, ielen, NULL, &wfd_ielen)) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("%s wfd_assoc_req_ielen =%d\n", __func__,
+                                 wfd_ielen);
+#endif
+
+                       if (pmlmepriv->wfd_assoc_req_ie) {
+                               pmlmepriv->wfd_assoc_req_ie_len = 0;
+                               kfree(pmlmepriv->wfd_assoc_req_ie);
+                               pmlmepriv->wfd_assoc_req_ie = NULL;
+                       }
+
+                       pmlmepriv->wfd_assoc_req_ie =
+                               kmalloc(wfd_ielen, GFP_KERNEL);
+                       if (pmlmepriv->wfd_assoc_req_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               goto exit;
+                       }
+                       rtw_get_wfd_ie(buf, ielen, pmlmepriv->wfd_assoc_req_ie,
+                                      &pmlmepriv->wfd_assoc_req_ie_len);
+               }
+       }
+#endif /* CONFIG_8723AU_P2P */
+
+       /* TKIP and AES disallow multicast packets until installing group key */
+       if (padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_ ||
+           padapter->securitypriv.dot11PrivacyAlgrthm == _TKIP_WTMIC_ ||
+           padapter->securitypriv.dot11PrivacyAlgrthm == _AES_)
+               /* WPS open need to enable multicast */
+               /* check_fwstate(&padapter->mlmepriv, WIFI_UNDER_WPS) == true)*/
+               rtw_hal_set_hwreg23a(padapter, HW_VAR_OFF_RCR_AM, null_addr);
+
+       RT_TRACE(_module_rtl871x_ioctl_os_c, _drv_info_,
+                ("rtw_set_wpa_ie: pairwise_cipher = 0x%08x padapter->"
+                 "securitypriv.ndisencryptstatus =%d padapter->"
+                 "securitypriv.ndisauthtype =%d\n", pairwise_cipher,
+                 padapter->securitypriv.ndisencryptstatus,
+                 padapter->securitypriv.ndisauthtype));
+
+exit:
+       kfree(buf);
+       if (ret)
+               _clr_fwstate_(&padapter->mlmepriv, WIFI_UNDER_WPS);
+       return ret;
+}
+
+static int cfg80211_rtw_connect(struct wiphy *wiphy, struct net_device *ndev,
+                               struct cfg80211_connect_params *sme)
+{
+       int ret = 0;
+       struct list_head *phead, *plist, *ptmp;
+       struct wlan_network *pnetwork = NULL;
+       enum ndis_802_11_auth_mode authmode;
+       struct cfg80211_ssid ndis_ssid;
+       u8 *dst_ssid;
+       u8 *src_ssid;
+       u8 *dst_bssid;
+       const u8 *src_bssid;
+       /* u8 matched_by_bssid = false; */
+       /* u8 matched_by_ssid = false; */
+       u8 matched = false;
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       struct rtw_queue *queue = &pmlmepriv->scanned_queue;
+
+       DBG_8723A("=>" FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+       DBG_8723A("privacy =%d, key =%p, key_len =%d, key_idx =%d\n",
+                 sme->privacy, sme->key, sme->key_len, sme->key_idx);
+
+       if (wdev_to_priv(padapter->rtw_wdev)->block) {
+               ret = -EBUSY;
+               DBG_8723A("%s wdev_priv.block is set\n", __func__);
+               goto exit;
+       }
+
+       if (_FAIL == rtw_pwr_wakeup(padapter)) {
+               ret = -EPERM;
+               goto exit;
+       }
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE)) {
+               ret = -EPERM;
+               goto exit;
+       }
+
+       if (!sme->ssid || !sme->ssid_len) {
+               ret = -EINVAL;
+               goto exit;
+       }
+
+       if (sme->ssid_len > IW_ESSID_MAX_SIZE) {
+               ret = -E2BIG;
+               goto exit;
+       }
+
+       memset(&ndis_ssid, 0, sizeof(struct cfg80211_ssid));
+       ndis_ssid.ssid_len = sme->ssid_len;
+       memcpy(ndis_ssid.ssid, sme->ssid, sme->ssid_len);
+
+       DBG_8723A("ssid =%s, len =%zu\n", ndis_ssid.ssid, sme->ssid_len);
+
+       if (sme->bssid)
+               DBG_8723A("bssid =" MAC_FMT "\n", MAC_ARG(sme->bssid));
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING)) {
+               ret = -EBUSY;
+               DBG_8723A("%s, fw_state = 0x%x, goto exit\n", __func__,
+                         pmlmepriv->fw_state);
+               goto exit;
+       }
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY)) {
+               rtw_scan_abort23a(padapter);
+       }
+
+       spin_lock_bh(&queue->lock);
+
+       phead = get_list_head(queue);
+
+       list_for_each_safe(plist, ptmp, phead) {
+               pnetwork = container_of(plist, struct wlan_network, list);
+
+               dst_ssid = pnetwork->network.Ssid.ssid;
+               dst_bssid = pnetwork->network.MacAddress;
+
+               if (sme->bssid) {
+                       if (memcmp(pnetwork->network.MacAddress,
+                                  sme->bssid, ETH_ALEN))
+                               continue;
+               }
+
+               if (sme->ssid && sme->ssid_len) {
+                       if (pnetwork->network.Ssid.ssid_len != sme->ssid_len ||
+                           memcmp(pnetwork->network.Ssid.ssid, sme->ssid,
+                                  sme->ssid_len))
+                               continue;
+               }
+
+               if (sme->bssid) {
+                       src_bssid = sme->bssid;
+
+                       if ((!memcmp(dst_bssid, src_bssid, ETH_ALEN))) {
+                               DBG_8723A("matched by bssid\n");
+
+                               ndis_ssid.ssid_len =
+                                   pnetwork->network.Ssid.ssid_len;
+                               memcpy(ndis_ssid.ssid,
+                                      pnetwork->network.Ssid.ssid,
+                                      pnetwork->network.Ssid.ssid_len);
+
+                               matched = true;
+                               break;
+                       }
+
+               } else if (sme->ssid && sme->ssid_len) {
+                       src_ssid = ndis_ssid.ssid;
+
+                       if ((!memcmp(dst_ssid, src_ssid, ndis_ssid.ssid_len)) &&
+                           (pnetwork->network.Ssid.ssid_len ==
+                            ndis_ssid.ssid_len)) {
+                               DBG_8723A("matched by ssid\n");
+                               matched = true;
+                               break;
+                       }
+               }
+       }
+
+       spin_unlock_bh(&queue->lock);
+
+       if (!matched || (pnetwork == NULL)) {
+               ret = -ENOENT;
+               DBG_8723A("connect, matched == false, goto exit\n");
+               goto exit;
+       }
+
+       if (rtw_set_802_11_infrastructure_mode23a
+           (padapter, pnetwork->network.InfrastructureMode) == false) {
+               ret = -EPERM;
+               goto exit;
+       }
+
+       psecuritypriv->ndisencryptstatus = Ndis802_11EncryptionDisabled;
+       psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+       psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+       psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+       psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
+
+       ret =
+           rtw_cfg80211_set_wpa_version(psecuritypriv,
+                                        sme->crypto.wpa_versions);
+       if (ret < 0)
+               goto exit;
+
+       ret = rtw_cfg80211_set_auth_type(psecuritypriv, sme->auth_type);
+
+       if (ret < 0)
+               goto exit;
+
+       DBG_8723A("%s, ie_len =%zu\n", __func__, sme->ie_len);
+
+       ret = rtw_cfg80211_set_wpa_ie(padapter, sme->ie, sme->ie_len);
+       if (ret < 0)
+               goto exit;
+
+       if (sme->crypto.n_ciphers_pairwise) {
+               ret = rtw_cfg80211_set_cipher(psecuritypriv,
+                                             sme->crypto.ciphers_pairwise[0],
+                                             true);
+               if (ret < 0)
+                       goto exit;
+       }
+
+       /* For WEP Shared auth */
+       if ((psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Shared ||
+            psecuritypriv->dot11AuthAlgrthm == dot11AuthAlgrthm_Auto) &&
+           sme->key) {
+               u32 wep_key_idx, wep_key_len, wep_total_len;
+               struct ndis_802_11_wep *pwep = NULL;
+               DBG_8723A("%s(): Shared/Auto WEP\n", __func__);
+
+               wep_key_idx = sme->key_idx;
+               wep_key_len = sme->key_len;
+
+               if (sme->key_idx > WEP_KEYS) {
+                       ret = -EINVAL;
+                       goto exit;
+               }
+
+               if (wep_key_len > 0) {
+                       wep_key_len = wep_key_len <= 5 ? 5 : 13;
+                       wep_total_len =
+                               wep_key_len +
+                               offsetof(struct ndis_802_11_wep, KeyMaterial);
+                       pwep = (struct ndis_802_11_wep *)kmalloc(wep_total_len,
+                                                                GFP_KERNEL);
+                       if (pwep == NULL) {
+                               DBG_8723A(" wpa_set_encryption: pwep "
+                                         "allocate fail !!!\n");
+                               ret = -ENOMEM;
+                               goto exit;
+                       }
+
+                       memset(pwep, 0, wep_total_len);
+
+                       pwep->KeyLength = wep_key_len;
+                       pwep->Length = wep_total_len;
+
+                       if (wep_key_len == 13) {
+                               padapter->securitypriv.dot11PrivacyAlgrthm =
+                                   _WEP104_;
+                               padapter->securitypriv.dot118021XGrpPrivacy =
+                                   _WEP104_;
+                       }
+               } else {
+                       ret = -EINVAL;
+                       goto exit;
+               }
+
+               pwep->KeyIndex = wep_key_idx;
+               pwep->KeyIndex |= 0x80000000;
+
+               memcpy(pwep->KeyMaterial, (void *)sme->key, pwep->KeyLength);
+
+               if (rtw_set_802_11_add_wep23a(padapter, pwep) == (u8) _FAIL) {
+                       ret = -EOPNOTSUPP;
+               }
+
+               kfree(pwep);
+
+               if (ret < 0)
+                       goto exit;
+       }
+
+       ret = rtw_cfg80211_set_cipher(psecuritypriv,
+                                     sme->crypto.cipher_group, false);
+       if (ret < 0)
+               return ret;
+
+       if (sme->crypto.n_akm_suites) {
+               ret = rtw_cfg80211_set_key_mgt(psecuritypriv,
+                                              sme->crypto.akm_suites[0]);
+               if (ret < 0)
+                       goto exit;
+       }
+
+       authmode = psecuritypriv->ndisauthtype;
+       rtw_set_802_11_authentication_mode23a(padapter, authmode);
+
+       /* rtw_set_802_11_encryption_mode(padapter,
+          padapter->securitypriv.ndisencryptstatus); */
+
+       if (rtw_set_802_11_ssid23a(padapter, &ndis_ssid) == false) {
+               ret = -1;
+               goto exit;
+       }
+
+       DBG_8723A("set ssid:dot11AuthAlgrthm =%d, dot11PrivacyAlgrthm =%d, "
+                 "dot118021XGrpPrivacy =%d\n", psecuritypriv->dot11AuthAlgrthm,
+                 psecuritypriv->dot11PrivacyAlgrthm,
+                 psecuritypriv->dot118021XGrpPrivacy);
+
+exit:
+
+       DBG_8723A("<=%s, ret %d\n", __func__, ret);
+
+       return ret;
+}
+
+static int cfg80211_rtw_disconnect(struct wiphy *wiphy, struct net_device *ndev,
+                                  u16 reason_code)
+{
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+
+       rtw_set_roaming(padapter, 0);
+
+       if (check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+               rtw_scan_abort23a(padapter);
+               LeaveAllPowerSaveMode23a(padapter);
+               rtw_disassoc_cmd23a(padapter, 500, false);
+
+               DBG_8723A("%s...call rtw_indicate_disconnect23a\n", __func__);
+
+               padapter->mlmepriv.not_indic_disco = true;
+               rtw_indicate_disconnect23a(padapter);
+               padapter->mlmepriv.not_indic_disco = false;
+
+               rtw_free_assoc_resources23a(padapter, 1);
+       }
+
+       return 0;
+}
+
+static int cfg80211_rtw_set_txpower(struct wiphy *wiphy,
+                                   struct wireless_dev *wdev,
+                                   enum nl80211_tx_power_setting type, int mbm)
+{
+       DBG_8723A("%s\n", __func__);
+       return 0;
+}
+
+static int cfg80211_rtw_get_txpower(struct wiphy *wiphy,
+                                   struct wireless_dev *wdev, int *dbm)
+{
+       DBG_8723A("%s\n", __func__);
+       *dbm = (12);
+       return 0;
+}
+
+inline bool rtw_cfg80211_pwr_mgmt(struct rtw_adapter *adapter)
+{
+       struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(adapter->rtw_wdev);
+       return rtw_wdev_priv->power_mgmt;
+}
+
+static int cfg80211_rtw_set_power_mgmt(struct wiphy *wiphy,
+                                      struct net_device *ndev,
+                                      bool enabled, int timeout)
+{
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct rtw_wdev_priv *rtw_wdev_priv = wdev_to_priv(padapter->rtw_wdev);
+
+       DBG_8723A(FUNC_NDEV_FMT " enabled:%u, timeout:%d\n",
+                 FUNC_NDEV_ARG(ndev), enabled, timeout);
+
+       rtw_wdev_priv->power_mgmt = enabled;
+
+       if (!enabled)
+               LPS_Leave23a(padapter);
+
+       return 0;
+}
+
+static int cfg80211_rtw_set_pmksa(struct wiphy *wiphy,
+                                 struct net_device *netdev,
+                                 struct cfg80211_pmksa *pmksa)
+{
+       u8 index, blInserted = false;
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       u8 strZeroMacAddress[ETH_ALEN] = { 0x00 };
+
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(netdev));
+
+       if (!memcmp(pmksa->bssid, strZeroMacAddress, ETH_ALEN)) {
+               return -EINVAL;
+       }
+
+       blInserted = false;
+
+       /* overwrite PMKID */
+       for (index = 0; index < NUM_PMKID_CACHE; index++) {
+               if (!memcmp(psecuritypriv->PMKIDList[index].Bssid,
+                           pmksa->bssid, ETH_ALEN)) {
+                       /* BSSID is matched, the same AP => rewrite with
+                          new PMKID. */
+                       DBG_8723A(FUNC_NDEV_FMT
+                                 " BSSID exists in the PMKList.\n",
+                                 FUNC_NDEV_ARG(netdev));
+
+                       memcpy(psecuritypriv->PMKIDList[index].PMKID,
+                              pmksa->pmkid, WLAN_PMKID_LEN);
+                       psecuritypriv->PMKIDList[index].bUsed = true;
+                       psecuritypriv->PMKIDIndex = index + 1;
+                       blInserted = true;
+                       break;
+               }
+       }
+
+       if (!blInserted) {
+               /*  Find a new entry */
+               DBG_8723A(FUNC_NDEV_FMT
+                         " Use the new entry index = %d for this PMKID.\n",
+                         FUNC_NDEV_ARG(netdev), psecuritypriv->PMKIDIndex);
+
+               memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].
+                      Bssid, pmksa->bssid, ETH_ALEN);
+               memcpy(psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].
+                      PMKID, pmksa->pmkid, WLAN_PMKID_LEN);
+
+               psecuritypriv->PMKIDList[psecuritypriv->PMKIDIndex].bUsed =
+                       true;
+               psecuritypriv->PMKIDIndex++;
+               if (psecuritypriv->PMKIDIndex == 16) {
+                       psecuritypriv->PMKIDIndex = 0;
+               }
+       }
+
+       return 0;
+}
+
+static int cfg80211_rtw_del_pmksa(struct wiphy *wiphy,
+                                 struct net_device *netdev,
+                                 struct cfg80211_pmksa *pmksa)
+{
+       u8 index, bMatched = false;
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(netdev));
+
+       for (index = 0; index < NUM_PMKID_CACHE; index++) {
+               if (!memcmp(psecuritypriv->PMKIDList[index].Bssid,
+                           pmksa->bssid, ETH_ALEN)) {
+                       /* BSSID is matched, the same AP => Remove this PMKID information and reset it. */
+                       memset(psecuritypriv->PMKIDList[index].Bssid, 0x00,
+                              ETH_ALEN);
+                       memset(psecuritypriv->PMKIDList[index].PMKID, 0x00,
+                              WLAN_PMKID_LEN);
+                       psecuritypriv->PMKIDList[index].bUsed = false;
+                       bMatched = true;
+                       break;
+               }
+       }
+
+       if (false == bMatched) {
+               DBG_8723A(FUNC_NDEV_FMT " do not have matched BSSID\n",
+                         FUNC_NDEV_ARG(netdev));
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int cfg80211_rtw_flush_pmksa(struct wiphy *wiphy,
+                                   struct net_device *netdev)
+{
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(netdev));
+
+       memset(&psecuritypriv->PMKIDList[0], 0x00,
+              sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+       psecuritypriv->PMKIDIndex = 0;
+
+       return 0;
+}
+
+#ifdef CONFIG_8723AU_AP_MODE
+void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter,
+                                    u8 *pmgmt_frame, uint frame_len)
+{
+       s32 freq;
+       int channel;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct net_device *ndev = padapter->pnetdev;
+
+       DBG_8723A("%s(padapter =%p,%s)\n", __func__, padapter, ndev->name);
+
+#if defined(RTW_USE_CFG80211_STA_EVENT)
+       {
+               struct station_info sinfo;
+               u8 ie_offset;
+               if (ieee80211_is_assoc_req(hdr->frame_control))
+                       ie_offset = _ASOCREQ_IE_OFFSET_;
+               else            /*  WIFI_REASSOCREQ */
+                       ie_offset = _REASOCREQ_IE_OFFSET_;
+
+               sinfo.filled = 0;
+               sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+               sinfo.assoc_req_ies = pmgmt_frame + WLAN_HDR_A3_LEN + ie_offset;
+               sinfo.assoc_req_ies_len =
+                       frame_len - WLAN_HDR_A3_LEN - ie_offset;
+               cfg80211_new_sta(ndev, hdr->addr2, &sinfo, GFP_ATOMIC);
+       }
+#else /* defined(RTW_USE_CFG80211_STA_EVENT) */
+       channel = pmlmeext->cur_channel;
+       if (channel <= RTW_CH_MAX_2G_CHANNEL)
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_2GHZ);
+       else
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_5GHZ);
+
+       rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len,
+                            GFP_ATOMIC);
+#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
+}
+
+void rtw_cfg80211_indicate_sta_disassoc(struct rtw_adapter *padapter,
+                                       unsigned char *da,
+                                       unsigned short reason)
+{
+       s32 freq;
+       int channel;
+       u8 *pmgmt_frame;
+       uint frame_len;
+       struct ieee80211_hdr *pwlanhdr;
+       unsigned short *fctrl;
+       u8 mgmt_buf[128] = { 0 };
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info;
+       struct net_device *ndev = padapter->pnetdev;
+
+       DBG_8723A("%s(padapter =%p,%s)\n", __func__, padapter, ndev->name);
+
+#if defined(RTW_USE_CFG80211_STA_EVENT)
+       cfg80211_del_sta(ndev, da, GFP_ATOMIC);
+#else /* defined(RTW_USE_CFG80211_STA_EVENT) */
+       channel = pmlmeext->cur_channel;
+       if (channel <= RTW_CH_MAX_2G_CHANNEL)
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_2GHZ);
+       else
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_5GHZ);
+
+       pmgmt_frame = mgmt_buf;
+       pwlanhdr = (struct ieee80211_hdr *)pmgmt_frame;
+
+       fctrl = &pwlanhdr->frame_control;
+       *(fctrl) = 0;
+
+       memcpy(pwlanhdr->addr1, myid(&padapter->eeprompriv), ETH_ALEN);
+       memcpy(pwlanhdr->addr2, da, ETH_ALEN);
+       memcpy(pwlanhdr->addr3, get_my_bssid23a(&pmlmeinfo->network), ETH_ALEN);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pmgmt_frame, WIFI_DEAUTH);
+
+       pmgmt_frame += sizeof(struct ieee80211_hdr_3addr);
+       frame_len = sizeof(struct ieee80211_hdr_3addr);
+
+       reason = cpu_to_le16(reason);
+       pmgmt_frame = rtw_set_fixed_ie23a(pmgmt_frame,
+                                      WLAN_REASON_PREV_AUTH_NOT_VALID,
+                                      (unsigned char *)&reason, &frame_len);
+
+       rtw_cfg80211_rx_mgmt(padapter, freq, 0, mgmt_buf, frame_len,
+                            GFP_ATOMIC);
+#endif /* defined(RTW_USE_CFG80211_STA_EVENT) */
+}
+
+static int rtw_cfg80211_monitor_if_open(struct net_device *ndev)
+{
+       int ret = 0;
+
+       DBG_8723A("%s\n", __func__);
+
+       return ret;
+}
+
+static int rtw_cfg80211_monitor_if_close(struct net_device *ndev)
+{
+       int ret = 0;
+
+       DBG_8723A("%s\n", __func__);
+
+       return ret;
+}
+
+static int rtw_cfg80211_monitor_if_xmit_entry(struct sk_buff *skb,
+                                             struct net_device *ndev)
+{
+       int ret = 0;
+       int rtap_len;
+       int qos_len = 0;
+       int dot11_hdr_len = 24;
+       int snap_len = 6;
+       unsigned char *pdata;
+       unsigned char src_mac_addr[6];
+       unsigned char dst_mac_addr[6];
+       struct ieee80211_hdr *dot11_hdr;
+       struct ieee80211_radiotap_header *rtap_hdr;
+       struct rtw_adapter *padapter = netdev_priv(ndev);
+
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+
+       if (unlikely(skb->len < sizeof(struct ieee80211_radiotap_header)))
+               goto fail;
+
+       rtap_hdr = (struct ieee80211_radiotap_header *)skb->data;
+       if (unlikely(rtap_hdr->it_version))
+               goto fail;
+
+       rtap_len = ieee80211_get_radiotap_len(skb->data);
+       if (unlikely(skb->len < rtap_len))
+               goto fail;
+
+       if (rtap_len != 14) {
+               DBG_8723A("radiotap len (should be 14): %d\n", rtap_len);
+               goto fail;
+       }
+
+       /* Skip the ratio tap header */
+       skb_pull(skb, rtap_len);
+
+       dot11_hdr = (struct ieee80211_hdr *)skb->data;
+       /* Check if the QoS bit is set */
+       if (ieee80211_is_data(dot11_hdr->frame_control)) {
+               /* Check if this ia a Wireless Distribution System (WDS) frame
+                * which has 4 MAC addresses
+                */
+               if (ieee80211_is_data_qos(dot11_hdr->frame_control))
+                       qos_len = IEEE80211_QOS_CTL_LEN;
+               if (ieee80211_has_a4(dot11_hdr->frame_control))
+                       dot11_hdr_len += 6;
+
+               memcpy(dst_mac_addr, dot11_hdr->addr1, sizeof(dst_mac_addr));
+               memcpy(src_mac_addr, dot11_hdr->addr2, sizeof(src_mac_addr));
+
+               /*
+                * Skip the 802.11 header, QoS (if any) and SNAP,
+                * but leave spaces for two MAC addresses
+                */
+               skb_pull(skb, dot11_hdr_len + qos_len + snap_len -
+                        ETH_ALEN * 2);
+               pdata = (unsigned char *)skb->data;
+               memcpy(pdata, dst_mac_addr, ETH_ALEN);
+               memcpy(pdata + ETH_ALEN, src_mac_addr, ETH_ALEN);
+
+               DBG_8723A("should be eapol packet\n");
+
+               /* Use the real net device to transmit the packet */
+               ret = rtw_xmit23a_entry23a(skb, padapter->pnetdev);
+
+               return ret;
+
+       } else if (ieee80211_is_action(dot11_hdr->frame_control)) {
+               /* only for action frames */
+               struct xmit_frame *pmgntframe;
+               struct pkt_attrib *pattrib;
+               unsigned char *pframe;
+               /* u8 category, action, OUI_Subtype, dialogToken = 0; */
+               /* unsigned char        *frame_body; */
+               struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+               struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+               u32 len = skb->len;
+               u8 category, action;
+#ifdef CONFIG_8723AU_P2P
+               int type = -1;
+#endif
+
+               if (rtw_action_frame_parse23a(skb->data, len, &category,
+                                          &action) == false) {
+                       DBG_8723A(FUNC_NDEV_FMT " frame_control:0x%x\n",
+                                 FUNC_NDEV_ARG(ndev),
+                                 le16_to_cpu(dot11_hdr->frame_control));
+                       goto fail;
+               }
+
+               DBG_8723A("RTW_Tx:da =" MAC_FMT " via " FUNC_NDEV_FMT "\n",
+                         MAC_ARG(dot11_hdr->addr1), FUNC_NDEV_ARG(ndev));
+#ifdef CONFIG_8723AU_P2P
+               type = rtw_p2p_check_frames(padapter, skb->data, len, true);
+               if (type >= 0)
+                       goto dump;
+#endif
+               if (category == WLAN_CATEGORY_PUBLIC)
+                       DBG_8723A("RTW_Tx:%s\n", action_public_str23a(action));
+               else
+                       DBG_8723A("RTW_Tx:category(%u), action(%u)\n", category,
+                                 action);
+#ifdef CONFIG_8723AU_P2P
+dump:
+#endif
+               /* starting alloc mgmt frame to dump it */
+               pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
+               if (pmgntframe == NULL)
+                       goto fail;
+
+               /* update attribute */
+               pattrib = &pmgntframe->attrib;
+               update_mgntframe_attrib23a(padapter, pattrib);
+               pattrib->retry_ctrl = false;
+
+               memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+               pframe = (u8 *)(pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+               memcpy(pframe, skb->data, len);
+#ifdef CONFIG_8723AU_P2P
+               if (type >= 0) {
+                       struct wifi_display_info *pwfd_info;
+
+                       pwfd_info = padapter->wdinfo.wfd_info;
+
+                       if (pwfd_info->wfd_enable)
+                               rtw_append_wfd_ie(padapter, pframe, &len);
+               }
+#endif /*  CONFIG_8723AU_P2P */
+               pattrib->pktlen = len;
+
+               /* update seq number */
+               pmlmeext->mgnt_seq = le16_to_cpu(dot11_hdr->seq_ctrl) >> 4;
+               pattrib->seqnum = pmlmeext->mgnt_seq;
+               pmlmeext->mgnt_seq++;
+
+               pattrib->last_txcmdsz = pattrib->pktlen;
+
+               dump_mgntframe23a(padapter, pmgntframe);
+       }
+
+fail:
+
+       dev_kfree_skb(skb);
+
+       return 0;
+}
+
+static int
+rtw_cfg80211_monitor_if_set_mac_address(struct net_device *ndev, void *addr)
+{
+       int ret = 0;
+
+       DBG_8723A("%s\n", __func__);
+
+       return ret;
+}
+
+static const struct net_device_ops rtw_cfg80211_monitor_if_ops = {
+       .ndo_open = rtw_cfg80211_monitor_if_open,
+       .ndo_stop = rtw_cfg80211_monitor_if_close,
+       .ndo_start_xmit = rtw_cfg80211_monitor_if_xmit_entry,
+       .ndo_set_mac_address = rtw_cfg80211_monitor_if_set_mac_address,
+};
+
+static int rtw_cfg80211_add_monitor_if(struct rtw_adapter *padapter, char *name,
+                                      struct net_device **ndev)
+{
+       int ret = 0;
+       struct net_device *mon_ndev = NULL;
+       struct wireless_dev *mon_wdev = NULL;
+       struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev);
+
+       if (!name) {
+               DBG_8723A(FUNC_ADPT_FMT " without specific name\n",
+                         FUNC_ADPT_ARG(padapter));
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (pwdev_priv->pmon_ndev) {
+               DBG_8723A(FUNC_ADPT_FMT " monitor interface exist: " NDEV_FMT
+                         "\n", FUNC_ADPT_ARG(padapter),
+                         NDEV_ARG(pwdev_priv->pmon_ndev));
+               ret = -EBUSY;
+               goto out;
+       }
+
+       mon_ndev = alloc_etherdev(sizeof(struct rtw_adapter));
+       if (!mon_ndev) {
+               DBG_8723A(FUNC_ADPT_FMT " allocate ndev fail\n",
+                         FUNC_ADPT_ARG(padapter));
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       mon_ndev->type = ARPHRD_IEEE80211_RADIOTAP;
+       strncpy(mon_ndev->name, name, IFNAMSIZ);
+       mon_ndev->name[IFNAMSIZ - 1] = 0;
+       mon_ndev->destructor = rtw_ndev_destructor;
+
+       mon_ndev->netdev_ops = &rtw_cfg80211_monitor_if_ops;
+
+       /*  wdev */
+       mon_wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+       if (!mon_wdev) {
+               DBG_8723A(FUNC_ADPT_FMT " allocate mon_wdev fail\n",
+                         FUNC_ADPT_ARG(padapter));
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       mon_wdev->wiphy = padapter->rtw_wdev->wiphy;
+       mon_wdev->netdev = mon_ndev;
+       mon_wdev->iftype = NL80211_IFTYPE_MONITOR;
+       mon_ndev->ieee80211_ptr = mon_wdev;
+
+       ret = register_netdevice(mon_ndev);
+       if (ret) {
+               goto out;
+       }
+
+       *ndev = pwdev_priv->pmon_ndev = mon_ndev;
+       memcpy(pwdev_priv->ifname_mon, name, IFNAMSIZ + 1);
+
+out:
+       if (ret) {
+               kfree(mon_wdev);
+               mon_wdev = NULL;
+       }
+
+       if (ret && mon_ndev) {
+               free_netdev(mon_ndev);
+               *ndev = mon_ndev = NULL;
+       }
+
+       return ret;
+}
+
+static struct wireless_dev *
+cfg80211_rtw_add_virtual_intf(struct wiphy *wiphy, const char *name,
+                             enum nl80211_iftype type, u32 *flags,
+                             struct vif_params *params)
+{
+       int ret = 0;
+       struct net_device *ndev = NULL;
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+
+       DBG_8723A(FUNC_ADPT_FMT " wiphy:%s, name:%s, type:%d\n",
+                 FUNC_ADPT_ARG(padapter), wiphy_name(wiphy), name, type);
+
+       switch (type) {
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_AP_VLAN:
+       case NL80211_IFTYPE_WDS:
+       case NL80211_IFTYPE_MESH_POINT:
+               ret = -ENODEV;
+               break;
+       case NL80211_IFTYPE_MONITOR:
+               ret =
+                   rtw_cfg80211_add_monitor_if(padapter, (char *)name, &ndev);
+               break;
+
+       case NL80211_IFTYPE_P2P_CLIENT:
+       case NL80211_IFTYPE_STATION:
+               ret = -ENODEV;
+               break;
+
+       case NL80211_IFTYPE_P2P_GO:
+       case NL80211_IFTYPE_AP:
+               ret = -ENODEV;
+               break;
+       default:
+               ret = -ENODEV;
+               DBG_8723A("Unsupported interface type\n");
+               break;
+       }
+
+       DBG_8723A(FUNC_ADPT_FMT " ndev:%p, ret:%d\n", FUNC_ADPT_ARG(padapter),
+                 ndev, ret);
+
+       return ndev ? ndev->ieee80211_ptr : ERR_PTR(ret);
+}
+
+static int cfg80211_rtw_del_virtual_intf(struct wiphy *wiphy,
+                                        struct wireless_dev *wdev)
+{
+       struct rtw_wdev_priv *pwdev_priv =
+           (struct rtw_wdev_priv *)wiphy_priv(wiphy);
+       struct net_device *ndev;
+       ndev = wdev ? wdev->netdev : NULL;
+
+       if (!ndev)
+               goto exit;
+
+       unregister_netdevice(ndev);
+
+       if (ndev == pwdev_priv->pmon_ndev) {
+               pwdev_priv->pmon_ndev = NULL;
+               pwdev_priv->ifname_mon[0] = '\0';
+               DBG_8723A(FUNC_NDEV_FMT " remove monitor interface\n",
+                         FUNC_NDEV_ARG(ndev));
+       }
+
+exit:
+       return 0;
+}
+
+static int rtw_add_beacon(struct rtw_adapter *adapter, const u8 *head,
+                         size_t head_len, const u8 *tail, size_t tail_len)
+{
+       int ret = 0;
+       u8 *pbuf = NULL;
+       uint len, wps_ielen = 0;
+#ifdef CONFIG_8723AU_P2P
+       uint p2p_ielen = 0;
+       u8 got_p2p_ie = false;
+#endif
+       struct mlme_priv *pmlmepriv = &adapter->mlmepriv;
+       /* struct sta_priv *pstapriv = &padapter->stapriv; */
+
+       DBG_8723A("%s beacon_head_len =%zu, beacon_tail_len =%zu\n",
+                 __func__, head_len, tail_len);
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE) != true)
+               return -EINVAL;
+
+       if (head_len < 24)
+               return -EINVAL;
+
+       pbuf = kzalloc(head_len + tail_len, GFP_KERNEL);
+       if (!pbuf)
+               return -ENOMEM;
+       /*  24 = beacon header len. */
+       memcpy(pbuf, (void *)head + 24, head_len - 24);
+       memcpy(pbuf + head_len - 24, (void *)tail, tail_len);
+
+       len = head_len + tail_len - 24;
+
+       /* check wps ie if inclued */
+       if (rtw_get_wps_ie23a
+           (pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL,
+            &wps_ielen))
+               DBG_8723A("add bcn, wps_ielen =%d\n", wps_ielen);
+
+#ifdef CONFIG_8723AU_P2P
+       /* check p2p ie if inclued */
+       if (rtw_get_p2p_ie23a
+           (pbuf + _FIXED_IE_LENGTH_, len - _FIXED_IE_LENGTH_, NULL,
+            &p2p_ielen)) {
+               DBG_8723A("got p2p_ie, len =%d\n", p2p_ielen);
+               got_p2p_ie = true;
+       }
+#endif
+
+       /* pbss_network->IEs will not include p2p_ie, wfd ie */
+       rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_,
+                         P2P_OUI23A, 4);
+       rtw_ies_remove_ie23a(pbuf, &len, _BEACON_IE_OFFSET_, _VENDOR_SPECIFIC_IE_,
+                         WFD_OUI23A, 4);
+
+       if (rtw_check_beacon_data23a(adapter, pbuf, len) == _SUCCESS) {
+#ifdef CONFIG_8723AU_P2P
+               /* check p2p if enable */
+               if (got_p2p_ie == true) {
+                       struct mlme_ext_priv *pmlmeext = &adapter->mlmeextpriv;
+                       struct wifidirect_info *pwdinfo = &adapter->wdinfo;
+
+                       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+                               DBG_8723A("Enable P2P function for the first "
+                                         "time\n");
+                               rtw_p2p_enable23a(adapter, P2P_ROLE_GO);
+                               wdev_to_priv(adapter->rtw_wdev)->p2p_enabled =
+                                       true;
+                       } else {
+                               del_timer_sync(&pwdinfo->find_phase_timer);
+                               del_timer_sync(&pwdinfo->
+                                              restore_p2p_state_timer);
+                               del_timer_sync(&pwdinfo->pre_tx_scan_timer);
+
+                               DBG_8723A("enter GO Mode, p2p_ielen =%d\n",
+                                         p2p_ielen);
+
+                               rtw_p2p_set_role(pwdinfo, P2P_ROLE_GO);
+                               rtw_p2p_set_state(pwdinfo, P2P_STATE_GONEGO_OK);
+                               pwdinfo->intent = 15;
+                       }
+
+                       pwdinfo->operating_channel = pmlmeext->cur_channel;
+               }
+#endif /* CONFIG_8723AU_P2P */
+
+               ret = 0;
+
+       } else {
+               ret = -EINVAL;
+       }
+
+       kfree(pbuf);
+
+       return ret;
+}
+
+static int cfg80211_rtw_start_ap(struct wiphy *wiphy, struct net_device *ndev,
+                                struct cfg80211_ap_settings *settings)
+{
+       int ret = 0;
+       struct rtw_adapter *adapter = wiphy_to_adapter(wiphy);
+
+       DBG_8723A(FUNC_NDEV_FMT " hidden_ssid:%d, auth_type:%d\n",
+                 FUNC_NDEV_ARG(ndev), settings->hidden_ssid,
+                 settings->auth_type);
+
+       ret = rtw_add_beacon(adapter, settings->beacon.head,
+                            settings->beacon.head_len, settings->beacon.tail,
+                            settings->beacon.tail_len);
+
+       adapter->mlmeextpriv.mlmext_info.hidden_ssid_mode =
+               settings->hidden_ssid;
+
+       if (settings->ssid && settings->ssid_len) {
+               struct wlan_bssid_ex *pbss_network =
+                       &adapter->mlmepriv.cur_network.network;
+               struct wlan_bssid_ex *pbss_network_ext =
+                       &adapter->mlmeextpriv.mlmext_info.network;
+
+               if (0)
+                       DBG_8723A(FUNC_ADPT_FMT
+                                 " ssid:(%s,%d), from ie:(%s,%d)\n",
+                                 FUNC_ADPT_ARG(adapter), settings->ssid,
+                                 (int)settings->ssid_len,
+                                 pbss_network->Ssid.ssid,
+                                 pbss_network->Ssid.ssid_len);
+
+               memcpy(pbss_network->Ssid.ssid, (void *)settings->ssid,
+                      settings->ssid_len);
+               pbss_network->Ssid.ssid_len = settings->ssid_len;
+               memcpy(pbss_network_ext->Ssid.ssid, (void *)settings->ssid,
+                      settings->ssid_len);
+               pbss_network_ext->Ssid.ssid_len = settings->ssid_len;
+
+               if (0)
+                       DBG_8723A(FUNC_ADPT_FMT
+                                 " after ssid:(%s,%d), (%s,%d)\n",
+                                 FUNC_ADPT_ARG(adapter),
+                                 pbss_network->Ssid.ssid,
+                                 pbss_network->Ssid.ssid_len,
+                                 pbss_network_ext->Ssid.ssid,
+                                 pbss_network_ext->Ssid.ssid_len);
+       }
+
+       return ret;
+}
+
+static int cfg80211_rtw_change_beacon(struct wiphy *wiphy,
+                                     struct net_device *ndev,
+                                     struct cfg80211_beacon_data *info)
+{
+       int ret = 0;
+       struct rtw_adapter *adapter = wiphy_to_adapter(wiphy);
+
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+
+       ret = rtw_add_beacon(adapter, info->head, info->head_len, info->tail,
+                            info->tail_len);
+
+       return ret;
+}
+
+static int cfg80211_rtw_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
+{
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+       return 0;
+}
+
+static int cfg80211_rtw_add_station(struct wiphy *wiphy,
+                                   struct net_device *ndev, u8 *mac,
+                                   struct station_parameters *params)
+{
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+
+       return 0;
+}
+
+static int cfg80211_rtw_del_station(struct wiphy *wiphy,
+                                   struct net_device *ndev, u8 *mac)
+{
+       int ret = 0;
+       struct list_head *phead, *plist, *ptmp;
+       u8 updated = 0;
+       struct sta_info *psta;
+       struct rtw_adapter *padapter = netdev_priv(ndev);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct sta_priv *pstapriv = &padapter->stapriv;
+
+       DBG_8723A("+" FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+
+       if (check_fwstate(pmlmepriv, (_FW_LINKED | WIFI_AP_STATE)) != true) {
+               DBG_8723A("%s, fw_state != FW_LINKED|WIFI_AP_STATE\n",
+                         __func__);
+               return -EINVAL;
+       }
+
+       if (!mac) {
+               DBG_8723A("flush all sta, and cam_entry\n");
+
+               flush_all_cam_entry23a(padapter);       /* clear CAM */
+
+               ret = rtw_sta_flush23a(padapter);
+
+               return ret;
+       }
+
+       DBG_8723A("free sta macaddr =" MAC_FMT "\n", MAC_ARG(mac));
+
+       if (is_broadcast_ether_addr(mac))
+               return -EINVAL;
+
+       spin_lock_bh(&pstapriv->asoc_list_lock);
+
+       phead = &pstapriv->asoc_list;
+
+       /* check asoc_queue */
+       list_for_each_safe(plist, ptmp, phead) {
+               psta = container_of(plist, struct sta_info, asoc_list);
+
+               if (!memcmp(mac, psta->hwaddr, ETH_ALEN)) {
+                       if (psta->dot8021xalg == 1 &&
+                           psta->bpairwise_key_installed == false) {
+                               DBG_8723A("%s, sta's dot8021xalg = 1 and "
+                                         "key_installed = false\n", __func__);
+                       } else {
+                               DBG_8723A("free psta =%p, aid =%d\n", psta,
+                                         psta->aid);
+
+                               list_del_init(&psta->asoc_list);
+                               pstapriv->asoc_list_cnt--;
+
+                               /* spin_unlock_bh(&pstapriv->asoc_list_lock); */
+                               updated =
+                                   ap_free_sta23a(padapter, psta, true,
+                                               WLAN_REASON_DEAUTH_LEAVING);
+                               /* spin_lock_bh(&pstapriv->asoc_list_lock); */
+
+                               psta = NULL;
+
+                               break;
+                       }
+               }
+       }
+
+       spin_unlock_bh(&pstapriv->asoc_list_lock);
+
+       associated_clients_update23a(padapter, updated);
+
+       DBG_8723A("-" FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+
+       return ret;
+}
+
+static int cfg80211_rtw_change_station(struct wiphy *wiphy,
+                                      struct net_device *ndev, u8 *mac,
+                                      struct station_parameters *params)
+{
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+       return 0;
+}
+
+static int cfg80211_rtw_dump_station(struct wiphy *wiphy,
+                                    struct net_device *ndev, int idx, u8 *mac,
+                                    struct station_info *sinfo)
+{
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+
+       /* TODO: dump scanned queue */
+
+       return -ENOENT;
+}
+
+static int cfg80211_rtw_change_bss(struct wiphy *wiphy, struct net_device *ndev,
+                                  struct bss_parameters *params)
+{
+       DBG_8723A(FUNC_NDEV_FMT "\n", FUNC_NDEV_ARG(ndev));
+       return 0;
+}
+#endif /* CONFIG_8723AU_AP_MODE */
+
+void rtw_cfg80211_rx_action_p2p(struct rtw_adapter *padapter, u8 *pmgmt_frame,
+                               uint frame_len)
+{
+#ifdef CONFIG_8723AU_P2P
+       int type;
+#endif
+       s32 freq;
+       int channel;
+       u8 category, action;
+
+       channel = rtw_get_oper_ch23a(padapter);
+
+       DBG_8723A("RTW_Rx:cur_ch =%d\n", channel);
+#ifdef CONFIG_8723AU_P2P
+       type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, false);
+       if (type >= 0)
+               goto indicate;
+#endif
+       rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action);
+       DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action);
+
+#ifdef CONFIG_8723AU_P2P
+indicate:
+#endif
+       if (channel <= RTW_CH_MAX_2G_CHANNEL)
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_2GHZ);
+       else
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_5GHZ);
+
+       rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len,
+                            GFP_ATOMIC);
+}
+
+void rtw_cfg80211_rx_p2p_action_public(struct rtw_adapter *padapter,
+                                      u8 *pmgmt_frame, uint frame_len)
+{
+#ifdef CONFIG_8723AU_P2P
+       int type;
+#endif
+       s32 freq;
+       int channel;
+       u8 category, action;
+
+       channel = rtw_get_oper_ch23a(padapter);
+
+       DBG_8723A("RTW_Rx:cur_ch =%d\n", channel);
+#ifdef CONFIG_8723AU_P2P
+       type = rtw_p2p_check_frames(padapter, pmgmt_frame, frame_len, false);
+       if (type >= 0) {
+               switch (type) {
+               case P2P_GO_NEGO_CONF:
+               case P2P_PROVISION_DISC_RESP:
+                       rtw_clear_scan_deny(padapter);
+               }
+               goto indicate;
+       }
+#endif
+       rtw_action_frame_parse23a(pmgmt_frame, frame_len, &category, &action);
+       DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category, action);
+
+#ifdef CONFIG_8723AU_P2P
+indicate:
+#endif
+       if (channel <= RTW_CH_MAX_2G_CHANNEL)
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_2GHZ);
+       else
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_5GHZ);
+
+       rtw_cfg80211_rx_mgmt(padapter, freq, 0, pmgmt_frame, frame_len,
+                            GFP_ATOMIC);
+}
+
+void rtw_cfg80211_rx_action(struct rtw_adapter *adapter, u8 *frame,
+                           uint frame_len, const char *msg)
+{
+       s32 freq;
+       int channel;
+       u8 category, action;
+
+       channel = rtw_get_oper_ch23a(adapter);
+
+       rtw_action_frame_parse23a(frame, frame_len, &category, &action);
+
+       DBG_8723A("RTW_Rx:cur_ch =%d\n", channel);
+       if (msg)
+               DBG_8723A("RTW_Rx:%s\n", msg);
+       else
+               DBG_8723A("RTW_Rx:category(%u), action(%u)\n", category,
+                         action);
+
+       if (channel <= RTW_CH_MAX_2G_CHANNEL)
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_2GHZ);
+       else
+               freq = ieee80211_channel_to_frequency(channel,
+                                                     IEEE80211_BAND_5GHZ);
+
+       rtw_cfg80211_rx_mgmt(adapter, freq, 0, frame, frame_len, GFP_ATOMIC);
+}
+
+#ifdef CONFIG_8723AU_P2P
+void rtw_cfg80211_issue_p2p_provision_request23a(struct rtw_adapter *padapter,
+                                             const u8 *buf, size_t len)
+{
+       u16 wps_devicepassword_id = 0x0000;
+       uint wps_devicepassword_id_len = 0;
+       u8 wpsie[255] = { 0x00 }, p2p_ie[255] = { 0x00 };
+       uint p2p_ielen = 0;
+       uint wpsielen = 0;
+       u32 devinfo_contentlen = 0;
+       u8 devinfo_content[64] = { 0x00 };
+       u16 capability = 0;
+       uint capability_len = 0;
+
+       unsigned char category = WLAN_CATEGORY_PUBLIC;
+       u8 action = P2P_PUB_ACTION_ACTION;
+       u8 dialogToken = 1;
+       u32 p2poui = cpu_to_be32(P2POUI);
+       u8 oui_subtype = P2P_PROVISION_DISC_REQ;
+       u32 p2pielen = 0;
+#ifdef CONFIG_8723AU_P2P
+       u32 wfdielen = 0;
+#endif /* CONFIG_8723AU_P2P */
+
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       struct ieee80211_hdr *pwlanhdr, *hdr;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       u8 *frame_body =
+           (unsigned char *)(buf + sizeof(struct ieee80211_hdr_3addr));
+       size_t frame_body_len = len - sizeof(struct ieee80211_hdr_3addr);
+
+       DBG_8723A("[%s] In\n", __func__);
+
+       hdr = (struct ieee80211_hdr *)buf;
+       /* prepare for building provision_request frame */
+       memcpy(pwdinfo->tx_prov_disc_info.peerIFAddr, hdr->addr1, ETH_ALEN);
+       memcpy(pwdinfo->tx_prov_disc_info.peerDevAddr, hdr->addr1, ETH_ALEN);
+
+       pwdinfo->tx_prov_disc_info.wps_config_method_request =
+           WPS_CM_PUSH_BUTTON;
+
+       rtw_get_wps_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_,
+                      frame_body_len - _PUBLIC_ACTION_IE_OFFSET_, wpsie,
+                      &wpsielen);
+       rtw_get_wps_attr_content23a(wpsie, wpsielen, WPS_ATTR_DEVICE_PWID,
+                                   (u8 *)&wps_devicepassword_id,
+                                   &wps_devicepassword_id_len);
+       wps_devicepassword_id = be16_to_cpu(wps_devicepassword_id);
+
+       switch (wps_devicepassword_id) {
+       case WPS_DPID_PIN:
+               pwdinfo->tx_prov_disc_info.wps_config_method_request =
+                       WPS_CM_LABEL;
+               break;
+       case WPS_DPID_USER_SPEC:
+               pwdinfo->tx_prov_disc_info.wps_config_method_request =
+                       WPS_CM_DISPLYA;
+               break;
+       case WPS_DPID_MACHINE_SPEC:
+               break;
+       case WPS_DPID_REKEY:
+               break;
+       case WPS_DPID_PBC:
+               pwdinfo->tx_prov_disc_info.wps_config_method_request =
+                       WPS_CM_PUSH_BUTTON;
+               break;
+       case WPS_DPID_REGISTRAR_SPEC:
+               pwdinfo->tx_prov_disc_info.wps_config_method_request =
+                       WPS_CM_KEYPAD;
+               break;
+       default:
+               break;
+       }
+
+       if (rtw_get_p2p_ie23a(frame_body + _PUBLIC_ACTION_IE_OFFSET_,
+                          frame_body_len - _PUBLIC_ACTION_IE_OFFSET_,
+                          p2p_ie, &p2p_ielen)) {
+               rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen,
+                                        P2P_ATTR_DEVICE_INFO, devinfo_content,
+                                        &devinfo_contentlen);
+               rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen, P2P_ATTR_CAPABILITY,
+                                        (u8 *)&capability, &capability_len);
+       }
+
+       /* start to build provision_request frame */
+       memset(wpsie, 0, sizeof(wpsie));
+       memset(p2p_ie, 0, sizeof(p2p_ie));
+       p2p_ielen = 0;
+
+       pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
+       if (pmgntframe == NULL)
+               return;
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *) (pmgntframe->buf_addr) + TXDESC_OFFSET;
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+
+       pwlanhdr->frame_control = 0;
+
+       memcpy(pwlanhdr->addr1, pwdinfo->tx_prov_disc_info.peerDevAddr,
+              ETH_ALEN);
+       memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
+       memcpy(pwlanhdr->addr3, pwdinfo->tx_prov_disc_info.peerDevAddr,
+              ETH_ALEN);
+
+       SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
+       pmlmeext->mgnt_seq++;
+       SetFrameSubType(pframe, WIFI_ACTION);
+
+       pframe += sizeof(struct ieee80211_hdr_3addr);
+       pattrib->pktlen = sizeof(struct ieee80211_hdr_3addr);
+
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &category, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &action, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 4, (unsigned char *)&p2poui,
+                                 &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &oui_subtype, &pattrib->pktlen);
+       pframe = rtw_set_fixed_ie23a(pframe, 1, &dialogToken, &pattrib->pktlen);
+
+       /* build_prov_disc_request_p2p_ie23a */
+       /*      P2P OUI */
+       p2pielen = 0;
+       p2p_ie[p2pielen++] = 0x50;
+       p2p_ie[p2pielen++] = 0x6F;
+       p2p_ie[p2pielen++] = 0x9A;
+       p2p_ie[p2pielen++] = 0x09;      /*      WFA P2P v1.0 */
+
+       /*      Commented by Albert 20110301 */
+       /*      According to the P2P Specification, the provision discovery request frame should contain 3 P2P attributes */
+       /*      1. P2P Capability */
+       /*      2. Device Info */
+       /*      3. Group ID ( When joining an operating P2P Group ) */
+
+       /*      P2P Capability ATTR */
+       /*      Type: */
+       p2p_ie[p2pielen++] = P2P_ATTR_CAPABILITY;
+
+       /*      Length: */
+       put_unaligned_le16(0x0002, p2p_ie + p2pielen);
+       p2pielen += 2;
+
+       /*      Value: */
+       /*      Device Capability Bitmap, 1 byte */
+       /*      Group Capability Bitmap, 1 byte */
+       memcpy(p2p_ie + p2pielen, &capability, 2);
+       p2pielen += 2;
+
+       /*      Device Info ATTR */
+       /*      Type: */
+       p2p_ie[p2pielen++] = P2P_ATTR_DEVICE_INFO;
+
+       /*      Length: */
+       put_unaligned_le16(devinfo_contentlen, p2p_ie + p2pielen);
+       p2pielen += 2;
+
+       /*      Value: */
+       memcpy(p2p_ie + p2pielen, devinfo_content, devinfo_contentlen);
+       p2pielen += devinfo_contentlen;
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, p2pielen,
+                           (unsigned char *)p2p_ie, &p2p_ielen);
+       pattrib->pktlen += p2p_ielen;
+
+       wpsielen = 0;
+       /*      WPS OUI */
+       *(u32 *)(wpsie) = cpu_to_be32(WPSOUI);
+       wpsielen += 4;
+
+       /*      WPS version */
+       /*      Type: */
+       *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_VER1);
+       wpsielen += 2;
+
+       /*      Length: */
+       *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0001);
+       wpsielen += 2;
+
+       /*      Value: */
+       wpsie[wpsielen++] = WPS_VERSION_1;      /*      Version 1.0 */
+
+       /*      Config Method */
+       /*      Type: */
+       *(u16 *)(wpsie + wpsielen) = cpu_to_be16(WPS_ATTR_CONF_METHOD);
+       wpsielen += 2;
+
+       /*      Length: */
+       *(u16 *)(wpsie + wpsielen) = cpu_to_be16(0x0002);
+       wpsielen += 2;
+
+       /*      Value: */
+       *(u16 *)(wpsie + wpsielen) =
+           cpu_to_be16(pwdinfo->tx_prov_disc_info.wps_config_method_request);
+       wpsielen += 2;
+
+       pframe = rtw_set_ie23a(pframe, _VENDOR_SPECIFIC_IE_, wpsielen,
+                           (unsigned char *)wpsie, &pattrib->pktlen);
+
+#ifdef CONFIG_8723AU_P2P
+       wfdielen = build_provdisc_req_wfd_ie(pwdinfo, pframe);
+       pframe += wfdielen;
+       pattrib->pktlen += wfdielen;
+#endif /* CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       /* dump_mgntframe23a(padapter, pmgntframe); */
+       if (dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe) != _SUCCESS)
+               DBG_8723A("%s, ack to\n", __func__);
+}
+
+static s32 cfg80211_rtw_remain_on_channel(struct wiphy *wiphy,
+                                         struct wireless_dev *wdev,
+                                         struct ieee80211_channel *channel,
+                                         unsigned int duration, u64 *cookie)
+{
+       s32 err = 0;
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       struct cfg80211_wifidirect_info *pcfg80211_wdinfo =
+           &padapter->cfg80211_wdinfo;
+       u8 remain_ch =
+               (u8) ieee80211_frequency_to_channel(channel->center_freq);
+       u8 ready_on_channel = false;
+
+       DBG_8723A(FUNC_ADPT_FMT " ch:%u duration:%d\n", FUNC_ADPT_ARG(padapter),
+                 remain_ch, duration);
+
+       if (pcfg80211_wdinfo->is_ro_ch == true) {
+               DBG_8723A("%s, cancel ro ch timer\n", __func__);
+
+               del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer);
+
+#ifdef CONFIG_8723AU_P2P
+               p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK);
+#endif
+       }
+
+       pcfg80211_wdinfo->is_ro_ch = true;
+
+       if (_FAIL == rtw_pwr_wakeup(padapter)) {
+               err = -EFAULT;
+               goto exit;
+       }
+
+       memcpy(&pcfg80211_wdinfo->remain_on_ch_channel, channel,
+              sizeof(struct ieee80211_channel));
+       pcfg80211_wdinfo->remain_on_ch_cookie = *cookie;
+
+       rtw_scan_abort23a(padapter);
+       if (rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+               rtw_p2p_enable23a(padapter, P2P_ROLE_DEVICE);
+               wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = true;
+       } else {
+               rtw_p2p_set_pre_state(pwdinfo, rtw_p2p_state(pwdinfo));
+#ifdef CONFIG_DEBUG_CFG80211
+               DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__,
+                         rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo));
+#endif
+       }
+
+       rtw_p2p_set_state(pwdinfo, P2P_STATE_LISTEN);
+
+       if (duration < 400)
+               duration = duration * 3;        /* extend from exper. */
+
+       pcfg80211_wdinfo->restore_channel = pmlmeext->cur_channel;
+
+       if (rtw_ch_set_search_ch23a(pmlmeext->channel_set, remain_ch) >= 0) {
+               if (remain_ch != pmlmeext->cur_channel) {
+                       ready_on_channel = true;
+               }
+       } else {
+               DBG_8723A("%s remain_ch:%u not in channel plan!!!!\n",
+                         __func__, remain_ch);
+       }
+
+       /* call this after other things have been done */
+       if (ready_on_channel == true) {
+               if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED)) {
+                       pmlmeext->cur_channel = remain_ch;
+
+                       set_channel_bwmode23a(padapter, remain_ch,
+                                          HAL_PRIME_CHNL_OFFSET_DONT_CARE,
+                                          HT_CHANNEL_WIDTH_20);
+               }
+       }
+       DBG_8723A("%s, set ro ch timer, duration =%d\n", __func__, duration);
+       mod_timer(&pcfg80211_wdinfo->remain_on_ch_timer,
+                 jiffies + msecs_to_jiffies(duration));
+
+       rtw_cfg80211_ready_on_channel(padapter, *cookie, channel, channel_type,
+                                     duration, GFP_KERNEL);
+
+       pwdinfo->listen_channel = pmlmeext->cur_channel;
+
+exit:
+       if (err)
+               pcfg80211_wdinfo->is_ro_ch = false;
+
+       return err;
+}
+
+static s32 cfg80211_rtw_cancel_remain_on_channel(struct wiphy *wiphy,
+                                                struct wireless_dev *wdev,
+                                                u64 cookie)
+{
+       s32 err = 0;
+       struct rtw_adapter *padapter = wiphy_to_adapter(wiphy);
+       struct wifidirect_info *pwdinfo = &padapter->wdinfo;
+       struct cfg80211_wifidirect_info *pcfg80211_wdinfo =
+           &padapter->cfg80211_wdinfo;
+
+       DBG_8723A(FUNC_ADPT_FMT "\n", FUNC_ADPT_ARG(padapter));
+
+       if (pcfg80211_wdinfo->is_ro_ch == true) {
+               DBG_8723A("%s, cancel ro ch timer\n", __func__);
+               del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer);
+#ifdef CONFIG_8723AU_P2P
+               p2p_protocol_wk_hdl23a(padapter, P2P_RO_CH_WK);
+#endif
+       }
+
+       rtw_p2p_set_state(pwdinfo, rtw_p2p_pre_state(pwdinfo));
+#ifdef CONFIG_DEBUG_CFG80211
+       DBG_8723A("%s, role =%d, p2p_state =%d\n", __func__,
+                 rtw_p2p_role(pwdinfo), rtw_p2p_state(pwdinfo));
+#endif
+       pcfg80211_wdinfo->is_ro_ch = false;
+
+       return err;
+}
+
+#endif /* CONFIG_8723AU_P2P */
+
+static int _cfg80211_rtw_mgmt_tx(struct rtw_adapter *padapter, u8 tx_ch,
+                                const u8 *buf, size_t len)
+{
+       struct xmit_frame *pmgntframe;
+       struct pkt_attrib *pattrib;
+       unsigned char *pframe;
+       int ret = _FAIL;
+       bool ack = true;
+       struct ieee80211_hdr *pwlanhdr;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+       /* struct cfg80211_wifidirect_info *pcfg80211_wdinfo = &padapter->cfg80211_wdinfo; */
+
+       if (_FAIL == rtw_pwr_wakeup(padapter)) {
+               ret = -EFAULT;
+               goto exit;
+       }
+
+       rtw_set_scan_deny(padapter, 1000);
+
+       rtw_scan_abort23a(padapter);
+
+       if (tx_ch != rtw_get_oper_ch23a(padapter)) {
+               if (!check_fwstate(&padapter->mlmepriv, _FW_LINKED))
+                       pmlmeext->cur_channel = tx_ch;
+               set_channel_bwmode23a(padapter, tx_ch,
+                                  HAL_PRIME_CHNL_OFFSET_DONT_CARE,
+                                  HT_CHANNEL_WIDTH_20);
+       }
+
+       /* starting alloc mgmt frame to dump it */
+       pmgntframe = alloc_mgtxmitframe23a(pxmitpriv);
+       if (pmgntframe == NULL) {
+               /* ret = -ENOMEM; */
+               ret = _FAIL;
+               goto exit;
+       }
+
+       /* update attribute */
+       pattrib = &pmgntframe->attrib;
+       update_mgntframe_attrib23a(padapter, pattrib);
+       pattrib->retry_ctrl = false;
+
+       memset(pmgntframe->buf_addr, 0, WLANHDR_OFFSET + TXDESC_OFFSET);
+
+       pframe = (u8 *) (pmgntframe->buf_addr) + TXDESC_OFFSET;
+
+       memcpy(pframe, (void *)buf, len);
+       pattrib->pktlen = len;
+
+       pwlanhdr = (struct ieee80211_hdr *)pframe;
+       /* update seq number */
+       pmlmeext->mgnt_seq = le16_to_cpu(pwlanhdr->seq_ctrl) >> 4;
+       pattrib->seqnum = pmlmeext->mgnt_seq;
+       pmlmeext->mgnt_seq++;
+
+#ifdef CONFIG_8723AU_P2P
+       {
+               struct wifi_display_info *pwfd_info;
+
+               pwfd_info = padapter->wdinfo.wfd_info;
+
+               if (true == pwfd_info->wfd_enable) {
+                       rtw_append_wfd_ie(padapter, pframe, &pattrib->pktlen);
+               }
+       }
+#endif /*  CONFIG_8723AU_P2P */
+
+       pattrib->last_txcmdsz = pattrib->pktlen;
+
+       if (dump_mgntframe23a_and_wait_ack23a(padapter, pmgntframe) != _SUCCESS) {
+               ack = false;
+               ret = _FAIL;
+
+#ifdef CONFIG_DEBUG_CFG80211
+               DBG_8723A("%s, ack == _FAIL\n", __func__);
+#endif
+       } else {
+#ifdef CONFIG_DEBUG_CFG80211
+               DBG_8723A("%s, ack =%d, ok!\n", __func__, ack);
+#endif
+               ret = _SUCCESS;
+       }
+
+exit:
+
+#ifdef CONFIG_DEBUG_CFG80211
+       DBG_8723A("%s, ret =%d\n", __func__, ret);
+#endif
+
+       return ret;
+}
+
+static int cfg80211_rtw_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3, 14, 0))
+                               struct ieee80211_channel *chan,
+                               bool offchan,
+                               unsigned int wait,
+                               const u8 *buf, size_t len,
+                               bool no_cck, bool dont_wait_for_ack,
+#else
+                               struct cfg80211_mgmt_tx_params *params,
+#endif
+                               u64 *cookie)
+{
+       struct rtw_adapter *padapter =
+               (struct rtw_adapter *)wiphy_to_adapter(wiphy);
+       struct rtw_wdev_priv *pwdev_priv = wdev_to_priv(padapter->rtw_wdev);
+       int ret = 0;
+       int tx_ret;
+       u32 dump_limit = RTW_MAX_MGMT_TX_CNT;
+       u32 dump_cnt = 0;
+       bool ack = true;
+       u8 category, action;
+       int type = (-1);
+       unsigned long start = jiffies;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 14, 0))
+       size_t len = params->len;
+       struct ieee80211_channel *chan = params->chan;
+       const u8 *buf = params->buf;
+#endif
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)buf;
+       u8 tx_ch = (u8) ieee80211_frequency_to_channel(chan->center_freq);
+
+       /* cookie generation */
+       *cookie = (unsigned long)buf;
+
+#ifdef CONFIG_DEBUG_CFG80211
+       DBG_8723A(FUNC_ADPT_FMT " len =%zu, ch =%d"
+                 "\n", FUNC_ADPT_ARG(padapter), len, tx_ch);
+#endif /* CONFIG_DEBUG_CFG80211 */
+
+       /* indicate ack before issue frame to avoid racing with rsp frame */
+       rtw_cfg80211_mgmt_tx_status(padapter, *cookie, buf, len, ack,
+                                   GFP_KERNEL);
+
+       if (rtw_action_frame_parse23a(buf, len, &category, &action) == false) {
+               DBG_8723A(FUNC_ADPT_FMT " frame_control:0x%x\n",
+                         FUNC_ADPT_ARG(padapter),
+                         le16_to_cpu(hdr->frame_control));
+               goto exit;
+       }
+
+       DBG_8723A("RTW_Tx:tx_ch =%d, da =" MAC_FMT "\n", tx_ch,
+                 MAC_ARG(hdr->addr1));
+#ifdef CONFIG_8723AU_P2P
+       type = rtw_p2p_check_frames(padapter, buf, len, true);
+       if (type >= 0)
+               goto dump;
+#endif
+       if (category == WLAN_CATEGORY_PUBLIC)
+               DBG_8723A("RTW_Tx:%s\n", action_public_str23a(action));
+       else
+               DBG_8723A("RTW_Tx:category(%u), action(%u)\n",
+                         category, action);
+
+#ifdef CONFIG_8723AU_P2P
+dump:
+#endif
+       do {
+               dump_cnt++;
+               tx_ret = _cfg80211_rtw_mgmt_tx(padapter, tx_ch, buf, len);
+       } while (dump_cnt < dump_limit && tx_ret != _SUCCESS);
+
+       if (tx_ret != _SUCCESS || dump_cnt > 1) {
+               DBG_8723A(FUNC_ADPT_FMT " %s (%d/%d) in %d ms\n",
+                         FUNC_ADPT_ARG(padapter),
+                         tx_ret == _SUCCESS ? "OK" : "FAIL", dump_cnt,
+                         dump_limit, jiffies_to_msecs(jiffies - start));
+       }
+
+       switch (type) {
+       case P2P_GO_NEGO_CONF:
+               rtw_clear_scan_deny(padapter);
+               break;
+       case P2P_INVIT_RESP:
+               if (pwdev_priv->invit_info.flags & BIT(0)
+                   && pwdev_priv->invit_info.status == 0) {
+                       DBG_8723A(FUNC_ADPT_FMT " agree with invitation of "
+                                 "persistent group\n",
+                                 FUNC_ADPT_ARG(padapter));
+                       rtw_set_scan_deny(padapter, 5000);
+                       rtw_pwr_wakeup_ex(padapter, 5000);
+                       rtw_clear_scan_deny(padapter);
+               }
+               break;
+       }
+
+exit:
+       return ret;
+}
+
+static void cfg80211_rtw_mgmt_frame_register(struct wiphy *wiphy,
+                                            struct wireless_dev *wdev,
+                                            u16 frame_type, bool reg)
+{
+
+#ifdef CONFIG_DEBUG_CFG80211
+       DBG_8723A(FUNC_ADPT_FMT " frame_type:%x, reg:%d\n",
+                 FUNC_ADPT_ARG(adapter), frame_type, reg);
+#endif
+
+       if (frame_type != (IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_PROBE_REQ))
+               return;
+
+       return;
+}
+
+static int rtw_cfg80211_set_beacon_wpsp2pie(struct net_device *ndev, char *buf,
+                                           int len)
+{
+       int ret = 0;
+       uint wps_ielen = 0;
+       u8 *wps_ie;
+#ifdef CONFIG_8723AU_P2P
+       u32 p2p_ielen = 0;
+       u32 wfd_ielen = 0;
+       u8 *p2p_ie;
+#endif
+#ifdef CONFIG_8723AU_AP_MODE
+       u8 wps_oui[8] = { 0x0, 0x50, 0xf2, 0x04 };
+#endif
+       struct rtw_adapter *padapter = netdev_priv(ndev);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
+
+       DBG_8723A(FUNC_NDEV_FMT " ielen =%d\n", FUNC_NDEV_ARG(ndev), len);
+
+       if (len > 0) {
+               wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen);
+               if (wps_ie) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("bcn_wps_ielen =%d\n", wps_ielen);
+#endif
+
+                       if (pmlmepriv->wps_beacon_ie) {
+                               pmlmepriv->wps_beacon_ie_len = 0;
+                               kfree(pmlmepriv->wps_beacon_ie);
+                               pmlmepriv->wps_beacon_ie = NULL;
+                       }
+
+                       pmlmepriv->wps_beacon_ie =
+                               kmalloc(wps_ielen, GFP_KERNEL);
+                       if (pmlmepriv->wps_beacon_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               return -EINVAL;
+                       }
+                       memcpy(pmlmepriv->wps_beacon_ie, wps_ie, wps_ielen);
+                       pmlmepriv->wps_beacon_ie_len = wps_ielen;
+
+#ifdef CONFIG_8723AU_AP_MODE
+                       update_beacon23a(padapter, _VENDOR_SPECIFIC_IE_, wps_oui,
+                                     true);
+#endif
+               }
+#ifdef CONFIG_8723AU_P2P
+               p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen);
+               if (p2p_ie) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("bcn_p2p_ielen =%d\n", p2p_ielen);
+#endif
+
+                       if (pmlmepriv->p2p_beacon_ie) {
+                               pmlmepriv->p2p_beacon_ie_len = 0;
+                               kfree(pmlmepriv->p2p_beacon_ie);
+                               pmlmepriv->p2p_beacon_ie = NULL;
+                       }
+
+                       pmlmepriv->p2p_beacon_ie =
+                               kmalloc(p2p_ielen, GFP_KERNEL);
+                       if (pmlmepriv->p2p_beacon_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               return -EINVAL;
+                       }
+
+                       memcpy(pmlmepriv->p2p_beacon_ie, p2p_ie, p2p_ielen);
+                       pmlmepriv->p2p_beacon_ie_len = p2p_ielen;
+               }
+#endif /* CONFIG_8723AU_P2P */
+
+               /* buf += p2p_ielen; */
+               /* len -= p2p_ielen; */
+
+#ifdef CONFIG_8723AU_P2P
+               if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("bcn_wfd_ielen =%d\n", wfd_ielen);
+#endif
+
+                       if (pmlmepriv->wfd_beacon_ie) {
+                               pmlmepriv->wfd_beacon_ie_len = 0;
+                               kfree(pmlmepriv->wfd_beacon_ie);
+                               pmlmepriv->wfd_beacon_ie = NULL;
+                       }
+
+                       pmlmepriv->wfd_beacon_ie =
+                               kmalloc(wfd_ielen, GFP_KERNEL);
+                       if (pmlmepriv->wfd_beacon_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               return -EINVAL;
+
+                       }
+                       rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_beacon_ie,
+                                      &pmlmepriv->wfd_beacon_ie_len);
+               }
+#endif /* CONFIG_8723AU_P2P */
+
+               pmlmeext->bstart_bss = true;
+
+       }
+
+       return ret;
+}
+
+static int rtw_cfg80211_set_probe_resp_wpsp2pie(struct net_device *net,
+                                               char *buf, int len)
+{
+       struct rtw_adapter *padapter = netdev_priv(net);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+#ifdef CONFIG_8723AU_P2P
+       u32 p2p_ielen = 0;
+       u8 *p2p_ie;
+       u32 wfd_ielen = 0;
+#endif
+       int ret = 0;
+       uint wps_ielen = 0;
+       u8 *wps_ie;
+
+       if (len > 0) {
+               wps_ie = rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen);
+               if (wps_ie) {
+                       uint attr_contentlen = 0;
+                       u16 uconfig_method, *puconfig_method = NULL;
+
+                       if (pmlmepriv->wps_probe_resp_ie) {
+                               pmlmepriv->wps_probe_resp_ie_len = 0;
+                               kfree(pmlmepriv->wps_probe_resp_ie);
+                               pmlmepriv->wps_probe_resp_ie = NULL;
+                       }
+
+                       pmlmepriv->wps_probe_resp_ie =
+                               kmalloc(wps_ielen, GFP_KERNEL);
+                       if (pmlmepriv->wps_probe_resp_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               return -EINVAL;
+
+                       }
+
+                       /* add PUSH_BUTTON config_method by driver self in
+                          wpsie of probe_resp at GO Mode */
+                       puconfig_method = (u16 *)rtw_get_wps_attr_content23a(wps_ie, wps_ielen,
+                                                             WPS_ATTR_CONF_METHOD,
+                                                             NULL,
+                                                             &attr_contentlen);
+                       if (puconfig_method) {
+                               uconfig_method = WPS_CM_PUSH_BUTTON;
+                               uconfig_method = cpu_to_be16(uconfig_method);
+
+                               *puconfig_method |= uconfig_method;
+                       }
+
+                       memcpy(pmlmepriv->wps_probe_resp_ie, wps_ie, wps_ielen);
+                       pmlmepriv->wps_probe_resp_ie_len = wps_ielen;
+
+               }
+
+               /* buf += wps_ielen; */
+               /* len -= wps_ielen; */
+
+#ifdef CONFIG_8723AU_P2P
+               p2p_ie = rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen);
+               if (p2p_ie) {
+                       u8 is_GO = false;
+                       u32 attr_contentlen = 0;
+                       u16 cap_attr = 0;
+
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("probe_resp_p2p_ielen =%d\n", p2p_ielen);
+#endif
+
+                       /* Check P2P Capability ATTR */
+                       if (rtw_get_p2p_attr23a_content(p2p_ie, p2p_ielen,
+                                                    P2P_ATTR_CAPABILITY,
+                                                    (u8 *) &cap_attr,
+                                                    (uint *) &attr_contentlen)) {
+                               u8 grp_cap = 0;
+                               /* DBG_8723A( "[%s] Got P2P Capability Attr!!\n", __func__ ); */
+                               cap_attr = le16_to_cpu(cap_attr);
+                               grp_cap = (u8) ((cap_attr >> 8) & 0xff);
+
+                               is_GO = (grp_cap & BIT(0)) ? true : false;
+
+                               if (is_GO)
+                                       DBG_8723A
+                                           ("Got P2P Capability Attr, grp_cap"
+                                            "= 0x%x, is_GO\n", grp_cap);
+                       }
+
+                       if (is_GO == false) {
+                               if (pmlmepriv->p2p_probe_resp_ie) {
+                                       pmlmepriv->p2p_probe_resp_ie_len = 0;
+                                       kfree(pmlmepriv->p2p_probe_resp_ie);
+                                       pmlmepriv->p2p_probe_resp_ie = NULL;
+                               }
+
+                               pmlmepriv->p2p_probe_resp_ie =
+                                   kmalloc(p2p_ielen, GFP_KERNEL);
+                               if (pmlmepriv->p2p_probe_resp_ie == NULL) {
+                                       DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                                 __func__, __LINE__);
+                                       return -EINVAL;
+                               }
+                               memcpy(pmlmepriv->p2p_probe_resp_ie, p2p_ie,
+                                      p2p_ielen);
+                               pmlmepriv->p2p_probe_resp_ie_len = p2p_ielen;
+                       } else {
+                               if (pmlmepriv->p2p_go_probe_resp_ie) {
+                                       pmlmepriv->p2p_go_probe_resp_ie_len = 0;
+                                       kfree(pmlmepriv->p2p_go_probe_resp_ie);
+                                       pmlmepriv->p2p_go_probe_resp_ie = NULL;
+                               }
+
+                               pmlmepriv->p2p_go_probe_resp_ie =
+                                   kmalloc(p2p_ielen, GFP_KERNEL);
+                               if (pmlmepriv->p2p_go_probe_resp_ie == NULL) {
+                                       DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                                 __func__, __LINE__);
+                                       return -EINVAL;
+
+                               }
+                               memcpy(pmlmepriv->p2p_go_probe_resp_ie,
+                                      p2p_ie, p2p_ielen);
+                               pmlmepriv->p2p_go_probe_resp_ie_len = p2p_ielen;
+                       }
+               }
+#endif /* CONFIG_8723AU_P2P */
+
+               /* buf += p2p_ielen; */
+               /* len -= p2p_ielen; */
+
+#ifdef CONFIG_8723AU_P2P
+               if (rtw_get_wfd_ie(buf, len, NULL, &wfd_ielen)) {
+#ifdef CONFIG_DEBUG_CFG80211
+                       DBG_8723A("probe_resp_wfd_ielen =%d\n", wfd_ielen);
+#endif
+
+                       if (pmlmepriv->wfd_probe_resp_ie) {
+                               pmlmepriv->wfd_probe_resp_ie_len = 0;
+                               kfree(pmlmepriv->wfd_probe_resp_ie);
+                               pmlmepriv->wfd_probe_resp_ie = NULL;
+                       }
+
+                       pmlmepriv->wfd_probe_resp_ie =
+                           kmalloc(wfd_ielen, GFP_KERNEL);
+                       if (pmlmepriv->wfd_probe_resp_ie == NULL) {
+                               DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                         __func__, __LINE__);
+                               return -EINVAL;
+
+                       }
+                       rtw_get_wfd_ie(buf, len, pmlmepriv->wfd_probe_resp_ie,
+                                      &pmlmepriv->wfd_probe_resp_ie_len);
+               }
+#endif /* CONFIG_8723AU_P2P */
+       }
+
+       return ret;
+}
+
+static int rtw_cfg80211_set_assoc_resp_wpsp2pie(struct net_device *net,
+                                               char *buf, int len)
+{
+       int ret = 0;
+       struct rtw_adapter *padapter = netdev_priv(net);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       DBG_8723A("%s, ielen =%d\n", __func__, len);
+
+       if (len > 0) {
+               if (pmlmepriv->wps_assoc_resp_ie) {
+                       pmlmepriv->wps_assoc_resp_ie_len = 0;
+                       kfree(pmlmepriv->wps_assoc_resp_ie);
+                       pmlmepriv->wps_assoc_resp_ie = NULL;
+               }
+
+               pmlmepriv->wps_assoc_resp_ie = kmalloc(len, GFP_KERNEL);
+               if (pmlmepriv->wps_assoc_resp_ie == NULL) {
+                       DBG_8723A("%s()-%d: kmalloc() ERROR!\n",
+                                 __func__, __LINE__);
+                       return -EINVAL;
+
+               }
+               memcpy(pmlmepriv->wps_assoc_resp_ie, buf, len);
+               pmlmepriv->wps_assoc_resp_ie_len = len;
+       }
+
+       return ret;
+}
+
+int rtw_cfg80211_set_mgnt_wpsp2pie(struct net_device *net, char *buf, int len,
+                                  int type)
+{
+       int ret = 0;
+       uint wps_ielen = 0;
+#ifdef CONFIG_8723AU_P2P
+       u32 p2p_ielen = 0;
+#endif
+
+#ifdef CONFIG_DEBUG_CFG80211
+       DBG_8723A("%s, ielen =%d\n", __func__, len);
+#endif
+
+       if ((rtw_get_wps_ie23a(buf, len, NULL, &wps_ielen) && (wps_ielen > 0))
+#ifdef CONFIG_8723AU_P2P
+           || (rtw_get_p2p_ie23a(buf, len, NULL, &p2p_ielen) && (p2p_ielen > 0))
+#endif
+           ) {
+               if (net) {
+                       switch (type) {
+                       case 0x1:       /* BEACON */
+                               ret =
+                                   rtw_cfg80211_set_beacon_wpsp2pie(net, buf,
+                                                                    len);
+                               break;
+                       case 0x2:       /* PROBE_RESP */
+                               ret =
+                                   rtw_cfg80211_set_probe_resp_wpsp2pie(net,
+                                                                        buf,
+                                                                        len);
+                               break;
+                       case 0x4:       /* ASSOC_RESP */
+                               ret =
+                                   rtw_cfg80211_set_assoc_resp_wpsp2pie(net,
+                                                                        buf,
+                                                                        len);
+                               break;
+                       }
+               }
+       }
+
+       return ret;
+
+}
+
+static struct cfg80211_ops rtw_cfg80211_ops = {
+       .change_virtual_intf = cfg80211_rtw_change_iface,
+       .add_key = cfg80211_rtw_add_key,
+       .get_key = cfg80211_rtw_get_key,
+       .del_key = cfg80211_rtw_del_key,
+       .set_default_key = cfg80211_rtw_set_default_key,
+       .get_station = cfg80211_rtw_get_station,
+       .scan = cfg80211_rtw_scan,
+       .set_wiphy_params = cfg80211_rtw_set_wiphy_params,
+       .connect = cfg80211_rtw_connect,
+       .disconnect = cfg80211_rtw_disconnect,
+       .join_ibss = cfg80211_rtw_join_ibss,
+       .leave_ibss = cfg80211_rtw_leave_ibss,
+       .set_tx_power = cfg80211_rtw_set_txpower,
+       .get_tx_power = cfg80211_rtw_get_txpower,
+       .set_power_mgmt = cfg80211_rtw_set_power_mgmt,
+       .set_pmksa = cfg80211_rtw_set_pmksa,
+       .del_pmksa = cfg80211_rtw_del_pmksa,
+       .flush_pmksa = cfg80211_rtw_flush_pmksa,
+
+#ifdef CONFIG_8723AU_AP_MODE
+       .add_virtual_intf = cfg80211_rtw_add_virtual_intf,
+       .del_virtual_intf = cfg80211_rtw_del_virtual_intf,
+
+       .start_ap = cfg80211_rtw_start_ap,
+       .change_beacon = cfg80211_rtw_change_beacon,
+       .stop_ap = cfg80211_rtw_stop_ap,
+
+       .add_station = cfg80211_rtw_add_station,
+       .del_station = cfg80211_rtw_del_station,
+       .change_station = cfg80211_rtw_change_station,
+       .dump_station = cfg80211_rtw_dump_station,
+       .change_bss = cfg80211_rtw_change_bss,
+#endif /* CONFIG_8723AU_AP_MODE */
+
+#ifdef CONFIG_8723AU_P2P
+       .remain_on_channel = cfg80211_rtw_remain_on_channel,
+       .cancel_remain_on_channel = cfg80211_rtw_cancel_remain_on_channel,
+#endif
+
+       .mgmt_tx = cfg80211_rtw_mgmt_tx,
+       .mgmt_frame_register = cfg80211_rtw_mgmt_frame_register,
+};
+
+static void rtw_cfg80211_init_ht_capab(struct ieee80211_sta_ht_cap *ht_cap,
+                                      enum ieee80211_band band, u8 rf_type)
+{
+
+#define MAX_BIT_RATE_40MHZ_MCS15       300     /* Mbps */
+#define MAX_BIT_RATE_40MHZ_MCS7                150     /* Mbps */
+
+       ht_cap->ht_supported = true;
+
+       ht_cap->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+           IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_SGI_20 |
+           IEEE80211_HT_CAP_DSSSCCK40 | IEEE80211_HT_CAP_MAX_AMSDU;
+
+       /*
+        *Maximum length of AMPDU that the STA can receive.
+        *Length = 2 ^ (13 + max_ampdu_length_exp) - 1 (octets)
+        */
+       ht_cap->ampdu_factor = IEEE80211_HT_MAX_AMPDU_64K;
+
+       /*Minimum MPDU start spacing , */
+       ht_cap->ampdu_density = IEEE80211_HT_MPDU_DENSITY_16;
+
+       ht_cap->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+       /*
+        *hw->wiphy->bands[IEEE80211_BAND_2GHZ]
+        *base on ant_num
+        *rx_mask: RX mask
+        *if rx_ant = 1 rx_mask[0]= 0xff;==>MCS0-MCS7
+        *if rx_ant = 2 rx_mask[1]= 0xff;==>MCS8-MCS15
+        *if rx_ant >= 3 rx_mask[2]= 0xff;
+        *if BW_40 rx_mask[4]= 0x01;
+        *highest supported RX rate
+        */
+       if (rf_type == RF_1T1R) {
+               ht_cap->mcs.rx_mask[0] = 0xFF;
+               ht_cap->mcs.rx_mask[1] = 0x00;
+               ht_cap->mcs.rx_mask[4] = 0x01;
+
+               ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS7;
+       } else if ((rf_type == RF_1T2R) || (rf_type == RF_2T2R)) {
+               ht_cap->mcs.rx_mask[0] = 0xFF;
+               ht_cap->mcs.rx_mask[1] = 0xFF;
+               ht_cap->mcs.rx_mask[4] = 0x01;
+
+               ht_cap->mcs.rx_highest = MAX_BIT_RATE_40MHZ_MCS15;
+       } else {
+               DBG_8723A("%s, error rf_type =%d\n", __func__, rf_type);
+       }
+
+}
+
+void rtw_cfg80211_init_wiphy(struct rtw_adapter *padapter)
+{
+       u8 rf_type;
+       struct ieee80211_supported_band *bands;
+       struct wireless_dev *pwdev = padapter->rtw_wdev;
+       struct wiphy *wiphy = pwdev->wiphy;
+
+       rtw23a_hal_get_hwreg(padapter, HW_VAR_RF_TYPE, (u8 *)(&rf_type));
+
+       DBG_8723A("%s:rf_type =%d\n", __func__, rf_type);
+
+       /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */
+       {
+               bands = wiphy->bands[IEEE80211_BAND_2GHZ];
+               if (bands)
+                       rtw_cfg80211_init_ht_capab(&bands->ht_cap,
+                                                  IEEE80211_BAND_2GHZ,
+                                                  rf_type);
+       }
+
+       /* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */
+       {
+               bands = wiphy->bands[IEEE80211_BAND_5GHZ];
+               if (bands)
+                       rtw_cfg80211_init_ht_capab(&bands->ht_cap,
+                                                  IEEE80211_BAND_5GHZ,
+                                                  rf_type);
+       }
+}
+
+static void rtw_cfg80211_preinit_wiphy(struct rtw_adapter *padapter,
+                                      struct wiphy *wiphy)
+{
+       wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+
+       wiphy->max_scan_ssids = RTW_SSID_SCAN_AMOUNT;
+       wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+       wiphy->max_num_pmkids = RTW_MAX_NUM_PMKIDS;
+
+       wiphy->max_remain_on_channel_duration =
+           RTW_MAX_REMAIN_ON_CHANNEL_DURATION;
+
+       wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+           BIT(NL80211_IFTYPE_ADHOC) |
+#ifdef CONFIG_8723AU_AP_MODE
+           BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_MONITOR) |
+#endif
+#if defined(CONFIG_8723AU_P2P)
+           BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) |
+#endif
+           0;
+
+#ifdef CONFIG_8723AU_AP_MODE
+       wiphy->mgmt_stypes = rtw_cfg80211_default_mgmt_stypes;
+#endif /* CONFIG_8723AU_AP_MODE */
+
+       wiphy->software_iftypes |= BIT(NL80211_IFTYPE_MONITOR);
+
+       /*
+          wiphy->iface_combinations = &rtw_combinations;
+          wiphy->n_iface_combinations = 1;
+        */
+
+       wiphy->cipher_suites = rtw_cipher_suites;
+       wiphy->n_cipher_suites = ARRAY_SIZE(rtw_cipher_suites);
+
+       /* if (padapter->registrypriv.wireless_mode & WIRELESS_11G) */
+       wiphy->bands[IEEE80211_BAND_2GHZ] =
+           rtw_spt_band_alloc(IEEE80211_BAND_2GHZ);
+       /* if (padapter->registrypriv.wireless_mode & WIRELESS_11A) */
+       wiphy->bands[IEEE80211_BAND_5GHZ] =
+           rtw_spt_band_alloc(IEEE80211_BAND_5GHZ);
+
+       wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+       wiphy->flags |= WIPHY_FLAG_OFFCHAN_TX | WIPHY_FLAG_HAVE_AP_SME;
+
+       if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE)
+               wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT;
+       else
+               wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
+}
+
+int rtw_wdev_alloc(struct rtw_adapter *padapter, struct device *dev)
+{
+       int ret = 0;
+       struct wiphy *wiphy;
+       struct wireless_dev *wdev;
+       struct rtw_wdev_priv *pwdev_priv;
+       struct net_device *pnetdev = padapter->pnetdev;
+
+       DBG_8723A("%s(padapter =%p)\n", __func__, padapter);
+
+       /* wiphy */
+       wiphy = wiphy_new(&rtw_cfg80211_ops, sizeof(struct rtw_wdev_priv));
+       if (!wiphy) {
+               DBG_8723A("Couldn't allocate wiphy device\n");
+               ret = -ENOMEM;
+               goto exit;
+       }
+       set_wiphy_dev(wiphy, dev);
+       rtw_cfg80211_preinit_wiphy(padapter, wiphy);
+
+       ret = wiphy_register(wiphy);
+       if (ret < 0) {
+               DBG_8723A("Couldn't register wiphy device\n");
+               goto free_wiphy;
+       }
+
+       /*  wdev */
+       wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
+       if (!wdev) {
+               DBG_8723A("Couldn't allocate wireless device\n");
+               ret = -ENOMEM;
+               goto unregister_wiphy;
+       }
+       wdev->wiphy = wiphy;
+       wdev->netdev = pnetdev;
+       /* wdev->iftype = NL80211_IFTYPE_STATION; */
+       /*  for rtw_setopmode_cmd23a() in cfg80211_rtw_change_iface() */
+       wdev->iftype = NL80211_IFTYPE_MONITOR;
+       padapter->rtw_wdev = wdev;
+       pnetdev->ieee80211_ptr = wdev;
+
+       /* init pwdev_priv */
+       pwdev_priv = wdev_to_priv(wdev);
+       pwdev_priv->rtw_wdev = wdev;
+       pwdev_priv->pmon_ndev = NULL;
+       pwdev_priv->ifname_mon[0] = '\0';
+       pwdev_priv->padapter = padapter;
+       pwdev_priv->scan_request = NULL;
+       spin_lock_init(&pwdev_priv->scan_req_lock);
+
+       pwdev_priv->p2p_enabled = false;
+       pwdev_priv->provdisc_req_issued = false;
+       rtw_wdev_invit_info_init(&pwdev_priv->invit_info);
+
+       if (padapter->registrypriv.power_mgnt != PS_MODE_ACTIVE)
+               pwdev_priv->power_mgmt = true;
+       else
+               pwdev_priv->power_mgmt = false;
+
+       return ret;
+unregister_wiphy:
+       wiphy_unregister(wiphy);
+free_wiphy:
+       wiphy_free(wiphy);
+exit:
+       return ret;
+}
+
+void rtw_wdev_free(struct wireless_dev *wdev)
+{
+       struct rtw_wdev_priv *pwdev_priv;
+
+       DBG_8723A("%s(wdev =%p)\n", __func__, wdev);
+
+       if (!wdev)
+               return;
+
+       pwdev_priv = wdev_to_priv(wdev);
+
+       kfree(wdev->wiphy->bands[IEEE80211_BAND_2GHZ]);
+       kfree(wdev->wiphy->bands[IEEE80211_BAND_5GHZ]);
+
+       wiphy_free(wdev->wiphy);
+
+       kfree(wdev);
+}
+
+void rtw_wdev_unregister(struct wireless_dev *wdev)
+{
+       struct rtw_wdev_priv *pwdev_priv;
+
+       DBG_8723A("%s(wdev =%p)\n", __func__, wdev);
+
+       if (!wdev)
+               return;
+
+       pwdev_priv = wdev_to_priv(wdev);
+
+       rtw_cfg80211_indicate_scan_done(pwdev_priv, true);
+
+       if (pwdev_priv->pmon_ndev) {
+               DBG_8723A("%s, unregister monitor interface\n", __func__);
+               unregister_netdev(pwdev_priv->pmon_ndev);
+       }
+
+       wiphy_unregister(wdev->wiphy);
+}
diff --git a/drivers/staging/rtl8723au/os_dep/mlme_linux.c b/drivers/staging/rtl8723au/os_dep/mlme_linux.c
new file mode 100644 (file)
index 0000000..b30d4d3
--- /dev/null
@@ -0,0 +1,187 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+#define _MLME_OSDEP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <mlme_osdep.h>
+#include <rtw_ioctl_set.h>
+
+void rtw_os_indicate_connect23a(struct rtw_adapter *adapter)
+{
+       rtw_cfg80211_indicate_connect(adapter);
+
+       netif_carrier_on(adapter->pnetdev);
+
+       if (adapter->pid[2] != 0)
+               rtw_signal_process(adapter->pid[2], SIGALRM);
+}
+
+void rtw_os_indicate_scan_done23a(struct rtw_adapter *padapter, bool aborted)
+{
+       rtw_cfg80211_indicate_scan_done(wdev_to_priv(padapter->rtw_wdev),
+                                       aborted);
+}
+
+static struct rt_pmkid_list backupPMKIDList[NUM_PMKID_CACHE];
+
+void rtw_reset_securitypriv23a(struct rtw_adapter *adapter)
+{
+       u8      backupPMKIDIndex = 0;
+       u8      backupTKIPCountermeasure = 0x00;
+       unsigned long backupTKIPcountermeasure_time = 0;
+
+       if (adapter->securitypriv.dot11AuthAlgrthm ==
+           dot11AuthAlgrthm_8021X) { /* 802.1x */
+               /*  We have to backup the PMK information for WiFi PMK
+                *  Caching test item.
+                *  Backup the btkip_countermeasure information.
+                *  When the countermeasure is trigger, the driver have to
+                *  disconnect with AP for 60 seconds.
+                */
+               memset(&backupPMKIDList[0], 0x00, sizeof(struct rt_pmkid_list) *
+                      NUM_PMKID_CACHE);
+
+               memcpy(&backupPMKIDList[0], &adapter->securitypriv.PMKIDList[0],
+                      sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+               backupPMKIDIndex = adapter->securitypriv.PMKIDIndex;
+               backupTKIPCountermeasure = adapter->securitypriv.btkip_countermeasure;
+               backupTKIPcountermeasure_time = adapter->securitypriv.btkip_countermeasure_time;
+
+               memset((unsigned char *)&adapter->securitypriv, 0,
+                      sizeof (struct security_priv));
+               /* Restore the PMK information to securitypriv structure
+                * for the following connection.
+                */
+               memcpy(&adapter->securitypriv.PMKIDList[0], &backupPMKIDList[0],
+                      sizeof(struct rt_pmkid_list) * NUM_PMKID_CACHE);
+               adapter->securitypriv.PMKIDIndex = backupPMKIDIndex;
+               adapter->securitypriv.btkip_countermeasure = backupTKIPCountermeasure;
+               adapter->securitypriv.btkip_countermeasure_time = backupTKIPcountermeasure_time;
+
+               adapter->securitypriv.ndisauthtype = Ndis802_11AuthModeOpen;
+               adapter->securitypriv.ndisencryptstatus = Ndis802_11WEPDisabled;
+       } else {  /* reset values in securitypriv */
+               struct security_priv *psec_priv = &adapter->securitypriv;
+
+               /* open system */
+               psec_priv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+               psec_priv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+               psec_priv->dot11PrivacyKeyIndex = 0;
+
+               psec_priv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+               psec_priv->dot118021XGrpKeyid = 1;
+
+               psec_priv->ndisauthtype = Ndis802_11AuthModeOpen;
+               psec_priv->ndisencryptstatus = Ndis802_11WEPDisabled;
+       }
+}
+
+void rtw_os_indicate_disconnect23a(struct rtw_adapter *adapter)
+{
+       /* Do it first for tx broadcast pkt after disconnection issue! */
+       netif_carrier_off(adapter->pnetdev);
+
+       rtw_cfg80211_indicate_disconnect(adapter);
+
+       rtw_reset_securitypriv23a(adapter);
+}
+
+void rtw_report_sec_ie23a(struct rtw_adapter *adapter, u8 authmode, u8 *sec_ie)
+{
+       uint    len;
+       u8      *buff, *p, i;
+       union iwreq_data wrqu;
+
+       RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
+                ("+rtw_report_sec_ie23a, authmode =%d\n", authmode));
+
+       buff = NULL;
+       if (authmode == _WPA_IE_ID_) {
+               RT_TRACE(_module_mlme_osdep_c_, _drv_info_,
+                        ("rtw_report_sec_ie23a, authmode =%d\n", authmode));
+
+               buff = kzalloc(IW_CUSTOM_MAX, GFP_KERNEL);
+               if (!buff)
+                       return;
+               p = buff;
+
+               p += sprintf(p, "ASSOCINFO(ReqIEs =");
+
+               len = sec_ie[1]+2;
+               len =  (len < IW_CUSTOM_MAX) ? len : IW_CUSTOM_MAX;
+
+               for (i = 0; i < len; i++)
+                       p += sprintf(p, "%02x", sec_ie[i]);
+
+               p += sprintf(p, ")");
+
+               memset(&wrqu, 0, sizeof(wrqu));
+
+               wrqu.data.length = p-buff;
+
+               wrqu.data.length = (wrqu.data.length < IW_CUSTOM_MAX) ?
+                                  wrqu.data.length : IW_CUSTOM_MAX;
+
+               kfree(buff);
+       }
+}
+
+#ifdef CONFIG_8723AU_AP_MODE
+void rtw_indicate_sta_assoc_event23a(struct rtw_adapter *padapter,
+                                 struct sta_info *psta)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       union iwreq_data wrqu;
+
+       if (psta == NULL)
+               return;
+
+       if (psta->aid > NUM_STA)
+               return;
+
+       if (pstapriv->sta_aid[psta->aid - 1] != psta)
+               return;
+
+       wrqu.addr.sa_family = ARPHRD_ETHER;
+
+       memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
+
+       DBG_8723A("+rtw_indicate_sta_assoc_event23a\n");
+}
+
+void rtw_indicate_sta_disassoc_event23a(struct rtw_adapter *padapter,
+                                    struct sta_info *psta)
+{
+       struct sta_priv *pstapriv = &padapter->stapriv;
+       union iwreq_data wrqu;
+
+       if (psta == NULL)
+               return;
+
+       if (psta->aid > NUM_STA)
+               return;
+
+       if (pstapriv->sta_aid[psta->aid - 1] != psta)
+               return;
+
+       wrqu.addr.sa_family = ARPHRD_ETHER;
+
+       memcpy(wrqu.addr.sa_data, psta->hwaddr, ETH_ALEN);
+
+       DBG_8723A("+rtw_indicate_sta_disassoc_event23a\n");
+}
+#endif
diff --git a/drivers/staging/rtl8723au/os_dep/os_intfs.c b/drivers/staging/rtl8723au/os_dep/os_intfs.c
new file mode 100644 (file)
index 0000000..57eca7a
--- /dev/null
@@ -0,0 +1,970 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _OS_INTFS_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <xmit_osdep.h>
+#include <recv_osdep.h>
+#include <hal_intf.h>
+#include <rtw_version.h>
+#include <ethernet.h>
+
+#include <usb_osintf.h>
+#include <linux/version.h>
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek Wireless Lan Driver");
+MODULE_AUTHOR("Realtek Semiconductor Corp.");
+MODULE_AUTHOR("Larry Finger <Larry.Finger@lwfinger.net>");
+MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@redhat.com>");
+MODULE_VERSION(DRIVERVERSION);
+MODULE_FIRMWARE("rtlwifi/rtl8821aefw.bin");
+
+/* module param defaults */
+static int rtw_chip_version = 0x00;
+static int rtw_rfintfs = HWPI;
+static int rtw_debug = 1;
+
+static int rtw_channel = 1;/* ad-hoc support requirement */
+static int rtw_wireless_mode = WIRELESS_11BG_24N;
+static int rtw_vrtl_carrier_sense = AUTO_VCS;
+static int rtw_vcs_type = RTS_CTS;/*  */
+static int rtw_rts_thresh = 2347;/*  */
+static int rtw_frag_thresh = 2346;/*  */
+static int rtw_preamble = PREAMBLE_LONG;/* long, short, auto */
+static int rtw_scan_mode = 1;/* active, passive */
+static int rtw_adhoc_tx_pwr = 1;
+static int rtw_soft_ap;
+static int rtw_power_mgnt = 1;
+static int rtw_ips_mode = IPS_NORMAL;
+
+static int rtw_smart_ps = 2;
+
+module_param(rtw_ips_mode, int, 0644);
+MODULE_PARM_DESC(rtw_ips_mode, "The default IPS mode");
+
+static int rtw_long_retry_lmt = 7;
+static int rtw_short_retry_lmt = 7;
+static int rtw_busy_thresh = 40;
+static int rtw_ack_policy = NORMAL_ACK;
+
+static int rtw_acm_method;/*  0:By SW 1:By HW. */
+
+static int rtw_wmm_enable = 1;/*  default is set to enable the wmm. */
+static int rtw_uapsd_enable;
+
+int rtw_ht_enable23A = 1;
+/* 0 :diable, bit(0): enable 2.4g, bit(1): enable 5g */
+int rtw_cbw40_enable23A = 3;
+int rtw_ampdu_enable23A = 1;/* for enable tx_ampdu */
+/*  0: disable, bit(0):enable 2.4g, bit(1):enable 5g, default is set to enable
+ * 2.4GHZ for IOT issue with bufflao's AP at 5GHZ
+ */
+static int rtw_rx_stbc = 1;
+static int rtw_ampdu_amsdu;/*  0: disabled, 1:enabled, 2:auto */
+
+/* Use 2 path Tx to transmit MCS0~7 and legacy mode */
+static int rtw_lowrate_two_xmit = 1;
+
+/* int rf_config = RF_1T2R;  1T2R */
+static int rtw_rf_config = RF_819X_MAX_TYPE;  /* auto */
+static int rtw_low_power;
+static int rtw_wifi_spec;
+static int rtw_channel_plan = RT_CHANNEL_DOMAIN_MAX;
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+static int rtw_btcoex_enable = 1;
+static int rtw_bt_iso = 2;/*  0:Low, 1:High, 2:From Efuse */
+/*  0:Idle, 1:None-SCO, 2:SCO, 3:From Counter, 4.Busy, 5.OtherBusy */
+static int rtw_bt_sco = 3;
+/*  0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+static int rtw_bt_ampdu = 1 ;
+#endif
+
+/*  0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */
+static int rtw_AcceptAddbaReq = true;
+
+static int rtw_antdiv_cfg = 2; /*  0:OFF , 1:ON, 2:decide by Efuse config */
+static int rtw_antdiv_type; /* 0:decide by efuse */
+
+static int rtw_enusbss;/* 0:disable, 1:enable */
+
+static int rtw_hwpdn_mode = 2;/* 0:disable, 1:enable, 2: by EFUSE config */
+
+static int rtw_hwpwrp_detect; /* HW power  ping detect 0:disable , 1:enable */
+
+static int rtw_hw_wps_pbc = 1;
+
+static int rtw_80211d;
+
+static int rtw_regulatory_id = 0xff;/*  Regulatory tab id, 0xff = follow efuse's setting */
+
+module_param(rtw_regulatory_id, int, 0644);
+
+static char *ifname = "wlan%d";
+module_param(ifname, charp, 0644);
+MODULE_PARM_DESC(ifname, "The default name to allocate for first interface");
+
+static char *if2name = "wlan%d";
+module_param(if2name, charp, 0644);
+MODULE_PARM_DESC(if2name, "The default name to allocate for second interface");
+
+module_param(rtw_channel_plan, int, 0644);
+module_param(rtw_chip_version, int, 0644);
+module_param(rtw_rfintfs, int, 0644);
+module_param(rtw_channel, int, 0644);
+module_param(rtw_wmm_enable, int, 0644);
+module_param(rtw_vrtl_carrier_sense, int, 0644);
+module_param(rtw_vcs_type, int, 0644);
+module_param(rtw_busy_thresh, int, 0644);
+module_param(rtw_ht_enable23A, int, 0644);
+module_param(rtw_cbw40_enable23A, int, 0644);
+module_param(rtw_ampdu_enable23A, int, 0644);
+module_param(rtw_rx_stbc, int, 0644);
+module_param(rtw_ampdu_amsdu, int, 0644);
+
+module_param(rtw_lowrate_two_xmit, int, 0644);
+
+module_param(rtw_rf_config, int, 0644);
+module_param(rtw_power_mgnt, int, 0644);
+module_param(rtw_smart_ps, int, 0644);
+module_param(rtw_low_power, int, 0644);
+module_param(rtw_wifi_spec, int, 0644);
+
+module_param(rtw_antdiv_cfg, int, 0644);
+
+module_param(rtw_enusbss, int, 0644);
+module_param(rtw_hwpdn_mode, int, 0644);
+module_param(rtw_hwpwrp_detect, int, 0644);
+
+module_param(rtw_hw_wps_pbc, int, 0644);
+
+static uint rtw_max_roaming_times = 2;
+module_param(rtw_max_roaming_times, uint, 0644);
+MODULE_PARM_DESC(rtw_max_roaming_times, "The max roaming times to try");
+
+module_param(rtw_80211d, int, 0644);
+MODULE_PARM_DESC(rtw_80211d, "Enable 802.11d mechanism");
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+module_param(rtw_btcoex_enable, int, 0644);
+MODULE_PARM_DESC(rtw_btcoex_enable, "Enable BT co-existence mechanism");
+#endif
+
+static uint rtw_notch_filter;
+module_param(rtw_notch_filter, uint, 0644);
+MODULE_PARM_DESC(rtw_notch_filter, "0:Disable, 1:Enable, 2:Enable only for P2P");
+module_param_named(debug, rtw_debug, int, 0444);
+MODULE_PARM_DESC(debug, "Set debug level (1-9) (default 1)");
+
+static int netdev_close(struct net_device *pnetdev);
+
+static uint loadparam(struct rtw_adapter *padapter,  struct net_device *pnetdev)
+{
+       struct registry_priv  *registry_par = &padapter->registrypriv;
+       uint status = _SUCCESS;
+
+       GlobalDebugLevel23A = rtw_debug;
+       registry_par->chip_version = (u8)rtw_chip_version;
+       registry_par->rfintfs = (u8)rtw_rfintfs;
+       memcpy(registry_par->ssid.ssid, "ANY", 3);
+       registry_par->ssid.ssid_len = 3;
+       registry_par->channel = (u8)rtw_channel;
+       registry_par->wireless_mode = (u8)rtw_wireless_mode;
+       registry_par->vrtl_carrier_sense = (u8)rtw_vrtl_carrier_sense;
+       registry_par->vcs_type = (u8)rtw_vcs_type;
+       registry_par->rts_thresh = (u16)rtw_rts_thresh;
+       registry_par->frag_thresh = (u16)rtw_frag_thresh;
+       registry_par->preamble = (u8)rtw_preamble;
+       registry_par->scan_mode = (u8)rtw_scan_mode;
+       registry_par->adhoc_tx_pwr = (u8)rtw_adhoc_tx_pwr;
+       registry_par->soft_ap =  (u8)rtw_soft_ap;
+       registry_par->smart_ps =  (u8)rtw_smart_ps;
+       registry_par->power_mgnt = (u8)rtw_power_mgnt;
+       registry_par->ips_mode = (u8)rtw_ips_mode;
+       registry_par->long_retry_lmt = (u8)rtw_long_retry_lmt;
+       registry_par->short_retry_lmt = (u8)rtw_short_retry_lmt;
+       registry_par->busy_thresh = (u16)rtw_busy_thresh;
+       registry_par->ack_policy = (u8)rtw_ack_policy;
+       registry_par->acm_method = (u8)rtw_acm_method;
+        /* UAPSD */
+       registry_par->wmm_enable = (u8)rtw_wmm_enable;
+       registry_par->uapsd_enable = (u8)rtw_uapsd_enable;
+       registry_par->ht_enable = (u8)rtw_ht_enable23A;
+       registry_par->cbw40_enable = (u8)rtw_cbw40_enable23A;
+       registry_par->ampdu_enable = (u8)rtw_ampdu_enable23A;
+       registry_par->rx_stbc = (u8)rtw_rx_stbc;
+       registry_par->ampdu_amsdu = (u8)rtw_ampdu_amsdu;
+       registry_par->lowrate_two_xmit = (u8)rtw_lowrate_two_xmit;
+       registry_par->rf_config = (u8)rtw_rf_config;
+       registry_par->low_power = (u8)rtw_low_power;
+       registry_par->wifi_spec = (u8)rtw_wifi_spec;
+       registry_par->channel_plan = (u8)rtw_channel_plan;
+#ifdef CONFIG_8723AU_BT_COEXIST
+       registry_par->btcoex = (u8)rtw_btcoex_enable;
+       registry_par->bt_iso = (u8)rtw_bt_iso;
+       registry_par->bt_sco = (u8)rtw_bt_sco;
+       registry_par->bt_ampdu = (u8)rtw_bt_ampdu;
+#endif
+       registry_par->bAcceptAddbaReq = (u8)rtw_AcceptAddbaReq;
+       registry_par->antdiv_cfg = (u8)rtw_antdiv_cfg;
+       registry_par->antdiv_type = (u8)rtw_antdiv_type;
+
+       /* 0:disable, 1:enable, 2:by EFUSE config */
+       registry_par->hwpdn_mode = (u8)rtw_hwpdn_mode;
+       /* 0:disable, 1:enable */
+       registry_par->hwpwrp_detect = (u8)rtw_hwpwrp_detect;
+       registry_par->hw_wps_pbc = (u8)rtw_hw_wps_pbc;
+       registry_par->max_roaming_times = (u8)rtw_max_roaming_times;
+       registry_par->enable80211d = (u8)rtw_80211d;
+       snprintf(registry_par->ifname, 16, "%s", ifname);
+       snprintf(registry_par->if2name, 16, "%s", if2name);
+       registry_par->notch_filter = (u8)rtw_notch_filter;
+       registry_par->regulatory_tid = (u8)rtw_regulatory_id;
+       return status;
+}
+
+static int rtw_net_set_mac_address(struct net_device *pnetdev, void *p)
+{
+       struct rtw_adapter *padapter = netdev_priv(pnetdev);
+       struct sockaddr *addr = p;
+
+       if (!padapter->bup)
+               ether_addr_copy(padapter->eeprompriv.mac_addr, addr->sa_data);
+       return 0;
+}
+
+static struct net_device_stats *rtw_net_get_stats(struct net_device *pnetdev)
+{
+       struct rtw_adapter *padapter = netdev_priv(pnetdev);
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+
+       padapter->stats.tx_packets = pxmitpriv->tx_pkts;
+       padapter->stats.rx_packets = precvpriv->rx_pkts;
+       padapter->stats.tx_dropped = pxmitpriv->tx_drop;
+       padapter->stats.rx_dropped = precvpriv->rx_drop;
+       padapter->stats.tx_bytes = pxmitpriv->tx_bytes;
+       padapter->stats.rx_bytes = precvpriv->rx_bytes;
+
+       return &padapter->stats;
+}
+
+/*
+ * AC to queue mapping
+ *
+ * AC_VO -> queue 0
+ * AC_VI -> queue 1
+ * AC_BE -> queue 2
+ * AC_BK -> queue 3
+ */
+static const u16 rtw_1d_to_queue[8] = { 2, 3, 3, 2, 1, 1, 0, 0 };
+
+/* Given a data frame determine the 802.1p/1d tag to use. */
+static unsigned int rtw_classify8021d(struct sk_buff *skb)
+{
+       unsigned int dscp;
+
+       /* skb->priority values from 256->263 are magic values to
+        * directly indicate a specific 802.1d priority.  This is used
+        * to allow 802.1d priority to be passed directly in from VLAN
+        * tags, etc.
+        */
+       if (skb->priority >= 256 && skb->priority <= 263)
+               return skb->priority - 256;
+       switch (skb->protocol) {
+       case htons(ETH_P_IP):
+               dscp = ip_hdr(skb)->tos & 0xfc;
+               break;
+       default:
+               return 0;
+       }
+       return dscp >> 5;
+}
+
+static u16 rtw_select_queue(struct net_device *dev, struct sk_buff *skb,
+                           void *accel_priv,
+                           select_queue_fallback_t fallback)
+{
+       struct rtw_adapter *padapter = netdev_priv(dev);
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       skb->priority = rtw_classify8021d(skb);
+
+       if (pmlmepriv->acm_mask != 0)
+               skb->priority = qos_acm23a(pmlmepriv->acm_mask, skb->priority);
+       return rtw_1d_to_queue[skb->priority];
+}
+
+u16 rtw_recv_select_queue23a(struct sk_buff *skb)
+{
+       struct iphdr *piphdr;
+       unsigned int dscp;
+       u16 eth_type;
+       u32 priority;
+       u8 *pdata = skb->data;
+
+       memcpy(&eth_type, pdata + (ETH_ALEN << 1), 2);
+       switch (eth_type) {
+       case htons(ETH_P_IP):
+               piphdr = (struct iphdr *)(pdata + ETH_HLEN);
+               dscp = piphdr->tos & 0xfc;
+               priority = dscp >> 5;
+               break;
+       default:
+               priority = 0;
+       }
+       return rtw_1d_to_queue[priority];
+}
+
+static const struct net_device_ops rtw_netdev_ops = {
+       .ndo_open = netdev_open23a,
+       .ndo_stop = netdev_close,
+       .ndo_start_xmit = rtw_xmit23a_entry23a,
+       .ndo_select_queue = rtw_select_queue,
+       .ndo_set_mac_address = rtw_net_set_mac_address,
+       .ndo_get_stats = rtw_net_get_stats,
+};
+
+int rtw_init_netdev23a_name23a(struct net_device *pnetdev, const char *ifname)
+{
+       if (dev_alloc_name(pnetdev, ifname) < 0) {
+               RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                        ("dev_alloc_name, fail!\n"));
+       }
+       netif_carrier_off(pnetdev);
+       return 0;
+}
+
+static const struct device_type wlan_type = {
+       .name = "wlan",
+};
+
+struct net_device *rtw_init_netdev23a(struct rtw_adapter *old_padapter)
+{
+       struct rtw_adapter *padapter;
+       struct net_device *pnetdev;
+
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+init_net_dev\n"));
+
+       pnetdev = alloc_etherdev_mq(sizeof(struct rtw_adapter), 4);
+       if (!pnetdev)
+               return NULL;
+
+       pnetdev->dev.type = &wlan_type;
+       padapter = netdev_priv(pnetdev);
+       padapter->pnetdev = pnetdev;
+
+       DBG_8723A("register rtw_netdev_ops to netdev_ops\n");
+       pnetdev->netdev_ops = &rtw_netdev_ops;
+
+       pnetdev->watchdog_timeo = HZ*3; /* 3 second timeout */
+
+       /* step 2. */
+       loadparam(padapter, pnetdev);
+       return pnetdev;
+}
+
+u32 rtw_start_drv_threads23a(struct rtw_adapter *padapter)
+{
+       u32 _status = _SUCCESS;
+
+       RT_TRACE(_module_os_intfs_c_, _drv_info_,
+                ("+rtw_start_drv_threads23a\n"));
+       padapter->cmdThread = kthread_run(rtw_cmd_thread23a, padapter,
+                                         "RTW_CMD_THREAD");
+       if (IS_ERR(padapter->cmdThread)) {
+               _status = _FAIL;
+       } else {
+               /* wait for cmd_thread to run */
+               down(&padapter->cmdpriv.terminate_cmdthread_sema);
+       }
+       rtw_hal_start_thread23a(padapter);
+       return _status;
+}
+
+void rtw_stop_drv_threads23a(struct rtw_adapter *padapter)
+{
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_stop_drv_threads23a\n"));
+
+       /* Below is to termindate rtw_cmd_thread23a & event_thread... */
+       up(&padapter->cmdpriv.cmd_queue_sema);
+       if (padapter->cmdThread)
+               down(&padapter->cmdpriv.terminate_cmdthread_sema);
+       rtw_hal_stop_thread23a(padapter);
+}
+
+static u8 rtw_init_default_value(struct rtw_adapter *padapter)
+{
+       struct registry_priv *pregistrypriv = &padapter->registrypriv;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       u8 ret = _SUCCESS;
+
+       /* xmit_priv */
+       pxmitpriv->vcs_setting = pregistrypriv->vrtl_carrier_sense;
+       pxmitpriv->vcs = pregistrypriv->vcs_type;
+       pxmitpriv->vcs_type = pregistrypriv->vcs_type;
+       /* pxmitpriv->rts_thresh = pregistrypriv->rts_thresh; */
+       pxmitpriv->frag_len = pregistrypriv->frag_thresh;
+
+       /* mlme_priv */
+       pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
+       pmlmepriv->scan_mode = SCAN_ACTIVE;
+
+       /* ht_priv */
+       pmlmepriv->htpriv.ampdu_enable = false;/* set to disabled */
+
+       /* security_priv */
+       psecuritypriv->binstallGrpkey = _FAIL;
+
+        /* open system */
+       psecuritypriv->dot11AuthAlgrthm = dot11AuthAlgrthm_Open;
+       psecuritypriv->dot11PrivacyAlgrthm = _NO_PRIVACY_;
+
+       psecuritypriv->dot11PrivacyKeyIndex = 0;
+
+       psecuritypriv->dot118021XGrpPrivacy = _NO_PRIVACY_;
+       psecuritypriv->dot118021XGrpKeyid = 1;
+
+       psecuritypriv->ndisauthtype = Ndis802_11AuthModeOpen;
+       psecuritypriv->ndisencryptstatus = Ndis802_11WEPDisabled;
+
+       /* registry_priv */
+       rtw_init_registrypriv_dev_network23a(padapter);
+       rtw_update_registrypriv_dev_network23a(padapter);
+
+       /* hal_priv */
+       rtw_hal_def_value_init23a(padapter);
+
+       /* misc. */
+       padapter->bReadPortCancel = false;
+       padapter->bWritePortCancel = false;
+       padapter->bRxRSSIDisplay = 0;
+       padapter->bNotifyChannelChange = 0;
+#ifdef CONFIG_8723AU_P2P
+       padapter->bShowGetP2PState = 1;
+#endif
+       return ret;
+}
+
+u8 rtw_reset_drv_sw23a(struct rtw_adapter *padapter)
+{
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct pwrctrl_priv *pwrctrlpriv = &padapter->pwrctrlpriv;
+       u8 ret8 = _SUCCESS;
+
+       /* hal_priv */
+       rtw_hal_def_value_init23a(padapter);
+       padapter->bReadPortCancel = false;
+       padapter->bWritePortCancel = false;
+       padapter->bRxRSSIDisplay = 0;
+       pmlmepriv->scan_interval = SCAN_INTERVAL;/*  30*2 sec = 60sec */
+
+       padapter->xmitpriv.tx_pkts = 0;
+       padapter->recvpriv.rx_pkts = 0;
+
+       pmlmepriv->LinkDetectInfo.bBusyTraffic = false;
+
+       _clr_fwstate_(pmlmepriv, _FW_UNDER_SURVEY | _FW_UNDER_LINKING);
+
+       rtw_hal_sreset_reset23a_value23a(padapter);
+       pwrctrlpriv->pwr_state_check_cnts = 0;
+
+       /* mlmeextpriv */
+       padapter->mlmeextpriv.sitesurvey_res.state = SCAN_DISABLE;
+
+       rtw_set_signal_stat_timer(&padapter->recvpriv);
+       return ret8;
+}
+
+u8 rtw_init_drv_sw23a(struct rtw_adapter *padapter)
+{
+       u8 ret8 = _SUCCESS;
+
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_init_drv_sw23a\n"));
+
+       if ((rtw_init_cmd_priv23a(&padapter->cmdpriv)) == _FAIL) {
+               RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                        ("\n Can't init cmd_priv\n"));
+               ret8 = _FAIL;
+               goto exit;
+       }
+
+       padapter->cmdpriv.padapter = padapter;
+
+       if (rtw_init_evt_priv23a(&padapter->evtpriv) == _FAIL) {
+               RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                        ("\n Can't init evt_priv\n"));
+               ret8 = _FAIL;
+               goto exit;
+       }
+
+       if (rtw_init_mlme_priv23a(padapter) == _FAIL) {
+               RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                        ("\n Can't init mlme_priv\n"));
+               ret8 = _FAIL;
+               goto exit;
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       rtw_init_wifidirect_timers23a(padapter);
+       init_wifidirect_info23a(padapter, P2P_ROLE_DISABLE);
+       reset_global_wifidirect_info23a(padapter);
+       rtw_init_cfg80211_wifidirect_info(padapter);
+#ifdef CONFIG_8723AU_P2P
+       if (rtw_init_wifi_display_info(padapter) == _FAIL)
+               RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                        ("\n Can't init init_wifi_display_info\n"));
+#endif
+#endif /* CONFIG_8723AU_P2P */
+
+       if (init_mlme_ext_priv23a(padapter) == _FAIL) {
+               RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                        ("\n Can't init mlme_ext_priv\n"));
+               ret8 = _FAIL;
+               goto exit;
+       }
+
+       if (_rtw_init_xmit_priv23a(&padapter->xmitpriv, padapter) == _FAIL) {
+               DBG_8723A("Can't _rtw_init_xmit_priv23a\n");
+               ret8 = _FAIL;
+               goto exit;
+       }
+
+       if (_rtw_init_recv_priv23a(&padapter->recvpriv, padapter) == _FAIL) {
+               DBG_8723A("Can't _rtw_init_recv_priv23a\n");
+               ret8 = _FAIL;
+               goto exit;
+       }
+
+       if (_rtw_init_sta_priv23a(&padapter->stapriv) == _FAIL) {
+               DBG_8723A("Can't _rtw_init_sta_priv23a\n");
+               ret8 = _FAIL;
+               goto exit;
+       }
+
+       padapter->stapriv.padapter = padapter;
+       padapter->setband = GHZ24_50;
+       rtw_init_bcmc_stainfo23a(padapter);
+
+       rtw_init_pwrctrl_priv23a(padapter);
+
+       ret8 = rtw_init_default_value(padapter);
+
+       rtw_hal_dm_init23a(padapter);
+       rtw_hal_sw_led_init23a(padapter);
+
+       rtw_hal_sreset_init23a(padapter);
+
+exit:
+
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_init_drv_sw23a\n"));
+       return ret8;
+}
+
+void rtw_cancel_all_timer23a(struct rtw_adapter *padapter)
+{
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+rtw_cancel_all_timer23a\n"));
+
+       del_timer_sync(&padapter->mlmepriv.assoc_timer);
+       RT_TRACE(_module_os_intfs_c_, _drv_info_,
+                ("rtw_cancel_all_timer23a:cancel association timer complete!\n"));
+
+       del_timer_sync(&padapter->mlmepriv.scan_to_timer);
+       RT_TRACE(_module_os_intfs_c_, _drv_info_,
+                ("rtw_cancel_all_timer23a:cancel scan_to_timer!\n"));
+
+       del_timer_sync(&padapter->mlmepriv.dynamic_chk_timer);
+       RT_TRACE(_module_os_intfs_c_, _drv_info_,
+                ("rtw_cancel_all_timer23a:cancel dynamic_chk_timer!\n"));
+
+       /*  cancel sw led timer */
+       rtw_hal_sw_led_deinit23a(padapter);
+       RT_TRACE(_module_os_intfs_c_, _drv_info_,
+                ("rtw_cancel_all_timer23a:cancel DeInitSwLeds!\n"));
+
+       del_timer_sync(&padapter->pwrctrlpriv.pwr_state_check_timer);
+
+#ifdef CONFIG_8723AU_P2P
+       del_timer_sync(&padapter->cfg80211_wdinfo.remain_on_ch_timer);
+#endif /* CONFIG_8723AU_P2P */
+
+       del_timer_sync(&padapter->mlmepriv.set_scan_deny_timer);
+       rtw_clear_scan_deny(padapter);
+       RT_TRACE(_module_os_intfs_c_, _drv_info_,
+                ("rtw_cancel_all_timer23a:cancel set_scan_deny_timer!\n"));
+
+       del_timer_sync(&padapter->recvpriv.signal_stat_timer);
+       /* cancel dm timer */
+       rtw_hal_dm_deinit23a(padapter);
+}
+
+u8 rtw_free_drv_sw23a(struct rtw_adapter *padapter)
+{
+#ifdef CONFIG_8723AU_P2P
+       struct wifidirect_info *pwdinfo;
+#endif
+
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("==>rtw_free_drv_sw23a"));
+
+       /* we can call rtw_p2p_enable23a here, but:
+        *  1. rtw_p2p_enable23a may have IO operation
+        *  2. rtw_p2p_enable23a is bundled with wext interface
+        */
+#ifdef CONFIG_8723AU_P2P
+       pwdinfo = &padapter->wdinfo;
+       if (!rtw_p2p_chk_state(pwdinfo, P2P_STATE_NONE)) {
+               del_timer_sync(&pwdinfo->find_phase_timer);
+               del_timer_sync(&pwdinfo->restore_p2p_state_timer);
+               del_timer_sync(&pwdinfo->pre_tx_scan_timer);
+               rtw_p2p_set_state(pwdinfo, P2P_STATE_NONE);
+       }
+#endif
+
+       free_mlme_ext_priv23a(&padapter->mlmeextpriv);
+
+       rtw_free_cmd_priv23a(&padapter->cmdpriv);
+
+       rtw_free_evt_priv23a(&padapter->evtpriv);
+
+       rtw_free_mlme_priv23a(&padapter->mlmepriv);
+
+       _rtw_free_xmit_priv23a(&padapter->xmitpriv);
+
+       _rtw_free_sta_priv23a(&padapter->stapriv);/* will free bcmc_stainfo here */
+
+       _rtw_free_recv_priv23a(&padapter->recvpriv);
+
+       rtw_free_pwrctrl_priv(padapter);
+
+       rtw_hal_free_data23a(padapter);
+
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("<== rtw_free_drv_sw23a\n"));
+
+       /* free the old_pnetdev */
+       if (padapter->rereg_nd_name_priv.old_pnetdev) {
+               free_netdev(padapter->rereg_nd_name_priv.old_pnetdev);
+               padapter->rereg_nd_name_priv.old_pnetdev = NULL;
+       }
+
+       /*  clear pbuddy_adapter to avoid access wrong pointer. */
+       if (padapter->pbuddy_adapter != NULL)
+               padapter->pbuddy_adapter->pbuddy_adapter = NULL;
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-rtw_free_drv_sw23a\n"));
+       return _SUCCESS;
+}
+
+static int _rtw_drv_register_netdev(struct rtw_adapter *padapter, char *name)
+{
+       struct net_device *pnetdev = padapter->pnetdev;
+       int ret = _SUCCESS;
+
+       /* alloc netdev name */
+       rtw_init_netdev23a_name23a(pnetdev, name);
+
+       ether_addr_copy(pnetdev->dev_addr, padapter->eeprompriv.mac_addr);
+
+       /* Tell the network stack we exist */
+       if (register_netdev(pnetdev)) {
+               DBG_8723A(FUNC_NDEV_FMT "Failed!\n", FUNC_NDEV_ARG(pnetdev));
+               ret = _FAIL;
+               goto error_register_netdev;
+       }
+       DBG_8723A("%s, MAC Address (if%d) = " MAC_FMT "\n", __func__,
+                 (padapter->iface_id + 1), MAC_ARG(pnetdev->dev_addr));
+       return ret;
+
+error_register_netdev:
+
+       if (padapter->iface_id > IFACE_ID0) {
+               rtw_free_drv_sw23a(padapter);
+
+               free_netdev(pnetdev);
+       }
+       return ret;
+}
+
+int rtw_drv_register_netdev(struct rtw_adapter *if1)
+{
+       struct dvobj_priv *dvobj = if1->dvobj;
+       int i, status = _SUCCESS;
+
+       if (dvobj->iface_nums < IFACE_ID_MAX) {
+               for (i = 0; i < dvobj->iface_nums; i++) {
+                       struct rtw_adapter *padapter = dvobj->padapters[i];
+
+                       if (padapter) {
+                               char *name;
+
+                               if (padapter->iface_id == IFACE_ID0)
+                                       name = if1->registrypriv.ifname;
+                               else if (padapter->iface_id == IFACE_ID1)
+                                       name = if1->registrypriv.if2name;
+                               else
+                                       name = "wlan%d";
+                               status = _rtw_drv_register_netdev(padapter,
+                                                                 name);
+                               if (status != _SUCCESS)
+                                       break;
+                       }
+               }
+       }
+       return status;
+}
+
+int netdev_open23a(struct net_device *pnetdev)
+{
+       struct rtw_adapter *padapter = netdev_priv(pnetdev);
+       struct pwrctrl_priv *pwrctrlpriv;
+       int ret = 0;
+       uint status;
+
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - dev_open\n"));
+       DBG_8723A("+871x_drv - drv_open, bup =%d\n", padapter->bup);
+
+       mutex_lock(&adapter_to_dvobj(padapter)->hw_init_mutex);
+
+       pwrctrlpriv = &padapter->pwrctrlpriv;
+       if (pwrctrlpriv->ps_flag) {
+               padapter->net_closed = false;
+               goto netdev_open23a_normal_process;
+       }
+
+       if (!padapter->bup) {
+               padapter->bDriverStopped = false;
+               padapter->bSurpriseRemoved = false;
+               padapter->bCardDisableWOHSM = false;
+
+               status = rtw_hal_init23a(padapter);
+               if (status == _FAIL) {
+                       RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                                ("rtl871x_hal_init(): Can't init h/w!\n"));
+                       goto netdev_open23a_error;
+               }
+
+               DBG_8723A("MAC Address = "MAC_FMT"\n",
+                         MAC_ARG(pnetdev->dev_addr));
+
+               status = rtw_start_drv_threads23a(padapter);
+               if (status == _FAIL) {
+                       DBG_8723A("Initialize driver software resource Failed!\n");
+                       goto netdev_open23a_error;
+               }
+
+               if (init_hw_mlme_ext23a(padapter) == _FAIL) {
+                       DBG_8723A("can't init mlme_ext_priv\n");
+                       goto netdev_open23a_error;
+               }
+
+               if (padapter->intf_start)
+                       padapter->intf_start(padapter);
+
+               rtw_cfg80211_init_wiphy(padapter);
+
+               rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+               padapter->bup = true;
+       }
+       padapter->net_closed = false;
+
+       mod_timer(&padapter->mlmepriv.dynamic_chk_timer,
+                 jiffies + msecs_to_jiffies(2000));
+
+       padapter->pwrctrlpriv.bips_processing = false;
+       rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+
+       /* netif_carrier_on(pnetdev);call this func when
+          rtw23a_joinbss_event_cb return success */
+       if (!rtw_netif_queue_stopped(pnetdev))
+               netif_tx_start_all_queues(pnetdev);
+       else
+               netif_tx_wake_all_queues(pnetdev);
+
+netdev_open23a_normal_process:
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - dev_open\n"));
+       DBG_8723A("-871x_drv - drv_open, bup =%d\n", padapter->bup);
+exit:
+       mutex_unlock(&adapter_to_dvobj(padapter)->hw_init_mutex);
+       return ret;
+
+netdev_open23a_error:
+       padapter->bup = false;
+
+       netif_carrier_off(pnetdev);
+       netif_tx_stop_all_queues(pnetdev);
+
+       RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                ("-871x_drv - dev_open, fail!\n"));
+       DBG_8723A("-871x_drv - drv_open fail, bup =%d\n", padapter->bup);
+
+       ret = -1;
+       goto exit;
+}
+
+static int  ips_netdrv_open(struct rtw_adapter *padapter)
+{
+       int status = _SUCCESS;
+
+       padapter->net_closed = false;
+       DBG_8723A("===> %s.........\n", __func__);
+
+       padapter->bDriverStopped = false;
+       padapter->bSurpriseRemoved = false;
+       padapter->bCardDisableWOHSM = false;
+
+       status = rtw_hal_init23a(padapter);
+       if (status == _FAIL) {
+               RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                        ("ips_netdrv_open(): Can't init h/w!\n"));
+               goto netdev_open23a_error;
+       }
+
+       if (padapter->intf_start)
+               padapter->intf_start(padapter);
+
+       rtw_set_pwr_state_check_timer(&padapter->pwrctrlpriv);
+       mod_timer(&padapter->mlmepriv.dynamic_chk_timer,
+                 jiffies + msecs_to_jiffies(5000));
+
+       return _SUCCESS;
+
+netdev_open23a_error:
+       /* padapter->bup = false; */
+       DBG_8723A("-ips_netdrv_open - drv_open failure, bup =%d\n",
+                 padapter->bup);
+
+       return _FAIL;
+}
+
+int rtw_ips_pwr_up23a(struct rtw_adapter *padapter)
+{
+       int result;
+       unsigned long start_time = jiffies;
+
+       DBG_8723A("===>  rtw_ips_pwr_up23a..............\n");
+       rtw_reset_drv_sw23a(padapter);
+
+       result = ips_netdrv_open(padapter);
+
+       rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+       DBG_8723A("<===  rtw_ips_pwr_up23a.............. in %dms\n",
+                 jiffies_to_msecs(jiffies - start_time));
+       return result;
+}
+
+void rtw_ips_pwr_down23a(struct rtw_adapter *padapter)
+{
+       unsigned long start_time = jiffies;
+
+       DBG_8723A("===> rtw_ips_pwr_down23a...................\n");
+
+       padapter->bCardDisableWOHSM = true;
+       padapter->net_closed = true;
+
+       rtw_led_control(padapter, LED_CTL_POWER_OFF);
+
+       rtw_ips_dev_unload23a(padapter);
+       padapter->bCardDisableWOHSM = false;
+       DBG_8723A("<=== rtw_ips_pwr_down23a..................... in %dms\n",
+                 jiffies_to_msecs(jiffies - start_time));
+}
+
+void rtw_ips_dev_unload23a(struct rtw_adapter *padapter)
+{
+       rtw_hal_set_hwreg23a(padapter, HW_VAR_FIFO_CLEARN_UP, NULL);
+
+       if (padapter->intf_stop)
+               padapter->intf_stop(padapter);
+
+       /* s5. */
+       if (!padapter->bSurpriseRemoved)
+               rtw_hal_deinit23a(padapter);
+}
+
+int pm_netdev_open23a(struct net_device *pnetdev, u8 bnormal)
+{
+       int status;
+
+       if (bnormal)
+               status = netdev_open23a(pnetdev);
+       else
+               status = (_SUCCESS == ips_netdrv_open(netdev_priv(pnetdev))) ?
+                        (0) : (-1);
+
+       return status;
+}
+
+static int netdev_close(struct net_device *pnetdev)
+{
+       struct rtw_adapter *padapter = netdev_priv(pnetdev);
+
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("+871x_drv - drv_close\n"));
+
+       if (padapter->pwrctrlpriv.bInternalAutoSuspend) {
+               if (padapter->pwrctrlpriv.rf_pwrstate == rf_off)
+                       padapter->pwrctrlpriv.ps_flag = true;
+       }
+       padapter->net_closed = true;
+
+       if (padapter->pwrctrlpriv.rf_pwrstate == rf_on) {
+               DBG_8723A("(2)871x_drv - drv_close, bup =%d, hw_init_completed =%d\n",
+                         padapter->bup,
+                         padapter->hw_init_completed);
+
+               /* s1. */
+               if (pnetdev) {
+                       if (!rtw_netif_queue_stopped(pnetdev))
+                               netif_tx_stop_all_queues(pnetdev);
+               }
+
+               /* s2. */
+               LeaveAllPowerSaveMode23a(padapter);
+               rtw_disassoc_cmd23a(padapter, 500, false);
+               /* s2-2.  indicate disconnect to os */
+               rtw_indicate_disconnect23a(padapter);
+               /* s2-3. */
+               rtw_free_assoc_resources23a(padapter, 1);
+               /* s2-4. */
+               rtw_free_network_queue23a(padapter, true);
+               /*  Close LED */
+               rtw_led_control(padapter, LED_CTL_POWER_OFF);
+       }
+
+#ifdef CONFIG_8723AU_P2P
+       if (wdev_to_priv(padapter->rtw_wdev)->p2p_enabled)
+               wdev_to_priv(padapter->rtw_wdev)->p2p_enabled = false;
+       rtw_p2p_enable23a(padapter, P2P_ROLE_DISABLE);
+#endif /* CONFIG_8723AU_P2P */
+
+       rtw_scan_abort23a(padapter);
+        /* set this at the end */
+       padapter->rtw_wdev->iftype = NL80211_IFTYPE_MONITOR;
+
+       RT_TRACE(_module_os_intfs_c_, _drv_info_, ("-871x_drv - drv_close\n"));
+       DBG_8723A("-871x_drv - drv_close, bup =%d\n", padapter->bup);
+
+       return 0;
+}
+
+void rtw_ndev_destructor(struct net_device *ndev)
+{
+       DBG_8723A(FUNC_NDEV_FMT"\n", FUNC_NDEV_ARG(ndev));
+       kfree(ndev->ieee80211_ptr);
+       free_netdev(ndev);
+}
diff --git a/drivers/staging/rtl8723au/os_dep/osdep_service.c b/drivers/staging/rtl8723au/os_dep/osdep_service.c
new file mode 100644 (file)
index 0000000..97fc27d
--- /dev/null
@@ -0,0 +1,175 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+
+
+#define _OSDEP_SERVICE_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <linux/vmalloc.h>
+
+#define RT_TAG ('1178')
+
+/*
+* Translate the OS dependent @param error_code to OS independent RTW_STATUS_CODE23a
+* @return: one of RTW_STATUS_CODE23a
+*/
+inline int RTW_STATUS_CODE23a(int error_code)
+{
+       if (error_code >= 0)
+               return _SUCCESS;
+       return _FAIL;
+}
+
+inline u8 *_rtw_vmalloc(u32 sz)
+{
+       u8      *pbuf;
+       pbuf = vmalloc(sz);
+
+       return pbuf;
+}
+
+inline u8 *_rtw_zvmalloc(u32 sz)
+{
+       u8      *pbuf;
+       pbuf = _rtw_vmalloc(sz);
+       if (pbuf != NULL)
+               memset(pbuf, 0, sz);
+
+       return pbuf;
+}
+
+inline void _rtw_vmfree(u8 *pbuf, u32 sz)
+{
+       vfree(pbuf);
+}
+
+void _rtw_init_queue23a(struct rtw_queue *pqueue)
+{
+       INIT_LIST_HEAD(&pqueue->queue);
+       spin_lock_init(&pqueue->lock);
+}
+
+u32 _rtw_queue_empty23a(struct rtw_queue *pqueue)
+{
+       if (list_empty(&pqueue->queue))
+               return true;
+       else
+               return false;
+}
+
+u64 rtw_modular6423a(u64 x, u64 y)
+{
+       return do_div(x, y);
+}
+
+u64 rtw_division6423a(u64 x, u64 y)
+{
+       do_div(x, y);
+       return x;
+}
+
+/* rtw_cbuf_full23a - test if cbuf is full
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Returns: true if cbuf is full
+ */
+inline bool rtw_cbuf_full23a(struct rtw_cbuf *cbuf)
+{
+       return (cbuf->write == cbuf->read-1) ? true : false;
+}
+
+/* rtw_cbuf_empty23a - test if cbuf is empty
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Returns: true if cbuf is empty
+ */
+inline bool rtw_cbuf_empty23a(struct rtw_cbuf *cbuf)
+{
+       return (cbuf->write == cbuf->read) ? true : false;
+}
+
+/**
+ * rtw_cbuf_push23a - push a pointer into cbuf
+ * @cbuf: pointer of struct rtw_cbuf
+ * @buf: pointer to push in
+ *
+ * Lock free operation, be careful of the use scheme
+ * Returns: true push success
+ */
+bool rtw_cbuf_push23a(struct rtw_cbuf *cbuf, void *buf)
+{
+       if (rtw_cbuf_full23a(cbuf))
+               return _FAIL;
+
+       if (0)
+               DBG_8723A("%s on %u\n", __func__, cbuf->write);
+       cbuf->bufs[cbuf->write] = buf;
+       cbuf->write = (cbuf->write+1)%cbuf->size;
+
+       return _SUCCESS;
+}
+
+/**
+ * rtw_cbuf_pop23a - pop a pointer from cbuf
+ * @cbuf: pointer of struct rtw_cbuf
+ *
+ * Lock free operation, be careful of the use scheme
+ * Returns: pointer popped out
+ */
+void *rtw_cbuf_pop23a(struct rtw_cbuf *cbuf)
+{
+       void *buf;
+       if (rtw_cbuf_empty23a(cbuf))
+               return NULL;
+
+       if (0)
+               DBG_8723A("%s on %u\n", __func__, cbuf->read);
+       buf = cbuf->bufs[cbuf->read];
+       cbuf->read = (cbuf->read+1)%cbuf->size;
+
+       return buf;
+}
+
+/**
+ * rtw_cbuf_alloc23a - allocte a rtw_cbuf with given size and do initialization
+ * @size: size of pointer
+ *
+ * Returns: pointer of srtuct rtw_cbuf, NULL for allocation failure
+ */
+struct rtw_cbuf *rtw_cbuf_alloc23a(u32 size)
+{
+       struct rtw_cbuf *cbuf;
+
+       cbuf = kmalloc(sizeof(*cbuf) + sizeof(void *)*size, GFP_KERNEL);
+
+       if (cbuf) {
+               cbuf->write = 0;
+               cbuf->read = 0;
+               cbuf->size = size;
+       }
+
+       return cbuf;
+}
+
+/**
+ * rtw_cbuf_free - free the given rtw_cbuf
+ * @cbuf: pointer of struct rtw_cbuf to free
+ */
+void rtw_cbuf_free(struct rtw_cbuf *cbuf)
+{
+       kfree(cbuf);
+}
diff --git a/drivers/staging/rtl8723au/os_dep/recv_linux.c b/drivers/staging/rtl8723au/os_dep/recv_linux.c
new file mode 100644 (file)
index 0000000..84402a5
--- /dev/null
@@ -0,0 +1,225 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _RECV_OSDEP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <wifi.h>
+#include <recv_osdep.h>
+
+#include <osdep_intf.h>
+#include <ethernet.h>
+
+#include <usb_ops.h>
+
+/* alloc os related resource in struct recv_frame */
+int rtw_os_recv_resource_alloc23a(struct rtw_adapter *padapter,
+                              struct recv_frame *precvframe)
+{
+       int res = _SUCCESS;
+
+       precvframe->pkt = NULL;
+
+       return res;
+}
+
+/* alloc os related resource in struct recv_buf */
+int rtw_os_recvbuf_resource_alloc23a(struct rtw_adapter *padapter,
+                                 struct recv_buf *precvbuf)
+{
+       int res = _SUCCESS;
+
+       precvbuf->purb = usb_alloc_urb(0, GFP_KERNEL);
+       if (precvbuf->purb == NULL)
+               res = _FAIL;
+
+       precvbuf->pskb = NULL;
+
+       return res;
+}
+
+/* free os related resource in struct recv_buf */
+int rtw_os_recvbuf_resource_free23a(struct rtw_adapter *padapter,
+                                struct recv_buf *precvbuf)
+{
+       int ret = _SUCCESS;
+
+       usb_free_urb(precvbuf->purb);
+
+       if (precvbuf->pskb)
+               dev_kfree_skb_any(precvbuf->pskb);
+
+       return ret;
+}
+
+void rtw_handle_tkip_mic_err23a(struct rtw_adapter *padapter, u8 bgroup)
+{
+       enum nl80211_key_type key_type = 0;
+       union iwreq_data wrqu;
+       struct iw_michaelmicfailure ev;
+       struct mlme_priv *pmlmepriv  = &padapter->mlmepriv;
+       struct security_priv *psecuritypriv = &padapter->securitypriv;
+       unsigned long cur_time;
+
+       if (psecuritypriv->last_mic_err_time == 0) {
+               psecuritypriv->last_mic_err_time = jiffies;
+       } else {
+               cur_time = jiffies;
+
+               if (cur_time - psecuritypriv->last_mic_err_time < 60*HZ) {
+                       psecuritypriv->btkip_countermeasure = true;
+                       psecuritypriv->last_mic_err_time = 0;
+                       psecuritypriv->btkip_countermeasure_time = cur_time;
+               } else {
+                       psecuritypriv->last_mic_err_time = jiffies;
+               }
+       }
+
+       if (bgroup)
+               key_type |= NL80211_KEYTYPE_GROUP;
+       else
+               key_type |= NL80211_KEYTYPE_PAIRWISE;
+
+       cfg80211_michael_mic_failure(padapter->pnetdev,
+                                    (u8 *)&pmlmepriv->assoc_bssid[0],
+                                    key_type, -1, NULL, GFP_ATOMIC);
+
+       memset(&ev, 0x00, sizeof(ev));
+       if (bgroup)
+               ev.flags |= IW_MICFAILURE_GROUP;
+       else
+               ev.flags |= IW_MICFAILURE_PAIRWISE;
+
+       ev.src_addr.sa_family = ARPHRD_ETHER;
+       ether_addr_copy(ev.src_addr.sa_data, &pmlmepriv->assoc_bssid[0]);
+
+       memset(&wrqu, 0x00, sizeof(wrqu));
+       wrqu.data.length = sizeof(ev);
+}
+
+void rtw_hostapd_mlme_rx23a(struct rtw_adapter *padapter,
+                        struct recv_frame *precv_frame)
+{
+}
+
+int rtw_recv_indicatepkt23a(struct rtw_adapter *padapter,
+                        struct recv_frame *precv_frame)
+{
+       struct recv_priv *precvpriv;
+       struct rtw_queue *pfree_recv_queue;
+       struct sk_buff *skb;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+       precvpriv = &(padapter->recvpriv);
+       pfree_recv_queue = &(precvpriv->free_recv_queue);
+
+       skb = precv_frame->pkt;
+       if (!skb) {
+               RT_TRACE(_module_recv_osdep_c_, _drv_err_,
+                        ("rtw_recv_indicatepkt23a():skb == NULL!!!!\n"));
+               goto _recv_indicatepkt_drop;
+       }
+
+       RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+                ("rtw_recv_indicatepkt23a():skb != NULL !!!\n"));
+       RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+                ("rtw_recv_indicatepkt23a():precv_frame->hdr.rx_data =%p\n",
+                 precv_frame->pkt->data));
+       RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+                ("\n skb->head =%p skb->data =%p skb->tail =%p skb->end =%p skb->len =%d\n",
+                 skb->head, skb->data,
+                 skb_tail_pointer(skb), skb_end_pointer(skb), skb->len));
+
+       if (check_fwstate(pmlmepriv, WIFI_AP_STATE) == true) {
+               struct sk_buff *pskb2 = NULL;
+               struct sta_info *psta = NULL;
+               struct sta_priv *pstapriv = &padapter->stapriv;
+               struct rx_pkt_attrib *pattrib = &precv_frame->attrib;
+               int bmcast = is_multicast_ether_addr(pattrib->dst);
+
+               /* DBG_8723A("bmcast =%d\n", bmcast); */
+
+               if (!ether_addr_equal(pattrib->dst,
+                                     myid(&padapter->eeprompriv))) {
+                       /* DBG_8723A("not ap psta =%p, addr =%pM\n", psta, pattrib->dst); */
+                       if (bmcast) {
+                               psta = rtw_get_bcmc_stainfo23a(padapter);
+                               pskb2 = skb_clone(skb, GFP_ATOMIC);
+                       } else {
+                               psta = rtw_get_stainfo23a(pstapriv, pattrib->dst);
+                       }
+
+                       if (psta) {
+                               struct net_device *pnetdev = padapter->pnetdev;
+
+                               /* DBG_8723A("directly forwarding to the rtw_xmit23a_entry23a\n"); */
+
+                               /* skb->ip_summed = CHECKSUM_NONE; */
+                               skb->dev = pnetdev;
+                               skb_set_queue_mapping(skb, rtw_recv_select_queue23a(skb));
+
+                               rtw_xmit23a_entry23a(skb, pnetdev);
+
+                               if (bmcast)
+                                       skb = pskb2;
+                               else
+                                       goto _recv_indicatepkt_end;
+                       }
+               } else { /*  to APself */
+                       /* DBG_8723A("to APSelf\n"); */
+               }
+       }
+
+       skb->ip_summed = CHECKSUM_NONE;
+       skb->dev = padapter->pnetdev;
+       skb->protocol = eth_type_trans(skb, padapter->pnetdev);
+
+       netif_rx(skb);
+
+_recv_indicatepkt_end:
+
+       precv_frame->pkt = NULL; /*  pointers to NULL before rtw_free_recvframe23a() */
+
+       rtw_free_recvframe23a(precv_frame, pfree_recv_queue);
+
+       RT_TRACE(_module_recv_osdep_c_, _drv_info_,
+                ("\n rtw_recv_indicatepkt23a :after netif_rx!!!!\n"));
+       return _SUCCESS;
+
+_recv_indicatepkt_drop:
+
+        rtw_free_recvframe23a(precv_frame, pfree_recv_queue);
+        return _FAIL;
+}
+
+void rtw_os_read_port23a(struct rtw_adapter *padapter, struct recv_buf *precvbuf)
+{
+       struct recv_priv *precvpriv = &padapter->recvpriv;
+
+       /* free skb in recv_buf */
+       dev_kfree_skb_any(precvbuf->pskb);
+
+       precvbuf->pskb = NULL;
+
+       rtw_read_port(padapter, precvpriv->ff_hwaddr, 0, precvbuf);
+}
+
+void rtw_init_recv_timer23a(struct recv_reorder_ctrl *preorder_ctrl)
+{
+       setup_timer(&preorder_ctrl->reordering_ctrl_timer,
+                   rtw_reordering_ctrl_timeout_handler23a,
+                   (unsigned long)preorder_ctrl);
+}
diff --git a/drivers/staging/rtl8723au/os_dep/usb_intf.c b/drivers/staging/rtl8723au/os_dep/usb_intf.c
new file mode 100644 (file)
index 0000000..612806e
--- /dev/null
@@ -0,0 +1,833 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _HCI_INTF_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+#include <recv_osdep.h>
+#include <xmit_osdep.h>
+#include <hal_intf.h>
+#include <rtw_version.h>
+#include <osdep_intf.h>
+#include <usb_vendor_req.h>
+#include <usb_ops.h>
+#include <usb_osintf.h>
+#include <usb_hal.h>
+
+static int rtw_suspend(struct usb_interface *intf, pm_message_t message);
+static int rtw_resume(struct usb_interface *intf);
+static int rtw_drv_init(struct usb_interface *pusb_intf,
+                       const struct usb_device_id *pdid);
+static void rtw_disconnect(struct usb_interface *pusb_intf);
+
+#define USB_VENDER_ID_REALTEK          0x0BDA
+
+#define RTL8723A_USB_IDS \
+       {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x8724,   \
+        0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ \
+       {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x1724,   \
+        0xff, 0xff, 0xff)}, /* 8723AU 1*1 */ \
+       {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDER_ID_REALTEK, 0x0724,   \
+        0xff, 0xff, 0xff)}, /* 8723AU 1*1 */
+
+static struct usb_device_id rtl8723a_usb_id_tbl[] = {
+       RTL8723A_USB_IDS
+       {}      /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, rtl8723a_usb_id_tbl);
+
+static struct usb_driver rtl8723a_usb_drv = {
+       .name = (char *)"rtl8723au",
+       .probe = rtw_drv_init,
+       .disconnect = rtw_disconnect,
+       .id_table = rtl8723a_usb_id_tbl,
+       .suspend = rtw_suspend,
+       .resume = rtw_resume,
+       .reset_resume  = rtw_resume,
+};
+
+static struct usb_driver *usb_drv = &rtl8723a_usb_drv;
+
+static inline int RT_usb_endpoint_dir_in(const struct usb_endpoint_descriptor *epd)
+{
+       return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN;
+}
+
+static inline int RT_usb_endpoint_dir_out(const struct usb_endpoint_descriptor *epd)
+{
+       return (epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT;
+}
+
+static inline int RT_usb_endpoint_xfer_int(const struct usb_endpoint_descriptor *epd)
+{
+       return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT;
+}
+
+static inline int RT_usb_endpoint_xfer_bulk(const struct usb_endpoint_descriptor *epd)
+{
+       return (epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK;
+}
+
+static inline int RT_usb_endpoint_is_bulk_in(const struct usb_endpoint_descriptor *epd)
+{
+       return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_in(epd);
+}
+
+static inline int RT_usb_endpoint_is_bulk_out(const struct usb_endpoint_descriptor *epd)
+{
+       return RT_usb_endpoint_xfer_bulk(epd) && RT_usb_endpoint_dir_out(epd);
+}
+
+static inline int RT_usb_endpoint_is_int_in(const struct usb_endpoint_descriptor *epd)
+{
+       return RT_usb_endpoint_xfer_int(epd) && RT_usb_endpoint_dir_in(epd);
+}
+
+static inline int RT_usb_endpoint_num(const struct usb_endpoint_descriptor *epd)
+{
+       return epd->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+}
+
+static u8 rtw_init_intf_priv(struct dvobj_priv *dvobj)
+{
+       u8 rst = _SUCCESS;
+
+       mutex_init(&dvobj->usb_vendor_req_mutex);
+       dvobj->usb_alloc_vendor_req_buf = kzalloc(MAX_USB_IO_CTL_SIZE,
+                                                 GFP_KERNEL);
+       if (dvobj->usb_alloc_vendor_req_buf == NULL) {
+               DBG_8723A("alloc usb_vendor_req_buf failed... /n");
+               rst = _FAIL;
+               goto exit;
+       }
+       dvobj->usb_vendor_req_buf =
+               PTR_ALIGN(dvobj->usb_alloc_vendor_req_buf, ALIGNMENT_UNIT);
+exit:
+       return rst;
+}
+
+static u8 rtw_deinit_intf_priv(struct dvobj_priv *dvobj)
+{
+       u8 rst = _SUCCESS;
+
+       kfree(dvobj->usb_alloc_vendor_req_buf);
+
+       mutex_destroy(&dvobj->usb_vendor_req_mutex);
+
+       return rst;
+}
+
+static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf)
+{
+       struct dvobj_priv *pdvobjpriv;
+       struct usb_device_descriptor *pdev_desc;
+       struct usb_host_config   *phost_conf;
+       struct usb_config_descriptor *pconf_desc;
+       struct usb_host_interface *phost_iface;
+       struct usb_interface_descriptor *piface_desc;
+       struct usb_host_endpoint *phost_endp;
+       struct usb_endpoint_descriptor *pendp_desc;
+       struct usb_device                *pusbd;
+       int     i;
+       int     status = _FAIL;
+
+       pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL);
+       if (!pdvobjpriv)
+               goto exit;
+
+       mutex_init(&pdvobjpriv->hw_init_mutex);
+       mutex_init(&pdvobjpriv->h2c_fwcmd_mutex);
+       mutex_init(&pdvobjpriv->setch_mutex);
+       mutex_init(&pdvobjpriv->setbw_mutex);
+
+       pdvobjpriv->pusbintf = usb_intf;
+       pusbd = interface_to_usbdev(usb_intf);
+       pdvobjpriv->pusbdev = pusbd;
+       usb_set_intfdata(usb_intf, pdvobjpriv);
+
+       pdvobjpriv->RtNumInPipes = 0;
+       pdvobjpriv->RtNumOutPipes = 0;
+
+       pdev_desc = &pusbd->descriptor;
+
+       phost_conf = pusbd->actconfig;
+       pconf_desc = &phost_conf->desc;
+
+       phost_iface = &usb_intf->altsetting[0];
+       piface_desc = &phost_iface->desc;
+
+       pdvobjpriv->NumInterfaces = pconf_desc->bNumInterfaces;
+       pdvobjpriv->InterfaceNumber = piface_desc->bInterfaceNumber;
+       pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints;
+
+       for (i = 0; i < pdvobjpriv->nr_endpoint; i++) {
+               phost_endp = phost_iface->endpoint + i;
+               if (phost_endp) {
+                       pendp_desc = &phost_endp->desc;
+
+                       DBG_8723A("\nusb_endpoint_descriptor(%d):\n", i);
+                       DBG_8723A("bLength =%x\n", pendp_desc->bLength);
+                       DBG_8723A("bDescriptorType =%x\n",
+                                 pendp_desc->bDescriptorType);
+                       DBG_8723A("bEndpointAddress =%x\n",
+                                 pendp_desc->bEndpointAddress);
+                       DBG_8723A("wMaxPacketSize =%d\n",
+                                 le16_to_cpu(pendp_desc->wMaxPacketSize));
+                       DBG_8723A("bInterval =%x\n", pendp_desc->bInterval);
+
+                       if (RT_usb_endpoint_is_bulk_in(pendp_desc)) {
+                               DBG_8723A("RT_usb_endpoint_is_bulk_in = %x\n",
+                                         RT_usb_endpoint_num(pendp_desc));
+                               pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
+                                       RT_usb_endpoint_num(pendp_desc);
+                               pdvobjpriv->RtNumInPipes++;
+                       } else if (RT_usb_endpoint_is_int_in(pendp_desc)) {
+                               DBG_8723A("RT_usb_endpoint_is_int_in = %x, Interval = %x\n",
+                                         RT_usb_endpoint_num(pendp_desc),
+                                         pendp_desc->bInterval);
+                               pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
+                                       RT_usb_endpoint_num(pendp_desc);
+                               pdvobjpriv->RtNumInPipes++;
+                       } else if (RT_usb_endpoint_is_bulk_out(pendp_desc)) {
+                               DBG_8723A("RT_usb_endpoint_is_bulk_out = %x\n",
+                                         RT_usb_endpoint_num(pendp_desc));
+                               pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] =
+                                       RT_usb_endpoint_num(pendp_desc);
+                               pdvobjpriv->RtNumOutPipes++;
+                       }
+                       pdvobjpriv->ep_num[i] = RT_usb_endpoint_num(pendp_desc);
+               }
+       }
+       DBG_8723A("nr_endpoint =%d, in_num =%d, out_num =%d\n\n",
+                 pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes,
+                 pdvobjpriv->RtNumOutPipes);
+
+       if (pusbd->speed == USB_SPEED_HIGH) {
+               pdvobjpriv->ishighspeed = true;
+               DBG_8723A("USB_SPEED_HIGH\n");
+       } else {
+               pdvobjpriv->ishighspeed = false;
+               DBG_8723A("NON USB_SPEED_HIGH\n");
+       }
+
+       if (rtw_init_intf_priv(pdvobjpriv) == _FAIL) {
+               RT_TRACE(_module_os_intfs_c_, _drv_err_,
+                        ("\n Can't INIT rtw_init_intf_priv\n"));
+               goto free_dvobj;
+       }
+       /* 3 misc */
+       sema_init(&(pdvobjpriv->usb_suspend_sema), 0);
+       rtw_reset_continual_urb_error(pdvobjpriv);
+       usb_get_dev(pusbd);
+       status = _SUCCESS;
+free_dvobj:
+       if (status != _SUCCESS && pdvobjpriv) {
+               usb_set_intfdata(usb_intf, NULL);
+               mutex_destroy(&pdvobjpriv->hw_init_mutex);
+               mutex_destroy(&pdvobjpriv->h2c_fwcmd_mutex);
+               mutex_destroy(&pdvobjpriv->setch_mutex);
+               mutex_destroy(&pdvobjpriv->setbw_mutex);
+               kfree(pdvobjpriv);
+               pdvobjpriv = NULL;
+       }
+exit:
+       return pdvobjpriv;
+}
+
+static void usb_dvobj_deinit(struct usb_interface *usb_intf)
+{
+       struct dvobj_priv *dvobj = usb_get_intfdata(usb_intf);
+
+       usb_set_intfdata(usb_intf, NULL);
+       if (dvobj) {
+               /* Modify condition for 92DU DMDP 2010.11.18, by Thomas */
+               if ((dvobj->NumInterfaces != 2 && dvobj->NumInterfaces != 3) ||
+                   (dvobj->InterfaceNumber == 1)) {
+                       if (interface_to_usbdev(usb_intf)->state !=
+                           USB_STATE_NOTATTACHED) {
+                               /* If we didn't unplug usb dongle and
+                                * remove/insert module, driver fails on
+                                * sitesurvey for the first time when
+                                * device is up .
+                                * Reset usb port for sitesurvey fail issue.
+                                */
+                               DBG_8723A("usb attached..., try to reset usb device\n");
+                               usb_reset_device(interface_to_usbdev(usb_intf));
+                       }
+               }
+               rtw_deinit_intf_priv(dvobj);
+               mutex_destroy(&dvobj->hw_init_mutex);
+               mutex_destroy(&dvobj->h2c_fwcmd_mutex);
+               mutex_destroy(&dvobj->setch_mutex);
+               mutex_destroy(&dvobj->setbw_mutex);
+               kfree(dvobj);
+       }
+       usb_put_dev(interface_to_usbdev(usb_intf));
+}
+
+static void decide_chip_type_by_usb_device_id(struct rtw_adapter *padapter,
+                                             const struct usb_device_id *pdid)
+{
+       padapter->chip_type = NULL_CHIP_TYPE;
+       hal_set_hw_type(padapter);
+}
+
+static void usb_intf_start(struct rtw_adapter *padapter)
+{
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_start\n"));
+       rtw_hal_inirp_init23a(padapter);
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_start\n"));
+}
+
+static void usb_intf_stop(struct rtw_adapter *padapter)
+{
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+usb_intf_stop\n"));
+
+       /* disable_hw_interrupt */
+       if (!padapter->bSurpriseRemoved) {
+               /* device still exists, so driver can do i/o operation
+                * TODO:
+                */
+               RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+                        ("SurpriseRemoved == false\n"));
+       }
+
+       /* cancel in irp */
+       rtw_hal_inirp_deinit23a(padapter);
+
+       /* cancel out irp */
+       rtw_write_port_cancel(padapter);
+
+       /* todo:cancel other irps */
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-usb_intf_stop\n"));
+}
+
+static void rtw_dev_unload(struct rtw_adapter *padapter)
+{
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_dev_unload\n"));
+
+       if (padapter->bup) {
+               DBG_8723A("===> rtw_dev_unload\n");
+
+               padapter->bDriverStopped = true;
+               if (padapter->xmitpriv.ack_tx)
+                       rtw_ack_tx_done23a(&padapter->xmitpriv,
+                                       RTW_SCTX_DONE_DRV_STOP);
+
+               /* s3. */
+               if (padapter->intf_stop)
+                       padapter->intf_stop(padapter);
+
+               /* s4. */
+               if (!padapter->pwrctrlpriv.bInternalAutoSuspend)
+                       rtw_stop_drv_threads23a(padapter);
+
+               /* s5. */
+               if (!padapter->bSurpriseRemoved) {
+                       rtw_hal_deinit23a(padapter);
+                       padapter->bSurpriseRemoved = true;
+               }
+               padapter->bup = false;
+       } else {
+               RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+                        ("r871x_dev_unload():padapter->bup == false\n"));
+       }
+       DBG_8723A("<=== rtw_dev_unload\n");
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n"));
+}
+
+int rtw_hw_suspend23a(struct rtw_adapter *padapter)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       struct net_device *pnetdev = padapter->pnetdev;
+
+       if ((!padapter->bup) || (padapter->bDriverStopped) ||
+           (padapter->bSurpriseRemoved)) {
+               DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n",
+                         padapter->bup, padapter->bDriverStopped,
+                         padapter->bSurpriseRemoved);
+               goto error_exit;
+       }
+
+       if (padapter) { /* system suspend */
+               LeaveAllPowerSaveMode23a(padapter);
+
+               DBG_8723A("==> rtw_hw_suspend23a\n");
+               down(&pwrpriv->lock);
+               pwrpriv->bips_processing = true;
+               /* padapter->net_closed = true; */
+               /* s1. */
+               if (pnetdev) {
+                       netif_carrier_off(pnetdev);
+                       netif_tx_stop_all_queues(pnetdev);
+               }
+
+               /* s2. */
+               rtw_disassoc_cmd23a(padapter, 500, false);
+
+               /* s2-2.  indicate disconnect to os */
+               /* rtw_indicate_disconnect23a(padapter); */
+               {
+                       struct  mlme_priv *pmlmepriv = &padapter->mlmepriv;
+
+                       if (check_fwstate(pmlmepriv, _FW_LINKED)) {
+                               _clr_fwstate_(pmlmepriv, _FW_LINKED);
+
+                               rtw_led_control(padapter, LED_CTL_NO_LINK);
+
+                               rtw_os_indicate_disconnect23a(padapter);
+
+                               /* donnot enqueue cmd */
+                               rtw_lps_ctrl_wk_cmd23a(padapter,
+                                                   LPS_CTRL_DISCONNECT, 0);
+                       }
+               }
+               /* s2-3. */
+               rtw_free_assoc_resources23a(padapter, 1);
+
+               /* s2-4. */
+               rtw_free_network_queue23a(padapter, true);
+               rtw_ips_dev_unload23a(padapter);
+               pwrpriv->rf_pwrstate = rf_off;
+               pwrpriv->bips_processing = false;
+               up(&pwrpriv->lock);
+       } else {
+               goto error_exit;
+       }
+       return 0;
+error_exit:
+       DBG_8723A("%s, failed\n", __func__);
+       return -1;
+}
+
+int rtw_hw_resume23a(struct rtw_adapter *padapter)
+{
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       struct net_device *pnetdev = padapter->pnetdev;
+
+       if (padapter) { /* system resume */
+               DBG_8723A("==> rtw_hw_resume23a\n");
+               down(&pwrpriv->lock);
+               pwrpriv->bips_processing = true;
+               rtw_reset_drv_sw23a(padapter);
+
+               if (pm_netdev_open23a(pnetdev, false)) {
+                       up(&pwrpriv->lock);
+                       goto error_exit;
+               }
+
+               netif_device_attach(pnetdev);
+               netif_carrier_on(pnetdev);
+
+               if (!rtw_netif_queue_stopped(pnetdev))
+                       netif_tx_start_all_queues(pnetdev);
+               else
+                       netif_tx_wake_all_queues(pnetdev);
+
+               pwrpriv->bkeepfwalive = false;
+               pwrpriv->brfoffbyhw = false;
+
+               pwrpriv->rf_pwrstate = rf_on;
+               pwrpriv->bips_processing = false;
+
+               up(&pwrpriv->lock);
+       } else {
+               goto error_exit;
+       }
+       return 0;
+error_exit:
+       DBG_8723A("%s, Open net dev failed\n", __func__);
+       return -1;
+}
+
+static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
+{
+       struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
+       struct rtw_adapter *padapter = dvobj->if1;
+       struct net_device *pnetdev = padapter->pnetdev;
+       struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       int ret = 0;
+       unsigned long start_time = jiffies;
+
+       DBG_8723A("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
+
+       if ((!padapter->bup) || (padapter->bDriverStopped) ||
+           (padapter->bSurpriseRemoved)) {
+               DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n",
+                         padapter->bup, padapter->bDriverStopped,
+                         padapter->bSurpriseRemoved);
+               goto exit;
+       }
+       pwrpriv->bInSuspend = true;
+       rtw_cancel_all_timer23a(padapter);
+       LeaveAllPowerSaveMode23a(padapter);
+
+       down(&pwrpriv->lock);
+       /* padapter->net_closed = true; */
+       /* s1. */
+       if (pnetdev) {
+               netif_carrier_off(pnetdev);
+               netif_tx_stop_all_queues(pnetdev);
+       }
+
+       /* s2. */
+       rtw_disassoc_cmd23a(padapter, 0, false);
+
+       if (check_fwstate(pmlmepriv, WIFI_STATION_STATE) &&
+           check_fwstate(pmlmepriv, _FW_LINKED)) {
+               DBG_8723A("%s:%d %s(%pM), length:%d assoc_ssid.length:%d\n",
+                         __func__, __LINE__,
+                         pmlmepriv->cur_network.network.Ssid.ssid,
+                         pmlmepriv->cur_network.network.MacAddress,
+                         pmlmepriv->cur_network.network.Ssid.ssid_len,
+                         pmlmepriv->assoc_ssid.ssid_len);
+
+               rtw_set_roaming(padapter, 1);
+       }
+       /* s2-2.  indicate disconnect to os */
+       rtw_indicate_disconnect23a(padapter);
+       /* s2-3. */
+       rtw_free_assoc_resources23a(padapter, 1);
+       /* s2-4. */
+       rtw_free_network_queue23a(padapter, true);
+
+       rtw_dev_unload(padapter);
+       up(&pwrpriv->lock);
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY))
+               rtw_indicate_scan_done23a(padapter, 1);
+
+       if (check_fwstate(pmlmepriv, _FW_UNDER_LINKING))
+               rtw_indicate_disconnect23a(padapter);
+
+exit:
+       DBG_8723A("<===  %s return %d.............. in %dms\n", __func__,
+                 ret, jiffies_to_msecs(jiffies - start_time));
+
+       return ret;
+}
+
+static int rtw_resume(struct usb_interface *pusb_intf)
+{
+       struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
+       struct rtw_adapter *padapter = dvobj->if1;
+       struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
+       int ret = 0;
+
+       if (pwrpriv->bInternalAutoSuspend)
+               ret = rtw_resume_process23a(padapter);
+       else
+               ret = rtw_resume_process23a(padapter);
+
+       return ret;
+}
+
+int rtw_resume_process23a(struct rtw_adapter *padapter)
+{
+       struct net_device *pnetdev;
+       struct pwrctrl_priv *pwrpriv = NULL;
+       int ret = -1;
+       unsigned long start_time = jiffies;
+
+       DBG_8723A("==> %s (%s:%d)\n", __func__, current->comm, current->pid);
+
+       if (!padapter)
+               goto exit;
+       pnetdev = padapter->pnetdev;
+       pwrpriv = &padapter->pwrctrlpriv;
+
+       down(&pwrpriv->lock);
+       rtw_reset_drv_sw23a(padapter);
+       pwrpriv->bkeepfwalive = false;
+
+       DBG_8723A("bkeepfwalive(%x)\n", pwrpriv->bkeepfwalive);
+       if (pm_netdev_open23a(pnetdev, true) != 0)
+               goto exit;
+
+       netif_device_attach(pnetdev);
+       netif_carrier_on(pnetdev);
+
+       up(&pwrpriv->lock);
+
+       if (padapter->pid[1] != 0) {
+               DBG_8723A("pid[1]:%d\n", padapter->pid[1]);
+               rtw_signal_process(padapter->pid[1], SIGUSR2);
+       }
+
+       rtw23a_roaming(padapter, NULL);
+
+       ret = 0;
+exit:
+       if (pwrpriv)
+               pwrpriv->bInSuspend = false;
+       DBG_8723A("<===  %s return %d.............. in %dms\n", __func__,
+                 ret, jiffies_to_msecs(jiffies - start_time));
+
+       return ret;
+}
+
+/*
+ * drv_init() - a device potentially for us
+ *
+ * notes: drv_init() is called when the bus driver has located a card
+ * for us to support.
+ *        We accept the new device by returning 0.
+ */
+static struct rtw_adapter *rtw_usb_if1_init(struct dvobj_priv *dvobj,
+                                           struct usb_interface *pusb_intf,
+                                           const struct usb_device_id *pdid)
+{
+       struct rtw_adapter *padapter = NULL;
+       struct net_device *pnetdev = NULL;
+       int status = _FAIL;
+
+       pnetdev = rtw_init_netdev23a(padapter);
+       if (!pnetdev)
+               goto handle_dualmac;
+       padapter = netdev_priv(pnetdev);
+
+       padapter->dvobj = dvobj;
+       padapter->bDriverStopped = true;
+       dvobj->if1 = padapter;
+       dvobj->padapters[dvobj->iface_nums++] = padapter;
+       padapter->iface_id = IFACE_ID0;
+
+       /* step 1-1., decide the chip_type via vid/pid */
+       decide_chip_type_by_usb_device_id(padapter, pdid);
+
+       if (rtw_handle_dualmac23a(padapter, 1) != _SUCCESS)
+               goto free_adapter;
+
+       SET_NETDEV_DEV(pnetdev, dvobj_to_dev(dvobj));
+
+       if (rtw_wdev_alloc(padapter, dvobj_to_dev(dvobj)))
+               goto handle_dualmac;
+
+       /* step 2. hook HalFunc, allocate HalData */
+       if (rtl8723au_set_hal_ops(padapter))
+               return NULL;
+
+       padapter->intf_start = &usb_intf_start;
+       padapter->intf_stop = &usb_intf_stop;
+
+       /* step init_io_priv */
+       rtw_init_io_priv23a(padapter, usb_set_intf_ops);
+
+       /* step read_chip_version */
+       rtw_hal_read_chip_version23a(padapter);
+
+       /* step usb endpoint mapping */
+       rtw_hal_chip_configure23a(padapter);
+
+       /* step read efuse/eeprom data and get mac_addr */
+       rtw_hal_read_chip_info23a(padapter);
+
+       /* step 5. */
+       if (rtw_init_drv_sw23a(padapter) == _FAIL) {
+               RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+                        ("Initialize driver software resource Failed!\n"));
+               goto free_hal_data;
+       }
+
+#ifdef CONFIG_PM
+       if (padapter->pwrctrlpriv.bSupportRemoteWakeup) {
+               dvobj->pusbdev->do_remote_wakeup = 1;
+               pusb_intf->needs_remote_wakeup = 1;
+               device_init_wakeup(&pusb_intf->dev, 1);
+               DBG_8723A("\n  padapter->pwrctrlpriv.bSupportRemoteWakeup~~~~~~\n");
+               DBG_8723A("\n  padapter->pwrctrlpriv.bSupportRemoteWakeup~~~[%d]~~~\n",
+                         device_may_wakeup(&pusb_intf->dev));
+       }
+#endif
+       /* 2012-07-11 Move here to prevent the 8723AS-VAU BT
+        * auto suspend influence
+        */
+       if (usb_autopm_get_interface(pusb_intf) < 0)
+               DBG_8723A("can't get autopm:\n");
+#ifdef CONFIG_8723AU_BT_COEXIST
+       padapter->pwrctrlpriv.autopm_cnt = 1;
+#endif
+
+       /*  set mac addr */
+       rtw_macaddr_cfg23a(padapter->eeprompriv.mac_addr);
+#ifdef CONFIG_8723AU_P2P
+       rtw_init_wifidirect_addrs23a(padapter, padapter->eeprompriv.mac_addr,
+                                 padapter->eeprompriv.mac_addr);
+#endif
+
+       DBG_8723A("bDriverStopped:%d, bSurpriseRemoved:%d, bup:%d, hw_init_completed:%d\n",
+                 padapter->bDriverStopped, padapter->bSurpriseRemoved,
+                 padapter->bup, padapter->hw_init_completed
+       );
+       status = _SUCCESS;
+
+free_hal_data:
+       if (status != _SUCCESS)
+               kfree(padapter->HalData);
+       if (status != _SUCCESS) {
+               rtw_wdev_unregister(padapter->rtw_wdev);
+               rtw_wdev_free(padapter->rtw_wdev);
+       }
+handle_dualmac:
+       if (status != _SUCCESS)
+               rtw_handle_dualmac23a(padapter, 0);
+free_adapter:
+       if (status != _SUCCESS) {
+               if (pnetdev)
+                       free_netdev(pnetdev);
+               padapter = NULL;
+       }
+       return padapter;
+}
+
+static void rtw_usb_if1_deinit(struct rtw_adapter *if1)
+{
+       struct net_device *pnetdev = if1->pnetdev;
+       struct mlme_priv *pmlmepriv = &if1->mlmepriv;
+
+       if (check_fwstate(pmlmepriv, _FW_LINKED))
+               rtw_disassoc_cmd23a(if1, 0, false);
+
+#ifdef CONFIG_8723AU_AP_MODE
+       free_mlme_ap_info23a(if1);
+#endif
+
+       if (pnetdev)
+               unregister_netdev(pnetdev); /* will call netdev_close() */
+
+       rtw_cancel_all_timer23a(if1);
+
+       rtw_dev_unload(if1);
+
+       DBG_8723A("+r871xu_dev_remove, hw_init_completed =%d\n",
+                 if1->hw_init_completed);
+
+       rtw_handle_dualmac23a(if1, 0);
+
+       if (if1->rtw_wdev) {
+               rtw_wdev_unregister(if1->rtw_wdev);
+               rtw_wdev_free(if1->rtw_wdev);
+       }
+
+#ifdef CONFIG_8723AU_BT_COEXIST
+       if (1 == if1->pwrctrlpriv.autopm_cnt) {
+               usb_autopm_put_interface(adapter_to_dvobj(if1)->pusbintf);
+               if1->pwrctrlpriv.autopm_cnt--;
+       }
+#endif
+
+       rtw_free_drv_sw23a(if1);
+
+       if (pnetdev)
+               free_netdev(pnetdev);
+}
+
+static int rtw_drv_init(struct usb_interface *pusb_intf,
+                       const struct usb_device_id *pdid)
+{
+       struct rtw_adapter *if1 = NULL;
+       struct dvobj_priv *dvobj;
+       int status = _FAIL;
+
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_init\n"));
+
+       /* Initialize dvobj_priv */
+       dvobj = usb_dvobj_init(pusb_intf);
+       if (!dvobj) {
+               RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+                        ("initialize device object priv Failed!\n"));
+               goto exit;
+       }
+
+       if1 = rtw_usb_if1_init(dvobj, pusb_intf, pdid);
+       if (!if1) {
+               DBG_8723A("rtw_init_primary_adapter Failed!\n");
+               goto free_dvobj;
+       }
+
+       /* dev_alloc_name && register_netdev */
+       status = rtw_drv_register_netdev(if1);
+       if (status != _SUCCESS)
+               goto free_if1;
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_,
+                ("-871x_drv - drv_init, success!\n"));
+
+       status = _SUCCESS;
+
+free_if1:
+       if (status != _SUCCESS && if1)
+               rtw_usb_if1_deinit(if1);
+free_dvobj:
+       if (status != _SUCCESS)
+               usb_dvobj_deinit(pusb_intf);
+exit:
+       return status == _SUCCESS ? 0 : -ENODEV;
+}
+
+/* dev_remove() - our device is being removed */
+static void rtw_disconnect(struct usb_interface *pusb_intf)
+{
+       struct dvobj_priv *dvobj;
+       struct rtw_adapter *padapter;
+       struct net_device *pnetdev;
+       struct mlme_priv *pmlmepriv;
+
+       dvobj = usb_get_intfdata(pusb_intf);
+       if (!dvobj)
+               return;
+
+       padapter = dvobj->if1;
+       pnetdev = padapter->pnetdev;
+       pmlmepriv = &padapter->mlmepriv;
+
+       usb_set_intfdata(pusb_intf, NULL);
+
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+dev_remove()\n"));
+
+       rtw_pm_set_ips23a(padapter, IPS_NONE);
+       rtw_pm_set_lps23a(padapter, PS_MODE_ACTIVE);
+
+       LeaveAllPowerSaveMode23a(padapter);
+
+       rtw_usb_if1_deinit(padapter);
+
+       usb_dvobj_deinit(pusb_intf);
+
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-dev_remove()\n"));
+       DBG_8723A("-r871xu_dev_remove, done\n");
+
+       return;
+}
+
+static int __init rtw_drv_entry(void)
+{
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_entry\n"));
+       return usb_register(usb_drv);
+}
+
+static void __exit rtw_drv_halt(void)
+{
+       RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("+rtw_drv_halt\n"));
+       DBG_8723A("+rtw_drv_halt\n");
+
+       usb_deregister(usb_drv);
+
+       DBG_8723A("-rtw_drv_halt\n");
+}
+
+module_init(rtw_drv_entry);
+module_exit(rtw_drv_halt);
diff --git a/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c b/drivers/staging/rtl8723au/os_dep/usb_ops_linux.c
new file mode 100644 (file)
index 0000000..c49160e
--- /dev/null
@@ -0,0 +1,283 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _USB_OPS_LINUX_C_
+
+#include <drv_types.h>
+#include <usb_ops_linux.h>
+#include <rtw_sreset.h>
+
+unsigned int ffaddr2pipehdl23a(struct dvobj_priv *pdvobj, u32 addr)
+{
+       struct usb_device *pusbd = pdvobj->pusbdev;
+       unsigned int pipe = 0, ep_num = 0;
+
+       if (addr == RECV_BULK_IN_ADDR) {
+               pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[0]);
+       } else if (addr == RECV_INT_IN_ADDR) {
+               pipe = usb_rcvbulkpipe(pusbd, pdvobj->RtInPipe[1]);
+       } else if (addr < HW_QUEUE_ENTRY) {
+               ep_num = pdvobj->Queue2Pipe[addr];
+               pipe = usb_sndbulkpipe(pusbd, ep_num);
+       }
+       return pipe;
+}
+
+struct zero_bulkout_context {
+       void *pbuf;
+       void *purb;
+       void *pirp;
+       void *padapter;
+};
+
+void usb_read_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *rmem)
+{
+}
+
+void usb_write_mem23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt, u8 *wmem)
+{
+}
+
+void usb_read_port_cancel23a(struct intf_hdl *pintfhdl)
+{
+       struct recv_buf *precvbuf;
+       struct rtw_adapter *padapter = pintfhdl->padapter;
+       int i;
+
+       precvbuf = (struct recv_buf *)padapter->recvpriv.precv_buf;
+
+       DBG_8723A("%s\n", __func__);
+
+       padapter->bReadPortCancel = true;
+
+       for (i = 0; i < NR_RECVBUFF ; i++) {
+               if (precvbuf->purb)
+                       usb_kill_urb(precvbuf->purb);
+               precvbuf++;
+       }
+       usb_kill_urb(padapter->recvpriv.int_in_urb);
+}
+
+static void usb_write_port23a_complete(struct urb *purb, struct pt_regs *regs)
+{
+       struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
+       struct rtw_adapter *padapter = pxmitbuf->padapter;
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct hal_data_8723a *phaldata;
+       unsigned long irqL;
+
+       switch (pxmitbuf->flags) {
+       case VO_QUEUE_INX:
+               pxmitpriv->voq_cnt--;
+               break;
+       case VI_QUEUE_INX:
+               pxmitpriv->viq_cnt--;
+               break;
+       case BE_QUEUE_INX:
+               pxmitpriv->beq_cnt--;
+               break;
+       case BK_QUEUE_INX:
+               pxmitpriv->bkq_cnt--;
+               break;
+       case HIGH_QUEUE_INX:
+#ifdef CONFIG_8723AU_AP_MODE
+               rtw_chk_hi_queue_cmd23a(padapter);
+#endif
+               break;
+       default:
+               break;
+       }
+
+       if (padapter->bSurpriseRemoved || padapter->bDriverStopped ||
+           padapter->bWritePortCancel) {
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("usb_write_port23a_complete:bDriverStopped(%d) OR bSurpriseRemoved(%d)",
+                        padapter->bDriverStopped, padapter->bSurpriseRemoved));
+               DBG_8723A("%s(): TX Warning! bDriverStopped(%d) OR bSurpriseRemoved(%d) bWritePortCancel(%d) pxmitbuf->ext_tag(%x)\n",
+                         __func__, padapter->bDriverStopped,
+                         padapter->bSurpriseRemoved, padapter->bReadPortCancel,
+                         pxmitbuf->ext_tag);
+
+               goto check_completion;
+       }
+
+       if (purb->status) {
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("usb_write_port23a_complete : purb->status(%d) != 0\n",
+                        purb->status));
+               DBG_8723A("###=> urb_write_port_complete status(%d)\n",
+                         purb->status);
+               if ((purb->status == -EPIPE) || (purb->status == -EPROTO)) {
+                       sreset_set_wifi_error_status23a(padapter,
+                                                    USB_WRITE_PORT_FAIL);
+               } else if (purb->status == -EINPROGRESS) {
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                                ("usb_write_port23a_complete: EINPROGESS\n"));
+                       goto check_completion;
+               } else if (purb->status == -ENOENT) {
+                       DBG_8723A("%s: -ENOENT\n", __func__);
+                       goto check_completion;
+               } else if (purb->status == -ECONNRESET) {
+                       DBG_8723A("%s: -ECONNRESET\n", __func__);
+                       goto check_completion;
+               } else if (purb->status == -ESHUTDOWN) {
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                                ("usb_write_port23a_complete: ESHUTDOWN\n"));
+                       padapter->bDriverStopped = true;
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                                ("usb_write_port23a_complete:bDriverStopped = true\n"));
+                       goto check_completion;
+               } else {
+                       padapter->bSurpriseRemoved = true;
+                       DBG_8723A("bSurpriseRemoved = true\n");
+                       RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                                ("usb_write_port23a_complete:bSurpriseRemoved = true\n"));
+                       goto check_completion;
+               }
+       }
+       phaldata = GET_HAL_DATA(padapter);
+       phaldata->srestpriv.last_tx_complete_time = jiffies;
+
+check_completion:
+       spin_lock_irqsave(&pxmitpriv->lock_sctx, irqL);
+       rtw23a_sctx_done_err(&pxmitbuf->sctx,
+                         purb->status ? RTW_SCTX_DONE_WRITE_PORT_ERR :
+                         RTW_SCTX_DONE_SUCCESS);
+       spin_unlock_irqrestore(&pxmitpriv->lock_sctx, irqL);
+
+       rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
+
+       tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+}
+
+u32 usb_write_port23a(struct intf_hdl *pintfhdl, u32 addr, u32 cnt,
+                  struct xmit_buf *pxmitbuf)
+{
+       struct urb *purb = NULL;
+       struct rtw_adapter *padapter = (struct rtw_adapter *)pintfhdl->padapter;
+       struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter);
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       struct xmit_frame *pxmitframe = (struct xmit_frame *)pxmitbuf->priv_data;
+       struct usb_device *pusbd = pdvobj->pusbdev;
+       unsigned long irqL;
+       unsigned int pipe;
+       int status;
+       u32 ret = _FAIL;
+
+       RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("+usb_write_port23a\n"));
+
+       if ((padapter->bDriverStopped) || (padapter->bSurpriseRemoved) ||
+           (padapter->pwrctrlpriv.pnp_bstop_trx)) {
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("usb_write_port23a:( padapter->bDriverStopped ||padapter->bSurpriseRemoved ||adapter->pwrctrlpriv.pnp_bstop_trx)!!!\n"));
+               rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_TX_DENY);
+               goto exit;
+       }
+
+       spin_lock_irqsave(&pxmitpriv->lock, irqL);
+
+       switch (addr) {
+       case VO_QUEUE_INX:
+               pxmitpriv->voq_cnt++;
+               pxmitbuf->flags = VO_QUEUE_INX;
+               break;
+       case VI_QUEUE_INX:
+               pxmitpriv->viq_cnt++;
+               pxmitbuf->flags = VI_QUEUE_INX;
+               break;
+       case BE_QUEUE_INX:
+               pxmitpriv->beq_cnt++;
+               pxmitbuf->flags = BE_QUEUE_INX;
+               break;
+       case BK_QUEUE_INX:
+               pxmitpriv->bkq_cnt++;
+               pxmitbuf->flags = BK_QUEUE_INX;
+               break;
+       case HIGH_QUEUE_INX:
+               pxmitbuf->flags = HIGH_QUEUE_INX;
+               break;
+       default:
+               pxmitbuf->flags = MGT_QUEUE_INX;
+               break;
+       }
+
+       spin_unlock_irqrestore(&pxmitpriv->lock, irqL);
+
+       purb    = pxmitbuf->pxmit_urb[0];
+
+       /* translate DMA FIFO addr to pipehandle */
+       pipe = ffaddr2pipehdl23a(pdvobj, addr);
+
+       usb_fill_bulk_urb(purb, pusbd, pipe,
+                         pxmitframe->buf_addr, /*  pxmitbuf->pbuf */
+                         cnt, usb_write_port23a_complete,
+                         pxmitbuf);/* context is pxmitbuf */
+
+       status = usb_submit_urb(purb, GFP_ATOMIC);
+       if (!status) {
+               struct hal_data_8723a *phaldata = GET_HAL_DATA(padapter);
+               phaldata->srestpriv.last_tx_time = jiffies;
+       } else {
+               rtw23a_sctx_done_err(&pxmitbuf->sctx,
+                                 RTW_SCTX_DONE_WRITE_PORT_ERR);
+               DBG_8723A("usb_write_port23a, status =%d\n", status);
+               RT_TRACE(_module_hci_ops_os_c_, _drv_err_,
+                        ("usb_write_port23a(): usb_submit_urb, status =%x\n",
+                        status));
+
+               switch (status) {
+               case -ENODEV:
+                       padapter->bDriverStopped = true;
+                       break;
+               default:
+                       break;
+               }
+               goto exit;
+       }
+       ret = _SUCCESS;
+       RT_TRACE(_module_hci_ops_os_c_, _drv_err_, ("-usb_write_port23a\n"));
+
+exit:
+       if (ret != _SUCCESS)
+               rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf);
+
+       return ret;
+}
+
+void usb_write_port23a_cancel(struct intf_hdl *pintfhdl)
+{
+       struct rtw_adapter *padapter = pintfhdl->padapter;
+       struct xmit_buf *pxmitbuf;
+       struct list_head *plist;
+       int j;
+
+       DBG_8723A("%s\n", __func__);
+
+       padapter->bWritePortCancel = true;
+
+       list_for_each(plist, &padapter->xmitpriv.xmitbuf_list) {
+               pxmitbuf = container_of(plist, struct xmit_buf, list2);
+               for (j = 0; j < 8; j++) {
+                       if (pxmitbuf->pxmit_urb[j])
+                               usb_kill_urb(pxmitbuf->pxmit_urb[j]);
+               }
+       }
+       list_for_each(plist, &padapter->xmitpriv.xmitextbuf_list) {
+               pxmitbuf = container_of(plist, struct xmit_buf, list2);
+               for (j = 0; j < 8; j++) {
+                       if (pxmitbuf->pxmit_urb[j])
+                               usb_kill_urb(pxmitbuf->pxmit_urb[j]);
+               }
+       }
+}
diff --git a/drivers/staging/rtl8723au/os_dep/xmit_linux.c b/drivers/staging/rtl8723au/os_dep/xmit_linux.c
new file mode 100644 (file)
index 0000000..e1c6fc7
--- /dev/null
@@ -0,0 +1,195 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2007 - 2012 Realtek Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License 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.
+ *
+ ******************************************************************************/
+#define _XMIT_OSDEP_C_
+
+#include <osdep_service.h>
+#include <drv_types.h>
+
+#include <linux/if_ether.h>
+#include <linux/ip.h>
+#include <wifi.h>
+#include <mlme_osdep.h>
+#include <xmit_osdep.h>
+#include <osdep_intf.h>
+
+uint rtw_remainder_len23a(struct pkt_file *pfile)
+{
+       return pfile->buf_len - ((unsigned long)(pfile->cur_addr) -
+              (unsigned long)(pfile->buf_start));
+}
+
+void _rtw_open_pktfile23a(struct sk_buff *pktptr, struct pkt_file *pfile)
+{
+       pfile->pkt = pktptr;
+       pfile->buf_start = pktptr->data;
+       pfile->cur_addr = pktptr->data;
+       pfile->buf_len = pktptr->len;
+       pfile->pkt_len = pktptr->len;
+
+       pfile->cur_buffer = pfile->buf_start;
+}
+
+uint _rtw_pktfile_read23a(struct pkt_file *pfile, u8 *rmem, uint rlen)
+{
+       uint    len = 0;
+
+       len =  rtw_remainder_len23a(pfile);
+       len = (rlen > len) ? len : rlen;
+
+       if (rmem)
+               skb_copy_bits(pfile->pkt, pfile->buf_len-pfile->pkt_len,
+                             rmem, len);
+
+       pfile->cur_addr += len;
+       pfile->pkt_len -= len;
+
+       return len;
+}
+
+int rtw_endofpktfile23a(struct pkt_file *pfile)
+{
+       if (pfile->pkt_len == 0)
+               return true;
+       return false;
+}
+
+int rtw_os_xmit_resource_alloc23a(struct rtw_adapter *padapter,
+                              struct xmit_buf *pxmitbuf, u32 alloc_sz)
+{
+       int i;
+
+       pxmitbuf->pallocated_buf = kzalloc(alloc_sz, GFP_KERNEL);
+       if (pxmitbuf->pallocated_buf == NULL)
+               return _FAIL;
+
+       pxmitbuf->pbuf = PTR_ALIGN(pxmitbuf->pallocated_buf, XMITBUF_ALIGN_SZ);
+
+       for (i = 0; i < 8; i++) {
+               pxmitbuf->pxmit_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+               if (pxmitbuf->pxmit_urb[i] == NULL) {
+                       DBG_8723A("pxmitbuf->pxmit_urb[i]==NULL");
+                       return _FAIL;
+               }
+       }
+       return _SUCCESS;
+}
+
+void rtw_os_xmit_resource_free23a(struct rtw_adapter *padapter,
+                              struct xmit_buf *pxmitbuf)
+{
+       int i;
+
+       for (i = 0; i < 8; i++)
+               usb_free_urb(pxmitbuf->pxmit_urb[i]);
+       kfree(pxmitbuf->pallocated_buf);
+}
+
+#define WMM_XMIT_THRESHOLD     (NR_XMITFRAME*2/5)
+
+void rtw_os_pkt_complete23a(struct rtw_adapter *padapter, struct sk_buff *pkt)
+{
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       u16     queue;
+
+       queue = skb_get_queue_mapping(pkt);
+       if (padapter->registrypriv.wifi_spec) {
+               if (__netif_subqueue_stopped(padapter->pnetdev, queue) &&
+                   (pxmitpriv->hwxmits[queue].accnt < WMM_XMIT_THRESHOLD))
+                       netif_wake_subqueue(padapter->pnetdev, queue);
+       } else {
+               if (__netif_subqueue_stopped(padapter->pnetdev, queue))
+                       netif_wake_subqueue(padapter->pnetdev, queue);
+       }
+       dev_kfree_skb_any(pkt);
+}
+
+void rtw_os_xmit_complete23a(struct rtw_adapter *padapter,
+                         struct xmit_frame *pxframe)
+{
+       if (pxframe->pkt)
+               rtw_os_pkt_complete23a(padapter, pxframe->pkt);
+
+       pxframe->pkt = NULL;
+}
+
+void rtw_os_xmit_schedule23a(struct rtw_adapter *padapter)
+{
+       struct xmit_priv *pxmitpriv;
+
+       if (!padapter)
+               return;
+       pxmitpriv = &padapter->xmitpriv;
+
+       spin_lock_bh(&pxmitpriv->lock);
+
+       if (rtw_txframes_pending23a(padapter))
+               tasklet_hi_schedule(&pxmitpriv->xmit_tasklet);
+       spin_unlock_bh(&pxmitpriv->lock);
+}
+
+static void rtw_check_xmit_resource(struct rtw_adapter *padapter,
+                                   struct sk_buff *pkt)
+{
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       u16     queue;
+
+       queue = skb_get_queue_mapping(pkt);
+       if (padapter->registrypriv.wifi_spec) {
+               /* No free space for Tx, tx_worker is too slow */
+               if (pxmitpriv->hwxmits[queue].accnt > WMM_XMIT_THRESHOLD)
+                       netif_stop_subqueue(padapter->pnetdev, queue);
+       } else {
+               if (pxmitpriv->free_xmitframe_cnt <= 4) {
+                       if (!netif_tx_queue_stopped(netdev_get_tx_queue(padapter->pnetdev, queue)))
+                               netif_stop_subqueue(padapter->pnetdev, queue);
+               }
+       }
+}
+
+int rtw_xmit23a_entry23a(struct sk_buff *skb, struct net_device *pnetdev)
+{
+       struct rtw_adapter *padapter = netdev_priv(pnetdev);
+       struct xmit_priv *pxmitpriv = &padapter->xmitpriv;
+       int res = 0;
+
+       RT_TRACE(_module_rtl871x_mlme_c_, _drv_info_, ("+xmit_enry\n"));
+
+       if (!rtw_if_up23a(padapter)) {
+               RT_TRACE(_module_xmit_osdep_c_, _drv_err_,
+                        ("rtw_xmit23a_entry23a: rtw_if_up23a fail\n"));
+               goto drop_packet;
+       }
+
+       rtw_check_xmit_resource(padapter, skb);
+
+       res = rtw_xmit23a(padapter, skb);
+       if (res < 0)
+               goto drop_packet;
+
+       pxmitpriv->tx_pkts++;
+       RT_TRACE(_module_xmit_osdep_c_, _drv_info_,
+                ("rtw_xmit23a_entry23a: tx_pkts=%d\n",
+                (u32)pxmitpriv->tx_pkts));
+       goto exit;
+
+drop_packet:
+       pxmitpriv->tx_drop++;
+       dev_kfree_skb_any(skb);
+       RT_TRACE(_module_xmit_osdep_c_, _drv_notice_,
+                ("rtw_xmit23a_entry23a: drop, tx_drop=%d\n",
+                (u32)pxmitpriv->tx_drop));
+exit:
+       return 0;
+}
index e2f597e..1ca91f7 100644 (file)
@@ -851,75 +851,75 @@ static ssize_t message_store(struct kobject *kobj, struct kobj_attribute *attr,
  * Declare the attributes.
  */
 static struct kobj_attribute keymap_attribute =
-       __ATTR(keymap, ROOT_W, keymap_show, keymap_store);
+       __ATTR(keymap, S_IWUSR|S_IRUGO, keymap_show, keymap_store);
 static struct kobj_attribute silent_attribute =
-       __ATTR(silent, USER_W, NULL, silent_store);
+       __ATTR(silent, S_IWUGO, NULL, silent_store);
 static struct kobj_attribute synth_attribute =
-       __ATTR(synth, USER_RW, synth_show, synth_store);
+       __ATTR(synth, S_IWUGO|S_IRUGO, synth_show, synth_store);
 static struct kobj_attribute synth_direct_attribute =
-       __ATTR(synth_direct, USER_W, NULL, synth_direct_store);
+       __ATTR(synth_direct, S_IWUGO, NULL, synth_direct_store);
 static struct kobj_attribute version_attribute =
        __ATTR_RO(version);
 
 static struct kobj_attribute delimiters_attribute =
-       __ATTR(delimiters, USER_RW, punc_show, punc_store);
+       __ATTR(delimiters, S_IWUGO|S_IRUGO, punc_show, punc_store);
 static struct kobj_attribute ex_num_attribute =
-       __ATTR(ex_num, USER_RW, punc_show, punc_store);
+       __ATTR(ex_num, S_IWUGO|S_IRUGO, punc_show, punc_store);
 static struct kobj_attribute punc_all_attribute =
-       __ATTR(punc_all, USER_RW, punc_show, punc_store);
+       __ATTR(punc_all, S_IWUGO|S_IRUGO, punc_show, punc_store);
 static struct kobj_attribute punc_most_attribute =
-       __ATTR(punc_most, USER_RW, punc_show, punc_store);
+       __ATTR(punc_most, S_IWUGO|S_IRUGO, punc_show, punc_store);
 static struct kobj_attribute punc_some_attribute =
-       __ATTR(punc_some, USER_RW, punc_show, punc_store);
+       __ATTR(punc_some, S_IWUGO|S_IRUGO, punc_show, punc_store);
 static struct kobj_attribute repeats_attribute =
-       __ATTR(repeats, USER_RW, punc_show, punc_store);
+       __ATTR(repeats, S_IWUGO|S_IRUGO, punc_show, punc_store);
 
 static struct kobj_attribute attrib_bleep_attribute =
-       __ATTR(attrib_bleep, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(attrib_bleep, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute bell_pos_attribute =
-       __ATTR(bell_pos, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(bell_pos, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute bleep_time_attribute =
-       __ATTR(bleep_time, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(bleep_time, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute bleeps_attribute =
-       __ATTR(bleeps, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(bleeps, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute cursor_time_attribute =
-       __ATTR(cursor_time, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(cursor_time, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute key_echo_attribute =
-       __ATTR(key_echo, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(key_echo, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute no_interrupt_attribute =
-       __ATTR(no_interrupt, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(no_interrupt, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute punc_level_attribute =
-       __ATTR(punc_level, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(punc_level, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute reading_punc_attribute =
-       __ATTR(reading_punc, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(reading_punc, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute say_control_attribute =
-       __ATTR(say_control, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(say_control, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute say_word_ctl_attribute =
-       __ATTR(say_word_ctl, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(say_word_ctl, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute spell_delay_attribute =
-       __ATTR(spell_delay, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(spell_delay, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * These attributes are i18n related.
  */
 static struct kobj_attribute announcements_attribute =
-       __ATTR(announcements, USER_RW, message_show, message_store);
+       __ATTR(announcements, S_IWUGO|S_IRUGO, message_show, message_store);
 static struct kobj_attribute characters_attribute =
-       __ATTR(characters, USER_RW, chars_chartab_show, chars_chartab_store);
+       __ATTR(characters, S_IWUGO|S_IRUGO, chars_chartab_show, chars_chartab_store);
 static struct kobj_attribute chartab_attribute =
-       __ATTR(chartab, USER_RW, chars_chartab_show, chars_chartab_store);
+       __ATTR(chartab, S_IWUGO|S_IRUGO, chars_chartab_show, chars_chartab_store);
 static struct kobj_attribute ctl_keys_attribute =
-       __ATTR(ctl_keys, USER_RW, message_show, message_store);
+       __ATTR(ctl_keys, S_IWUGO|S_IRUGO, message_show, message_store);
 static struct kobj_attribute colors_attribute =
-       __ATTR(colors, USER_RW, message_show, message_store);
+       __ATTR(colors, S_IWUGO|S_IRUGO, message_show, message_store);
 static struct kobj_attribute formatted_attribute =
-       __ATTR(formatted, USER_RW, message_show, message_store);
+       __ATTR(formatted, S_IWUGO|S_IRUGO, message_show, message_store);
 static struct kobj_attribute function_names_attribute =
-       __ATTR(function_names, USER_RW, message_show, message_store);
+       __ATTR(function_names, S_IWUGO|S_IRUGO, message_show, message_store);
 static struct kobj_attribute key_names_attribute =
-       __ATTR(key_names, USER_RW, message_show, message_store);
+       __ATTR(key_names, S_IWUGO|S_IRUGO, message_show, message_store);
 static struct kobj_attribute states_attribute =
-       __ATTR(states, USER_RW, message_show, message_store);
+       __ATTR(states, S_IWUGO|S_IRUGO, message_show, message_store);
 
 /*
  * Create groups of attributes so that we can create and destroy them all
index 0126f71..a7bccee 100644 (file)
@@ -12,8 +12,6 @@
 /* proc permissions */
 #define USER_R (S_IFREG|S_IRUGO)
 #define USER_W (S_IFREG|S_IWUGO)
-#define USER_RW (S_IFREG|S_IRUGO|S_IWUGO)
-#define ROOT_W (S_IFREG|S_IRUGO|S_IWUSR)
 
 #define TOGGLE_0 .u.n = {NULL, 0, 0, 1, 0, 0, NULL }
 #define TOGGLE_1 .u.n = {NULL, 1, 0, 1, 0, 0, NULL }
index 1c8a7f4..e7dfa43 100644 (file)
@@ -62,28 +62,28 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/acntpc.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 22a8b72..c7f014e 100644 (file)
@@ -47,28 +47,28 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/acntsa.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IRUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IRUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IRUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IRUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 70cf159..38c8c22 100644 (file)
@@ -53,30 +53,30 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/apollo.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute lang_attribute =
-       __ATTR(lang, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(lang, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute voice_attribute =
-       __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(voice, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 61a3cee..de5b4a5 100644 (file)
@@ -49,30 +49,30 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/audptr.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute punct_attribute =
-       __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(punct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 4bfe3d4..4939e8c 100644 (file)
@@ -44,28 +44,28 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/bns.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index d306e01..b17af98 100644 (file)
@@ -70,30 +70,30 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/decext.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute punct_attribute =
-       __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(punct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute voice_attribute =
-       __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(voice, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index ea6b72d..cfa4bc0 100644 (file)
@@ -164,30 +164,30 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/decpc.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute punct_attribute =
-       __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(punct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute voice_attribute =
-       __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(voice, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 756d015..1fcae55 100644 (file)
@@ -70,30 +70,30 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/dectlk.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute punct_attribute =
-       __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(punct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute voice_attribute =
-       __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(voice, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 1feb0fb..5c6c341 100644 (file)
@@ -67,34 +67,34 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/dtlk.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute freq_attribute =
-       __ATTR(freq, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(freq, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute punct_attribute =
-       __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(punct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute voice_attribute =
-       __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(voice, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 4a24b9c..e19e999 100644 (file)
@@ -46,28 +46,28 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/dummy.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 2f2fe5e..9c246d7 100644 (file)
@@ -59,24 +59,24 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/keypc.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 326f94d..c9be6f5 100644 (file)
@@ -50,34 +50,34 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/ltlk.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute freq_attribute =
-       __ATTR(freq, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(freq, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute punct_attribute =
-       __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(punct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute voice_attribute =
-       __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(voice, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 243c3d5..ee60895 100644 (file)
@@ -61,41 +61,41 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/soft.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute freq_attribute =
-       __ATTR(freq, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(freq, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute punct_attribute =
-       __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(punct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute voice_attribute =
-       __ATTR(voice, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(voice, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * We should uncomment the following definition, when we agree on a
  * method of passing a language designation to the software synthesizer.
  * static struct kobj_attribute lang_attribute =
- *     __ATTR(lang, USER_RW, spk_var_show, spk_var_store);
+ *     __ATTR(lang, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
  */
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index e74f856..711cf11 100644 (file)
@@ -48,30 +48,30 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/spkout.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute punct_attribute =
-       __ATTR(punct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(punct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index 5a29b9f..3f0be04 100644 (file)
@@ -44,28 +44,28 @@ static struct var_t vars[] = {
  * These attributes will appear in /sys/accessibility/speakup/txprt.
  */
 static struct kobj_attribute caps_start_attribute =
-       __ATTR(caps_start, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_start, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute caps_stop_attribute =
-       __ATTR(caps_stop, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(caps_stop, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute pitch_attribute =
-       __ATTR(pitch, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(pitch, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute rate_attribute =
-       __ATTR(rate, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(rate, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute tone_attribute =
-       __ATTR(tone, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(tone, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute vol_attribute =
-       __ATTR(vol, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(vol, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 
 static struct kobj_attribute delay_time_attribute =
-       __ATTR(delay_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(delay_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute direct_attribute =
-       __ATTR(direct, USER_RW, spk_var_show, spk_var_store);
+       __ATTR(direct, S_IWUGO|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute full_time_attribute =
-       __ATTR(full_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(full_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute jiffy_delta_attribute =
-       __ATTR(jiffy_delta, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(jiffy_delta, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 static struct kobj_attribute trigger_time_attribute =
-       __ATTR(trigger_time, ROOT_W, spk_var_show, spk_var_store);
+       __ATTR(trigger_time, S_IWUSR|S_IRUGO, spk_var_show, spk_var_store);
 
 /*
  * Create a group of attributes so that we can create and destroy them all
index ac080c9..6bae2af 100644 (file)
@@ -3,7 +3,7 @@
 #
 menuconfig UNISYSSPAR
        bool "Unisys SPAR driver support"
-       depends on X86_64
+       depends on X86_64 && BROKEN
        ---help---
        Support for the Unisys SPAR drivers
 
index 431cff8..f950d6e 100644 (file)
@@ -83,7 +83,7 @@ struct any_request {
         * coarsest possible alignment boundary that could be required
         * for any user data structure.
         */
-       u8 caller_context_data[1] __aligned(sizeof(ulong2);
+       u8 caller_context_data[1] __aligned(sizeof(ulong2));
 };
 
 /*
index 8252ca1..257c6e5 100644 (file)
@@ -2414,6 +2414,9 @@ proc_read_installer(struct file *file, char __user *buf,
        char *vbuf;
        loff_t pos = *offset;
 
+       if (!ControlVm_channel)
+               return -ENODEV;
+
        if (pos < 0)
                return -EINVAL;
 
@@ -2463,6 +2466,9 @@ proc_write_installer(struct file *file,
        U16 remainingSteps;
        U32 error, textId;
 
+       if (!ControlVm_channel)
+               return -ENODEV;
+
        /* Check to make sure there is no buffer overflow */
        if (count > (sizeof(buf) - 1))
                return -EINVAL;
@@ -2524,6 +2530,9 @@ proc_read_toolaction(struct file *file, char __user *buf,
        char *vbuf;
        loff_t pos = *offset;
 
+       if (!ControlVm_channel)
+               return -ENODEV;
+
        if (pos < 0)
                return -EINVAL;
 
@@ -2562,6 +2571,9 @@ proc_write_toolaction(struct file *file,
        char buf[3];
        U8 toolAction;
 
+       if (!ControlVm_channel)
+               return -ENODEV;
+
        /* Check to make sure there is no buffer overflow */
        if (count > (sizeof(buf) - 1))
                return -EINVAL;
@@ -2601,6 +2613,9 @@ proc_read_bootToTool(struct file *file, char __user *buf,
        char *vbuf;
        loff_t pos = *offset;
 
+       if (!ControlVm_channel)
+               return -ENODEV;
+
        if (pos < 0)
                return -EINVAL;
 
@@ -2639,6 +2654,9 @@ proc_write_bootToTool(struct file *file,
        int inputVal;
        ULTRA_EFI_SPAR_INDICATION efiSparIndication;
 
+       if (!ControlVm_channel)
+               return -ENODEV;
+
        /* Check to make sure there is no buffer overflow */
        if (count > (sizeof(buf) - 1))
                return -EINVAL;
index 45af765..a99c631 100644 (file)
@@ -62,12 +62,16 @@ enum imx_thermal_trip {
 #define IMX_POLLING_DELAY              2000 /* millisecond */
 #define IMX_PASSIVE_DELAY              1000
 
+#define FACTOR0                                10000000
+#define FACTOR1                                15976
+#define FACTOR2                                4297157
+
 struct imx_thermal_data {
        struct thermal_zone_device *tz;
        struct thermal_cooling_device *cdev;
        enum thermal_device_mode mode;
        struct regmap *tempmon;
-       int c1, c2; /* See formula in imx_get_sensor_data() */
+       u32 c1, c2; /* See formula in imx_get_sensor_data() */
        unsigned long temp_passive;
        unsigned long temp_critical;
        unsigned long alarm_temp;
@@ -84,7 +88,7 @@ static void imx_set_alarm_temp(struct imx_thermal_data *data,
        int alarm_value;
 
        data->alarm_temp = alarm_temp;
-       alarm_value = (alarm_temp - data->c2) / data->c1;
+       alarm_value = (data->c2 - alarm_temp) / data->c1;
        regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_ALARM_VALUE_MASK);
        regmap_write(map, TEMPSENSE0 + REG_SET, alarm_value <<
                        TEMPSENSE0_ALARM_VALUE_SHIFT);
@@ -136,7 +140,7 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
        n_meas = (val & TEMPSENSE0_TEMP_CNT_MASK) >> TEMPSENSE0_TEMP_CNT_SHIFT;
 
        /* See imx_get_sensor_data() for formula derivation */
-       *temp = data->c2 + data->c1 * n_meas;
+       *temp = data->c2 - n_meas * data->c1;
 
        /* Update alarm value to next higher trip point */
        if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive)
@@ -305,6 +309,7 @@ static int imx_get_sensor_data(struct platform_device *pdev)
        int t1, t2, n1, n2;
        int ret;
        u32 val;
+       u64 temp64;
 
        map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
                                              "fsl,tempmon-data");
@@ -330,6 +335,8 @@ static int imx_get_sensor_data(struct platform_device *pdev)
         *   [31:20] - sensor value @ 25C
         *    [19:8] - sensor value of hot
         *     [7:0] - hot temperature value
+        * Use universal formula now and only need sensor value @ 25C
+        * slope = 0.4297157 - (0.0015976 * 25C fuse)
         */
        n1 = val >> 20;
        n2 = (val & 0xfff00) >> 8;
@@ -337,20 +344,26 @@ static int imx_get_sensor_data(struct platform_device *pdev)
        t1 = 25; /* t1 always 25C */
 
        /*
-        * Derived from linear interpolation,
-        * Tmeas = T2 + (Nmeas - N2) * (T1 - T2) / (N1 - N2)
+        * Derived from linear interpolation:
+        * slope = 0.4297157 - (0.0015976 * 25C fuse)
+        * slope = (FACTOR2 - FACTOR1 * n1) / FACTOR0
+        * (Nmeas - n1) / (Tmeas - t1) = slope
         * We want to reduce this down to the minimum computation necessary
         * for each temperature read.  Also, we want Tmeas in millicelsius
         * and we don't want to lose precision from integer division. So...
-        * milli_Tmeas = 1000 * T2 + 1000 * (Nmeas - N2) * (T1 - T2) / (N1 - N2)
-        * Let constant c1 = 1000 * (T1 - T2) / (N1 - N2)
-        * milli_Tmeas = (1000 * T2) + c1 * (Nmeas - N2)
-        * milli_Tmeas = (1000 * T2) + (c1 * Nmeas) - (c1 * N2)
-        * Let constant c2 = (1000 * T2) - (c1 * N2)
-        * milli_Tmeas = c2 + (c1 * Nmeas)
+        * Tmeas = (Nmeas - n1) / slope + t1
+        * milli_Tmeas = 1000 * (Nmeas - n1) / slope + 1000 * t1
+        * milli_Tmeas = -1000 * (n1 - Nmeas) / slope + 1000 * t1
+        * Let constant c1 = (-1000 / slope)
+        * milli_Tmeas = (n1 - Nmeas) * c1 + 1000 * t1
+        * Let constant c2 = n1 *c1 + 1000 * t1
+        * milli_Tmeas = c2 - Nmeas * c1
         */
-       data->c1 = 1000 * (t1 - t2) / (n1 - n2);
-       data->c2 = 1000 * t2 - data->c1 * n2;
+       temp64 = FACTOR0;
+       temp64 *= 1000;
+       do_div(temp64, FACTOR1 * n1 - FACTOR2);
+       data->c1 = temp64;
+       data->c2 = n1 * data->c1 + 1000 * t1;
 
        /*
         * Set the default passive cooling trip point to 20 °C below the
index 79a09d0..5a37940 100644 (file)
@@ -299,12 +299,17 @@ static void _rcar_thermal_irq_ctrl(struct rcar_thermal_priv *priv, int enable)
 static void rcar_thermal_work(struct work_struct *work)
 {
        struct rcar_thermal_priv *priv;
+       unsigned long cctemp, nctemp;
 
        priv = container_of(work, struct rcar_thermal_priv, work.work);
 
+       rcar_thermal_get_temp(priv->zone, &cctemp);
        rcar_thermal_update_temp(priv);
        rcar_thermal_irq_enable(priv);
-       thermal_zone_device_update(priv->zone);
+
+       rcar_thermal_get_temp(priv->zone, &nctemp);
+       if (nctemp != cctemp)
+               thermal_zone_device_update(priv->zone);
 }
 
 static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
@@ -313,7 +318,7 @@ static u32 rcar_thermal_had_changed(struct rcar_thermal_priv *priv, u32 status)
 
        status = (status >> rcar_id_to_shift(priv)) & 0x3;
 
-       if (status & 0x3) {
+       if (status) {
                dev_dbg(dev, "thermal%d %s%s\n",
                        priv->id,
                        (status & 0x2) ? "Rising " : "",
index 74c0e34..3ab12ee 100644 (file)
@@ -1500,10 +1500,8 @@ static int ti_bandgap_resume(struct device *dev)
 
        return ti_bandgap_restore_ctxt(bgp);
 }
-static const struct dev_pm_ops ti_bandgap_dev_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(ti_bandgap_suspend,
-                               ti_bandgap_resume)
-};
+static SIMPLE_DEV_PM_OPS(ti_bandgap_dev_pm_ops, ti_bandgap_suspend,
+                        ti_bandgap_resume);
 
 #define DEV_PM_OPS     (&ti_bandgap_dev_pm_ops)
 #else
index 081fd7e..9ea3d9d 100644 (file)
@@ -590,12 +590,12 @@ static int __init pkg_temp_thermal_init(void)
        platform_thermal_package_rate_control =
                        pkg_temp_thermal_platform_thermal_rate_control;
 
-       get_online_cpus();
+       cpu_notifier_register_begin();
        for_each_online_cpu(i)
                if (get_core_online(i))
                        goto err_ret;
-       register_hotcpu_notifier(&pkg_temp_thermal_notifier);
-       put_online_cpus();
+       __register_hotcpu_notifier(&pkg_temp_thermal_notifier);
+       cpu_notifier_register_done();
 
        pkg_temp_debugfs_init(); /* Don't care if fails */
 
@@ -604,7 +604,7 @@ static int __init pkg_temp_thermal_init(void)
 err_ret:
        for_each_online_cpu(i)
                put_core_offline(i);
-       put_online_cpus();
+       cpu_notifier_register_done();
        kfree(pkg_work_scheduled);
        platform_thermal_package_notify = NULL;
        platform_thermal_package_rate_control = NULL;
@@ -617,8 +617,8 @@ static void __exit pkg_temp_thermal_exit(void)
        struct phy_dev_entry *phdev, *n;
        int i;
 
-       get_online_cpus();
-       unregister_hotcpu_notifier(&pkg_temp_thermal_notifier);
+       cpu_notifier_register_begin();
+       __unregister_hotcpu_notifier(&pkg_temp_thermal_notifier);
        mutex_lock(&phy_dev_list_mutex);
        list_for_each_entry_safe(phdev, n, &phy_dev_list, list) {
                /* Retore old MSR value for package thermal interrupt */
@@ -636,7 +636,7 @@ static void __exit pkg_temp_thermal_exit(void)
        for_each_online_cpu(i)
                cancel_delayed_work_sync(
                        &per_cpu(pkg_temp_thermal_threshold_work, i));
-       put_online_cpus();
+       cpu_notifier_register_done();
 
        kfree(pkg_work_scheduled);
 
index b01659b..a585079 100644 (file)
@@ -61,6 +61,7 @@ static struct hvc_opal_priv *hvc_opal_privs[MAX_NR_HVC_CONSOLES];
 /* For early boot console */
 static struct hvc_opal_priv hvc_opal_boot_priv;
 static u32 hvc_opal_boot_termno;
+static bool hvc_opal_event_registered;
 
 static const struct hv_ops hvc_opal_raw_ops = {
        .get_chars = opal_get_chars,
@@ -161,6 +162,18 @@ static const struct hv_ops hvc_opal_hvsi_ops = {
        .tiocmset = hvc_opal_hvsi_tiocmset,
 };
 
+static int hvc_opal_console_event(struct notifier_block *nb,
+                                 unsigned long events, void *change)
+{
+       if (events & OPAL_EVENT_CONSOLE_INPUT)
+               hvc_kick();
+       return 0;
+}
+
+static struct notifier_block hvc_opal_console_nb = {
+       .notifier_call  = hvc_opal_console_event,
+};
+
 static int hvc_opal_probe(struct platform_device *dev)
 {
        const struct hv_ops *ops;
@@ -170,6 +183,7 @@ static int hvc_opal_probe(struct platform_device *dev)
        unsigned int termno, boot = 0;
        const __be32 *reg;
 
+
        if (of_device_is_compatible(dev->dev.of_node, "ibm,opal-console-raw")) {
                proto = HV_PROTOCOL_RAW;
                ops = &hvc_opal_raw_ops;
@@ -213,12 +227,18 @@ static int hvc_opal_probe(struct platform_device *dev)
                dev->dev.of_node->full_name,
                boot ? " (boot console)" : "");
 
-       /* We don't do IRQ yet */
+       /* We don't do IRQ ... */
        hp = hvc_alloc(termno, 0, ops, MAX_VIO_PUT_CHARS);
        if (IS_ERR(hp))
                return PTR_ERR(hp);
        dev_set_drvdata(&dev->dev, hp);
 
+       /* ...  but we use OPAL event to kick the console */
+       if (!hvc_opal_event_registered) {
+               opal_notifier_register(&hvc_opal_console_nb);
+               hvc_opal_event_registered = true;
+       }
+
        return 0;
 }
 
index 27d3cf2..bd2172c 100644 (file)
@@ -347,7 +347,7 @@ struct backlight_device *backlight_device_register(const char *name,
 
        rc = device_register(&new_bd->dev);
        if (rc) {
-               kfree(new_bd);
+               put_device(&new_bd->dev);
                return ERR_PTR(rc);
        }
 
index 81fb127..a2eba12 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 #include <linux/platform_data/gpio_backlight.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
@@ -23,6 +25,7 @@ struct gpio_backlight {
 
        int gpio;
        int active;
+       int def_value;
 };
 
 static int gpio_backlight_update_status(struct backlight_device *bl)
@@ -60,6 +63,29 @@ static const struct backlight_ops gpio_backlight_ops = {
        .check_fb       = gpio_backlight_check_fb,
 };
 
+static int gpio_backlight_probe_dt(struct platform_device *pdev,
+                                  struct gpio_backlight *gbl)
+{
+       struct device_node *np = pdev->dev.of_node;
+       enum of_gpio_flags gpio_flags;
+
+       gbl->gpio = of_get_gpio_flags(np, 0, &gpio_flags);
+
+       if (!gpio_is_valid(gbl->gpio)) {
+               if (gbl->gpio != -EPROBE_DEFER) {
+                       dev_err(&pdev->dev,
+                               "Error: The gpios parameter is missing or invalid.\n");
+               }
+               return gbl->gpio;
+       }
+
+       gbl->active = (gpio_flags & OF_GPIO_ACTIVE_LOW) ? 0 : 1;
+
+       gbl->def_value = of_property_read_bool(np, "default-on");
+
+       return 0;
+}
+
 static int gpio_backlight_probe(struct platform_device *pdev)
 {
        struct gpio_backlight_platform_data *pdata =
@@ -67,10 +93,12 @@ static int gpio_backlight_probe(struct platform_device *pdev)
        struct backlight_properties props;
        struct backlight_device *bl;
        struct gpio_backlight *gbl;
+       struct device_node *np = pdev->dev.of_node;
        int ret;
 
-       if (!pdata) {
-               dev_err(&pdev->dev, "failed to find platform data\n");
+       if (!pdata && !np) {
+               dev_err(&pdev->dev,
+                       "failed to find platform data or device tree node.\n");
                return -ENODEV;
        }
 
@@ -79,14 +107,22 @@ static int gpio_backlight_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        gbl->dev = &pdev->dev;
-       gbl->fbdev = pdata->fbdev;
-       gbl->gpio = pdata->gpio;
-       gbl->active = pdata->active_low ? 0 : 1;
+
+       if (np) {
+               ret = gpio_backlight_probe_dt(pdev, gbl);
+               if (ret)
+                       return ret;
+       } else {
+               gbl->fbdev = pdata->fbdev;
+               gbl->gpio = pdata->gpio;
+               gbl->active = pdata->active_low ? 0 : 1;
+               gbl->def_value = pdata->def_value;
+       }
 
        ret = devm_gpio_request_one(gbl->dev, gbl->gpio, GPIOF_DIR_OUT |
                                    (gbl->active ? GPIOF_INIT_LOW
                                                 : GPIOF_INIT_HIGH),
-                                   pdata->name);
+                                   pdata ? pdata->name : "backlight");
        if (ret < 0) {
                dev_err(&pdev->dev, "unable to request GPIO\n");
                return ret;
@@ -103,17 +139,25 @@ static int gpio_backlight_probe(struct platform_device *pdev)
                return PTR_ERR(bl);
        }
 
-       bl->props.brightness = pdata->def_value;
+       bl->props.brightness = gbl->def_value;
        backlight_update_status(bl);
 
        platform_set_drvdata(pdev, bl);
        return 0;
 }
 
+#ifdef CONFIG_OF
+static struct of_device_id gpio_backlight_of_match[] = {
+       { .compatible = "gpio-backlight" },
+       { /* sentinel */ }
+};
+#endif
+
 static struct platform_driver gpio_backlight_driver = {
        .driver         = {
                .name           = "gpio-backlight",
                .owner          = THIS_MODULE,
+               .of_match_table = of_match_ptr(gpio_backlight_of_match),
        },
        .probe          = gpio_backlight_probe,
 };
index 6fd60ad..5f36808 100644 (file)
@@ -349,8 +349,9 @@ static int lm3639_probe(struct i2c_client *client,
        props.brightness = pdata->init_brt_led;
        props.max_brightness = pdata->max_brt_led;
        pchip->bled =
-           backlight_device_register("lm3639_bled", pchip->dev, pchip,
-                                     &lm3639_bled_ops, &props);
+           devm_backlight_device_register(pchip->dev, "lm3639_bled",
+                                          pchip->dev, pchip, &lm3639_bled_ops,
+                                          &props);
        if (IS_ERR(pchip->bled)) {
                dev_err(&client->dev, "fail : backlight register\n");
                ret = PTR_ERR(pchip->bled);
@@ -360,7 +361,7 @@ static int lm3639_probe(struct i2c_client *client,
        ret = device_create_file(&(pchip->bled->dev), &dev_attr_bled_mode);
        if (ret < 0) {
                dev_err(&client->dev, "failed : add sysfs entries\n");
-               goto err_bled_mode;
+               goto err_out;
        }
 
        /* flash */
@@ -391,8 +392,6 @@ err_torch:
        led_classdev_unregister(&pchip->cdev_flash);
 err_flash:
        device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
-err_bled_mode:
-       backlight_device_unregister(pchip->bled);
 err_out:
        return ret;
 }
@@ -407,10 +406,8 @@ static int lm3639_remove(struct i2c_client *client)
                led_classdev_unregister(&pchip->cdev_torch);
        if (&pchip->cdev_flash)
                led_classdev_unregister(&pchip->cdev_flash);
-       if (pchip->bled) {
+       if (pchip->bled)
                device_remove_file(&(pchip->bled->dev), &dev_attr_bled_mode);
-               backlight_device_unregister(pchip->bled);
-       }
        return 0;
 }
 
@@ -432,6 +429,6 @@ static struct i2c_driver lm3639_i2c_driver = {
 module_i2c_driver(lm3639_i2c_driver);
 
 MODULE_DESCRIPTION("Texas Instruments Backlight+Flash LED driver for LM3639");
-MODULE_AUTHOR("Daniel Jeong <daniel.jeong@ti.com>");
-MODULE_AUTHOR("G.Shark Jeong <gshark.jeong@gmail.com>");
+MODULE_AUTHOR("Daniel Jeong <gshark.jeong@gmail.com>");
+MODULE_AUTHOR("Ldd Mlp <ldd-mlp@list.ti.com>");
 MODULE_LICENSE("GPL v2");
index eb6f2b0..fcf2d48 100644 (file)
@@ -29,11 +29,4 @@ config EXYNOS_LCD_S6E8AX0
          If you have an S6E8AX0 MIPI AMOLED LCD Panel, say Y to enable its
          LCD control driver.
 
-config EXYNOS_DP
-       bool "EXYNOS DP driver support"
-       depends on ARCH_EXYNOS
-       default n
-       help
-         This enables support for DP device.
-
 endif # EXYNOS_VIDEO
index ec7772e..b5b1bd2 100644 (file)
@@ -5,4 +5,3 @@
 obj-$(CONFIG_EXYNOS_MIPI_DSI)          += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
                                        exynos_mipi_dsi_lowlevel.o
 obj-$(CONFIG_EXYNOS_LCD_S6E8AX0)       += s6e8ax0.o
-obj-$(CONFIG_EXYNOS_DP)                        += exynos_dp_core.o exynos_dp_reg.o
diff --git a/drivers/video/exynos/exynos_dp_core.c b/drivers/video/exynos/exynos_dp_core.c
deleted file mode 100644 (file)
index 5e1a715..0000000
+++ /dev/null
@@ -1,1156 +0,0 @@
-/*
- * Samsung SoC DP (Display Port) interface driver.
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/slab.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/of.h>
-#include <linux/phy/phy.h>
-
-#include "exynos_dp_core.h"
-
-static int exynos_dp_init_dp(struct exynos_dp_device *dp)
-{
-       exynos_dp_reset(dp);
-
-       exynos_dp_swreset(dp);
-
-       exynos_dp_init_analog_param(dp);
-       exynos_dp_init_interrupt(dp);
-
-       /* SW defined function Normal operation */
-       exynos_dp_enable_sw_function(dp);
-
-       exynos_dp_config_interrupt(dp);
-       exynos_dp_init_analog_func(dp);
-
-       exynos_dp_init_hpd(dp);
-       exynos_dp_init_aux(dp);
-
-       return 0;
-}
-
-static int exynos_dp_detect_hpd(struct exynos_dp_device *dp)
-{
-       int timeout_loop = 0;
-
-       while (exynos_dp_get_plug_in_status(dp) != 0) {
-               timeout_loop++;
-               if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-                       dev_err(dp->dev, "failed to get hpd plug status\n");
-                       return -ETIMEDOUT;
-               }
-               usleep_range(10, 11);
-       }
-
-       return 0;
-}
-
-static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data)
-{
-       int i;
-       unsigned char sum = 0;
-
-       for (i = 0; i < EDID_BLOCK_LENGTH; i++)
-               sum = sum + edid_data[i];
-
-       return sum;
-}
-
-static int exynos_dp_read_edid(struct exynos_dp_device *dp)
-{
-       unsigned char edid[EDID_BLOCK_LENGTH * 2];
-       unsigned int extend_block = 0;
-       unsigned char sum;
-       unsigned char test_vector;
-       int retval;
-
-       /*
-        * EDID device address is 0x50.
-        * However, if necessary, you must have set upper address
-        * into E-EDID in I2C device, 0x30.
-        */
-
-       /* Read Extension Flag, Number of 128-byte EDID extension blocks */
-       retval = exynos_dp_read_byte_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-                               EDID_EXTENSION_FLAG,
-                               &extend_block);
-       if (retval)
-               return retval;
-
-       if (extend_block > 0) {
-               dev_dbg(dp->dev, "EDID data includes a single extension!\n");
-
-               /* Read EDID data */
-               retval = exynos_dp_read_bytes_from_i2c(dp, I2C_EDID_DEVICE_ADDR,
-                                               EDID_HEADER_PATTERN,
-                                               EDID_BLOCK_LENGTH,
-                                               &edid[EDID_HEADER_PATTERN]);
-               if (retval != 0) {
-                       dev_err(dp->dev, "EDID Read failed!\n");
-                       return -EIO;
-               }
-               sum = exynos_dp_calc_edid_check_sum(edid);
-               if (sum != 0) {
-                       dev_err(dp->dev, "EDID bad checksum!\n");
-                       return -EIO;
-               }
-
-               /* Read additional EDID data */
-               retval = exynos_dp_read_bytes_from_i2c(dp,
-                               I2C_EDID_DEVICE_ADDR,
-                               EDID_BLOCK_LENGTH,
-                               EDID_BLOCK_LENGTH,
-                               &edid[EDID_BLOCK_LENGTH]);
-               if (retval != 0) {
-                       dev_err(dp->dev, "EDID Read failed!\n");
-                       return -EIO;
-               }
-               sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]);
-               if (sum != 0) {
-                       dev_err(dp->dev, "EDID bad checksum!\n");
-                       return -EIO;
-               }
-
-               exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_TEST_REQUEST,
-                                       &test_vector);
-               if (test_vector & DPCD_TEST_EDID_READ) {
-                       exynos_dp_write_byte_to_dpcd(dp,
-                               DPCD_ADDR_TEST_EDID_CHECKSUM,
-                               edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]);
-                       exynos_dp_write_byte_to_dpcd(dp,
-                               DPCD_ADDR_TEST_RESPONSE,
-                               DPCD_TEST_EDID_CHECKSUM_WRITE);
-               }
-       } else {
-               dev_info(dp->dev, "EDID data does not include any extensions.\n");
-
-               /* Read EDID data */
-               retval = exynos_dp_read_bytes_from_i2c(dp,
-                               I2C_EDID_DEVICE_ADDR,
-                               EDID_HEADER_PATTERN,
-                               EDID_BLOCK_LENGTH,
-                               &edid[EDID_HEADER_PATTERN]);
-               if (retval != 0) {
-                       dev_err(dp->dev, "EDID Read failed!\n");
-                       return -EIO;
-               }
-               sum = exynos_dp_calc_edid_check_sum(edid);
-               if (sum != 0) {
-                       dev_err(dp->dev, "EDID bad checksum!\n");
-                       return -EIO;
-               }
-
-               exynos_dp_read_byte_from_dpcd(dp,
-                       DPCD_ADDR_TEST_REQUEST,
-                       &test_vector);
-               if (test_vector & DPCD_TEST_EDID_READ) {
-                       exynos_dp_write_byte_to_dpcd(dp,
-                               DPCD_ADDR_TEST_EDID_CHECKSUM,
-                               edid[EDID_CHECKSUM]);
-                       exynos_dp_write_byte_to_dpcd(dp,
-                               DPCD_ADDR_TEST_RESPONSE,
-                               DPCD_TEST_EDID_CHECKSUM_WRITE);
-               }
-       }
-
-       dev_err(dp->dev, "EDID Read success!\n");
-       return 0;
-}
-
-static int exynos_dp_handle_edid(struct exynos_dp_device *dp)
-{
-       u8 buf[12];
-       int i;
-       int retval;
-
-       /* Read DPCD DPCD_ADDR_DPCD_REV~RECEIVE_PORT1_CAP_1 */
-       retval = exynos_dp_read_bytes_from_dpcd(dp, DPCD_ADDR_DPCD_REV,
-                               12, buf);
-       if (retval)
-               return retval;
-
-       /* Read EDID */
-       for (i = 0; i < 3; i++) {
-               retval = exynos_dp_read_edid(dp);
-               if (!retval)
-                       break;
-       }
-
-       return retval;
-}
-
-static void exynos_dp_enable_rx_to_enhanced_mode(struct exynos_dp_device *dp,
-                                               bool enable)
-{
-       u8 data;
-
-       exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET, &data);
-
-       if (enable)
-               exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
-                       DPCD_ENHANCED_FRAME_EN |
-                       DPCD_LANE_COUNT_SET(data));
-       else
-               exynos_dp_write_byte_to_dpcd(dp, DPCD_ADDR_LANE_COUNT_SET,
-                       DPCD_LANE_COUNT_SET(data));
-}
-
-static int exynos_dp_is_enhanced_mode_available(struct exynos_dp_device *dp)
-{
-       u8 data;
-       int retval;
-
-       exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
-       retval = DPCD_ENHANCED_FRAME_CAP(data);
-
-       return retval;
-}
-
-static void exynos_dp_set_enhanced_mode(struct exynos_dp_device *dp)
-{
-       u8 data;
-
-       data = exynos_dp_is_enhanced_mode_available(dp);
-       exynos_dp_enable_rx_to_enhanced_mode(dp, data);
-       exynos_dp_enable_enhanced_mode(dp, data);
-}
-
-static void exynos_dp_training_pattern_dis(struct exynos_dp_device *dp)
-{
-       exynos_dp_set_training_pattern(dp, DP_NONE);
-
-       exynos_dp_write_byte_to_dpcd(dp,
-               DPCD_ADDR_TRAINING_PATTERN_SET,
-               DPCD_TRAINING_PATTERN_DISABLED);
-}
-
-static void exynos_dp_set_lane_lane_pre_emphasis(struct exynos_dp_device *dp,
-                                       int pre_emphasis, int lane)
-{
-       switch (lane) {
-       case 0:
-               exynos_dp_set_lane0_pre_emphasis(dp, pre_emphasis);
-               break;
-       case 1:
-               exynos_dp_set_lane1_pre_emphasis(dp, pre_emphasis);
-               break;
-
-       case 2:
-               exynos_dp_set_lane2_pre_emphasis(dp, pre_emphasis);
-               break;
-
-       case 3:
-               exynos_dp_set_lane3_pre_emphasis(dp, pre_emphasis);
-               break;
-       }
-}
-
-static int exynos_dp_link_start(struct exynos_dp_device *dp)
-{
-       u8 buf[4];
-       int lane, lane_count, pll_tries, retval;
-
-       lane_count = dp->link_train.lane_count;
-
-       dp->link_train.lt_state = CLOCK_RECOVERY;
-       dp->link_train.eq_loop = 0;
-
-       for (lane = 0; lane < lane_count; lane++)
-               dp->link_train.cr_loop[lane] = 0;
-
-       /* Set link rate and count as you want to establish*/
-       exynos_dp_set_link_bandwidth(dp, dp->link_train.link_rate);
-       exynos_dp_set_lane_count(dp, dp->link_train.lane_count);
-
-       /* Setup RX configuration */
-       buf[0] = dp->link_train.link_rate;
-       buf[1] = dp->link_train.lane_count;
-       retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_LINK_BW_SET,
-                               2, buf);
-       if (retval)
-               return retval;
-
-       /* Set TX pre-emphasis to minimum */
-       for (lane = 0; lane < lane_count; lane++)
-               exynos_dp_set_lane_lane_pre_emphasis(dp,
-                       PRE_EMPHASIS_LEVEL_0, lane);
-
-       /* Wait for PLL lock */
-       pll_tries = 0;
-       while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-               if (pll_tries == DP_TIMEOUT_LOOP_COUNT) {
-                       dev_err(dp->dev, "Wait for PLL lock timed out\n");
-                       return -ETIMEDOUT;
-               }
-
-               pll_tries++;
-               usleep_range(90, 120);
-       }
-
-       /* Set training pattern 1 */
-       exynos_dp_set_training_pattern(dp, TRAINING_PTN1);
-
-       /* Set RX training pattern */
-       retval = exynos_dp_write_byte_to_dpcd(dp,
-                       DPCD_ADDR_TRAINING_PATTERN_SET,
-                       DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1);
-       if (retval)
-               return retval;
-
-       for (lane = 0; lane < lane_count; lane++)
-               buf[lane] = DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0 |
-                           DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0;
-
-       retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
-                       lane_count, buf);
-
-       return retval;
-}
-
-static unsigned char exynos_dp_get_lane_status(u8 link_status[2], int lane)
-{
-       int shift = (lane & 1) * 4;
-       u8 link_value = link_status[lane>>1];
-
-       return (link_value >> shift) & 0xf;
-}
-
-static int exynos_dp_clock_recovery_ok(u8 link_status[2], int lane_count)
-{
-       int lane;
-       u8 lane_status;
-
-       for (lane = 0; lane < lane_count; lane++) {
-               lane_status = exynos_dp_get_lane_status(link_status, lane);
-               if ((lane_status & DPCD_LANE_CR_DONE) == 0)
-                       return -EINVAL;
-       }
-       return 0;
-}
-
-static int exynos_dp_channel_eq_ok(u8 link_status[2], u8 link_align,
-                               int lane_count)
-{
-       int lane;
-       u8 lane_status;
-
-       if ((link_align & DPCD_INTERLANE_ALIGN_DONE) == 0)
-               return -EINVAL;
-
-       for (lane = 0; lane < lane_count; lane++) {
-               lane_status = exynos_dp_get_lane_status(link_status, lane);
-               lane_status &= DPCD_CHANNEL_EQ_BITS;
-               if (lane_status != DPCD_CHANNEL_EQ_BITS)
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-static unsigned char exynos_dp_get_adjust_request_voltage(u8 adjust_request[2],
-                                                       int lane)
-{
-       int shift = (lane & 1) * 4;
-       u8 link_value = adjust_request[lane>>1];
-
-       return (link_value >> shift) & 0x3;
-}
-
-static unsigned char exynos_dp_get_adjust_request_pre_emphasis(
-                                       u8 adjust_request[2],
-                                       int lane)
-{
-       int shift = (lane & 1) * 4;
-       u8 link_value = adjust_request[lane>>1];
-
-       return ((link_value >> shift) & 0xc) >> 2;
-}
-
-static void exynos_dp_set_lane_link_training(struct exynos_dp_device *dp,
-                                       u8 training_lane_set, int lane)
-{
-       switch (lane) {
-       case 0:
-               exynos_dp_set_lane0_link_training(dp, training_lane_set);
-               break;
-       case 1:
-               exynos_dp_set_lane1_link_training(dp, training_lane_set);
-               break;
-
-       case 2:
-               exynos_dp_set_lane2_link_training(dp, training_lane_set);
-               break;
-
-       case 3:
-               exynos_dp_set_lane3_link_training(dp, training_lane_set);
-               break;
-       }
-}
-
-static unsigned int exynos_dp_get_lane_link_training(
-                               struct exynos_dp_device *dp,
-                               int lane)
-{
-       u32 reg;
-
-       switch (lane) {
-       case 0:
-               reg = exynos_dp_get_lane0_link_training(dp);
-               break;
-       case 1:
-               reg = exynos_dp_get_lane1_link_training(dp);
-               break;
-       case 2:
-               reg = exynos_dp_get_lane2_link_training(dp);
-               break;
-       case 3:
-               reg = exynos_dp_get_lane3_link_training(dp);
-               break;
-       default:
-               WARN_ON(1);
-               return 0;
-       }
-
-       return reg;
-}
-
-static void exynos_dp_reduce_link_rate(struct exynos_dp_device *dp)
-{
-       exynos_dp_training_pattern_dis(dp);
-       exynos_dp_set_enhanced_mode(dp);
-
-       dp->link_train.lt_state = FAILED;
-}
-
-static void exynos_dp_get_adjust_training_lane(struct exynos_dp_device *dp,
-                                       u8 adjust_request[2])
-{
-       int lane, lane_count;
-       u8 voltage_swing, pre_emphasis, training_lane;
-
-       lane_count = dp->link_train.lane_count;
-       for (lane = 0; lane < lane_count; lane++) {
-               voltage_swing = exynos_dp_get_adjust_request_voltage(
-                                               adjust_request, lane);
-               pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
-                                               adjust_request, lane);
-               training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
-                               DPCD_PRE_EMPHASIS_SET(pre_emphasis);
-
-               if (voltage_swing == VOLTAGE_LEVEL_3)
-                       training_lane |= DPCD_MAX_SWING_REACHED;
-               if (pre_emphasis == PRE_EMPHASIS_LEVEL_3)
-                       training_lane |= DPCD_MAX_PRE_EMPHASIS_REACHED;
-
-               dp->link_train.training_lane[lane] = training_lane;
-       }
-}
-
-static int exynos_dp_process_clock_recovery(struct exynos_dp_device *dp)
-{
-       int lane, lane_count, retval;
-       u8 voltage_swing, pre_emphasis, training_lane;
-       u8 link_status[2], adjust_request[2];
-
-       usleep_range(100, 101);
-
-       lane_count = dp->link_train.lane_count;
-
-       retval =  exynos_dp_read_bytes_from_dpcd(dp,
-                       DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
-       if (retval)
-               return retval;
-
-       retval =  exynos_dp_read_bytes_from_dpcd(dp,
-                       DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
-       if (retval)
-               return retval;
-
-       if (exynos_dp_clock_recovery_ok(link_status, lane_count) == 0) {
-               /* set training pattern 2 for EQ */
-               exynos_dp_set_training_pattern(dp, TRAINING_PTN2);
-
-               retval = exynos_dp_write_byte_to_dpcd(dp,
-                               DPCD_ADDR_TRAINING_PATTERN_SET,
-                               DPCD_SCRAMBLING_DISABLED |
-                               DPCD_TRAINING_PATTERN_2);
-               if (retval)
-                       return retval;
-
-               dev_info(dp->dev, "Link Training Clock Recovery success\n");
-               dp->link_train.lt_state = EQUALIZER_TRAINING;
-       } else {
-               for (lane = 0; lane < lane_count; lane++) {
-                       training_lane = exynos_dp_get_lane_link_training(
-                                                       dp, lane);
-                       voltage_swing = exynos_dp_get_adjust_request_voltage(
-                                                       adjust_request, lane);
-                       pre_emphasis = exynos_dp_get_adjust_request_pre_emphasis(
-                                                       adjust_request, lane);
-
-                       if (DPCD_VOLTAGE_SWING_GET(training_lane) ==
-                                       voltage_swing &&
-                           DPCD_PRE_EMPHASIS_GET(training_lane) ==
-                                       pre_emphasis)
-                               dp->link_train.cr_loop[lane]++;
-
-                       if (dp->link_train.cr_loop[lane] == MAX_CR_LOOP ||
-                           voltage_swing == VOLTAGE_LEVEL_3 ||
-                           pre_emphasis == PRE_EMPHASIS_LEVEL_3) {
-                               dev_err(dp->dev, "CR Max reached (%d,%d,%d)\n",
-                                       dp->link_train.cr_loop[lane],
-                                       voltage_swing, pre_emphasis);
-                               exynos_dp_reduce_link_rate(dp);
-                               return -EIO;
-                       }
-               }
-       }
-
-       exynos_dp_get_adjust_training_lane(dp, adjust_request);
-
-       for (lane = 0; lane < lane_count; lane++)
-               exynos_dp_set_lane_link_training(dp,
-                       dp->link_train.training_lane[lane], lane);
-
-       retval = exynos_dp_write_bytes_to_dpcd(dp,
-                       DPCD_ADDR_TRAINING_LANE0_SET, lane_count,
-                       dp->link_train.training_lane);
-       if (retval)
-               return retval;
-
-       return retval;
-}
-
-static int exynos_dp_process_equalizer_training(struct exynos_dp_device *dp)
-{
-       int lane, lane_count, retval;
-       u32 reg;
-       u8 link_align, link_status[2], adjust_request[2];
-
-       usleep_range(400, 401);
-
-       lane_count = dp->link_train.lane_count;
-
-       retval = exynos_dp_read_bytes_from_dpcd(dp,
-                       DPCD_ADDR_LANE0_1_STATUS, 2, link_status);
-       if (retval)
-               return retval;
-
-       if (exynos_dp_clock_recovery_ok(link_status, lane_count)) {
-               exynos_dp_reduce_link_rate(dp);
-               return -EIO;
-       }
-
-       retval = exynos_dp_read_bytes_from_dpcd(dp,
-                       DPCD_ADDR_ADJUST_REQUEST_LANE0_1, 2, adjust_request);
-       if (retval)
-               return retval;
-
-       retval = exynos_dp_read_byte_from_dpcd(dp,
-                       DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED, &link_align);
-       if (retval)
-               return retval;
-
-       exynos_dp_get_adjust_training_lane(dp, adjust_request);
-
-       if (!exynos_dp_channel_eq_ok(link_status, link_align, lane_count)) {
-               /* traing pattern Set to Normal */
-               exynos_dp_training_pattern_dis(dp);
-
-               dev_info(dp->dev, "Link Training success!\n");
-
-               exynos_dp_get_link_bandwidth(dp, &reg);
-               dp->link_train.link_rate = reg;
-               dev_dbg(dp->dev, "final bandwidth = %.2x\n",
-                       dp->link_train.link_rate);
-
-               exynos_dp_get_lane_count(dp, &reg);
-               dp->link_train.lane_count = reg;
-               dev_dbg(dp->dev, "final lane count = %.2x\n",
-                       dp->link_train.lane_count);
-
-               /* set enhanced mode if available */
-               exynos_dp_set_enhanced_mode(dp);
-               dp->link_train.lt_state = FINISHED;
-
-               return 0;
-       }
-
-       /* not all locked */
-       dp->link_train.eq_loop++;
-
-       if (dp->link_train.eq_loop > MAX_EQ_LOOP) {
-               dev_err(dp->dev, "EQ Max loop\n");
-               exynos_dp_reduce_link_rate(dp);
-               return -EIO;
-       }
-
-       for (lane = 0; lane < lane_count; lane++)
-               exynos_dp_set_lane_link_training(dp,
-                       dp->link_train.training_lane[lane], lane);
-
-       retval = exynos_dp_write_bytes_to_dpcd(dp, DPCD_ADDR_TRAINING_LANE0_SET,
-                       lane_count, dp->link_train.training_lane);
-
-       return retval;
-}
-
-static void exynos_dp_get_max_rx_bandwidth(struct exynos_dp_device *dp,
-                                       u8 *bandwidth)
-{
-       u8 data;
-
-       /*
-        * For DP rev.1.1, Maximum link rate of Main Link lanes
-        * 0x06 = 1.62 Gbps, 0x0a = 2.7 Gbps
-        */
-       exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LINK_RATE, &data);
-       *bandwidth = data;
-}
-
-static void exynos_dp_get_max_rx_lane_count(struct exynos_dp_device *dp,
-                                       u8 *lane_count)
-{
-       u8 data;
-
-       /*
-        * For DP rev.1.1, Maximum number of Main Link lanes
-        * 0x01 = 1 lane, 0x02 = 2 lanes, 0x04 = 4 lanes
-        */
-       exynos_dp_read_byte_from_dpcd(dp, DPCD_ADDR_MAX_LANE_COUNT, &data);
-       *lane_count = DPCD_MAX_LANE_COUNT(data);
-}
-
-static void exynos_dp_init_training(struct exynos_dp_device *dp,
-                       enum link_lane_count_type max_lane,
-                       enum link_rate_type max_rate)
-{
-       /*
-        * MACRO_RST must be applied after the PLL_LOCK to avoid
-        * the DP inter pair skew issue for at least 10 us
-        */
-       exynos_dp_reset_macro(dp);
-
-       /* Initialize by reading RX's DPCD */
-       exynos_dp_get_max_rx_bandwidth(dp, &dp->link_train.link_rate);
-       exynos_dp_get_max_rx_lane_count(dp, &dp->link_train.lane_count);
-
-       if ((dp->link_train.link_rate != LINK_RATE_1_62GBPS) &&
-          (dp->link_train.link_rate != LINK_RATE_2_70GBPS)) {
-               dev_err(dp->dev, "Rx Max Link Rate is abnormal :%x !\n",
-                       dp->link_train.link_rate);
-               dp->link_train.link_rate = LINK_RATE_1_62GBPS;
-       }
-
-       if (dp->link_train.lane_count == 0) {
-               dev_err(dp->dev, "Rx Max Lane count is abnormal :%x !\n",
-                       dp->link_train.lane_count);
-               dp->link_train.lane_count = (u8)LANE_COUNT1;
-       }
-
-       /* Setup TX lane count & rate */
-       if (dp->link_train.lane_count > max_lane)
-               dp->link_train.lane_count = max_lane;
-       if (dp->link_train.link_rate > max_rate)
-               dp->link_train.link_rate = max_rate;
-
-       /* All DP analog module power up */
-       exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
-}
-
-static int exynos_dp_sw_link_training(struct exynos_dp_device *dp)
-{
-       int retval = 0, training_finished = 0;
-
-       dp->link_train.lt_state = START;
-
-       /* Process here */
-       while (!retval && !training_finished) {
-               switch (dp->link_train.lt_state) {
-               case START:
-                       retval = exynos_dp_link_start(dp);
-                       if (retval)
-                               dev_err(dp->dev, "LT link start failed!\n");
-                       break;
-               case CLOCK_RECOVERY:
-                       retval = exynos_dp_process_clock_recovery(dp);
-                       if (retval)
-                               dev_err(dp->dev, "LT CR failed!\n");
-                       break;
-               case EQUALIZER_TRAINING:
-                       retval = exynos_dp_process_equalizer_training(dp);
-                       if (retval)
-                               dev_err(dp->dev, "LT EQ failed!\n");
-                       break;
-               case FINISHED:
-                       training_finished = 1;
-                       break;
-               case FAILED:
-                       return -EREMOTEIO;
-               }
-       }
-       if (retval)
-               dev_err(dp->dev, "eDP link training failed (%d)\n", retval);
-
-       return retval;
-}
-
-static int exynos_dp_set_link_train(struct exynos_dp_device *dp,
-                               u32 count,
-                               u32 bwtype)
-{
-       int i;
-       int retval;
-
-       for (i = 0; i < DP_TIMEOUT_LOOP_COUNT; i++) {
-               exynos_dp_init_training(dp, count, bwtype);
-               retval = exynos_dp_sw_link_training(dp);
-               if (retval == 0)
-                       break;
-
-               usleep_range(100, 110);
-       }
-
-       return retval;
-}
-
-static int exynos_dp_config_video(struct exynos_dp_device *dp)
-{
-       int retval = 0;
-       int timeout_loop = 0;
-       int done_count = 0;
-
-       exynos_dp_config_video_slave_mode(dp);
-
-       exynos_dp_set_video_color_format(dp);
-
-       if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-               dev_err(dp->dev, "PLL is not locked yet.\n");
-               return -EINVAL;
-       }
-
-       for (;;) {
-               timeout_loop++;
-               if (exynos_dp_is_slave_video_stream_clock_on(dp) == 0)
-                       break;
-               if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-                       dev_err(dp->dev, "Timeout of video streamclk ok\n");
-                       return -ETIMEDOUT;
-               }
-
-               usleep_range(1, 2);
-       }
-
-       /* Set to use the register calculated M/N video */
-       exynos_dp_set_video_cr_mn(dp, CALCULATED_M, 0, 0);
-
-       /* For video bist, Video timing must be generated by register */
-       exynos_dp_set_video_timing_mode(dp, VIDEO_TIMING_FROM_CAPTURE);
-
-       /* Disable video mute */
-       exynos_dp_enable_video_mute(dp, 0);
-
-       /* Configure video slave mode */
-       exynos_dp_enable_video_master(dp, 0);
-
-       /* Enable video */
-       exynos_dp_start_video(dp);
-
-       timeout_loop = 0;
-
-       for (;;) {
-               timeout_loop++;
-               if (exynos_dp_is_video_stream_on(dp) == 0) {
-                       done_count++;
-                       if (done_count > 10)
-                               break;
-               } else if (done_count) {
-                       done_count = 0;
-               }
-               if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-                       dev_err(dp->dev, "Timeout of video streamclk ok\n");
-                       return -ETIMEDOUT;
-               }
-
-               usleep_range(1000, 1001);
-       }
-
-       if (retval != 0)
-               dev_err(dp->dev, "Video stream is not detected!\n");
-
-       return retval;
-}
-
-static void exynos_dp_enable_scramble(struct exynos_dp_device *dp, bool enable)
-{
-       u8 data;
-
-       if (enable) {
-               exynos_dp_enable_scrambling(dp);
-
-               exynos_dp_read_byte_from_dpcd(dp,
-                       DPCD_ADDR_TRAINING_PATTERN_SET,
-                       &data);
-               exynos_dp_write_byte_to_dpcd(dp,
-                       DPCD_ADDR_TRAINING_PATTERN_SET,
-                       (u8)(data & ~DPCD_SCRAMBLING_DISABLED));
-       } else {
-               exynos_dp_disable_scrambling(dp);
-
-               exynos_dp_read_byte_from_dpcd(dp,
-                       DPCD_ADDR_TRAINING_PATTERN_SET,
-                       &data);
-               exynos_dp_write_byte_to_dpcd(dp,
-                       DPCD_ADDR_TRAINING_PATTERN_SET,
-                       (u8)(data | DPCD_SCRAMBLING_DISABLED));
-       }
-}
-
-static irqreturn_t exynos_dp_irq_handler(int irq, void *arg)
-{
-       struct exynos_dp_device *dp = arg;
-
-       enum dp_irq_type irq_type;
-
-       irq_type = exynos_dp_get_irq_type(dp);
-       switch (irq_type) {
-       case DP_IRQ_TYPE_HP_CABLE_IN:
-               dev_dbg(dp->dev, "Received irq - cable in\n");
-               schedule_work(&dp->hotplug_work);
-               exynos_dp_clear_hotplug_interrupts(dp);
-               break;
-       case DP_IRQ_TYPE_HP_CABLE_OUT:
-               dev_dbg(dp->dev, "Received irq - cable out\n");
-               exynos_dp_clear_hotplug_interrupts(dp);
-               break;
-       case DP_IRQ_TYPE_HP_CHANGE:
-               /*
-                * We get these change notifications once in a while, but there
-                * is nothing we can do with them. Just ignore it for now and
-                * only handle cable changes.
-                */
-               dev_dbg(dp->dev, "Received irq - hotplug change; ignoring.\n");
-               exynos_dp_clear_hotplug_interrupts(dp);
-               break;
-       default:
-               dev_err(dp->dev, "Received irq - unknown type!\n");
-               break;
-       }
-       return IRQ_HANDLED;
-}
-
-static void exynos_dp_hotplug(struct work_struct *work)
-{
-       struct exynos_dp_device *dp;
-       int ret;
-
-       dp = container_of(work, struct exynos_dp_device, hotplug_work);
-
-       ret = exynos_dp_detect_hpd(dp);
-       if (ret) {
-               /* Cable has been disconnected, we're done */
-               return;
-       }
-
-       ret = exynos_dp_handle_edid(dp);
-       if (ret) {
-               dev_err(dp->dev, "unable to handle edid\n");
-               return;
-       }
-
-       ret = exynos_dp_set_link_train(dp, dp->video_info->lane_count,
-                                       dp->video_info->link_rate);
-       if (ret) {
-               dev_err(dp->dev, "unable to do link train\n");
-               return;
-       }
-
-       exynos_dp_enable_scramble(dp, 1);
-       exynos_dp_enable_rx_to_enhanced_mode(dp, 1);
-       exynos_dp_enable_enhanced_mode(dp, 1);
-
-       exynos_dp_set_lane_count(dp, dp->video_info->lane_count);
-       exynos_dp_set_link_bandwidth(dp, dp->video_info->link_rate);
-
-       exynos_dp_init_video(dp);
-       ret = exynos_dp_config_video(dp);
-       if (ret)
-               dev_err(dp->dev, "unable to config video\n");
-}
-
-static struct video_info *exynos_dp_dt_parse_pdata(struct device *dev)
-{
-       struct device_node *dp_node = dev->of_node;
-       struct video_info *dp_video_config;
-
-       dp_video_config = devm_kzalloc(dev,
-                               sizeof(*dp_video_config), GFP_KERNEL);
-       if (!dp_video_config) {
-               dev_err(dev, "memory allocation for video config failed\n");
-               return ERR_PTR(-ENOMEM);
-       }
-
-       dp_video_config->h_sync_polarity =
-               of_property_read_bool(dp_node, "hsync-active-high");
-
-       dp_video_config->v_sync_polarity =
-               of_property_read_bool(dp_node, "vsync-active-high");
-
-       dp_video_config->interlaced =
-               of_property_read_bool(dp_node, "interlaced");
-
-       if (of_property_read_u32(dp_node, "samsung,color-space",
-                               &dp_video_config->color_space)) {
-               dev_err(dev, "failed to get color-space\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (of_property_read_u32(dp_node, "samsung,dynamic-range",
-                               &dp_video_config->dynamic_range)) {
-               dev_err(dev, "failed to get dynamic-range\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (of_property_read_u32(dp_node, "samsung,ycbcr-coeff",
-                               &dp_video_config->ycbcr_coeff)) {
-               dev_err(dev, "failed to get ycbcr-coeff\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (of_property_read_u32(dp_node, "samsung,color-depth",
-                               &dp_video_config->color_depth)) {
-               dev_err(dev, "failed to get color-depth\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (of_property_read_u32(dp_node, "samsung,link-rate",
-                               &dp_video_config->link_rate)) {
-               dev_err(dev, "failed to get link-rate\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       if (of_property_read_u32(dp_node, "samsung,lane-count",
-                               &dp_video_config->lane_count)) {
-               dev_err(dev, "failed to get lane-count\n");
-               return ERR_PTR(-EINVAL);
-       }
-
-       return dp_video_config;
-}
-
-static int exynos_dp_dt_parse_phydata(struct exynos_dp_device *dp)
-{
-       struct device_node *dp_phy_node = of_node_get(dp->dev->of_node);
-       u32 phy_base;
-       int ret = 0;
-
-       dp_phy_node = of_find_node_by_name(dp_phy_node, "dptx-phy");
-       if (!dp_phy_node) {
-               dp->phy = devm_phy_get(dp->dev, "dp");
-               if (IS_ERR(dp->phy))
-                       return PTR_ERR(dp->phy);
-               else
-                       return 0;
-       }
-
-       if (of_property_read_u32(dp_phy_node, "reg", &phy_base)) {
-               dev_err(dp->dev, "failed to get reg for dptx-phy\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       if (of_property_read_u32(dp_phy_node, "samsung,enable-mask",
-                               &dp->enable_mask)) {
-               dev_err(dp->dev, "failed to get enable-mask for dptx-phy\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       dp->phy_addr = ioremap(phy_base, SZ_4);
-       if (!dp->phy_addr) {
-               dev_err(dp->dev, "failed to ioremap dp-phy\n");
-               ret = -ENOMEM;
-               goto err;
-       }
-
-err:
-       of_node_put(dp_phy_node);
-
-       return ret;
-}
-
-static void exynos_dp_phy_init(struct exynos_dp_device *dp)
-{
-       if (dp->phy) {
-               phy_power_on(dp->phy);
-       } else if (dp->phy_addr) {
-               u32 reg;
-
-               reg = __raw_readl(dp->phy_addr);
-               reg |= dp->enable_mask;
-               __raw_writel(reg, dp->phy_addr);
-       }
-}
-
-static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
-{
-       if (dp->phy) {
-               phy_power_off(dp->phy);
-       } else if (dp->phy_addr) {
-               u32 reg;
-
-               reg = __raw_readl(dp->phy_addr);
-               reg &= ~(dp->enable_mask);
-               __raw_writel(reg, dp->phy_addr);
-       }
-}
-
-static int exynos_dp_probe(struct platform_device *pdev)
-{
-       struct resource *res;
-       struct exynos_dp_device *dp;
-
-       int ret = 0;
-
-       dp = devm_kzalloc(&pdev->dev, sizeof(struct exynos_dp_device),
-                               GFP_KERNEL);
-       if (!dp) {
-               dev_err(&pdev->dev, "no memory for device data\n");
-               return -ENOMEM;
-       }
-
-       dp->dev = &pdev->dev;
-
-       dp->video_info = exynos_dp_dt_parse_pdata(&pdev->dev);
-       if (IS_ERR(dp->video_info))
-               return PTR_ERR(dp->video_info);
-
-       ret = exynos_dp_dt_parse_phydata(dp);
-       if (ret)
-               return ret;
-
-       dp->clock = devm_clk_get(&pdev->dev, "dp");
-       if (IS_ERR(dp->clock)) {
-               dev_err(&pdev->dev, "failed to get clock\n");
-               return PTR_ERR(dp->clock);
-       }
-
-       clk_prepare_enable(dp->clock);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-
-       dp->reg_base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(dp->reg_base))
-               return PTR_ERR(dp->reg_base);
-
-       dp->irq = platform_get_irq(pdev, 0);
-       if (dp->irq == -ENXIO) {
-               dev_err(&pdev->dev, "failed to get irq\n");
-               return -ENODEV;
-       }
-
-       INIT_WORK(&dp->hotplug_work, exynos_dp_hotplug);
-
-       exynos_dp_phy_init(dp);
-
-       exynos_dp_init_dp(dp);
-
-       ret = devm_request_irq(&pdev->dev, dp->irq, exynos_dp_irq_handler, 0,
-                               "exynos-dp", dp);
-       if (ret) {
-               dev_err(&pdev->dev, "failed to request irq\n");
-               return ret;
-       }
-
-       platform_set_drvdata(pdev, dp);
-
-       return 0;
-}
-
-static int exynos_dp_remove(struct platform_device *pdev)
-{
-       struct exynos_dp_device *dp = platform_get_drvdata(pdev);
-
-       flush_work(&dp->hotplug_work);
-
-       exynos_dp_phy_exit(dp);
-
-       clk_disable_unprepare(dp->clock);
-
-
-       return 0;
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int exynos_dp_suspend(struct device *dev)
-{
-       struct exynos_dp_device *dp = dev_get_drvdata(dev);
-
-       disable_irq(dp->irq);
-
-       flush_work(&dp->hotplug_work);
-
-       exynos_dp_phy_exit(dp);
-
-       clk_disable_unprepare(dp->clock);
-
-       return 0;
-}
-
-static int exynos_dp_resume(struct device *dev)
-{
-       struct exynos_dp_device *dp = dev_get_drvdata(dev);
-
-       exynos_dp_phy_init(dp);
-
-       clk_prepare_enable(dp->clock);
-
-       exynos_dp_init_dp(dp);
-
-       enable_irq(dp->irq);
-
-       return 0;
-}
-#endif
-
-static const struct dev_pm_ops exynos_dp_pm_ops = {
-       SET_SYSTEM_SLEEP_PM_OPS(exynos_dp_suspend, exynos_dp_resume)
-};
-
-static const struct of_device_id exynos_dp_match[] = {
-       { .compatible = "samsung,exynos5-dp" },
-       {},
-};
-MODULE_DEVICE_TABLE(of, exynos_dp_match);
-
-static struct platform_driver exynos_dp_driver = {
-       .probe          = exynos_dp_probe,
-       .remove         = exynos_dp_remove,
-       .driver         = {
-               .name   = "exynos-dp",
-               .owner  = THIS_MODULE,
-               .pm     = &exynos_dp_pm_ops,
-               .of_match_table = exynos_dp_match,
-       },
-};
-
-module_platform_driver(exynos_dp_driver);
-
-MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DP Driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/video/exynos/exynos_dp_core.h b/drivers/video/exynos/exynos_dp_core.h
deleted file mode 100644 (file)
index 607e36d..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-/*
- * Header file for Samsung DP (Display Port) interface driver.
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#ifndef _EXYNOS_DP_CORE_H
-#define _EXYNOS_DP_CORE_H
-
-#define DP_TIMEOUT_LOOP_COUNT 100
-#define MAX_CR_LOOP 5
-#define MAX_EQ_LOOP 5
-
-enum link_rate_type {
-       LINK_RATE_1_62GBPS = 0x06,
-       LINK_RATE_2_70GBPS = 0x0a
-};
-
-enum link_lane_count_type {
-       LANE_COUNT1 = 1,
-       LANE_COUNT2 = 2,
-       LANE_COUNT4 = 4
-};
-
-enum link_training_state {
-       START,
-       CLOCK_RECOVERY,
-       EQUALIZER_TRAINING,
-       FINISHED,
-       FAILED
-};
-
-enum voltage_swing_level {
-       VOLTAGE_LEVEL_0,
-       VOLTAGE_LEVEL_1,
-       VOLTAGE_LEVEL_2,
-       VOLTAGE_LEVEL_3,
-};
-
-enum pre_emphasis_level {
-       PRE_EMPHASIS_LEVEL_0,
-       PRE_EMPHASIS_LEVEL_1,
-       PRE_EMPHASIS_LEVEL_2,
-       PRE_EMPHASIS_LEVEL_3,
-};
-
-enum pattern_set {
-       PRBS7,
-       D10_2,
-       TRAINING_PTN1,
-       TRAINING_PTN2,
-       DP_NONE
-};
-
-enum color_space {
-       COLOR_RGB,
-       COLOR_YCBCR422,
-       COLOR_YCBCR444
-};
-
-enum color_depth {
-       COLOR_6,
-       COLOR_8,
-       COLOR_10,
-       COLOR_12
-};
-
-enum color_coefficient {
-       COLOR_YCBCR601,
-       COLOR_YCBCR709
-};
-
-enum dynamic_range {
-       VESA,
-       CEA
-};
-
-enum pll_status {
-       PLL_UNLOCKED,
-       PLL_LOCKED
-};
-
-enum clock_recovery_m_value_type {
-       CALCULATED_M,
-       REGISTER_M
-};
-
-enum video_timing_recognition_type {
-       VIDEO_TIMING_FROM_CAPTURE,
-       VIDEO_TIMING_FROM_REGISTER
-};
-
-enum analog_power_block {
-       AUX_BLOCK,
-       CH0_BLOCK,
-       CH1_BLOCK,
-       CH2_BLOCK,
-       CH3_BLOCK,
-       ANALOG_TOTAL,
-       POWER_ALL
-};
-
-enum dp_irq_type {
-       DP_IRQ_TYPE_HP_CABLE_IN,
-       DP_IRQ_TYPE_HP_CABLE_OUT,
-       DP_IRQ_TYPE_HP_CHANGE,
-       DP_IRQ_TYPE_UNKNOWN,
-};
-
-struct video_info {
-       char *name;
-
-       bool h_sync_polarity;
-       bool v_sync_polarity;
-       bool interlaced;
-
-       enum color_space color_space;
-       enum dynamic_range dynamic_range;
-       enum color_coefficient ycbcr_coeff;
-       enum color_depth color_depth;
-
-       enum link_rate_type link_rate;
-       enum link_lane_count_type lane_count;
-};
-
-struct link_train {
-       int eq_loop;
-       int cr_loop[4];
-
-       u8 link_rate;
-       u8 lane_count;
-       u8 training_lane[4];
-
-       enum link_training_state lt_state;
-};
-
-struct exynos_dp_device {
-       struct device           *dev;
-       struct clk              *clock;
-       unsigned int            irq;
-       void __iomem            *reg_base;
-       void __iomem            *phy_addr;
-       unsigned int            enable_mask;
-
-       struct video_info       *video_info;
-       struct link_train       link_train;
-       struct work_struct      hotplug_work;
-       struct phy              *phy;
-};
-
-/* exynos_dp_reg.c */
-void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_stop_video(struct exynos_dp_device *dp);
-void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_init_analog_param(struct exynos_dp_device *dp);
-void exynos_dp_init_interrupt(struct exynos_dp_device *dp);
-void exynos_dp_reset(struct exynos_dp_device *dp);
-void exynos_dp_swreset(struct exynos_dp_device *dp);
-void exynos_dp_config_interrupt(struct exynos_dp_device *dp);
-enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp);
-void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
-                               enum analog_power_block block,
-                               bool enable);
-void exynos_dp_init_analog_func(struct exynos_dp_device *dp);
-void exynos_dp_init_hpd(struct exynos_dp_device *dp);
-enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp);
-void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp);
-void exynos_dp_reset_aux(struct exynos_dp_device *dp);
-void exynos_dp_init_aux(struct exynos_dp_device *dp);
-int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp);
-void exynos_dp_enable_sw_function(struct exynos_dp_device *dp);
-int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp);
-int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
-                               unsigned int reg_addr,
-                               unsigned char data);
-int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
-                               unsigned int reg_addr,
-                               unsigned char *data);
-int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
-                               unsigned int reg_addr,
-                               unsigned int count,
-                               unsigned char data[]);
-int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
-                               unsigned int reg_addr,
-                               unsigned int count,
-                               unsigned char data[]);
-int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
-                               unsigned int device_addr,
-                               unsigned int reg_addr);
-int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
-                               unsigned int device_addr,
-                               unsigned int reg_addr,
-                               unsigned int *data);
-int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
-                               unsigned int device_addr,
-                               unsigned int reg_addr,
-                               unsigned int count,
-                               unsigned char edid[]);
-void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype);
-void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype);
-void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count);
-void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count);
-void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
-                                enum pattern_set pattern);
-void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level);
-void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
-                               u32 training_lane);
-void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
-                               u32 training_lane);
-void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
-                               u32 training_lane);
-void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
-                               u32 training_lane);
-u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp);
-u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp);
-u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp);
-u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp);
-void exynos_dp_reset_macro(struct exynos_dp_device *dp);
-void exynos_dp_init_video(struct exynos_dp_device *dp);
-
-void exynos_dp_set_video_color_format(struct exynos_dp_device *dp);
-int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp);
-void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
-                       enum clock_recovery_m_value_type type,
-                       u32 m_value,
-                       u32 n_value);
-void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type);
-void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable);
-void exynos_dp_start_video(struct exynos_dp_device *dp);
-int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp);
-void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp);
-void exynos_dp_enable_scrambling(struct exynos_dp_device *dp);
-void exynos_dp_disable_scrambling(struct exynos_dp_device *dp);
-
-/* I2C EDID Chip ID, Slave Address */
-#define I2C_EDID_DEVICE_ADDR                   0x50
-#define I2C_E_EDID_DEVICE_ADDR                 0x30
-
-#define EDID_BLOCK_LENGTH                      0x80
-#define EDID_HEADER_PATTERN                    0x00
-#define EDID_EXTENSION_FLAG                    0x7e
-#define EDID_CHECKSUM                          0x7f
-
-/* Definition for DPCD Register */
-#define DPCD_ADDR_DPCD_REV                     0x0000
-#define DPCD_ADDR_MAX_LINK_RATE                        0x0001
-#define DPCD_ADDR_MAX_LANE_COUNT               0x0002
-#define DPCD_ADDR_LINK_BW_SET                  0x0100
-#define DPCD_ADDR_LANE_COUNT_SET               0x0101
-#define DPCD_ADDR_TRAINING_PATTERN_SET         0x0102
-#define DPCD_ADDR_TRAINING_LANE0_SET           0x0103
-#define DPCD_ADDR_LANE0_1_STATUS               0x0202
-#define DPCD_ADDR_LANE_ALIGN_STATUS_UPDATED    0x0204
-#define DPCD_ADDR_ADJUST_REQUEST_LANE0_1       0x0206
-#define DPCD_ADDR_ADJUST_REQUEST_LANE2_3       0x0207
-#define DPCD_ADDR_TEST_REQUEST                 0x0218
-#define DPCD_ADDR_TEST_RESPONSE                        0x0260
-#define DPCD_ADDR_TEST_EDID_CHECKSUM           0x0261
-#define DPCD_ADDR_SINK_POWER_STATE             0x0600
-
-/* DPCD_ADDR_MAX_LANE_COUNT */
-#define DPCD_ENHANCED_FRAME_CAP(x)             (((x) >> 7) & 0x1)
-#define DPCD_MAX_LANE_COUNT(x)                 ((x) & 0x1f)
-
-/* DPCD_ADDR_LANE_COUNT_SET */
-#define DPCD_ENHANCED_FRAME_EN                 (0x1 << 7)
-#define DPCD_LANE_COUNT_SET(x)                 ((x) & 0x1f)
-
-/* DPCD_ADDR_TRAINING_PATTERN_SET */
-#define DPCD_SCRAMBLING_DISABLED               (0x1 << 5)
-#define DPCD_SCRAMBLING_ENABLED                        (0x0 << 5)
-#define DPCD_TRAINING_PATTERN_2                        (0x2 << 0)
-#define DPCD_TRAINING_PATTERN_1                        (0x1 << 0)
-#define DPCD_TRAINING_PATTERN_DISABLED         (0x0 << 0)
-
-/* DPCD_ADDR_TRAINING_LANE0_SET */
-#define DPCD_MAX_PRE_EMPHASIS_REACHED          (0x1 << 5)
-#define DPCD_PRE_EMPHASIS_SET(x)               (((x) & 0x3) << 3)
-#define DPCD_PRE_EMPHASIS_GET(x)               (((x) >> 3) & 0x3)
-#define DPCD_PRE_EMPHASIS_PATTERN2_LEVEL0      (0x0 << 3)
-#define DPCD_MAX_SWING_REACHED                 (0x1 << 2)
-#define DPCD_VOLTAGE_SWING_SET(x)              (((x) & 0x3) << 0)
-#define DPCD_VOLTAGE_SWING_GET(x)              (((x) >> 0) & 0x3)
-#define DPCD_VOLTAGE_SWING_PATTERN1_LEVEL0     (0x0 << 0)
-
-/* DPCD_ADDR_LANE0_1_STATUS */
-#define DPCD_LANE_SYMBOL_LOCKED                        (0x1 << 2)
-#define DPCD_LANE_CHANNEL_EQ_DONE              (0x1 << 1)
-#define DPCD_LANE_CR_DONE                      (0x1 << 0)
-#define DPCD_CHANNEL_EQ_BITS                   (DPCD_LANE_CR_DONE|     \
-                                                DPCD_LANE_CHANNEL_EQ_DONE|\
-                                                DPCD_LANE_SYMBOL_LOCKED)
-
-/* DPCD_ADDR_LANE_ALIGN__STATUS_UPDATED */
-#define DPCD_LINK_STATUS_UPDATED               (0x1 << 7)
-#define DPCD_DOWNSTREAM_PORT_STATUS_CHANGED    (0x1 << 6)
-#define DPCD_INTERLANE_ALIGN_DONE              (0x1 << 0)
-
-/* DPCD_ADDR_TEST_REQUEST */
-#define DPCD_TEST_EDID_READ                    (0x1 << 2)
-
-/* DPCD_ADDR_TEST_RESPONSE */
-#define DPCD_TEST_EDID_CHECKSUM_WRITE          (0x1 << 2)
-
-/* DPCD_ADDR_SINK_POWER_STATE */
-#define DPCD_SET_POWER_STATE_D0                        (0x1 << 0)
-#define DPCD_SET_POWER_STATE_D4                        (0x2 << 0)
-
-#endif /* _EXYNOS_DP_CORE_H */
diff --git a/drivers/video/exynos/exynos_dp_reg.c b/drivers/video/exynos/exynos_dp_reg.c
deleted file mode 100644 (file)
index b70da50..0000000
+++ /dev/null
@@ -1,1243 +0,0 @@
-/*
- * Samsung DP (Display port) register interface driver.
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/device.h>
-#include <linux/io.h>
-#include <linux/delay.h>
-
-#include "exynos_dp_core.h"
-#include "exynos_dp_reg.h"
-
-#define COMMON_INT_MASK_1      0
-#define COMMON_INT_MASK_2      0
-#define COMMON_INT_MASK_3      0
-#define COMMON_INT_MASK_4      (HOTPLUG_CHG | HPD_LOST | PLUG)
-#define INT_STA_MASK           INT_HPD
-
-void exynos_dp_enable_video_mute(struct exynos_dp_device *dp, bool enable)
-{
-       u32 reg;
-
-       if (enable) {
-               reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-               reg |= HDCP_VIDEO_MUTE;
-               writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-       } else {
-               reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-               reg &= ~HDCP_VIDEO_MUTE;
-               writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-       }
-}
-
-void exynos_dp_stop_video(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-       reg &= ~VIDEO_EN;
-       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-}
-
-void exynos_dp_lane_swap(struct exynos_dp_device *dp, bool enable)
-{
-       u32 reg;
-
-       if (enable)
-               reg = LANE3_MAP_LOGIC_LANE_0 | LANE2_MAP_LOGIC_LANE_1 |
-                       LANE1_MAP_LOGIC_LANE_2 | LANE0_MAP_LOGIC_LANE_3;
-       else
-               reg = LANE3_MAP_LOGIC_LANE_3 | LANE2_MAP_LOGIC_LANE_2 |
-                       LANE1_MAP_LOGIC_LANE_1 | LANE0_MAP_LOGIC_LANE_0;
-
-       writel(reg, dp->reg_base + EXYNOS_DP_LANE_MAP);
-}
-
-void exynos_dp_init_analog_param(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = TX_TERMINAL_CTRL_50_OHM;
-       writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_1);
-
-       reg = SEL_24M | TX_DVDD_BIT_1_0625V;
-       writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_2);
-
-       reg = DRIVE_DVDD_BIT_1_0625V | VCO_BIT_600_MICRO;
-       writel(reg, dp->reg_base + EXYNOS_DP_ANALOG_CTL_3);
-
-       reg = PD_RING_OSC | AUX_TERMINAL_CTRL_50_OHM |
-               TX_CUR1_2X | TX_CUR_16_MA;
-       writel(reg, dp->reg_base + EXYNOS_DP_PLL_FILTER_CTL_1);
-
-       reg = CH3_AMP_400_MV | CH2_AMP_400_MV |
-               CH1_AMP_400_MV | CH0_AMP_400_MV;
-       writel(reg, dp->reg_base + EXYNOS_DP_TX_AMP_TUNING_CTL);
-}
-
-void exynos_dp_init_interrupt(struct exynos_dp_device *dp)
-{
-       /* Set interrupt pin assertion polarity as high */
-       writel(INT_POL1 | INT_POL0, dp->reg_base + EXYNOS_DP_INT_CTL);
-
-       /* Clear pending regisers */
-       writel(0xff, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
-       writel(0x4f, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_2);
-       writel(0xe0, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_3);
-       writel(0xe7, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
-       writel(0x63, dp->reg_base + EXYNOS_DP_INT_STA);
-
-       /* 0:mask,1: unmask */
-       writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
-       writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
-       writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
-       writel(0x00, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
-       writel(0x00, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
-}
-
-void exynos_dp_reset(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       exynos_dp_stop_video(dp);
-       exynos_dp_enable_video_mute(dp, 0);
-
-       reg = MASTER_VID_FUNC_EN_N | SLAVE_VID_FUNC_EN_N |
-               AUD_FIFO_FUNC_EN_N | AUD_FUNC_EN_N |
-               HDCP_FUNC_EN_N | SW_FUNC_EN_N;
-       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-
-       reg = SSC_FUNC_EN_N | AUX_FUNC_EN_N |
-               SERDES_FIFO_FUNC_EN_N |
-               LS_CLK_DOMAIN_FUNC_EN_N;
-       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-
-       usleep_range(20, 30);
-
-       exynos_dp_lane_swap(dp, 0);
-
-       writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-       writel(0x40, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-       writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-       writel(0x0, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-
-       writel(0x0, dp->reg_base + EXYNOS_DP_PKT_SEND_CTL);
-       writel(0x0, dp->reg_base + EXYNOS_DP_HDCP_CTL);
-
-       writel(0x5e, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_L);
-       writel(0x1a, dp->reg_base + EXYNOS_DP_HPD_DEGLITCH_H);
-
-       writel(0x10, dp->reg_base + EXYNOS_DP_LINK_DEBUG_CTL);
-
-       writel(0x0, dp->reg_base + EXYNOS_DP_PHY_TEST);
-
-       writel(0x0, dp->reg_base + EXYNOS_DP_VIDEO_FIFO_THRD);
-       writel(0x20, dp->reg_base + EXYNOS_DP_AUDIO_MARGIN);
-
-       writel(0x4, dp->reg_base + EXYNOS_DP_M_VID_GEN_FILTER_TH);
-       writel(0x2, dp->reg_base + EXYNOS_DP_M_AUD_GEN_FILTER_TH);
-
-       writel(0x00000101, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-}
-
-void exynos_dp_swreset(struct exynos_dp_device *dp)
-{
-       writel(RESET_DP_TX, dp->reg_base + EXYNOS_DP_TX_SW_RESET);
-}
-
-void exynos_dp_config_interrupt(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       /* 0: mask, 1: unmask */
-       reg = COMMON_INT_MASK_1;
-       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_1);
-
-       reg = COMMON_INT_MASK_2;
-       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_2);
-
-       reg = COMMON_INT_MASK_3;
-       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_3);
-
-       reg = COMMON_INT_MASK_4;
-       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_MASK_4);
-
-       reg = INT_STA_MASK;
-       writel(reg, dp->reg_base + EXYNOS_DP_INT_STA_MASK);
-}
-
-enum pll_status exynos_dp_get_pll_lock_status(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
-       if (reg & PLL_LOCK)
-               return PLL_LOCKED;
-       else
-               return PLL_UNLOCKED;
-}
-
-void exynos_dp_set_pll_power_down(struct exynos_dp_device *dp, bool enable)
-{
-       u32 reg;
-
-       if (enable) {
-               reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
-               reg |= DP_PLL_PD;
-               writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
-       } else {
-               reg = readl(dp->reg_base + EXYNOS_DP_PLL_CTL);
-               reg &= ~DP_PLL_PD;
-               writel(reg, dp->reg_base + EXYNOS_DP_PLL_CTL);
-       }
-}
-
-void exynos_dp_set_analog_power_down(struct exynos_dp_device *dp,
-                               enum analog_power_block block,
-                               bool enable)
-{
-       u32 reg;
-
-       switch (block) {
-       case AUX_BLOCK:
-               if (enable) {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg |= AUX_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               } else {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg &= ~AUX_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               }
-               break;
-       case CH0_BLOCK:
-               if (enable) {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg |= CH0_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               } else {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg &= ~CH0_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               }
-               break;
-       case CH1_BLOCK:
-               if (enable) {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg |= CH1_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               } else {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg &= ~CH1_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               }
-               break;
-       case CH2_BLOCK:
-               if (enable) {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg |= CH2_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               } else {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg &= ~CH2_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               }
-               break;
-       case CH3_BLOCK:
-               if (enable) {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg |= CH3_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               } else {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg &= ~CH3_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               }
-               break;
-       case ANALOG_TOTAL:
-               if (enable) {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg |= DP_PHY_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               } else {
-                       reg = readl(dp->reg_base + EXYNOS_DP_PHY_PD);
-                       reg &= ~DP_PHY_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               }
-               break;
-       case POWER_ALL:
-               if (enable) {
-                       reg = DP_PHY_PD | AUX_PD | CH3_PD | CH2_PD |
-                               CH1_PD | CH0_PD;
-                       writel(reg, dp->reg_base + EXYNOS_DP_PHY_PD);
-               } else {
-                       writel(0x00, dp->reg_base + EXYNOS_DP_PHY_PD);
-               }
-               break;
-       default:
-               break;
-       }
-}
-
-void exynos_dp_init_analog_func(struct exynos_dp_device *dp)
-{
-       u32 reg;
-       int timeout_loop = 0;
-
-       exynos_dp_set_analog_power_down(dp, POWER_ALL, 0);
-
-       reg = PLL_LOCK_CHG;
-       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
-
-       reg = readl(dp->reg_base + EXYNOS_DP_DEBUG_CTL);
-       reg &= ~(F_PLL_LOCK | PLL_LOCK_CTRL);
-       writel(reg, dp->reg_base + EXYNOS_DP_DEBUG_CTL);
-
-       /* Power up PLL */
-       if (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-               exynos_dp_set_pll_power_down(dp, 0);
-
-               while (exynos_dp_get_pll_lock_status(dp) == PLL_UNLOCKED) {
-                       timeout_loop++;
-                       if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-                               dev_err(dp->dev, "failed to get pll lock status\n");
-                               return;
-                       }
-                       usleep_range(10, 20);
-               }
-       }
-
-       /* Enable Serdes FIFO function and Link symbol clock domain module */
-       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-       reg &= ~(SERDES_FIFO_FUNC_EN_N | LS_CLK_DOMAIN_FUNC_EN_N
-               | AUX_FUNC_EN_N);
-       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-}
-
-void exynos_dp_clear_hotplug_interrupts(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = HOTPLUG_CHG | HPD_LOST | PLUG;
-       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
-
-       reg = INT_HPD;
-       writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
-}
-
-void exynos_dp_init_hpd(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       exynos_dp_clear_hotplug_interrupts(dp);
-
-       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-       reg &= ~(F_HPD | HPD_CTRL);
-       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-}
-
-enum dp_irq_type exynos_dp_get_irq_type(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       /* Parse hotplug interrupt status register */
-       reg = readl(dp->reg_base + EXYNOS_DP_COMMON_INT_STA_4);
-
-       if (reg & PLUG)
-               return DP_IRQ_TYPE_HP_CABLE_IN;
-
-       if (reg & HPD_LOST)
-               return DP_IRQ_TYPE_HP_CABLE_OUT;
-
-       if (reg & HOTPLUG_CHG)
-               return DP_IRQ_TYPE_HP_CHANGE;
-
-       return DP_IRQ_TYPE_UNKNOWN;
-}
-
-void exynos_dp_reset_aux(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       /* Disable AUX channel module */
-       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-       reg |= AUX_FUNC_EN_N;
-       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-}
-
-void exynos_dp_init_aux(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       /* Clear inerrupts related to AUX channel */
-       reg = RPLY_RECEIV | AUX_ERR;
-       writel(reg, dp->reg_base + EXYNOS_DP_INT_STA);
-
-       exynos_dp_reset_aux(dp);
-
-       /* Disable AUX transaction H/W retry */
-       reg = AUX_BIT_PERIOD_EXPECTED_DELAY(3) | AUX_HW_RETRY_COUNT_SEL(0)|
-               AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
-       writel(reg, dp->reg_base + EXYNOS_DP_AUX_HW_RETRY_CTL) ;
-
-       /* Receive AUX Channel DEFER commands equal to DEFFER_COUNT*64 */
-       reg = DEFER_CTRL_EN | DEFER_COUNT(1);
-       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_DEFER_CTL);
-
-       /* Enable AUX channel module */
-       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-       reg &= ~AUX_FUNC_EN_N;
-       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_2);
-}
-
-int exynos_dp_get_plug_in_status(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-       if (reg & HPD_STATUS)
-               return 0;
-
-       return -EINVAL;
-}
-
-void exynos_dp_enable_sw_function(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-       reg &= ~SW_FUNC_EN_N;
-       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-}
-
-int exynos_dp_start_aux_transaction(struct exynos_dp_device *dp)
-{
-       int reg;
-       int retval = 0;
-       int timeout_loop = 0;
-
-       /* Enable AUX CH operation */
-       reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-       reg |= AUX_EN;
-       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-
-       /* Is AUX CH command reply received? */
-       reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
-       while (!(reg & RPLY_RECEIV)) {
-               timeout_loop++;
-               if (DP_TIMEOUT_LOOP_COUNT < timeout_loop) {
-                       dev_err(dp->dev, "AUX CH command reply failed!\n");
-                       return -ETIMEDOUT;
-               }
-               reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
-               usleep_range(10, 11);
-       }
-
-       /* Clear interrupt source for AUX CH command reply */
-       writel(RPLY_RECEIV, dp->reg_base + EXYNOS_DP_INT_STA);
-
-       /* Clear interrupt source for AUX CH access error */
-       reg = readl(dp->reg_base + EXYNOS_DP_INT_STA);
-       if (reg & AUX_ERR) {
-               writel(AUX_ERR, dp->reg_base + EXYNOS_DP_INT_STA);
-               return -EREMOTEIO;
-       }
-
-       /* Check AUX CH error access status */
-       reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_STA);
-       if ((reg & AUX_STATUS_MASK) != 0) {
-               dev_err(dp->dev, "AUX CH error happens: %d\n\n",
-                       reg & AUX_STATUS_MASK);
-               return -EREMOTEIO;
-       }
-
-       return retval;
-}
-
-int exynos_dp_write_byte_to_dpcd(struct exynos_dp_device *dp,
-                               unsigned int reg_addr,
-                               unsigned char data)
-{
-       u32 reg;
-       int i;
-       int retval;
-
-       for (i = 0; i < 3; i++) {
-               /* Clear AUX CH data buffer */
-               reg = BUF_CLR;
-               writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-               /* Select DPCD device address */
-               reg = AUX_ADDR_7_0(reg_addr);
-               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-               reg = AUX_ADDR_15_8(reg_addr);
-               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-               reg = AUX_ADDR_19_16(reg_addr);
-               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-               /* Write data buffer */
-               reg = (unsigned int)data;
-               writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-
-               /*
-                * Set DisplayPort transaction and write 1 byte
-                * If bit 3 is 1, DisplayPort transaction.
-                * If Bit 3 is 0, I2C transaction.
-                */
-               reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
-               writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-               /* Start AUX transaction */
-               retval = exynos_dp_start_aux_transaction(dp);
-               if (retval == 0)
-                       break;
-               else
-                       dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-                               __func__);
-       }
-
-       return retval;
-}
-
-int exynos_dp_read_byte_from_dpcd(struct exynos_dp_device *dp,
-                               unsigned int reg_addr,
-                               unsigned char *data)
-{
-       u32 reg;
-       int i;
-       int retval;
-
-       for (i = 0; i < 3; i++) {
-               /* Clear AUX CH data buffer */
-               reg = BUF_CLR;
-               writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-               /* Select DPCD device address */
-               reg = AUX_ADDR_7_0(reg_addr);
-               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-               reg = AUX_ADDR_15_8(reg_addr);
-               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-               reg = AUX_ADDR_19_16(reg_addr);
-               writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-               /*
-                * Set DisplayPort transaction and read 1 byte
-                * If bit 3 is 1, DisplayPort transaction.
-                * If Bit 3 is 0, I2C transaction.
-                */
-               reg = AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
-               writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-               /* Start AUX transaction */
-               retval = exynos_dp_start_aux_transaction(dp);
-               if (retval == 0)
-                       break;
-               else
-                       dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-                               __func__);
-       }
-
-       /* Read data buffer */
-       reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-       *data = (unsigned char)(reg & 0xff);
-
-       return retval;
-}
-
-int exynos_dp_write_bytes_to_dpcd(struct exynos_dp_device *dp,
-                               unsigned int reg_addr,
-                               unsigned int count,
-                               unsigned char data[])
-{
-       u32 reg;
-       unsigned int start_offset;
-       unsigned int cur_data_count;
-       unsigned int cur_data_idx;
-       int i;
-       int retval = 0;
-
-       /* Clear AUX CH data buffer */
-       reg = BUF_CLR;
-       writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-       start_offset = 0;
-       while (start_offset < count) {
-               /* Buffer size of AUX CH is 16 * 4bytes */
-               if ((count - start_offset) > 16)
-                       cur_data_count = 16;
-               else
-                       cur_data_count = count - start_offset;
-
-               for (i = 0; i < 3; i++) {
-                       /* Select DPCD device address */
-                       reg = AUX_ADDR_7_0(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-                       reg = AUX_ADDR_15_8(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-                       reg = AUX_ADDR_19_16(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-                       for (cur_data_idx = 0; cur_data_idx < cur_data_count;
-                            cur_data_idx++) {
-                               reg = data[start_offset + cur_data_idx];
-                               writel(reg, dp->reg_base + EXYNOS_DP_BUF_DATA_0
-                                                         + 4 * cur_data_idx);
-                       }
-
-                       /*
-                        * Set DisplayPort transaction and write
-                        * If bit 3 is 1, DisplayPort transaction.
-                        * If Bit 3 is 0, I2C transaction.
-                        */
-                       reg = AUX_LENGTH(cur_data_count) |
-                               AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_WRITE;
-                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-                       /* Start AUX transaction */
-                       retval = exynos_dp_start_aux_transaction(dp);
-                       if (retval == 0)
-                               break;
-                       else
-                               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-                                       __func__);
-               }
-
-               start_offset += cur_data_count;
-       }
-
-       return retval;
-}
-
-int exynos_dp_read_bytes_from_dpcd(struct exynos_dp_device *dp,
-                               unsigned int reg_addr,
-                               unsigned int count,
-                               unsigned char data[])
-{
-       u32 reg;
-       unsigned int start_offset;
-       unsigned int cur_data_count;
-       unsigned int cur_data_idx;
-       int i;
-       int retval = 0;
-
-       /* Clear AUX CH data buffer */
-       reg = BUF_CLR;
-       writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-       start_offset = 0;
-       while (start_offset < count) {
-               /* Buffer size of AUX CH is 16 * 4bytes */
-               if ((count - start_offset) > 16)
-                       cur_data_count = 16;
-               else
-                       cur_data_count = count - start_offset;
-
-               /* AUX CH Request Transaction process */
-               for (i = 0; i < 3; i++) {
-                       /* Select DPCD device address */
-                       reg = AUX_ADDR_7_0(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-                       reg = AUX_ADDR_15_8(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-                       reg = AUX_ADDR_19_16(reg_addr + start_offset);
-                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-                       /*
-                        * Set DisplayPort transaction and read
-                        * If bit 3 is 1, DisplayPort transaction.
-                        * If Bit 3 is 0, I2C transaction.
-                        */
-                       reg = AUX_LENGTH(cur_data_count) |
-                               AUX_TX_COMM_DP_TRANSACTION | AUX_TX_COMM_READ;
-                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-                       /* Start AUX transaction */
-                       retval = exynos_dp_start_aux_transaction(dp);
-                       if (retval == 0)
-                               break;
-                       else
-                               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-                                       __func__);
-               }
-
-               for (cur_data_idx = 0; cur_data_idx < cur_data_count;
-                   cur_data_idx++) {
-                       reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
-                                                + 4 * cur_data_idx);
-                       data[start_offset + cur_data_idx] =
-                               (unsigned char)reg;
-               }
-
-               start_offset += cur_data_count;
-       }
-
-       return retval;
-}
-
-int exynos_dp_select_i2c_device(struct exynos_dp_device *dp,
-                               unsigned int device_addr,
-                               unsigned int reg_addr)
-{
-       u32 reg;
-       int retval;
-
-       /* Set EDID device address */
-       reg = device_addr;
-       writel(reg, dp->reg_base + EXYNOS_DP_AUX_ADDR_7_0);
-       writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_15_8);
-       writel(0x0, dp->reg_base + EXYNOS_DP_AUX_ADDR_19_16);
-
-       /* Set offset from base address of EDID device */
-       writel(reg_addr, dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-
-       /*
-        * Set I2C transaction and write address
-        * If bit 3 is 1, DisplayPort transaction.
-        * If Bit 3 is 0, I2C transaction.
-        */
-       reg = AUX_TX_COMM_I2C_TRANSACTION | AUX_TX_COMM_MOT |
-               AUX_TX_COMM_WRITE;
-       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-       /* Start AUX transaction */
-       retval = exynos_dp_start_aux_transaction(dp);
-       if (retval != 0)
-               dev_dbg(dp->dev, "%s: Aux Transaction fail!\n", __func__);
-
-       return retval;
-}
-
-int exynos_dp_read_byte_from_i2c(struct exynos_dp_device *dp,
-                               unsigned int device_addr,
-                               unsigned int reg_addr,
-                               unsigned int *data)
-{
-       u32 reg;
-       int i;
-       int retval;
-
-       for (i = 0; i < 3; i++) {
-               /* Clear AUX CH data buffer */
-               reg = BUF_CLR;
-               writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-               /* Select EDID device */
-               retval = exynos_dp_select_i2c_device(dp, device_addr, reg_addr);
-               if (retval != 0)
-                       continue;
-
-               /*
-                * Set I2C transaction and read data
-                * If bit 3 is 1, DisplayPort transaction.
-                * If Bit 3 is 0, I2C transaction.
-                */
-               reg = AUX_TX_COMM_I2C_TRANSACTION |
-                       AUX_TX_COMM_READ;
-               writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_1);
-
-               /* Start AUX transaction */
-               retval = exynos_dp_start_aux_transaction(dp);
-               if (retval == 0)
-                       break;
-               else
-                       dev_dbg(dp->dev, "%s: Aux Transaction fail!\n",
-                               __func__);
-       }
-
-       /* Read data */
-       if (retval == 0)
-               *data = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0);
-
-       return retval;
-}
-
-int exynos_dp_read_bytes_from_i2c(struct exynos_dp_device *dp,
-                               unsigned int device_addr,
-                               unsigned int reg_addr,
-                               unsigned int count,
-                               unsigned char edid[])
-{
-       u32 reg;
-       unsigned int i, j;
-       unsigned int cur_data_idx;
-       unsigned int defer = 0;
-       int retval = 0;
-
-       for (i = 0; i < count; i += 16) {
-               for (j = 0; j < 3; j++) {
-                       /* Clear AUX CH data buffer */
-                       reg = BUF_CLR;
-                       writel(reg, dp->reg_base + EXYNOS_DP_BUFFER_DATA_CTL);
-
-                       /* Set normal AUX CH command */
-                       reg = readl(dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-                       reg &= ~ADDR_ONLY;
-                       writel(reg, dp->reg_base + EXYNOS_DP_AUX_CH_CTL_2);
-
-                       /*
-                        * If Rx sends defer, Tx sends only reads
-                        * request without sending address
-                        */
-                       if (!defer)
-                               retval = exynos_dp_select_i2c_device(dp,
-                                               device_addr, reg_addr + i);
-                       else
-                               defer = 0;
-
-                       if (retval == 0) {
-                               /*
-                                * Set I2C transaction and write data
-                                * If bit 3 is 1, DisplayPort transaction.
-                                * If Bit 3 is 0, I2C transaction.
-                                */
-                               reg = AUX_LENGTH(16) |
-                                       AUX_TX_COMM_I2C_TRANSACTION |
-                                       AUX_TX_COMM_READ;
-                               writel(reg, dp->reg_base +
-                                       EXYNOS_DP_AUX_CH_CTL_1);
-
-                               /* Start AUX transaction */
-                               retval = exynos_dp_start_aux_transaction(dp);
-                               if (retval == 0)
-                                       break;
-                               else
-                                       dev_dbg(dp->dev,
-                                               "%s: Aux Transaction fail!\n",
-                                               __func__);
-                       }
-                       /* Check if Rx sends defer */
-                       reg = readl(dp->reg_base + EXYNOS_DP_AUX_RX_COMM);
-                       if (reg == AUX_RX_COMM_AUX_DEFER ||
-                               reg == AUX_RX_COMM_I2C_DEFER) {
-                               dev_err(dp->dev, "Defer: %d\n\n", reg);
-                               defer = 1;
-                       }
-               }
-
-               for (cur_data_idx = 0; cur_data_idx < 16; cur_data_idx++) {
-                       reg = readl(dp->reg_base + EXYNOS_DP_BUF_DATA_0
-                                                + 4 * cur_data_idx);
-                       edid[i + cur_data_idx] = (unsigned char)reg;
-               }
-       }
-
-       return retval;
-}
-
-void exynos_dp_set_link_bandwidth(struct exynos_dp_device *dp, u32 bwtype)
-{
-       u32 reg;
-
-       reg = bwtype;
-       if ((bwtype == LINK_RATE_2_70GBPS) || (bwtype == LINK_RATE_1_62GBPS))
-               writel(reg, dp->reg_base + EXYNOS_DP_LINK_BW_SET);
-}
-
-void exynos_dp_get_link_bandwidth(struct exynos_dp_device *dp, u32 *bwtype)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LINK_BW_SET);
-       *bwtype = reg;
-}
-
-void exynos_dp_set_lane_count(struct exynos_dp_device *dp, u32 count)
-{
-       u32 reg;
-
-       reg = count;
-       writel(reg, dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
-}
-
-void exynos_dp_get_lane_count(struct exynos_dp_device *dp, u32 *count)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LANE_COUNT_SET);
-       *count = reg;
-}
-
-void exynos_dp_enable_enhanced_mode(struct exynos_dp_device *dp, bool enable)
-{
-       u32 reg;
-
-       if (enable) {
-               reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-               reg |= ENHANCED;
-               writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-       } else {
-               reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-               reg &= ~ENHANCED;
-               writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-       }
-}
-
-void exynos_dp_set_training_pattern(struct exynos_dp_device *dp,
-                                enum pattern_set pattern)
-{
-       u32 reg;
-
-       switch (pattern) {
-       case PRBS7:
-               reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_PRBS7;
-               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-               break;
-       case D10_2:
-               reg = SCRAMBLING_ENABLE | LINK_QUAL_PATTERN_SET_D10_2;
-               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-               break;
-       case TRAINING_PTN1:
-               reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN1;
-               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-               break;
-       case TRAINING_PTN2:
-               reg = SCRAMBLING_DISABLE | SW_TRAINING_PATTERN_SET_PTN2;
-               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-               break;
-       case DP_NONE:
-               reg = SCRAMBLING_ENABLE |
-                       LINK_QUAL_PATTERN_SET_DISABLE |
-                       SW_TRAINING_PATTERN_SET_NORMAL;
-               writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-               break;
-       default:
-               break;
-       }
-}
-
-void exynos_dp_set_lane0_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-       reg &= ~PRE_EMPHASIS_SET_MASK;
-       reg |= level << PRE_EMPHASIS_SET_SHIFT;
-       writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane1_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-       reg &= ~PRE_EMPHASIS_SET_MASK;
-       reg |= level << PRE_EMPHASIS_SET_SHIFT;
-       writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane2_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-       reg &= ~PRE_EMPHASIS_SET_MASK;
-       reg |= level << PRE_EMPHASIS_SET_SHIFT;
-       writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane3_pre_emphasis(struct exynos_dp_device *dp, u32 level)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-       reg &= ~PRE_EMPHASIS_SET_MASK;
-       reg |= level << PRE_EMPHASIS_SET_SHIFT;
-       writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane0_link_training(struct exynos_dp_device *dp,
-                                       u32 training_lane)
-{
-       u32 reg;
-
-       reg = training_lane;
-       writel(reg, dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane1_link_training(struct exynos_dp_device *dp,
-                                       u32 training_lane)
-{
-       u32 reg;
-
-       reg = training_lane;
-       writel(reg, dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane2_link_training(struct exynos_dp_device *dp,
-                                       u32 training_lane)
-{
-       u32 reg;
-
-       reg = training_lane;
-       writel(reg, dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-}
-
-void exynos_dp_set_lane3_link_training(struct exynos_dp_device *dp,
-                                       u32 training_lane)
-{
-       u32 reg;
-
-       reg = training_lane;
-       writel(reg, dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-}
-
-u32 exynos_dp_get_lane0_link_training(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LN0_LINK_TRAINING_CTL);
-       return reg;
-}
-
-u32 exynos_dp_get_lane1_link_training(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LN1_LINK_TRAINING_CTL);
-       return reg;
-}
-
-u32 exynos_dp_get_lane2_link_training(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LN2_LINK_TRAINING_CTL);
-       return reg;
-}
-
-u32 exynos_dp_get_lane3_link_training(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_LN3_LINK_TRAINING_CTL);
-       return reg;
-}
-
-void exynos_dp_reset_macro(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_PHY_TEST);
-       reg |= MACRO_RST;
-       writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
-
-       /* 10 us is the minimum reset time. */
-       usleep_range(10, 20);
-
-       reg &= ~MACRO_RST;
-       writel(reg, dp->reg_base + EXYNOS_DP_PHY_TEST);
-}
-
-void exynos_dp_init_video(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = VSYNC_DET | VID_FORMAT_CHG | VID_CLK_CHG;
-       writel(reg, dp->reg_base + EXYNOS_DP_COMMON_INT_STA_1);
-
-       reg = 0x0;
-       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-
-       reg = CHA_CRI(4) | CHA_CTRL;
-       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-
-       reg = 0x0;
-       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-
-       reg = VID_HRES_TH(2) | VID_VRES_TH(0);
-       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_8);
-}
-
-void exynos_dp_set_video_color_format(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       /* Configure the input color depth, color space, dynamic range */
-       reg = (dp->video_info->dynamic_range << IN_D_RANGE_SHIFT) |
-               (dp->video_info->color_depth << IN_BPC_SHIFT) |
-               (dp->video_info->color_space << IN_COLOR_F_SHIFT);
-       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_2);
-
-       /* Set Input Color YCbCr Coefficients to ITU601 or ITU709 */
-       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
-       reg &= ~IN_YC_COEFFI_MASK;
-       if (dp->video_info->ycbcr_coeff)
-               reg |= IN_YC_COEFFI_ITU709;
-       else
-               reg |= IN_YC_COEFFI_ITU601;
-       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_3);
-}
-
-int exynos_dp_is_slave_video_stream_clock_on(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-
-       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_1);
-
-       if (!(reg & DET_STA)) {
-               dev_dbg(dp->dev, "Input stream clock not detected.\n");
-               return -EINVAL;
-       }
-
-       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-
-       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_2);
-       dev_dbg(dp->dev, "wait SYS_CTL_2.\n");
-
-       if (reg & CHA_STA) {
-               dev_dbg(dp->dev, "Input stream clk is changing\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-void exynos_dp_set_video_cr_mn(struct exynos_dp_device *dp,
-               enum clock_recovery_m_value_type type,
-               u32 m_value,
-               u32 n_value)
-{
-       u32 reg;
-
-       if (type == REGISTER_M) {
-               reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-               reg |= FIX_M_VID;
-               writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-               reg = m_value & 0xff;
-               writel(reg, dp->reg_base + EXYNOS_DP_M_VID_0);
-               reg = (m_value >> 8) & 0xff;
-               writel(reg, dp->reg_base + EXYNOS_DP_M_VID_1);
-               reg = (m_value >> 16) & 0xff;
-               writel(reg, dp->reg_base + EXYNOS_DP_M_VID_2);
-
-               reg = n_value & 0xff;
-               writel(reg, dp->reg_base + EXYNOS_DP_N_VID_0);
-               reg = (n_value >> 8) & 0xff;
-               writel(reg, dp->reg_base + EXYNOS_DP_N_VID_1);
-               reg = (n_value >> 16) & 0xff;
-               writel(reg, dp->reg_base + EXYNOS_DP_N_VID_2);
-       } else  {
-               reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-               reg &= ~FIX_M_VID;
-               writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_4);
-
-               writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_0);
-               writel(0x80, dp->reg_base + EXYNOS_DP_N_VID_1);
-               writel(0x00, dp->reg_base + EXYNOS_DP_N_VID_2);
-       }
-}
-
-void exynos_dp_set_video_timing_mode(struct exynos_dp_device *dp, u32 type)
-{
-       u32 reg;
-
-       if (type == VIDEO_TIMING_FROM_CAPTURE) {
-               reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-               reg &= ~FORMAT_SEL;
-               writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-       } else {
-               reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-               reg |= FORMAT_SEL;
-               writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-       }
-}
-
-void exynos_dp_enable_video_master(struct exynos_dp_device *dp, bool enable)
-{
-       u32 reg;
-
-       if (enable) {
-               reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-               reg &= ~VIDEO_MODE_MASK;
-               reg |= VIDEO_MASTER_MODE_EN | VIDEO_MODE_MASTER_MODE;
-               writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-       } else {
-               reg = readl(dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-               reg &= ~VIDEO_MODE_MASK;
-               reg |= VIDEO_MODE_SLAVE_MODE;
-               writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-       }
-}
-
-void exynos_dp_start_video(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-       reg |= VIDEO_EN;
-       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_1);
-}
-
-int exynos_dp_is_video_stream_on(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-       writel(reg, dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-
-       reg = readl(dp->reg_base + EXYNOS_DP_SYS_CTL_3);
-       if (!(reg & STRM_VALID)) {
-               dev_dbg(dp->dev, "Input video stream is not detected.\n");
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-void exynos_dp_config_video_slave_mode(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-       reg &= ~(MASTER_VID_FUNC_EN_N|SLAVE_VID_FUNC_EN_N);
-       reg |= MASTER_VID_FUNC_EN_N;
-       writel(reg, dp->reg_base + EXYNOS_DP_FUNC_EN_1);
-
-       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-       reg &= ~INTERACE_SCAN_CFG;
-       reg |= (dp->video_info->interlaced << 2);
-       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-
-       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-       reg &= ~VSYNC_POLARITY_CFG;
-       reg |= (dp->video_info->v_sync_polarity << 1);
-       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-
-       reg = readl(dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-       reg &= ~HSYNC_POLARITY_CFG;
-       reg |= (dp->video_info->h_sync_polarity << 0);
-       writel(reg, dp->reg_base + EXYNOS_DP_VIDEO_CTL_10);
-
-       reg = AUDIO_MODE_SPDIF_MODE | VIDEO_MODE_SLAVE_MODE;
-       writel(reg, dp->reg_base + EXYNOS_DP_SOC_GENERAL_CTL);
-}
-
-void exynos_dp_enable_scrambling(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-       reg &= ~SCRAMBLING_DISABLE;
-       writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-}
-
-void exynos_dp_disable_scrambling(struct exynos_dp_device *dp)
-{
-       u32 reg;
-
-       reg = readl(dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-       reg |= SCRAMBLING_DISABLE;
-       writel(reg, dp->reg_base + EXYNOS_DP_TRAINING_PTN_SET);
-}
diff --git a/drivers/video/exynos/exynos_dp_reg.h b/drivers/video/exynos/exynos_dp_reg.h
deleted file mode 100644 (file)
index 2e9bd0e..0000000
+++ /dev/null
@@ -1,366 +0,0 @@
-/*
- * Register definition file for Samsung DP driver
- *
- * Copyright (C) 2012 Samsung Electronics Co., Ltd.
- * Author: Jingoo Han <jg1.han@samsung.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 _EXYNOS_DP_REG_H
-#define _EXYNOS_DP_REG_H
-
-#define EXYNOS_DP_TX_SW_RESET                  0x14
-#define EXYNOS_DP_FUNC_EN_1                    0x18
-#define EXYNOS_DP_FUNC_EN_2                    0x1C
-#define EXYNOS_DP_VIDEO_CTL_1                  0x20
-#define EXYNOS_DP_VIDEO_CTL_2                  0x24
-#define EXYNOS_DP_VIDEO_CTL_3                  0x28
-
-#define EXYNOS_DP_VIDEO_CTL_8                  0x3C
-#define EXYNOS_DP_VIDEO_CTL_10                 0x44
-
-#define EXYNOS_DP_LANE_MAP                     0x35C
-
-#define EXYNOS_DP_ANALOG_CTL_1                 0x370
-#define EXYNOS_DP_ANALOG_CTL_2                 0x374
-#define EXYNOS_DP_ANALOG_CTL_3                 0x378
-#define EXYNOS_DP_PLL_FILTER_CTL_1             0x37C
-#define EXYNOS_DP_TX_AMP_TUNING_CTL            0x380
-
-#define EXYNOS_DP_AUX_HW_RETRY_CTL             0x390
-
-#define EXYNOS_DP_COMMON_INT_STA_1             0x3C4
-#define EXYNOS_DP_COMMON_INT_STA_2             0x3C8
-#define EXYNOS_DP_COMMON_INT_STA_3             0x3CC
-#define EXYNOS_DP_COMMON_INT_STA_4             0x3D0
-#define EXYNOS_DP_INT_STA                      0x3DC
-#define EXYNOS_DP_COMMON_INT_MASK_1            0x3E0
-#define EXYNOS_DP_COMMON_INT_MASK_2            0x3E4
-#define EXYNOS_DP_COMMON_INT_MASK_3            0x3E8
-#define EXYNOS_DP_COMMON_INT_MASK_4            0x3EC
-#define EXYNOS_DP_INT_STA_MASK                 0x3F8
-#define EXYNOS_DP_INT_CTL                      0x3FC
-
-#define EXYNOS_DP_SYS_CTL_1                    0x600
-#define EXYNOS_DP_SYS_CTL_2                    0x604
-#define EXYNOS_DP_SYS_CTL_3                    0x608
-#define EXYNOS_DP_SYS_CTL_4                    0x60C
-
-#define EXYNOS_DP_PKT_SEND_CTL                 0x640
-#define EXYNOS_DP_HDCP_CTL                     0x648
-
-#define EXYNOS_DP_LINK_BW_SET                  0x680
-#define EXYNOS_DP_LANE_COUNT_SET               0x684
-#define EXYNOS_DP_TRAINING_PTN_SET             0x688
-#define EXYNOS_DP_LN0_LINK_TRAINING_CTL                0x68C
-#define EXYNOS_DP_LN1_LINK_TRAINING_CTL                0x690
-#define EXYNOS_DP_LN2_LINK_TRAINING_CTL                0x694
-#define EXYNOS_DP_LN3_LINK_TRAINING_CTL                0x698
-
-#define EXYNOS_DP_DEBUG_CTL                    0x6C0
-#define EXYNOS_DP_HPD_DEGLITCH_L               0x6C4
-#define EXYNOS_DP_HPD_DEGLITCH_H               0x6C8
-#define EXYNOS_DP_LINK_DEBUG_CTL               0x6E0
-
-#define EXYNOS_DP_M_VID_0                      0x700
-#define EXYNOS_DP_M_VID_1                      0x704
-#define EXYNOS_DP_M_VID_2                      0x708
-#define EXYNOS_DP_N_VID_0                      0x70C
-#define EXYNOS_DP_N_VID_1                      0x710
-#define EXYNOS_DP_N_VID_2                      0x714
-
-#define EXYNOS_DP_PLL_CTL                      0x71C
-#define EXYNOS_DP_PHY_PD                       0x720
-#define EXYNOS_DP_PHY_TEST                     0x724
-
-#define EXYNOS_DP_VIDEO_FIFO_THRD              0x730
-#define EXYNOS_DP_AUDIO_MARGIN                 0x73C
-
-#define EXYNOS_DP_M_VID_GEN_FILTER_TH          0x764
-#define EXYNOS_DP_M_AUD_GEN_FILTER_TH          0x778
-#define EXYNOS_DP_AUX_CH_STA                   0x780
-#define EXYNOS_DP_AUX_CH_DEFER_CTL             0x788
-#define EXYNOS_DP_AUX_RX_COMM                  0x78C
-#define EXYNOS_DP_BUFFER_DATA_CTL              0x790
-#define EXYNOS_DP_AUX_CH_CTL_1                 0x794
-#define EXYNOS_DP_AUX_ADDR_7_0                 0x798
-#define EXYNOS_DP_AUX_ADDR_15_8                        0x79C
-#define EXYNOS_DP_AUX_ADDR_19_16               0x7A0
-#define EXYNOS_DP_AUX_CH_CTL_2                 0x7A4
-
-#define EXYNOS_DP_BUF_DATA_0                   0x7C0
-
-#define EXYNOS_DP_SOC_GENERAL_CTL              0x800
-
-/* EXYNOS_DP_TX_SW_RESET */
-#define RESET_DP_TX                            (0x1 << 0)
-
-/* EXYNOS_DP_FUNC_EN_1 */
-#define MASTER_VID_FUNC_EN_N                   (0x1 << 7)
-#define SLAVE_VID_FUNC_EN_N                    (0x1 << 5)
-#define AUD_FIFO_FUNC_EN_N                     (0x1 << 4)
-#define AUD_FUNC_EN_N                          (0x1 << 3)
-#define HDCP_FUNC_EN_N                         (0x1 << 2)
-#define CRC_FUNC_EN_N                          (0x1 << 1)
-#define SW_FUNC_EN_N                           (0x1 << 0)
-
-/* EXYNOS_DP_FUNC_EN_2 */
-#define SSC_FUNC_EN_N                          (0x1 << 7)
-#define AUX_FUNC_EN_N                          (0x1 << 2)
-#define SERDES_FIFO_FUNC_EN_N                  (0x1 << 1)
-#define LS_CLK_DOMAIN_FUNC_EN_N                        (0x1 << 0)
-
-/* EXYNOS_DP_VIDEO_CTL_1 */
-#define VIDEO_EN                               (0x1 << 7)
-#define HDCP_VIDEO_MUTE                                (0x1 << 6)
-
-/* EXYNOS_DP_VIDEO_CTL_1 */
-#define IN_D_RANGE_MASK                                (0x1 << 7)
-#define IN_D_RANGE_SHIFT                       (7)
-#define IN_D_RANGE_CEA                         (0x1 << 7)
-#define IN_D_RANGE_VESA                                (0x0 << 7)
-#define IN_BPC_MASK                            (0x7 << 4)
-#define IN_BPC_SHIFT                           (4)
-#define IN_BPC_12_BITS                         (0x3 << 4)
-#define IN_BPC_10_BITS                         (0x2 << 4)
-#define IN_BPC_8_BITS                          (0x1 << 4)
-#define IN_BPC_6_BITS                          (0x0 << 4)
-#define IN_COLOR_F_MASK                                (0x3 << 0)
-#define IN_COLOR_F_SHIFT                       (0)
-#define IN_COLOR_F_YCBCR444                    (0x2 << 0)
-#define IN_COLOR_F_YCBCR422                    (0x1 << 0)
-#define IN_COLOR_F_RGB                         (0x0 << 0)
-
-/* EXYNOS_DP_VIDEO_CTL_3 */
-#define IN_YC_COEFFI_MASK                      (0x1 << 7)
-#define IN_YC_COEFFI_SHIFT                     (7)
-#define IN_YC_COEFFI_ITU709                    (0x1 << 7)
-#define IN_YC_COEFFI_ITU601                    (0x0 << 7)
-#define VID_CHK_UPDATE_TYPE_MASK               (0x1 << 4)
-#define VID_CHK_UPDATE_TYPE_SHIFT              (4)
-#define VID_CHK_UPDATE_TYPE_1                  (0x1 << 4)
-#define VID_CHK_UPDATE_TYPE_0                  (0x0 << 4)
-
-/* EXYNOS_DP_VIDEO_CTL_8 */
-#define VID_HRES_TH(x)                         (((x) & 0xf) << 4)
-#define VID_VRES_TH(x)                         (((x) & 0xf) << 0)
-
-/* EXYNOS_DP_VIDEO_CTL_10 */
-#define FORMAT_SEL                             (0x1 << 4)
-#define INTERACE_SCAN_CFG                      (0x1 << 2)
-#define VSYNC_POLARITY_CFG                     (0x1 << 1)
-#define HSYNC_POLARITY_CFG                     (0x1 << 0)
-
-/* EXYNOS_DP_LANE_MAP */
-#define LANE3_MAP_LOGIC_LANE_0                 (0x0 << 6)
-#define LANE3_MAP_LOGIC_LANE_1                 (0x1 << 6)
-#define LANE3_MAP_LOGIC_LANE_2                 (0x2 << 6)
-#define LANE3_MAP_LOGIC_LANE_3                 (0x3 << 6)
-#define LANE2_MAP_LOGIC_LANE_0                 (0x0 << 4)
-#define LANE2_MAP_LOGIC_LANE_1                 (0x1 << 4)
-#define LANE2_MAP_LOGIC_LANE_2                 (0x2 << 4)
-#define LANE2_MAP_LOGIC_LANE_3                 (0x3 << 4)
-#define LANE1_MAP_LOGIC_LANE_0                 (0x0 << 2)
-#define LANE1_MAP_LOGIC_LANE_1                 (0x1 << 2)
-#define LANE1_MAP_LOGIC_LANE_2                 (0x2 << 2)
-#define LANE1_MAP_LOGIC_LANE_3                 (0x3 << 2)
-#define LANE0_MAP_LOGIC_LANE_0                 (0x0 << 0)
-#define LANE0_MAP_LOGIC_LANE_1                 (0x1 << 0)
-#define LANE0_MAP_LOGIC_LANE_2                 (0x2 << 0)
-#define LANE0_MAP_LOGIC_LANE_3                 (0x3 << 0)
-
-/* EXYNOS_DP_ANALOG_CTL_1 */
-#define TX_TERMINAL_CTRL_50_OHM                        (0x1 << 4)
-
-/* EXYNOS_DP_ANALOG_CTL_2 */
-#define SEL_24M                                        (0x1 << 3)
-#define TX_DVDD_BIT_1_0625V                    (0x4 << 0)
-
-/* EXYNOS_DP_ANALOG_CTL_3 */
-#define DRIVE_DVDD_BIT_1_0625V                 (0x4 << 5)
-#define VCO_BIT_600_MICRO                      (0x5 << 0)
-
-/* EXYNOS_DP_PLL_FILTER_CTL_1 */
-#define PD_RING_OSC                            (0x1 << 6)
-#define AUX_TERMINAL_CTRL_50_OHM               (0x2 << 4)
-#define TX_CUR1_2X                             (0x1 << 2)
-#define TX_CUR_16_MA                           (0x3 << 0)
-
-/* EXYNOS_DP_TX_AMP_TUNING_CTL */
-#define CH3_AMP_400_MV                         (0x0 << 24)
-#define CH2_AMP_400_MV                         (0x0 << 16)
-#define CH1_AMP_400_MV                         (0x0 << 8)
-#define CH0_AMP_400_MV                         (0x0 << 0)
-
-/* EXYNOS_DP_AUX_HW_RETRY_CTL */
-#define AUX_BIT_PERIOD_EXPECTED_DELAY(x)       (((x) & 0x7) << 8)
-#define AUX_HW_RETRY_INTERVAL_MASK             (0x3 << 3)
-#define AUX_HW_RETRY_INTERVAL_600_MICROSECONDS (0x0 << 3)
-#define AUX_HW_RETRY_INTERVAL_800_MICROSECONDS (0x1 << 3)
-#define AUX_HW_RETRY_INTERVAL_1000_MICROSECONDS        (0x2 << 3)
-#define AUX_HW_RETRY_INTERVAL_1800_MICROSECONDS        (0x3 << 3)
-#define AUX_HW_RETRY_COUNT_SEL(x)              (((x) & 0x7) << 0)
-
-/* EXYNOS_DP_COMMON_INT_STA_1 */
-#define VSYNC_DET                              (0x1 << 7)
-#define PLL_LOCK_CHG                           (0x1 << 6)
-#define SPDIF_ERR                              (0x1 << 5)
-#define SPDIF_UNSTBL                           (0x1 << 4)
-#define VID_FORMAT_CHG                         (0x1 << 3)
-#define AUD_CLK_CHG                            (0x1 << 2)
-#define VID_CLK_CHG                            (0x1 << 1)
-#define SW_INT                                 (0x1 << 0)
-
-/* EXYNOS_DP_COMMON_INT_STA_2 */
-#define ENC_EN_CHG                             (0x1 << 6)
-#define HW_BKSV_RDY                            (0x1 << 3)
-#define HW_SHA_DONE                            (0x1 << 2)
-#define HW_AUTH_STATE_CHG                      (0x1 << 1)
-#define HW_AUTH_DONE                           (0x1 << 0)
-
-/* EXYNOS_DP_COMMON_INT_STA_3 */
-#define AFIFO_UNDER                            (0x1 << 7)
-#define AFIFO_OVER                             (0x1 << 6)
-#define R0_CHK_FLAG                            (0x1 << 5)
-
-/* EXYNOS_DP_COMMON_INT_STA_4 */
-#define PSR_ACTIVE                             (0x1 << 7)
-#define PSR_INACTIVE                           (0x1 << 6)
-#define SPDIF_BI_PHASE_ERR                     (0x1 << 5)
-#define HOTPLUG_CHG                            (0x1 << 2)
-#define HPD_LOST                               (0x1 << 1)
-#define PLUG                                   (0x1 << 0)
-
-/* EXYNOS_DP_INT_STA */
-#define INT_HPD                                        (0x1 << 6)
-#define HW_TRAINING_FINISH                     (0x1 << 5)
-#define RPLY_RECEIV                            (0x1 << 1)
-#define AUX_ERR                                        (0x1 << 0)
-
-/* EXYNOS_DP_INT_CTL */
-#define SOFT_INT_CTRL                          (0x1 << 2)
-#define INT_POL1                               (0x1 << 1)
-#define INT_POL0                               (0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_1 */
-#define DET_STA                                        (0x1 << 2)
-#define FORCE_DET                              (0x1 << 1)
-#define DET_CTRL                               (0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_2 */
-#define CHA_CRI(x)                             (((x) & 0xf) << 4)
-#define CHA_STA                                        (0x1 << 2)
-#define FORCE_CHA                              (0x1 << 1)
-#define CHA_CTRL                               (0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_3 */
-#define HPD_STATUS                             (0x1 << 6)
-#define F_HPD                                  (0x1 << 5)
-#define HPD_CTRL                               (0x1 << 4)
-#define HDCP_RDY                               (0x1 << 3)
-#define STRM_VALID                             (0x1 << 2)
-#define F_VALID                                        (0x1 << 1)
-#define VALID_CTRL                             (0x1 << 0)
-
-/* EXYNOS_DP_SYS_CTL_4 */
-#define FIX_M_AUD                              (0x1 << 4)
-#define ENHANCED                               (0x1 << 3)
-#define FIX_M_VID                              (0x1 << 2)
-#define M_VID_UPDATE_CTRL                      (0x3 << 0)
-
-/* EXYNOS_DP_TRAINING_PTN_SET */
-#define SCRAMBLER_TYPE                         (0x1 << 9)
-#define HW_LINK_TRAINING_PATTERN               (0x1 << 8)
-#define SCRAMBLING_DISABLE                     (0x1 << 5)
-#define SCRAMBLING_ENABLE                      (0x0 << 5)
-#define LINK_QUAL_PATTERN_SET_MASK             (0x3 << 2)
-#define LINK_QUAL_PATTERN_SET_PRBS7            (0x3 << 2)
-#define LINK_QUAL_PATTERN_SET_D10_2            (0x1 << 2)
-#define LINK_QUAL_PATTERN_SET_DISABLE          (0x0 << 2)
-#define SW_TRAINING_PATTERN_SET_MASK           (0x3 << 0)
-#define SW_TRAINING_PATTERN_SET_PTN2           (0x2 << 0)
-#define SW_TRAINING_PATTERN_SET_PTN1           (0x1 << 0)
-#define SW_TRAINING_PATTERN_SET_NORMAL         (0x0 << 0)
-
-/* EXYNOS_DP_LN0_LINK_TRAINING_CTL */
-#define PRE_EMPHASIS_SET_MASK                  (0x3 << 3)
-#define PRE_EMPHASIS_SET_SHIFT                 (3)
-
-/* EXYNOS_DP_DEBUG_CTL */
-#define PLL_LOCK                               (0x1 << 4)
-#define F_PLL_LOCK                             (0x1 << 3)
-#define PLL_LOCK_CTRL                          (0x1 << 2)
-#define PN_INV                                 (0x1 << 0)
-
-/* EXYNOS_DP_PLL_CTL */
-#define DP_PLL_PD                              (0x1 << 7)
-#define DP_PLL_RESET                           (0x1 << 6)
-#define DP_PLL_LOOP_BIT_DEFAULT                        (0x1 << 4)
-#define DP_PLL_REF_BIT_1_1250V                 (0x5 << 0)
-#define DP_PLL_REF_BIT_1_2500V                 (0x7 << 0)
-
-/* EXYNOS_DP_PHY_PD */
-#define DP_PHY_PD                              (0x1 << 5)
-#define AUX_PD                                 (0x1 << 4)
-#define CH3_PD                                 (0x1 << 3)
-#define CH2_PD                                 (0x1 << 2)
-#define CH1_PD                                 (0x1 << 1)
-#define CH0_PD                                 (0x1 << 0)
-
-/* EXYNOS_DP_PHY_TEST */
-#define MACRO_RST                              (0x1 << 5)
-#define CH1_TEST                               (0x1 << 1)
-#define CH0_TEST                               (0x1 << 0)
-
-/* EXYNOS_DP_AUX_CH_STA */
-#define AUX_BUSY                               (0x1 << 4)
-#define AUX_STATUS_MASK                                (0xf << 0)
-
-/* EXYNOS_DP_AUX_CH_DEFER_CTL */
-#define DEFER_CTRL_EN                          (0x1 << 7)
-#define DEFER_COUNT(x)                         (((x) & 0x7f) << 0)
-
-/* EXYNOS_DP_AUX_RX_COMM */
-#define AUX_RX_COMM_I2C_DEFER                  (0x2 << 2)
-#define AUX_RX_COMM_AUX_DEFER                  (0x2 << 0)
-
-/* EXYNOS_DP_BUFFER_DATA_CTL */
-#define BUF_CLR                                        (0x1 << 7)
-#define BUF_DATA_COUNT(x)                      (((x) & 0x1f) << 0)
-
-/* EXYNOS_DP_AUX_CH_CTL_1 */
-#define AUX_LENGTH(x)                          (((x - 1) & 0xf) << 4)
-#define AUX_TX_COMM_MASK                       (0xf << 0)
-#define AUX_TX_COMM_DP_TRANSACTION             (0x1 << 3)
-#define AUX_TX_COMM_I2C_TRANSACTION            (0x0 << 3)
-#define AUX_TX_COMM_MOT                                (0x1 << 2)
-#define AUX_TX_COMM_WRITE                      (0x0 << 0)
-#define AUX_TX_COMM_READ                       (0x1 << 0)
-
-/* EXYNOS_DP_AUX_ADDR_7_0 */
-#define AUX_ADDR_7_0(x)                                (((x) >> 0) & 0xff)
-
-/* EXYNOS_DP_AUX_ADDR_15_8 */
-#define AUX_ADDR_15_8(x)                       (((x) >> 8) & 0xff)
-
-/* EXYNOS_DP_AUX_ADDR_19_16 */
-#define AUX_ADDR_19_16(x)                      (((x) >> 16) & 0x0f)
-
-/* EXYNOS_DP_AUX_CH_CTL_2 */
-#define ADDR_ONLY                              (0x1 << 1)
-#define AUX_EN                                 (0x1 << 0)
-
-/* EXYNOS_DP_SOC_GENERAL_CTL */
-#define AUDIO_MODE_SPDIF_MODE                  (0x1 << 8)
-#define AUDIO_MODE_MASTER_MODE                 (0x0 << 8)
-#define MASTER_VIDEO_INTERLACE_EN              (0x1 << 4)
-#define VIDEO_MASTER_CLK_SEL                   (0x1 << 2)
-#define VIDEO_MASTER_MODE_EN                   (0x1 << 1)
-#define VIDEO_MODE_MASK                                (0x1 << 0)
-#define VIDEO_MODE_SLAVE_MODE                  (0x1 << 0)
-#define VIDEO_MODE_MASTER_MODE                 (0x0 << 0)
-
-#endif /* _EXYNOS_DP_REG_H */
index 27f33ef..5ee3b55 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 
 #include <video/omapdss.h>
 #include <video/omap-panel-data.h>
@@ -42,6 +43,12 @@ static const struct omap_video_timings tvc_pal_timings = {
        .interlace      = true,
 };
 
+static const struct of_device_id tvc_of_match[];
+
+struct tvc_of_data {
+       enum omap_dss_venc_type connector_type;
+};
+
 #define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
 
 static int tvc_connect(struct omap_dss_device *dssdev)
@@ -91,8 +98,12 @@ static int tvc_enable(struct omap_dss_device *dssdev)
 
        in->ops.atv->set_timings(in, &ddata->timings);
 
-       in->ops.atv->set_type(in, ddata->connector_type);
-       in->ops.atv->invert_vid_out_polarity(in, ddata->invert_polarity);
+       if (!ddata->dev->of_node) {
+               in->ops.atv->set_type(in, ddata->connector_type);
+
+               in->ops.atv->invert_vid_out_polarity(in,
+                       ddata->invert_polarity);
+       }
 
        r = in->ops.atv->enable(in);
        if (r)
@@ -205,6 +216,23 @@ static int tvc_probe_pdata(struct platform_device *pdev)
        return 0;
 }
 
+static int tvc_probe_of(struct platform_device *pdev)
+{
+       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct device_node *node = pdev->dev.of_node;
+       struct omap_dss_device *in;
+
+       in = omapdss_of_find_source_for_first_ep(node);
+       if (IS_ERR(in)) {
+               dev_err(&pdev->dev, "failed to find video source\n");
+               return PTR_ERR(in);
+       }
+
+       ddata->in = in;
+
+       return 0;
+}
+
 static int tvc_probe(struct platform_device *pdev)
 {
        struct panel_drv_data *ddata;
@@ -222,6 +250,10 @@ static int tvc_probe(struct platform_device *pdev)
                r = tvc_probe_pdata(pdev);
                if (r)
                        return r;
+       } else if (pdev->dev.of_node) {
+               r = tvc_probe_of(pdev);
+               if (r)
+                       return r;
        } else {
                return -ENODEV;
        }
@@ -263,12 +295,19 @@ static int __exit tvc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id tvc_of_match[] = {
+       { .compatible = "omapdss,svideo-connector", },
+       { .compatible = "omapdss,composite-video-connector", },
+       {},
+};
+
 static struct platform_driver tvc_connector_driver = {
        .probe  = tvc_probe,
        .remove = __exit_p(tvc_remove),
        .driver = {
                .name   = "connector-analog-tv",
                .owner  = THIS_MODULE,
+               .of_match_table = tvc_of_match,
        },
 };
 
index d18e4b8..74de2bc 100644 (file)
@@ -277,6 +277,37 @@ static int dvic_probe_pdata(struct platform_device *pdev)
        return 0;
 }
 
+static int dvic_probe_of(struct platform_device *pdev)
+{
+       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct device_node *node = pdev->dev.of_node;
+       struct omap_dss_device *in;
+       struct device_node *adapter_node;
+       struct i2c_adapter *adapter;
+
+       in = omapdss_of_find_source_for_first_ep(node);
+       if (IS_ERR(in)) {
+               dev_err(&pdev->dev, "failed to find video source\n");
+               return PTR_ERR(in);
+       }
+
+       ddata->in = in;
+
+       adapter_node = of_parse_phandle(node, "ddc-i2c-bus", 0);
+       if (adapter_node) {
+               adapter = of_find_i2c_adapter_by_node(adapter_node);
+               if (adapter == NULL) {
+                       dev_err(&pdev->dev, "failed to parse ddc-i2c-bus\n");
+                       omap_dss_put_device(ddata->in);
+                       return -EPROBE_DEFER;
+               }
+
+               ddata->i2c_adapter = adapter;
+       }
+
+       return 0;
+}
+
 static int dvic_probe(struct platform_device *pdev)
 {
        struct panel_drv_data *ddata;
@@ -293,6 +324,10 @@ static int dvic_probe(struct platform_device *pdev)
                r = dvic_probe_pdata(pdev);
                if (r)
                        return r;
+       } else if (pdev->dev.of_node) {
+               r = dvic_probe_of(pdev);
+               if (r)
+                       return r;
        } else {
                return -ENODEV;
        }
@@ -342,12 +377,20 @@ static int __exit dvic_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id dvic_of_match[] = {
+       { .compatible = "omapdss,dvi-connector", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, dvic_of_match);
+
 static struct platform_driver dvi_connector_driver = {
        .probe  = dvic_probe,
        .remove = __exit_p(dvic_remove),
        .driver = {
                .name   = "connector-dvi",
                .owner  = THIS_MODULE,
+               .of_match_table = dvic_of_match,
        },
 };
 
index 9393e2d..29ed21b 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 
 #include <drm/drm_edid.h>
 
@@ -301,6 +302,23 @@ static int hdmic_probe_pdata(struct platform_device *pdev)
        return 0;
 }
 
+static int hdmic_probe_of(struct platform_device *pdev)
+{
+       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct device_node *node = pdev->dev.of_node;
+       struct omap_dss_device *in;
+
+       in = omapdss_of_find_source_for_first_ep(node);
+       if (IS_ERR(in)) {
+               dev_err(&pdev->dev, "failed to find video source\n");
+               return PTR_ERR(in);
+       }
+
+       ddata->in = in;
+
+       return 0;
+}
+
 static int hdmic_probe(struct platform_device *pdev)
 {
        struct panel_drv_data *ddata;
@@ -318,6 +336,10 @@ static int hdmic_probe(struct platform_device *pdev)
                r = hdmic_probe_pdata(pdev);
                if (r)
                        return r;
+       } else if (pdev->dev.of_node) {
+               r = hdmic_probe_of(pdev);
+               if (r)
+                       return r;
        } else {
                return -ENODEV;
        }
@@ -359,12 +381,20 @@ static int __exit hdmic_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id hdmic_of_match[] = {
+       { .compatible = "omapdss,hdmi-connector", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, hdmic_of_match);
+
 static struct platform_driver hdmi_connector_driver = {
        .probe  = hdmic_probe,
        .remove = __exit_p(hdmic_remove),
        .driver = {
                .name   = "connector-hdmi",
                .owner  = THIS_MODULE,
+               .of_match_table = hdmic_of_match,
        },
 };
 
index 4a291e7..b4e9a42 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/of_gpio.h>
 
 #include <video/omapdss.h>
 #include <video/omap-panel-data.h>
@@ -82,7 +83,8 @@ static int tfp410_enable(struct omap_dss_device *dssdev)
                return 0;
 
        in->ops.dpi->set_timings(in, &ddata->timings);
-       in->ops.dpi->set_data_lines(in, ddata->data_lines);
+       if (ddata->data_lines)
+               in->ops.dpi->set_data_lines(in, ddata->data_lines);
 
        r = in->ops.dpi->enable(in);
        if (r)
@@ -179,6 +181,33 @@ static int tfp410_probe_pdata(struct platform_device *pdev)
        return 0;
 }
 
+static int tfp410_probe_of(struct platform_device *pdev)
+{
+       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct device_node *node = pdev->dev.of_node;
+       struct omap_dss_device *in;
+       int gpio;
+
+       gpio = of_get_named_gpio(node, "powerdown-gpios", 0);
+
+       if (gpio_is_valid(gpio) || gpio == -ENOENT) {
+               ddata->pd_gpio = gpio;
+       } else {
+               dev_err(&pdev->dev, "failed to parse PD gpio\n");
+               return gpio;
+       }
+
+       in = omapdss_of_find_source_for_first_ep(node);
+       if (IS_ERR(in)) {
+               dev_err(&pdev->dev, "failed to find video source\n");
+               return PTR_ERR(in);
+       }
+
+       ddata->in = in;
+
+       return 0;
+}
+
 static int tfp410_probe(struct platform_device *pdev)
 {
        struct panel_drv_data *ddata;
@@ -195,6 +224,10 @@ static int tfp410_probe(struct platform_device *pdev)
                r = tfp410_probe_pdata(pdev);
                if (r)
                        return r;
+       } else if (pdev->dev.of_node) {
+               r = tfp410_probe_of(pdev);
+               if (r)
+                       return r;
        } else {
                return -ENODEV;
        }
@@ -251,12 +284,20 @@ static int __exit tfp410_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id tfp410_of_match[] = {
+       { .compatible = "omapdss,ti,tfp410", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, tfp410_of_match);
+
 static struct platform_driver tfp410_driver = {
        .probe  = tfp410_probe,
        .remove = __exit_p(tfp410_remove),
        .driver = {
                .name   = "tfp410",
                .owner  = THIS_MODULE,
+               .of_match_table = tfp410_of_match,
        },
 };
 
index d5c936c..7e33686 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/gpio.h>
 #include <linux/platform_device.h>
+#include <linux/of_gpio.h>
 
 #include <video/omapdss.h>
 #include <video/omap-panel-data.h>
@@ -289,6 +290,49 @@ static int tpd_probe_pdata(struct platform_device *pdev)
        return 0;
 }
 
+static int tpd_probe_of(struct platform_device *pdev)
+{
+       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct device_node *node = pdev->dev.of_node;
+       struct omap_dss_device *in;
+       int gpio;
+
+       /* CT CP HPD GPIO */
+       gpio = of_get_gpio(node, 0);
+       if (!gpio_is_valid(gpio)) {
+               dev_err(&pdev->dev, "failed to parse CT CP HPD gpio\n");
+               return gpio;
+       }
+       ddata->ct_cp_hpd_gpio = gpio;
+
+       /* LS OE GPIO */
+       gpio = of_get_gpio(node, 1);
+       if (gpio_is_valid(gpio) || gpio == -ENOENT) {
+               ddata->ls_oe_gpio = gpio;
+       } else {
+               dev_err(&pdev->dev, "failed to parse LS OE gpio\n");
+               return gpio;
+       }
+
+       /* HPD GPIO */
+       gpio = of_get_gpio(node, 2);
+       if (!gpio_is_valid(gpio)) {
+               dev_err(&pdev->dev, "failed to parse HPD gpio\n");
+               return gpio;
+       }
+       ddata->hpd_gpio = gpio;
+
+       in = omapdss_of_find_source_for_first_ep(node);
+       if (IS_ERR(in)) {
+               dev_err(&pdev->dev, "failed to find video source\n");
+               return PTR_ERR(in);
+       }
+
+       ddata->in = in;
+
+       return 0;
+}
+
 static int tpd_probe(struct platform_device *pdev)
 {
        struct omap_dss_device *in, *dssdev;
@@ -307,6 +351,10 @@ static int tpd_probe(struct platform_device *pdev)
                r = tpd_probe_pdata(pdev);
                if (r)
                        return r;
+       } else if (pdev->dev.of_node) {
+               r = tpd_probe_of(pdev);
+               if (r)
+                       return r;
        } else {
                return -ENODEV;
        }
@@ -379,12 +427,20 @@ static int __exit tpd_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id tpd_of_match[] = {
+       { .compatible = "omapdss,ti,tpd12s015", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, tpd_of_match);
+
 static struct platform_driver tpd_driver = {
        .probe  = tpd_probe,
        .remove = __exit_p(tpd_remove),
        .driver = {
                .name   = "tpd12s015",
                .owner  = THIS_MODULE,
+               .of_match_table = tpd_of_match,
        },
 };
 
index f317c87..d6f14e8 100644 (file)
@@ -22,6 +22,8 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
+#include <linux/of_device.h>
+#include <linux/of_gpio.h>
 
 #include <video/omapdss.h>
 #include <video/omap-panel-data.h>
@@ -595,10 +597,13 @@ static int dsicm_power_on(struct panel_drv_data *ddata)
                .lp_clk_max = 10000000,
        };
 
-       r = in->ops.dsi->configure_pins(in, &ddata->pin_config);
-       if (r) {
-               dev_err(&ddata->pdev->dev, "failed to configure DSI pins\n");
-               goto err0;
+       if (ddata->pin_config.num_pins > 0) {
+               r = in->ops.dsi->configure_pins(in, &ddata->pin_config);
+               if (r) {
+                       dev_err(&ddata->pdev->dev,
+                               "failed to configure DSI pins\n");
+                       goto err0;
+               }
        }
 
        r = in->ops.dsi->set_config(in, &dsi_config);
@@ -1156,6 +1161,41 @@ static int dsicm_probe_pdata(struct platform_device *pdev)
        return 0;
 }
 
+static int dsicm_probe_of(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+       struct omap_dss_device *in;
+       int gpio;
+
+       gpio = of_get_named_gpio(node, "reset-gpios", 0);
+       if (!gpio_is_valid(gpio)) {
+               dev_err(&pdev->dev, "failed to parse reset gpio\n");
+               return gpio;
+       }
+       ddata->reset_gpio = gpio;
+
+       gpio = of_get_named_gpio(node, "te-gpios", 0);
+       if (gpio_is_valid(gpio) || gpio == -ENOENT) {
+               ddata->ext_te_gpio = gpio;
+       } else {
+               dev_err(&pdev->dev, "failed to parse TE gpio\n");
+               return gpio;
+       }
+
+       in = omapdss_of_find_source_for_first_ep(node);
+       if (IS_ERR(in)) {
+               dev_err(&pdev->dev, "failed to find video source\n");
+               return PTR_ERR(in);
+       }
+
+       ddata->in = in;
+
+       /* TODO: ulps, backlight */
+
+       return 0;
+}
+
 static int dsicm_probe(struct platform_device *pdev)
 {
        struct backlight_properties props;
@@ -1178,6 +1218,10 @@ static int dsicm_probe(struct platform_device *pdev)
                r = dsicm_probe_pdata(pdev);
                if (r)
                        return r;
+       } else if (pdev->dev.of_node) {
+               r = dsicm_probe_of(pdev);
+               if (r)
+                       return r;
        } else {
                return -ENODEV;
        }
@@ -1320,12 +1364,20 @@ static int __exit dsicm_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id dsicm_of_match[] = {
+       { .compatible = "omapdss,panel-dsi-cm", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, dsicm_of_match);
+
 static struct platform_driver dsicm_driver = {
        .probe = dsicm_probe,
        .remove = __exit_p(dsicm_remove),
        .driver = {
                .name = "panel-dsi-cm",
                .owner = THIS_MODULE,
+               .of_match_table = dsicm_of_match,
        },
 };
 
index 27f60ad..c7ba4d8 100644 (file)
@@ -30,6 +30,8 @@
 #include <linux/backlight.h>
 #include <linux/fb.h>
 #include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
 
 #include <video/omapdss.h>
 #include <video/omap-panel-data.h>
@@ -547,7 +549,9 @@ static int acx565akm_panel_power_on(struct omap_dss_device *dssdev)
        dev_dbg(&ddata->spi->dev, "%s\n", __func__);
 
        in->ops.sdi->set_timings(in, &ddata->videomode);
-       in->ops.sdi->set_datapairs(in, ddata->datapairs);
+
+       if (ddata->datapairs > 0)
+               in->ops.sdi->set_datapairs(in, ddata->datapairs);
 
        r = in->ops.sdi->enable(in);
        if (r) {
@@ -726,6 +730,22 @@ static int acx565akm_probe_pdata(struct spi_device *spi)
        return 0;
 }
 
+static int acx565akm_probe_of(struct spi_device *spi)
+{
+       struct panel_drv_data *ddata = dev_get_drvdata(&spi->dev);
+       struct device_node *np = spi->dev.of_node;
+
+       ddata->reset_gpio = of_get_named_gpio(np, "reset-gpios", 0);
+
+       ddata->in = omapdss_of_find_source_for_first_ep(np);
+       if (IS_ERR(ddata->in)) {
+               dev_err(&spi->dev, "failed to find video source\n");
+               return PTR_ERR(ddata->in);
+       }
+
+       return 0;
+}
+
 static int acx565akm_probe(struct spi_device *spi)
 {
        struct panel_drv_data *ddata;
@@ -753,7 +773,12 @@ static int acx565akm_probe(struct spi_device *spi)
                r = acx565akm_probe_pdata(spi);
                if (r)
                        return r;
+       } else if (spi->dev.of_node) {
+               r = acx565akm_probe_of(spi);
+               if (r)
+                       return r;
        } else {
+               dev_err(&spi->dev, "platform data missing!\n");
                return -ENODEV;
        }
 
@@ -864,10 +889,16 @@ static int acx565akm_remove(struct spi_device *spi)
        return 0;
 }
 
+static const struct of_device_id acx565akm_of_match[] = {
+       { .compatible = "omapdss,sony,acx565akm", },
+       {},
+};
+
 static struct spi_driver acx565akm_driver = {
        .driver = {
                .name   = "acx565akm",
                .owner  = THIS_MODULE,
+               .of_match_table = acx565akm_of_match,
        },
        .probe  = acx565akm_probe,
        .remove = acx565akm_remove,
index d3aa91b..8aec8bd 100644 (file)
@@ -1,7 +1,7 @@
 obj-$(CONFIG_OMAP2_DSS) += omapdss.o
 # Core DSS files
 omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
-       output.o
+       output.o dss-of.o
 # DSS compat layer files
 omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
        dispc-compat.o display-sysfs.o
index aaecbf3..2bbdb7f 100644 (file)
@@ -3778,12 +3778,20 @@ static const struct dev_pm_ops dispc_pm_ops = {
        .runtime_resume = dispc_runtime_resume,
 };
 
+static const struct of_device_id dispc_of_match[] = {
+       { .compatible = "ti,omap2-dispc", },
+       { .compatible = "ti,omap3-dispc", },
+       { .compatible = "ti,omap4-dispc", },
+       {},
+};
+
 static struct platform_driver omap_dispchw_driver = {
        .remove         = __exit_p(omap_dispchw_remove),
        .driver         = {
                .name   = "omapdss_dispc",
                .owner  = THIS_MODULE,
                .pm     = &dispc_pm_ops,
+               .of_match_table = dispc_of_match,
        },
 };
 
index 9f19ae2..2412a0d 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/module.h>
 #include <linux/jiffies.h>
 #include <linux/platform_device.h>
+#include <linux/of.h>
 
 #include <video/omapdss.h>
 #include "dss.h"
@@ -133,9 +134,32 @@ static int disp_num_counter;
 int omapdss_register_display(struct omap_dss_device *dssdev)
 {
        struct omap_dss_driver *drv = dssdev->driver;
+       int id;
 
-       snprintf(dssdev->alias, sizeof(dssdev->alias),
-                       "display%d", disp_num_counter++);
+       /*
+        * Note: this presumes all the displays are either using DT or non-DT,
+        * which normally should be the case. This also presumes that all
+        * displays either have an DT alias, or none has.
+        */
+
+       if (dssdev->dev->of_node) {
+               id = of_alias_get_id(dssdev->dev->of_node, "display");
+
+               if (id < 0)
+                       id = disp_num_counter++;
+       } else {
+               id = disp_num_counter++;
+       }
+
+       snprintf(dssdev->alias, sizeof(dssdev->alias), "display%d", id);
+
+       /* Use 'label' property for name, if it exists */
+       if (dssdev->dev->of_node)
+               of_property_read_string(dssdev->dev->of_node, "label",
+                       &dssdev->name);
+
+       if (dssdev->name == NULL)
+               dssdev->name = dssdev->alias;
 
        if (drv && drv->get_resolution == NULL)
                drv->get_resolution = omapdss_default_get_resolution;
index 6c0bb09..157921d 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/string.h>
+#include <linux/of.h>
 
 #include <video/omapdss.h>
 
@@ -49,6 +50,8 @@ static struct {
        int data_lines;
 
        struct omap_dss_device output;
+
+       bool port_initialized;
 } dpi;
 
 static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
@@ -725,3 +728,47 @@ void __exit dpi_uninit_platform_driver(void)
 {
        platform_driver_unregister(&omap_dpi_driver);
 }
+
+int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
+{
+       struct device_node *ep;
+       u32 datalines;
+       int r;
+
+       ep = omapdss_of_get_next_endpoint(port, NULL);
+       if (!ep)
+               return 0;
+
+       r = of_property_read_u32(ep, "data-lines", &datalines);
+       if (r) {
+               DSSERR("failed to parse datalines\n");
+               goto err_datalines;
+       }
+
+       dpi.data_lines = datalines;
+
+       of_node_put(ep);
+
+       dpi.pdev = pdev;
+
+       mutex_init(&dpi.lock);
+
+       dpi_init_output(pdev);
+
+       dpi.port_initialized = true;
+
+       return 0;
+
+err_datalines:
+       of_node_put(ep);
+
+       return r;
+}
+
+void __exit dpi_uninit_port(void)
+{
+       if (!dpi.port_initialized)
+               return;
+
+       dpi_uninit_output(dpi.pdev);
+}
index 0d82f73..121d104 100644 (file)
@@ -38,6 +38,8 @@
 #include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
 
 #include <video/omapdss.h>
 #include <video/mipi_display.h>
@@ -386,6 +388,13 @@ struct dsi_packet_sent_handler_data {
        struct completion *completion;
 };
 
+struct dsi_module_id_data {
+       u32 address;
+       int id;
+};
+
+static const struct of_device_id dsi_of_match[];
+
 #ifdef DSI_PERF_MEASURE
 static bool dsi_perf;
 module_param(dsi_perf, bool, 0644);
@@ -1151,15 +1160,11 @@ static int dsi_regulator_init(struct platform_device *dsidev)
        if (dsi->vdds_dsi_reg != NULL)
                return 0;
 
-       vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdds_dsi");
-
-       /* DT HACK: try VCXIO to make omapdss work for o4 sdp/panda */
-       if (IS_ERR(vdds_dsi))
-               vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "VCXIO");
+       vdds_dsi = devm_regulator_get(&dsi->pdev->dev, "vdd");
 
        if (IS_ERR(vdds_dsi)) {
                if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
-                       DSSERR("can't get VDDS_DSI regulator\n");
+                       DSSERR("can't get DSI VDD regulator\n");
                return PTR_ERR(vdds_dsi);
        }
 
@@ -5370,12 +5375,69 @@ static void dsi_uninit_output(struct platform_device *dsidev)
        omapdss_unregister_output(out);
 }
 
+static int dsi_probe_of(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct dsi_data *dsi = dsi_get_dsidrv_data(pdev);
+       struct property *prop;
+       u32 lane_arr[10];
+       int len, num_pins;
+       int r, i;
+       struct device_node *ep;
+       struct omap_dsi_pin_config pin_cfg;
+
+       ep = omapdss_of_get_first_endpoint(node);
+       if (!ep)
+               return 0;
+
+       prop = of_find_property(ep, "lanes", &len);
+       if (prop == NULL) {
+               dev_err(&pdev->dev, "failed to find lane data\n");
+               r = -EINVAL;
+               goto err;
+       }
+
+       num_pins = len / sizeof(u32);
+
+       if (num_pins < 4 || num_pins % 2 != 0 ||
+               num_pins > dsi->num_lanes_supported * 2) {
+               dev_err(&pdev->dev, "bad number of lanes\n");
+               r = -EINVAL;
+               goto err;
+       }
+
+       r = of_property_read_u32_array(ep, "lanes", lane_arr, num_pins);
+       if (r) {
+               dev_err(&pdev->dev, "failed to read lane data\n");
+               goto err;
+       }
+
+       pin_cfg.num_pins = num_pins;
+       for (i = 0; i < num_pins; ++i)
+               pin_cfg.pins[i] = (int)lane_arr[i];
+
+       r = dsi_configure_pins(&dsi->output, &pin_cfg);
+       if (r) {
+               dev_err(&pdev->dev, "failed to configure pins");
+               goto err;
+       }
+
+       of_node_put(ep);
+
+       return 0;
+
+err:
+       of_node_put(ep);
+       return r;
+}
+
 /* DSI1 HW IP initialisation */
 static int omap_dsihw_probe(struct platform_device *dsidev)
 {
        u32 rev;
        int r, i;
        struct dsi_data *dsi;
+       struct resource *dsi_mem;
        struct resource *res;
        struct resource temp_res;
 
@@ -5383,7 +5445,6 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
        if (!dsi)
                return -ENOMEM;
 
-       dsi->module_id = dsidev->id;
        dsi->pdev = dsidev;
        dev_set_drvdata(&dsidev->dev, dsi);
 
@@ -5421,6 +5482,8 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
                res = &temp_res;
        }
 
+       dsi_mem = res;
+
        dsi->proto_base = devm_ioremap(&dsidev->dev, res->start,
                resource_size(res));
        if (!dsi->proto_base) {
@@ -5481,6 +5544,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
                return r;
        }
 
+       if (dsidev->dev.of_node) {
+               const struct of_device_id *match;
+               const struct dsi_module_id_data *d;
+
+               match = of_match_node(dsi_of_match, dsidev->dev.of_node);
+               if (!match) {
+                       DSSERR("unsupported DSI module\n");
+                       return -ENODEV;
+               }
+
+               d = match->data;
+
+               while (d->address != 0 && d->address != dsi_mem->start)
+                       d++;
+
+               if (d->address == 0) {
+                       DSSERR("unsupported DSI module\n");
+                       return -ENODEV;
+               }
+
+               dsi->module_id = d->id;
+       } else {
+               dsi->module_id = dsidev->id;
+       }
+
        /* DSI VCs initialization */
        for (i = 0; i < ARRAY_SIZE(dsi->vc); i++) {
                dsi->vc[i].source = DSI_VC_SOURCE_L4;
@@ -5516,6 +5604,19 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
 
        dsi_init_output(dsidev);
 
+       if (dsidev->dev.of_node) {
+               r = dsi_probe_of(dsidev);
+               if (r) {
+                       DSSERR("Invalid DSI DT data\n");
+                       goto err_probe_of;
+               }
+
+               r = of_platform_populate(dsidev->dev.of_node, NULL, NULL,
+                       &dsidev->dev);
+               if (r)
+                       DSSERR("Failed to populate DSI child devices: %d\n", r);
+       }
+
        dsi_runtime_put(dsidev);
 
        if (dsi->module_id == 0)
@@ -5529,17 +5630,31 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
        else if (dsi->module_id == 1)
                dss_debugfs_create_file("dsi2_irqs", dsi2_dump_irqs);
 #endif
+
        return 0;
 
+err_probe_of:
+       dsi_uninit_output(dsidev);
+       dsi_runtime_put(dsidev);
+
 err_runtime_get:
        pm_runtime_disable(&dsidev->dev);
        return r;
 }
 
+static int dsi_unregister_child(struct device *dev, void *data)
+{
+       struct platform_device *pdev = to_platform_device(dev);
+       platform_device_unregister(pdev);
+       return 0;
+}
+
 static int __exit omap_dsihw_remove(struct platform_device *dsidev)
 {
        struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
 
+       device_for_each_child(&dsidev->dev, NULL, dsi_unregister_child);
+
        WARN_ON(dsi->scp_clk_refcount > 0);
 
        dsi_uninit_output(dsidev);
@@ -5577,6 +5692,23 @@ static const struct dev_pm_ops dsi_pm_ops = {
        .runtime_resume = dsi_runtime_resume,
 };
 
+static const struct dsi_module_id_data dsi_of_data_omap3[] = {
+       { .address = 0x4804fc00, .id = 0, },
+       { },
+};
+
+static const struct dsi_module_id_data dsi_of_data_omap4[] = {
+       { .address = 0x58004000, .id = 0, },
+       { .address = 0x58005000, .id = 1, },
+       { },
+};
+
+static const struct of_device_id dsi_of_match[] = {
+       { .compatible = "ti,omap3-dsi", .data = dsi_of_data_omap3, },
+       { .compatible = "ti,omap4-dsi", .data = dsi_of_data_omap4, },
+       {},
+};
+
 static struct platform_driver omap_dsihw_driver = {
        .probe          = omap_dsihw_probe,
        .remove         = __exit_p(omap_dsihw_remove),
@@ -5584,6 +5716,7 @@ static struct platform_driver omap_dsihw_driver = {
                .name   = "omapdss_dsi",
                .owner  = THIS_MODULE,
                .pm     = &dsi_pm_ops,
+               .of_match_table = dsi_of_match,
        },
 };
 
diff --git a/drivers/video/omap2/dss/dss-of.c b/drivers/video/omap2/dss/dss-of.c
new file mode 100644 (file)
index 0000000..a4b20aa
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/seq_file.h>
+
+#include <video/omapdss.h>
+
+struct device_node *
+omapdss_of_get_next_port(const struct device_node *parent,
+                        struct device_node *prev)
+{
+       struct device_node *port = NULL;
+
+       if (!parent)
+               return NULL;
+
+       if (!prev) {
+               struct device_node *ports;
+               /*
+                * It's the first call, we have to find a port subnode
+                * within this node or within an optional 'ports' node.
+                */
+               ports = of_get_child_by_name(parent, "ports");
+               if (ports)
+                       parent = ports;
+
+               port = of_get_child_by_name(parent, "port");
+
+               /* release the 'ports' node */
+               of_node_put(ports);
+       } else {
+               struct device_node *ports;
+
+               ports = of_get_parent(prev);
+               if (!ports)
+                       return NULL;
+
+               do {
+                       port = of_get_next_child(ports, prev);
+                       if (!port) {
+                               of_node_put(ports);
+                               return NULL;
+                       }
+                       prev = port;
+               } while (of_node_cmp(port->name, "port") != 0);
+       }
+
+       return port;
+}
+EXPORT_SYMBOL_GPL(omapdss_of_get_next_port);
+
+struct device_node *
+omapdss_of_get_next_endpoint(const struct device_node *parent,
+                            struct device_node *prev)
+{
+       struct device_node *ep = NULL;
+
+       if (!parent)
+               return NULL;
+
+       do {
+               ep = of_get_next_child(parent, prev);
+               if (!ep)
+                       return NULL;
+               prev = ep;
+       } while (of_node_cmp(ep->name, "endpoint") != 0);
+
+       return ep;
+}
+EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
+
+static struct device_node *
+omapdss_of_get_remote_device_node(const struct device_node *node)
+{
+       struct device_node *np;
+       int i;
+
+       np = of_parse_phandle(node, "remote-endpoint", 0);
+
+       if (!np)
+               return NULL;
+
+       np = of_get_next_parent(np);
+
+       for (i = 0; i < 3 && np; ++i) {
+               struct property *prop;
+
+               prop = of_find_property(np, "compatible", NULL);
+
+               if (prop)
+                       return np;
+
+               np = of_get_next_parent(np);
+       }
+
+       return NULL;
+}
+
+struct device_node *
+omapdss_of_get_first_endpoint(const struct device_node *parent)
+{
+       struct device_node *port, *ep;
+
+       port = omapdss_of_get_next_port(parent, NULL);
+
+       if (!port)
+               return NULL;
+
+       ep = omapdss_of_get_next_endpoint(port, NULL);
+
+       of_node_put(port);
+
+       return ep;
+}
+EXPORT_SYMBOL_GPL(omapdss_of_get_first_endpoint);
+
+struct omap_dss_device *
+omapdss_of_find_source_for_first_ep(struct device_node *node)
+{
+       struct device_node *ep;
+       struct device_node *src_node;
+       struct omap_dss_device *src;
+
+       ep = omapdss_of_get_first_endpoint(node);
+       if (!ep)
+               return ERR_PTR(-EINVAL);
+
+       src_node = omapdss_of_get_remote_device_node(ep);
+
+       of_node_put(ep);
+
+       if (!src_node)
+               return ERR_PTR(-EINVAL);
+
+       src = omap_dss_find_output_by_node(src_node);
+
+       of_node_put(src_node);
+
+       if (!src)
+               return ERR_PTR(-EPROBE_DEFER);
+
+       return src;
+}
+EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
index 96e400c..825c019 100644 (file)
@@ -23,6 +23,7 @@
 #define DSS_SUBSYS_NAME "DSS"
 
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/io.h>
 #include <linux/export.h>
 #include <linux/err.h>
@@ -33,6 +34,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/gfp.h>
 #include <linux/sizes.h>
+#include <linux/of.h>
 
 #include <video/omapdss.h>
 
@@ -772,6 +774,56 @@ static int __init dss_init_features(struct platform_device *pdev)
        return 0;
 }
 
+static int __init dss_init_ports(struct platform_device *pdev)
+{
+       struct device_node *parent = pdev->dev.of_node;
+       struct device_node *port;
+       int r;
+
+       if (parent == NULL)
+               return 0;
+
+       port = omapdss_of_get_next_port(parent, NULL);
+       if (!port) {
+#ifdef CONFIG_OMAP2_DSS_DPI
+               dpi_init_port(pdev, parent);
+#endif
+               return 0;
+       }
+
+       do {
+               u32 reg;
+
+               r = of_property_read_u32(port, "reg", &reg);
+               if (r)
+                       reg = 0;
+
+#ifdef CONFIG_OMAP2_DSS_DPI
+               if (reg == 0)
+                       dpi_init_port(pdev, port);
+#endif
+
+#ifdef CONFIG_OMAP2_DSS_SDI
+               if (reg == 1)
+                       sdi_init_port(pdev, port);
+#endif
+
+       } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
+
+       return 0;
+}
+
+static void dss_uninit_ports(void)
+{
+#ifdef CONFIG_OMAP2_DSS_DPI
+       dpi_uninit_port();
+#endif
+
+#ifdef CONFIG_OMAP2_DSS_SDI
+       sdi_uninit_port();
+#endif
+}
+
 /* DSS HW IP initialisation */
 static int __init omap_dsshw_probe(struct platform_device *pdev)
 {
@@ -830,6 +882,8 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
        dss.lcd_clk_source[0] = OMAP_DSS_CLK_SRC_FCK;
        dss.lcd_clk_source[1] = OMAP_DSS_CLK_SRC_FCK;
 
+       dss_init_ports(pdev);
+
        rev = dss_read_reg(DSS_REVISION);
        printk(KERN_INFO "OMAP DSS rev %d.%d\n",
                        FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
@@ -849,6 +903,8 @@ err_setup_clocks:
 
 static int __exit omap_dsshw_remove(struct platform_device *pdev)
 {
+       dss_uninit_ports();
+
        pm_runtime_disable(&pdev->dev);
 
        dss_put_clocks();
@@ -886,12 +942,22 @@ static const struct dev_pm_ops dss_pm_ops = {
        .runtime_resume = dss_runtime_resume,
 };
 
+static const struct of_device_id dss_of_match[] = {
+       { .compatible = "ti,omap2-dss", },
+       { .compatible = "ti,omap3-dss", },
+       { .compatible = "ti,omap4-dss", },
+       {},
+};
+
+MODULE_DEVICE_TABLE(of, dss_of_match);
+
 static struct platform_driver omap_dsshw_driver = {
        .remove         = __exit_p(omap_dsshw_remove),
        .driver         = {
                .name   = "omapdss_dss",
                .owner  = THIS_MODULE,
                .pm     = &dss_pm_ops,
+               .of_match_table = dss_of_match,
        },
 };
 
index 570f7ed..918fec1 100644 (file)
@@ -250,6 +250,9 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min,
 int sdi_init_platform_driver(void) __init;
 void sdi_uninit_platform_driver(void) __exit;
 
+int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init;
+void sdi_uninit_port(void) __exit;
+
 /* DSI */
 
 typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
@@ -361,6 +364,9 @@ static inline bool dsi_pll_calc(struct platform_device *dsidev,
 int dpi_init_platform_driver(void) __init;
 void dpi_uninit_platform_driver(void) __exit;
 
+int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init;
+void dpi_uninit_port(void) __exit;
+
 /* DISPC */
 int dispc_init_platform_driver(void) __init;
 void dispc_uninit_platform_driver(void) __exit;
index 895c252..f5f7944 100644 (file)
@@ -88,15 +88,11 @@ static int hdmi_init_regulator(void)
        if (hdmi.vdda_hdmi_dac_reg != NULL)
                return 0;
 
-       reg = devm_regulator_get(&hdmi.pdev->dev, "vdda_hdmi_dac");
-
-       /* DT HACK: try VDAC to make omapdss work for o4 sdp/panda */
-       if (IS_ERR(reg))
-               reg = devm_regulator_get(&hdmi.pdev->dev, "VDAC");
+       reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
 
        if (IS_ERR(reg)) {
                if (PTR_ERR(reg) != -EPROBE_DEFER)
-                       DSSERR("can't get VDDA_HDMI_DAC regulator\n");
+                       DSSERR("can't get VDDA regulator\n");
                return PTR_ERR(reg);
        }
 
@@ -680,6 +676,11 @@ static const struct dev_pm_ops hdmi_pm_ops = {
        .runtime_resume = hdmi_runtime_resume,
 };
 
+static const struct of_device_id hdmi_of_match[] = {
+       { .compatible = "ti,omap4-hdmi", },
+       {},
+};
+
 static struct platform_driver omapdss_hdmihw_driver = {
        .probe          = omapdss_hdmihw_probe,
        .remove         = __exit_p(omapdss_hdmihw_remove),
@@ -687,6 +688,7 @@ static struct platform_driver omapdss_hdmihw_driver = {
                .name   = "omapdss_hdmi",
                .owner  = THIS_MODULE,
                .pm     = &hdmi_pm_ops,
+               .of_match_table = hdmi_of_match,
        },
 };
 
index cd620c6..f5f4ccf 100644 (file)
@@ -171,6 +171,8 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
        video_fmt->packing_mode = HDMI_PACK_10b_RGB_YUV444;
        video_fmt->y_res = param->timings.y_res;
        video_fmt->x_res = param->timings.x_res;
+       if (param->timings.interlace)
+               video_fmt->y_res /= 2;
 
        timings->hbp = param->timings.hbp;
        timings->hfp = param->timings.hfp;
index b679e33..911dcc9 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/export.h>
 #include <linux/platform_device.h>
 #include <linux/string.h>
+#include <linux/of.h>
 
 #include <video/omapdss.h>
 #include "dss.h"
@@ -41,6 +42,8 @@ static struct {
        int datapairs;
 
        struct omap_dss_device output;
+
+       bool port_initialized;
 } sdi;
 
 struct sdi_clk_calc_ctx {
@@ -386,3 +389,45 @@ void __exit sdi_uninit_platform_driver(void)
 {
        platform_driver_unregister(&omap_sdi_driver);
 }
+
+int __init sdi_init_port(struct platform_device *pdev, struct device_node *port)
+{
+       struct device_node *ep;
+       u32 datapairs;
+       int r;
+
+       ep = omapdss_of_get_next_endpoint(port, NULL);
+       if (!ep)
+               return 0;
+
+       r = of_property_read_u32(ep, "datapairs", &datapairs);
+       if (r) {
+               DSSERR("failed to parse datapairs\n");
+               goto err_datapairs;
+       }
+
+       sdi.datapairs = datapairs;
+
+       of_node_put(ep);
+
+       sdi.pdev = pdev;
+
+       sdi_init_output(pdev);
+
+       sdi.port_initialized = true;
+
+       return 0;
+
+err_datapairs:
+       of_node_put(ep);
+
+       return r;
+}
+
+void __exit sdi_uninit_port(void)
+{
+       if (!sdi.port_initialized)
+               return;
+
+       sdi_uninit_output(sdi.pdev);
+}
index 59ade34..21d8111 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/platform_device.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
+#include <linux/of.h>
 
 #include <video/omapdss.h>
 
@@ -636,7 +637,10 @@ static int venc_init_regulator(void)
        if (venc.vdda_dac_reg != NULL)
                return 0;
 
-       vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac");
+       if (venc.pdev->dev.of_node)
+               vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda");
+       else
+               vdda_dac = devm_regulator_get(&venc.pdev->dev, "vdda_dac");
 
        if (IS_ERR(vdda_dac)) {
                if (PTR_ERR(vdda_dac) != -EPROBE_DEFER)
@@ -805,6 +809,48 @@ static void __exit venc_uninit_output(struct platform_device *pdev)
        omapdss_unregister_output(out);
 }
 
+static int venc_probe_of(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct device_node *ep;
+       u32 channels;
+       int r;
+
+       ep = omapdss_of_get_first_endpoint(node);
+       if (!ep)
+               return 0;
+
+       venc.invert_polarity = of_property_read_bool(ep, "ti,invert-polarity");
+
+       r = of_property_read_u32(ep, "ti,channels", &channels);
+       if (r) {
+               dev_err(&pdev->dev,
+                       "failed to read property 'ti,channels': %d\n", r);
+               goto err;
+       }
+
+       switch (channels) {
+       case 1:
+               venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE;
+               break;
+       case 2:
+               venc.type = OMAP_DSS_VENC_TYPE_SVIDEO;
+               break;
+       default:
+               dev_err(&pdev->dev, "bad channel propert '%d'\n", channels);
+               r = -EINVAL;
+               goto err;
+       }
+
+       of_node_put(ep);
+
+       return 0;
+err:
+       of_node_put(ep);
+
+       return 0;
+}
+
 /* VENC HW IP initialisation */
 static int omap_venchw_probe(struct platform_device *pdev)
 {
@@ -846,12 +892,21 @@ static int omap_venchw_probe(struct platform_device *pdev)
 
        venc_runtime_put();
 
+       if (pdev->dev.of_node) {
+               r = venc_probe_of(pdev);
+               if (r) {
+                       DSSERR("Invalid DT data\n");
+                       goto err_probe_of;
+               }
+       }
+
        dss_debugfs_create_file("venc", venc_dump_regs);
 
        venc_init_output(pdev);
 
        return 0;
 
+err_probe_of:
 err_runtime_get:
        pm_runtime_disable(&pdev->dev);
        return r;
@@ -895,6 +950,14 @@ static const struct dev_pm_ops venc_pm_ops = {
        .runtime_resume = venc_runtime_resume,
 };
 
+
+static const struct of_device_id venc_of_match[] = {
+       { .compatible = "ti,omap2-venc", },
+       { .compatible = "ti,omap3-venc", },
+       { .compatible = "ti,omap4-venc", },
+       {},
+};
+
 static struct platform_driver omap_venchw_driver = {
        .probe          = omap_venchw_probe,
        .remove         = __exit_p(omap_venchw_remove),
@@ -902,6 +965,7 @@ static struct platform_driver omap_venchw_driver = {
                .name   = "omapdss_venc",
                .owner  = THIS_MODULE,
                .pm     = &venc_pm_ops,
+               .of_match_table = venc_of_match,
        },
 };
 
index 8d02f16..ec2d132 100644 (file)
@@ -2417,6 +2417,55 @@ static int omapfb_init_connections(struct omapfb2_device *fbdev,
        return 0;
 }
 
+static struct omap_dss_device *
+omapfb_find_default_display(struct omapfb2_device *fbdev)
+{
+       const char *def_name;
+       int i;
+
+       /*
+        * Search with the display name from the user or the board file,
+        * comparing to display names and aliases
+        */
+
+       def_name = omapdss_get_default_display_name();
+
+       if (def_name) {
+               for (i = 0; i < fbdev->num_displays; ++i) {
+                       struct omap_dss_device *dssdev;
+
+                       dssdev = fbdev->displays[i].dssdev;
+
+                       if (dssdev->name && strcmp(def_name, dssdev->name) == 0)
+                               return dssdev;
+
+                       if (strcmp(def_name, dssdev->alias) == 0)
+                               return dssdev;
+               }
+
+               /* def_name given but not found */
+               return NULL;
+       }
+
+       /* then look for DT alias display0 */
+       for (i = 0; i < fbdev->num_displays; ++i) {
+               struct omap_dss_device *dssdev;
+               int id;
+
+               dssdev = fbdev->displays[i].dssdev;
+
+               if (dssdev->dev->of_node == NULL)
+                       continue;
+
+               id = of_alias_get_id(dssdev->dev->of_node, "display");
+               if (id == 0)
+                       return dssdev;
+       }
+
+       /* return the first display we have in the list */
+       return fbdev->displays[0].dssdev;
+}
+
 static int omapfb_probe(struct platform_device *pdev)
 {
        struct omapfb2_device *fbdev = NULL;
@@ -2494,23 +2543,7 @@ static int omapfb_probe(struct platform_device *pdev)
        for (i = 0; i < fbdev->num_managers; i++)
                fbdev->managers[i] = omap_dss_get_overlay_manager(i);
 
-       def_display = NULL;
-
-       for (i = 0; i < fbdev->num_displays; ++i) {
-               struct omap_dss_device *dssdev;
-               const char *def_name;
-
-               def_name = omapdss_get_default_display_name();
-
-               dssdev = fbdev->displays[i].dssdev;
-
-               if (def_name == NULL ||
-                       (dssdev->name && strcmp(def_name, dssdev->name) == 0)) {
-                       def_display = dssdev;
-                       break;
-               }
-       }
-
+       def_display = omapfb_find_default_display(fbdev);
        if (def_display == NULL) {
                dev_err(fbdev->dev, "failed to find default display\n");
                r = -EPROBE_DEFER;
index 0e6c033..0ba1b7c 100644 (file)
@@ -48,7 +48,7 @@
 
 /* Module and version information */
 #define DRV_NAME       "iTCO_wdt"
-#define DRV_VERSION    "1.10"
+#define DRV_VERSION    "1.11"
 
 /* Includes */
 #include <linux/module.h>              /* For module specific items */
@@ -92,9 +92,12 @@ static struct {              /* this is private data for the iTCO_wdt device */
        unsigned int iTCO_version;
        struct resource *tco_res;
        struct resource *smi_res;
-       struct resource *gcs_res;
-       /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/
-       unsigned long __iomem *gcs;
+       /*
+        * NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2),
+        * or memory-mapped PMC register bit 4 (TCO version 3).
+        */
+       struct resource *gcs_pmc_res;
+       unsigned long __iomem *gcs_pmc;
        /* the lock for io operations */
        spinlock_t io_lock;
        struct platform_device *dev;
@@ -125,11 +128,19 @@ MODULE_PARM_DESC(turn_SMI_watchdog_clear_off,
  * Some TCO specific functions
  */
 
-static inline unsigned int seconds_to_ticks(int seconds)
+/*
+ * The iTCO v1 and v2's internal timer is stored as ticks which decrement
+ * every 0.6 seconds.  v3's internal timer is stored as seconds (some
+ * datasheets incorrectly state 0.6 seconds).
+ */
+static inline unsigned int seconds_to_ticks(int secs)
 {
-       /* the internal timer is stored as ticks which decrement
-        * every 0.6 seconds */
-       return (seconds * 10) / 6;
+       return iTCO_wdt_private.iTCO_version == 3 ? secs : (secs * 10) / 6;
+}
+
+static inline unsigned int ticks_to_seconds(int ticks)
+{
+       return iTCO_wdt_private.iTCO_version == 3 ? ticks : (ticks * 6) / 10;
 }
 
 static void iTCO_wdt_set_NO_REBOOT_bit(void)
@@ -137,10 +148,14 @@ static void iTCO_wdt_set_NO_REBOOT_bit(void)
        u32 val32;
 
        /* Set the NO_REBOOT bit: this disables reboots */
-       if (iTCO_wdt_private.iTCO_version == 2) {
-               val32 = readl(iTCO_wdt_private.gcs);
+       if (iTCO_wdt_private.iTCO_version == 3) {
+               val32 = readl(iTCO_wdt_private.gcs_pmc);
+               val32 |= 0x00000010;
+               writel(val32, iTCO_wdt_private.gcs_pmc);
+       } else if (iTCO_wdt_private.iTCO_version == 2) {
+               val32 = readl(iTCO_wdt_private.gcs_pmc);
                val32 |= 0x00000020;
-               writel(val32, iTCO_wdt_private.gcs);
+               writel(val32, iTCO_wdt_private.gcs_pmc);
        } else if (iTCO_wdt_private.iTCO_version == 1) {
                pci_read_config_dword(iTCO_wdt_private.pdev, 0xd4, &val32);
                val32 |= 0x00000002;
@@ -154,12 +169,20 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void)
        u32 val32;
 
        /* Unset the NO_REBOOT bit: this enables reboots */
-       if (iTCO_wdt_private.iTCO_version == 2) {
-               val32 = readl(iTCO_wdt_private.gcs);
+       if (iTCO_wdt_private.iTCO_version == 3) {
+               val32 = readl(iTCO_wdt_private.gcs_pmc);
+               val32 &= 0xffffffef;
+               writel(val32, iTCO_wdt_private.gcs_pmc);
+
+               val32 = readl(iTCO_wdt_private.gcs_pmc);
+               if (val32 & 0x00000010)
+                       ret = -EIO;
+       } else if (iTCO_wdt_private.iTCO_version == 2) {
+               val32 = readl(iTCO_wdt_private.gcs_pmc);
                val32 &= 0xffffffdf;
-               writel(val32, iTCO_wdt_private.gcs);
+               writel(val32, iTCO_wdt_private.gcs_pmc);
 
-               val32 = readl(iTCO_wdt_private.gcs);
+               val32 = readl(iTCO_wdt_private.gcs_pmc);
                if (val32 & 0x00000020)
                        ret = -EIO;
        } else if (iTCO_wdt_private.iTCO_version == 1) {
@@ -192,7 +215,7 @@ static int iTCO_wdt_start(struct watchdog_device *wd_dev)
 
        /* Force the timer to its reload value by writing to the TCO_RLD
           register */
-       if (iTCO_wdt_private.iTCO_version == 2)
+       if (iTCO_wdt_private.iTCO_version >= 2)
                outw(0x01, TCO_RLD);
        else if (iTCO_wdt_private.iTCO_version == 1)
                outb(0x01, TCO_RLD);
@@ -240,9 +263,9 @@ static int iTCO_wdt_ping(struct watchdog_device *wd_dev)
        iTCO_vendor_pre_keepalive(iTCO_wdt_private.smi_res, wd_dev->timeout);
 
        /* Reload the timer by writing to the TCO Timer Counter register */
-       if (iTCO_wdt_private.iTCO_version == 2)
+       if (iTCO_wdt_private.iTCO_version >= 2) {
                outw(0x01, TCO_RLD);
-       else if (iTCO_wdt_private.iTCO_version == 1) {
+       else if (iTCO_wdt_private.iTCO_version == 1) {
                /* Reset the timeout status bit so that the timer
                 * needs to count down twice again before rebooting */
                outw(0x0008, TCO1_STS); /* write 1 to clear bit */
@@ -270,14 +293,14 @@ static int iTCO_wdt_set_timeout(struct watchdog_device *wd_dev, unsigned int t)
        /* "Values of 0h-3h are ignored and should not be attempted" */
        if (tmrval < 0x04)
                return -EINVAL;
-       if (((iTCO_wdt_private.iTCO_version == 2) && (tmrval > 0x3ff)) ||
+       if (((iTCO_wdt_private.iTCO_version >= 2) && (tmrval > 0x3ff)) ||
            ((iTCO_wdt_private.iTCO_version == 1) && (tmrval > 0x03f)))
                return -EINVAL;
 
        iTCO_vendor_pre_set_heartbeat(tmrval);
 
        /* Write new heartbeat to watchdog */
-       if (iTCO_wdt_private.iTCO_version == 2) {
+       if (iTCO_wdt_private.iTCO_version >= 2) {
                spin_lock(&iTCO_wdt_private.io_lock);
                val16 = inw(TCOv2_TMR);
                val16 &= 0xfc00;
@@ -312,13 +335,13 @@ static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
        unsigned int time_left = 0;
 
        /* read the TCO Timer */
-       if (iTCO_wdt_private.iTCO_version == 2) {
+       if (iTCO_wdt_private.iTCO_version >= 2) {
                spin_lock(&iTCO_wdt_private.io_lock);
                val16 = inw(TCO_RLD);
                val16 &= 0x3ff;
                spin_unlock(&iTCO_wdt_private.io_lock);
 
-               time_left = (val16 * 6) / 10;
+               time_left = ticks_to_seconds(val16);
        } else if (iTCO_wdt_private.iTCO_version == 1) {
                spin_lock(&iTCO_wdt_private.io_lock);
                val8 = inb(TCO_RLD);
@@ -327,7 +350,7 @@ static unsigned int iTCO_wdt_get_timeleft(struct watchdog_device *wd_dev)
                        val8 += (inb(TCOv1_TMR) & 0x3f);
                spin_unlock(&iTCO_wdt_private.io_lock);
 
-               time_left = (val8 * 6) / 10;
+               time_left = ticks_to_seconds(val8);
        }
        return time_left;
 }
@@ -376,16 +399,16 @@ static void iTCO_wdt_cleanup(void)
                        resource_size(iTCO_wdt_private.tco_res));
        release_region(iTCO_wdt_private.smi_res->start,
                        resource_size(iTCO_wdt_private.smi_res));
-       if (iTCO_wdt_private.iTCO_version == 2) {
-               iounmap(iTCO_wdt_private.gcs);
-               release_mem_region(iTCO_wdt_private.gcs_res->start,
-                               resource_size(iTCO_wdt_private.gcs_res));
+       if (iTCO_wdt_private.iTCO_version >= 2) {
+               iounmap(iTCO_wdt_private.gcs_pmc);
+               release_mem_region(iTCO_wdt_private.gcs_pmc_res->start,
+                               resource_size(iTCO_wdt_private.gcs_pmc_res));
        }
 
        iTCO_wdt_private.tco_res = NULL;
        iTCO_wdt_private.smi_res = NULL;
-       iTCO_wdt_private.gcs_res = NULL;
-       iTCO_wdt_private.gcs = NULL;
+       iTCO_wdt_private.gcs_pmc_res = NULL;
+       iTCO_wdt_private.gcs_pmc = NULL;
 }
 
 static int iTCO_wdt_probe(struct platform_device *dev)
@@ -414,27 +437,27 @@ static int iTCO_wdt_probe(struct platform_device *dev)
        iTCO_wdt_private.pdev = to_pci_dev(dev->dev.parent);
 
        /*
-        * Get the Memory-Mapped GCS register, we need it for the
-        * NO_REBOOT flag (TCO v2).
+        * Get the Memory-Mapped GCS or PMC register, we need it for the
+        * NO_REBOOT flag (TCO v2 and v3).
         */
-       if (iTCO_wdt_private.iTCO_version == 2) {
-               iTCO_wdt_private.gcs_res = platform_get_resource(dev,
+       if (iTCO_wdt_private.iTCO_version >= 2) {
+               iTCO_wdt_private.gcs_pmc_res = platform_get_resource(dev,
                                                        IORESOURCE_MEM,
-                                                       ICH_RES_MEM_GCS);
+                                                       ICH_RES_MEM_GCS_PMC);
 
-               if (!iTCO_wdt_private.gcs_res)
+               if (!iTCO_wdt_private.gcs_pmc_res)
                        goto out;
 
-               if (!request_mem_region(iTCO_wdt_private.gcs_res->start,
-                       resource_size(iTCO_wdt_private.gcs_res), dev->name)) {
+               if (!request_mem_region(iTCO_wdt_private.gcs_pmc_res->start,
+                       resource_size(iTCO_wdt_private.gcs_pmc_res), dev->name)) {
                        ret = -EBUSY;
                        goto out;
                }
-               iTCO_wdt_private.gcs = ioremap(iTCO_wdt_private.gcs_res->start,
-                       resource_size(iTCO_wdt_private.gcs_res));
-               if (!iTCO_wdt_private.gcs) {
+               iTCO_wdt_private.gcs_pmc = ioremap(iTCO_wdt_private.gcs_pmc_res->start,
+                       resource_size(iTCO_wdt_private.gcs_pmc_res));
+               if (!iTCO_wdt_private.gcs_pmc) {
                        ret = -EIO;
-                       goto unreg_gcs;
+                       goto unreg_gcs_pmc;
                }
        }
 
@@ -442,7 +465,7 @@ static int iTCO_wdt_probe(struct platform_device *dev)
        if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) {
                pr_info("unable to reset NO_REBOOT flag, device disabled by hardware/BIOS\n");
                ret = -ENODEV;  /* Cannot reset NO_REBOOT bit */
-               goto unmap_gcs;
+               goto unmap_gcs_pmc;
        }
 
        /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
@@ -454,7 +477,7 @@ static int iTCO_wdt_probe(struct platform_device *dev)
                pr_err("I/O address 0x%04llx already in use, device disabled\n",
                       (u64)SMI_EN);
                ret = -EBUSY;
-               goto unmap_gcs;
+               goto unmap_gcs_pmc;
        }
        if (turn_SMI_watchdog_clear_off >= iTCO_wdt_private.iTCO_version) {
                /*
@@ -478,9 +501,13 @@ static int iTCO_wdt_probe(struct platform_device *dev)
                ich_info->name, ich_info->iTCO_version, (u64)TCOBASE);
 
        /* Clear out the (probably old) status */
-       outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
-       outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
-       outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */
+       if (iTCO_wdt_private.iTCO_version == 3) {
+               outl(0x20008, TCO1_STS);
+       } else {
+               outw(0x0008, TCO1_STS); /* Clear the Time Out Status bit */
+               outw(0x0002, TCO2_STS); /* Clear SECOND_TO_STS bit */
+               outw(0x0004, TCO2_STS); /* Clear BOOT_STS bit */
+       }
 
        iTCO_wdt_watchdog_dev.bootstatus = 0;
        iTCO_wdt_watchdog_dev.timeout = WATCHDOG_TIMEOUT;
@@ -515,18 +542,18 @@ unreg_tco:
 unreg_smi:
        release_region(iTCO_wdt_private.smi_res->start,
                        resource_size(iTCO_wdt_private.smi_res));
-unmap_gcs:
-       if (iTCO_wdt_private.iTCO_version == 2)
-               iounmap(iTCO_wdt_private.gcs);
-unreg_gcs:
-       if (iTCO_wdt_private.iTCO_version == 2)
-               release_mem_region(iTCO_wdt_private.gcs_res->start,
-                               resource_size(iTCO_wdt_private.gcs_res));
+unmap_gcs_pmc:
+       if (iTCO_wdt_private.iTCO_version >= 2)
+               iounmap(iTCO_wdt_private.gcs_pmc);
+unreg_gcs_pmc:
+       if (iTCO_wdt_private.iTCO_version >= 2)
+               release_mem_region(iTCO_wdt_private.gcs_pmc_res->start,
+                               resource_size(iTCO_wdt_private.gcs_pmc_res));
 out:
        iTCO_wdt_private.tco_res = NULL;
        iTCO_wdt_private.smi_res = NULL;
-       iTCO_wdt_private.gcs_res = NULL;
-       iTCO_wdt_private.gcs = NULL;
+       iTCO_wdt_private.gcs_pmc_res = NULL;
+       iTCO_wdt_private.gcs_pmc = NULL;
 
        return ret;
 }
index 4612088..4baf2d7 100644 (file)
@@ -708,10 +708,13 @@ static int __init octeon_wdt_init(void)
 
        cpumask_clear(&irq_enabled_cpus);
 
+       cpu_notifier_register_begin();
        for_each_online_cpu(cpu)
                octeon_wdt_setup_interrupt(cpu);
 
-       register_hotcpu_notifier(&octeon_wdt_cpu_notifier);
+       __register_hotcpu_notifier(&octeon_wdt_cpu_notifier);
+       cpu_notifier_register_done();
+
 out:
        return ret;
 }
@@ -725,7 +728,8 @@ static void __exit octeon_wdt_cleanup(void)
 
        misc_deregister(&octeon_wdt_miscdev);
 
-       unregister_hotcpu_notifier(&octeon_wdt_cpu_notifier);
+       cpu_notifier_register_begin();
+       __unregister_hotcpu_notifier(&octeon_wdt_cpu_notifier);
 
        for_each_online_cpu(cpu) {
                int core = cpu2core(cpu);
@@ -734,6 +738,9 @@ static void __exit octeon_wdt_cleanup(void)
                /* Free the interrupt handler */
                free_irq(OCTEON_IRQ_WDOG0 + core, octeon_wdt_poke_irq);
        }
+
+       cpu_notifier_register_done();
+
        /*
         * Disable the boot-bus memory, the code it points to is soon
         * to go missing.
index 61a6ac8..b7a506f 100644 (file)
@@ -604,19 +604,29 @@ static void __init balloon_add_region(unsigned long start_pfn,
        }
 }
 
+static int alloc_balloon_scratch_page(int cpu)
+{
+       if (per_cpu(balloon_scratch_page, cpu) != NULL)
+               return 0;
+
+       per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL);
+       if (per_cpu(balloon_scratch_page, cpu) == NULL) {
+               pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+
 static int balloon_cpu_notify(struct notifier_block *self,
                                    unsigned long action, void *hcpu)
 {
        int cpu = (long)hcpu;
        switch (action) {
        case CPU_UP_PREPARE:
-               if (per_cpu(balloon_scratch_page, cpu) != NULL)
-                       break;
-               per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL);
-               if (per_cpu(balloon_scratch_page, cpu) == NULL) {
-                       pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu);
+               if (alloc_balloon_scratch_page(cpu))
                        return NOTIFY_BAD;
-               }
                break;
        default:
                break;
@@ -636,15 +646,17 @@ static int __init balloon_init(void)
                return -ENODEV;
 
        if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-               for_each_online_cpu(cpu)
-               {
-                       per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL);
-                       if (per_cpu(balloon_scratch_page, cpu) == NULL) {
-                               pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu);
+               register_cpu_notifier(&balloon_cpu_notifier);
+
+               get_online_cpus();
+               for_each_online_cpu(cpu) {
+                       if (alloc_balloon_scratch_page(cpu)) {
+                               put_online_cpus();
+                               unregister_cpu_notifier(&balloon_cpu_notifier);
                                return -ENOMEM;
                        }
                }
-               register_cpu_notifier(&balloon_cpu_notifier);
+               put_online_cpus();
        }
 
        pr_info("Initialising balloon driver\n");
index d5a3de8..dfa12a4 100644 (file)
@@ -1248,8 +1248,8 @@ void xen_evtchn_do_upcall(struct pt_regs *regs)
        irq_enter();
 #ifdef CONFIG_X86
        exit_idle();
-#endif
        inc_irq_stat(irq_hv_callback_count);
+#endif
 
        __xen_evtchn_do_upcall();
 
index a16b0ff..d822320 100644 (file)
@@ -832,6 +832,7 @@ static void v9fs_mmap_vm_close(struct vm_area_struct *vma)
 
 static const struct vm_operations_struct v9fs_file_vm_ops = {
        .fault = filemap_fault,
+       .map_pages = filemap_map_pages,
        .page_mkwrite = v9fs_vm_page_mkwrite,
        .remap_pages = generic_file_remap_pages,
 };
@@ -839,6 +840,7 @@ static const struct vm_operations_struct v9fs_file_vm_ops = {
 static const struct vm_operations_struct v9fs_mmap_file_vm_ops = {
        .close = v9fs_mmap_vm_close,
        .fault = filemap_fault,
+       .map_pages = filemap_map_pages,
        .page_mkwrite = v9fs_vm_page_mkwrite,
        .remap_pages = generic_file_remap_pages,
 };
index 952aeb0..9852bdf 100644 (file)
@@ -266,7 +266,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        adfs_inode_cachep = kmem_cache_create("adfs_inode_cache",
                                             sizeof(struct adfs_inode_info),
index 3952121..25b23b1 100644 (file)
@@ -5,14 +5,6 @@
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
 
-/* AmigaOS allows file names with up to 30 characters length.
- * Names longer than that will be silently truncated. If you
- * want to disallow this, comment out the following #define.
- * Creating filesystem objects with longer names will then
- * result in an error (ENAMETOOLONG).
- */
-/*#define AFFS_NO_TRUNCATE */
-
 /* Ugly macros make the code more pretty. */
 
 #define GET_END_PTR(st,p,sz)            ((st *)((char *)(p)+((sz)-sizeof(st))))
@@ -28,7 +20,6 @@
 
 #define AFFS_CACHE_SIZE                PAGE_SIZE
 
-#define AFFS_MAX_PREALLOC      32
 #define AFFS_LC_SIZE           (AFFS_CACHE_SIZE/sizeof(u32)/2)
 #define AFFS_AC_SIZE           (AFFS_CACHE_SIZE/sizeof(struct affs_ext_key)/2)
 #define AFFS_AC_MASK           (AFFS_AC_SIZE-1)
@@ -118,6 +109,7 @@ struct affs_sb_info {
 #define SF_OFS         0x0200          /* Old filesystem */
 #define SF_PREFIX      0x0400          /* Buffer for prefix is allocated */
 #define SF_VERBOSE     0x0800          /* Talk about fs when mounting */
+#define SF_NO_TRUNCATE 0x1000          /* Don't truncate filenames */
 
 /* short cut to get to the affs specific sb data */
 static inline struct affs_sb_info *AFFS_SB(struct super_block *sb)
@@ -137,9 +129,13 @@ extern void        affs_fix_checksum(struct super_block *sb, struct buffer_head *bh);
 extern void    secs_to_datestamp(time_t secs, struct affs_date *ds);
 extern umode_t prot_to_mode(u32 prot);
 extern void    mode_to_prot(struct inode *inode);
-extern void    affs_error(struct super_block *sb, const char *function, const char *fmt, ...);
-extern void    affs_warning(struct super_block *sb, const char *function, const char *fmt, ...);
-extern int     affs_check_name(const unsigned char *name, int len);
+extern void    affs_error(struct super_block *sb, const char *function,
+                          const char *fmt, ...);
+extern void    affs_warning(struct super_block *sb, const char *function,
+                            const char *fmt, ...);
+extern bool    affs_nofilenametruncate(const struct dentry *dentry);
+extern int     affs_check_name(const unsigned char *name, int len,
+                               bool notruncate);
 extern int     affs_copy_name(unsigned char *bstr, struct dentry *dentry);
 
 /* bitmap. c */
index d9a4367..533a322 100644 (file)
@@ -471,20 +471,27 @@ affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
                function,ErrorBuffer);
 }
 
+bool
+affs_nofilenametruncate(const struct dentry *dentry)
+{
+       struct inode *inode = dentry->d_inode;
+       return AFFS_SB(inode->i_sb)->s_flags & SF_NO_TRUNCATE;
+
+}
+
 /* Check if the name is valid for a affs object. */
 
 int
-affs_check_name(const unsigned char *name, int len)
+affs_check_name(const unsigned char *name, int len, bool notruncate)
 {
        int      i;
 
-       if (len > 30)
-#ifdef AFFS_NO_TRUNCATE
-               return -ENAMETOOLONG;
-#else
-               len = 30;
-#endif
-
+       if (len > 30) {
+               if (notruncate)
+                       return -ENAMETOOLONG;
+               else
+                       len = 30;
+       }
        for (i = 0; i < len; i++) {
                if (name[i] < ' ' || name[i] == ':'
                    || (name[i] > 0x7e && name[i] < 0xa0))
index f1eba8c..cbbda47 100644 (file)
@@ -52,8 +52,10 @@ affs_readdir(struct file *file, struct dir_context *ctx)
        int                      hash_pos;
        int                      chain_pos;
        u32                      ino;
+       int                      error = 0;
 
-       pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)ctx->pos);
+       pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",
+                inode->i_ino, (unsigned long)ctx->pos);
 
        if (ctx->pos < 2) {
                file->private_data = (void *)0;
@@ -72,7 +74,7 @@ affs_readdir(struct file *file, struct dir_context *ctx)
        }
        dir_bh = affs_bread(sb, inode->i_ino);
        if (!dir_bh)
-               goto readdir_out;
+               goto out_unlock_dir;
 
        /* If the directory hasn't changed since the last call to readdir(),
         * we can jump directly to where we left off.
@@ -88,7 +90,8 @@ affs_readdir(struct file *file, struct dir_context *ctx)
                fh_bh = affs_bread(sb, ino);
                if (!fh_bh) {
                        affs_error(sb, "readdir","Cannot read block %d", i);
-                       return -EIO;
+                       error = -EIO;
+                       goto out_brelse_dir;
                }
                ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
                affs_brelse(fh_bh);
@@ -107,29 +110,34 @@ inside:
                do {
                        fh_bh = affs_bread(sb, ino);
                        if (!fh_bh) {
-                               affs_error(sb, "readdir","Cannot read block %d", ino);
+                               affs_error(sb, "readdir",
+                                          "Cannot read block %d", ino);
                                break;
                        }
 
                        namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
                        name = AFFS_TAIL(sb, fh_bh)->name + 1;
-                       pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
+                       pr_debug("AFFS: readdir(): dir_emit(\"%.*s\", "
+                                "ino=%u), hash=%d, f_pos=%x\n",
                                 namelen, name, ino, hash_pos, (u32)ctx->pos);
+
                        if (!dir_emit(ctx, name, namelen, ino, DT_UNKNOWN))
-                               goto readdir_done;
+                               goto done;
                        ctx->pos++;
                        ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
                        affs_brelse(fh_bh);
                        fh_bh = NULL;
                } while (ino);
        }
-readdir_done:
+done:
        file->f_version = inode->i_version;
        file->private_data = (void *)(long)ino;
+       affs_brelse(fh_bh);
 
-readdir_out:
+out_brelse_dir:
        affs_brelse(dir_bh);
-       affs_brelse(fh_bh);
+
+out_unlock_dir:
        affs_unlock_dir(inode);
-       return 0;
+       return error;
 }
index c36cbb4..6dae1cc 100644 (file)
@@ -60,13 +60,13 @@ affs_get_toupper(struct super_block *sb)
  * Note: the dentry argument is the parent dentry.
  */
 static inline int
-__affs_hash_dentry(struct qstr *qstr, toupper_t toupper)
+__affs_hash_dentry(struct qstr *qstr, toupper_t toupper, bool notruncate)
 {
        const u8 *name = qstr->name;
        unsigned long hash;
        int i;
 
-       i = affs_check_name(qstr->name, qstr->len);
+       i = affs_check_name(qstr->name, qstr->len, notruncate);
        if (i)
                return i;
 
@@ -82,16 +82,22 @@ __affs_hash_dentry(struct qstr *qstr, toupper_t toupper)
 static int
 affs_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
-       return __affs_hash_dentry(qstr, affs_toupper);
+       return __affs_hash_dentry(qstr, affs_toupper,
+                                 affs_nofilenametruncate(dentry));
+
 }
+
 static int
 affs_intl_hash_dentry(const struct dentry *dentry, struct qstr *qstr)
 {
-       return __affs_hash_dentry(qstr, affs_intl_toupper);
+       return __affs_hash_dentry(qstr, affs_intl_toupper,
+                                 affs_nofilenametruncate(dentry));
+
 }
 
 static inline int __affs_compare_dentry(unsigned int len,
-               const char *str, const struct qstr *name, toupper_t toupper)
+               const char *str, const struct qstr *name, toupper_t toupper,
+               bool notruncate)
 {
        const u8 *aname = str;
        const u8 *bname = name->name;
@@ -101,7 +107,7 @@ static inline int __affs_compare_dentry(unsigned int len,
         * must be valid. 'name' must be validated first.
         */
 
-       if (affs_check_name(name->name, name->len))
+       if (affs_check_name(name->name, name->len, notruncate))
                return 1;
 
        /*
@@ -126,13 +132,18 @@ static int
 affs_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
-       return __affs_compare_dentry(len, str, name, affs_toupper);
+
+       return __affs_compare_dentry(len, str, name, affs_toupper,
+                                    affs_nofilenametruncate(parent));
 }
+
 static int
 affs_intl_compare_dentry(const struct dentry *parent, const struct dentry *dentry,
                unsigned int len, const char *str, const struct qstr *name)
 {
-       return __affs_compare_dentry(len, str, name, affs_intl_toupper);
+       return __affs_compare_dentry(len, str, name, affs_intl_toupper,
+                                    affs_nofilenametruncate(parent));
+
 }
 
 /*
@@ -411,7 +422,10 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
                 (u32)old_dir->i_ino, (int)old_dentry->d_name.len, old_dentry->d_name.name,
                 (u32)new_dir->i_ino, (int)new_dentry->d_name.len, new_dentry->d_name.name);
 
-       retval = affs_check_name(new_dentry->d_name.name,new_dentry->d_name.len);
+       retval = affs_check_name(new_dentry->d_name.name,
+                                new_dentry->d_name.len,
+                                affs_nofilenametruncate(old_dentry));
+
        if (retval)
                return retval;
 
index 3074530..6d589f2 100644 (file)
@@ -128,7 +128,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        affs_inode_cachep = kmem_cache_create("affs_inode_cache",
                                             sizeof(struct affs_inode_info),
@@ -163,7 +163,7 @@ static const struct super_operations affs_sops = {
 };
 
 enum {
-       Opt_bs, Opt_mode, Opt_mufs, Opt_prefix, Opt_protect,
+       Opt_bs, Opt_mode, Opt_mufs, Opt_notruncate, Opt_prefix, Opt_protect,
        Opt_reserved, Opt_root, Opt_setgid, Opt_setuid,
        Opt_verbose, Opt_volume, Opt_ignore, Opt_err,
 };
@@ -172,6 +172,7 @@ static const match_table_t tokens = {
        {Opt_bs, "bs=%u"},
        {Opt_mode, "mode=%o"},
        {Opt_mufs, "mufs"},
+       {Opt_notruncate, "nofilenametruncate"},
        {Opt_prefix, "prefix=%s"},
        {Opt_protect, "protect"},
        {Opt_reserved, "reserved=%u"},
@@ -233,6 +234,9 @@ parse_options(char *options, kuid_t *uid, kgid_t *gid, int *mode, int *reserved,
                case Opt_mufs:
                        *mount_opts |= SF_MUFS;
                        break;
+               case Opt_notruncate:
+                       *mount_opts |= SF_NO_TRUNCATE;
+                       break;
                case Opt_prefix:
                        *prefix = match_strdup(&args[0]);
                        if (!*prefix)
index 3182c0e..232e03d 100644 (file)
@@ -103,6 +103,9 @@ static struct autofs_dev_ioctl *copy_dev_ioctl(struct autofs_dev_ioctl __user *i
        if (tmp.size < sizeof(tmp))
                return ERR_PTR(-EINVAL);
 
+       if (tmp.size > (PATH_MAX + sizeof(tmp)))
+               return ERR_PTR(-ENAMETOOLONG);
+
        return memdup_user(in, tmp.size);
 }
 
index 29aa5cf..7041ac3 100644 (file)
@@ -266,7 +266,7 @@ static void init_once(void *foo)
        inode_init_once(&bi->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        bfs_inode_cachep = kmem_cache_create("bfs_inode_cache",
                                             sizeof(struct bfs_inode_info),
index 0f59799..aa3cb62 100644 (file)
@@ -584,7 +584,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
        unsigned long start_code, end_code, start_data, end_data;
        unsigned long reloc_func_desc __maybe_unused = 0;
        int executable_stack = EXSTACK_DEFAULT;
-       unsigned long def_flags = 0;
        struct pt_regs *regs = current_pt_regs();
        struct {
                struct elfhdr elf_ex;
@@ -724,9 +723,6 @@ static int load_elf_binary(struct linux_binprm *bprm)
        if (retval)
                goto out_free_dentry;
 
-       /* OK, This is the point of no return */
-       current->mm->def_flags = def_flags;
-
        /* Do this immediately, since STACK_TOP as used in setup_arg_pages
           may depend on the personality.  */
        SET_PERSONALITY(loc->elf_ex);
index 29696b7..1c2ce0c 100644 (file)
@@ -182,6 +182,9 @@ static int bdev_integrity_enabled(struct block_device *bdev, int rw)
  */
 int bio_integrity_enabled(struct bio *bio)
 {
+       if (!bio_is_rw(bio))
+               return 0;
+
        /* Already protected? */
        if (bio_integrity(bio))
                return 0;
@@ -309,10 +312,9 @@ static int bio_integrity_generate_verify(struct bio *bio, int operate)
 {
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
        struct blk_integrity_exchg bix;
-       struct bio_vec bv;
-       struct bvec_iter iter;
+       struct bio_vec *bv;
        sector_t sector;
-       unsigned int sectors, ret = 0;
+       unsigned int sectors, ret = 0, i;
        void *prot_buf = bio->bi_integrity->bip_buf;
 
        if (operate)
@@ -323,16 +325,16 @@ static int bio_integrity_generate_verify(struct bio *bio, int operate)
        bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
        bix.sector_size = bi->sector_size;
 
-       bio_for_each_segment(bv, bio, iter) {
-               void *kaddr = kmap_atomic(bv.bv_page);
-               bix.data_buf = kaddr + bv.bv_offset;
-               bix.data_size = bv.bv_len;
+       bio_for_each_segment_all(bv, bio, i) {
+               void *kaddr = kmap_atomic(bv->bv_page);
+               bix.data_buf = kaddr + bv->bv_offset;
+               bix.data_size = bv->bv_len;
                bix.prot_buf = prot_buf;
                bix.sector = sector;
 
-               if (operate) {
+               if (operate)
                        bi->generate_fn(&bix);
-               else {
+               else {
                        ret = bi->verify_fn(&bix);
                        if (ret) {
                                kunmap_atomic(kaddr);
@@ -340,7 +342,7 @@ static int bio_integrity_generate_verify(struct bio *bio, int operate)
                        }
                }
 
-               sectors = bv.bv_len / bi->sector_size;
+               sectors = bv->bv_len / bi->sector_size;
                sector += sectors;
                prot_buf += sectors * bi->tuple_size;
 
index e1ffb1e..c660527 100644 (file)
@@ -2025,6 +2025,7 @@ out:
 
 static const struct vm_operations_struct btrfs_file_vm_ops = {
        .fault          = filemap_fault,
+       .map_pages      = filemap_map_pages,
        .page_mkwrite   = btrfs_page_mkwrite,
        .remap_pages    = generic_file_remap_pages,
 };
index 8c44fdd..834f9f3 100644 (file)
@@ -205,6 +205,7 @@ void ceph_fscache_register_inode_cookie(struct ceph_fs_client* fsc,
        ci->fscache = fscache_acquire_cookie(fsc->fscache,
                                             &ceph_fscache_inode_object_def,
                                             ci, true);
+       fscache_check_consistency(ci->fscache);
 done:
        mutex_unlock(&inode->i_mutex);
 
index da95f61..5ac591b 100644 (file)
@@ -48,6 +48,12 @@ void ceph_readpage_to_fscache(struct inode *inode, struct page *page);
 void ceph_invalidate_fscache_page(struct inode* inode, struct page *page);
 void ceph_queue_revalidate(struct inode *inode);
 
+static inline void ceph_fscache_update_objectsize(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       fscache_attr_changed(ci->fscache);
+}
+
 static inline void ceph_fscache_invalidate(struct inode *inode)
 {
        fscache_invalidate(ceph_inode(inode)->fscache);
@@ -135,6 +141,10 @@ static inline void ceph_readpage_to_fscache(struct inode *inode,
 {
 }
 
+static inline void ceph_fscache_update_objectsize(struct inode *inode)
+{
+}
+
 static inline void ceph_fscache_invalidate(struct inode *inode)
 {
 }
index 1754338..2e5e648 100644 (file)
@@ -622,8 +622,10 @@ retry:
 
        if (flags & CEPH_CAP_FLAG_AUTH) {
                if (ci->i_auth_cap == NULL ||
-                   ceph_seq_cmp(ci->i_auth_cap->mseq, mseq) < 0)
+                   ceph_seq_cmp(ci->i_auth_cap->mseq, mseq) < 0) {
                        ci->i_auth_cap = cap;
+                       cap->mds_wanted = wanted;
+               }
                ci->i_cap_exporting_issued = 0;
        } else {
                WARN_ON(ci->i_auth_cap == cap);
@@ -885,7 +887,10 @@ int __ceph_caps_mds_wanted(struct ceph_inode_info *ci)
                cap = rb_entry(p, struct ceph_cap, ci_node);
                if (!__cap_is_valid(cap))
                        continue;
-               mds_wanted |= cap->mds_wanted;
+               if (cap == ci->i_auth_cap)
+                       mds_wanted |= cap->mds_wanted;
+               else
+                       mds_wanted |= (cap->mds_wanted & ~CEPH_CAP_ANY_FILE_WR);
        }
        return mds_wanted;
 }
index 6d59006..16b54aa 100644 (file)
@@ -93,6 +93,8 @@ static int mdsc_show(struct seq_file *s, void *p)
                } else if (req->r_path1) {
                        seq_printf(s, " #%llx/%s", req->r_ino1.ino,
                                   req->r_path1);
+               } else {
+                       seq_printf(s, " #%llx", req->r_ino1.ino);
                }
 
                if (req->r_old_dentry) {
@@ -102,7 +104,8 @@ static int mdsc_show(struct seq_file *s, void *p)
                                path = NULL;
                        spin_lock(&req->r_old_dentry->d_lock);
                        seq_printf(s, " #%llx/%.*s (%s)",
-                          ceph_ino(req->r_old_dentry_dir),
+                                  req->r_old_dentry_dir ?
+                                  ceph_ino(req->r_old_dentry_dir) : 0,
                                   req->r_old_dentry->d_name.len,
                                   req->r_old_dentry->d_name.name,
                                   path ? path : "");
index 45eda6d..766410a 100644 (file)
@@ -119,7 +119,8 @@ static int fpos_cmp(loff_t l, loff_t r)
  * defined IFF we hold CEPH_CAP_FILE_SHARED (which will be revoked by
  * the MDS if/when the directory is modified).
  */
-static int __dcache_readdir(struct file *file, struct dir_context *ctx)
+static int __dcache_readdir(struct file *file,  struct dir_context *ctx,
+                           u32 shared_gen)
 {
        struct ceph_file_info *fi = file->private_data;
        struct dentry *parent = file->f_dentry;
@@ -133,8 +134,8 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx)
        last = fi->dentry;
        fi->dentry = NULL;
 
-       dout("__dcache_readdir %p at %llu (last %p)\n", dir, ctx->pos,
-            last);
+       dout("__dcache_readdir %p v%u at %llu (last %p)\n",
+            dir, shared_gen, ctx->pos, last);
 
        spin_lock(&parent->d_lock);
 
@@ -161,7 +162,8 @@ more:
                        goto out_unlock;
                }
                spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
-               if (!d_unhashed(dentry) && dentry->d_inode &&
+               if (di->lease_shared_gen == shared_gen &&
+                   !d_unhashed(dentry) && dentry->d_inode &&
                    ceph_snap(dentry->d_inode) != CEPH_SNAPDIR &&
                    ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
                    fpos_cmp(ctx->pos, di->offset) <= 0)
@@ -190,7 +192,7 @@ more:
                if (last) {
                        /* remember our position */
                        fi->dentry = last;
-                       fi->next_offset = di->offset;
+                       fi->next_offset = fpos_off(di->offset);
                }
                dput(dentry);
                return 0;
@@ -252,8 +254,6 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
        int err;
        u32 ftype;
        struct ceph_mds_reply_info_parsed *rinfo;
-       const int max_entries = fsc->mount_options->max_readdir;
-       const int max_bytes = fsc->mount_options->max_readdir_bytes;
 
        dout("readdir %p file %p frag %u off %u\n", inode, file, frag, off);
        if (fi->flags & CEPH_F_ATEND)
@@ -291,8 +291,9 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
            ceph_snap(inode) != CEPH_SNAPDIR &&
            __ceph_dir_is_complete(ci) &&
            __ceph_caps_issued_mask(ci, CEPH_CAP_FILE_SHARED, 1)) {
+               u32 shared_gen = ci->i_shared_gen;
                spin_unlock(&ci->i_ceph_lock);
-               err = __dcache_readdir(file, ctx);
+               err = __dcache_readdir(file, ctx, shared_gen);
                if (err != -EAGAIN)
                        return err;
        } else {
@@ -322,14 +323,16 @@ more:
                        fi->last_readdir = NULL;
                }
 
-               /* requery frag tree, as the frag topology may have changed */
-               frag = ceph_choose_frag(ceph_inode(inode), frag, NULL, NULL);
-
                dout("readdir fetching %llx.%llx frag %x offset '%s'\n",
                     ceph_vinop(inode), frag, fi->last_name);
                req = ceph_mdsc_create_request(mdsc, op, USE_AUTH_MDS);
                if (IS_ERR(req))
                        return PTR_ERR(req);
+               err = ceph_alloc_readdir_reply_buffer(req, inode);
+               if (err) {
+                       ceph_mdsc_put_request(req);
+                       return err;
+               }
                req->r_inode = inode;
                ihold(inode);
                req->r_dentry = dget(file->f_dentry);
@@ -340,9 +343,6 @@ more:
                req->r_path2 = kstrdup(fi->last_name, GFP_NOFS);
                req->r_readdir_offset = fi->next_offset;
                req->r_args.readdir.frag = cpu_to_le32(frag);
-               req->r_args.readdir.max_entries = cpu_to_le32(max_entries);
-               req->r_args.readdir.max_bytes = cpu_to_le32(max_bytes);
-               req->r_num_caps = max_entries + 1;
                err = ceph_mdsc_do_request(mdsc, NULL, req);
                if (err < 0) {
                        ceph_mdsc_put_request(req);
@@ -369,9 +369,9 @@ more:
                                fi->next_offset = 0;
                        off = fi->next_offset;
                }
+               fi->frag = frag;
                fi->offset = fi->next_offset;
                fi->last_readdir = req;
-               fi->frag = frag;
 
                if (req->r_reply_info.dir_end) {
                        kfree(fi->last_name);
@@ -454,7 +454,7 @@ more:
        return 0;
 }
 
-static void reset_readdir(struct ceph_file_info *fi)
+static void reset_readdir(struct ceph_file_info *fi, unsigned frag)
 {
        if (fi->last_readdir) {
                ceph_mdsc_put_request(fi->last_readdir);
@@ -462,7 +462,10 @@ static void reset_readdir(struct ceph_file_info *fi)
        }
        kfree(fi->last_name);
        fi->last_name = NULL;
-       fi->next_offset = 2;  /* compensate for . and .. */
+       if (ceph_frag_is_leftmost(frag))
+               fi->next_offset = 2;  /* compensate for . and .. */
+       else
+               fi->next_offset = 0;
        if (fi->dentry) {
                dput(fi->dentry);
                fi->dentry = NULL;
@@ -474,7 +477,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence)
 {
        struct ceph_file_info *fi = file->private_data;
        struct inode *inode = file->f_mapping->host;
-       loff_t old_offset = offset;
+       loff_t old_offset = ceph_make_fpos(fi->frag, fi->next_offset);
        loff_t retval;
 
        mutex_lock(&inode->i_mutex);
@@ -491,7 +494,7 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence)
                goto out;
        }
 
-       if (offset >= 0 && offset <= inode->i_sb->s_maxbytes) {
+       if (offset >= 0) {
                if (offset != file->f_pos) {
                        file->f_pos = offset;
                        file->f_version = 0;
@@ -504,14 +507,14 @@ static loff_t ceph_dir_llseek(struct file *file, loff_t offset, int whence)
                 * seek to new frag, or seek prior to current chunk.
                 */
                if (offset == 0 ||
-                   fpos_frag(offset) != fpos_frag(old_offset) ||
+                   fpos_frag(offset) != fi->frag ||
                    fpos_off(offset) < fi->offset) {
                        dout("dir_llseek dropping %p content\n", file);
-                       reset_readdir(fi);
+                       reset_readdir(fi, fpos_frag(offset));
                }
 
                /* bump dir_release_count if we did a forward seek */
-               if (offset > old_offset)
+               if (fpos_cmp(offset, old_offset) > 0)
                        fi->dir_release_count--;
        }
 out:
@@ -812,8 +815,7 @@ static int ceph_link(struct dentry *old_dentry, struct inode *dir,
        }
        req->r_dentry = dget(dentry);
        req->r_num_caps = 2;
-       req->r_old_dentry = dget(old_dentry); /* or inode? hrm. */
-       req->r_old_dentry_dir = ceph_get_dentry_parent_inode(old_dentry);
+       req->r_old_dentry = dget(old_dentry);
        req->r_locked_dir = dir;
        req->r_dentry_drop = CEPH_CAP_FILE_SHARED;
        req->r_dentry_unless = CEPH_CAP_FILE_EXCL;
@@ -911,10 +913,11 @@ static int ceph_rename(struct inode *old_dir, struct dentry *old_dentry,
        req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_RENAME, USE_AUTH_MDS);
        if (IS_ERR(req))
                return PTR_ERR(req);
+       ihold(old_dir);
        req->r_dentry = dget(new_dentry);
        req->r_num_caps = 2;
        req->r_old_dentry = dget(old_dentry);
-       req->r_old_dentry_dir = ceph_get_dentry_parent_inode(old_dentry);
+       req->r_old_dentry_dir = old_dir;
        req->r_locked_dir = new_dir;
        req->r_old_dentry_drop = CEPH_CAP_FILE_SHARED;
        req->r_old_dentry_unless = CEPH_CAP_FILE_EXCL;
index 16796be..00d6af6 100644 (file)
@@ -7,23 +7,6 @@
 #include "super.h"
 #include "mds_client.h"
 
-/*
- * NFS export support
- *
- * NFS re-export of a ceph mount is, at present, only semireliable.
- * The basic issue is that the Ceph architectures doesn't lend itself
- * well to generating filehandles that will remain valid forever.
- *
- * So, we do our best.  If you're lucky, your inode will be in the
- * client's cache.  If it's not, and you have a connectable fh, then
- * the MDS server may be able to find it for you.  Otherwise, you get
- * ESTALE.
- *
- * There are ways to this more reliable, but in the non-connectable fh
- * case, we won't every work perfectly, and in the connectable case,
- * some changes are needed on the MDS side to work better.
- */
-
 /*
  * Basic fh
  */
@@ -32,22 +15,12 @@ struct ceph_nfs_fh {
 } __attribute__ ((packed));
 
 /*
- * Larger 'connectable' fh that includes parent ino and name hash.
- * Use this whenever possible, as it works more reliably.
+ * Larger fh that includes parent ino.
  */
 struct ceph_nfs_confh {
        u64 ino, parent_ino;
-       u32 parent_name_hash;
 } __attribute__ ((packed));
 
-/*
- * The presence of @parent_inode here tells us whether NFS wants a
- * connectable file handle.  However, we want to make a connectionable
- * file handle unconditionally so that the MDS gets as much of a hint
- * as possible.  That means we only use @parent_dentry to indicate
- * whether nfsd wants a connectable fh, and whether we should indicate
- * failure from a too-small @max_len.
- */
 static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
                          struct inode *parent_inode)
 {
@@ -56,54 +29,36 @@ static int ceph_encode_fh(struct inode *inode, u32 *rawfh, int *max_len,
        struct ceph_nfs_confh *cfh = (void *)rawfh;
        int connected_handle_length = sizeof(*cfh)/4;
        int handle_length = sizeof(*fh)/4;
-       struct dentry *dentry;
-       struct dentry *parent;
 
        /* don't re-export snaps */
        if (ceph_snap(inode) != CEPH_NOSNAP)
                return -EINVAL;
 
-       dentry = d_find_alias(inode);
+       if (parent_inode && (*max_len < connected_handle_length)) {
+               *max_len = connected_handle_length;
+               return FILEID_INVALID;
+       } else if (*max_len < handle_length) {
+               *max_len = handle_length;
+               return FILEID_INVALID;
+       }
 
-       /* if we found an alias, generate a connectable fh */
-       if (*max_len >= connected_handle_length && dentry) {
-               dout("encode_fh %p connectable\n", dentry);
-               spin_lock(&dentry->d_lock);
-               parent = dentry->d_parent;
+       if (parent_inode) {
+               dout("encode_fh %llx with parent %llx\n",
+                    ceph_ino(inode), ceph_ino(parent_inode));
                cfh->ino = ceph_ino(inode);
-               cfh->parent_ino = ceph_ino(parent->d_inode);
-               cfh->parent_name_hash = ceph_dentry_hash(parent->d_inode,
-                                                        dentry);
+               cfh->parent_ino = ceph_ino(parent_inode);
                *max_len = connected_handle_length;
-               type = 2;
-               spin_unlock(&dentry->d_lock);
-       } else if (*max_len >= handle_length) {
-               if (parent_inode) {
-                       /* nfsd wants connectable */
-                       *max_len = connected_handle_length;
-                       type = FILEID_INVALID;
-               } else {
-                       dout("encode_fh %p\n", dentry);
-                       fh->ino = ceph_ino(inode);
-                       *max_len = handle_length;
-                       type = 1;
-               }
+               type = FILEID_INO32_GEN_PARENT;
        } else {
+               dout("encode_fh %llx\n", ceph_ino(inode));
+               fh->ino = ceph_ino(inode);
                *max_len = handle_length;
-               type = FILEID_INVALID;
+               type = FILEID_INO32_GEN;
        }
-       if (dentry)
-               dput(dentry);
        return type;
 }
 
-/*
- * convert regular fh to dentry
- *
- * FIXME: we should try harder by querying the mds for the ino.
- */
-static struct dentry *__fh_to_dentry(struct super_block *sb,
-                                    struct ceph_nfs_fh *fh, int fh_len)
+static struct dentry *__fh_to_dentry(struct super_block *sb, u64 ino)
 {
        struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
        struct inode *inode;
@@ -111,11 +66,7 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,
        struct ceph_vino vino;
        int err;
 
-       if (fh_len < sizeof(*fh) / 4)
-               return ERR_PTR(-ESTALE);
-
-       dout("__fh_to_dentry %llx\n", fh->ino);
-       vino.ino = fh->ino;
+       vino.ino = ino;
        vino.snap = CEPH_NOSNAP;
        inode = ceph_find_inode(sb, vino);
        if (!inode) {
@@ -139,139 +90,161 @@ static struct dentry *__fh_to_dentry(struct super_block *sb,
 
        dentry = d_obtain_alias(inode);
        if (IS_ERR(dentry)) {
-               pr_err("fh_to_dentry %llx -- inode %p but ENOMEM\n",
-                      fh->ino, inode);
                iput(inode);
                return dentry;
        }
        err = ceph_init_dentry(dentry);
        if (err < 0) {
-               iput(inode);
+               dput(dentry);
                return ERR_PTR(err);
        }
-       dout("__fh_to_dentry %llx %p dentry %p\n", fh->ino, inode, dentry);
+       dout("__fh_to_dentry %llx %p dentry %p\n", ino, inode, dentry);
        return dentry;
 }
 
 /*
- * convert connectable fh to dentry
+ * convert regular fh to dentry
  */
-static struct dentry *__cfh_to_dentry(struct super_block *sb,
-                                     struct ceph_nfs_confh *cfh, int fh_len)
+static struct dentry *ceph_fh_to_dentry(struct super_block *sb,
+                                       struct fid *fid,
+                                       int fh_len, int fh_type)
+{
+       struct ceph_nfs_fh *fh = (void *)fid->raw;
+
+       if (fh_type != FILEID_INO32_GEN  &&
+           fh_type != FILEID_INO32_GEN_PARENT)
+               return NULL;
+       if (fh_len < sizeof(*fh) / 4)
+               return NULL;
+
+       dout("fh_to_dentry %llx\n", fh->ino);
+       return __fh_to_dentry(sb, fh->ino);
+}
+
+static struct dentry *__get_parent(struct super_block *sb,
+                                  struct dentry *child, u64 ino)
 {
        struct ceph_mds_client *mdsc = ceph_sb_to_client(sb)->mdsc;
+       struct ceph_mds_request *req;
        struct inode *inode;
        struct dentry *dentry;
-       struct ceph_vino vino;
        int err;
 
-       if (fh_len < sizeof(*cfh) / 4)
-               return ERR_PTR(-ESTALE);
-
-       dout("__cfh_to_dentry %llx (%llx/%x)\n",
-            cfh->ino, cfh->parent_ino, cfh->parent_name_hash);
-
-       vino.ino = cfh->ino;
-       vino.snap = CEPH_NOSNAP;
-       inode = ceph_find_inode(sb, vino);
-       if (!inode) {
-               struct ceph_mds_request *req;
-
-               req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPHASH,
-                                              USE_ANY_MDS);
-               if (IS_ERR(req))
-                       return ERR_CAST(req);
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPPARENT,
+                                      USE_ANY_MDS);
+       if (IS_ERR(req))
+               return ERR_CAST(req);
 
-               req->r_ino1 = vino;
-               req->r_ino2.ino = cfh->parent_ino;
-               req->r_ino2.snap = CEPH_NOSNAP;
-               req->r_path2 = kmalloc(16, GFP_NOFS);
-               snprintf(req->r_path2, 16, "%d", cfh->parent_name_hash);
-               req->r_num_caps = 1;
-               err = ceph_mdsc_do_request(mdsc, NULL, req);
-               inode = req->r_target_inode;
-               if (inode)
-                       ihold(inode);
-               ceph_mdsc_put_request(req);
-               if (!inode)
-                       return ERR_PTR(err ? err : -ESTALE);
+       if (child) {
+               req->r_inode = child->d_inode;
+               ihold(child->d_inode);
+       } else {
+               req->r_ino1 = (struct ceph_vino) {
+                       .ino = ino,
+                       .snap = CEPH_NOSNAP,
+               };
        }
+       req->r_num_caps = 1;
+       err = ceph_mdsc_do_request(mdsc, NULL, req);
+       inode = req->r_target_inode;
+       if (inode)
+               ihold(inode);
+       ceph_mdsc_put_request(req);
+       if (!inode)
+               return ERR_PTR(-ENOENT);
 
        dentry = d_obtain_alias(inode);
        if (IS_ERR(dentry)) {
-               pr_err("cfh_to_dentry %llx -- inode %p but ENOMEM\n",
-                      cfh->ino, inode);
                iput(inode);
                return dentry;
        }
        err = ceph_init_dentry(dentry);
        if (err < 0) {
-               iput(inode);
+               dput(dentry);
                return ERR_PTR(err);
        }
-       dout("__cfh_to_dentry %llx %p dentry %p\n", cfh->ino, inode, dentry);
+       dout("__get_parent ino %llx parent %p ino %llx.%llx\n",
+            child ? ceph_ino(child->d_inode) : ino,
+            dentry, ceph_vinop(inode));
        return dentry;
 }
 
-static struct dentry *ceph_fh_to_dentry(struct super_block *sb, struct fid *fid,
-                                       int fh_len, int fh_type)
+struct dentry *ceph_get_parent(struct dentry *child)
 {
-       if (fh_type == 1)
-               return __fh_to_dentry(sb, (struct ceph_nfs_fh *)fid->raw,
-                                                               fh_len);
-       else
-               return __cfh_to_dentry(sb, (struct ceph_nfs_confh *)fid->raw,
-                                                               fh_len);
+       /* don't re-export snaps */
+       if (ceph_snap(child->d_inode) != CEPH_NOSNAP)
+               return ERR_PTR(-EINVAL);
+
+       dout("get_parent %p ino %llx.%llx\n",
+            child, ceph_vinop(child->d_inode));
+       return __get_parent(child->d_sb, child, 0);
 }
 
 /*
- * get parent, if possible.
- *
- * FIXME: we could do better by querying the mds to discover the
- * parent.
+ * convert regular fh to parent
  */
 static struct dentry *ceph_fh_to_parent(struct super_block *sb,
-                                        struct fid *fid,
+                                       struct fid *fid,
                                        int fh_len, int fh_type)
 {
        struct ceph_nfs_confh *cfh = (void *)fid->raw;
-       struct ceph_vino vino;
-       struct inode *inode;
        struct dentry *dentry;
-       int err;
 
-       if (fh_type == 1)
-               return ERR_PTR(-ESTALE);
+       if (fh_type != FILEID_INO32_GEN_PARENT)
+               return NULL;
        if (fh_len < sizeof(*cfh) / 4)
-               return ERR_PTR(-ESTALE);
+               return NULL;
 
-       pr_debug("fh_to_parent %llx/%d\n", cfh->parent_ino,
-                cfh->parent_name_hash);
+       dout("fh_to_parent %llx\n", cfh->parent_ino);
+       dentry = __get_parent(sb, NULL, cfh->ino);
+       if (IS_ERR(dentry) && PTR_ERR(dentry) == -ENOENT)
+               dentry = __fh_to_dentry(sb, cfh->parent_ino);
+       return dentry;
+}
 
-       vino.ino = cfh->ino;
-       vino.snap = CEPH_NOSNAP;
-       inode = ceph_find_inode(sb, vino);
-       if (!inode)
-               return ERR_PTR(-ESTALE);
+static int ceph_get_name(struct dentry *parent, char *name,
+                        struct dentry *child)
+{
+       struct ceph_mds_client *mdsc;
+       struct ceph_mds_request *req;
+       int err;
 
-       dentry = d_obtain_alias(inode);
-       if (IS_ERR(dentry)) {
-               pr_err("fh_to_parent %llx -- inode %p but ENOMEM\n",
-                      cfh->ino, inode);
-               iput(inode);
-               return dentry;
-       }
-       err = ceph_init_dentry(dentry);
-       if (err < 0) {
-               iput(inode);
-               return ERR_PTR(err);
+       mdsc = ceph_inode_to_client(child->d_inode)->mdsc;
+       req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_LOOKUPNAME,
+                                      USE_ANY_MDS);
+       if (IS_ERR(req))
+               return PTR_ERR(req);
+
+       mutex_lock(&parent->d_inode->i_mutex);
+
+       req->r_inode = child->d_inode;
+       ihold(child->d_inode);
+       req->r_ino2 = ceph_vino(parent->d_inode);
+       req->r_locked_dir = parent->d_inode;
+       req->r_num_caps = 2;
+       err = ceph_mdsc_do_request(mdsc, NULL, req);
+
+       mutex_unlock(&parent->d_inode->i_mutex);
+
+       if (!err) {
+               struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
+               memcpy(name, rinfo->dname, rinfo->dname_len);
+               name[rinfo->dname_len] = 0;
+               dout("get_name %p ino %llx.%llx name %s\n",
+                    child, ceph_vinop(child->d_inode), name);
+       } else {
+               dout("get_name %p ino %llx.%llx err %d\n",
+                    child, ceph_vinop(child->d_inode), err);
        }
-       dout("fh_to_parent %llx %p dentry %p\n", cfh->ino, inode, dentry);
-       return dentry;
+
+       ceph_mdsc_put_request(req);
+       return err;
 }
 
 const struct export_operations ceph_export_ops = {
        .encode_fh = ceph_encode_fh,
        .fh_to_dentry = ceph_fh_to_dentry,
        .fh_to_parent = ceph_fh_to_parent,
+       .get_parent = ceph_get_parent,
+       .get_name = ceph_get_name,
 };
index 09c7afe..66075a4 100644 (file)
@@ -210,7 +210,7 @@ int ceph_open(struct inode *inode, struct file *file)
        ihold(inode);
 
        req->r_num_caps = 1;
-       if (flags & (O_CREAT|O_TRUNC))
+       if (flags & O_CREAT)
                parent_inode = ceph_get_dentry_parent_inode(file->f_dentry);
        err = ceph_mdsc_do_request(mdsc, parent_inode, req);
        iput(parent_inode);
@@ -291,8 +291,9 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
                }
                err = finish_open(file, dentry, ceph_open, opened);
        }
-
 out_err:
+       if (!req->r_err && req->r_target_inode)
+               ceph_put_fmode(ceph_inode(req->r_target_inode), req->r_fmode);
        ceph_mdsc_put_request(req);
        dout("atomic_open result=%d\n", err);
        return err;
@@ -970,6 +971,7 @@ retry_snap:
                        goto retry_snap;
                }
        } else {
+               loff_t old_size = inode->i_size;
                /*
                 * No need to acquire the i_truncate_mutex. Because
                 * the MDS revokes Fwb caps before sending truncate
@@ -980,6 +982,8 @@ retry_snap:
                written = generic_file_buffered_write(iocb, iov, nr_segs,
                                                      pos, &iocb->ki_pos,
                                                      count, 0);
+               if (inode->i_size > old_size)
+                       ceph_fscache_update_objectsize(inode);
                mutex_unlock(&inode->i_mutex);
        }
 
index 32d519d..0b0728e 100644 (file)
@@ -659,14 +659,6 @@ static int fill_inode(struct inode *inode,
                            le32_to_cpu(info->time_warp_seq),
                            &ctime, &mtime, &atime);
 
-       /* only update max_size on auth cap */
-       if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) &&
-           ci->i_max_size != le64_to_cpu(info->max_size)) {
-               dout("max_size %lld -> %llu\n", ci->i_max_size,
-                    le64_to_cpu(info->max_size));
-               ci->i_max_size = le64_to_cpu(info->max_size);
-       }
-
        ci->i_layout = info->layout;
        inode->i_blkbits = fls(le32_to_cpu(info->layout.fl_stripe_unit)) - 1;
 
@@ -755,6 +747,14 @@ static int fill_inode(struct inode *inode,
                ci->i_max_offset = 2;
        }
 no_change:
+       /* only update max_size on auth cap */
+       if ((info->cap.flags & CEPH_CAP_FLAG_AUTH) &&
+           ci->i_max_size != le64_to_cpu(info->max_size)) {
+               dout("max_size %lld -> %llu\n", ci->i_max_size,
+                    le64_to_cpu(info->max_size));
+               ci->i_max_size = le64_to_cpu(info->max_size);
+       }
+
        spin_unlock(&ci->i_ceph_lock);
 
        /* queue truncate if we saw i_size decrease */
@@ -1044,10 +1044,59 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
                                         session, req->r_request_started, -1,
                                         &req->r_caps_reservation);
                        if (err < 0)
-                               return err;
+                               goto done;
                } else {
                        WARN_ON_ONCE(1);
                }
+
+               if (dir && req->r_op == CEPH_MDS_OP_LOOKUPNAME) {
+                       struct qstr dname;
+                       struct dentry *dn, *parent;
+
+                       BUG_ON(!rinfo->head->is_target);
+                       BUG_ON(req->r_dentry);
+
+                       parent = d_find_any_alias(dir);
+                       BUG_ON(!parent);
+
+                       dname.name = rinfo->dname;
+                       dname.len = rinfo->dname_len;
+                       dname.hash = full_name_hash(dname.name, dname.len);
+                       vino.ino = le64_to_cpu(rinfo->targeti.in->ino);
+                       vino.snap = le64_to_cpu(rinfo->targeti.in->snapid);
+retry_lookup:
+                       dn = d_lookup(parent, &dname);
+                       dout("d_lookup on parent=%p name=%.*s got %p\n",
+                            parent, dname.len, dname.name, dn);
+
+                       if (!dn) {
+                               dn = d_alloc(parent, &dname);
+                               dout("d_alloc %p '%.*s' = %p\n", parent,
+                                    dname.len, dname.name, dn);
+                               if (dn == NULL) {
+                                       dput(parent);
+                                       err = -ENOMEM;
+                                       goto done;
+                               }
+                               err = ceph_init_dentry(dn);
+                               if (err < 0) {
+                                       dput(dn);
+                                       dput(parent);
+                                       goto done;
+                               }
+                       } else if (dn->d_inode &&
+                                  (ceph_ino(dn->d_inode) != vino.ino ||
+                                   ceph_snap(dn->d_inode) != vino.snap)) {
+                               dout(" dn %p points to wrong inode %p\n",
+                                    dn, dn->d_inode);
+                               d_delete(dn);
+                               dput(dn);
+                               goto retry_lookup;
+                       }
+
+                       req->r_dentry = dn;
+                       dput(parent);
+               }
        }
 
        if (rinfo->head->is_target) {
@@ -1063,7 +1112,7 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req,
 
                err = fill_inode(in, &rinfo->targeti, NULL,
                                session, req->r_request_started,
-                               (le32_to_cpu(rinfo->head->result) == 0) ?
+                               (!req->r_aborted && rinfo->head->result == 0) ?
                                req->r_fmode : -1,
                                &req->r_caps_reservation);
                if (err < 0) {
@@ -1616,8 +1665,6 @@ static const struct inode_operations ceph_symlink_iops = {
        .getxattr = ceph_getxattr,
        .listxattr = ceph_listxattr,
        .removexattr = ceph_removexattr,
-       .get_acl = ceph_get_acl,
-       .set_acl = ceph_set_acl,
 };
 
 /*
@@ -1627,7 +1674,6 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
 {
        struct inode *inode = dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct inode *parent_inode;
        const unsigned int ia_valid = attr->ia_valid;
        struct ceph_mds_request *req;
        struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc;
@@ -1819,9 +1865,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
                req->r_inode_drop = release;
                req->r_args.setattr.mask = cpu_to_le32(mask);
                req->r_num_caps = 1;
-               parent_inode = ceph_get_dentry_parent_inode(dentry);
-               err = ceph_mdsc_do_request(mdsc, parent_inode, req);
-               iput(parent_inode);
+               err = ceph_mdsc_do_request(mdsc, NULL, req);
        }
        dout("setattr %p result=%d (%s locally, %d remote)\n", inode, err,
             ceph_cap_string(dirtied), mask);
index dc66c9e..efbe082 100644 (file)
@@ -64,7 +64,6 @@ static long __validate_layout(struct ceph_mds_client *mdsc,
 static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
 {
        struct inode *inode = file_inode(file);
-       struct inode *parent_inode;
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_mds_request *req;
        struct ceph_ioctl_layout l;
@@ -121,9 +120,7 @@ static long ceph_ioctl_set_layout(struct file *file, void __user *arg)
                cpu_to_le32(l.object_size);
        req->r_args.setlayout.layout.fl_pg_pool = cpu_to_le32(l.data_pool);
 
-       parent_inode = ceph_get_dentry_parent_inode(file->f_dentry);
-       err = ceph_mdsc_do_request(mdsc, parent_inode, req);
-       iput(parent_inode);
+       err = ceph_mdsc_do_request(mdsc, NULL, req);
        ceph_mdsc_put_request(req);
        return err;
 }
index ae6d14e..d94ba0d 100644 (file)
@@ -2,11 +2,31 @@
 
 #include <linux/file.h>
 #include <linux/namei.h>
+#include <linux/random.h>
 
 #include "super.h"
 #include "mds_client.h"
 #include <linux/ceph/pagelist.h>
 
+static u64 lock_secret;
+
+static inline u64 secure_addr(void *addr)
+{
+       u64 v = lock_secret ^ (u64)(unsigned long)addr;
+       /*
+        * Set the most significant bit, so that MDS knows the 'owner'
+        * is sufficient to identify the owner of lock. (old code uses
+        * both 'owner' and 'pid')
+        */
+       v |= (1ULL << 63);
+       return v;
+}
+
+void __init ceph_flock_init(void)
+{
+       get_random_bytes(&lock_secret, sizeof(lock_secret));
+}
+
 /**
  * Implement fcntl and flock locking functions.
  */
@@ -14,11 +34,11 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
                             int cmd, u8 wait, struct file_lock *fl)
 {
        struct inode *inode = file_inode(file);
-       struct ceph_mds_client *mdsc =
-               ceph_sb_to_client(inode->i_sb)->mdsc;
+       struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_mds_request *req;
        int err;
        u64 length = 0;
+       u64 owner;
 
        req = ceph_mdsc_create_request(mdsc, operation, USE_AUTH_MDS);
        if (IS_ERR(req))
@@ -32,25 +52,27 @@ static int ceph_lock_message(u8 lock_type, u16 operation, struct file *file,
        else
                length = fl->fl_end - fl->fl_start + 1;
 
-       dout("ceph_lock_message: rule: %d, op: %d, pid: %llu, start: %llu, "
-            "length: %llu, wait: %d, type: %d", (int)lock_type,
-            (int)operation, (u64)fl->fl_pid, fl->fl_start,
-            length, wait, fl->fl_type);
+       if (lock_type == CEPH_LOCK_FCNTL)
+               owner = secure_addr(fl->fl_owner);
+       else
+               owner = secure_addr(fl->fl_file);
+
+       dout("ceph_lock_message: rule: %d, op: %d, owner: %llx, pid: %llu, "
+            "start: %llu, length: %llu, wait: %d, type: %d", (int)lock_type,
+            (int)operation, owner, (u64)fl->fl_pid, fl->fl_start, length,
+            wait, fl->fl_type);
 
        req->r_args.filelock_change.rule = lock_type;
        req->r_args.filelock_change.type = cmd;
+       req->r_args.filelock_change.owner = cpu_to_le64(owner);
        req->r_args.filelock_change.pid = cpu_to_le64((u64)fl->fl_pid);
-       /* This should be adjusted, but I'm not sure if
-          namespaces actually get id numbers*/
-       req->r_args.filelock_change.pid_namespace =
-               cpu_to_le64((u64)(unsigned long)fl->fl_nspid);
        req->r_args.filelock_change.start = cpu_to_le64(fl->fl_start);
        req->r_args.filelock_change.length = cpu_to_le64(length);
        req->r_args.filelock_change.wait = wait;
 
        err = ceph_mdsc_do_request(mdsc, inode, req);
 
-       if ( operation == CEPH_MDS_OP_GETFILELOCK){
+       if (operation == CEPH_MDS_OP_GETFILELOCK) {
                fl->fl_pid = le64_to_cpu(req->r_reply_info.filelock_reply->pid);
                if (CEPH_LOCK_SHARED == req->r_reply_info.filelock_reply->type)
                        fl->fl_type = F_RDLCK;
@@ -87,14 +109,19 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
        u8 wait = 0;
        u16 op = CEPH_MDS_OP_SETFILELOCK;
 
-       fl->fl_nspid = get_pid(task_tgid(current));
-       dout("ceph_lock, fl_pid:%d", fl->fl_pid);
+       if (!(fl->fl_flags & FL_POSIX))
+               return -ENOLCK;
+       /* No mandatory locks */
+       if (__mandatory_lock(file->f_mapping->host) && fl->fl_type != F_UNLCK)
+               return -ENOLCK;
+
+       dout("ceph_lock, fl_owner: %p", fl->fl_owner);
 
        /* set wait bit as appropriate, then make command as Ceph expects it*/
-       if (F_SETLKW == cmd)
-               wait = 1;
-       if (F_GETLK == cmd)
+       if (IS_GETLK(cmd))
                op = CEPH_MDS_OP_GETFILELOCK;
+       else if (IS_SETLKW(cmd))
+               wait = 1;
 
        if (F_RDLCK == fl->fl_type)
                lock_cmd = CEPH_LOCK_SHARED;
@@ -105,7 +132,7 @@ int ceph_lock(struct file *file, int cmd, struct file_lock *fl)
 
        err = ceph_lock_message(CEPH_LOCK_FCNTL, op, file, lock_cmd, wait, fl);
        if (!err) {
-               if ( op != CEPH_MDS_OP_GETFILELOCK ){
+               if (op != CEPH_MDS_OP_GETFILELOCK) {
                        dout("mds locked, locking locally");
                        err = posix_lock_file(file, fl, NULL);
                        if (err && (CEPH_MDS_OP_SETFILELOCK == op)) {
@@ -131,20 +158,22 @@ int ceph_flock(struct file *file, int cmd, struct file_lock *fl)
 {
        u8 lock_cmd;
        int err;
-       u8 wait = 1;
-
-       fl->fl_nspid = get_pid(task_tgid(current));
-       dout("ceph_flock, fl_pid:%d", fl->fl_pid);
-
-       /* set wait bit, then clear it out of cmd*/
-       if (cmd & LOCK_NB)
-               wait = 0;
-       cmd = cmd & (LOCK_SH | LOCK_EX | LOCK_UN);
-       /* set command sequence that Ceph wants to see:
-          shared lock, exclusive lock, or unlock */
-       if (LOCK_SH == cmd)
+       u8 wait = 0;
+
+       if (!(fl->fl_flags & FL_FLOCK))
+               return -ENOLCK;
+       /* No mandatory locks */
+       if (__mandatory_lock(file->f_mapping->host) && fl->fl_type != F_UNLCK)
+               return -ENOLCK;
+
+       dout("ceph_flock, fl_file: %p", fl->fl_file);
+
+       if (IS_SETLKW(cmd))
+               wait = 1;
+
+       if (F_RDLCK == fl->fl_type)
                lock_cmd = CEPH_LOCK_SHARED;
-       else if (LOCK_EX == cmd)
+       else if (F_WRLCK == fl->fl_type)
                lock_cmd = CEPH_LOCK_EXCL;
        else
                lock_cmd = CEPH_LOCK_UNLOCK;
@@ -280,13 +309,14 @@ int lock_to_ceph_filelock(struct file_lock *lock,
                          struct ceph_filelock *cephlock)
 {
        int err = 0;
-
        cephlock->start = cpu_to_le64(lock->fl_start);
        cephlock->length = cpu_to_le64(lock->fl_end - lock->fl_start + 1);
        cephlock->client = cpu_to_le64(0);
-       cephlock->pid = cpu_to_le64(lock->fl_pid);
-       cephlock->pid_namespace =
-               cpu_to_le64((u64)(unsigned long)lock->fl_nspid);
+       cephlock->pid = cpu_to_le64((u64)lock->fl_pid);
+       if (lock->fl_flags & FL_POSIX)
+               cephlock->owner = cpu_to_le64(secure_addr(lock->fl_owner));
+       else
+               cephlock->owner = cpu_to_le64(secure_addr(lock->fl_file));
 
        switch (lock->fl_type) {
        case F_RDLCK:
index f4f050a..2b4d093 100644 (file)
@@ -3,6 +3,7 @@
 #include <linux/fs.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
+#include <linux/gfp.h>
 #include <linux/sched.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
@@ -165,21 +166,18 @@ static int parse_reply_info_dir(void **p, void *end,
        if (num == 0)
                goto done;
 
-       /* alloc large array */
-       info->dir_nr = num;
-       info->dir_in = kcalloc(num, sizeof(*info->dir_in) +
-                              sizeof(*info->dir_dname) +
-                              sizeof(*info->dir_dname_len) +
-                              sizeof(*info->dir_dlease),
-                              GFP_NOFS);
-       if (info->dir_in == NULL) {
-               err = -ENOMEM;
-               goto out_bad;
-       }
+       BUG_ON(!info->dir_in);
        info->dir_dname = (void *)(info->dir_in + num);
        info->dir_dname_len = (void *)(info->dir_dname + num);
        info->dir_dlease = (void *)(info->dir_dname_len + num);
+       if ((unsigned long)(info->dir_dlease + num) >
+           (unsigned long)info->dir_in + info->dir_buf_size) {
+               pr_err("dir contents are larger than expected\n");
+               WARN_ON(1);
+               goto bad;
+       }
 
+       info->dir_nr = num;
        while (num) {
                /* dentry */
                ceph_decode_need(p, end, sizeof(u32)*2, bad);
@@ -327,7 +325,9 @@ out_bad:
 
 static void destroy_reply_info(struct ceph_mds_reply_info_parsed *info)
 {
-       kfree(info->dir_in);
+       if (!info->dir_in)
+               return;
+       free_pages((unsigned long)info->dir_in, get_order(info->dir_buf_size));
 }
 
 
@@ -512,12 +512,11 @@ void ceph_mdsc_release_request(struct kref *kref)
        struct ceph_mds_request *req = container_of(kref,
                                                    struct ceph_mds_request,
                                                    r_kref);
+       destroy_reply_info(&req->r_reply_info);
        if (req->r_request)
                ceph_msg_put(req->r_request);
-       if (req->r_reply) {
+       if (req->r_reply)
                ceph_msg_put(req->r_reply);
-               destroy_reply_info(&req->r_reply_info);
-       }
        if (req->r_inode) {
                ceph_put_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN);
                iput(req->r_inode);
@@ -528,7 +527,9 @@ void ceph_mdsc_release_request(struct kref *kref)
                iput(req->r_target_inode);
        if (req->r_dentry)
                dput(req->r_dentry);
-       if (req->r_old_dentry) {
+       if (req->r_old_dentry)
+               dput(req->r_old_dentry);
+       if (req->r_old_dentry_dir) {
                /*
                 * track (and drop pins for) r_old_dentry_dir
                 * separately, since r_old_dentry's d_parent may have
@@ -537,7 +538,6 @@ void ceph_mdsc_release_request(struct kref *kref)
                 */
                ceph_put_cap_refs(ceph_inode(req->r_old_dentry_dir),
                                  CEPH_CAP_PIN);
-               dput(req->r_old_dentry);
                iput(req->r_old_dentry_dir);
        }
        kfree(req->r_path1);
@@ -1311,6 +1311,9 @@ static int trim_caps(struct ceph_mds_client *mdsc,
                        trim_caps - session->s_trim_caps);
                session->s_trim_caps = 0;
        }
+
+       ceph_add_cap_releases(mdsc, session);
+       ceph_send_cap_releases(mdsc, session);
        return 0;
 }
 
@@ -1461,15 +1464,18 @@ static void discard_cap_releases(struct ceph_mds_client *mdsc,
 
        dout("discard_cap_releases mds%d\n", session->s_mds);
 
-       /* zero out the in-progress message */
-       msg = list_first_entry(&session->s_cap_releases,
-                              struct ceph_msg, list_head);
-       head = msg->front.iov_base;
-       num = le32_to_cpu(head->num);
-       dout("discard_cap_releases mds%d %p %u\n", session->s_mds, msg, num);
-       head->num = cpu_to_le32(0);
-       msg->front.iov_len = sizeof(*head);
-       session->s_num_cap_releases += num;
+       if (!list_empty(&session->s_cap_releases)) {
+               /* zero out the in-progress message */
+               msg = list_first_entry(&session->s_cap_releases,
+                                       struct ceph_msg, list_head);
+               head = msg->front.iov_base;
+               num = le32_to_cpu(head->num);
+               dout("discard_cap_releases mds%d %p %u\n",
+                    session->s_mds, msg, num);
+               head->num = cpu_to_le32(0);
+               msg->front.iov_len = sizeof(*head);
+               session->s_num_cap_releases += num;
+       }
 
        /* requeue completed messages */
        while (!list_empty(&session->s_cap_releases_done)) {
@@ -1492,6 +1498,43 @@ static void discard_cap_releases(struct ceph_mds_client *mdsc,
  * requests
  */
 
+int ceph_alloc_readdir_reply_buffer(struct ceph_mds_request *req,
+                                   struct inode *dir)
+{
+       struct ceph_inode_info *ci = ceph_inode(dir);
+       struct ceph_mds_reply_info_parsed *rinfo = &req->r_reply_info;
+       struct ceph_mount_options *opt = req->r_mdsc->fsc->mount_options;
+       size_t size = sizeof(*rinfo->dir_in) + sizeof(*rinfo->dir_dname_len) +
+                     sizeof(*rinfo->dir_dname) + sizeof(*rinfo->dir_dlease);
+       int order, num_entries;
+
+       spin_lock(&ci->i_ceph_lock);
+       num_entries = ci->i_files + ci->i_subdirs;
+       spin_unlock(&ci->i_ceph_lock);
+       num_entries = max(num_entries, 1);
+       num_entries = min(num_entries, opt->max_readdir);
+
+       order = get_order(size * num_entries);
+       while (order >= 0) {
+               rinfo->dir_in = (void*)__get_free_pages(GFP_NOFS | __GFP_NOWARN,
+                                                       order);
+               if (rinfo->dir_in)
+                       break;
+               order--;
+       }
+       if (!rinfo->dir_in)
+               return -ENOMEM;
+
+       num_entries = (PAGE_SIZE << order) / size;
+       num_entries = min(num_entries, opt->max_readdir);
+
+       rinfo->dir_buf_size = PAGE_SIZE << order;
+       req->r_num_caps = num_entries + 1;
+       req->r_args.readdir.max_entries = cpu_to_le32(num_entries);
+       req->r_args.readdir.max_bytes = cpu_to_le32(opt->max_readdir_bytes);
+       return 0;
+}
+
 /*
  * Create an mds request.
  */
@@ -2053,7 +2096,7 @@ int ceph_mdsc_do_request(struct ceph_mds_client *mdsc,
                ceph_get_cap_refs(ceph_inode(req->r_inode), CEPH_CAP_PIN);
        if (req->r_locked_dir)
                ceph_get_cap_refs(ceph_inode(req->r_locked_dir), CEPH_CAP_PIN);
-       if (req->r_old_dentry)
+       if (req->r_old_dentry_dir)
                ceph_get_cap_refs(ceph_inode(req->r_old_dentry_dir),
                                  CEPH_CAP_PIN);
 
index 6828891..e90cfcc 100644 (file)
@@ -67,6 +67,7 @@ struct ceph_mds_reply_info_parsed {
                /* for readdir results */
                struct {
                        struct ceph_mds_reply_dirfrag *dir_dir;
+                       size_t                        dir_buf_size;
                        int                           dir_nr;
                        char                          **dir_dname;
                        u32                           *dir_dname_len;
@@ -346,7 +347,8 @@ extern void ceph_mdsc_lease_release(struct ceph_mds_client *mdsc,
                                    struct dentry *dn);
 
 extern void ceph_invalidate_dir_request(struct ceph_mds_request *req);
-
+extern int ceph_alloc_readdir_reply_buffer(struct ceph_mds_request *req,
+                                          struct inode *dir);
 extern struct ceph_mds_request *
 ceph_mdsc_create_request(struct ceph_mds_client *mdsc, int op, int mode);
 extern void ceph_mdsc_submit_request(struct ceph_mds_client *mdsc,
index 4440f44..51cc23e 100644 (file)
@@ -54,6 +54,7 @@ const char *ceph_mds_op_name(int op)
        case CEPH_MDS_OP_LOOKUPHASH:  return "lookuphash";
        case CEPH_MDS_OP_LOOKUPPARENT:  return "lookupparent";
        case CEPH_MDS_OP_LOOKUPINO:  return "lookupino";
+       case CEPH_MDS_OP_LOOKUPNAME:  return "lookupname";
        case CEPH_MDS_OP_GETATTR:  return "getattr";
        case CEPH_MDS_OP_SETXATTR: return "setxattr";
        case CEPH_MDS_OP_SETATTR: return "setattr";
index 10a4ccb..06150fd 100644 (file)
@@ -1026,6 +1026,7 @@ static int __init init_ceph(void)
        if (ret)
                goto out;
 
+       ceph_flock_init();
        ceph_xattr_init();
        ret = register_filesystem(&ceph_fs_type);
        if (ret)
index d8801a9..7866cd0 100644 (file)
@@ -577,7 +577,7 @@ struct ceph_file_info {
 
        /* readdir: position within a frag */
        unsigned offset;       /* offset of last chunk, adjusted for . and .. */
-       u64 next_offset;       /* offset of next chunk (last_name's + 1) */
+       unsigned next_offset;  /* offset of next chunk (last_name's + 1) */
        char *last_name;       /* last entry in previous chunk */
        struct dentry *dentry; /* next dentry (for dcache readdir) */
        int dir_release_count;
@@ -871,6 +871,7 @@ extern long ceph_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 extern const struct export_operations ceph_export_ops;
 
 /* locks.c */
+extern __init void ceph_flock_init(void);
 extern int ceph_lock(struct file *file, int cmd, struct file_lock *fl);
 extern int ceph_flock(struct file *file, int cmd, struct file_lock *fl);
 extern void ceph_count_locks(struct inode *inode, int *p_num, int *f_num);
index a55ec37..c9c2b88 100644 (file)
@@ -64,32 +64,48 @@ static bool ceph_vxattrcb_layout_exists(struct ceph_inode_info *ci)
 }
 
 static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
-                                       size_t size)
+                                  size_t size)
 {
        int ret;
        struct ceph_fs_client *fsc = ceph_sb_to_client(ci->vfs_inode.i_sb);
        struct ceph_osd_client *osdc = &fsc->client->osdc;
        s64 pool = ceph_file_layout_pg_pool(ci->i_layout);
        const char *pool_name;
+       char buf[128];
 
        dout("ceph_vxattrcb_layout %p\n", &ci->vfs_inode);
        down_read(&osdc->map_sem);
        pool_name = ceph_pg_pool_name_by_id(osdc->osdmap, pool);
-       if (pool_name)
-               ret = snprintf(val, size,
-               "stripe_unit=%lld stripe_count=%lld object_size=%lld pool=%s",
+       if (pool_name) {
+               size_t len = strlen(pool_name);
+               ret = snprintf(buf, sizeof(buf),
+               "stripe_unit=%lld stripe_count=%lld object_size=%lld pool=",
                (unsigned long long)ceph_file_layout_su(ci->i_layout),
                (unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
-               (unsigned long long)ceph_file_layout_object_size(ci->i_layout),
-               pool_name);
-       else
-               ret = snprintf(val, size,
+               (unsigned long long)ceph_file_layout_object_size(ci->i_layout));
+               if (!size) {
+                       ret += len;
+               } else if (ret + len > size) {
+                       ret = -ERANGE;
+               } else {
+                       memcpy(val, buf, ret);
+                       memcpy(val + ret, pool_name, len);
+                       ret += len;
+               }
+       } else {
+               ret = snprintf(buf, sizeof(buf),
                "stripe_unit=%lld stripe_count=%lld object_size=%lld pool=%lld",
                (unsigned long long)ceph_file_layout_su(ci->i_layout),
                (unsigned long long)ceph_file_layout_stripe_count(ci->i_layout),
                (unsigned long long)ceph_file_layout_object_size(ci->i_layout),
                (unsigned long long)pool);
-
+               if (size) {
+                       if (ret <= size)
+                               memcpy(val, buf, ret);
+                       else
+                               ret = -ERANGE;
+               }
+       }
        up_read(&osdc->map_sem);
        return ret;
 }
@@ -215,7 +231,7 @@ static struct ceph_vxattr ceph_dir_vxattrs[] = {
                .name_size = sizeof("ceph.dir.layout"),
                .getxattr_cb = ceph_vxattrcb_layout,
                .readonly = false,
-               .hidden = false,
+               .hidden = true,
                .exists_cb = ceph_vxattrcb_layout_exists,
        },
        XATTR_LAYOUT_FIELD(dir, layout, stripe_unit),
@@ -242,7 +258,7 @@ static struct ceph_vxattr ceph_file_vxattrs[] = {
                .name_size = sizeof("ceph.file.layout"),
                .getxattr_cb = ceph_vxattrcb_layout,
                .readonly = false,
-               .hidden = false,
+               .hidden = true,
                .exists_cb = ceph_vxattrcb_layout_exists,
        },
        XATTR_LAYOUT_FIELD(file, layout, stripe_unit),
@@ -842,7 +858,6 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
        struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
        struct inode *inode = dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       struct inode *parent_inode;
        struct ceph_mds_request *req;
        struct ceph_mds_client *mdsc = fsc->mdsc;
        int err;
@@ -893,9 +908,7 @@ static int ceph_sync_setxattr(struct dentry *dentry, const char *name,
        req->r_data_len = size;
 
        dout("xattr.ver (before): %lld\n", ci->i_xattrs.version);
-       parent_inode = ceph_get_dentry_parent_inode(dentry);
-       err = ceph_mdsc_do_request(mdsc, parent_inode, req);
-       iput(parent_inode);
+       err = ceph_mdsc_do_request(mdsc, NULL, req);
        ceph_mdsc_put_request(req);
        dout("xattr.ver (after): %lld\n", ci->i_xattrs.version);
 
@@ -1019,7 +1032,6 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name)
        struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
        struct ceph_mds_client *mdsc = fsc->mdsc;
        struct inode *inode = dentry->d_inode;
-       struct inode *parent_inode;
        struct ceph_mds_request *req;
        int err;
 
@@ -1033,9 +1045,7 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name)
        req->r_num_caps = 1;
        req->r_path2 = kstrdup(name, GFP_NOFS);
 
-       parent_inode = ceph_get_dentry_parent_inode(dentry);
-       err = ceph_mdsc_do_request(mdsc, parent_inode, req);
-       iput(parent_inode);
+       err = ceph_mdsc_do_request(mdsc, NULL, req);
        ceph_mdsc_put_request(req);
        return err;
 }
index 834fce7..216d7e9 100644 (file)
@@ -3113,6 +3113,7 @@ cifs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 
 static struct vm_operations_struct cifs_file_vm_ops = {
        .fault = filemap_fault,
+       .map_pages = filemap_map_pages,
        .page_mkwrite = cifs_page_mkwrite,
        .remap_pages = generic_file_remap_pages,
 };
index 66cba5a..40707d8 100644 (file)
@@ -3144,6 +3144,7 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
                end = ERR_PTR(-ENAMETOOLONG);
        return end;
 }
+EXPORT_SYMBOL(simple_dname);
 
 /*
  * Write full pathname from the root of the filesystem into the buffer.
index 25dfeba..9e81c63 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -26,6 +26,7 @@
 #include <linux/file.h>
 #include <linux/fdtable.h>
 #include <linux/mm.h>
+#include <linux/vmacache.h>
 #include <linux/stat.h>
 #include <linux/fcntl.h>
 #include <linux/swap.h>
@@ -822,7 +823,7 @@ EXPORT_SYMBOL(read_code);
 static int exec_mmap(struct mm_struct *mm)
 {
        struct task_struct *tsk;
-       struct mm_struct * old_mm, *active_mm;
+       struct mm_struct *old_mm, *active_mm;
 
        /* Notify parent that we're no longer interested in the old VM */
        tsk = current;
@@ -848,6 +849,8 @@ static int exec_mmap(struct mm_struct *mm)
        tsk->mm = mm;
        tsk->active_mm = mm;
        activate_mm(active_mm, mm);
+       tsk->mm->vmacache_seqnum = 0;
+       vmacache_flush(tsk);
        task_unlock(tsk);
        if (old_mm) {
                up_read(&old_mm->mmap_sem);
@@ -1043,7 +1046,7 @@ EXPORT_SYMBOL_GPL(get_task_comm);
  * so that a new one can be started
  */
 
-void set_task_comm(struct task_struct *tsk, char *buf)
+void set_task_comm(struct task_struct *tsk, const char *buf)
 {
        task_lock(tsk);
        trace_task_rename(tsk, buf);
@@ -1052,21 +1055,6 @@ void set_task_comm(struct task_struct *tsk, char *buf)
        perf_event_comm(tsk);
 }
 
-static void filename_to_taskname(char *tcomm, const char *fn, unsigned int len)
-{
-       int i, ch;
-
-       /* Copies the binary name from after last slash */
-       for (i = 0; (ch = *(fn++)) != '\0';) {
-               if (ch == '/')
-                       i = 0; /* overwrite what we wrote */
-               else
-                       if (i < len - 1)
-                               tcomm[i++] = ch;
-       }
-       tcomm[i] = '\0';
-}
-
 int flush_old_exec(struct linux_binprm * bprm)
 {
        int retval;
@@ -1080,8 +1068,6 @@ int flush_old_exec(struct linux_binprm * bprm)
                goto out;
 
        set_mm_exe_file(bprm->mm, bprm->file);
-
-       filename_to_taskname(bprm->tcomm, bprm->filename, sizeof(bprm->tcomm));
        /*
         * Release all of the old mmap stuff
         */
@@ -1124,7 +1110,7 @@ void setup_new_exec(struct linux_binprm * bprm)
        else
                set_dumpable(current->mm, suid_dumpable);
 
-       set_task_comm(current, bprm->tcomm);
+       set_task_comm(current, kbasename(bprm->filename));
 
        /* Set the new mm task size. We have to do that late because it may
         * depend on TIF_32BIT which is only updated in flush_thread() on
index 1b8001b..27695e6 100644 (file)
@@ -4,7 +4,6 @@
  * Copyright (C) 2001-2003 Andreas Gruenbacher, <agruen@suse.de>
  */
 
-#include <linux/capability.h>
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
index 7cadd82..7d66fb0 100644 (file)
@@ -284,7 +284,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
                int best_ndir = inodes_per_group;
                int best_group = -1;
 
-               get_random_bytes(&group, sizeof(group));
+               group = prandom_u32();
                parent_group = (unsigned)group % ngroups;
                for (i = 0; i < ngroups; i++) {
                        group = (parent_group + i) % ngroups;
index d260115..3750031 100644 (file)
@@ -192,7 +192,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        ext2_inode_cachep = kmem_cache_create("ext2_inode_cache",
                                             sizeof(struct ext2_inode_info),
index cfedb2c..c0ebc4d 100644 (file)
@@ -42,8 +42,8 @@ ext2_xattr_security_set(struct dentry *dentry, const char *name,
                              value, size, flags);
 }
 
-int ext2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
-                   void *fs_info)
+static int ext2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
+                          void *fs_info)
 {
        const struct xattr *xattr;
        int err = 0;
index 22548f5..158b5d4 100644 (file)
@@ -1727,10 +1727,7 @@ allocated:
        percpu_counter_sub(&sbi->s_freeblocks_counter, num);
 
        BUFFER_TRACE(gdp_bh, "journal_dirty_metadata for group descriptor");
-       err = ext3_journal_dirty_metadata(handle, gdp_bh);
-       if (!fatal)
-               fatal = err;
-
+       fatal = ext3_journal_dirty_metadata(handle, gdp_bh);
        if (fatal)
                goto out;
 
index e66e480..17742ee 100644 (file)
@@ -275,7 +275,7 @@ static inline loff_t ext3_get_htree_eof(struct file *filp)
  * NOTE: offsets obtained *before* ext3_set_inode_flag(dir, EXT3_INODE_INDEX)
  *       will be invalid once the directory was converted into a dx directory
  */
-loff_t ext3_dir_llseek(struct file *file, loff_t offset, int whence)
+static loff_t ext3_dir_llseek(struct file *file, loff_t offset, int whence)
 {
        struct inode *inode = file->f_mapping->host;
        int dx_dir = is_dx_dir(inode);
index 082afd7..a1b8102 100644 (file)
@@ -215,7 +215,7 @@ static int find_group_orlov(struct super_block *sb, struct inode *parent)
                int best_ndir = inodes_per_group;
                int best_group = -1;
 
-               get_random_bytes(&group, sizeof(group));
+               group = prandom_u32();
                parent_group = (unsigned)group % ngroups;
                for (i = 0; i < ngroups; i++) {
                        group = (parent_group + i) % ngroups;
index efce2bb..f5157d0 100644 (file)
@@ -1559,56 +1559,17 @@ static int buffer_unmapped(handle_t *handle, struct buffer_head *bh)
 }
 
 /*
- * Note that we always start a transaction even if we're not journalling
- * data.  This is to preserve ordering: any hole instantiation within
- * __block_write_full_page -> ext3_get_block() should be journalled
- * along with the data so we don't crash and then get metadata which
+ * Note that whenever we need to map blocks we start a transaction even if
+ * we're not journalling data.  This is to preserve ordering: any hole
+ * instantiation within __block_write_full_page -> ext3_get_block() should be
+ * journalled along with the data so we don't crash and then get metadata which
  * refers to old data.
  *
  * In all journalling modes block_write_full_page() will start the I/O.
  *
- * Problem:
- *
- *     ext3_writepage() -> kmalloc() -> __alloc_pages() -> page_launder() ->
- *             ext3_writepage()
- *
- * Similar for:
- *
- *     ext3_file_write() -> generic_file_write() -> __alloc_pages() -> ...
- *
- * Same applies to ext3_get_block().  We will deadlock on various things like
- * lock_journal and i_truncate_mutex.
- *
- * Setting PF_MEMALLOC here doesn't work - too many internal memory
- * allocations fail.
- *
- * 16May01: If we're reentered then journal_current_handle() will be
- *         non-zero. We simply *return*.
- *
- * 1 July 2001: @@@ FIXME:
- *   In journalled data mode, a data buffer may be metadata against the
- *   current transaction.  But the same file is part of a shared mapping
- *   and someone does a writepage() on it.
- *
- *   We will move the buffer onto the async_data list, but *after* it has
- *   been dirtied. So there's a small window where we have dirty data on
- *   BJ_Metadata.
- *
- *   Note that this only applies to the last partial page in the file.  The
- *   bit which block_write_full_page() uses prepare/commit for.  (That's
- *   broken code anyway: it's wrong for msync()).
- *
- *   It's a rare case: affects the final partial page, for journalled data
- *   where the file is subject to bith write() and writepage() in the same
- *   transction.  To fix it we'll need a custom block_write_full_page().
- *   We'll probably need that anyway for journalling writepage() output.
- *
  * We don't honour synchronous mounts for writepage().  That would be
  * disastrous.  Any write() or metadata operation will sync the fs for
  * us.
- *
- * AKPM2: if all the page's buffers are mapped to disk and !data=journal,
- * we don't need to open a transaction here.
  */
 static int ext3_ordered_writepage(struct page *page,
                                struct writeback_control *wbc)
@@ -1673,12 +1634,9 @@ static int ext3_ordered_writepage(struct page *page,
         * block_write_full_page() succeeded.  Otherwise they are unmapped,
         * and generally junk.
         */
-       if (ret == 0) {
-               err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE,
+       if (ret == 0)
+               ret = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE,
                                        NULL, journal_dirty_data_fn);
-               if (!ret)
-                       ret = err;
-       }
        walk_page_buffers(handle, page_bufs, 0,
                        PAGE_CACHE_SIZE, NULL, bput_one);
        err = ext3_journal_stop(handle);
@@ -1925,6 +1883,8 @@ retry:
                         * and pretend the write failed... */
                        ext3_truncate_failed_direct_write(inode);
                        ret = PTR_ERR(handle);
+                       if (inode->i_nlink)
+                               ext3_orphan_del(NULL, inode);
                        goto out;
                }
                if (inode->i_nlink)
@@ -3212,21 +3172,20 @@ out_brelse:
  *
  * We are called from a few places:
  *
- * - Within generic_file_write() for O_SYNC files.
+ * - Within generic_file_aio_write() -> generic_write_sync() for O_SYNC files.
  *   Here, there will be no transaction running. We wait for any running
  *   transaction to commit.
  *
- * - Within sys_sync(), kupdate and such.
- *   We wait on commit, if tol to.
+ * - Within flush work (for sys_sync(), kupdate and such).
+ *   We wait on commit, if told to.
  *
- * - Within prune_icache() (PF_MEMALLOC == true)
- *   Here we simply return.  We can't afford to block kswapd on the
- *   journal commit.
+ * - Within iput_final() -> write_inode_now()
+ *   We wait on commit, if told to.
  *
  * In all cases it is actually safe for us to return without doing anything,
  * because the inode has been copied into a raw inode buffer in
- * ext3_mark_inode_dirty().  This is a correctness thing for O_SYNC and for
- * knfsd.
+ * ext3_mark_inode_dirty().  This is a correctness thing for WB_SYNC_ALL
+ * writeback.
  *
  * Note that we are absolutely dependent upon all inode dirtiers doing the
  * right thing: they *must* call mark_inode_dirty() after dirtying info in
@@ -3238,13 +3197,13 @@ out_brelse:
  *     stuff();
  *     inode->i_size = expr;
  *
- * is in error because a kswapd-driven write_inode() could occur while
- * `stuff()' is running, and the new i_size will be lost.  Plus the inode
- * will no longer be on the superblock's dirty inode list.
+ * is in error because write_inode() could occur while `stuff()' is running,
+ * and the new i_size will be lost.  Plus the inode will no longer be on the
+ * superblock's dirty inode list.
  */
 int ext3_write_inode(struct inode *inode, struct writeback_control *wbc)
 {
-       if (current->flags & PF_MEMALLOC)
+       if (WARN_ON_ONCE(current->flags & PF_MEMALLOC))
                return 0;
 
        if (ext3_journal_current_handle()) {
@@ -3253,7 +3212,12 @@ int ext3_write_inode(struct inode *inode, struct writeback_control *wbc)
                return -EIO;
        }
 
-       if (wbc->sync_mode != WB_SYNC_ALL)
+       /*
+        * No need to force transaction in WB_SYNC_NONE mode. Also
+        * ext3_sync_fs() will force the commit after everything is
+        * written.
+        */
+       if (wbc->sync_mode != WB_SYNC_ALL || wbc->for_sync)
                return 0;
 
        return ext3_force_commit(inode->i_sb);
index 95c6c5a..08cdfe5 100644 (file)
@@ -527,7 +527,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        ext3_inode_cachep = kmem_cache_create("ext3_inode_cache",
                                             sizeof(struct ext3_inode_info),
index 3387664..722c2bf 100644 (file)
@@ -43,8 +43,9 @@ ext3_xattr_security_set(struct dentry *dentry, const char *name,
                              name, value, size, flags);
 }
 
-int ext3_initxattrs(struct inode *inode, const struct xattr *xattr_array,
-                   void *fs_info)
+static int ext3_initxattrs(struct inode *inode,
+                          const struct xattr *xattr_array,
+                          void *fs_info)
 {
        const struct xattr *xattr;
        handle_t *handle = fs_info;
index 6db7f7d..4e508fc 100644 (file)
@@ -200,6 +200,7 @@ ext4_file_write(struct kiocb *iocb, const struct iovec *iov,
 
 static const struct vm_operations_struct ext4_file_vm_ops = {
        .fault          = filemap_fault,
+       .map_pages      = filemap_map_pages,
        .page_mkwrite   = ext4_page_mkwrite,
        .remap_pages    = generic_file_remap_pages,
 };
index fa8da4c..e93e4ec 100644 (file)
@@ -174,7 +174,7 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
 
        retval = f2fs_getxattr(inode, name_index, "", NULL, 0);
        if (retval > 0) {
-               value = kmalloc(retval, GFP_KERNEL);
+               value = kmalloc(retval, GFP_F2FS_ZERO);
                if (!value)
                        return ERR_PTR(-ENOMEM);
                retval = f2fs_getxattr(inode, name_index, "", value, retval);
@@ -203,6 +203,12 @@ static int __f2fs_set_acl(struct inode *inode, int type,
        size_t size = 0;
        int error;
 
+       if (acl) {
+               error = posix_acl_valid(acl);
+               if (error < 0)
+                       return error;
+       }
+
        switch (type) {
        case ACL_TYPE_ACCESS:
                name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
index 293d048..4aa521a 100644 (file)
@@ -33,14 +33,12 @@ struct page *grab_meta_page(struct f2fs_sb_info *sbi, pgoff_t index)
        struct address_space *mapping = META_MAPPING(sbi);
        struct page *page = NULL;
 repeat:
-       page = grab_cache_page(mapping, index);
+       page = grab_cache_page_write_begin(mapping, index, AOP_FLAG_NOFS);
        if (!page) {
                cond_resched();
                goto repeat;
        }
 
-       /* We wait writeback only inside grab_meta_page() */
-       wait_on_page_writeback(page);
        SetPageUptodate(page);
        return page;
 }
@@ -75,23 +73,102 @@ out:
        return page;
 }
 
+inline int get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
+{
+       switch (type) {
+       case META_NAT:
+               return NM_I(sbi)->max_nid / NAT_ENTRY_PER_BLOCK;
+       case META_SIT:
+               return SIT_BLK_CNT(sbi);
+       case META_SSA:
+       case META_CP:
+               return 0;
+       default:
+               BUG();
+       }
+}
+
+/*
+ * Readahead CP/NAT/SIT/SSA pages
+ */
+int ra_meta_pages(struct f2fs_sb_info *sbi, int start, int nrpages, int type)
+{
+       block_t prev_blk_addr = 0;
+       struct page *page;
+       int blkno = start;
+       int max_blks = get_max_meta_blks(sbi, type);
+
+       struct f2fs_io_info fio = {
+               .type = META,
+               .rw = READ_SYNC | REQ_META | REQ_PRIO
+       };
+
+       for (; nrpages-- > 0; blkno++) {
+               block_t blk_addr;
+
+               switch (type) {
+               case META_NAT:
+                       /* get nat block addr */
+                       if (unlikely(blkno >= max_blks))
+                               blkno = 0;
+                       blk_addr = current_nat_addr(sbi,
+                                       blkno * NAT_ENTRY_PER_BLOCK);
+                       break;
+               case META_SIT:
+                       /* get sit block addr */
+                       if (unlikely(blkno >= max_blks))
+                               goto out;
+                       blk_addr = current_sit_addr(sbi,
+                                       blkno * SIT_ENTRY_PER_BLOCK);
+                       if (blkno != start && prev_blk_addr + 1 != blk_addr)
+                               goto out;
+                       prev_blk_addr = blk_addr;
+                       break;
+               case META_SSA:
+               case META_CP:
+                       /* get ssa/cp block addr */
+                       blk_addr = blkno;
+                       break;
+               default:
+                       BUG();
+               }
+
+               page = grab_cache_page(META_MAPPING(sbi), blk_addr);
+               if (!page)
+                       continue;
+               if (PageUptodate(page)) {
+                       mark_page_accessed(page);
+                       f2fs_put_page(page, 1);
+                       continue;
+               }
+
+               f2fs_submit_page_mbio(sbi, page, blk_addr, &fio);
+               mark_page_accessed(page);
+               f2fs_put_page(page, 0);
+       }
+out:
+       f2fs_submit_merged_bio(sbi, META, READ);
+       return blkno - start;
+}
+
 static int f2fs_write_meta_page(struct page *page,
                                struct writeback_control *wbc)
 {
        struct inode *inode = page->mapping->host;
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
 
-       /* Should not write any meta pages, if any IO error was occurred */
-       if (unlikely(sbi->por_doing ||
-                       is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)))
+       if (unlikely(sbi->por_doing))
                goto redirty_out;
-
        if (wbc->for_reclaim)
                goto redirty_out;
 
-       wait_on_page_writeback(page);
+       /* Should not write any meta pages, if any IO error was occurred */
+       if (unlikely(is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)))
+               goto no_write;
 
+       f2fs_wait_on_page_writeback(page, META);
        write_meta_page(sbi, page);
+no_write:
        dec_page_count(sbi, F2FS_DIRTY_META);
        unlock_page(page);
        return 0;
@@ -99,6 +176,7 @@ static int f2fs_write_meta_page(struct page *page,
 redirty_out:
        dec_page_count(sbi, F2FS_DIRTY_META);
        wbc->pages_skipped++;
+       account_page_redirty(page);
        set_page_dirty(page);
        return AOP_WRITEPAGE_ACTIVATE;
 }
@@ -107,21 +185,23 @@ static int f2fs_write_meta_pages(struct address_space *mapping,
                                struct writeback_control *wbc)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
-       int nrpages = MAX_BIO_BLOCKS(max_hw_blocks(sbi));
-       long written;
-
-       if (wbc->for_kupdate)
-               return 0;
+       long diff, written;
 
        /* collect a number of dirty meta pages and write together */
-       if (get_pages(sbi, F2FS_DIRTY_META) < nrpages)
-               return 0;
+       if (wbc->for_kupdate ||
+               get_pages(sbi, F2FS_DIRTY_META) < nr_pages_to_skip(sbi, META))
+               goto skip_write;
 
        /* if mounting is failed, skip writing node pages */
        mutex_lock(&sbi->cp_mutex);
-       written = sync_meta_pages(sbi, META, nrpages);
+       diff = nr_pages_to_write(sbi, META, wbc);
+       written = sync_meta_pages(sbi, META, wbc->nr_to_write);
        mutex_unlock(&sbi->cp_mutex);
-       wbc->nr_to_write -= written;
+       wbc->nr_to_write = max((long)0, wbc->nr_to_write - written - diff);
+       return 0;
+
+skip_write:
+       wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_META);
        return 0;
 }
 
@@ -148,10 +228,22 @@ long sync_meta_pages(struct f2fs_sb_info *sbi, enum page_type type,
 
                for (i = 0; i < nr_pages; i++) {
                        struct page *page = pvec.pages[i];
+
                        lock_page(page);
-                       f2fs_bug_on(page->mapping != mapping);
-                       f2fs_bug_on(!PageDirty(page));
-                       clear_page_dirty_for_io(page);
+
+                       if (unlikely(page->mapping != mapping)) {
+continue_unlock:
+                               unlock_page(page);
+                               continue;
+                       }
+                       if (!PageDirty(page)) {
+                               /* someone wrote it for us */
+                               goto continue_unlock;
+                       }
+
+                       if (!clear_page_dirty_for_io(page))
+                               goto continue_unlock;
+
                        if (f2fs_write_meta_page(page, &wbc)) {
                                unlock_page(page);
                                break;
@@ -216,16 +308,15 @@ void release_orphan_inode(struct f2fs_sb_info *sbi)
 
 void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 {
-       struct list_head *head, *this;
-       struct orphan_inode_entry *new = NULL, *orphan = NULL;
+       struct list_head *head;
+       struct orphan_inode_entry *new, *orphan;
 
        new = f2fs_kmem_cache_alloc(orphan_entry_slab, GFP_ATOMIC);
        new->ino = ino;
 
        spin_lock(&sbi->orphan_inode_lock);
        head = &sbi->orphan_inode_list;
-       list_for_each(this, head) {
-               orphan = list_entry(this, struct orphan_inode_entry, list);
+       list_for_each_entry(orphan, head, list) {
                if (orphan->ino == ino) {
                        spin_unlock(&sbi->orphan_inode_lock);
                        kmem_cache_free(orphan_entry_slab, new);
@@ -234,14 +325,10 @@ void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
 
                if (orphan->ino > ino)
                        break;
-               orphan = NULL;
        }
 
-       /* add new_oentry into list which is sorted by inode number */
-       if (orphan)
-               list_add(&new->list, this->prev);
-       else
-               list_add_tail(&new->list, head);
+       /* add new orphan entry into list which is sorted by inode number */
+       list_add_tail(&new->list, &orphan->list);
        spin_unlock(&sbi->orphan_inode_lock);
 }
 
@@ -255,10 +342,11 @@ void remove_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
        list_for_each_entry(orphan, head, list) {
                if (orphan->ino == ino) {
                        list_del(&orphan->list);
-                       kmem_cache_free(orphan_entry_slab, orphan);
                        f2fs_bug_on(sbi->n_orphans == 0);
                        sbi->n_orphans--;
-                       break;
+                       spin_unlock(&sbi->orphan_inode_lock);
+                       kmem_cache_free(orphan_entry_slab, orphan);
+                       return;
                }
        }
        spin_unlock(&sbi->orphan_inode_lock);
@@ -285,6 +373,8 @@ void recover_orphan_inodes(struct f2fs_sb_info *sbi)
        start_blk = __start_cp_addr(sbi) + 1;
        orphan_blkaddr = __start_sum_addr(sbi) - 1;
 
+       ra_meta_pages(sbi, start_blk, orphan_blkaddr, META_CP);
+
        for (i = 0; i < orphan_blkaddr; i++) {
                struct page *page = get_meta_page(sbi, start_blk + i);
                struct f2fs_orphan_block *orphan_blk;
@@ -466,14 +556,12 @@ static int __add_dirty_inode(struct inode *inode, struct dir_inode_entry *new)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct list_head *head = &sbi->dir_inode_list;
-       struct list_head *this;
+       struct dir_inode_entry *entry;
 
-       list_for_each(this, head) {
-               struct dir_inode_entry *entry;
-               entry = list_entry(this, struct dir_inode_entry, list);
+       list_for_each_entry(entry, head, list)
                if (unlikely(entry->inode == inode))
                        return -EEXIST;
-       }
+
        list_add_tail(&new->list, head);
        stat_inc_dirty_dir(sbi);
        return 0;
@@ -483,6 +571,7 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct dir_inode_entry *new;
+       int ret = 0;
 
        if (!S_ISDIR(inode->i_mode))
                return;
@@ -492,13 +581,13 @@ void set_dirty_dir_page(struct inode *inode, struct page *page)
        INIT_LIST_HEAD(&new->list);
 
        spin_lock(&sbi->dir_inode_lock);
-       if (__add_dirty_inode(inode, new))
-               kmem_cache_free(inode_entry_slab, new);
-
-       inc_page_count(sbi, F2FS_DIRTY_DENTS);
+       ret = __add_dirty_inode(inode, new);
        inode_inc_dirty_dents(inode);
        SetPagePrivate(page);
        spin_unlock(&sbi->dir_inode_lock);
+
+       if (ret)
+               kmem_cache_free(inode_entry_slab, new);
 }
 
 void add_dirty_dir_inode(struct inode *inode)
@@ -506,44 +595,47 @@ void add_dirty_dir_inode(struct inode *inode)
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct dir_inode_entry *new =
                        f2fs_kmem_cache_alloc(inode_entry_slab, GFP_NOFS);
+       int ret = 0;
 
        new->inode = inode;
        INIT_LIST_HEAD(&new->list);
 
        spin_lock(&sbi->dir_inode_lock);
-       if (__add_dirty_inode(inode, new))
-               kmem_cache_free(inode_entry_slab, new);
+       ret = __add_dirty_inode(inode, new);
        spin_unlock(&sbi->dir_inode_lock);
+
+       if (ret)
+               kmem_cache_free(inode_entry_slab, new);
 }
 
 void remove_dirty_dir_inode(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-
-       struct list_head *this, *head;
+       struct list_head *head;
+       struct dir_inode_entry *entry;
 
        if (!S_ISDIR(inode->i_mode))
                return;
 
        spin_lock(&sbi->dir_inode_lock);
-       if (atomic_read(&F2FS_I(inode)->dirty_dents)) {
+       if (get_dirty_dents(inode)) {
                spin_unlock(&sbi->dir_inode_lock);
                return;
        }
 
        head = &sbi->dir_inode_list;
-       list_for_each(this, head) {
-               struct dir_inode_entry *entry;
-               entry = list_entry(this, struct dir_inode_entry, list);
+       list_for_each_entry(entry, head, list) {
                if (entry->inode == inode) {
                        list_del(&entry->list);
-                       kmem_cache_free(inode_entry_slab, entry);
                        stat_dec_dirty_dir(sbi);
-                       break;
+                       spin_unlock(&sbi->dir_inode_lock);
+                       kmem_cache_free(inode_entry_slab, entry);
+                       goto done;
                }
        }
        spin_unlock(&sbi->dir_inode_lock);
 
+done:
        /* Only from the recovery routine */
        if (is_inode_flag_set(F2FS_I(inode), FI_DELAY_IPUT)) {
                clear_inode_flag(F2FS_I(inode), FI_DELAY_IPUT);
@@ -554,15 +646,14 @@ void remove_dirty_dir_inode(struct inode *inode)
 struct inode *check_dirty_dir_inode(struct f2fs_sb_info *sbi, nid_t ino)
 {
 
-       struct list_head *this, *head;
+       struct list_head *head;
        struct inode *inode = NULL;
+       struct dir_inode_entry *entry;
 
        spin_lock(&sbi->dir_inode_lock);
 
        head = &sbi->dir_inode_list;
-       list_for_each(this, head) {
-               struct dir_inode_entry *entry;
-               entry = list_entry(this, struct dir_inode_entry, list);
+       list_for_each_entry(entry, head, list) {
                if (entry->inode->i_ino == ino) {
                        inode = entry->inode;
                        break;
@@ -589,7 +680,7 @@ retry:
        inode = igrab(entry->inode);
        spin_unlock(&sbi->dir_inode_lock);
        if (inode) {
-               filemap_flush(inode->i_mapping);
+               filemap_fdatawrite(inode->i_mapping);
                iput(inode);
        } else {
                /*
@@ -824,6 +915,7 @@ void write_checkpoint(struct f2fs_sb_info *sbi, bool is_umount)
        unblock_operations(sbi);
        mutex_unlock(&sbi->cp_mutex);
 
+       stat_inc_cp_count(sbi->stat_info);
        trace_f2fs_write_checkpoint(sbi->sb, is_umount, "finish checkpoint");
 }
 
@@ -845,11 +937,11 @@ void init_orphan_info(struct f2fs_sb_info *sbi)
 int __init create_checkpoint_caches(void)
 {
        orphan_entry_slab = f2fs_kmem_cache_create("f2fs_orphan_entry",
-                       sizeof(struct orphan_inode_entry), NULL);
+                       sizeof(struct orphan_inode_entry));
        if (!orphan_entry_slab)
                return -ENOMEM;
        inode_entry_slab = f2fs_kmem_cache_create("f2fs_dirty_dir_entry",
-                       sizeof(struct dir_inode_entry), NULL);
+                       sizeof(struct dir_inode_entry));
        if (!inode_entry_slab) {
                kmem_cache_destroy(orphan_entry_slab);
                return -ENOMEM;
index 2261ccd..45abd60 100644 (file)
@@ -45,7 +45,7 @@ static void f2fs_read_end_io(struct bio *bio, int err)
 
 static void f2fs_write_end_io(struct bio *bio, int err)
 {
-       struct f2fs_sb_info *sbi = F2FS_SB(bio->bi_io_vec->bv_page->mapping->host->i_sb);
+       struct f2fs_sb_info *sbi = bio->bi_private;
        struct bio_vec *bvec;
        int i;
 
@@ -55,15 +55,16 @@ static void f2fs_write_end_io(struct bio *bio, int err)
                if (unlikely(err)) {
                        SetPageError(page);
                        set_bit(AS_EIO, &page->mapping->flags);
-                       set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
-                       sbi->sb->s_flags |= MS_RDONLY;
+                       f2fs_stop_checkpoint(sbi);
                }
                end_page_writeback(page);
                dec_page_count(sbi, F2FS_WRITEBACK);
        }
 
-       if (bio->bi_private)
-               complete(bio->bi_private);
+       if (sbi->wait_io) {
+               complete(sbi->wait_io);
+               sbi->wait_io = NULL;
+       }
 
        if (!get_pages(sbi, F2FS_WRITEBACK) &&
                        !list_empty(&sbi->cp_wait.task_list))
@@ -86,6 +87,7 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
        bio->bi_bdev = sbi->sb->s_bdev;
        bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
        bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io;
+       bio->bi_private = sbi;
 
        return bio;
 }
@@ -113,7 +115,7 @@ static void __submit_merged_bio(struct f2fs_bio_info *io)
                 */
                if (fio->type == META_FLUSH) {
                        DECLARE_COMPLETION_ONSTACK(wait);
-                       io->bio->bi_private = &wait;
+                       io->sbi->wait_io = &wait;
                        submit_bio(rw, io->bio);
                        wait_for_completion(&wait);
                } else {
@@ -132,7 +134,7 @@ void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
 
        io = is_read_io(rw) ? &sbi->read_io : &sbi->write_io[btype];
 
-       mutex_lock(&io->io_mutex);
+       down_write(&io->io_rwsem);
 
        /* change META to META_FLUSH in the checkpoint procedure */
        if (type >= META_FLUSH) {
@@ -140,7 +142,7 @@ void f2fs_submit_merged_bio(struct f2fs_sb_info *sbi,
                io->fio.rw = WRITE_FLUSH_FUA | REQ_META | REQ_PRIO;
        }
        __submit_merged_bio(io);
-       mutex_unlock(&io->io_mutex);
+       up_write(&io->io_rwsem);
 }
 
 /*
@@ -178,7 +180,7 @@ void f2fs_submit_page_mbio(struct f2fs_sb_info *sbi, struct page *page,
 
        verify_block_addr(sbi, blk_addr);
 
-       mutex_lock(&io->io_mutex);
+       down_write(&io->io_rwsem);
 
        if (!is_read)
                inc_page_count(sbi, F2FS_WRITEBACK);
@@ -202,7 +204,7 @@ alloc_new:
 
        io->last_block_in_bio = blk_addr;
 
-       mutex_unlock(&io->io_mutex);
+       up_write(&io->io_rwsem);
        trace_f2fs_submit_page_mbio(page, fio->rw, fio->type, blk_addr);
 }
 
@@ -797,48 +799,36 @@ static int f2fs_write_data_page(struct page *page,
         */
        offset = i_size & (PAGE_CACHE_SIZE - 1);
        if ((page->index >= end_index + 1) || !offset) {
-               if (S_ISDIR(inode->i_mode)) {
-                       dec_page_count(sbi, F2FS_DIRTY_DENTS);
-                       inode_dec_dirty_dents(inode);
-               }
+               inode_dec_dirty_dents(inode);
                goto out;
        }
 
        zero_user_segment(page, offset, PAGE_CACHE_SIZE);
 write:
-       if (unlikely(sbi->por_doing)) {
-               err = AOP_WRITEPAGE_ACTIVATE;
+       if (unlikely(sbi->por_doing))
                goto redirty_out;
-       }
 
        /* Dentry blocks are controlled by checkpoint */
        if (S_ISDIR(inode->i_mode)) {
-               dec_page_count(sbi, F2FS_DIRTY_DENTS);
                inode_dec_dirty_dents(inode);
                err = do_write_data_page(page, &fio);
-       } else {
-               f2fs_lock_op(sbi);
-
-               if (f2fs_has_inline_data(inode) || f2fs_may_inline(inode)) {
-                       err = f2fs_write_inline_data(inode, page, offset);
-                       f2fs_unlock_op(sbi);
-                       goto out;
-               } else {
-                       err = do_write_data_page(page, &fio);
-               }
+               goto done;
+       }
 
-               f2fs_unlock_op(sbi);
+       if (!wbc->for_reclaim)
                need_balance_fs = true;
-       }
-       if (err == -ENOENT)
-               goto out;
-       else if (err)
+       else if (has_not_enough_free_secs(sbi, 0))
                goto redirty_out;
 
-       if (wbc->for_reclaim) {
-               f2fs_submit_merged_bio(sbi, DATA, WRITE);
-               need_balance_fs = false;
-       }
+       f2fs_lock_op(sbi);
+       if (f2fs_has_inline_data(inode) || f2fs_may_inline(inode))
+               err = f2fs_write_inline_data(inode, page, offset);
+       else
+               err = do_write_data_page(page, &fio);
+       f2fs_unlock_op(sbi);
+done:
+       if (err && err != -ENOENT)
+               goto redirty_out;
 
        clear_cold_data(page);
 out:
@@ -849,12 +839,11 @@ out:
 
 redirty_out:
        wbc->pages_skipped++;
+       account_page_redirty(page);
        set_page_dirty(page);
-       return err;
+       return AOP_WRITEPAGE_ACTIVATE;
 }
 
-#define MAX_DESIRED_PAGES_WP   4096
-
 static int __f2fs_writepage(struct page *page, struct writeback_control *wbc,
                        void *data)
 {
@@ -871,17 +860,17 @@ static int f2fs_write_data_pages(struct address_space *mapping,
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        bool locked = false;
        int ret;
-       long excess_nrtw = 0, desired_nrtw;
+       long diff;
 
        /* deal with chardevs and other special file */
        if (!mapping->a_ops->writepage)
                return 0;
 
-       if (wbc->nr_to_write < MAX_DESIRED_PAGES_WP) {
-               desired_nrtw = MAX_DESIRED_PAGES_WP;
-               excess_nrtw = desired_nrtw - wbc->nr_to_write;
-               wbc->nr_to_write = desired_nrtw;
-       }
+       if (S_ISDIR(inode->i_mode) && wbc->sync_mode == WB_SYNC_NONE &&
+                       get_dirty_dents(inode) < nr_pages_to_skip(sbi, DATA))
+               goto skip_write;
+
+       diff = nr_pages_to_write(sbi, DATA, wbc);
 
        if (!S_ISDIR(inode->i_mode)) {
                mutex_lock(&sbi->writepages);
@@ -895,8 +884,12 @@ static int f2fs_write_data_pages(struct address_space *mapping,
 
        remove_dirty_dir_inode(inode);
 
-       wbc->nr_to_write -= excess_nrtw;
+       wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
        return ret;
+
+skip_write:
+       wbc->pages_skipped += get_dirty_dents(inode);
+       return 0;
 }
 
 static int f2fs_write_begin(struct file *file, struct address_space *mapping,
@@ -949,13 +942,19 @@ inline_data:
        if (dn.data_blkaddr == NEW_ADDR) {
                zero_user_segment(page, 0, PAGE_CACHE_SIZE);
        } else {
-               if (f2fs_has_inline_data(inode))
+               if (f2fs_has_inline_data(inode)) {
                        err = f2fs_read_inline_data(inode, page);
-               else
+                       if (err) {
+                               page_cache_release(page);
+                               return err;
+                       }
+               } else {
                        err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr,
                                                        READ_SYNC);
-               if (err)
-                       return err;
+                       if (err)
+                               return err;
+               }
+
                lock_page(page);
                if (unlikely(!PageUptodate(page))) {
                        f2fs_put_page(page, 1);
@@ -1031,11 +1030,8 @@ static void f2fs_invalidate_data_page(struct page *page, unsigned int offset,
                                      unsigned int length)
 {
        struct inode *inode = page->mapping->host;
-       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       if (S_ISDIR(inode->i_mode) && PageDirty(page)) {
-               dec_page_count(sbi, F2FS_DIRTY_DENTS);
+       if (PageDirty(page))
                inode_dec_dirty_dents(inode);
-       }
        ClearPagePrivate(page);
 }
 
index 3de9d20..b52c12c 100644 (file)
@@ -86,7 +86,6 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
 {
        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;
        int ndirty = 0;
 
@@ -94,7 +93,6 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
        total_vblocks = 0;
        blks_per_sec = sbi->segs_per_sec * (1 << sbi->log_blocks_per_seg);
        hblks_per_sec = blks_per_sec / 2;
-       mutex_lock(&sit_i->sentry_lock);
        for (segno = 0; segno < TOTAL_SEGS(sbi); segno += sbi->segs_per_sec) {
                vblocks = get_valid_blocks(sbi, segno, sbi->segs_per_sec);
                dist = abs(vblocks - hblks_per_sec);
@@ -105,7 +103,6 @@ static void update_sit_info(struct f2fs_sb_info *sbi)
                        ndirty++;
                }
        }
-       mutex_unlock(&sit_i->sentry_lock);
        dist = TOTAL_SECS(sbi) * hblks_per_sec * hblks_per_sec / 100;
        si->bimodal = bimodal / dist;
        if (si->dirty_count)
@@ -236,6 +233,7 @@ static int stat_show(struct seq_file *s, void *v)
                           si->dirty_count);
                seq_printf(s, "  - Prefree: %d\n  - Free: %d (%d)\n\n",
                           si->prefree_count, si->free_segs, si->free_secs);
+               seq_printf(s, "CP calls: %d\n", si->cp_count);
                seq_printf(s, "GC calls: %d (BG: %d)\n",
                           si->call_count, si->bg_gc);
                seq_printf(s, "  - data segments : %d\n", si->data_segs);
@@ -252,10 +250,10 @@ static int stat_show(struct seq_file *s, void *v)
                           si->ndirty_dent, si->ndirty_dirs);
                seq_printf(s, "  - meta: %4d in %4d\n",
                           si->ndirty_meta, si->meta_pages);
-               seq_printf(s, "  - NATs: %5d > %lu\n",
-                          si->nats, NM_WOUT_THRESHOLD);
-               seq_printf(s, "  - SITs: %5d\n  - free_nids: %5d\n",
-                          si->sits, si->fnids);
+               seq_printf(s, "  - NATs: %9d\n  - SITs: %9d\n",
+                          si->nats, si->sits);
+               seq_printf(s, "  - free_nids: %9d\n",
+                          si->fnids);
                seq_puts(s, "\nDistribution of User Blocks:");
                seq_puts(s, " [ valid | invalid | free ]\n");
                seq_puts(s, "  [");
index 2b7c255..972fd0e 100644 (file)
@@ -21,12 +21,12 @@ static unsigned long dir_blocks(struct inode *inode)
                                                        >> PAGE_CACHE_SHIFT;
 }
 
-static unsigned int dir_buckets(unsigned int level)
+static unsigned int dir_buckets(unsigned int level, int dir_level)
 {
        if (level < MAX_DIR_HASH_DEPTH / 2)
-               return 1 << level;
+               return 1 << (level + dir_level);
        else
-               return 1 << ((MAX_DIR_HASH_DEPTH / 2) - 1);
+               return 1 << ((MAX_DIR_HASH_DEPTH / 2 + dir_level) - 1);
 }
 
 static unsigned int bucket_blocks(unsigned int level)
@@ -65,13 +65,14 @@ static void set_de_type(struct f2fs_dir_entry *de, struct inode *inode)
        de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
 }
 
-static unsigned long dir_block_index(unsigned int level, unsigned int idx)
+static unsigned long dir_block_index(unsigned int level,
+                               int dir_level, unsigned int idx)
 {
        unsigned long i;
        unsigned long bidx = 0;
 
        for (i = 0; i < level; i++)
-               bidx += dir_buckets(i) * bucket_blocks(i);
+               bidx += dir_buckets(i, dir_level) * bucket_blocks(i);
        bidx += idx * bucket_blocks(level);
        return bidx;
 }
@@ -93,16 +94,21 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
                        f2fs_hash_t namehash, struct page **res_page)
 {
        struct f2fs_dir_entry *de;
-       unsigned long bit_pos, end_pos, next_pos;
+       unsigned long bit_pos = 0;
        struct f2fs_dentry_block *dentry_blk = kmap(dentry_page);
-       int slots;
+       const void *dentry_bits = &dentry_blk->dentry_bitmap;
+       int max_len = 0;
 
-       bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
-                                       NR_DENTRY_IN_BLOCK, 0);
        while (bit_pos < NR_DENTRY_IN_BLOCK) {
+               if (!test_bit_le(bit_pos, dentry_bits)) {
+                       if (bit_pos == 0)
+                               max_len = 1;
+                       else if (!test_bit_le(bit_pos - 1, dentry_bits))
+                               max_len++;
+                       bit_pos++;
+                       continue;
+               }
                de = &dentry_blk->dentry[bit_pos];
-               slots = GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
-
                if (early_match_name(name, namelen, namehash, de)) {
                        if (!memcmp(dentry_blk->filename[bit_pos],
                                                        name, namelen)) {
@@ -110,20 +116,18 @@ static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
                                goto found;
                        }
                }
-               next_pos = bit_pos + slots;
-               bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
-                               NR_DENTRY_IN_BLOCK, next_pos);
-               if (bit_pos >= NR_DENTRY_IN_BLOCK)
-                       end_pos = NR_DENTRY_IN_BLOCK;
-               else
-                       end_pos = bit_pos;
-               if (*max_slots < end_pos - next_pos)
-                       *max_slots = end_pos - next_pos;
+               if (max_len > *max_slots) {
+                       *max_slots = max_len;
+                       max_len = 0;
+               }
+               bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
        }
 
        de = NULL;
        kunmap(dentry_page);
 found:
+       if (max_len > *max_slots)
+               *max_slots = max_len;
        return de;
 }
 
@@ -141,10 +145,11 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
 
        f2fs_bug_on(level > MAX_DIR_HASH_DEPTH);
 
-       nbucket = dir_buckets(level);
+       nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level);
        nblock = bucket_blocks(level);
 
-       bidx = dir_block_index(level, le32_to_cpu(namehash) % nbucket);
+       bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level,
+                                       le32_to_cpu(namehash) % nbucket);
        end_block = bidx + nblock;
 
        for (; bidx < end_block; bidx++) {
@@ -248,7 +253,7 @@ void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
                struct page *page, struct inode *inode)
 {
        lock_page(page);
-       wait_on_page_writeback(page);
+       f2fs_wait_on_page_writeback(page, DATA);
        de->ino = cpu_to_le32(inode->i_ino);
        set_de_type(de, inode);
        kunmap(page);
@@ -347,14 +352,11 @@ static struct page *init_inode_metadata(struct inode *inode,
                err = f2fs_init_security(inode, dir, name, page);
                if (err)
                        goto put_error;
-
-               wait_on_page_writeback(page);
        } else {
                page = get_node_page(F2FS_SB(dir->i_sb), inode->i_ino);
                if (IS_ERR(page))
                        return page;
 
-               wait_on_page_writeback(page);
                set_cold_node(inode, page);
        }
 
@@ -372,6 +374,10 @@ static struct page *init_inode_metadata(struct inode *inode,
 
 put_error:
        f2fs_put_page(page, 1);
+       /* once the failed inode becomes a bad inode, i_mode is S_IFREG */
+       truncate_inode_pages(&inode->i_data, 0);
+       truncate_blocks(inode, 0);
+       remove_dirty_dir_inode(inode);
 error:
        remove_inode_page(inode);
        return ERR_PTR(err);
@@ -395,9 +401,6 @@ static void update_parent_metadata(struct inode *dir, struct inode *inode,
                set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
        }
 
-       if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR))
-               update_inode_page(dir);
-
        if (is_inode_flag_set(F2FS_I(inode), FI_INC_LINK))
                clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
 }
@@ -464,10 +467,11 @@ start:
        if (level == current_depth)
                ++current_depth;
 
-       nbucket = dir_buckets(level);
+       nbucket = dir_buckets(level, F2FS_I(dir)->i_dir_level);
        nblock = bucket_blocks(level);
 
-       bidx = dir_block_index(level, (le32_to_cpu(dentry_hash) % nbucket));
+       bidx = dir_block_index(level, F2FS_I(dir)->i_dir_level,
+                               (le32_to_cpu(dentry_hash) % nbucket));
 
        for (block = bidx; block <= (bidx + nblock - 1); block++) {
                dentry_page = get_new_data_page(dir, NULL, block, true);
@@ -487,8 +491,9 @@ start:
        ++level;
        goto start;
 add_dentry:
-       wait_on_page_writeback(dentry_page);
+       f2fs_wait_on_page_writeback(dentry_page, DATA);
 
+       down_write(&F2FS_I(inode)->i_sem);
        page = init_inode_metadata(inode, dir, name);
        if (IS_ERR(page)) {
                err = PTR_ERR(page);
@@ -511,7 +516,12 @@ add_dentry:
 
        update_parent_metadata(dir, inode, current_depth);
 fail:
-       clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
+       up_write(&F2FS_I(inode)->i_sem);
+
+       if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) {
+               update_inode_page(dir);
+               clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
+       }
        kunmap(dentry_page);
        f2fs_put_page(dentry_page, 1);
        return err;
@@ -528,13 +538,12 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
        unsigned int bit_pos;
        struct address_space *mapping = page->mapping;
        struct inode *dir = mapping->host;
-       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
        int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
        void *kaddr = page_address(page);
        int i;
 
        lock_page(page);
-       wait_on_page_writeback(page);
+       f2fs_wait_on_page_writeback(page, DATA);
 
        dentry_blk = (struct f2fs_dentry_block *)kaddr;
        bit_pos = dentry - (struct f2fs_dir_entry *)dentry_blk->dentry;
@@ -551,6 +560,10 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
 
        if (inode) {
+               struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
+
+               down_write(&F2FS_I(inode)->i_sem);
+
                if (S_ISDIR(inode->i_mode)) {
                        drop_nlink(dir);
                        update_inode_page(dir);
@@ -561,6 +574,7 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
                        drop_nlink(inode);
                        i_size_write(inode, 0);
                }
+               up_write(&F2FS_I(inode)->i_sem);
                update_inode_page(inode);
 
                if (inode->i_nlink == 0)
@@ -573,7 +587,6 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
                truncate_hole(dir, page->index, page->index + 1);
                clear_page_dirty_for_io(page);
                ClearPageUptodate(page);
-               dec_page_count(sbi, F2FS_DIRTY_DENTS);
                inode_dec_dirty_dents(dir);
        }
        f2fs_put_page(page, 1);
index fc3c558..2ecac83 100644 (file)
@@ -40,6 +40,7 @@
 #define F2FS_MOUNT_DISABLE_EXT_IDENTIFY        0x00000040
 #define F2FS_MOUNT_INLINE_XATTR                0x00000080
 #define F2FS_MOUNT_INLINE_DATA         0x00000100
+#define F2FS_MOUNT_FLUSH_MERGE         0x00000200
 
 #define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
 #define set_opt(sbi, option)   (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -88,6 +89,16 @@ enum {
        SIT_BITMAP
 };
 
+/*
+ * For CP/NAT/SIT/SSA readahead
+ */
+enum {
+       META_CP,
+       META_NAT,
+       META_SIT,
+       META_SSA
+};
+
 /* for the list of orphan inodes */
 struct orphan_inode_entry {
        struct list_head list;  /* list head */
@@ -187,16 +198,20 @@ struct extent_info {
 #define FADVISE_COLD_BIT       0x01
 #define FADVISE_LOST_PINO_BIT  0x02
 
+#define DEF_DIR_LEVEL          0
+
 struct f2fs_inode_info {
        struct inode vfs_inode;         /* serve a vfs inode */
        unsigned long i_flags;          /* keep an inode flags for ioctl */
        unsigned char i_advise;         /* use to give file attribute hints */
+       unsigned char i_dir_level;      /* use for dentry level for large dir */
        unsigned int i_current_depth;   /* use only in directory structure */
        unsigned int i_pino;            /* parent inode number */
        umode_t i_acl_mode;             /* keep file acl mode temporarily */
 
        /* Use below internally in f2fs*/
        unsigned long flags;            /* use to pass per-file flags */
+       struct rw_semaphore i_sem;      /* protect fi info */
        atomic_t dirty_dents;           /* # of dirty dentry pages */
        f2fs_hash_t chash;              /* hash value of given file name */
        unsigned int clevel;            /* maximum level of given file name */
@@ -229,6 +244,7 @@ struct f2fs_nm_info {
        block_t nat_blkaddr;            /* base disk address of NAT */
        nid_t max_nid;                  /* maximum possible node ids */
        nid_t next_scan_nid;            /* the next nid to be scanned */
+       unsigned int ram_thresh;        /* control the memory footprint */
 
        /* NAT cache management */
        struct radix_tree_root nat_root;/* root of the nat entry cache */
@@ -238,6 +254,7 @@ struct f2fs_nm_info {
        struct list_head dirty_nat_entries; /* cached nat entry list (dirty) */
 
        /* free node ids management */
+       struct radix_tree_root free_nid_root;/* root of the free_nid cache */
        struct list_head free_nid_list; /* a list for free nids */
        spinlock_t free_nid_list_lock;  /* protect free nid list */
        unsigned int fcnt;              /* the number of free node id */
@@ -300,6 +317,12 @@ enum {
        NO_CHECK_TYPE
 };
 
+struct flush_cmd {
+       struct flush_cmd *next;
+       struct completion wait;
+       int ret;
+};
+
 struct f2fs_sm_info {
        struct sit_info *sit_info;              /* whole segment information */
        struct free_segmap_info *free_info;     /* free segment information */
@@ -328,6 +351,14 @@ struct f2fs_sm_info {
 
        unsigned int ipu_policy;        /* in-place-update policy */
        unsigned int min_ipu_util;      /* in-place-update threshold */
+
+       /* for flush command control */
+       struct task_struct *f2fs_issue_flush;   /* flush thread */
+       wait_queue_head_t flush_wait_queue;     /* waiting queue for wake-up */
+       struct flush_cmd *issue_list;           /* list for command issue */
+       struct flush_cmd *dispatch_list;        /* list for command dispatch */
+       spinlock_t issue_lock;                  /* for issue list lock */
+       struct flush_cmd *issue_tail;           /* list tail of issue list */
 };
 
 /*
@@ -378,7 +409,7 @@ struct f2fs_bio_info {
        struct bio *bio;                /* bios to merge */
        sector_t last_block_in_bio;     /* last block number */
        struct f2fs_io_info fio;        /* store buffered io info. */
-       struct mutex io_mutex;          /* mutex for bio */
+       struct rw_semaphore io_rwsem;   /* blocking op for bio */
 };
 
 struct f2fs_sb_info {
@@ -398,6 +429,7 @@ struct f2fs_sb_info {
        /* for bio operations */
        struct f2fs_bio_info read_io;                   /* for read bios */
        struct f2fs_bio_info write_io[NR_PAGE_TYPE];    /* for write bios */
+       struct completion *wait_io;             /* for completion bios */
 
        /* for checkpoint */
        struct f2fs_checkpoint *ckpt;           /* raw checkpoint pointer */
@@ -407,7 +439,6 @@ struct f2fs_sb_info {
        struct mutex node_write;                /* locking node writes */
        struct mutex writepages;                /* mutex for writepages() */
        bool por_doing;                         /* recovery is doing or not */
-       bool on_build_free_nids;                /* build_free_nids is doing */
        wait_queue_head_t cp_wait;
 
        /* for orphan inode management */
@@ -436,6 +467,7 @@ struct f2fs_sb_info {
        unsigned int total_valid_node_count;    /* valid node block count */
        unsigned int total_valid_inode_count;   /* valid inode count */
        int active_logs;                        /* # of active logs */
+       int dir_level;                          /* directory level */
 
        block_t user_block_count;               /* # of user blocks */
        block_t total_valid_block_count;        /* # of valid blocks */
@@ -622,6 +654,11 @@ static inline int F2FS_HAS_BLOCKS(struct inode *inode)
                return inode->i_blocks > F2FS_DEFAULT_ALLOCATED_BLOCKS;
 }
 
+static inline bool f2fs_has_xattr_block(unsigned int ofs)
+{
+       return ofs == XATTR_NODE_OFFSET;
+}
+
 static inline bool inc_valid_block_count(struct f2fs_sb_info *sbi,
                                 struct inode *inode, blkcnt_t count)
 {
@@ -661,6 +698,7 @@ static inline void inc_page_count(struct f2fs_sb_info *sbi, int count_type)
 
 static inline void inode_inc_dirty_dents(struct inode *inode)
 {
+       inc_page_count(F2FS_SB(inode->i_sb), F2FS_DIRTY_DENTS);
        atomic_inc(&F2FS_I(inode)->dirty_dents);
 }
 
@@ -671,6 +709,10 @@ static inline void dec_page_count(struct f2fs_sb_info *sbi, int count_type)
 
 static inline void inode_dec_dirty_dents(struct inode *inode)
 {
+       if (!S_ISDIR(inode->i_mode))
+               return;
+
+       dec_page_count(F2FS_SB(inode->i_sb), F2FS_DIRTY_DENTS);
        atomic_dec(&F2FS_I(inode)->dirty_dents);
 }
 
@@ -679,6 +721,11 @@ static inline int get_pages(struct f2fs_sb_info *sbi, int count_type)
        return atomic_read(&sbi->nr_pages[count_type]);
 }
 
+static inline int get_dirty_dents(struct inode *inode)
+{
+       return atomic_read(&F2FS_I(inode)->dirty_dents);
+}
+
 static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type)
 {
        unsigned int pages_per_sec = sbi->segs_per_sec *
@@ -689,11 +736,7 @@ static inline int get_blocktype_secs(struct f2fs_sb_info *sbi, int block_type)
 
 static inline block_t valid_user_blocks(struct f2fs_sb_info *sbi)
 {
-       block_t ret;
-       spin_lock(&sbi->stat_lock);
-       ret = sbi->total_valid_block_count;
-       spin_unlock(&sbi->stat_lock);
-       return ret;
+       return sbi->total_valid_block_count;
 }
 
 static inline unsigned long __bitmap_size(struct f2fs_sb_info *sbi, int flag)
@@ -789,11 +832,7 @@ static inline void dec_valid_node_count(struct f2fs_sb_info *sbi,
 
 static inline unsigned int valid_node_count(struct f2fs_sb_info *sbi)
 {
-       unsigned int ret;
-       spin_lock(&sbi->stat_lock);
-       ret = sbi->total_valid_node_count;
-       spin_unlock(&sbi->stat_lock);
-       return ret;
+       return sbi->total_valid_node_count;
 }
 
 static inline void inc_valid_inode_count(struct f2fs_sb_info *sbi)
@@ -814,11 +853,7 @@ static inline void dec_valid_inode_count(struct f2fs_sb_info *sbi)
 
 static inline unsigned int valid_inode_count(struct f2fs_sb_info *sbi)
 {
-       unsigned int ret;
-       spin_lock(&sbi->stat_lock);
-       ret = sbi->total_valid_inode_count;
-       spin_unlock(&sbi->stat_lock);
-       return ret;
+       return sbi->total_valid_inode_count;
 }
 
 static inline void f2fs_put_page(struct page *page, int unlock)
@@ -844,9 +879,9 @@ static inline void f2fs_put_dnode(struct dnode_of_data *dn)
 }
 
 static inline struct kmem_cache *f2fs_kmem_cache_create(const char *name,
-                                       size_t size, void (*ctor)(void *))
+                                       size_t size)
 {
-       return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, ctor);
+       return kmem_cache_create(name, size, 0, SLAB_RECLAIM_ACCOUNT, NULL);
 }
 
 static inline void *f2fs_kmem_cache_alloc(struct kmem_cache *cachep,
@@ -983,24 +1018,28 @@ static inline void set_raw_inline(struct f2fs_inode_info *fi,
                ri->i_inline |= F2FS_INLINE_DATA;
 }
 
+static inline int f2fs_has_inline_xattr(struct inode *inode)
+{
+       return is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR);
+}
+
 static inline unsigned int addrs_per_inode(struct f2fs_inode_info *fi)
 {
-       if (is_inode_flag_set(fi, FI_INLINE_XATTR))
+       if (f2fs_has_inline_xattr(&fi->vfs_inode))
                return DEF_ADDRS_PER_INODE - F2FS_INLINE_XATTR_ADDRS;
        return DEF_ADDRS_PER_INODE;
 }
 
 static inline void *inline_xattr_addr(struct page *page)
 {
-       struct f2fs_inode *ri;
-       ri = (struct f2fs_inode *)page_address(page);
+       struct f2fs_inode *ri = F2FS_INODE(page);
        return (void *)&(ri->i_addr[DEF_ADDRS_PER_INODE -
                                        F2FS_INLINE_XATTR_ADDRS]);
 }
 
 static inline int inline_xattr_size(struct inode *inode)
 {
-       if (is_inode_flag_set(F2FS_I(inode), FI_INLINE_XATTR))
+       if (f2fs_has_inline_xattr(inode))
                return F2FS_INLINE_XATTR_ADDRS << 2;
        else
                return 0;
@@ -1013,8 +1052,7 @@ static inline int f2fs_has_inline_data(struct inode *inode)
 
 static inline void *inline_data_addr(struct page *page)
 {
-       struct f2fs_inode *ri;
-       ri = (struct f2fs_inode *)page_address(page);
+       struct f2fs_inode *ri = F2FS_INODE(page);
        return (void *)&(ri->i_addr[1]);
 }
 
@@ -1023,6 +1061,12 @@ static inline int f2fs_readonly(struct super_block *sb)
        return sb->s_flags & MS_RDONLY;
 }
 
+static inline void f2fs_stop_checkpoint(struct f2fs_sb_info *sbi)
+{
+       set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
+       sbi->sb->s_flags |= MS_RDONLY;
+}
+
 #define get_inode_mode(i) \
        ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \
         (F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
@@ -1048,7 +1092,7 @@ void f2fs_set_inode_flags(struct inode *);
 struct inode *f2fs_iget(struct super_block *, unsigned long);
 int try_to_free_nats(struct f2fs_sb_info *, int);
 void update_inode(struct inode *, struct page *);
-int update_inode_page(struct inode *);
+void update_inode_page(struct inode *);
 int f2fs_write_inode(struct inode *, struct writeback_control *);
 void f2fs_evict_inode(struct inode *);
 
@@ -1097,6 +1141,7 @@ struct dnode_of_data;
 struct node_info;
 
 int is_checkpointed_node(struct f2fs_sb_info *, nid_t);
+bool fsync_mark_done(struct f2fs_sb_info *, nid_t);
 void get_node_info(struct f2fs_sb_info *, nid_t, struct node_info *);
 int get_dnode_of_data(struct dnode_of_data *, pgoff_t, int);
 int truncate_inode_blocks(struct inode *, pgoff_t);
@@ -1115,6 +1160,7 @@ void alloc_nid_done(struct f2fs_sb_info *, nid_t);
 void alloc_nid_failed(struct f2fs_sb_info *, nid_t);
 void recover_node_page(struct f2fs_sb_info *, struct page *,
                struct f2fs_summary *, struct node_info *, block_t);
+bool recover_xattr_data(struct inode *, struct page *, block_t);
 int recover_inode_page(struct f2fs_sb_info *, struct page *);
 int restore_node_summary(struct f2fs_sb_info *, unsigned int,
                                struct f2fs_summary_block *);
@@ -1129,7 +1175,9 @@ void destroy_node_manager_caches(void);
  */
 void f2fs_balance_fs(struct f2fs_sb_info *);
 void f2fs_balance_fs_bg(struct f2fs_sb_info *);
+int f2fs_issue_flush(struct f2fs_sb_info *);
 void invalidate_blocks(struct f2fs_sb_info *, block_t);
+void refresh_sit_entry(struct f2fs_sb_info *, block_t, block_t);
 void clear_prefree_segments(struct f2fs_sb_info *);
 int npages_for_summary_flush(struct f2fs_sb_info *);
 void allocate_new_segments(struct f2fs_sb_info *);
@@ -1162,6 +1210,7 @@ void destroy_segment_manager_caches(void);
  */
 struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
 struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
+int ra_meta_pages(struct f2fs_sb_info *, int, int, int);
 long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
 int acquire_orphan_inode(struct f2fs_sb_info *);
 void release_orphan_inode(struct f2fs_sb_info *);
@@ -1231,7 +1280,7 @@ struct f2fs_stat_info {
        int util_free, util_valid, util_invalid;
        int rsvd_segs, overp_segs;
        int dirty_count, node_pages, meta_pages;
-       int prefree_count, call_count;
+       int prefree_count, call_count, cp_count;
        int tot_segs, node_segs, data_segs, free_segs, free_secs;
        int tot_blks, data_blks, node_blks;
        int curseg[NR_CURSEG_TYPE];
@@ -1248,6 +1297,7 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
        return (struct f2fs_stat_info *)sbi->stat_info;
 }
 
+#define stat_inc_cp_count(si)          ((si)->cp_count++)
 #define stat_inc_call_count(si)                ((si)->call_count++)
 #define stat_inc_bggc_count(sbi)       ((sbi)->bg_gc++)
 #define stat_inc_dirty_dir(sbi)                ((sbi)->n_dirty_dirs++)
@@ -1302,6 +1352,7 @@ void f2fs_destroy_stats(struct f2fs_sb_info *);
 void __init f2fs_create_root_stats(void);
 void f2fs_destroy_root_stats(void);
 #else
+#define stat_inc_cp_count(si)
 #define stat_inc_call_count(si)
 #define stat_inc_bggc_count(si)
 #define stat_inc_dirty_dir(sbi)
index 0dfcef5..60e7d54 100644 (file)
@@ -76,7 +76,7 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
        trace_f2fs_vm_page_mkwrite(page, DATA);
 mapped:
        /* fill the page */
-       wait_on_page_writeback(page);
+       f2fs_wait_on_page_writeback(page, DATA);
 out:
        sb_end_pagefault(inode->i_sb);
        return block_page_mkwrite_return(err);
@@ -84,6 +84,7 @@ out:
 
 static const struct vm_operations_struct f2fs_file_vm_ops = {
        .fault          = filemap_fault,
+       .map_pages      = filemap_map_pages,
        .page_mkwrite   = f2fs_vm_page_mkwrite,
        .remap_pages    = generic_file_remap_pages,
 };
@@ -111,11 +112,12 @@ static int get_parent_ino(struct inode *inode, nid_t *pino)
 int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
 {
        struct inode *inode = file->f_mapping->host;
+       struct f2fs_inode_info *fi = F2FS_I(inode);
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        int ret = 0;
        bool need_cp = false;
        struct writeback_control wbc = {
-               .sync_mode = WB_SYNC_NONE,
+               .sync_mode = WB_SYNC_ALL,
                .nr_to_write = LONG_MAX,
                .for_reclaim = 0,
        };
@@ -133,7 +135,7 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        /* guarantee free sections for fsync */
        f2fs_balance_fs(sbi);
 
-       mutex_lock(&inode->i_mutex);
+       down_read(&fi->i_sem);
 
        /*
         * Both of fdatasync() and fsync() are able to be recovered from
@@ -150,25 +152,33 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi)))
                need_cp = true;
 
+       up_read(&fi->i_sem);
+
        if (need_cp) {
                nid_t pino;
 
-               F2FS_I(inode)->xattr_ver = 0;
-
                /* all the dirty node pages should be flushed for POR */
                ret = f2fs_sync_fs(inode->i_sb, 1);
+
+               down_write(&fi->i_sem);
+               F2FS_I(inode)->xattr_ver = 0;
                if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
                                        get_parent_ino(inode, &pino)) {
                        F2FS_I(inode)->i_pino = pino;
                        file_got_pino(inode);
+                       up_write(&fi->i_sem);
                        mark_inode_dirty_sync(inode);
                        ret = f2fs_write_inode(inode, NULL);
                        if (ret)
                                goto out;
+               } else {
+                       up_write(&fi->i_sem);
                }
        } else {
                /* if there is no written node page, write its inode page */
                while (!sync_node_pages(sbi, inode->i_ino, &wbc)) {
+                       if (fsync_mark_done(sbi, inode->i_ino))
+                               goto out;
                        mark_inode_dirty_sync(inode);
                        ret = f2fs_write_inode(inode, NULL);
                        if (ret)
@@ -177,10 +187,9 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
                ret = wait_on_node_pages_writeback(sbi, inode->i_ino);
                if (ret)
                        goto out;
-               ret = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
+               ret = f2fs_issue_flush(F2FS_SB(inode->i_sb));
        }
 out:
-       mutex_unlock(&inode->i_mutex);
        trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
        return ret;
 }
@@ -245,7 +254,7 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
                f2fs_put_page(page, 1);
                return;
        }
-       wait_on_page_writeback(page);
+       f2fs_wait_on_page_writeback(page, DATA);
        zero_user(page, offset, PAGE_CACHE_SIZE - offset);
        set_page_dirty(page);
        f2fs_put_page(page, 1);
@@ -422,7 +431,7 @@ static void fill_zero(struct inode *inode, pgoff_t index,
        f2fs_unlock_op(sbi);
 
        if (!IS_ERR(page)) {
-               wait_on_page_writeback(page);
+               f2fs_wait_on_page_writeback(page, DATA);
                zero_user(page, start, len);
                set_page_dirty(page);
                f2fs_put_page(page, 1);
@@ -560,6 +569,8 @@ static long f2fs_fallocate(struct file *file, int mode,
        if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
                return -EOPNOTSUPP;
 
+       mutex_lock(&inode->i_mutex);
+
        if (mode & FALLOC_FL_PUNCH_HOLE)
                ret = punch_hole(inode, offset, len);
        else
@@ -569,6 +580,9 @@ static long f2fs_fallocate(struct file *file, int mode,
                inode->i_mtime = inode->i_ctime = CURRENT_TIME;
                mark_inode_dirty(inode);
        }
+
+       mutex_unlock(&inode->i_mutex);
+
        trace_f2fs_fallocate(inode, mode, offset, len, ret);
        return ret;
 }
index ea0371e..b90dbe5 100644 (file)
@@ -531,15 +531,10 @@ static void move_data_page(struct inode *inode, struct page *page, int gc_type)
                set_page_dirty(page);
                set_cold_data(page);
        } else {
-               struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-
                f2fs_wait_on_page_writeback(page, DATA);
 
-               if (clear_page_dirty_for_io(page) &&
-                       S_ISDIR(inode->i_mode)) {
-                       dec_page_count(sbi, F2FS_DIRTY_DENTS);
+               if (clear_page_dirty_for_io(page))
                        inode_dec_dirty_dents(inode);
-               }
                set_cold_data(page);
                do_write_data_page(page, &fio);
                clear_cold_data(page);
@@ -701,6 +696,8 @@ int f2fs_gc(struct f2fs_sb_info *sbi)
 gc_more:
        if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE)))
                goto stop;
+       if (unlikely(is_set_ckpt_flags(F2FS_CKPT(sbi), CP_ERROR_FLAG)))
+               goto stop;
 
        if (gc_type == BG_GC && has_not_enough_free_secs(sbi, nfree)) {
                gc_type = FG_GC;
@@ -711,6 +708,11 @@ gc_more:
                goto stop;
        ret = 0;
 
+       /* readahead multi ssa blocks those have contiguous address */
+       if (sbi->segs_per_sec > 1)
+               ra_meta_pages(sbi, GET_SUM_BLOCK(sbi, segno), sbi->segs_per_sec,
+                                                               META_SSA);
+
        for (i = 0; i < sbi->segs_per_sec; i++)
                do_garbage_collect(sbi, segno + i, &ilist, gc_type);
 
@@ -740,7 +742,7 @@ void build_gc_manager(struct f2fs_sb_info *sbi)
 int __init create_gc_caches(void)
 {
        winode_slab = f2fs_kmem_cache_create("f2fs_gc_inodes",
-                       sizeof(struct inode_entry), NULL);
+                       sizeof(struct inode_entry));
        if (!winode_slab)
                return -ENOMEM;
        return 0;
index 31ee5b1..383db1f 100644 (file)
@@ -45,8 +45,10 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
        }
 
        ipage = get_node_page(sbi, inode->i_ino);
-       if (IS_ERR(ipage))
+       if (IS_ERR(ipage)) {
+               unlock_page(page);
                return PTR_ERR(ipage);
+       }
 
        zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
 
index 28cea76..ee829d3 100644 (file)
@@ -107,6 +107,7 @@ static int do_read_inode(struct inode *inode)
        fi->flags = 0;
        fi->i_advise = ri->i_advise;
        fi->i_pino = le32_to_cpu(ri->i_pino);
+       fi->i_dir_level = ri->i_dir_level;
 
        get_extent_info(&fi->ext, ri->i_ext);
        get_inline_info(fi, ri);
@@ -204,6 +205,7 @@ void update_inode(struct inode *inode, struct page *node_page)
        ri->i_flags = cpu_to_le32(F2FS_I(inode)->i_flags);
        ri->i_pino = cpu_to_le32(F2FS_I(inode)->i_pino);
        ri->i_generation = cpu_to_le32(inode->i_generation);
+       ri->i_dir_level = F2FS_I(inode)->i_dir_level;
 
        __set_inode_rdev(inode, ri);
        set_cold_node(inode, node_page);
@@ -212,24 +214,29 @@ void update_inode(struct inode *inode, struct page *node_page)
        clear_inode_flag(F2FS_I(inode), FI_DIRTY_INODE);
 }
 
-int update_inode_page(struct inode *inode)
+void update_inode_page(struct inode *inode)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct page *node_page;
-
+retry:
        node_page = get_node_page(sbi, inode->i_ino);
-       if (IS_ERR(node_page))
-               return PTR_ERR(node_page);
-
+       if (IS_ERR(node_page)) {
+               int err = PTR_ERR(node_page);
+               if (err == -ENOMEM) {
+                       cond_resched();
+                       goto retry;
+               } else if (err != -ENOENT) {
+                       f2fs_stop_checkpoint(sbi);
+               }
+               return;
+       }
        update_inode(inode, node_page);
        f2fs_put_page(node_page, 1);
-       return 0;
 }
 
 int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       int ret;
 
        if (inode->i_ino == F2FS_NODE_INO(sbi) ||
                        inode->i_ino == F2FS_META_INO(sbi))
@@ -243,13 +250,13 @@ int f2fs_write_inode(struct inode *inode, struct writeback_control *wbc)
         * during the urgent cleaning time when runing out of free sections.
         */
        f2fs_lock_op(sbi);
-       ret = update_inode_page(inode);
+       update_inode_page(inode);
        f2fs_unlock_op(sbi);
 
        if (wbc)
                f2fs_balance_fs(sbi);
 
-       return ret;
+       return 0;
 }
 
 /*
@@ -266,7 +273,7 @@ void f2fs_evict_inode(struct inode *inode)
                        inode->i_ino == F2FS_META_INO(sbi))
                goto no_delete;
 
-       f2fs_bug_on(atomic_read(&F2FS_I(inode)->dirty_dents));
+       f2fs_bug_on(get_dirty_dents(inode));
        remove_dirty_dir_inode(inode);
 
        if (inode->i_nlink || is_bad_inode(inode))
index 397d459..a9409d1 100644 (file)
@@ -207,6 +207,8 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
                inode = f2fs_iget(dir->i_sb, ino);
                if (IS_ERR(inode))
                        return ERR_CAST(inode);
+
+               stat_inc_inline_inode(inode);
        }
 
        return d_splice_alias(inode, dentry);
@@ -424,12 +426,17 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                }
 
                f2fs_set_link(new_dir, new_entry, new_page, old_inode);
+               down_write(&F2FS_I(old_inode)->i_sem);
                F2FS_I(old_inode)->i_pino = new_dir->i_ino;
+               up_write(&F2FS_I(old_inode)->i_sem);
 
                new_inode->i_ctime = CURRENT_TIME;
+               down_write(&F2FS_I(new_inode)->i_sem);
                if (old_dir_entry)
                        drop_nlink(new_inode);
                drop_nlink(new_inode);
+               up_write(&F2FS_I(new_inode)->i_sem);
+
                mark_inode_dirty(new_inode);
 
                if (!new_inode->i_nlink)
@@ -459,7 +466,9 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
                if (old_dir != new_dir) {
                        f2fs_set_link(old_inode, old_dir_entry,
                                                old_dir_page, new_dir);
+                       down_write(&F2FS_I(old_inode)->i_sem);
                        F2FS_I(old_inode)->i_pino = new_dir->i_ino;
+                       up_write(&F2FS_I(old_inode)->i_sem);
                        update_inode_page(old_inode);
                } else {
                        kunmap(old_dir_page);
index b0649b7..a161e95 100644 (file)
 #include "segment.h"
 #include <trace/events/f2fs.h>
 
+#define on_build_free_nids(nmi) mutex_is_locked(&nm_i->build_lock)
+
 static struct kmem_cache *nat_entry_slab;
 static struct kmem_cache *free_nid_slab;
 
+static inline bool available_free_memory(struct f2fs_nm_info *nm_i, int type)
+{
+       struct sysinfo val;
+       unsigned long mem_size = 0;
+
+       si_meminfo(&val);
+       if (type == FREE_NIDS)
+               mem_size = nm_i->fcnt * sizeof(struct free_nid);
+       else if (type == NAT_ENTRIES)
+               mem_size += nm_i->nat_cnt * sizeof(struct nat_entry);
+       mem_size >>= 12;
+
+       /* give 50:50 memory for free nids and nat caches respectively */
+       return (mem_size < ((val.totalram * nm_i->ram_thresh) >> 11));
+}
+
 static void clear_node_page_dirty(struct page *page)
 {
        struct address_space *mapping = page->mapping;
@@ -82,42 +100,6 @@ static struct page *get_next_nat_page(struct f2fs_sb_info *sbi, nid_t nid)
        return dst_page;
 }
 
-/*
- * Readahead NAT pages
- */
-static void ra_nat_pages(struct f2fs_sb_info *sbi, int nid)
-{
-       struct address_space *mapping = META_MAPPING(sbi);
-       struct f2fs_nm_info *nm_i = NM_I(sbi);
-       struct page *page;
-       pgoff_t index;
-       int i;
-       struct f2fs_io_info fio = {
-               .type = META,
-               .rw = READ_SYNC | REQ_META | REQ_PRIO
-       };
-
-
-       for (i = 0; i < FREE_NID_PAGES; i++, nid += NAT_ENTRY_PER_BLOCK) {
-               if (unlikely(nid >= nm_i->max_nid))
-                       nid = 0;
-               index = current_nat_addr(sbi, nid);
-
-               page = grab_cache_page(mapping, index);
-               if (!page)
-                       continue;
-               if (PageUptodate(page)) {
-                       mark_page_accessed(page);
-                       f2fs_put_page(page, 1);
-                       continue;
-               }
-               f2fs_submit_page_mbio(sbi, page, index, &fio);
-               mark_page_accessed(page);
-               f2fs_put_page(page, 0);
-       }
-       f2fs_submit_merged_bio(sbi, META, READ);
-}
-
 static struct nat_entry *__lookup_nat_cache(struct f2fs_nm_info *nm_i, nid_t n)
 {
        return radix_tree_lookup(&nm_i->nat_root, n);
@@ -151,6 +133,20 @@ int is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
        return is_cp;
 }
 
+bool fsync_mark_done(struct f2fs_sb_info *sbi, nid_t nid)
+{
+       struct f2fs_nm_info *nm_i = NM_I(sbi);
+       struct nat_entry *e;
+       bool fsync_done = false;
+
+       read_lock(&nm_i->nat_tree_lock);
+       e = __lookup_nat_cache(nm_i, nid);
+       if (e)
+               fsync_done = e->fsync_done;
+       read_unlock(&nm_i->nat_tree_lock);
+       return fsync_done;
+}
+
 static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
 {
        struct nat_entry *new;
@@ -164,6 +160,7 @@ static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
        }
        memset(new, 0, sizeof(struct nat_entry));
        nat_set_nid(new, nid);
+       new->checkpointed = true;
        list_add_tail(&new->list, &nm_i->nat_entries);
        nm_i->nat_cnt++;
        return new;
@@ -185,13 +182,12 @@ retry:
                nat_set_blkaddr(e, le32_to_cpu(ne->block_addr));
                nat_set_ino(e, le32_to_cpu(ne->ino));
                nat_set_version(e, ne->version);
-               e->checkpointed = true;
        }
        write_unlock(&nm_i->nat_tree_lock);
 }
 
 static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
-                       block_t new_blkaddr)
+                       block_t new_blkaddr, bool fsync_done)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct nat_entry *e;
@@ -205,7 +201,6 @@ retry:
                        goto retry;
                }
                e->ni = *ni;
-               e->checkpointed = true;
                f2fs_bug_on(ni->blk_addr == NEW_ADDR);
        } else if (new_blkaddr == NEW_ADDR) {
                /*
@@ -217,9 +212,6 @@ retry:
                f2fs_bug_on(ni->blk_addr != NULL_ADDR);
        }
 
-       if (new_blkaddr == NEW_ADDR)
-               e->checkpointed = false;
-
        /* sanity check */
        f2fs_bug_on(nat_get_blkaddr(e) != ni->blk_addr);
        f2fs_bug_on(nat_get_blkaddr(e) == NULL_ADDR &&
@@ -239,6 +231,11 @@ retry:
        /* change address */
        nat_set_blkaddr(e, new_blkaddr);
        __set_nat_cache_dirty(nm_i, e);
+
+       /* update fsync_mark if its inode nat entry is still alive */
+       e = __lookup_nat_cache(nm_i, ni->ino);
+       if (e)
+               e->fsync_done = fsync_done;
        write_unlock(&nm_i->nat_tree_lock);
 }
 
@@ -246,7 +243,7 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
 
-       if (nm_i->nat_cnt <= NM_WOUT_THRESHOLD)
+       if (available_free_memory(nm_i, NAT_ENTRIES))
                return 0;
 
        write_lock(&nm_i->nat_tree_lock);
@@ -505,7 +502,7 @@ static void truncate_node(struct dnode_of_data *dn)
        /* Deallocate node address */
        invalidate_blocks(sbi, ni.blk_addr);
        dec_valid_node_count(sbi, dn->inode);
-       set_node_addr(sbi, &ni, NULL_ADDR);
+       set_node_addr(sbi, &ni, NULL_ADDR, false);
 
        if (dn->nid == dn->inode->i_ino) {
                remove_orphan_inode(sbi, dn->nid);
@@ -763,7 +760,7 @@ skip_partial:
                                f2fs_put_page(page, 1);
                                goto restart;
                        }
-                       wait_on_page_writeback(page);
+                       f2fs_wait_on_page_writeback(page, NODE);
                        ri->i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
                        set_page_dirty(page);
                        unlock_page(page);
@@ -852,7 +849,8 @@ struct page *new_node_page(struct dnode_of_data *dn,
        if (unlikely(is_inode_flag_set(F2FS_I(dn->inode), FI_NO_ALLOC)))
                return ERR_PTR(-EPERM);
 
-       page = grab_cache_page(NODE_MAPPING(sbi), dn->nid);
+       page = grab_cache_page_write_begin(NODE_MAPPING(sbi),
+                                       dn->nid, AOP_FLAG_NOFS);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -867,14 +865,14 @@ struct page *new_node_page(struct dnode_of_data *dn,
        f2fs_bug_on(old_ni.blk_addr != NULL_ADDR);
        new_ni = old_ni;
        new_ni.ino = dn->inode->i_ino;
-       set_node_addr(sbi, &new_ni, NEW_ADDR);
+       set_node_addr(sbi, &new_ni, NEW_ADDR, false);
 
        fill_node_footer(page, dn->nid, dn->inode->i_ino, ofs, true);
        set_cold_node(dn->inode, page);
        SetPageUptodate(page);
        set_page_dirty(page);
 
-       if (ofs == XATTR_NODE_OFFSET)
+       if (f2fs_has_xattr_block(ofs))
                F2FS_I(dn->inode)->i_xattr_nid = dn->nid;
 
        dn->node_page = page;
@@ -948,7 +946,8 @@ struct page *get_node_page(struct f2fs_sb_info *sbi, pgoff_t nid)
        struct page *page;
        int err;
 repeat:
-       page = grab_cache_page(NODE_MAPPING(sbi), nid);
+       page = grab_cache_page_write_begin(NODE_MAPPING(sbi),
+                                       nid, AOP_FLAG_NOFS);
        if (!page)
                return ERR_PTR(-ENOMEM);
 
@@ -959,7 +958,7 @@ repeat:
                goto got_it;
 
        lock_page(page);
-       if (unlikely(!PageUptodate(page))) {
+       if (unlikely(!PageUptodate(page) || nid != nid_of_node(page))) {
                f2fs_put_page(page, 1);
                return ERR_PTR(-EIO);
        }
@@ -968,7 +967,6 @@ repeat:
                goto repeat;
        }
 got_it:
-       f2fs_bug_on(nid != nid_of_node(page));
        mark_page_accessed(page);
        return page;
 }
@@ -1168,7 +1166,7 @@ int wait_on_node_pages_writeback(struct f2fs_sb_info *sbi, nid_t ino)
                                continue;
 
                        if (ino && ino_of_node(page) == ino) {
-                               wait_on_page_writeback(page);
+                               f2fs_wait_on_page_writeback(page, NODE);
                                if (TestClearPageError(page))
                                        ret = -EIO;
                        }
@@ -1201,7 +1199,7 @@ static int f2fs_write_node_page(struct page *page,
        if (unlikely(sbi->por_doing))
                goto redirty_out;
 
-       wait_on_page_writeback(page);
+       f2fs_wait_on_page_writeback(page, NODE);
 
        /* get old block addr of this node page */
        nid = nid_of_node(page);
@@ -1222,7 +1220,7 @@ static int f2fs_write_node_page(struct page *page,
        mutex_lock(&sbi->node_write);
        set_page_writeback(page);
        write_node_page(sbi, page, &fio, nid, ni.blk_addr, &new_addr);
-       set_node_addr(sbi, &ni, new_addr);
+       set_node_addr(sbi, &ni, new_addr, is_fsync_dnode(page));
        dec_page_count(sbi, F2FS_DIRTY_NODES);
        mutex_unlock(&sbi->node_write);
        unlock_page(page);
@@ -1231,35 +1229,32 @@ static int f2fs_write_node_page(struct page *page,
 redirty_out:
        dec_page_count(sbi, F2FS_DIRTY_NODES);
        wbc->pages_skipped++;
+       account_page_redirty(page);
        set_page_dirty(page);
        return AOP_WRITEPAGE_ACTIVATE;
 }
 
-/*
- * It is very important to gather dirty pages and write at once, so that we can
- * submit a big bio without interfering other data writes.
- * Be default, 512 pages (2MB) * 3 node types, is more reasonable.
- */
-#define COLLECT_DIRTY_NODES    1536
 static int f2fs_write_node_pages(struct address_space *mapping,
                            struct writeback_control *wbc)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(mapping->host->i_sb);
-       long nr_to_write = wbc->nr_to_write;
+       long diff;
 
        /* balancing f2fs's metadata in background */
        f2fs_balance_fs_bg(sbi);
 
        /* collect a number of dirty node pages and write together */
-       if (get_pages(sbi, F2FS_DIRTY_NODES) < COLLECT_DIRTY_NODES)
-               return 0;
+       if (get_pages(sbi, F2FS_DIRTY_NODES) < nr_pages_to_skip(sbi, NODE))
+               goto skip_write;
 
-       /* if mounting is failed, skip writing node pages */
-       wbc->nr_to_write = 3 * max_hw_blocks(sbi);
+       diff = nr_pages_to_write(sbi, NODE, wbc);
        wbc->sync_mode = WB_SYNC_NONE;
        sync_node_pages(sbi, 0, wbc);
-       wbc->nr_to_write = nr_to_write - (3 * max_hw_blocks(sbi) -
-                                               wbc->nr_to_write);
+       wbc->nr_to_write = max((long)0, wbc->nr_to_write - diff);
+       return 0;
+
+skip_write:
+       wbc->pages_skipped += get_pages(sbi, F2FS_DIRTY_NODES);
        return 0;
 }
 
@@ -1307,22 +1302,17 @@ const struct address_space_operations f2fs_node_aops = {
        .releasepage    = f2fs_release_node_page,
 };
 
-static struct free_nid *__lookup_free_nid_list(nid_t n, struct list_head *head)
+static struct free_nid *__lookup_free_nid_list(struct f2fs_nm_info *nm_i,
+                                               nid_t n)
 {
-       struct list_head *this;
-       struct free_nid *i;
-       list_for_each(this, head) {
-               i = list_entry(this, struct free_nid, list);
-               if (i->nid == n)
-                       return i;
-       }
-       return NULL;
+       return radix_tree_lookup(&nm_i->free_nid_root, n);
 }
 
-static void __del_from_free_nid_list(struct free_nid *i)
+static void __del_from_free_nid_list(struct f2fs_nm_info *nm_i,
+                                               struct free_nid *i)
 {
        list_del(&i->list);
-       kmem_cache_free(free_nid_slab, i);
+       radix_tree_delete(&nm_i->free_nid_root, i->nid);
 }
 
 static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
@@ -1331,7 +1321,7 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
        struct nat_entry *ne;
        bool allocated = false;
 
-       if (nm_i->fcnt > 2 * MAX_FREE_NIDS)
+       if (!available_free_memory(nm_i, FREE_NIDS))
                return -1;
 
        /* 0 nid should not be used */
@@ -1342,7 +1332,8 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
                /* do not add allocated nids */
                read_lock(&nm_i->nat_tree_lock);
                ne = __lookup_nat_cache(nm_i, nid);
-               if (ne && nat_get_blkaddr(ne) != NULL_ADDR)
+               if (ne &&
+                       (!ne->checkpointed || nat_get_blkaddr(ne) != NULL_ADDR))
                        allocated = true;
                read_unlock(&nm_i->nat_tree_lock);
                if (allocated)
@@ -1354,7 +1345,7 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
        i->state = NID_NEW;
 
        spin_lock(&nm_i->free_nid_list_lock);
-       if (__lookup_free_nid_list(nid, &nm_i->free_nid_list)) {
+       if (radix_tree_insert(&nm_i->free_nid_root, i->nid, i)) {
                spin_unlock(&nm_i->free_nid_list_lock);
                kmem_cache_free(free_nid_slab, i);
                return 0;
@@ -1368,13 +1359,19 @@ static int add_free_nid(struct f2fs_nm_info *nm_i, nid_t nid, bool build)
 static void remove_free_nid(struct f2fs_nm_info *nm_i, nid_t nid)
 {
        struct free_nid *i;
+       bool need_free = false;
+
        spin_lock(&nm_i->free_nid_list_lock);
-       i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
+       i = __lookup_free_nid_list(nm_i, nid);
        if (i && i->state == NID_NEW) {
-               __del_from_free_nid_list(i);
+               __del_from_free_nid_list(nm_i, i);
                nm_i->fcnt--;
+               need_free = true;
        }
        spin_unlock(&nm_i->free_nid_list_lock);
+
+       if (need_free)
+               kmem_cache_free(free_nid_slab, i);
 }
 
 static void scan_nat_page(struct f2fs_nm_info *nm_i,
@@ -1413,7 +1410,7 @@ static void build_free_nids(struct f2fs_sb_info *sbi)
                return;
 
        /* readahead nat pages to be scanned */
-       ra_nat_pages(sbi, nid);
+       ra_meta_pages(sbi, NAT_BLOCK_OFFSET(nid), FREE_NID_PAGES, META_NAT);
 
        while (1) {
                struct page *page = get_current_nat_page(sbi, nid);
@@ -1454,7 +1451,6 @@ bool alloc_nid(struct f2fs_sb_info *sbi, nid_t *nid)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct free_nid *i = NULL;
-       struct list_head *this;
 retry:
        if (unlikely(sbi->total_valid_node_count + 1 >= nm_i->max_nid))
                return false;
@@ -1462,13 +1458,11 @@ retry:
        spin_lock(&nm_i->free_nid_list_lock);
 
        /* We should not use stale free nids created by build_free_nids */
-       if (nm_i->fcnt && !sbi->on_build_free_nids) {
+       if (nm_i->fcnt && !on_build_free_nids(nm_i)) {
                f2fs_bug_on(list_empty(&nm_i->free_nid_list));
-               list_for_each(this, &nm_i->free_nid_list) {
-                       i = list_entry(this, struct free_nid, list);
+               list_for_each_entry(i, &nm_i->free_nid_list, list)
                        if (i->state == NID_NEW)
                                break;
-               }
 
                f2fs_bug_on(i->state != NID_NEW);
                *nid = i->nid;
@@ -1481,9 +1475,7 @@ retry:
 
        /* Let's scan nat pages and its caches to get free nids */
        mutex_lock(&nm_i->build_lock);
-       sbi->on_build_free_nids = true;
        build_free_nids(sbi);
-       sbi->on_build_free_nids = false;
        mutex_unlock(&nm_i->build_lock);
        goto retry;
 }
@@ -1497,10 +1489,12 @@ void alloc_nid_done(struct f2fs_sb_info *sbi, nid_t nid)
        struct free_nid *i;
 
        spin_lock(&nm_i->free_nid_list_lock);
-       i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
+       i = __lookup_free_nid_list(nm_i, nid);
        f2fs_bug_on(!i || i->state != NID_ALLOC);
-       __del_from_free_nid_list(i);
+       __del_from_free_nid_list(nm_i, i);
        spin_unlock(&nm_i->free_nid_list_lock);
+
+       kmem_cache_free(free_nid_slab, i);
 }
 
 /*
@@ -1510,20 +1504,25 @@ void alloc_nid_failed(struct f2fs_sb_info *sbi, nid_t nid)
 {
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct free_nid *i;
+       bool need_free = false;
 
        if (!nid)
                return;
 
        spin_lock(&nm_i->free_nid_list_lock);
-       i = __lookup_free_nid_list(nid, &nm_i->free_nid_list);
+       i = __lookup_free_nid_list(nm_i, nid);
        f2fs_bug_on(!i || i->state != NID_ALLOC);
-       if (nm_i->fcnt > 2 * MAX_FREE_NIDS) {
-               __del_from_free_nid_list(i);
+       if (!available_free_memory(nm_i, FREE_NIDS)) {
+               __del_from_free_nid_list(nm_i, i);
+               need_free = true;
        } else {
                i->state = NID_NEW;
                nm_i->fcnt++;
        }
        spin_unlock(&nm_i->free_nid_list_lock);
+
+       if (need_free)
+               kmem_cache_free(free_nid_slab, i);
 }
 
 void recover_node_page(struct f2fs_sb_info *sbi, struct page *page,
@@ -1531,10 +1530,83 @@ void recover_node_page(struct f2fs_sb_info *sbi, struct page *page,
                block_t new_blkaddr)
 {
        rewrite_node_page(sbi, page, sum, ni->blk_addr, new_blkaddr);
-       set_node_addr(sbi, ni, new_blkaddr);
+       set_node_addr(sbi, ni, new_blkaddr, false);
        clear_node_page_dirty(page);
 }
 
+void recover_inline_xattr(struct inode *inode, struct page *page)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       void *src_addr, *dst_addr;
+       size_t inline_size;
+       struct page *ipage;
+       struct f2fs_inode *ri;
+
+       if (!f2fs_has_inline_xattr(inode))
+               return;
+
+       if (!IS_INODE(page))
+               return;
+
+       ri = F2FS_INODE(page);
+       if (!(ri->i_inline & F2FS_INLINE_XATTR))
+               return;
+
+       ipage = get_node_page(sbi, inode->i_ino);
+       f2fs_bug_on(IS_ERR(ipage));
+
+       dst_addr = inline_xattr_addr(ipage);
+       src_addr = inline_xattr_addr(page);
+       inline_size = inline_xattr_size(inode);
+
+       memcpy(dst_addr, src_addr, inline_size);
+
+       update_inode(inode, ipage);
+       f2fs_put_page(ipage, 1);
+}
+
+bool recover_xattr_data(struct inode *inode, struct page *page, block_t blkaddr)
+{
+       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
+       nid_t prev_xnid = F2FS_I(inode)->i_xattr_nid;
+       nid_t new_xnid = nid_of_node(page);
+       struct node_info ni;
+
+       recover_inline_xattr(inode, page);
+
+       if (!f2fs_has_xattr_block(ofs_of_node(page)))
+               return false;
+
+       /* 1: invalidate the previous xattr nid */
+       if (!prev_xnid)
+               goto recover_xnid;
+
+       /* Deallocate node address */
+       get_node_info(sbi, prev_xnid, &ni);
+       f2fs_bug_on(ni.blk_addr == NULL_ADDR);
+       invalidate_blocks(sbi, ni.blk_addr);
+       dec_valid_node_count(sbi, inode);
+       set_node_addr(sbi, &ni, NULL_ADDR, false);
+
+recover_xnid:
+       /* 2: allocate new xattr nid */
+       if (unlikely(!inc_valid_node_count(sbi, inode)))
+               f2fs_bug_on(1);
+
+       remove_free_nid(NM_I(sbi), new_xnid);
+       get_node_info(sbi, new_xnid, &ni);
+       ni.ino = inode->i_ino;
+       set_node_addr(sbi, &ni, NEW_ADDR, false);
+       F2FS_I(inode)->i_xattr_nid = new_xnid;
+
+       /* 3: update xattr blkaddr */
+       refresh_sit_entry(sbi, NEW_ADDR, blkaddr);
+       set_node_addr(sbi, &ni, blkaddr, false);
+
+       update_inode_page(inode);
+       return true;
+}
+
 int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
 {
        struct f2fs_inode *src, *dst;
@@ -1567,7 +1639,7 @@ int recover_inode_page(struct f2fs_sb_info *sbi, struct page *page)
 
        if (unlikely(!inc_valid_node_count(sbi, NULL)))
                WARN_ON(1);
-       set_node_addr(sbi, &new_ni, NEW_ADDR);
+       set_node_addr(sbi, &new_ni, NEW_ADDR, false);
        inc_valid_inode_count(sbi);
        f2fs_put_page(ipage, 1);
        return 0;
@@ -1590,15 +1662,8 @@ static int ra_sum_pages(struct f2fs_sb_info *sbi, struct list_head *pages,
        for (; page_idx < start + nrpages; page_idx++) {
                /* alloc temporal page for read node summary info*/
                page = alloc_page(GFP_F2FS_ZERO);
-               if (!page) {
-                       struct page *tmp;
-                       list_for_each_entry_safe(page, tmp, pages, lru) {
-                               list_del(&page->lru);
-                               unlock_page(page);
-                               __free_pages(page, 0);
-                       }
-                       return -ENOMEM;
-               }
+               if (!page)
+                       break;
 
                lock_page(page);
                page->index = page_idx;
@@ -1609,7 +1674,8 @@ static int ra_sum_pages(struct f2fs_sb_info *sbi, struct list_head *pages,
                f2fs_submit_page_mbio(sbi, page, page->index, &fio);
 
        f2fs_submit_merged_bio(sbi, META, READ);
-       return 0;
+
+       return page_idx - start;
 }
 
 int restore_node_summary(struct f2fs_sb_info *sbi,
@@ -1628,15 +1694,17 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
        addr = START_BLOCK(sbi, segno);
        sum_entry = &sum->entries[0];
 
-       for (i = 0; i < last_offset; i += nrpages, addr += nrpages) {
+       for (i = 0; !err && i < last_offset; i += nrpages, addr += nrpages) {
                nrpages = min(last_offset - i, bio_blocks);
 
                /* read ahead node pages */
-               err = ra_sum_pages(sbi, &page_list, addr, nrpages);
-               if (err)
-                       return err;
+               nrpages = ra_sum_pages(sbi, &page_list, addr, nrpages);
+               if (!nrpages)
+                       return -ENOMEM;
 
                list_for_each_entry_safe(page, tmp, &page_list, lru) {
+                       if (err)
+                               goto skip;
 
                        lock_page(page);
                        if (unlikely(!PageUptodate(page))) {
@@ -1648,9 +1716,9 @@ int restore_node_summary(struct f2fs_sb_info *sbi,
                                sum_entry->ofs_in_node = 0;
                                sum_entry++;
                        }
-
-                       list_del(&page->lru);
                        unlock_page(page);
+skip:
+                       list_del(&page->lru);
                        __free_pages(page, 0);
                }
        }
@@ -1709,7 +1777,7 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
        struct f2fs_nm_info *nm_i = NM_I(sbi);
        struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
        struct f2fs_summary_block *sum = curseg->sum_blk;
-       struct list_head *cur, *n;
+       struct nat_entry *ne, *cur;
        struct page *page = NULL;
        struct f2fs_nat_block *nat_blk = NULL;
        nid_t start_nid = 0, end_nid = 0;
@@ -1721,18 +1789,17 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
                mutex_lock(&curseg->curseg_mutex);
 
        /* 1) flush dirty nat caches */
-       list_for_each_safe(cur, n, &nm_i->dirty_nat_entries) {
-               struct nat_entry *ne;
+       list_for_each_entry_safe(ne, cur, &nm_i->dirty_nat_entries, list) {
                nid_t nid;
                struct f2fs_nat_entry raw_ne;
                int offset = -1;
                block_t new_blkaddr;
 
-               ne = list_entry(cur, struct nat_entry, list);
-               nid = nat_get_nid(ne);
-
                if (nat_get_blkaddr(ne) == NEW_ADDR)
                        continue;
+
+               nid = nat_get_nid(ne);
+
                if (flushed)
                        goto to_nat_page;
 
@@ -1783,16 +1850,12 @@ flush_now:
                } else {
                        write_lock(&nm_i->nat_tree_lock);
                        __clear_nat_cache_dirty(nm_i, ne);
-                       ne->checkpointed = true;
                        write_unlock(&nm_i->nat_tree_lock);
                }
        }
        if (!flushed)
                mutex_unlock(&curseg->curseg_mutex);
        f2fs_put_page(page, 1);
-
-       /* 2) shrink nat caches if necessary */
-       try_to_free_nats(sbi, nm_i->nat_cnt - NM_WOUT_THRESHOLD);
 }
 
 static int init_node_manager(struct f2fs_sb_info *sbi)
@@ -1807,10 +1870,14 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
        /* segment_count_nat includes pair segment so divide to 2. */
        nat_segs = le32_to_cpu(sb_raw->segment_count_nat) >> 1;
        nat_blocks = nat_segs << le32_to_cpu(sb_raw->log_blocks_per_seg);
-       nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks;
+
+       /* not used nids: 0, node, meta, (and root counted as valid node) */
+       nm_i->max_nid = NAT_ENTRY_PER_BLOCK * nat_blocks - 3;
        nm_i->fcnt = 0;
        nm_i->nat_cnt = 0;
+       nm_i->ram_thresh = DEF_RAM_THRESHOLD;
 
+       INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC);
        INIT_LIST_HEAD(&nm_i->free_nid_list);
        INIT_RADIX_TREE(&nm_i->nat_root, GFP_ATOMIC);
        INIT_LIST_HEAD(&nm_i->nat_entries);
@@ -1864,8 +1931,11 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
        spin_lock(&nm_i->free_nid_list_lock);
        list_for_each_entry_safe(i, next_i, &nm_i->free_nid_list, list) {
                f2fs_bug_on(i->state == NID_ALLOC);
-               __del_from_free_nid_list(i);
+               __del_from_free_nid_list(nm_i, i);
                nm_i->fcnt--;
+               spin_unlock(&nm_i->free_nid_list_lock);
+               kmem_cache_free(free_nid_slab, i);
+               spin_lock(&nm_i->free_nid_list_lock);
        }
        f2fs_bug_on(nm_i->fcnt);
        spin_unlock(&nm_i->free_nid_list_lock);
@@ -1875,11 +1945,9 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
        while ((found = __gang_lookup_nat_cache(nm_i,
                                        nid, NATVEC_SIZE, natvec))) {
                unsigned idx;
-               for (idx = 0; idx < found; idx++) {
-                       struct nat_entry *e = natvec[idx];
-                       nid = nat_get_nid(e) + 1;
-                       __del_from_nat_cache(nm_i, e);
-               }
+               nid = nat_get_nid(natvec[found - 1]) + 1;
+               for (idx = 0; idx < found; idx++)
+                       __del_from_nat_cache(nm_i, natvec[idx]);
        }
        f2fs_bug_on(nm_i->nat_cnt);
        write_unlock(&nm_i->nat_tree_lock);
@@ -1892,12 +1960,12 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
 int __init create_node_manager_caches(void)
 {
        nat_entry_slab = f2fs_kmem_cache_create("nat_entry",
-                       sizeof(struct nat_entry), NULL);
+                       sizeof(struct nat_entry));
        if (!nat_entry_slab)
                return -ENOMEM;
 
        free_nid_slab = f2fs_kmem_cache_create("free_nid",
-                       sizeof(struct free_nid), NULL);
+                       sizeof(struct free_nid));
        if (!free_nid_slab) {
                kmem_cache_destroy(nat_entry_slab);
                return -ENOMEM;
index c4c7988..5decc1a 100644 (file)
 /* # of pages to perform readahead before building free nids */
 #define FREE_NID_PAGES 4
 
-/* maximum # of free node ids to produce during build_free_nids */
-#define MAX_FREE_NIDS (NAT_ENTRY_PER_BLOCK * FREE_NID_PAGES)
-
 /* maximum readahead size for node during getting data blocks */
 #define MAX_RA_NODE            128
 
-/* maximum cached nat entries to manage memory footprint */
-#define NM_WOUT_THRESHOLD      (64 * NAT_ENTRY_PER_BLOCK)
+/* control the memory footprint threshold (10MB per 1GB ram) */
+#define DEF_RAM_THRESHOLD      10
 
 /* vector size for gang look-up from nat cache that consists of radix tree */
 #define NATVEC_SIZE    64
@@ -45,6 +42,7 @@ struct node_info {
 struct nat_entry {
        struct list_head list;  /* for clean or dirty nat list */
        bool checkpointed;      /* whether it is checkpointed or not */
+       bool fsync_done;        /* whether the latest node has fsync mark */
        struct node_info ni;    /* in-memory node information */
 };
 
@@ -58,9 +56,15 @@ struct nat_entry {
 #define nat_set_version(nat, v)                (nat->ni.version = v)
 
 #define __set_nat_cache_dirty(nm_i, ne)                                        \
-       list_move_tail(&ne->list, &nm_i->dirty_nat_entries);
+       do {                                                            \
+               ne->checkpointed = false;                               \
+               list_move_tail(&ne->list, &nm_i->dirty_nat_entries);    \
+       } while (0);
 #define __clear_nat_cache_dirty(nm_i, ne)                              \
-       list_move_tail(&ne->list, &nm_i->nat_entries);
+       do {                                                            \
+               ne->checkpointed = true;                                \
+               list_move_tail(&ne->list, &nm_i->nat_entries);          \
+       } while (0);
 #define inc_node_version(version)      (++version)
 
 static inline void node_info_from_raw_nat(struct node_info *ni,
@@ -71,6 +75,11 @@ static inline void node_info_from_raw_nat(struct node_info *ni,
        ni->version = raw_ne->version;
 }
 
+enum nid_type {
+       FREE_NIDS,      /* indicates the free nid list */
+       NAT_ENTRIES     /* indicates the cached nat entry */
+};
+
 /*
  * For free nid mangement
  */
@@ -236,7 +245,7 @@ static inline bool IS_DNODE(struct page *node_page)
 {
        unsigned int ofs = ofs_of_node(node_page);
 
-       if (ofs == XATTR_NODE_OFFSET)
+       if (f2fs_has_xattr_block(ofs))
                return false;
 
        if (ofs == 3 || ofs == 4 + NIDS_PER_BLOCK ||
index 976a7a9..b1ae89f 100644 (file)
@@ -27,14 +27,12 @@ bool space_for_roll_forward(struct f2fs_sb_info *sbi)
 static struct fsync_inode_entry *get_fsync_inode(struct list_head *head,
                                                                nid_t ino)
 {
-       struct list_head *this;
        struct fsync_inode_entry *entry;
 
-       list_for_each(this, head) {
-               entry = list_entry(this, struct fsync_inode_entry, list);
+       list_for_each_entry(entry, head, list)
                if (entry->inode->i_ino == ino)
                        return entry;
-       }
+
        return NULL;
 }
 
@@ -136,7 +134,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
 
        /* get node pages in the current segment */
        curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
-       blkaddr = START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff;
+       blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
 
        /* read node page */
        page = alloc_page(GFP_F2FS_ZERO);
@@ -218,13 +216,12 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
 {
        struct seg_entry *sentry;
        unsigned int segno = GET_SEGNO(sbi, blkaddr);
-       unsigned short blkoff = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) &
-                                       (sbi->blocks_per_seg - 1);
+       unsigned short blkoff = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
+       struct f2fs_summary_block *sum_node;
        struct f2fs_summary sum;
+       struct page *sum_page, *node_page;
        nid_t ino, nid;
-       void *kaddr;
        struct inode *inode;
-       struct page *node_page;
        unsigned int offset;
        block_t bidx;
        int i;
@@ -238,18 +235,15 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
                struct curseg_info *curseg = CURSEG_I(sbi, i);
                if (curseg->segno == segno) {
                        sum = curseg->sum_blk->entries[blkoff];
-                       break;
+                       goto got_it;
                }
        }
-       if (i > CURSEG_COLD_DATA) {
-               struct page *sum_page = get_sum_page(sbi, segno);
-               struct f2fs_summary_block *sum_node;
-               kaddr = page_address(sum_page);
-               sum_node = (struct f2fs_summary_block *)kaddr;
-               sum = sum_node->entries[blkoff];
-               f2fs_put_page(sum_page, 1);
-       }
 
+       sum_page = get_sum_page(sbi, segno);
+       sum_node = (struct f2fs_summary_block *)page_address(sum_page);
+       sum = sum_node->entries[blkoff];
+       f2fs_put_page(sum_page, 1);
+got_it:
        /* Use the locked dnode page and inode */
        nid = le32_to_cpu(sum.nid);
        if (dn->inode->i_ino == nid) {
@@ -301,6 +295,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
        if (recover_inline_data(inode, page))
                goto out;
 
+       if (recover_xattr_data(inode, page, blkaddr))
+               goto out;
+
        start = start_bidx_of_node(ofs_of_node(page), fi);
        if (IS_INODE(page))
                end = start + ADDRS_PER_INODE(fi);
@@ -317,7 +314,7 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode,
                goto out;
        }
 
-       wait_on_page_writeback(dn.node_page);
+       f2fs_wait_on_page_writeback(dn.node_page, NODE);
 
        get_node_info(sbi, dn.nid, &ni);
        f2fs_bug_on(ni.ino != ino_of_node(page));
@@ -437,7 +434,7 @@ int recover_fsync_data(struct f2fs_sb_info *sbi)
        bool need_writecp = false;
 
        fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry",
-                       sizeof(struct fsync_inode_entry), NULL);
+                       sizeof(struct fsync_inode_entry));
        if (!fsync_entry_slab)
                return -ENOMEM;
 
index 7caac5f..085f548 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/bio.h>
 #include <linux/blkdev.h>
 #include <linux/prefetch.h>
+#include <linux/kthread.h>
 #include <linux/vmalloc.h>
 #include <linux/swap.h>
 
@@ -24,6 +25,7 @@
 #define __reverse_ffz(x) __reverse_ffs(~(x))
 
 static struct kmem_cache *discard_entry_slab;
+static struct kmem_cache *flush_cmd_slab;
 
 /*
  * __reverse_ffs is copied from include/asm-generic/bitops/__ffs.h since
@@ -195,6 +197,73 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
                f2fs_sync_fs(sbi->sb, true);
 }
 
+static int issue_flush_thread(void *data)
+{
+       struct f2fs_sb_info *sbi = data;
+       struct f2fs_sm_info *sm_i = SM_I(sbi);
+       wait_queue_head_t *q = &sm_i->flush_wait_queue;
+repeat:
+       if (kthread_should_stop())
+               return 0;
+
+       spin_lock(&sm_i->issue_lock);
+       if (sm_i->issue_list) {
+               sm_i->dispatch_list = sm_i->issue_list;
+               sm_i->issue_list = sm_i->issue_tail = NULL;
+       }
+       spin_unlock(&sm_i->issue_lock);
+
+       if (sm_i->dispatch_list) {
+               struct bio *bio = bio_alloc(GFP_NOIO, 0);
+               struct flush_cmd *cmd, *next;
+               int ret;
+
+               bio->bi_bdev = sbi->sb->s_bdev;
+               ret = submit_bio_wait(WRITE_FLUSH, bio);
+
+               for (cmd = sm_i->dispatch_list; cmd; cmd = next) {
+                       cmd->ret = ret;
+                       next = cmd->next;
+                       complete(&cmd->wait);
+               }
+               sm_i->dispatch_list = NULL;
+       }
+
+       wait_event_interruptible(*q, kthread_should_stop() || sm_i->issue_list);
+       goto repeat;
+}
+
+int f2fs_issue_flush(struct f2fs_sb_info *sbi)
+{
+       struct f2fs_sm_info *sm_i = SM_I(sbi);
+       struct flush_cmd *cmd;
+       int ret;
+
+       if (!test_opt(sbi, FLUSH_MERGE))
+               return blkdev_issue_flush(sbi->sb->s_bdev, GFP_KERNEL, NULL);
+
+       cmd = f2fs_kmem_cache_alloc(flush_cmd_slab, GFP_ATOMIC);
+       cmd->next = NULL;
+       cmd->ret = 0;
+       init_completion(&cmd->wait);
+
+       spin_lock(&sm_i->issue_lock);
+       if (sm_i->issue_list)
+               sm_i->issue_tail->next = cmd;
+       else
+               sm_i->issue_list = cmd;
+       sm_i->issue_tail = cmd;
+       spin_unlock(&sm_i->issue_lock);
+
+       if (!sm_i->dispatch_list)
+               wake_up(&sm_i->flush_wait_queue);
+
+       wait_for_completion(&cmd->wait);
+       ret = cmd->ret;
+       kmem_cache_free(flush_cmd_slab, cmd);
+       return ret;
+}
+
 static void __locate_dirty_segment(struct f2fs_sb_info *sbi, unsigned int segno,
                enum dirty_type dirty_type)
 {
@@ -340,8 +409,7 @@ static void set_prefree_as_free_segments(struct f2fs_sb_info *sbi)
 void clear_prefree_segments(struct f2fs_sb_info *sbi)
 {
        struct list_head *head = &(SM_I(sbi)->discard_list);
-       struct list_head *this, *next;
-       struct discard_entry *entry;
+       struct discard_entry *entry, *this;
        struct dirty_seglist_info *dirty_i = DIRTY_I(sbi);
        unsigned long *prefree_map = dirty_i->dirty_segmap[PRE];
        unsigned int total_segs = TOTAL_SEGS(sbi);
@@ -370,8 +438,7 @@ void clear_prefree_segments(struct f2fs_sb_info *sbi)
        mutex_unlock(&dirty_i->seglist_lock);
 
        /* send small discards */
-       list_for_each_safe(this, next, head) {
-               entry = list_entry(this, struct discard_entry, list);
+       list_for_each_entry_safe(entry, this, head, list) {
                f2fs_issue_discard(sbi, entry->blkaddr, entry->len);
                list_del(&entry->list);
                SM_I(sbi)->nr_discards -= entry->len;
@@ -405,7 +472,7 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
 
        se = get_seg_entry(sbi, segno);
        new_vblocks = se->valid_blocks + del;
-       offset = GET_SEGOFF_FROM_SEG0(sbi, blkaddr) & (sbi->blocks_per_seg - 1);
+       offset = GET_BLKOFF_FROM_SEG0(sbi, blkaddr);
 
        f2fs_bug_on((new_vblocks >> (sizeof(unsigned short) << 3) ||
                                (new_vblocks > sbi->blocks_per_seg)));
@@ -434,12 +501,14 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
                get_sec_entry(sbi, segno)->valid_blocks += del;
 }
 
-static void refresh_sit_entry(struct f2fs_sb_info *sbi,
-                       block_t old_blkaddr, block_t new_blkaddr)
+void refresh_sit_entry(struct f2fs_sb_info *sbi, block_t old, block_t new)
 {
-       update_sit_entry(sbi, new_blkaddr, 1);
-       if (GET_SEGNO(sbi, old_blkaddr) != NULL_SEGNO)
-               update_sit_entry(sbi, old_blkaddr, -1);
+       update_sit_entry(sbi, new, 1);
+       if (GET_SEGNO(sbi, old) != NULL_SEGNO)
+               update_sit_entry(sbi, old, -1);
+
+       locate_dirty_segment(sbi, GET_SEGNO(sbi, old));
+       locate_dirty_segment(sbi, GET_SEGNO(sbi, new));
 }
 
 void invalidate_blocks(struct f2fs_sb_info *sbi, block_t addr)
@@ -881,17 +950,15 @@ void allocate_data_block(struct f2fs_sb_info *sbi, struct page *page,
 
        stat_inc_block_count(sbi, curseg);
 
+       if (!__has_curseg_space(sbi, type))
+               sit_i->s_ops->allocate_segment(sbi, type, false);
        /*
         * SIT information should be updated before segment allocation,
         * since SSR needs latest valid block information.
         */
        refresh_sit_entry(sbi, old_blkaddr, *new_blkaddr);
-
-       if (!__has_curseg_space(sbi, type))
-               sit_i->s_ops->allocate_segment(sbi, type, false);
-
        locate_dirty_segment(sbi, old_cursegno);
-       locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
+
        mutex_unlock(&sit_i->sentry_lock);
 
        if (page && IS_NODESEG(type))
@@ -987,14 +1054,11 @@ void recover_data_page(struct f2fs_sb_info *sbi,
                change_curseg(sbi, type, true);
        }
 
-       curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) &
-                                       (sbi->blocks_per_seg - 1);
+       curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
        __add_sum_entry(sbi, type, sum);
 
        refresh_sit_entry(sbi, old_blkaddr, new_blkaddr);
-
        locate_dirty_segment(sbi, old_cursegno);
-       locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
 
        mutex_unlock(&sit_i->sentry_lock);
        mutex_unlock(&curseg->curseg_mutex);
@@ -1028,8 +1092,7 @@ void rewrite_node_page(struct f2fs_sb_info *sbi,
                curseg->next_segno = segno;
                change_curseg(sbi, type, true);
        }
-       curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, new_blkaddr) &
-                                       (sbi->blocks_per_seg - 1);
+       curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, new_blkaddr);
        __add_sum_entry(sbi, type, sum);
 
        /* change the current log to the next block addr in advance */
@@ -1037,28 +1100,50 @@ void rewrite_node_page(struct f2fs_sb_info *sbi,
                curseg->next_segno = next_segno;
                change_curseg(sbi, type, true);
        }
-       curseg->next_blkoff = GET_SEGOFF_FROM_SEG0(sbi, next_blkaddr) &
-                                       (sbi->blocks_per_seg - 1);
+       curseg->next_blkoff = GET_BLKOFF_FROM_SEG0(sbi, next_blkaddr);
 
        /* rewrite node page */
        set_page_writeback(page);
        f2fs_submit_page_mbio(sbi, page, new_blkaddr, &fio);
        f2fs_submit_merged_bio(sbi, NODE, WRITE);
        refresh_sit_entry(sbi, old_blkaddr, new_blkaddr);
-
        locate_dirty_segment(sbi, old_cursegno);
-       locate_dirty_segment(sbi, GET_SEGNO(sbi, old_blkaddr));
 
        mutex_unlock(&sit_i->sentry_lock);
        mutex_unlock(&curseg->curseg_mutex);
 }
 
+static inline bool is_merged_page(struct f2fs_sb_info *sbi,
+                                       struct page *page, enum page_type type)
+{
+       enum page_type btype = PAGE_TYPE_OF_BIO(type);
+       struct f2fs_bio_info *io = &sbi->write_io[btype];
+       struct bio_vec *bvec;
+       int i;
+
+       down_read(&io->io_rwsem);
+       if (!io->bio)
+               goto out;
+
+       bio_for_each_segment_all(bvec, io->bio, i) {
+               if (page == bvec->bv_page) {
+                       up_read(&io->io_rwsem);
+                       return true;
+               }
+       }
+
+out:
+       up_read(&io->io_rwsem);
+       return false;
+}
+
 void f2fs_wait_on_page_writeback(struct page *page,
                                enum page_type type)
 {
        struct f2fs_sb_info *sbi = F2FS_SB(page->mapping->host->i_sb);
        if (PageWriteback(page)) {
-               f2fs_submit_merged_bio(sbi, type, WRITE);
+               if (is_merged_page(sbi, page, type))
+                       f2fs_submit_merged_bio(sbi, type, WRITE);
                wait_on_page_writeback(page);
        }
 }
@@ -1167,9 +1252,12 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
                                ns->ofs_in_node = 0;
                        }
                } else {
-                       if (restore_node_summary(sbi, segno, sum)) {
+                       int err;
+
+                       err = restore_node_summary(sbi, segno, sum);
+                       if (err) {
                                f2fs_put_page(new, 1);
-                               return -EINVAL;
+                               return err;
                        }
                }
        }
@@ -1190,6 +1278,7 @@ static int read_normal_summaries(struct f2fs_sb_info *sbi, int type)
 static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
 {
        int type = CURSEG_HOT_DATA;
+       int err;
 
        if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_COMPACT_SUM_FLAG)) {
                /* restore for compacted data summary */
@@ -1198,9 +1287,12 @@ static int restore_curseg_summaries(struct f2fs_sb_info *sbi)
                type = CURSEG_HOT_NODE;
        }
 
-       for (; type <= CURSEG_COLD_NODE; type++)
-               if (read_normal_summaries(sbi, type))
-                       return -EINVAL;
+       for (; type <= CURSEG_COLD_NODE; type++) {
+               err = read_normal_summaries(sbi, type);
+               if (err)
+                       return err;
+       }
+
        return 0;
 }
 
@@ -1583,47 +1675,6 @@ static int build_curseg(struct f2fs_sb_info *sbi)
        return restore_curseg_summaries(sbi);
 }
 
-static int ra_sit_pages(struct f2fs_sb_info *sbi, int start, int nrpages)
-{
-       struct address_space *mapping = META_MAPPING(sbi);
-       struct page *page;
-       block_t blk_addr, prev_blk_addr = 0;
-       int sit_blk_cnt = SIT_BLK_CNT(sbi);
-       int blkno = start;
-       struct f2fs_io_info fio = {
-               .type = META,
-               .rw = READ_SYNC | REQ_META | REQ_PRIO
-       };
-
-       for (; blkno < start + nrpages && blkno < sit_blk_cnt; blkno++) {
-
-               blk_addr = current_sit_addr(sbi, blkno * SIT_ENTRY_PER_BLOCK);
-
-               if (blkno != start && prev_blk_addr + 1 != blk_addr)
-                       break;
-               prev_blk_addr = blk_addr;
-repeat:
-               page = grab_cache_page(mapping, blk_addr);
-               if (!page) {
-                       cond_resched();
-                       goto repeat;
-               }
-               if (PageUptodate(page)) {
-                       mark_page_accessed(page);
-                       f2fs_put_page(page, 1);
-                       continue;
-               }
-
-               f2fs_submit_page_mbio(sbi, page, blk_addr, &fio);
-
-               mark_page_accessed(page);
-               f2fs_put_page(page, 0);
-       }
-
-       f2fs_submit_merged_bio(sbi, META, READ);
-       return blkno - start;
-}
-
 static void build_sit_entries(struct f2fs_sb_info *sbi)
 {
        struct sit_info *sit_i = SIT_I(sbi);
@@ -1635,7 +1686,7 @@ static void build_sit_entries(struct f2fs_sb_info *sbi)
        int nrpages = MAX_BIO_BLOCKS(max_hw_blocks(sbi));
 
        do {
-               readed = ra_sit_pages(sbi, start_blk, nrpages);
+               readed = ra_meta_pages(sbi, start_blk, nrpages, META_SIT);
 
                start = start_blk * sit_i->sents_per_block;
                end = (start_blk + readed) * sit_i->sents_per_block;
@@ -1781,6 +1832,7 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
 {
        struct f2fs_super_block *raw_super = F2FS_RAW_SUPER(sbi);
        struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
+       dev_t dev = sbi->sb->s_bdev->bd_dev;
        struct f2fs_sm_info *sm_info;
        int err;
 
@@ -1799,7 +1851,8 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
        sm_info->ovp_segments = le32_to_cpu(ckpt->overprov_segment_count);
        sm_info->main_segments = le32_to_cpu(raw_super->segment_count_main);
        sm_info->ssa_blkaddr = le32_to_cpu(raw_super->ssa_blkaddr);
-       sm_info->rec_prefree_segments = DEF_RECLAIM_PREFREE_SEGMENTS;
+       sm_info->rec_prefree_segments = sm_info->main_segments *
+                                       DEF_RECLAIM_PREFREE_SEGMENTS / 100;
        sm_info->ipu_policy = F2FS_IPU_DISABLE;
        sm_info->min_ipu_util = DEF_MIN_IPU_UTIL;
 
@@ -1807,6 +1860,16 @@ int build_segment_manager(struct f2fs_sb_info *sbi)
        sm_info->nr_discards = 0;
        sm_info->max_discards = 0;
 
+       if (test_opt(sbi, FLUSH_MERGE)) {
+               spin_lock_init(&sm_info->issue_lock);
+               init_waitqueue_head(&sm_info->flush_wait_queue);
+
+               sm_info->f2fs_issue_flush = kthread_run(issue_flush_thread, sbi,
+                               "f2fs_flush-%u:%u", MAJOR(dev), MINOR(dev));
+               if (IS_ERR(sm_info->f2fs_issue_flush))
+                       return PTR_ERR(sm_info->f2fs_issue_flush);
+       }
+
        err = build_sit_info(sbi);
        if (err)
                return err;
@@ -1915,6 +1978,8 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi)
        struct f2fs_sm_info *sm_info = SM_I(sbi);
        if (!sm_info)
                return;
+       if (sm_info->f2fs_issue_flush)
+               kthread_stop(sm_info->f2fs_issue_flush);
        destroy_dirty_segmap(sbi);
        destroy_curseg(sbi);
        destroy_free_segmap(sbi);
@@ -1926,13 +1991,20 @@ void destroy_segment_manager(struct f2fs_sb_info *sbi)
 int __init create_segment_manager_caches(void)
 {
        discard_entry_slab = f2fs_kmem_cache_create("discard_entry",
-                       sizeof(struct discard_entry), NULL);
+                       sizeof(struct discard_entry));
        if (!discard_entry_slab)
                return -ENOMEM;
+       flush_cmd_slab = f2fs_kmem_cache_create("flush_command",
+                       sizeof(struct flush_cmd));
+       if (!flush_cmd_slab) {
+               kmem_cache_destroy(discard_entry_slab);
+               return -ENOMEM;
+       }
        return 0;
 }
 
 void destroy_segment_manager_caches(void)
 {
        kmem_cache_destroy(discard_entry_slab);
+       kmem_cache_destroy(flush_cmd_slab);
 }
index 5731682..7091204 100644 (file)
@@ -14,7 +14,7 @@
 #define NULL_SEGNO                     ((unsigned int)(~0))
 #define NULL_SECNO                     ((unsigned int)(~0))
 
-#define DEF_RECLAIM_PREFREE_SEGMENTS   100     /* 200MB of prefree segments */
+#define DEF_RECLAIM_PREFREE_SEGMENTS   5       /* 5% over total segments */
 
 /* L: Logical segment # in volume, R: Relative segment # in main area */
 #define GET_L2R_SEGNO(free_i, segno)   (segno - free_i->start_segno)
@@ -57,6 +57,9 @@
        ((blk_addr) - SM_I(sbi)->seg0_blkaddr)
 #define GET_SEGNO_FROM_SEG0(sbi, blk_addr)                             \
        (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) >> sbi->log_blocks_per_seg)
+#define GET_BLKOFF_FROM_SEG0(sbi, blk_addr)                            \
+       (GET_SEGOFF_FROM_SEG0(sbi, blk_addr) & (sbi->blocks_per_seg - 1))
+
 #define GET_SEGNO(sbi, blk_addr)                                       \
        (((blk_addr == NULL_ADDR) || (blk_addr == NEW_ADDR)) ?          \
        NULL_SEGNO : GET_L2R_SEGNO(FREE_I(sbi),                 \
@@ -377,26 +380,12 @@ static inline void get_sit_bitmap(struct f2fs_sb_info *sbi,
 
 static inline block_t written_block_count(struct f2fs_sb_info *sbi)
 {
-       struct sit_info *sit_i = SIT_I(sbi);
-       block_t vblocks;
-
-       mutex_lock(&sit_i->sentry_lock);
-       vblocks = sit_i->written_valid_blocks;
-       mutex_unlock(&sit_i->sentry_lock);
-
-       return vblocks;
+       return SIT_I(sbi)->written_valid_blocks;
 }
 
 static inline unsigned int free_segments(struct f2fs_sb_info *sbi)
 {
-       struct free_segmap_info *free_i = FREE_I(sbi);
-       unsigned int free_segs;
-
-       read_lock(&free_i->segmap_lock);
-       free_segs = free_i->free_segments;
-       read_unlock(&free_i->segmap_lock);
-
-       return free_segs;
+       return FREE_I(sbi)->free_segments;
 }
 
 static inline int reserved_segments(struct f2fs_sb_info *sbi)
@@ -406,14 +395,7 @@ static inline int reserved_segments(struct f2fs_sb_info *sbi)
 
 static inline unsigned int free_sections(struct f2fs_sb_info *sbi)
 {
-       struct free_segmap_info *free_i = FREE_I(sbi);
-       unsigned int free_secs;
-
-       read_lock(&free_i->segmap_lock);
-       free_secs = free_i->free_sections;
-       read_unlock(&free_i->segmap_lock);
-
-       return free_secs;
+       return FREE_I(sbi)->free_sections;
 }
 
 static inline unsigned int prefree_segments(struct f2fs_sb_info *sbi)
@@ -682,3 +664,46 @@ static inline unsigned int max_hw_blocks(struct f2fs_sb_info *sbi)
        struct request_queue *q = bdev_get_queue(bdev);
        return SECTOR_TO_BLOCK(sbi, queue_max_sectors(q));
 }
+
+/*
+ * It is very important to gather dirty pages and write at once, so that we can
+ * submit a big bio without interfering other data writes.
+ * By default, 512 pages for directory data,
+ * 512 pages (2MB) * 3 for three types of nodes, and
+ * max_bio_blocks for meta are set.
+ */
+static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type)
+{
+       if (type == DATA)
+               return sbi->blocks_per_seg;
+       else if (type == NODE)
+               return 3 * sbi->blocks_per_seg;
+       else if (type == META)
+               return MAX_BIO_BLOCKS(max_hw_blocks(sbi));
+       else
+               return 0;
+}
+
+/*
+ * When writing pages, it'd better align nr_to_write for segment size.
+ */
+static inline long nr_pages_to_write(struct f2fs_sb_info *sbi, int type,
+                                       struct writeback_control *wbc)
+{
+       long nr_to_write, desired;
+
+       if (wbc->sync_mode != WB_SYNC_NONE)
+               return 0;
+
+       nr_to_write = wbc->nr_to_write;
+
+       if (type == DATA)
+               desired = 4096;
+       else if (type == NODE)
+               desired = 3 * max_hw_blocks(sbi);
+       else
+               desired = MAX_BIO_BLOCKS(max_hw_blocks(sbi));
+
+       wbc->nr_to_write = desired;
+       return desired - nr_to_write;
+}
index 856bdf9..c756923 100644 (file)
@@ -51,6 +51,7 @@ enum {
        Opt_disable_ext_identify,
        Opt_inline_xattr,
        Opt_inline_data,
+       Opt_flush_merge,
        Opt_err,
 };
 
@@ -67,6 +68,7 @@ static match_table_t f2fs_tokens = {
        {Opt_disable_ext_identify, "disable_ext_identify"},
        {Opt_inline_xattr, "inline_xattr"},
        {Opt_inline_data, "inline_data"},
+       {Opt_flush_merge, "flush_merge"},
        {Opt_err, NULL},
 };
 
@@ -74,6 +76,7 @@ static match_table_t f2fs_tokens = {
 enum {
        GC_THREAD,      /* struct f2fs_gc_thread */
        SM_INFO,        /* struct f2fs_sm_info */
+       NM_INFO,        /* struct f2fs_nm_info */
        F2FS_SBI,       /* struct f2fs_sb_info */
 };
 
@@ -92,6 +95,8 @@ static unsigned char *__struct_ptr(struct f2fs_sb_info *sbi, int struct_type)
                return (unsigned char *)sbi->gc_thread;
        else if (struct_type == SM_INFO)
                return (unsigned char *)SM_I(sbi);
+       else if (struct_type == NM_INFO)
+               return (unsigned char *)NM_I(sbi);
        else if (struct_type == F2FS_SBI)
                return (unsigned char *)sbi;
        return NULL;
@@ -183,7 +188,9 @@ F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, reclaim_segments, rec_prefree_segments);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, max_small_discards, max_discards);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, ipu_policy, ipu_policy);
 F2FS_RW_ATTR(SM_INFO, f2fs_sm_info, min_ipu_util, min_ipu_util);
+F2FS_RW_ATTR(NM_INFO, f2fs_nm_info, ram_thresh, ram_thresh);
 F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, max_victim_search, max_victim_search);
+F2FS_RW_ATTR(F2FS_SBI, f2fs_sb_info, dir_level, dir_level);
 
 #define ATTR_LIST(name) (&f2fs_attr_##name.attr)
 static struct attribute *f2fs_attrs[] = {
@@ -196,6 +203,8 @@ static struct attribute *f2fs_attrs[] = {
        ATTR_LIST(ipu_policy),
        ATTR_LIST(min_ipu_util),
        ATTR_LIST(max_victim_search),
+       ATTR_LIST(dir_level),
+       ATTR_LIST(ram_thresh),
        NULL,
 };
 
@@ -256,9 +265,9 @@ static int parse_options(struct super_block *sb, char *options)
 
                        if (!name)
                                return -ENOMEM;
-                       if (!strncmp(name, "on", 2))
+                       if (strlen(name) == 2 && !strncmp(name, "on", 2))
                                set_opt(sbi, BG_GC);
-                       else if (!strncmp(name, "off", 3))
+                       else if (strlen(name) == 3 && !strncmp(name, "off", 3))
                                clear_opt(sbi, BG_GC);
                        else {
                                kfree(name);
@@ -327,6 +336,9 @@ static int parse_options(struct super_block *sb, char *options)
                case Opt_inline_data:
                        set_opt(sbi, INLINE_DATA);
                        break;
+               case Opt_flush_merge:
+                       set_opt(sbi, FLUSH_MERGE);
+                       break;
                default:
                        f2fs_msg(sb, KERN_ERR,
                                "Unrecognized mount option \"%s\" or missing value",
@@ -353,12 +365,16 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
        fi->i_current_depth = 1;
        fi->i_advise = 0;
        rwlock_init(&fi->ext.ext_lock);
+       init_rwsem(&fi->i_sem);
 
        set_inode_flag(fi, FI_NEW_INODE);
 
        if (test_opt(F2FS_SB(sb), INLINE_XATTR))
                set_inode_flag(fi, FI_INLINE_XATTR);
 
+       /* Will be used by directory only */
+       fi->i_dir_level = F2FS_SB(sb)->dir_level;
+
        return &fi->vfs_inode;
 }
 
@@ -526,6 +542,8 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
                seq_puts(seq, ",disable_ext_identify");
        if (test_opt(sbi, INLINE_DATA))
                seq_puts(seq, ",inline_data");
+       if (test_opt(sbi, FLUSH_MERGE))
+               seq_puts(seq, ",flush_merge");
        seq_printf(seq, ",active_logs=%u", sbi->active_logs);
 
        return 0;
@@ -539,13 +557,22 @@ static int segment_info_seq_show(struct seq_file *seq, void *offset)
                        le32_to_cpu(sbi->raw_super->segment_count_main);
        int i;
 
+       seq_puts(seq, "format: segment_type|valid_blocks\n"
+               "segment_type(0:HD, 1:WD, 2:CD, 3:HN, 4:WN, 5:CN)\n");
+
        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");
+               struct seg_entry *se = get_seg_entry(sbi, i);
+
+               if ((i % 10) == 0)
+                       seq_printf(seq, "%-5d", i);
+               seq_printf(seq, "%d|%-3u", se->type,
+                                       get_valid_blocks(sbi, i, 1));
+               if ((i % 10) == 9 || i == (total_segs - 1))
+                       seq_putc(seq, '\n');
                else
-                       seq_puts(seq, " ");
+                       seq_putc(seq, ' ');
        }
+
        return 0;
 }
 
@@ -640,6 +667,8 @@ static struct inode *f2fs_nfs_get_inode(struct super_block *sb,
 
        if (unlikely(ino < F2FS_ROOT_INO(sbi)))
                return ERR_PTR(-ESTALE);
+       if (unlikely(ino >= NM_I(sbi)->max_nid))
+               return ERR_PTR(-ESTALE);
 
        /*
         * f2fs_iget isn't quite right if the inode is currently unallocated!
@@ -787,6 +816,8 @@ static void init_sb_info(struct f2fs_sb_info *sbi)
 
        for (i = 0; i < NR_COUNT_TYPE; i++)
                atomic_set(&sbi->nr_pages[i], 0);
+
+       sbi->dir_level = DEF_DIR_LEVEL;
 }
 
 /*
@@ -898,11 +929,11 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        sbi->por_doing = false;
        spin_lock_init(&sbi->stat_lock);
 
-       mutex_init(&sbi->read_io.io_mutex);
+       init_rwsem(&sbi->read_io.io_rwsem);
        sbi->read_io.sbi = sbi;
        sbi->read_io.bio = NULL;
        for (i = 0; i < NR_PAGE_TYPE; i++) {
-               mutex_init(&sbi->write_io[i].io_mutex);
+               init_rwsem(&sbi->write_io[i].io_rwsem);
                sbi->write_io[i].sbi = sbi;
                sbi->write_io[i].bio = NULL;
        }
@@ -991,28 +1022,9 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
                goto free_root_inode;
        }
 
-       /* recover fsynced data */
-       if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
-               err = recover_fsync_data(sbi);
-               if (err)
-                       f2fs_msg(sb, KERN_ERR,
-                               "Cannot recover all fsync data errno=%ld", err);
-       }
-
-       /*
-        * If filesystem is not mounted as read-only then
-        * do start the gc_thread.
-        */
-       if (!(sb->s_flags & MS_RDONLY)) {
-               /* After POR, we can run background GC thread.*/
-               err = start_gc_thread(sbi);
-               if (err)
-                       goto free_gc;
-       }
-
        err = f2fs_build_stats(sbi);
        if (err)
-               goto free_gc;
+               goto free_root_inode;
 
        if (f2fs_proc_root)
                sbi->s_proc = proc_mkdir(sb->s_id, f2fs_proc_root);
@@ -1034,17 +1046,36 @@ static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
        err = kobject_init_and_add(&sbi->s_kobj, &f2fs_ktype, NULL,
                                                        "%s", sb->s_id);
        if (err)
-               goto fail;
+               goto free_proc;
+
+       /* recover fsynced data */
+       if (!test_opt(sbi, DISABLE_ROLL_FORWARD)) {
+               err = recover_fsync_data(sbi);
+               if (err)
+                       f2fs_msg(sb, KERN_ERR,
+                               "Cannot recover all fsync data errno=%ld", err);
+       }
 
+       /*
+        * If filesystem is not mounted as read-only then
+        * do start the gc_thread.
+        */
+       if (!(sb->s_flags & MS_RDONLY)) {
+               /* After POR, we can run background GC thread.*/
+               err = start_gc_thread(sbi);
+               if (err)
+                       goto free_kobj;
+       }
        return 0;
-fail:
+
+free_kobj:
+       kobject_del(&sbi->s_kobj);
+free_proc:
        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);
-free_gc:
-       stop_gc_thread(sbi);
 free_root_inode:
        dput(sb->s_root);
        sb->s_root = NULL;
@@ -1084,7 +1115,7 @@ MODULE_ALIAS_FS("f2fs");
 static int __init init_inodecache(void)
 {
        f2fs_inode_cachep = f2fs_kmem_cache_create("f2fs_inode_cache",
-                       sizeof(struct f2fs_inode_info), NULL);
+                       sizeof(struct f2fs_inode_info));
        if (!f2fs_inode_cachep)
                return -ENOMEM;
        return 0;
index 89d0422..503c245 100644 (file)
@@ -275,7 +275,7 @@ static void *read_all_xattrs(struct inode *inode, struct page *ipage)
 
        inline_size = inline_xattr_size(inode);
 
-       txattr_addr = kzalloc(inline_size + size, GFP_KERNEL);
+       txattr_addr = kzalloc(inline_size + size, GFP_F2FS_ZERO);
        if (!txattr_addr)
                return NULL;
 
@@ -407,6 +407,8 @@ int f2fs_getxattr(struct inode *inode, int name_index, const char *name,
        if (name == NULL)
                return -EINVAL;
        name_len = strlen(name);
+       if (name_len > F2FS_NAME_LEN)
+               return -ERANGE;
 
        base_addr = read_all_xattrs(inode, NULL);
        if (!base_addr)
@@ -590,7 +592,10 @@ int f2fs_setxattr(struct inode *inode, int name_index, const char *name,
        f2fs_balance_fs(sbi);
 
        f2fs_lock_op(sbi);
+       /* protect xattr_ver */
+       down_write(&F2FS_I(inode)->i_sem);
        err = __f2fs_setxattr(inode, name_index, name, value, value_len, ipage);
+       up_write(&F2FS_I(inode)->i_sem);
        f2fs_unlock_op(sbi);
 
        return err;
index 23e363f..13b691a 100644 (file)
@@ -569,7 +569,7 @@ static ssize_t cuse_class_waiting_show(struct device *dev,
 
        return sprintf(buf, "%d\n", atomic_read(&cc->fc.num_waiting));
 }
-static DEVICE_ATTR(waiting, S_IFREG | 0400, cuse_class_waiting_show, NULL);
+static DEVICE_ATTR(waiting, 0400, cuse_class_waiting_show, NULL);
 
 static ssize_t cuse_class_abort_store(struct device *dev,
                                      struct device_attribute *attr,
@@ -580,7 +580,7 @@ static ssize_t cuse_class_abort_store(struct device *dev,
        fuse_abort_conn(&cc->fc);
        return count;
 }
-static DEVICE_ATTR(abort, S_IFREG | 0200, NULL, cuse_class_abort_store);
+static DEVICE_ATTR(abort, 0200, NULL, cuse_class_abort_store);
 
 static struct attribute *cuse_class_dev_attrs[] = {
        &dev_attr_waiting.attr,
index 65df7d8..48992ca 100644 (file)
@@ -2117,6 +2117,7 @@ static int fuse_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 static const struct vm_operations_struct fuse_file_vm_ops = {
        .close          = fuse_vma_close,
        .fault          = filemap_fault,
+       .map_pages      = filemap_map_pages,
        .page_mkwrite   = fuse_page_mkwrite,
        .remap_pages    = generic_file_remap_pages,
 };
index 6c79408..80d6725 100644 (file)
@@ -494,6 +494,7 @@ out:
 
 static const struct vm_operations_struct gfs2_vm_ops = {
        .fault = filemap_fault,
+       .map_pages = filemap_map_pages,
        .page_mkwrite = gfs2_page_mkwrite,
        .remap_pages = generic_file_remap_pages,
 };
index 6af66ee..4556ce1 100644 (file)
@@ -93,7 +93,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        isofs_inode_cachep = kmem_cache_create("isofs_inode_cache",
                                        sizeof(struct iso_inode_info),
index 16a5047..406d9cc 100644 (file)
@@ -33,7 +33,7 @@ static int jffs2_rtime_compress(unsigned char *data_in,
                                unsigned char *cpage_out,
                                uint32_t *sourcelen, uint32_t *dstlen)
 {
-       short positions[256];
+       unsigned short positions[256];
        int outpos = 0;
        int pos=0;
 
@@ -74,7 +74,7 @@ static int jffs2_rtime_decompress(unsigned char *data_in,
                                  unsigned char *cpage_out,
                                  uint32_t srclen, uint32_t destlen)
 {
-       short positions[256];
+       unsigned short positions[256];
        int outpos = 0;
        int pos=0;
 
index f739915..601afd1 100644 (file)
@@ -457,12 +457,14 @@ struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_r
           The umask is only applied if there's no default ACL */
        ret = jffs2_init_acl_pre(dir_i, inode, &mode);
        if (ret) {
-           make_bad_inode(inode);
-           iput(inode);
-           return ERR_PTR(ret);
+               mutex_unlock(&f->sem);
+               make_bad_inode(inode);
+               iput(inode);
+               return ERR_PTR(ret);
        }
        ret = jffs2_do_new_inode (c, f, mode, ri);
        if (ret) {
+               mutex_unlock(&f->sem);
                make_bad_inode(inode);
                iput(inode);
                return ERR_PTR(ret);
@@ -479,6 +481,7 @@ struct inode *jffs2_new_inode (struct inode *dir_i, umode_t mode, struct jffs2_r
        inode->i_size = 0;
 
        if (insert_inode_locked(inode) < 0) {
+               mutex_unlock(&f->sem);
                make_bad_inode(inode);
                iput(inode);
                return ERR_PTR(-EINVAL);
index e4619b0..fa35ff7 100644 (file)
@@ -231,7 +231,7 @@ struct jffs2_tmp_dnode_info
        uint32_t version;
        uint32_t data_crc;
        uint32_t partial_crc;
-       uint16_t csize;
+       uint32_t csize;
        uint16_t overlapped;
 };
 
index 0331072..b6bd4af 100644 (file)
@@ -179,6 +179,7 @@ int jffs2_reserve_space(struct jffs2_sb_info *c, uint32_t minsize,
                                        spin_unlock(&c->erase_completion_lock);
 
                                        schedule();
+                                       remove_wait_queue(&c->erase_wait, &wait);
                                } else
                                        spin_unlock(&c->erase_completion_lock);
                        } else if (ret)
@@ -211,20 +212,25 @@ out:
 int jffs2_reserve_space_gc(struct jffs2_sb_info *c, uint32_t minsize,
                           uint32_t *len, uint32_t sumsize)
 {
-       int ret = -EAGAIN;
+       int ret;
        minsize = PAD(minsize);
 
        jffs2_dbg(1, "%s(): Requested 0x%x bytes\n", __func__, minsize);
 
-       spin_lock(&c->erase_completion_lock);
-       while(ret == -EAGAIN) {
+       while (true) {
+               spin_lock(&c->erase_completion_lock);
                ret = jffs2_do_reserve_space(c, minsize, len, sumsize);
                if (ret) {
                        jffs2_dbg(1, "%s(): looping, ret is %d\n",
                                  __func__, ret);
                }
+               spin_unlock(&c->erase_completion_lock);
+
+               if (ret == -EAGAIN)
+                       cond_resched();
+               else
+                       break;
        }
-       spin_unlock(&c->erase_completion_lock);
        if (!ret)
                ret = jffs2_prealloc_raw_node_refs(c, c->nextblock, 1);
 
index 10d6c41..6bf06a0 100644 (file)
@@ -235,6 +235,7 @@ out_err:
        if (warned++ == 0)
                printk(KERN_WARNING
                        "lockd_up: makesock failed, error=%d\n", err);
+       svc_shutdown_net(serv, net);
        return err;
 }
 
index c320ac5..08b8ea8 100644 (file)
@@ -339,7 +339,7 @@ ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
        if (val)
                goto finished;
 
-       DDPRINTK("ncp_lookup_validate: %pd2 not valid, age=%ld, server lookup\n",
+       ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n",
                dentry, NCP_GET_AGE(dentry));
 
        len = sizeof(__name);
@@ -358,7 +358,7 @@ ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
                        res = ncp_obtain_info(server, dir, __name, &(finfo.i));
        }
        finfo.volume = finfo.i.volNumber;
-       DDPRINTK("ncp_lookup_validate: looked for %pd/%s, res=%d\n",
+       ncp_dbg(2, "looked for %pd/%s, res=%d\n",
                dentry->d_parent, __name, res);
        /*
         * If we didn't find it, or if it has a different dirEntNum to
@@ -372,14 +372,14 @@ ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
                        ncp_new_dentry(dentry);
                        val=1;
                } else
-                       DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n");
+                       ncp_dbg(2, "found, but dirEntNum changed\n");
 
                ncp_update_inode2(inode, &finfo);
                mutex_unlock(&inode->i_mutex);
        }
 
 finished:
-       DDPRINTK("ncp_lookup_validate: result=%d\n", val);
+       ncp_dbg(2, "result=%d\n", val);
        dput(parent);
        return val;
 }
@@ -453,8 +453,7 @@ static int ncp_readdir(struct file *file, struct dir_context *ctx)
        ctl.page  = NULL;
        ctl.cache = NULL;
 
-       DDPRINTK("ncp_readdir: reading %pD2, pos=%d\n", file,
-               (int) ctx->pos);
+       ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
 
        result = -EIO;
        /* Do not generate '.' and '..' when server is dead. */
@@ -697,8 +696,7 @@ ncp_read_volume_list(struct file *file, struct dir_context *ctx,
        struct ncp_entry_info entry;
        int i;
 
-       DPRINTK("ncp_read_volume_list: pos=%ld\n",
-                       (unsigned long) ctx->pos);
+       ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
 
        for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
                int inval_dentry;
@@ -708,12 +706,11 @@ ncp_read_volume_list(struct file *file, struct dir_context *ctx,
                if (!strlen(info.volume_name))
                        continue;
 
-               DPRINTK("ncp_read_volume_list: found vol: %s\n",
-                       info.volume_name);
+               ncp_dbg(1, "found vol: %s\n", info.volume_name);
 
                if (ncp_lookup_volume(server, info.volume_name,
                                        &entry.i)) {
-                       DPRINTK("ncpfs: could not lookup vol %s\n",
+                       ncp_dbg(1, "could not lookup vol %s\n",
                                info.volume_name);
                        continue;
                }
@@ -738,14 +735,13 @@ ncp_do_readdir(struct file *file, struct dir_context *ctx,
        int more;
        size_t bufsize;
 
-       DPRINTK("ncp_do_readdir: %pD2, fpos=%ld\n", file,
-               (unsigned long) ctx->pos);
-       PPRINTK("ncp_do_readdir: init %pD, volnum=%d, dirent=%u\n",
-               file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
+       ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
+       ncp_vdbg("init %pD, volnum=%d, dirent=%u\n",
+                file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
 
        err = ncp_initialize_search(server, dir, &seq);
        if (err) {
-               DPRINTK("ncp_do_readdir: init failed, err=%d\n", err);
+               ncp_dbg(1, "init failed, err=%d\n", err);
                return;
        }
        /* We MUST NOT use server->buffer_size handshaked with server if we are
@@ -808,8 +804,7 @@ int ncp_conn_logged_in(struct super_block *sb)
                        goto out;
                result = -ENOENT;
                if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
-                       PPRINTK("ncp_conn_logged_in: %s not found\n",
-                               server->m.mounted_vol);
+                       ncp_vdbg("%s not found\n", server->m.mounted_vol);
                        goto out;
                }
                dent = sb->s_root;
@@ -822,10 +817,10 @@ int ncp_conn_logged_in(struct super_block *sb)
                                NCP_FINFO(ino)->DosDirNum = DosDirNum;
                                result = 0;
                        } else {
-                               DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n");
+                               ncp_dbg(1, "sb->s_root->d_inode == NULL!\n");
                        }
                } else {
-                       DPRINTK("ncpfs: sb->s_root == NULL!\n");
+                       ncp_dbg(1, "sb->s_root == NULL!\n");
                }
        } else
                result = 0;
@@ -846,7 +841,7 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig
        if (!ncp_conn_valid(server))
                goto finished;
 
-       PPRINTK("ncp_lookup: server lookup for %pd2\n", dentry);
+       ncp_vdbg("server lookup for %pd2\n", dentry);
 
        len = sizeof(__name);
        if (ncp_is_server_root(dir)) {
@@ -854,15 +849,15 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsig
                                 dentry->d_name.len, 1);
                if (!res)
                        res = ncp_lookup_volume(server, __name, &(finfo.i));
-                       if (!res)
-                               ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
+               if (!res)
+                       ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
        } else {
                res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
                                 dentry->d_name.len, !ncp_preserve_case(dir));
                if (!res)
                        res = ncp_obtain_info(server, dir, __name, &(finfo.i));
        }
-       PPRINTK("ncp_lookup: looked for %pd2, res=%d\n", dentry, res);
+       ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
        /*
         * If we didn't find an entry, make a negative dentry.
         */
@@ -886,7 +881,7 @@ add_entry:
        }
 
 finished:
-       PPRINTK("ncp_lookup: result=%d\n", error);
+       ncp_vdbg("result=%d\n", error);
        return ERR_PTR(error);
 }
 
@@ -909,7 +904,7 @@ out:
        return error;
 
 out_close:
-       PPRINTK("ncp_instantiate: %pd2 failed, closing file\n", dentry);
+       ncp_vdbg("%pd2 failed, closing file\n", dentry);
        ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
        goto out;
 }
@@ -923,7 +918,7 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
        int opmode;
        __u8 __name[NCP_MAXPATHLEN + 1];
        
-       PPRINTK("ncp_create_new: creating %pd2, mode=%hx\n", dentry, mode);
+       ncp_vdbg("creating %pd2, mode=%hx\n", dentry, mode);
 
        ncp_age_dentry(server, dentry);
        len = sizeof(__name);
@@ -952,7 +947,7 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
                                error = -ENAMETOOLONG;
                        else if (result < 0)
                                error = result;
-                       DPRINTK("ncp_create: %pd2 failed\n", dentry);
+                       ncp_dbg(1, "%pd2 failed\n", dentry);
                        goto out;
                }
                opmode = O_WRONLY;
@@ -985,7 +980,7 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        int error, len;
        __u8 __name[NCP_MAXPATHLEN + 1];
 
-       DPRINTK("ncp_mkdir: making %pd2\n", dentry);
+       ncp_dbg(1, "making %pd2\n", dentry);
 
        ncp_age_dentry(server, dentry);
        len = sizeof(__name);
@@ -1022,7 +1017,7 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
        int error, result, len;
        __u8 __name[NCP_MAXPATHLEN + 1];
 
-       DPRINTK("ncp_rmdir: removing %pd2\n", dentry);
+       ncp_dbg(1, "removing %pd2\n", dentry);
 
        len = sizeof(__name);
        error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
@@ -1067,13 +1062,13 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
        int error;
 
        server = NCP_SERVER(dir);
-       DPRINTK("ncp_unlink: unlinking %pd2\n", dentry);
+       ncp_dbg(1, "unlinking %pd2\n", dentry);
        
        /*
         * Check whether to close the file ...
         */
        if (inode) {
-               PPRINTK("ncp_unlink: closing file\n");
+               ncp_vdbg("closing file\n");
                ncp_make_closed(inode);
        }
 
@@ -1087,7 +1082,7 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry)
 #endif
        switch (error) {
                case 0x00:
-                       DPRINTK("ncp: removed %pd2\n", dentry);
+                       ncp_dbg(1, "removed %pd2\n", dentry);
                        break;
                case 0x85:
                case 0x8A:
@@ -1120,7 +1115,7 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
        int old_len, new_len;
        __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
 
-       DPRINTK("ncp_rename: %pd2 to %pd2\n", old_dentry, new_dentry);
+       ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
 
        ncp_age_dentry(server, old_dentry);
        ncp_age_dentry(server, new_dentry);
@@ -1150,8 +1145,8 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
 #endif
        switch (error) {
                case 0x00:
-                               DPRINTK("ncp renamed %pd -> %pd.\n",
-                                old_dentry, new_dentry);
+                       ncp_dbg(1, "renamed %pd -> %pd\n",
+                               old_dentry, new_dentry);
                        break;
                case 0x9E:
                        error = -ENAMETOOLONG;
@@ -1173,7 +1168,7 @@ static int ncp_mknod(struct inode * dir, struct dentry *dentry,
        if (!new_valid_dev(rdev))
                return -EINVAL;
        if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
-               DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%ho\n", mode);
+               ncp_dbg(1, "mode = 0%ho\n", mode);
                return ncp_create_new(dir, dentry, mode, rdev, 0);
        }
        return -EPERM; /* Strange, but true */
index 8f5074e..77640a8 100644 (file)
@@ -6,6 +6,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <asm/uaccess.h>
 
 #include <linux/time.h>
@@ -34,11 +36,11 @@ int ncp_make_open(struct inode *inode, int right)
 
        error = -EINVAL;
        if (!inode) {
-               printk(KERN_ERR "ncp_make_open: got NULL inode\n");
+               pr_err("%s: got NULL inode\n", __func__);
                goto out;
        }
 
-       DPRINTK("ncp_make_open: opened=%d, volume # %u, dir entry # %u\n",
+       ncp_dbg(1, "opened=%d, volume # %u, dir entry # %u\n",
                atomic_read(&NCP_FINFO(inode)->opened), 
                NCP_FINFO(inode)->volNumber, 
                NCP_FINFO(inode)->dirEntNum);
@@ -71,7 +73,7 @@ int ncp_make_open(struct inode *inode, int right)
                                break;
                }
                if (result) {
-                       PPRINTK("ncp_make_open: failed, result=%d\n", result);
+                       ncp_vdbg("failed, result=%d\n", result);
                        goto out_unlock;
                }
                /*
@@ -83,7 +85,7 @@ int ncp_make_open(struct inode *inode, int right)
        }
 
        access = NCP_FINFO(inode)->access;
-       PPRINTK("ncp_make_open: file open, access=%x\n", access);
+       ncp_vdbg("file open, access=%x\n", access);
        if (access == right || access == O_RDWR) {
                atomic_inc(&NCP_FINFO(inode)->opened);
                error = 0;
@@ -107,7 +109,7 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
        void* freepage;
        size_t freelen;
 
-       DPRINTK("ncp_file_read: enter %pd2\n", dentry);
+       ncp_dbg(1, "enter %pd2\n", dentry);
 
        pos = *ppos;
 
@@ -124,7 +126,7 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 
        error = ncp_make_open(inode, O_RDONLY);
        if (error) {
-               DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error);
+               ncp_dbg(1, "open failed, error=%d\n", error);
                return error;
        }
 
@@ -165,7 +167,7 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
 
        file_accessed(file);
 
-       DPRINTK("ncp_file_read: exit %pd2\n", dentry);
+       ncp_dbg(1, "exit %pd2\n", dentry);
 outrel:
        ncp_inode_close(inode);         
        return already_read ? already_read : error;
@@ -182,7 +184,7 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
        int errno;
        void* bouncebuffer;
 
-       DPRINTK("ncp_file_write: enter %pd2\n", dentry);
+       ncp_dbg(1, "enter %pd2\n", dentry);
        if ((ssize_t) count < 0)
                return -EINVAL;
        pos = *ppos;
@@ -211,7 +213,7 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
                return 0;
        errno = ncp_make_open(inode, O_WRONLY);
        if (errno) {
-               DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno);
+               ncp_dbg(1, "open failed, error=%d\n", errno);
                return errno;
        }
        bufsize = NCP_SERVER(inode)->buffer_size;
@@ -261,7 +263,7 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
                        i_size_write(inode, pos);
                mutex_unlock(&inode->i_mutex);
        }
-       DPRINTK("ncp_file_write: exit %pd2\n", dentry);
+       ncp_dbg(1, "exit %pd2\n", dentry);
 outrel:
        ncp_inode_close(inode);         
        return already_written ? already_written : errno;
@@ -269,7 +271,7 @@ outrel:
 
 static int ncp_release(struct inode *inode, struct file *file) {
        if (ncp_make_closed(inode)) {
-               DPRINTK("ncp_release: failed to close\n");
+               ncp_dbg(1, "failed to close\n");
        }
        return 0;
 }
index 0af3349..03ffde1 100644 (file)
@@ -2,6 +2,8 @@
  * getopt.c
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/kernel.h>
 #include <linux/string.h>
 
@@ -46,8 +48,8 @@ int ncp_getopt(const char *caller, char **options, const struct ncp_option *opts
                                if (opts->has_arg & OPT_NOPARAM) {
                                        return opts->val;
                                }
-                               printk(KERN_INFO "%s: the %s option requires an argument\n",
-                                      caller, token);
+                               pr_info("%s: the %s option requires an argument\n",
+                                       caller, token);
                                return -EINVAL;
                        }
                        if (opts->has_arg & OPT_INT) {
@@ -57,18 +59,18 @@ int ncp_getopt(const char *caller, char **options, const struct ncp_option *opts
                                if (!*v) {
                                        return opts->val;
                                }
-                               printk(KERN_INFO "%s: invalid numeric value in %s=%s\n",
+                               pr_info("%s: invalid numeric value in %s=%s\n",
                                        caller, token, val);
                                return -EDOM;
                        }
                        if (opts->has_arg & OPT_STRING) {
                                return opts->val;
                        }
-                       printk(KERN_INFO "%s: unexpected argument %s to the %s option\n",
+                       pr_info("%s: unexpected argument %s to the %s option\n",
                                caller, val, token);
                        return -EINVAL;
                }
        }
-       printk(KERN_INFO "%s: Unrecognized mount option %s\n", caller, token);
+       pr_info("%s: Unrecognized mount option %s\n", caller, token);
        return -EOPNOTSUPP;
 }
index 647d86d..81b4f64 100644 (file)
@@ -9,6 +9,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 
 #include <asm/uaccess.h>
@@ -133,7 +135,7 @@ void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
        NCP_FINFO(inode)->access = nwinfo->access;
        memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
                        sizeof(nwinfo->file_handle));
-       DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n",
+       ncp_dbg(1, "updated %s, volnum=%d, dirent=%u\n",
                nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
                NCP_FINFO(inode)->dirEntNum);
 }
@@ -141,8 +143,7 @@ void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
 static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
 {
        /* NFS namespace mode overrides others if it's set. */
-       DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n",
-               nwi->entryName, nwi->nfs.mode);
+       ncp_dbg(1, "(%s) nfs.mode=0%o\n", nwi->entryName, nwi->nfs.mode);
        if (nwi->nfs.mode) {
                /* XXX Security? */
                inode->i_mode = nwi->nfs.mode;
@@ -230,7 +231,7 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
        
        ncp_update_attrs(inode, nwinfo);
 
-       DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
+       ncp_dbg(2, "inode->i_mode = %u\n", inode->i_mode);
 
        set_nlink(inode, 1);
        inode->i_uid = server->m.uid;
@@ -258,7 +259,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
        struct inode *inode;
 
        if (info == NULL) {
-               printk(KERN_ERR "ncp_iget: info is NULL\n");
+               pr_err("%s: info is NULL\n", __func__);
                return NULL;
        }
 
@@ -290,7 +291,7 @@ ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
                }
                insert_inode_hash(inode);
        } else
-               printk(KERN_ERR "ncp_iget: iget failed!\n");
+               pr_err("%s: iget failed!\n", __func__);
        return inode;
 }
 
@@ -301,12 +302,12 @@ ncp_evict_inode(struct inode *inode)
        clear_inode(inode);
 
        if (S_ISDIR(inode->i_mode)) {
-               DDPRINTK("ncp_evict_inode: put directory %ld\n", inode->i_ino);
+               ncp_dbg(2, "put directory %ld\n", inode->i_ino);
        }
 
        if (ncp_make_closed(inode) != 0) {
                /* We can't do anything but complain. */
-               printk(KERN_ERR "ncp_evict_inode: could not close\n");
+               pr_err("%s: could not close\n", __func__);
        }
 }
 
@@ -621,7 +622,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
           now because of PATH_MAX changes.. */
        if (server->m.time_out < 1) {
                server->m.time_out = 10;
-               printk(KERN_INFO "You need to recompile your ncpfs utils..\n");
+               pr_info("You need to recompile your ncpfs utils..\n");
        }
        server->m.time_out = server->m.time_out * HZ / 100;
        server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
@@ -682,7 +683,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
        ncp_unlock_server(server);
        if (error < 0)
                goto out_rxbuf;
-       DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb));
+       ncp_dbg(1, "NCP_SBP(sb) = %p\n", NCP_SBP(sb));
 
        error = -EMSGSIZE;      /* -EREMOTESIDEINCOMPATIBLE */
 #ifdef CONFIG_NCPFS_PACKET_SIGNING
@@ -710,7 +711,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
        if (ncp_negotiate_buffersize(server, default_bufsize,
                                     &(server->buffer_size)) != 0)
                goto out_disconnect;
-       DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
+       ncp_dbg(1, "bufsize = %d\n", server->buffer_size);
 
        memset(&finfo, 0, sizeof(finfo));
        finfo.i.attributes      = aDIR;
@@ -739,7 +740,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
         root_inode = ncp_iget(sb, &finfo);
         if (!root_inode)
                goto out_disconnect;
-       DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
+       ncp_dbg(1, "root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
        sb->s_root = d_make_root(root_inode);
         if (!sb->s_root)
                goto out_disconnect;
@@ -985,8 +986,7 @@ int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
        if ((attr->ia_valid & ATTR_SIZE) != 0) {
                int written;
 
-               DPRINTK("ncpfs: trying to change size to %ld\n",
-                       attr->ia_size);
+               ncp_dbg(1, "trying to change size to %llu\n", attr->ia_size);
 
                if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
                        result = -EACCES;
@@ -1072,7 +1072,7 @@ MODULE_ALIAS_FS("ncpfs");
 static int __init init_ncp_fs(void)
 {
        int err;
-       DPRINTK("ncpfs: init_ncp_fs called\n");
+       ncp_dbg(1, "called\n");
 
        err = init_inodecache();
        if (err)
@@ -1089,7 +1089,7 @@ out1:
 
 static void __exit exit_ncp_fs(void)
 {
-       DPRINTK("ncpfs: exit_ncp_fs called\n");
+       ncp_dbg(1, "called\n");
        unregister_filesystem(&ncp_fs_type);
        destroy_inodecache();
 }
index 60426cc..d5659d9 100644 (file)
@@ -41,7 +41,7 @@ ncp_get_fs_info(struct ncp_server * server, struct inode *inode,
                return -EFAULT;
 
        if (info.version != NCP_GET_FS_INFO_VERSION) {
-               DPRINTK("info.version invalid: %d\n", info.version);
+               ncp_dbg(1, "info.version invalid: %d\n", info.version);
                return -EINVAL;
        }
        /* TODO: info.addr = server->m.serv_addr; */
@@ -66,7 +66,7 @@ ncp_get_fs_info_v2(struct ncp_server * server, struct inode *inode,
                return -EFAULT;
 
        if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
-               DPRINTK("info.version invalid: %d\n", info2.version);
+               ncp_dbg(1, "info.version invalid: %d\n", info2.version);
                return -EINVAL;
        }
        info2.mounted_uid   = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
@@ -132,7 +132,7 @@ ncp_get_compat_fs_info_v2(struct ncp_server * server, struct inode *inode,
                return -EFAULT;
 
        if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
-               DPRINTK("info.version invalid: %d\n", info2.version);
+               ncp_dbg(1, "info.version invalid: %d\n", info2.version);
                return -EINVAL;
        }
        info2.mounted_uid   = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
@@ -308,8 +308,7 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg
                else
                        result = server->reply_size;
                ncp_unlock_server(server);
-               DPRINTK("ncp_ioctl: copy %d bytes\n",
-                       result);
+               ncp_dbg(1, "copy %d bytes\n", result);
                if (result >= 0)
                        if (copy_to_user(request.data, bouncebuffer, result))
                                result = -EFAULT;
@@ -385,9 +384,9 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg
                                                sr.namespace = server->name_space[sr.volNumber];
                                                result = 0;
                                        } else
-                                               DPRINTK("ncpfs: s_root->d_inode==NULL\n");
+                                               ncp_dbg(1, "s_root->d_inode==NULL\n");
                                } else
-                                       DPRINTK("ncpfs: s_root==NULL\n");
+                                       ncp_dbg(1, "s_root==NULL\n");
                        } else {
                                sr.volNumber = -1;
                                sr.namespace = 0;
@@ -440,11 +439,11 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg
                                                        NCP_FINFO(s_inode)->DosDirNum = dosde;
                                                        server->root_setuped = 1;
                                                } else {
-                                                       DPRINTK("ncpfs: s_root->d_inode==NULL\n");
+                                                       ncp_dbg(1, "s_root->d_inode==NULL\n");
                                                        result = -EIO;
                                                }
                                        } else {
-                                               DPRINTK("ncpfs: s_root==NULL\n");
+                                               ncp_dbg(1, "s_root==NULL\n");
                                                result = -EIO;
                                        }
                                }
index 3c5dd55..b359d12 100644 (file)
@@ -107,7 +107,7 @@ int ncp_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct inode *inode = file_inode(file);
        
-       DPRINTK("ncp_mmap: called\n");
+       ncp_dbg(1, "called\n");
 
        if (!ncp_conn_valid(NCP_SERVER(inode)))
                return -EIO;
index 31831af..b9f69e1 100644 (file)
@@ -2,30 +2,32 @@
 #include "ncp_fs_i.h"
 #include "ncp_fs_sb.h"
 
-/* define because it is easy to change PRINTK to {*}PRINTK */
-#define PRINTK(format, args...) printk(KERN_DEBUG format , ## args)
-
 #undef NCPFS_PARANOIA
 #ifdef NCPFS_PARANOIA
-#define PPRINTK(format, args...) PRINTK(format , ## args)
+#define ncp_vdbg(fmt, ...)                                     \
+       pr_debug(fmt, ##__VA_ARGS__)
 #else
-#define PPRINTK(format, args...)
+#define ncp_vdbg(fmt, ...)                                     \
+do {                                                           \
+       if (0)                                                  \
+               pr_debug(fmt, ##__VA_ARGS__);                   \
+} while (0)
 #endif
 
 #ifndef DEBUG_NCP
 #define DEBUG_NCP 0
 #endif
-#if DEBUG_NCP > 0
-#define DPRINTK(format, args...) PRINTK(format , ## args)
-#else
-#define DPRINTK(format, args...)
-#endif
-#if DEBUG_NCP > 1
-#define DDPRINTK(format, args...) PRINTK(format , ## args)
-#else
-#define DDPRINTK(format, args...)
+
+#if DEBUG_NCP > 0 && !defined(DEBUG)
+#define DEBUG
 #endif
 
+#define ncp_dbg(level, fmt, ...)                               \
+do {                                                           \
+       if (level <= DEBUG_NCP)                                 \
+               pr_debug(fmt, ##__VA_ARGS__);                   \
+} while (0)
+
 #define NCP_MAX_RPC_TIMEOUT (6*HZ)
 
 
index 981a956..4823875 100644 (file)
@@ -9,14 +9,14 @@
  *
  */
 
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include "ncp_fs.h"
 
 static inline void assert_server_locked(struct ncp_server *server)
 {
        if (server->lock == 0) {
-               DPRINTK("ncpfs: server not locked!\n");
+               ncp_dbg(1, "server not locked!\n");
        }
 }
 
@@ -75,7 +75,7 @@ static void ncp_add_pstring(struct ncp_server *server, const char *s)
        int len = strlen(s);
        assert_server_locked(server);
        if (len > 255) {
-               DPRINTK("ncpfs: string too long: %s\n", s);
+               ncp_dbg(1, "string too long: %s\n", s);
                len = 255;
        }
        ncp_add_byte(server, len);
@@ -225,7 +225,7 @@ int ncp_get_volume_info_with_number(struct ncp_server* server,
        result = -EIO;
        len = ncp_reply_byte(server, 29);
        if (len > NCP_VOLNAME_LEN) {
-               DPRINTK("ncpfs: volume name too long: %d\n", len);
+               ncp_dbg(1, "volume name too long: %d\n", len);
                goto out;
        }
        memcpy(&(target->volume_name), ncp_reply_data(server, 30), len);
@@ -259,7 +259,7 @@ int ncp_get_directory_info(struct ncp_server* server, __u8 n,
        result = -EIO;
        len = ncp_reply_byte(server, 21);
        if (len > NCP_VOLNAME_LEN) {
-               DPRINTK("ncpfs: volume name too long: %d\n", len);
+               ncp_dbg(1, "volume name too long: %d\n", len);
                goto out;
        }
        memcpy(&(target->volume_name), ncp_reply_data(server, 22), len);
@@ -295,9 +295,9 @@ ncp_make_closed(struct inode *inode)
                err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle);
 
                if (!err)
-                       PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
-                               NCP_FINFO(inode)->volNumber,
-                               NCP_FINFO(inode)->dirEntNum, err);
+                       ncp_vdbg("volnum=%d, dirent=%u, error=%d\n",
+                                NCP_FINFO(inode)->volNumber,
+                                NCP_FINFO(inode)->dirEntNum, err);
        }
        mutex_unlock(&NCP_FINFO(inode)->open_mutex);
        return err;
@@ -394,8 +394,7 @@ int ncp_obtain_nfs_info(struct ncp_server *server,
 
                if ((result = ncp_request(server, 87)) == 0) {
                        ncp_extract_nfs_info(ncp_reply_data(server, 0), &target->nfs);
-                       DPRINTK(KERN_DEBUG
-                               "ncp_obtain_nfs_info: (%s) mode=0%o, rdev=0x%x\n",
+                       ncp_dbg(1, "(%s) mode=0%o, rdev=0x%x\n",
                                target->entryName, target->nfs.mode,
                                target->nfs.rdev);
                } else {
@@ -425,7 +424,7 @@ int ncp_obtain_info(struct ncp_server *server, struct inode *dir, const char *pa
        int result;
 
        if (target == NULL) {
-               printk(KERN_ERR "ncp_obtain_info: invalid call\n");
+               pr_err("%s: invalid call\n", __func__);
                return -EINVAL;
        }
        ncp_init_request(server);
@@ -498,7 +497,7 @@ ncp_get_known_namespace(struct ncp_server *server, __u8 volume)
        namespace = ncp_reply_data(server, 2);
 
        while (no_namespaces > 0) {
-               DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume);
+               ncp_dbg(1, "found %d on %d\n", *namespace, volume);
 
 #ifdef CONFIG_NCPFS_NFS_NS
                if ((*namespace == NW_NS_NFS) && !(server->m.flags&NCP_MOUNT_NO_NFS)) 
@@ -531,8 +530,7 @@ ncp_update_known_namespace(struct ncp_server *server, __u8 volume, int *ret_ns)
        if (ret_ns)
                *ret_ns = ns;
 
-       DPRINTK("lookup_vol: namespace[%d] = %d\n",
-               volume, server->name_space[volume]);
+       ncp_dbg(1, "namespace[%d] = %d\n", volume, server->name_space[volume]);
 
        if (server->name_space[volume] == ns)
                return 0;
@@ -596,7 +594,7 @@ ncp_get_volume_root(struct ncp_server *server,
 {
        int result;
 
-       DPRINTK("ncp_get_volume_root: looking up vol %s\n", volname);
+       ncp_dbg(1, "looking up vol %s\n", volname);
 
        ncp_init_request(server);
        ncp_add_byte(server, 22);       /* Subfunction: Generate dir handle */
index 3a15872..04a69a4 100644 (file)
@@ -8,6 +8,7 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/time.h>
 #include <linux/errno.h>
@@ -231,7 +232,7 @@ static void __ncptcp_try_send(struct ncp_server *server)
                return;
 
        if (result < 0) {
-               printk(KERN_ERR "ncpfs: tcp: Send failed: %d\n", result);
+               pr_err("tcp: Send failed: %d\n", result);
                __ncp_abort_request(server, rq, result);
                return;
        }
@@ -332,7 +333,7 @@ static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *
        mutex_lock(&server->rcv.creq_mutex);
        if (!ncp_conn_valid(server)) {
                mutex_unlock(&server->rcv.creq_mutex);
-               printk(KERN_ERR "ncpfs: tcp: Server died\n");
+               pr_err("tcp: Server died\n");
                return -EIO;
        }
        ncp_req_get(req);
@@ -405,15 +406,15 @@ void ncpdgram_rcv_proc(struct work_struct *work)
                                }
                                result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
                                if (result < 0) {
-                                       DPRINTK("recv failed with %d\n", result);
+                                       ncp_dbg(1, "recv failed with %d\n", result);
                                        continue;
                                }
                                if (result < 10) {
-                                       DPRINTK("too short (%u) watchdog packet\n", result);
+                                       ncp_dbg(1, "too short (%u) watchdog packet\n", result);
                                        continue;
                                }
                                if (buf[9] != '?') {
-                                       DPRINTK("bad signature (%02X) in watchdog packet\n", buf[9]);
+                                       ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
                                        continue;
                                }
                                buf[9] = 'Y';
@@ -448,7 +449,7 @@ void ncpdgram_rcv_proc(struct work_struct *work)
                                                        result -= 8;
                                                        hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
                                                        if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
-                                                               printk(KERN_INFO "ncpfs: Signature violation\n");
+                                                               pr_info("Signature violation\n");
                                                                result = -EIO;
                                                        }
                                                }
@@ -524,7 +525,7 @@ static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
                return result;
        }
        if (result > len) {
-               printk(KERN_ERR "ncpfs: tcp: bug in recvmsg (%u > %Zu)\n", result, len);
+               pr_err("tcp: bug in recvmsg (%u > %Zu)\n", result, len);
                return -EIO;                    
        }
        return result;
@@ -552,9 +553,9 @@ static int __ncptcp_rcv_proc(struct ncp_server *server)
                                        __ncptcp_abort(server);
                                }
                                if (result < 0) {
-                                       printk(KERN_ERR "ncpfs: tcp: error in recvmsg: %d\n", result);
+                                       pr_err("tcp: error in recvmsg: %d\n", result);
                                } else {
-                                       DPRINTK(KERN_ERR "ncpfs: tcp: EOF\n");
+                                       ncp_dbg(1, "tcp: EOF\n");
                                }
                                return -EIO;
                        }
@@ -566,20 +567,20 @@ static int __ncptcp_rcv_proc(struct ncp_server *server)
                switch (server->rcv.state) {
                        case 0:
                                if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
-                                       printk(KERN_ERR "ncpfs: tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
+                                       pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
                                        __ncptcp_abort(server);
                                        return -EIO;
                                }
                                datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
                                if (datalen < 10) {
-                                       printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
+                                       pr_err("tcp: Unexpected reply len %d\n", datalen);
                                        __ncptcp_abort(server);
                                        return -EIO;
                                }
 #ifdef CONFIG_NCPFS_PACKET_SIGNING                             
                                if (server->sign_active) {
                                        if (datalen < 18) {
-                                               printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d\n", datalen);
+                                               pr_err("tcp: Unexpected reply len %d\n", datalen);
                                                __ncptcp_abort(server);
                                                return -EIO;
                                        }
@@ -604,7 +605,7 @@ cont:;
                                                server->rcv.len = datalen - 10;
                                                break;
                                        }                                       
-                                       DPRINTK("ncpfs: tcp: Unexpected NCP type %02X\n", type);
+                                       ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
 skipdata2:;
                                        server->rcv.state = 2;
 skipdata:;
@@ -614,11 +615,11 @@ skipdata:;
                                }
                                req = server->rcv.creq;
                                if (!req) {
-                                       DPRINTK(KERN_ERR "ncpfs: Reply without appropriate request\n");
+                                       ncp_dbg(1, "Reply without appropriate request\n");
                                        goto skipdata2;
                                }
                                if (datalen > req->datalen + 8) {
-                                       printk(KERN_ERR "ncpfs: tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
+                                       pr_err("tcp: Unexpected reply len %d (expected at most %Zd)\n", datalen, req->datalen + 8);
                                        server->rcv.state = 3;
                                        goto skipdata;
                                }
@@ -638,12 +639,12 @@ skipdata:;
                                req = server->rcv.creq;
                                if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
                                        if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
-                                               printk(KERN_ERR "ncpfs: tcp: Bad sequence number\n");
+                                               pr_err("tcp: Bad sequence number\n");
                                                __ncp_abort_request(server, req, -EIO);
                                                return -EIO;
                                        }
                                        if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
-                                               printk(KERN_ERR "ncpfs: tcp: Connection number mismatch\n");
+                                               pr_err("tcp: Connection number mismatch\n");
                                                __ncp_abort_request(server, req, -EIO);
                                                return -EIO;
                                        }
@@ -651,7 +652,7 @@ skipdata:;
 #ifdef CONFIG_NCPFS_PACKET_SIGNING                             
                                if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
                                        if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
-                                               printk(KERN_ERR "ncpfs: tcp: Signature violation\n");
+                                               pr_err("tcp: Signature violation\n");
                                                __ncp_abort_request(server, req, -EIO);
                                                return -EIO;
                                        }
@@ -742,7 +743,7 @@ static int ncp_do_request(struct ncp_server *server, int size,
        int result;
 
        if (server->lock == 0) {
-               printk(KERN_ERR "ncpfs: Server not locked!\n");
+               pr_err("Server not locked!\n");
                return -EIO;
        }
        if (!ncp_conn_valid(server)) {
@@ -781,7 +782,7 @@ static int ncp_do_request(struct ncp_server *server, int size,
                spin_unlock_irqrestore(&current->sighand->siglock, flags);
        }
 
-       DDPRINTK("do_ncp_rpc_call returned %d\n", result);
+       ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
 
        return result;
 }
@@ -811,7 +812,7 @@ int ncp_request2(struct ncp_server *server, int function,
 
        result = ncp_do_request(server, server->current_size, reply, size);
        if (result < 0) {
-               DPRINTK("ncp_request_error: %d\n", result);
+               ncp_dbg(1, "ncp_request_error: %d\n", result);
                goto out;
        }
        server->completion = reply->completion_code;
@@ -822,7 +823,7 @@ int ncp_request2(struct ncp_server *server, int function,
        result = reply->completion_code;
 
        if (result != 0)
-               PPRINTK("ncp_request: completion code=%x\n", result);
+               ncp_vdbg("completion code=%x\n", result);
 out:
        return result;
 }
@@ -865,14 +866,14 @@ void ncp_lock_server(struct ncp_server *server)
 {
        mutex_lock(&server->mutex);
        if (server->lock)
-               printk(KERN_WARNING "ncp_lock_server: was locked!\n");
+               pr_warn("%s: was locked!\n", __func__);
        server->lock = 1;
 }
 
 void ncp_unlock_server(struct ncp_server *server)
 {
        if (!server->lock) {
-               printk(KERN_WARNING "ncp_unlock_server: was not locked!\n");
+               pr_warn("%s: was not locked!\n", __func__);
                return;
        }
        server->lock = 0;
index 52439dd..1a63bfd 100644 (file)
@@ -112,7 +112,7 @@ int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
        __le32 attr;
        unsigned int hdr;
 
-       DPRINTK("ncp_symlink(dir=%p,dentry=%p,symname=%s)\n",dir,dentry,symname);
+       ncp_dbg(1, "dir=%p, dentry=%p, symname=%s\n", dir, dentry, symname);
 
        if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber))
                kludge = 0;
index ae2e87b..41db525 100644 (file)
@@ -112,7 +112,8 @@ out:
  * TODO: keep track of all layouts (and delegations) in a hash table
  * hashed by filehandle.
  */
-static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp, struct nfs_fh *fh)
+static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
+               struct nfs_fh *fh, nfs4_stateid *stateid)
 {
        struct nfs_server *server;
        struct inode *ino;
@@ -120,17 +121,19 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
 
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
                list_for_each_entry(lo, &server->layouts, plh_layouts) {
+                       if (!nfs4_stateid_match_other(&lo->plh_stateid, stateid))
+                               continue;
                        if (nfs_compare_fh(fh, &NFS_I(lo->plh_inode)->fh))
                                continue;
                        ino = igrab(lo->plh_inode);
                        if (!ino)
-                               continue;
+                               break;
                        spin_lock(&ino->i_lock);
                        /* Is this layout in the process of being freed? */
                        if (NFS_I(ino)->layout != lo) {
                                spin_unlock(&ino->i_lock);
                                iput(ino);
-                               continue;
+                               break;
                        }
                        pnfs_get_layout_hdr(lo);
                        spin_unlock(&ino->i_lock);
@@ -141,13 +144,14 @@ static struct pnfs_layout_hdr * get_layout_by_fh_locked(struct nfs_client *clp,
        return NULL;
 }
 
-static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp, struct nfs_fh *fh)
+static struct pnfs_layout_hdr * get_layout_by_fh(struct nfs_client *clp,
+               struct nfs_fh *fh, nfs4_stateid *stateid)
 {
        struct pnfs_layout_hdr *lo;
 
        spin_lock(&clp->cl_lock);
        rcu_read_lock();
-       lo = get_layout_by_fh_locked(clp, fh);
+       lo = get_layout_by_fh_locked(clp, fh, stateid);
        rcu_read_unlock();
        spin_unlock(&clp->cl_lock);
 
@@ -162,9 +166,9 @@ static u32 initiate_file_draining(struct nfs_client *clp,
        u32 rv = NFS4ERR_NOMATCHING_LAYOUT;
        LIST_HEAD(free_me_list);
 
-       lo = get_layout_by_fh(clp, &args->cbl_fh);
+       lo = get_layout_by_fh(clp, &args->cbl_fh, &args->cbl_stateid);
        if (!lo)
-               return NFS4ERR_NOMATCHING_LAYOUT;
+               goto out;
 
        ino = lo->plh_inode;
        spin_lock(&ino->i_lock);
@@ -179,6 +183,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,
        pnfs_free_lseg_list(&free_me_list);
        pnfs_put_layout_hdr(lo);
        iput(ino);
+out:
        return rv;
 }
 
index 4a48fe4..d9f3d06 100644 (file)
@@ -69,21 +69,28 @@ const struct address_space_operations nfs_dir_aops = {
 
 static struct nfs_open_dir_context *alloc_nfs_open_dir_context(struct inode *dir, struct rpc_cred *cred)
 {
+       struct nfs_inode *nfsi = NFS_I(dir);
        struct nfs_open_dir_context *ctx;
        ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
        if (ctx != NULL) {
                ctx->duped = 0;
-               ctx->attr_gencount = NFS_I(dir)->attr_gencount;
+               ctx->attr_gencount = nfsi->attr_gencount;
                ctx->dir_cookie = 0;
                ctx->dup_cookie = 0;
                ctx->cred = get_rpccred(cred);
+               spin_lock(&dir->i_lock);
+               list_add(&ctx->list, &nfsi->open_files);
+               spin_unlock(&dir->i_lock);
                return ctx;
        }
        return  ERR_PTR(-ENOMEM);
 }
 
-static void put_nfs_open_dir_context(struct nfs_open_dir_context *ctx)
+static void put_nfs_open_dir_context(struct inode *dir, struct nfs_open_dir_context *ctx)
 {
+       spin_lock(&dir->i_lock);
+       list_del(&ctx->list);
+       spin_unlock(&dir->i_lock);
        put_rpccred(ctx->cred);
        kfree(ctx);
 }
@@ -126,7 +133,7 @@ out:
 static int
 nfs_closedir(struct inode *inode, struct file *filp)
 {
-       put_nfs_open_dir_context(filp->private_data);
+       put_nfs_open_dir_context(filp->f_path.dentry->d_inode, filp->private_data);
        return 0;
 }
 
@@ -306,10 +313,9 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
                                        if (printk_ratelimit()) {
                                                pr_notice("NFS: directory %pD2 contains a readdir loop."
                                                                "Please contact your server vendor.  "
-                                                               "The file: %s has duplicate cookie %llu\n",
-                                                               desc->file,
-                                                               array->array[i].string.name,
-                                                               *desc->dir_cookie);
+                                                               "The file: %.*s has duplicate cookie %llu\n",
+                                                               desc->file, array->array[i].string.len,
+                                                               array->array[i].string.name, *desc->dir_cookie);
                                        }
                                        status = -ELOOP;
                                        goto out;
@@ -437,6 +443,22 @@ void nfs_advise_use_readdirplus(struct inode *dir)
        set_bit(NFS_INO_ADVISE_RDPLUS, &NFS_I(dir)->flags);
 }
 
+/*
+ * This function is mainly for use by nfs_getattr().
+ *
+ * If this is an 'ls -l', we want to force use of readdirplus.
+ * Do this by checking if there is an active file descriptor
+ * and calling nfs_advise_use_readdirplus, then forcing a
+ * cache flush.
+ */
+void nfs_force_use_readdirplus(struct inode *dir)
+{
+       if (!list_empty(&NFS_I(dir)->open_files)) {
+               nfs_advise_use_readdirplus(dir);
+               nfs_zap_mapping(dir, dir->i_mapping);
+       }
+}
+
 static
 void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
 {
@@ -815,6 +837,17 @@ int uncached_readdir(nfs_readdir_descriptor_t *desc)
        goto out;
 }
 
+static bool nfs_dir_mapping_need_revalidate(struct inode *dir)
+{
+       struct nfs_inode *nfsi = NFS_I(dir);
+
+       if (nfs_attribute_cache_expired(dir))
+               return true;
+       if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
+               return true;
+       return false;
+}
+
 /* The file offset position represents the dirent entry number.  A
    last cookie cache takes care of the common case of reading the
    whole directory.
@@ -847,7 +880,7 @@ static int nfs_readdir(struct file *file, struct dir_context *ctx)
        desc->plus = nfs_use_readdirplus(inode, ctx) ? 1 : 0;
 
        nfs_block_sillyrename(dentry);
-       if (ctx->pos == 0 || nfs_attribute_cache_expired(inode))
+       if (ctx->pos == 0 || nfs_dir_mapping_need_revalidate(inode))
                res = nfs_revalidate_mapping(inode, file->f_mapping);
        if (res < 0)
                goto out;
@@ -1911,6 +1944,7 @@ int nfs_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 dentry *dentry = NULL, *rehash = NULL;
+       struct rpc_task *task;
        int error = -EBUSY;
 
        dfprintk(VFS, "NFS: rename(%pd2 -> %pd2, ct=%d)\n",
@@ -1958,8 +1992,16 @@ int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (new_inode != NULL)
                NFS_PROTO(new_inode)->return_delegation(new_inode);
 
-       error = NFS_PROTO(old_dir)->rename(old_dir, &old_dentry->d_name,
-                                          new_dir, &new_dentry->d_name);
+       task = nfs_async_rename(old_dir, new_dir, old_dentry, new_dentry, NULL);
+       if (IS_ERR(task)) {
+               error = PTR_ERR(task);
+               goto out;
+       }
+
+       error = rpc_wait_for_completion_task(task);
+       if (error == 0)
+               error = task->tk_status;
+       rpc_put_task(task);
        nfs_mark_for_revalidate(old_inode);
 out:
        if (rehash)
index 5bb790a..284ca90 100644 (file)
@@ -617,6 +617,7 @@ out:
 
 static const struct vm_operations_struct nfs_file_vm_ops = {
        .fault = filemap_fault,
+       .map_pages = filemap_map_pages,
        .page_mkwrite = nfs_vm_page_mkwrite,
        .remap_pages = generic_file_remap_pages,
 };
index c4702ba..0c43897 100644 (file)
@@ -588,6 +588,25 @@ void nfs_setattr_update_inode(struct inode *inode, struct iattr *attr)
 }
 EXPORT_SYMBOL_GPL(nfs_setattr_update_inode);
 
+static void nfs_request_parent_use_readdirplus(struct dentry *dentry)
+{
+       struct dentry *parent;
+
+       parent = dget_parent(dentry);
+       nfs_force_use_readdirplus(parent->d_inode);
+       dput(parent);
+}
+
+static bool nfs_need_revalidate_inode(struct inode *inode)
+{
+       if (NFS_I(inode)->cache_validity &
+                       (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
+               return true;
+       if (nfs_attribute_cache_expired(inode))
+               return true;
+       return false;
+}
+
 int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
 {
        struct inode *inode = dentry->d_inode;
@@ -616,10 +635,13 @@ int nfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
            ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode)))
                need_atime = 0;
 
-       if (need_atime)
-               err = __nfs_revalidate_inode(NFS_SERVER(inode), inode);
-       else
-               err = nfs_revalidate_inode(NFS_SERVER(inode), inode);
+       if (need_atime || nfs_need_revalidate_inode(inode)) {
+               struct nfs_server *server = NFS_SERVER(inode);
+
+               if (server->caps & NFS_CAP_READDIRPLUS)
+                       nfs_request_parent_use_readdirplus(dentry);
+               err = __nfs_revalidate_inode(server, inode);
+       }
        if (!err) {
                generic_fillattr(inode, stat);
                stat->ino = nfs_compat_user_ino64(NFS_FILEID(inode));
@@ -961,9 +983,7 @@ int nfs_attribute_cache_expired(struct inode *inode)
  */
 int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 {
-       if (!(NFS_I(inode)->cache_validity &
-                       (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL))
-                       && !nfs_attribute_cache_expired(inode))
+       if (!nfs_need_revalidate_inode(inode))
                return NFS_STALE(inode) ? -ESTALE : 0;
        return __nfs_revalidate_inode(server, inode);
 }
index b46cf5a..dd8bfc2 100644 (file)
@@ -301,6 +301,7 @@ extern struct nfs_client *nfs_init_client(struct nfs_client *clp,
                           const char *ip_addr);
 
 /* dir.c */
+extern void nfs_force_use_readdirplus(struct inode *dir);
 extern unsigned long nfs_access_cache_count(struct shrinker *shrink,
                                            struct shrink_control *sc);
 extern unsigned long nfs_access_cache_scan(struct shrinker *shrink,
@@ -474,6 +475,13 @@ extern int nfs_migrate_page(struct address_space *,
 #define nfs_migrate_page NULL
 #endif
 
+/* unlink.c */
+extern struct rpc_task *
+nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
+                struct dentry *old_dentry, struct dentry *new_dentry,
+                void (*complete)(struct rpc_task *, struct nfs_renamedata *));
+extern int nfs_sillyrename(struct inode *dir, struct dentry *dentry);
+
 /* direct.c */
 void nfs_init_cinfo_from_dreq(struct nfs_commit_info *cinfo,
                              struct nfs_direct_req *dreq);
index a462ef0..db60149 100644 (file)
@@ -478,41 +478,6 @@ nfs3_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
        return 1;
 }
 
-static int
-nfs3_proc_rename(struct inode *old_dir, struct qstr *old_name,
-                struct inode *new_dir, struct qstr *new_name)
-{
-       struct nfs_renameargs   arg = {
-               .old_dir        = NFS_FH(old_dir),
-               .old_name       = old_name,
-               .new_dir        = NFS_FH(new_dir),
-               .new_name       = new_name,
-       };
-       struct nfs_renameres res;
-       struct rpc_message msg = {
-               .rpc_proc       = &nfs3_procedures[NFS3PROC_RENAME],
-               .rpc_argp       = &arg,
-               .rpc_resp       = &res,
-       };
-       int status = -ENOMEM;
-
-       dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
-
-       res.old_fattr = nfs_alloc_fattr();
-       res.new_fattr = nfs_alloc_fattr();
-       if (res.old_fattr == NULL || res.new_fattr == NULL)
-               goto out;
-
-       status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
-       nfs_post_op_update_inode(old_dir, res.old_fattr);
-       nfs_post_op_update_inode(new_dir, res.new_fattr);
-out:
-       nfs_free_fattr(res.old_fattr);
-       nfs_free_fattr(res.new_fattr);
-       dprintk("NFS reply rename: %d\n", status);
-       return status;
-}
-
 static int
 nfs3_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
 {
@@ -968,7 +933,6 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .unlink_setup   = nfs3_proc_unlink_setup,
        .unlink_rpc_prepare = nfs3_proc_unlink_rpc_prepare,
        .unlink_done    = nfs3_proc_unlink_done,
-       .rename         = nfs3_proc_rename,
        .rename_setup   = nfs3_proc_rename_setup,
        .rename_rpc_prepare = nfs3_proc_rename_rpc_prepare,
        .rename_done    = nfs3_proc_rename_done,
index a5b27c2..e1d1bad 100644 (file)
@@ -427,6 +427,7 @@ extern void nfs4_close_sync(struct nfs4_state *, fmode_t);
 extern void nfs4_state_set_mode_locked(struct nfs4_state *, fmode_t);
 extern void nfs_inode_find_state_and_recover(struct inode *inode,
                const nfs4_stateid *stateid);
+extern int nfs4_state_mark_reclaim_nograce(struct nfs_client *, struct nfs4_state *);
 extern void nfs4_schedule_lease_recovery(struct nfs_client *);
 extern int nfs4_wait_clnt_recover(struct nfs_client *clp);
 extern int nfs4_client_recover_expired_lease(struct nfs_client *clp);
@@ -500,6 +501,16 @@ static inline bool nfs4_stateid_match(const nfs4_stateid *dst, const nfs4_statei
        return memcmp(dst, src, sizeof(*dst)) == 0;
 }
 
+static inline bool nfs4_stateid_match_other(const nfs4_stateid *dst, const nfs4_stateid *src)
+{
+       return memcmp(dst->other, src->other, NFS4_STATEID_OTHER_SIZE) == 0;
+}
+
+static inline bool nfs4_stateid_is_newer(const nfs4_stateid *s1, const nfs4_stateid *s2)
+{
+       return (s32)(be32_to_cpu(s1->seqid) - be32_to_cpu(s2->seqid)) > 0;
+}
+
 static inline bool nfs4_valid_open_stateid(const struct nfs4_state *state)
 {
        return test_bit(NFS_STATE_RECOVERY_FAILED, &state->flags) == 0;
index 0e46d3d..aa9ef48 100644 (file)
@@ -531,6 +531,13 @@ int nfs40_walk_client_list(struct nfs_client *new,
                        *result = pos;
                        dprintk("NFS: <-- %s using nfs_client = %p ({%d})\n",
                                __func__, pos, atomic_read(&pos->cl_count));
+                       goto out;
+               case -ERESTARTSYS:
+               case -ETIMEDOUT:
+                       /* The callback path may have been inadvertently
+                        * changed. Schedule recovery!
+                        */
+                       nfs4_schedule_path_down_recovery(pos);
                default:
                        goto out;
                }
index 450bfed..397be39 100644 (file)
@@ -1068,6 +1068,7 @@ static void nfs4_opendata_free(struct kref *kref)
        dput(p->dentry);
        nfs_sb_deactive(sb);
        nfs_fattr_free_names(&p->f_attr);
+       kfree(p->f_attr.mdsthreshold);
        kfree(p);
 }
 
@@ -1137,12 +1138,71 @@ static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
        nfs4_state_set_mode_locked(state, state->state | fmode);
 }
 
-static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
+static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state)
+{
+       struct nfs_client *clp = state->owner->so_server->nfs_client;
+       bool need_recover = false;
+
+       if (test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags) && state->n_rdonly)
+               need_recover = true;
+       if (test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags) && state->n_wronly)
+               need_recover = true;
+       if (test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags) && state->n_rdwr)
+               need_recover = true;
+       if (need_recover)
+               nfs4_state_mark_reclaim_nograce(clp, state);
+}
+
+static bool nfs_need_update_open_stateid(struct nfs4_state *state,
+               nfs4_stateid *stateid)
+{
+       if (test_and_set_bit(NFS_OPEN_STATE, &state->flags) == 0)
+               return true;
+       if (!nfs4_stateid_match_other(stateid, &state->open_stateid)) {
+               nfs_test_and_clear_all_open_stateid(state);
+               return true;
+       }
+       if (nfs4_stateid_is_newer(stateid, &state->open_stateid))
+               return true;
+       return false;
+}
+
+static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
+               nfs4_stateid *stateid, fmode_t fmode)
 {
+       clear_bit(NFS_O_RDWR_STATE, &state->flags);
+       switch (fmode & (FMODE_READ|FMODE_WRITE)) {
+       case FMODE_WRITE:
+               clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+               break;
+       case FMODE_READ:
+               clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+               break;
+       case 0:
+               clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+               clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+               clear_bit(NFS_OPEN_STATE, &state->flags);
+       }
+       if (stateid == NULL)
+               return;
+       if (!nfs_need_update_open_stateid(state, stateid))
+               return;
        if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
                nfs4_stateid_copy(&state->stateid, stateid);
        nfs4_stateid_copy(&state->open_stateid, stateid);
-       set_bit(NFS_OPEN_STATE, &state->flags);
+}
+
+static void nfs_clear_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
+{
+       write_seqlock(&state->seqlock);
+       nfs_clear_open_stateid_locked(state, stateid, fmode);
+       write_sequnlock(&state->seqlock);
+       if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
+               nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
+}
+
+static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
+{
        switch (fmode) {
                case FMODE_READ:
                        set_bit(NFS_O_RDONLY_STATE, &state->flags);
@@ -1153,13 +1213,11 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *
                case FMODE_READ|FMODE_WRITE:
                        set_bit(NFS_O_RDWR_STATE, &state->flags);
        }
-}
-
-static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
-{
-       write_seqlock(&state->seqlock);
-       nfs_set_open_stateid_locked(state, stateid, fmode);
-       write_sequnlock(&state->seqlock);
+       if (!nfs_need_update_open_stateid(state, stateid))
+               return;
+       if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
+               nfs4_stateid_copy(&state->stateid, stateid);
+       nfs4_stateid_copy(&state->open_stateid, stateid);
 }
 
 static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode)
@@ -1217,6 +1275,8 @@ no_delegation:
                __update_open_stateid(state, open_stateid, NULL, fmode);
                ret = 1;
        }
+       if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
+               nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
 
        return ret;
 }
@@ -1450,12 +1510,15 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
        struct nfs4_state *newstate;
        int ret;
 
+       /* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */
+       clear_bit(NFS_O_RDWR_STATE, &state->flags);
+       clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+       clear_bit(NFS_O_RDONLY_STATE, &state->flags);
        /* memory barrier prior to reading state->n_* */
        clear_bit(NFS_DELEGATED_STATE, &state->flags);
        clear_bit(NFS_OPEN_STATE, &state->flags);
        smp_rmb();
        if (state->n_rdwr != 0) {
-               clear_bit(NFS_O_RDWR_STATE, &state->flags);
                ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
                if (ret != 0)
                        return ret;
@@ -1463,7 +1526,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
                        return -ESTALE;
        }
        if (state->n_wronly != 0) {
-               clear_bit(NFS_O_WRONLY_STATE, &state->flags);
                ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
                if (ret != 0)
                        return ret;
@@ -1471,7 +1533,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
                        return -ESTALE;
        }
        if (state->n_rdonly != 0) {
-               clear_bit(NFS_O_RDONLY_STATE, &state->flags);
                ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
                if (ret != 0)
                        return ret;
@@ -2244,10 +2305,12 @@ static int _nfs4_do_open(struct inode *dir,
                }
        }
 
-       if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
-               opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
-               if (!opendata->f_attr.mdsthreshold)
-                       goto err_free_label;
+       if (server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
+               if (!opendata->f_attr.mdsthreshold) {
+                       opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
+                       if (!opendata->f_attr.mdsthreshold)
+                               goto err_free_label;
+               }
                opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0];
        }
        if (dentry->d_inode != NULL)
@@ -2275,11 +2338,10 @@ static int _nfs4_do_open(struct inode *dir,
        if (opendata->file_created)
                *opened |= FILE_CREATED;
 
-       if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
+       if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) {
                *ctx_th = opendata->f_attr.mdsthreshold;
-       else
-               kfree(opendata->f_attr.mdsthreshold);
-       opendata->f_attr.mdsthreshold = NULL;
+               opendata->f_attr.mdsthreshold = NULL;
+       }
 
        nfs4_label_free(olabel);
 
@@ -2289,7 +2351,6 @@ static int _nfs4_do_open(struct inode *dir,
 err_free_label:
        nfs4_label_free(olabel);
 err_opendata_put:
-       kfree(opendata->f_attr.mdsthreshold);
        nfs4_opendata_put(opendata);
 err_put_state_owner:
        nfs4_put_state_owner(sp);
@@ -2479,26 +2540,6 @@ static void nfs4_free_closedata(void *data)
        kfree(calldata);
 }
 
-static void nfs4_close_clear_stateid_flags(struct nfs4_state *state,
-               fmode_t fmode)
-{
-       spin_lock(&state->owner->so_lock);
-       clear_bit(NFS_O_RDWR_STATE, &state->flags);
-       switch (fmode & (FMODE_READ|FMODE_WRITE)) {
-       case FMODE_WRITE:
-               clear_bit(NFS_O_RDONLY_STATE, &state->flags);
-               break;
-       case FMODE_READ:
-               clear_bit(NFS_O_WRONLY_STATE, &state->flags);
-               break;
-       case 0:
-               clear_bit(NFS_O_RDONLY_STATE, &state->flags);
-               clear_bit(NFS_O_WRONLY_STATE, &state->flags);
-               clear_bit(NFS_OPEN_STATE, &state->flags);
-       }
-       spin_unlock(&state->owner->so_lock);
-}
-
 static void nfs4_close_done(struct rpc_task *task, void *data)
 {
        struct nfs4_closedata *calldata = data;
@@ -2517,9 +2558,9 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                        if (calldata->roc)
                                pnfs_roc_set_barrier(state->inode,
                                                     calldata->roc_barrier);
-                       nfs_set_open_stateid(state, &calldata->res.stateid, 0);
+                       nfs_clear_open_stateid(state, &calldata->res.stateid, 0);
                        renew_lease(server, calldata->timestamp);
-                       break;
+                       goto out_release;
                case -NFS4ERR_ADMIN_REVOKED:
                case -NFS4ERR_STALE_STATEID:
                case -NFS4ERR_OLD_STATEID:
@@ -2533,7 +2574,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
                                goto out_release;
                        }
        }
-       nfs4_close_clear_stateid_flags(state, calldata->arg.fmode);
+       nfs_clear_open_stateid(state, NULL, calldata->arg.fmode);
 out_release:
        nfs_release_seqid(calldata->arg.seqid);
        nfs_refresh_inode(calldata->inode, calldata->res.fattr);
@@ -3507,49 +3548,6 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
        return 1;
 }
 
-static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
-               struct inode *new_dir, struct qstr *new_name)
-{
-       struct nfs_server *server = NFS_SERVER(old_dir);
-       struct nfs_renameargs arg = {
-               .old_dir = NFS_FH(old_dir),
-               .new_dir = NFS_FH(new_dir),
-               .old_name = old_name,
-               .new_name = new_name,
-       };
-       struct nfs_renameres res = {
-               .server = server,
-       };
-       struct rpc_message msg = {
-               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME],
-               .rpc_argp = &arg,
-               .rpc_resp = &res,
-       };
-       int status = -ENOMEM;
-
-       status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
-       if (!status) {
-               update_changeattr(old_dir, &res.old_cinfo);
-               update_changeattr(new_dir, &res.new_cinfo);
-       }
-       return status;
-}
-
-static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
-               struct inode *new_dir, struct qstr *new_name)
-{
-       struct nfs4_exception exception = { };
-       int err;
-       do {
-               err = _nfs4_proc_rename(old_dir, old_name,
-                                       new_dir, new_name);
-               trace_nfs4_rename(old_dir, old_name, new_dir, new_name, err);
-               err = nfs4_handle_exception(NFS_SERVER(old_dir), err,
-                               &exception);
-       } while (exception.retry);
-       return err;
-}
-
 static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
 {
        struct nfs_server *server = NFS_SERVER(inode);
@@ -4884,6 +4882,20 @@ nfs4_init_uniform_client_string(const struct nfs_client *clp,
                                nodename);
 }
 
+/*
+ * nfs4_callback_up_net() starts only "tcp" and "tcp6" callback
+ * services.  Advertise one based on the address family of the
+ * clientaddr.
+ */
+static unsigned int
+nfs4_init_callback_netid(const struct nfs_client *clp, char *buf, size_t len)
+{
+       if (strchr(clp->cl_ipaddr, ':') != NULL)
+               return scnprintf(buf, len, "tcp6");
+       else
+               return scnprintf(buf, len, "tcp");
+}
+
 /**
  * nfs4_proc_setclientid - Negotiate client ID
  * @clp: state data structure
@@ -4925,12 +4937,10 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
                                                setclientid.sc_name,
                                                sizeof(setclientid.sc_name));
        /* cb_client4 */
-       rcu_read_lock();
-       setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
-                               sizeof(setclientid.sc_netid), "%s",
-                               rpc_peeraddr2str(clp->cl_rpcclient,
-                                                       RPC_DISPLAY_NETID));
-       rcu_read_unlock();
+       setclientid.sc_netid_len =
+                               nfs4_init_callback_netid(clp,
+                                               setclientid.sc_netid,
+                                               sizeof(setclientid.sc_netid));
        setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
                                sizeof(setclientid.sc_uaddr), "%s.%u.%u",
                                clp->cl_ipaddr, port >> 8, port & 255);
@@ -8408,7 +8418,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
        .unlink_setup   = nfs4_proc_unlink_setup,
        .unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare,
        .unlink_done    = nfs4_proc_unlink_done,
-       .rename         = nfs4_proc_rename,
        .rename_setup   = nfs4_proc_rename_setup,
        .rename_rpc_prepare = nfs4_proc_rename_rpc_prepare,
        .rename_done    = nfs4_proc_rename_done,
index 0deb321..2349518 100644 (file)
@@ -1316,7 +1316,7 @@ static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_st
        return 1;
 }
 
-static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
+int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
 {
        set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
        clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
@@ -2075,8 +2075,10 @@ again:
        switch (status) {
        case 0:
                break;
-       case -NFS4ERR_DELAY:
        case -ETIMEDOUT:
+               if (clnt->cl_softrtry)
+                       break;
+       case -NFS4ERR_DELAY:
        case -EAGAIN:
                ssleep(1);
        case -NFS4ERR_STALE_CLIENTID:
index 72f3bf1..73ce8d4 100644 (file)
@@ -203,8 +203,7 @@ static int nfs4_stat_to_errno(int);
                                 2 + encode_verifier_maxsz + 5 + \
                                nfs4_label_maxsz)
 #define decode_readdir_maxsz   (op_decode_hdr_maxsz + \
-                                decode_verifier_maxsz + \
-                               nfs4_label_maxsz + nfs4_fattr_maxsz)
+                                decode_verifier_maxsz)
 #define encode_readlink_maxsz  (op_encode_hdr_maxsz)
 #define decode_readlink_maxsz  (op_decode_hdr_maxsz + 1)
 #define encode_write_maxsz     (op_encode_hdr_maxsz + \
index 4755858..cb53d45 100644 (file)
@@ -662,7 +662,18 @@ pnfs_destroy_all_layouts(struct nfs_client *clp)
  */
 static bool pnfs_seqid_is_newer(u32 s1, u32 s2)
 {
-       return (s32)s1 - (s32)s2 > 0;
+       return (s32)(s1 - s2) > 0;
+}
+
+static void
+pnfs_verify_layout_stateid(struct pnfs_layout_hdr *lo,
+               const nfs4_stateid *new,
+               struct list_head *free_me_list)
+{
+       if (nfs4_stateid_match_other(&lo->plh_stateid, new))
+               return;
+       /* Layout is new! Kill existing layout segments */
+       pnfs_mark_matching_lsegs_invalid(lo, free_me_list, NULL);
 }
 
 /* update lo->plh_stateid with new if is more recent */
@@ -1315,6 +1326,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
        struct nfs4_layoutget_res *res = &lgp->res;
        struct pnfs_layout_segment *lseg;
        struct inode *ino = lo->plh_inode;
+       LIST_HEAD(free_me);
        int status = 0;
 
        /* Inject layout blob into I/O device driver */
@@ -1341,6 +1353,8 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
                goto out_forget_reply;
        }
 
+       /* Check that the new stateid matches the old stateid */
+       pnfs_verify_layout_stateid(lo, &res->stateid, &free_me);
        /* Done processing layoutget. Set the layout stateid */
        pnfs_set_layout_stateid(lo, &res->stateid, false);
 
@@ -1355,6 +1369,7 @@ pnfs_layout_process(struct nfs4_layoutget *lgp)
        }
 
        spin_unlock(&ino->i_lock);
+       pnfs_free_lseg_list(&free_me);
        return lseg;
 out:
        return ERR_PTR(status);
index fddbba2..e55ce9e 100644 (file)
@@ -356,30 +356,6 @@ nfs_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
        return 1;
 }
 
-static int
-nfs_proc_rename(struct inode *old_dir, struct qstr *old_name,
-               struct inode *new_dir, struct qstr *new_name)
-{
-       struct nfs_renameargs   arg = {
-               .old_dir        = NFS_FH(old_dir),
-               .old_name       = old_name,
-               .new_dir        = NFS_FH(new_dir),
-               .new_name       = new_name,
-       };
-       struct rpc_message msg = {
-               .rpc_proc       = &nfs_procedures[NFSPROC_RENAME],
-               .rpc_argp       = &arg,
-       };
-       int                     status;
-
-       dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
-       status = rpc_call_sync(NFS_CLIENT(old_dir), &msg, 0);
-       nfs_mark_for_revalidate(old_dir);
-       nfs_mark_for_revalidate(new_dir);
-       dprintk("NFS reply rename: %d\n", status);
-       return status;
-}
-
 static int
 nfs_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
 {
@@ -745,7 +721,6 @@ const struct nfs_rpc_ops nfs_v2_clientops = {
        .unlink_setup   = nfs_proc_unlink_setup,
        .unlink_rpc_prepare = nfs_proc_unlink_rpc_prepare,
        .unlink_done    = nfs_proc_unlink_done,
-       .rename         = nfs_proc_rename,
        .rename_setup   = nfs_proc_rename_setup,
        .rename_rpc_prepare = nfs_proc_rename_rpc_prepare,
        .rename_done    = nfs_proc_rename_done,
index 11d7894..de54129 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/namei.h>
+#include <linux/fsnotify.h>
 
 #include "internal.h"
 #include "nfs4_fs.h"
@@ -353,8 +354,8 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata)
                return;
        }
 
-       if (task->tk_status != 0)
-               nfs_cancel_async_unlink(old_dentry);
+       if (data->complete)
+               data->complete(task, data);
 }
 
 /**
@@ -399,9 +400,10 @@ static const struct rpc_call_ops nfs_rename_ops = {
  *
  * It's expected that valid references to the dentries and inodes are held
  */
-static struct rpc_task *
+struct rpc_task *
 nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
-                struct dentry *old_dentry, struct dentry *new_dentry)
+                struct dentry *old_dentry, struct dentry *new_dentry,
+                void (*complete)(struct rpc_task *, struct nfs_renamedata *))
 {
        struct nfs_renamedata *data;
        struct rpc_message msg = { };
@@ -438,6 +440,7 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
        data->new_dentry = dget(new_dentry);
        nfs_fattr_init(&data->old_fattr);
        nfs_fattr_init(&data->new_fattr);
+       data->complete = complete;
 
        /* set up nfs_renameargs */
        data->args.old_dir = NFS_FH(old_dir);
@@ -456,6 +459,27 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir,
        return rpc_run_task(&task_setup_data);
 }
 
+/*
+ * Perform tasks needed when a sillyrename is done such as cancelling the
+ * queued async unlink if it failed.
+ */
+static void
+nfs_complete_sillyrename(struct rpc_task *task, struct nfs_renamedata *data)
+{
+       struct dentry *dentry = data->old_dentry;
+
+       if (task->tk_status != 0) {
+               nfs_cancel_async_unlink(dentry);
+               return;
+       }
+
+       /*
+        * vfs_unlink and the like do not issue this when a file is
+        * sillyrenamed, so do it here.
+        */
+       fsnotify_nameremove(dentry, 0);
+}
+
 #define SILLYNAME_PREFIX ".nfs"
 #define SILLYNAME_PREFIX_LEN ((unsigned)sizeof(SILLYNAME_PREFIX) - 1)
 #define SILLYNAME_FILEID_LEN ((unsigned)sizeof(u64) << 1)
@@ -548,7 +572,8 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry)
        }
 
        /* run the rename task, undo unlink if it fails */
-       task = nfs_async_rename(dir, dir, dentry, sdentry);
+       task = nfs_async_rename(dir, dir, dentry, sdentry,
+                                       nfs_complete_sillyrename);
        if (IS_ERR(task)) {
                error = -EBUSY;
                nfs_cancel_async_unlink(dentry);
index a812fd1..b481e1f 100644 (file)
@@ -39,9 +39,13 @@ struct nfs4_acl;
 struct svc_fh;
 struct svc_rqst;
 
-/* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to
- * fit in a page: */
-#define NFS4_ACL_MAX 170
+/*
+ * Maximum ACL we'll accept from a client; chosen (somewhat
+ * arbitrarily) so that kmalloc'ing the ACL shouldn't require a
+ * high-order allocation.  This allows 204 ACEs on x86_64:
+ */
+#define NFS4_ACL_MAX ((PAGE_SIZE - sizeof(struct nfs4_acl)) \
+                       / sizeof(struct nfs4_ace))
 
 struct nfs4_acl *nfs4_acl_new(int);
 int nfs4_acl_get_whotype(char *, u32);
index d190e33..6f3f392 100644 (file)
@@ -542,7 +542,10 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
         * up setting a 3-element effective posix ACL with all
         * permissions zero.
         */
-       nace = 4 + state->users->n + state->groups->n;
+       if (!state->users->n && !state->groups->n)
+               nace = 3;
+       else /* Note we also include a MASK ACE in this case: */
+               nace = 4 + state->users->n + state->groups->n;
        pacl = posix_acl_alloc(nace, GFP_KERNEL);
        if (!pacl)
                return ERR_PTR(-ENOMEM);
@@ -586,9 +589,11 @@ posix_state_to_acl(struct posix_acl_state *state, unsigned int flags)
                add_to_mask(state, &state->groups->aces[i].perms);
        }
 
-       pace++;
-       pace->e_tag = ACL_MASK;
-       low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
+       if (!state->users->n && !state->groups->n) {
+               pace++;
+               pace->e_tag = ACL_MASK;
+               low_mode_from_nfs4(state->mask.allow, &pace->e_perm, flags);
+       }
 
        pace++;
        pace->e_tag = ACL_OTHER;
index 7f05cd1..39c8ef8 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 #include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/xprt.h>
 #include <linux/sunrpc/svc_xprt.h>
 #include <linux/slab.h>
 #include "nfsd.h"
@@ -635,6 +636,22 @@ static struct rpc_cred *get_backchannel_cred(struct nfs4_client *clp, struct rpc
        }
 }
 
+static struct rpc_clnt *create_backchannel_client(struct rpc_create_args *args)
+{
+       struct rpc_xprt *xprt;
+
+       if (args->protocol != XPRT_TRANSPORT_BC_TCP)
+               return rpc_create(args);
+
+       xprt = args->bc_xprt->xpt_bc_xprt;
+       if (xprt) {
+               xprt_get(xprt);
+               return rpc_create_xprt(args, xprt);
+       }
+
+       return rpc_create(args);
+}
+
 static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *conn, struct nfsd4_session *ses)
 {
        struct rpc_timeout      timeparms = {
@@ -674,7 +691,7 @@ static int setup_callback_client(struct nfs4_client *clp, struct nfs4_cb_conn *c
                args.authflavor = ses->se_cb_sec.flavor;
        }
        /* Create RPC client */
-       client = rpc_create(&args);
+       client = create_backchannel_client(&args);
        if (IS_ERR(client)) {
                dprintk("NFSD: couldn't create callback client: %ld\n",
                        PTR_ERR(client));
index 82189b2..d543222 100644 (file)
@@ -1273,6 +1273,8 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
        struct nfsd4_op *op;
        struct nfsd4_operation *opdesc;
        struct nfsd4_compound_state *cstate = &resp->cstate;
+       struct svc_fh *current_fh = &cstate->current_fh;
+       struct svc_fh *save_fh = &cstate->save_fh;
        int             slack_bytes;
        u32             plen = 0;
        __be32          status;
@@ -1288,11 +1290,11 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
        resp->tag = args->tag;
        resp->opcnt = 0;
        resp->rqstp = rqstp;
-       resp->cstate.minorversion = args->minorversion;
-       resp->cstate.replay_owner = NULL;
-       resp->cstate.session = NULL;
-       fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
-       fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
+       cstate->minorversion = args->minorversion;
+       cstate->replay_owner = NULL;
+       cstate->session = NULL;
+       fh_init(current_fh, NFS4_FHSIZE);
+       fh_init(save_fh, NFS4_FHSIZE);
        /*
         * Don't use the deferral mechanism for NFSv4; compounds make it
         * too hard to avoid non-idempotency problems.
@@ -1345,20 +1347,28 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
 
                opdesc = OPDESC(op);
 
-               if (!cstate->current_fh.fh_dentry) {
+               if (!current_fh->fh_dentry) {
                        if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
                                op->status = nfserr_nofilehandle;
                                goto encode_op;
                        }
-               } else if (cstate->current_fh.fh_export->ex_fslocs.migrated &&
+               } else if (current_fh->fh_export->ex_fslocs.migrated &&
                          !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
                        op->status = nfserr_moved;
                        goto encode_op;
                }
 
+               fh_clear_wcc(current_fh);
+
                /* If op is non-idempotent */
                if (opdesc->op_flags & OP_MODIFIES_SOMETHING) {
                        plen = opdesc->op_rsize_bop(rqstp, op);
+                       /*
+                        * If there's still another operation, make sure
+                        * we'll have space to at least encode an error:
+                        */
+                       if (resp->opcnt < args->opcnt)
+                               plen += COMPOUND_ERR_SLACK_SPACE;
                        op->status = nfsd4_check_resp_size(resp, plen);
                }
 
@@ -1377,12 +1387,12 @@ nfsd4_proc_compound(struct svc_rqst *rqstp,
                                clear_current_stateid(cstate);
 
                        if (need_wrongsec_check(rqstp))
-                               op->status = check_nfsd_access(cstate->current_fh.fh_export, rqstp);
+                               op->status = check_nfsd_access(current_fh->fh_export, rqstp);
                }
 
 encode_op:
                /* Only from SEQUENCE */
-               if (resp->cstate.status == nfserr_replay_cache) {
+               if (cstate->status == nfserr_replay_cache) {
                        dprintk("%s NFS4.1 replay from cache\n", __func__);
                        status = op->status;
                        goto out;
@@ -1411,10 +1421,10 @@ encode_op:
                nfsd4_increment_op_stats(op->opnum);
        }
 
-       resp->cstate.status = status;
-       fh_put(&resp->cstate.current_fh);
-       fh_put(&resp->cstate.save_fh);
-       BUG_ON(resp->cstate.replay_owner);
+       cstate->status = status;
+       fh_put(current_fh);
+       fh_put(save_fh);
+       BUG_ON(cstate->replay_owner);
 out:
        /* Reset deferral mechanism for RPC deferrals */
        rqstp->rq_usedeferral = 1;
@@ -1523,7 +1533,8 @@ static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *o
 
 static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 {
-       return (op_encode_hdr_size + 2 + 1024) * sizeof(__be32);
+       return (op_encode_hdr_size + 2 + XDR_QUADLEN(NFS4_VERIFIER_SIZE)) *
+                                                               sizeof(__be32);
 }
 
 static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
index d5d070f..3ba6597 100644 (file)
@@ -1538,7 +1538,7 @@ out_err:
 }
 
 /*
- * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size.
+ * Cache a reply. nfsd4_check_resp_size() has bounded the cache size.
  */
 void
 nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
@@ -1596,7 +1596,7 @@ nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
  * The sequence operation is not cached because we can use the slot and
  * session values.
  */
-__be32
+static __be32
 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
                         struct nfsd4_sequence *seq)
 {
@@ -1605,9 +1605,8 @@ nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
 
        dprintk("--> %s slot %p\n", __func__, slot);
 
-       /* Either returns 0 or nfserr_retry_uncached */
        status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
-       if (status == nfserr_retry_uncached_rep)
+       if (status)
                return status;
 
        /* The sequence operation has been encoded, cstate->datap set. */
@@ -2287,7 +2286,8 @@ out:
        if (!list_empty(&clp->cl_revoked))
                seq->status_flags |= SEQ4_STATUS_RECALLABLE_STATE_REVOKED;
 out_no_session:
-       kfree(conn);
+       if (conn)
+               free_conn(conn);
        spin_unlock(&nn->client_lock);
        return status;
 out_put_session:
@@ -3627,8 +3627,11 @@ static __be32 nfsd4_lookup_stateid(stateid_t *stateid, unsigned char typemask,
                return nfserr_bad_stateid;
        status = lookup_clientid(&stateid->si_opaque.so_clid, sessions,
                                                        nn, &cl);
-       if (status == nfserr_stale_clientid)
+       if (status == nfserr_stale_clientid) {
+               if (sessions)
+                       return nfserr_bad_stateid;
                return nfserr_stale_stateid;
+       }
        if (status)
                return status;
        *s = find_stateid_by_type(cl, stateid, typemask);
@@ -5062,7 +5065,6 @@ nfs4_state_destroy_net(struct net *net)
        int i;
        struct nfs4_client *clp = NULL;
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
-       struct rb_node *node, *tmp;
 
        for (i = 0; i < CLIENT_HASH_SIZE; i++) {
                while (!list_empty(&nn->conf_id_hashtbl[i])) {
@@ -5071,13 +5073,11 @@ nfs4_state_destroy_net(struct net *net)
                }
        }
 
-       node = rb_first(&nn->unconf_name_tree);
-       while (node != NULL) {
-               tmp = node;
-               node = rb_next(tmp);
-               clp = rb_entry(tmp, struct nfs4_client, cl_namenode);
-               rb_erase(tmp, &nn->unconf_name_tree);
-               destroy_client(clp);
+       for (i = 0; i < CLIENT_HASH_SIZE; i++) {
+               while (!list_empty(&nn->unconf_id_hashtbl[i])) {
+                       clp = list_entry(nn->unconf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
+                       destroy_client(clp);
+               }
        }
 
        kfree(nn->sessionid_hashtbl);
index 63f2395..2723c1b 100644 (file)
@@ -294,7 +294,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                READ32(nace);
 
                if (nace > NFS4_ACL_MAX)
-                       return nfserr_resource;
+                       return nfserr_fbig;
 
                *acl = nfs4_acl_new(nace);
                if (*acl == NULL)
@@ -1222,7 +1222,6 @@ nfsd4_decode_write(struct nfsd4_compoundargs *argp, struct nfsd4_write *write)
        }
        write->wr_head.iov_base = p;
        write->wr_head.iov_len = avail;
-       WARN_ON(avail != (XDR_QUADLEN(avail) << 2));
        write->wr_pagelist = argp->pagelist;
 
        len = XDR_QUADLEN(write->wr_buflen) << 2;
@@ -2483,6 +2482,8 @@ out_acl:
                        goto out;
        }
        if (bmval2 & FATTR4_WORD2_SUPPATTR_EXCLCREAT) {
+               if ((buflen -= 16) < 0)
+                       goto out_resource;
                WRITE32(3);
                WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD0);
                WRITE32(NFSD_SUPPATTR_EXCLCREAT_WORD1);
@@ -2499,8 +2500,10 @@ out:
                security_release_secctx(context, contextlen);
 #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
        kfree(acl);
-       if (tempfh)
+       if (tempfh) {
                fh_put(tempfh);
+               kfree(tempfh);
+       }
        return status;
 out_nfserr:
        status = nfserrno(err);
@@ -3471,6 +3474,9 @@ nfsd4_encode_test_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
        struct nfsd4_test_stateid_id *stateid, *next;
        __be32 *p;
 
+       if (nfserr)
+               return nfserr;
+
        RESERVE_SPACE(4 + (4 * test_stateid->ts_num_ids));
        *p++ = htonl(test_stateid->ts_num_ids);
 
@@ -3579,8 +3585,6 @@ __be32 nfsd4_check_resp_size(struct nfsd4_compoundres *resp, u32 pad)
                return 0;
 
        session = resp->cstate.session;
-       if (session == NULL)
-               return 0;
 
        if (xb->page_len == 0) {
                length = (char *)resp->p - (char *)xb->head[0].iov_base + pad;
@@ -3620,9 +3624,17 @@ nfsd4_encode_operation(struct nfsd4_compoundres *resp, struct nfsd4_op *op)
        BUG_ON(op->opnum < 0 || op->opnum >= ARRAY_SIZE(nfsd4_enc_ops) ||
               !nfsd4_enc_ops[op->opnum]);
        op->status = nfsd4_enc_ops[op->opnum](resp, op->status, &op->u);
-       /* nfsd4_check_drc_limit guarantees enough room for error status */
+       /* nfsd4_check_resp_size guarantees enough room for error status */
        if (!op->status)
                op->status = nfsd4_check_resp_size(resp, 0);
+       if (op->status == nfserr_resource && nfsd4_has_session(&resp->cstate)) {
+               struct nfsd4_slot *slot = resp->cstate.slot;
+
+               if (slot->sl_flags & NFSD4_SLOT_CACHETHIS)
+                       op->status = nfserr_rep_too_big_to_cache;
+               else
+                       op->status = nfserr_rep_too_big;
+       }
        if (so) {
                so->so_replay.rp_status = op->status;
                so->so_replay.rp_buflen = (char *)resp->p - (char *)(statp+1);
@@ -3691,6 +3703,12 @@ int nfsd4_release_compoundargs(void *rq, __be32 *p, void *resp)
 int
 nfs4svc_decode_compoundargs(struct svc_rqst *rqstp, __be32 *p, struct nfsd4_compoundargs *args)
 {
+       if (rqstp->rq_arg.head[0].iov_len % 4) {
+               /* client is nuts */
+               dprintk("%s: compound not properly padded! (peeraddr=%pISc xid=0x%x)",
+                       __func__, svc_addr(rqstp), be32_to_cpu(rqstp->rq_xid));
+               return 0;
+       }
        args->p = p;
        args->end = rqstp->rq_arg.head[0].iov_base + rqstp->rq_arg.head[0].iov_len;
        args->pagelist = rqstp->rq_arg.pages;
index 7f55517..f34d9de 100644 (file)
@@ -699,6 +699,11 @@ static ssize_t __write_ports_addfd(char *buf, struct net *net)
        if (err != 0 || fd < 0)
                return -EINVAL;
 
+       if (svc_alien_sock(net, fd)) {
+               printk(KERN_ERR "%s: socket net is different to NFSd's one\n", __func__);
+               return -EINVAL;
+       }
+
        err = nfsd_create_serv(net);
        if (err != 0)
                return err;
index 30f34ab..479eb68 100644 (file)
@@ -282,7 +282,7 @@ void                nfsd_lockd_shutdown(void);
  * reason.
  */
 #define        COMPOUND_SLACK_SPACE            140    /* OP_GETFH */
-#define COMPOUND_ERR_SLACK_SPACE       12     /* OP_SETATTR */
+#define COMPOUND_ERR_SLACK_SPACE       16     /* OP_SETATTR */
 
 #define NFSD_LAUNDROMAT_MINTIMEOUT      1   /* seconds */
 
index 4775bc4..ad67964 100644 (file)
@@ -132,6 +132,17 @@ fh_init(struct svc_fh *fhp, int maxsize)
 }
 
 #ifdef CONFIG_NFSD_V3
+/*
+ * The wcc data stored in current_fh should be cleared
+ * between compound ops.
+ */
+static inline void
+fh_clear_wcc(struct svc_fh *fhp)
+{
+       fhp->fh_post_saved = 0;
+       fhp->fh_pre_saved = 0;
+}
+
 /*
  * Fill in the pre_op attr for the wcc data
  */
@@ -152,7 +163,8 @@ fill_pre_wcc(struct svc_fh *fhp)
 
 extern void fill_post_wcc(struct svc_fh *);
 #else
-#define        fill_pre_wcc(ignored)
+#define fh_clear_wcc(ignored)
+#define fill_pre_wcc(ignored)
 #define fill_post_wcc(notused)
 #endif /* CONFIG_NFSD_V3 */
 
index b17d932..9c769a4 100644 (file)
@@ -152,7 +152,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
        type = (stat->mode & S_IFMT);
 
        *p++ = htonl(nfs_ftypes[type >> 12]);
-       *p++ = htonl((u32) (stat->mode & S_IALLUGO));
+       *p++ = htonl((u32) stat->mode);
        *p++ = htonl((u32) stat->nlink);
        *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
        *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
index 915808b..16f0673 100644 (file)
@@ -404,6 +404,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        umode_t         ftype = 0;
        __be32          err;
        int             host_err;
+       bool            get_write_count;
        int             size_change = 0;
 
        if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
@@ -411,10 +412,18 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
        if (iap->ia_valid & ATTR_SIZE)
                ftype = S_IFREG;
 
+       /* Callers that do fh_verify should do the fh_want_write: */
+       get_write_count = !fhp->fh_dentry;
+
        /* Get inode */
        err = fh_verify(rqstp, fhp, ftype, accmode);
        if (err)
                goto out;
+       if (get_write_count) {
+               host_err = fh_want_write(fhp);
+               if (host_err)
+                       return nfserrno(host_err);
+       }
 
        dentry = fhp->fh_dentry;
        inode = dentry->d_inode;
@@ -1706,10 +1715,10 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        dput(odentry);
  out_nfserr:
        err = nfserrno(host_err);
-
-       /* we cannot reply on fh_unlock on the two filehandles,
+       /*
+        * We cannot rely on fh_unlock on the two filehandles,
         * as that would do the wrong thing if the two directories
-        * were the same, so again we do it by hand
+        * were the same, so again we do it by hand.
         */
        fill_post_wcc(ffhp);
        fill_post_wcc(tfhp);
index d278a0d..5ea7df3 100644 (file)
@@ -574,8 +574,6 @@ extern __be32 nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
                struct nfsd4_compound_state *,
                struct nfsd4_setclientid_confirm *setclientid_confirm);
 extern void nfsd4_store_cache_entry(struct nfsd4_compoundres *resp);
-extern __be32 nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
-               struct nfsd4_sequence *seq);
 extern __be32 nfsd4_exchange_id(struct svc_rqst *rqstp,
                struct nfsd4_compound_state *, struct nfsd4_exchange_id *);
 extern __be32 nfsd4_backchannel_ctl(struct svc_rqst *, struct nfsd4_compound_state *, struct nfsd4_backchannel_ctl *);
index 08fdb77..f3a82fb 100644 (file)
@@ -134,6 +134,7 @@ static int nilfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 
 static const struct vm_operations_struct nilfs_file_vm_ops = {
        .fault          = filemap_fault,
+       .map_pages      = filemap_map_pages,
        .page_mkwrite   = nilfs_page_mkwrite,
        .remap_pages    = generic_file_remap_pages,
 };
index 807150e..dd6103c 100644 (file)
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
-
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 #include "debug.h"
 
-/*
- * A static buffer to hold the error string being displayed and a spinlock
- * to protect concurrent accesses to it.
- */
-static char err_buf[1024];
-static DEFINE_SPINLOCK(err_buf_lock);
-
 /**
  * __ntfs_warning - output a warning to the syslog
  * @function:  name of function outputting the warning
@@ -50,6 +43,7 @@ static DEFINE_SPINLOCK(err_buf_lock);
 void __ntfs_warning(const char *function, const struct super_block *sb,
                const char *fmt, ...)
 {
+       struct va_format vaf;
        va_list args;
        int flen = 0;
 
@@ -59,17 +53,15 @@ void __ntfs_warning(const char *function, const struct super_block *sb,
 #endif
        if (function)
                flen = strlen(function);
-       spin_lock(&err_buf_lock);
        va_start(args, fmt);
-       vsnprintf(err_buf, sizeof(err_buf), fmt, args);
-       va_end(args);
+       vaf.fmt = fmt;
+       vaf.va = &args;
        if (sb)
-               printk(KERN_ERR "NTFS-fs warning (device %s): %s(): %s\n",
-                               sb->s_id, flen ? function : "", err_buf);
+               pr_warn("(device %s): %s(): %pV\n",
+                       sb->s_id, flen ? function : "", &vaf);
        else
-               printk(KERN_ERR "NTFS-fs warning: %s(): %s\n",
-                               flen ? function : "", err_buf);
-       spin_unlock(&err_buf_lock);
+               pr_warn("%s(): %pV\n", flen ? function : "", &vaf);
+       va_end(args);
 }
 
 /**
@@ -94,6 +86,7 @@ void __ntfs_warning(const char *function, const struct super_block *sb,
 void __ntfs_error(const char *function, const struct super_block *sb,
                const char *fmt, ...)
 {
+       struct va_format vaf;
        va_list args;
        int flen = 0;
 
@@ -103,17 +96,15 @@ void __ntfs_error(const char *function, const struct super_block *sb,
 #endif
        if (function)
                flen = strlen(function);
-       spin_lock(&err_buf_lock);
        va_start(args, fmt);
-       vsnprintf(err_buf, sizeof(err_buf), fmt, args);
-       va_end(args);
+       vaf.fmt = fmt;
+       vaf.va = &args;
        if (sb)
-               printk(KERN_ERR "NTFS-fs error (device %s): %s(): %s\n",
-                               sb->s_id, flen ? function : "", err_buf);
+               pr_err("(device %s): %s(): %pV\n",
+                      sb->s_id, flen ? function : "", &vaf);
        else
-               printk(KERN_ERR "NTFS-fs error: %s(): %s\n",
-                               flen ? function : "", err_buf);
-       spin_unlock(&err_buf_lock);
+               pr_err("%s(): %pV\n", flen ? function : "", &vaf);
+       va_end(args);
 }
 
 #ifdef DEBUG
@@ -124,6 +115,7 @@ int debug_msgs = 0;
 void __ntfs_debug (const char *file, int line, const char *function,
                const char *fmt, ...)
 {
+       struct va_format vaf;
        va_list args;
        int flen = 0;
 
@@ -131,13 +123,11 @@ void __ntfs_debug (const char *file, int line, const char *function,
                return;
        if (function)
                flen = strlen(function);
-       spin_lock(&err_buf_lock);
        va_start(args, fmt);
-       vsnprintf(err_buf, sizeof(err_buf), fmt, args);
+       vaf.fmt = fmt;
+       vaf.va = &args;
+       pr_debug("(%s, %d): %s(): %pV", file, line, flen ? function : "", &vaf);
        va_end(args);
-       printk(KERN_DEBUG "NTFS-fs DEBUG (%s, %d): %s(): %s\n", file, line,
-                       flen ? function : "", err_buf);
-       spin_unlock(&err_buf_lock);
 }
 
 /* Dump a runlist. Caller has to provide synchronisation for @rl. */
@@ -149,12 +139,12 @@ void ntfs_debug_dump_runlist(const runlist_element *rl)
 
        if (!debug_msgs)
                return;
-       printk(KERN_DEBUG "NTFS-fs DEBUG: Dumping runlist (values in hex):\n");
+       pr_debug("Dumping runlist (values in hex):\n");
        if (!rl) {
-               printk(KERN_DEBUG "Run list not present.\n");
+               pr_debug("Run list not present.\n");
                return;
        }
-       printk(KERN_DEBUG "VCN              LCN               Run length\n");
+       pr_debug("VCN              LCN               Run length\n");
        for (i = 0; ; i++) {
                LCN lcn = (rl + i)->lcn;
 
@@ -163,13 +153,13 @@ void ntfs_debug_dump_runlist(const runlist_element *rl)
 
                        if (index > -LCN_ENOENT - 1)
                                index = 3;
-                       printk(KERN_DEBUG "%-16Lx %s %-16Lx%s\n",
+                       pr_debug("%-16Lx %s %-16Lx%s\n",
                                        (long long)(rl + i)->vcn, lcn_str[index],
                                        (long long)(rl + i)->length,
                                        (rl + i)->length ? "" :
                                                " (runlist end)");
                } else
-                       printk(KERN_DEBUG "%-16Lx %-16Lx  %-16Lx%s\n",
+                       pr_debug("%-16Lx %-16Lx  %-16Lx%s\n",
                                        (long long)(rl + i)->vcn,
                                        (long long)(rl + i)->lcn,
                                        (long long)(rl + i)->length,
index 53c27ea..61bf091 100644 (file)
@@ -48,7 +48,12 @@ extern void ntfs_debug_dump_runlist(const runlist_element *rl);
 
 #else  /* !DEBUG */
 
-#define ntfs_debug(f, a...)            do {} while (0)
+#define ntfs_debug(fmt, ...)                                           \
+do {                                                                   \
+       if (0)                                                          \
+               no_printk(fmt, ##__VA_ARGS__);                          \
+} while (0)
+
 #define ntfs_debug_dump_runlist(rl)    do {} while (0)
 
 #endif /* !DEBUG */
index bd5610d..9de2491 100644 (file)
@@ -19,6 +19,7 @@
  * distribution in the file COPYING); if not, write to the Free Software
  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/stddef.h>
 #include <linux/init.h>
@@ -1896,7 +1897,7 @@ get_ctx_vol_failed:
        vol->minor_ver = vi->minor_ver;
        ntfs_attr_put_search_ctx(ctx);
        unmap_mft_record(NTFS_I(vol->vol_ino));
-       printk(KERN_INFO "NTFS volume version %i.%i.\n", vol->major_ver,
+       pr_info("volume version %i.%i.\n", vol->major_ver,
                        vol->minor_ver);
        if (vol->major_ver < 3 && NVolSparseEnabled(vol)) {
                ntfs_warning(vol->sb, "Disabling sparse support due to NTFS "
@@ -3095,7 +3096,7 @@ static int __init init_ntfs_fs(void)
        int err = 0;
 
        /* This may be ugly but it results in pretty output so who cares. (-8 */
-       printk(KERN_INFO "NTFS driver " NTFS_VERSION " [Flags: R/"
+       pr_info("driver " NTFS_VERSION " [Flags: R/"
 #ifdef NTFS_RW
                        "W"
 #else
@@ -3115,16 +3116,15 @@ static int __init init_ntfs_fs(void)
                        sizeof(ntfs_index_context), 0 /* offset */,
                        SLAB_HWCACHE_ALIGN, NULL /* ctor */);
        if (!ntfs_index_ctx_cache) {
-               printk(KERN_CRIT "NTFS: Failed to create %s!\n",
-                               ntfs_index_ctx_cache_name);
+               pr_crit("Failed to create %s!\n", ntfs_index_ctx_cache_name);
                goto ictx_err_out;
        }
        ntfs_attr_ctx_cache = kmem_cache_create(ntfs_attr_ctx_cache_name,
                        sizeof(ntfs_attr_search_ctx), 0 /* offset */,
                        SLAB_HWCACHE_ALIGN, NULL /* ctor */);
        if (!ntfs_attr_ctx_cache) {
-               printk(KERN_CRIT "NTFS: Failed to create %s!\n",
-                               ntfs_attr_ctx_cache_name);
+               pr_crit("NTFS: Failed to create %s!\n",
+                       ntfs_attr_ctx_cache_name);
                goto actx_err_out;
        }
 
@@ -3132,8 +3132,7 @@ static int __init init_ntfs_fs(void)
                        (NTFS_MAX_NAME_LEN+1) * sizeof(ntfschar), 0,
                        SLAB_HWCACHE_ALIGN, NULL);
        if (!ntfs_name_cache) {
-               printk(KERN_CRIT "NTFS: Failed to create %s!\n",
-                               ntfs_name_cache_name);
+               pr_crit("Failed to create %s!\n", ntfs_name_cache_name);
                goto name_err_out;
        }
 
@@ -3141,8 +3140,7 @@ static int __init init_ntfs_fs(void)
                        sizeof(ntfs_inode), 0,
                        SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD, NULL);
        if (!ntfs_inode_cache) {
-               printk(KERN_CRIT "NTFS: Failed to create %s!\n",
-                               ntfs_inode_cache_name);
+               pr_crit("Failed to create %s!\n", ntfs_inode_cache_name);
                goto inode_err_out;
        }
 
@@ -3151,15 +3149,14 @@ static int __init init_ntfs_fs(void)
                        SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD,
                        ntfs_big_inode_init_once);
        if (!ntfs_big_inode_cache) {
-               printk(KERN_CRIT "NTFS: Failed to create %s!\n",
-                               ntfs_big_inode_cache_name);
+               pr_crit("Failed to create %s!\n", ntfs_big_inode_cache_name);
                goto big_inode_err_out;
        }
 
        /* Register the ntfs sysctls. */
        err = ntfs_sysctl(1);
        if (err) {
-               printk(KERN_CRIT "NTFS: Failed to register NTFS sysctls!\n");
+               pr_crit("Failed to register NTFS sysctls!\n");
                goto sysctl_err_out;
        }
 
@@ -3168,7 +3165,7 @@ static int __init init_ntfs_fs(void)
                ntfs_debug("NTFS driver registered successfully.");
                return 0; /* Success! */
        }
-       printk(KERN_CRIT "NTFS: Failed to register NTFS filesystem driver!\n");
+       pr_crit("Failed to register NTFS filesystem driver!\n");
 
        /* Unregister the ntfs sysctls. */
        ntfs_sysctl(0);
@@ -3184,8 +3181,7 @@ actx_err_out:
        kmem_cache_destroy(ntfs_index_ctx_cache);
 ictx_err_out:
        if (!err) {
-               printk(KERN_CRIT "NTFS: Aborting NTFS filesystem driver "
-                               "registration...\n");
+               pr_crit("Aborting NTFS filesystem driver registration...\n");
                err = -ENOMEM;
        }
        return err;
index a4b0773..b7f5727 100644 (file)
@@ -41,7 +41,7 @@ static ssize_t version_show(struct kobject *kobj, struct kobj_attribute *attr,
        return snprintf(buf, PAGE_SIZE, "%u\n", O2NM_API_VERSION);
 }
 static struct kobj_attribute attr_version =
-       __ATTR(interface_revision, S_IFREG | S_IRUGO, version_show, NULL);
+       __ATTR(interface_revision, S_IRUGO, version_show, NULL);
 
 static struct attribute *o2cb_attrs[] = {
        &attr_version.attr,
index 5c8343f..83f1a66 100644 (file)
@@ -496,7 +496,7 @@ static ssize_t ocfs2_max_locking_protocol_show(struct kobject *kobj,
 }
 
 static struct kobj_attribute ocfs2_attr_max_locking_protocol =
-       __ATTR(max_locking_protocol, S_IFREG | S_IRUGO,
+       __ATTR(max_locking_protocol, S_IRUGO,
               ocfs2_max_locking_protocol_show, NULL);
 
 static ssize_t ocfs2_loaded_cluster_plugins_show(struct kobject *kobj,
@@ -528,7 +528,7 @@ static ssize_t ocfs2_loaded_cluster_plugins_show(struct kobject *kobj,
 }
 
 static struct kobj_attribute ocfs2_attr_loaded_cluster_plugins =
-       __ATTR(loaded_cluster_plugins, S_IFREG | S_IRUGO,
+       __ATTR(loaded_cluster_plugins, S_IRUGO,
               ocfs2_loaded_cluster_plugins_show, NULL);
 
 static ssize_t ocfs2_active_cluster_plugin_show(struct kobject *kobj,
@@ -550,7 +550,7 @@ static ssize_t ocfs2_active_cluster_plugin_show(struct kobject *kobj,
 }
 
 static struct kobj_attribute ocfs2_attr_active_cluster_plugin =
-       __ATTR(active_cluster_plugin, S_IFREG | S_IRUGO,
+       __ATTR(active_cluster_plugin, S_IRUGO,
               ocfs2_active_cluster_plugin_show, NULL);
 
 static ssize_t ocfs2_cluster_stack_show(struct kobject *kobj,
@@ -599,7 +599,7 @@ static ssize_t ocfs2_cluster_stack_store(struct kobject *kobj,
 
 
 static struct kobj_attribute ocfs2_attr_cluster_stack =
-       __ATTR(cluster_stack, S_IFREG | S_IRUGO | S_IWUSR,
+       __ATTR(cluster_stack, S_IRUGO | S_IWUSR,
               ocfs2_cluster_stack_show,
               ocfs2_cluster_stack_store);
 
index 656e401..64db2bc 100644 (file)
@@ -138,8 +138,8 @@ static const char * const task_state_array[] = {
        "D (disk sleep)",       /*   2 */
        "T (stopped)",          /*   4 */
        "t (tracing stop)",     /*   8 */
-       "Z (zombie)",           /*  16 */
-       "X (dead)",             /*  32 */
+       "X (dead)",             /*  16 */
+       "Z (zombie)",           /*  32 */
 };
 
 static inline const char *get_task_state(struct task_struct *tsk)
index b976062..6b7087e 100644 (file)
@@ -1236,6 +1236,9 @@ static ssize_t proc_fault_inject_write(struct file * file,
        make_it_fail = simple_strtol(strstrip(buffer), &end, 0);
        if (*end)
                return -EINVAL;
+       if (make_it_fail < 0 || make_it_fail > 1)
+               return -EINVAL;
+
        task = get_proc_task(file_inode(file));
        if (!task)
                return -ESRCH;
@@ -2588,7 +2591,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        REG("environ",    S_IRUSR, proc_environ_operations),
        INF("auxv",       S_IRUSR, proc_pid_auxv),
        ONE("status",     S_IRUGO, proc_pid_status),
-       ONE("personality", S_IRUGO, proc_pid_personality),
+       ONE("personality", S_IRUSR, proc_pid_personality),
        INF("limits",     S_IRUGO, proc_pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",      S_IRUGO|S_IWUSR, proc_pid_sched_operations),
@@ -2598,7 +2601,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 #endif
        REG("comm",      S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
-       INF("syscall",    S_IRUGO, proc_pid_syscall),
+       INF("syscall",    S_IRUSR, proc_pid_syscall),
 #endif
        INF("cmdline",    S_IRUGO, proc_pid_cmdline),
        ONE("stat",       S_IRUGO, proc_tgid_stat),
@@ -2617,7 +2620,7 @@ static const struct pid_entry tgid_base_stuff[] = {
 #ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
        REG("smaps",      S_IRUGO, proc_pid_smaps_operations),
-       REG("pagemap",    S_IRUGO, proc_pagemap_operations),
+       REG("pagemap",    S_IRUSR, proc_pagemap_operations),
 #endif
 #ifdef CONFIG_SECURITY
        DIR("attr",       S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
@@ -2626,7 +2629,7 @@ static const struct pid_entry tgid_base_stuff[] = {
        INF("wchan",      S_IRUGO, proc_pid_wchan),
 #endif
 #ifdef CONFIG_STACKTRACE
-       ONE("stack",      S_IRUGO, proc_pid_stack),
+       ONE("stack",      S_IRUSR, proc_pid_stack),
 #endif
 #ifdef CONFIG_SCHEDSTATS
        INF("schedstat",  S_IRUGO, proc_pid_schedstat),
@@ -2927,14 +2930,14 @@ static const struct pid_entry tid_base_stuff[] = {
        REG("environ",   S_IRUSR, proc_environ_operations),
        INF("auxv",      S_IRUSR, proc_pid_auxv),
        ONE("status",    S_IRUGO, proc_pid_status),
-       ONE("personality", S_IRUGO, proc_pid_personality),
+       ONE("personality", S_IRUSR, proc_pid_personality),
        INF("limits",    S_IRUGO, proc_pid_limits),
 #ifdef CONFIG_SCHED_DEBUG
        REG("sched",     S_IRUGO|S_IWUSR, proc_pid_sched_operations),
 #endif
        REG("comm",      S_IRUGO|S_IWUSR, proc_pid_set_comm_operations),
 #ifdef CONFIG_HAVE_ARCH_TRACEHOOK
-       INF("syscall",   S_IRUGO, proc_pid_syscall),
+       INF("syscall",   S_IRUSR, proc_pid_syscall),
 #endif
        INF("cmdline",   S_IRUGO, proc_pid_cmdline),
        ONE("stat",      S_IRUGO, proc_tid_stat),
@@ -2955,7 +2958,7 @@ static const struct pid_entry tid_base_stuff[] = {
 #ifdef CONFIG_PROC_PAGE_MONITOR
        REG("clear_refs", S_IWUSR, proc_clear_refs_operations),
        REG("smaps",     S_IRUGO, proc_tid_smaps_operations),
-       REG("pagemap",    S_IRUGO, proc_pagemap_operations),
+       REG("pagemap",    S_IRUSR, proc_pagemap_operations),
 #endif
 #ifdef CONFIG_SECURITY
        DIR("attr",      S_IRUGO|S_IXUGO, proc_attr_dir_inode_operations, proc_attr_dir_operations),
@@ -2964,7 +2967,7 @@ static const struct pid_entry tid_base_stuff[] = {
        INF("wchan",     S_IRUGO, proc_pid_wchan),
 #endif
 #ifdef CONFIG_STACKTRACE
-       ONE("stack",      S_IRUGO, proc_pid_stack),
+       ONE("stack",      S_IRUSR, proc_pid_stack),
 #endif
 #ifdef CONFIG_SCHEDSTATS
        INF("schedstat", S_IRUGO, proc_pid_schedstat),
index 985ea88..0788d09 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/proc_fs.h>
 
+#include "../mount.h"
 #include "internal.h"
 #include "fd.h"
 
@@ -48,8 +49,9 @@ static int seq_show(struct seq_file *m, void *v)
        }
 
        if (!ret) {
-                seq_printf(m, "pos:\t%lli\nflags:\t0%o\n",
-                          (long long)file->f_pos, f_flags);
+               seq_printf(m, "pos:\t%lli\nflags:\t0%o\nmnt_id:\t%i\n",
+                          (long long)file->f_pos, f_flags,
+                          real_mount(file->f_path.mnt)->mnt_id);
                if (file->f_op->show_fdinfo)
                        ret = file->f_op->show_fdinfo(m, file);
                fput(file);
index 8f20e34..0adbc02 100644 (file)
@@ -47,7 +47,7 @@ static void proc_evict_inode(struct inode *inode)
                pde_put(de);
        head = PROC_I(inode)->sysctl;
        if (head) {
-               rcu_assign_pointer(PROC_I(inode)->sysctl, NULL);
+               RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL);
                sysctl_head_put(head);
        }
        /* Release any associated namespace */
index 136e548..7445af0 100644 (file)
@@ -73,7 +73,7 @@ static int meminfo_proc_show(struct seq_file *m, void *v)
        available += pagecache;
 
        /*
-        * Part of the reclaimable swap consists of items that are in use,
+        * Part of the reclaimable slab consists of items that are in use,
         * and cannot be freed. Cap this estimate at the low watermark.
         */
        available += global_page_state(NR_SLAB_RECLAIMABLE) -
index fb52b54..442177b 100644 (file)
@@ -1,4 +1,5 @@
 #include <linux/mm.h>
+#include <linux/vmacache.h>
 #include <linux/hugetlb.h>
 #include <linux/huge_mm.h>
 #include <linux/mount.h>
@@ -152,7 +153,7 @@ static void *m_start(struct seq_file *m, loff_t *pos)
 
        /*
         * We remember last_addr rather than next_addr to hit with
-        * mmap_cache most of the time. We have zero last_addr at
+        * vmacache most of the time. We have zero last_addr at
         * the beginning and also after lseek. We will have -1 last_addr
         * after the end of the vmas.
         */
index 88d4585..6a8e785 100644 (file)
@@ -484,7 +484,6 @@ static int __init update_note_header_size_elf64(const Elf64_Ehdr *ehdr_ptr)
                phdr_ptr->p_memsz = real_sz;
                if (real_sz == 0) {
                        pr_warn("Warning: Zero PT_NOTE entries found\n");
-                       return -EINVAL;
                }
        }
 
@@ -671,7 +670,6 @@ static int __init update_note_header_size_elf32(const Elf32_Ehdr *ehdr_ptr)
                phdr_ptr->p_memsz = real_sz;
                if (real_sz == 0) {
                        pr_warn("Warning: Zero PT_NOTE entries found\n");
-                       return -EINVAL;
                }
        }
 
@@ -1118,4 +1116,3 @@ void vmcore_cleanup(void)
        }
        free_elfcorebuf();
 }
-EXPORT_SYMBOL_GPL(vmcore_cleanup);
index 880fd98..c51df1d 100644 (file)
@@ -8,9 +8,10 @@ config QUOTA
        help
          If you say Y here, you will be able to set per user limits for disk
          usage (also called disk quotas). Currently, it works for the
-         ext2, ext3, and reiserfs file system. ext3 also supports journalled
-         quotas for which you don't need to run quotacheck(8) after an unclean
-         shutdown.
+         ext2, ext3, ext4, jfs, ocfs2 and reiserfs file systems.
+         Note that gfs2 and xfs use their own quota system.
+         Ext3, ext4 and reiserfs also support journaled quotas for which
+         you don't need to run quotacheck(8) after an unclean shutdown.
          For further details, read the Quota mini-HOWTO, available from
          <http://www.tldp.org/docs.html#howto>, or the documentation provided
          with the quota tools. Probably the quota support is only useful for
index 1fd2051..af67735 100644 (file)
@@ -125,6 +125,7 @@ int reiserfs_readdir_inode(struct inode *inode, struct dir_context *ctx)
                                int d_reclen;
                                char *d_name;
                                ino_t d_ino;
+                               loff_t cur_pos = deh_offset(deh);
 
                                if (!de_visible(deh))
                                        /* it is hidden entry */
@@ -196,8 +197,9 @@ int reiserfs_readdir_inode(struct inode *inode, struct dir_context *ctx)
                                if (local_buf != small_buf) {
                                        kfree(local_buf);
                                }
-                               // next entry should be looked for with such offset
-                               next_pos = deh_offset(deh) + 1;
+
+                               /* deh_offset(deh) may be invalid now. */
+                               next_pos = cur_pos + 1;
 
                                if (item_moved(&tmp_ih, &path_to_entry)) {
                                        set_cpu_key_k_offset(&pos_key,
index 123c79b..4f34dba 100644 (file)
@@ -1538,6 +1538,7 @@ out_unlock:
 
 static const struct vm_operations_struct ubifs_file_vm_ops = {
        .fault        = filemap_fault,
+       .map_pages = filemap_map_pages,
        .page_mkwrite = ubifs_vm_page_mkwrite,
        .remap_pages = generic_file_remap_pages,
 };
index 64f2b73..3286db0 100644 (file)
@@ -175,7 +175,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        udf_inode_cachep = kmem_cache_create("udf_inode_cache",
                                             sizeof(struct udf_inode_info),
@@ -505,6 +505,7 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
        while ((p = strsep(&options, ",")) != NULL) {
                substring_t args[MAX_OPT_ARGS];
                int token;
+               unsigned n;
                if (!*p)
                        continue;
 
@@ -516,7 +517,10 @@ static int udf_parse_options(char *options, struct udf_options *uopt,
                case Opt_bs:
                        if (match_int(&args[0], &option))
                                return 0;
-                       uopt->blocksize = option;
+                       n = option;
+                       if (n != 512 && n != 1024 && n != 2048 && n != 4096)
+                               return 0;
+                       uopt->blocksize = n;
                        uopt->flags |= (1 << UDF_FLAG_BLOCKSIZE_SET);
                        break;
                case Opt_unhide:
index a7ea492..0ab1de4 100644 (file)
@@ -38,7 +38,6 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
 {
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
        struct ufs_cg_private_info * ucpi;
        struct ufs_cylinder_group * ucg;
        unsigned cgno, bit, end_bit, bbase, blkmap, i;
@@ -46,7 +45,6 @@ void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(uspi);
        
        UFSD("ENTER, fragment %llu, count %u\n",
             (unsigned long long)fragment, count);
@@ -135,7 +133,6 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
 {
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
        struct ufs_cg_private_info * ucpi;
        struct ufs_cylinder_group * ucg;
        unsigned overflow, cgno, bit, end_bit, i;
@@ -143,7 +140,6 @@ void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(uspi);
 
        UFSD("ENTER, fragment %llu, count %u\n",
             (unsigned long long)fragment, count);
@@ -499,7 +495,6 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
 {
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
        struct ufs_cg_private_info * ucpi;
        struct ufs_cylinder_group * ucg;
        unsigned cgno, fragno, fragoff, count, fragsize, i;
@@ -509,7 +504,6 @@ static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
        
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first (uspi);
        count = newcount - oldcount;
        
        cgno = ufs_dtog(uspi, fragment);
@@ -577,7 +571,6 @@ static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
 {
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
        struct ufs_cg_private_info * ucpi;
        struct ufs_cylinder_group * ucg;
        unsigned oldcg, i, j, k, allocsize;
@@ -588,7 +581,6 @@ static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(uspi);
        oldcg = cgno;
        
        /*
@@ -690,7 +682,6 @@ static u64 ufs_alloccg_block(struct inode *inode,
 {
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
        struct ufs_cylinder_group * ucg;
        u64 result, blkno;
 
@@ -698,7 +689,6 @@ static u64 ufs_alloccg_block(struct inode *inode,
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(uspi);
        ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 
        if (goal == 0) {
@@ -794,7 +784,6 @@ static u64 ufs_bitmap_search(struct super_block *sb,
                0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
        };
        struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
-       struct ufs_super_block_first *usb1;
        struct ufs_cylinder_group *ucg;
        unsigned start, length, loc;
        unsigned pos, want, blockmap, mask, end;
@@ -803,7 +792,6 @@ static u64 ufs_bitmap_search(struct super_block *sb,
        UFSD("ENTER, cg %u, goal %llu, count %u\n", ucpi->c_cgx,
             (unsigned long long)goal, count);
 
-       usb1 = ubh_get_usb_first (uspi);
        ucg = ubh_get_ucg(UCPI_UBH(ucpi));
 
        if (goal)
index d0426d7..98f7211 100644 (file)
@@ -57,7 +57,6 @@ void ufs_free_inode (struct inode * inode)
 {
        struct super_block * sb;
        struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
        struct ufs_cg_private_info * ucpi;
        struct ufs_cylinder_group * ucg;
        int is_directory;
@@ -67,7 +66,6 @@ void ufs_free_inode (struct inode * inode)
 
        sb = inode->i_sb;
        uspi = UFS_SB(sb)->s_uspi;
-       usb1 = ubh_get_usb_first(uspi);
        
        ino = inode->i_ino;
 
@@ -175,7 +173,6 @@ struct inode *ufs_new_inode(struct inode *dir, umode_t mode)
        struct super_block * sb;
        struct ufs_sb_info * sbi;
        struct ufs_sb_private_info * uspi;
-       struct ufs_super_block_first * usb1;
        struct ufs_cg_private_info * ucpi;
        struct ufs_cylinder_group * ucg;
        struct inode * inode;
@@ -195,7 +192,6 @@ struct inode *ufs_new_inode(struct inode *dir, umode_t mode)
        ufsi = UFS_I(inode);
        sbi = UFS_SB(sb);
        uspi = sbi->s_uspi;
-       usb1 = ubh_get_usb_first(uspi);
 
        mutex_lock(&sbi->s_lock);
 
index b8c6791..c1183f9 100644 (file)
@@ -524,11 +524,9 @@ static int ufs_read_cylinder_structures(struct super_block *sb)
        struct ufs_buffer_head * ubh;
        unsigned char * base, * space;
        unsigned size, blks, i;
-       struct ufs_super_block_third *usb3;
 
        UFSD("ENTER\n");
 
-       usb3 = ubh_get_usb_third(uspi);
        /*
         * Read cs structures from (usually) first data block
         * on the device. 
@@ -1390,15 +1388,11 @@ static int ufs_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct super_block *sb = dentry->d_sb;
        struct ufs_sb_private_info *uspi= UFS_SB(sb)->s_uspi;
        unsigned  flags = UFS_SB(sb)->s_flags;
-       struct ufs_super_block_first *usb1;
-       struct ufs_super_block_second *usb2;
        struct ufs_super_block_third *usb3;
        u64 id = huge_encode_dev(sb->s_bdev->bd_dev);
 
        lock_ufs(sb);
 
-       usb1 = ubh_get_usb_first(uspi);
-       usb2 = ubh_get_usb_second(uspi);
        usb3 = ubh_get_usb_third(uspi);
        
        if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
@@ -1454,7 +1448,7 @@ static void init_once(void *foo)
        inode_init_once(&ei->vfs_inode);
 }
 
-static int init_inodecache(void)
+static int __init init_inodecache(void)
 {
        ufs_inode_cachep = kmem_cache_create("ufs_inode_cache",
                                             sizeof(struct ufs_inode_info),
index f7abff8..003c005 100644 (file)
@@ -1483,6 +1483,7 @@ const struct file_operations xfs_dir_file_operations = {
 
 static const struct vm_operations_struct xfs_file_vm_ops = {
        .fault          = filemap_fault,
+       .map_pages      = filemap_map_pages,
        .page_mkwrite   = xfs_vm_page_mkwrite,
        .remap_pages    = generic_file_remap_pages,
 };
index 7d10f96..630dd23 100644 (file)
@@ -52,7 +52,7 @@ struct bug_entry {
 #endif
 
 #ifndef HAVE_ARCH_BUG_ON
-#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while(0)
+#define BUG_ON(condition) do { if (unlikely(condition)) BUG(); } while (0)
 #endif
 
 /*
@@ -106,33 +106,6 @@ extern void warn_slowpath_null(const char *file, const int line);
        unlikely(__ret_warn_on);                                        \
 })
 
-#else /* !CONFIG_BUG */
-#ifndef HAVE_ARCH_BUG
-#define BUG() do {} while(0)
-#endif
-
-#ifndef HAVE_ARCH_BUG_ON
-#define BUG_ON(condition) do { if (condition) ; } while(0)
-#endif
-
-#ifndef HAVE_ARCH_WARN_ON
-#define WARN_ON(condition) ({                                          \
-       int __ret_warn_on = !!(condition);                              \
-       unlikely(__ret_warn_on);                                        \
-})
-#endif
-
-#ifndef WARN
-#define WARN(condition, format...) ({                                  \
-       int __ret_warn_on = !!(condition);                              \
-       unlikely(__ret_warn_on);                                        \
-})
-#endif
-
-#define WARN_TAINT(condition, taint, format...) WARN_ON(condition)
-
-#endif
-
 #define WARN_ON_ONCE(condition)        ({                              \
        static bool __section(.data.unlikely) __warned;         \
        int __ret_warn_once = !!(condition);                    \
@@ -163,6 +136,37 @@ extern void warn_slowpath_null(const char *file, const int line);
        unlikely(__ret_warn_once);                              \
 })
 
+#else /* !CONFIG_BUG */
+#ifndef HAVE_ARCH_BUG
+#define BUG() do {} while (1)
+#endif
+
+#ifndef HAVE_ARCH_BUG_ON
+#define BUG_ON(condition) do { if (condition) ; } while (0)
+#endif
+
+#ifndef HAVE_ARCH_WARN_ON
+#define WARN_ON(condition) ({                                          \
+       int __ret_warn_on = !!(condition);                              \
+       unlikely(__ret_warn_on);                                        \
+})
+#endif
+
+#ifndef WARN
+#define WARN(condition, format...) ({                                  \
+       int __ret_warn_on = !!(condition);                              \
+       no_printk(format);                                              \
+       unlikely(__ret_warn_on);                                        \
+})
+#endif
+
+#define WARN_ON_ONCE(condition) WARN_ON(condition)
+#define WARN_ONCE(condition, format...) WARN(condition, format)
+#define WARN_TAINT(condition, taint, format...) WARN(condition, format)
+#define WARN_TAINT_ONCE(condition, taint, format...) WARN(condition, format)
+
+#endif
+
 /*
  * WARN_ON_SMP() is for cases that the warning is either
  * meaningless for !SMP or may even cause failures.
diff --git a/include/asm-generic/early_ioremap.h b/include/asm-generic/early_ioremap.h
new file mode 100644 (file)
index 0000000..a5de55c
--- /dev/null
@@ -0,0 +1,42 @@
+#ifndef _ASM_EARLY_IOREMAP_H_
+#define _ASM_EARLY_IOREMAP_H_
+
+#include <linux/types.h>
+
+/*
+ * early_ioremap() and early_iounmap() are for temporary early boot-time
+ * mappings, before the real ioremap() is functional.
+ */
+extern void __iomem *early_ioremap(resource_size_t phys_addr,
+                                  unsigned long size);
+extern void *early_memremap(resource_size_t phys_addr,
+                           unsigned long size);
+extern void early_iounmap(void __iomem *addr, unsigned long size);
+extern void early_memunmap(void *addr, unsigned long size);
+
+/*
+ * Weak function called by early_ioremap_reset(). It does nothing, but
+ * architectures may provide their own version to do any needed cleanups.
+ */
+extern void early_ioremap_shutdown(void);
+
+#if defined(CONFIG_GENERIC_EARLY_IOREMAP) && defined(CONFIG_MMU)
+/* Arch-specific initialization */
+extern void early_ioremap_init(void);
+
+/* Generic initialization called by architecture code */
+extern void early_ioremap_setup(void);
+
+/*
+ * Called as last step in paging_init() so library can act
+ * accordingly for subsequent map/unmap requests.
+ */
+extern void early_ioremap_reset(void);
+
+#else
+static inline void early_ioremap_init(void) { }
+static inline void early_ioremap_setup(void) { }
+static inline void early_ioremap_reset(void) { }
+#endif
+
+#endif /* _ASM_EARLY_IOREMAP_H_ */
index d5afe96..975e1cc 100644 (file)
@@ -327,7 +327,7 @@ static inline void iounmap(void __iomem *addr)
 }
 #endif /* CONFIG_MMU */
 
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
 #ifndef CONFIG_GENERIC_IOMAP
 static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
 {
@@ -341,7 +341,7 @@ static inline void ioport_unmap(void __iomem *p)
 extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
 extern void ioport_unmap(void __iomem *p);
 #endif /* CONFIG_GENERIC_IOMAP */
-#endif /* CONFIG_HAS_IOPORT */
+#endif /* CONFIG_HAS_IOPORT_MAP */
 
 #ifndef xlate_dev_kmem_ptr
 #define xlate_dev_kmem_ptr(p)  p
index 6afd7d6..1b41011 100644 (file)
@@ -56,7 +56,7 @@ extern void iowrite8_rep(void __iomem *port, const void *buf, unsigned long coun
 extern void iowrite16_rep(void __iomem *port, const void *buf, unsigned long count);
 extern void iowrite32_rep(void __iomem *port, const void *buf, unsigned long count);
 
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
 /* Create a virtual mapping cookie for an IO port range */
 extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
 extern void ioport_unmap(void __iomem *);
index d17784e..0703aa7 100644 (file)
@@ -56,17 +56,17 @@ extern unsigned long __per_cpu_offset[NR_CPUS];
 #define per_cpu(var, cpu) \
        (*SHIFT_PERCPU_PTR(&(var), per_cpu_offset(cpu)))
 
-#ifndef __this_cpu_ptr
-#define __this_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)
+#ifndef raw_cpu_ptr
+#define raw_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, __my_cpu_offset)
 #endif
 #ifdef CONFIG_DEBUG_PREEMPT
 #define this_cpu_ptr(ptr) SHIFT_PERCPU_PTR(ptr, my_cpu_offset)
 #else
-#define this_cpu_ptr(ptr) __this_cpu_ptr(ptr)
+#define this_cpu_ptr(ptr) raw_cpu_ptr(ptr)
 #endif
 
 #define __get_cpu_var(var) (*this_cpu_ptr(&(var)))
-#define __raw_get_cpu_var(var) (*__this_cpu_ptr(&(var)))
+#define __raw_get_cpu_var(var) (*raw_cpu_ptr(&(var)))
 
 #ifdef CONFIG_HAVE_SETUP_PER_CPU_AREA
 extern void setup_per_cpu_areas(void);
@@ -83,7 +83,7 @@ extern void setup_per_cpu_areas(void);
 #define __get_cpu_var(var)     (*VERIFY_PERCPU_PTR(&(var)))
 #define __raw_get_cpu_var(var) (*VERIFY_PERCPU_PTR(&(var)))
 #define this_cpu_ptr(ptr)      per_cpu_ptr(ptr, 0)
-#define __this_cpu_ptr(ptr)    this_cpu_ptr(ptr)
+#define raw_cpu_ptr(ptr)       this_cpu_ptr(ptr)
 
 #endif /* SMP */
 
@@ -122,4 +122,7 @@ extern void setup_per_cpu_areas(void);
 #define PER_CPU_DEF_ATTRIBUTES
 #endif
 
+/* Keep until we have removed all uses of __this_cpu_ptr */
+#define __this_cpu_ptr raw_cpu_ptr
+
 #endif /* _ASM_GENERIC_PERCPU_H_ */
diff --git a/include/drm/bridge/ptn3460.h b/include/drm/bridge/ptn3460.h
new file mode 100644 (file)
index 0000000..ff62344
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2013 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _DRM_BRIDGE_PTN3460_H_
+#define _DRM_BRIDGE_PTN3460_H_
+
+struct drm_device;
+struct drm_encoder;
+struct i2c_client;
+struct device_node;
+
+#if defined(CONFIG_DRM_PTN3460) || defined(CONFIG_DRM_PTN3460_MODULE)
+
+int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
+               struct i2c_client *client, struct device_node *node);
+#else
+
+static inline int ptn3460_init(struct drm_device *dev,
+               struct drm_encoder *encoder, struct i2c_client *client,
+               struct device_node *node)
+{
+       return 0;
+}
+
+#endif
+
+#endif
index 04a7f31..a7c2a86 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/current.h>
 #endif                         /* __alpha__ */
 #include <linux/kernel.h>
+#include <linux/kref.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -87,46 +88,41 @@ struct videomode;
 #include <drm/drm_hashtab.h>
 #include <drm/drm_mm.h>
 
-#define DRM_UT_CORE            0x01
-#define DRM_UT_DRIVER          0x02
-#define DRM_UT_KMS             0x04
-#define DRM_UT_PRIME           0x08
 /*
- * Three debug levels are defined.
- * drm_core, drm_driver, drm_kms
- * drm_core level can be used in the generic drm code. For example:
- *     drm_ioctl, drm_mm, drm_memory
- * The macro definition of DRM_DEBUG is used.
- *     DRM_DEBUG(fmt, args...)
- *     The debug info by using the DRM_DEBUG can be obtained by adding
- *     the boot option of "drm.debug=1".
+ * 4 debug categories are defined:
+ *
+ * CORE: Used in the generic drm code: drm_ioctl.c, drm_mm.c, drm_memory.c, ...
+ *      This is the category used by the DRM_DEBUG() macro.
+ *
+ * DRIVER: Used in the vendor specific part of the driver: i915, radeon, ...
+ *        This is the category used by the DRM_DEBUG_DRIVER() macro.
+ *
+ * KMS: used in the modesetting code.
+ *     This is the category used by the DRM_DEBUG_KMS() macro.
+ *
+ * PRIME: used in the prime code.
+ *       This is the category used by the DRM_DEBUG_PRIME() macro.
  *
- * drm_driver level can be used in the specific drm driver. It is used
- * to add the debug info related with the drm driver. For example:
- * i915_drv, i915_dma, i915_gem, radeon_drv,
- *     The macro definition of DRM_DEBUG_DRIVER can be used.
- *     DRM_DEBUG_DRIVER(fmt, args...)
- *     The debug info by using the DRM_DEBUG_DRIVER can be obtained by
- *     adding the boot option of "drm.debug=0x02"
+ * Enabling verbose debug messages is done through the drm.debug parameter,
+ * each category being enabled by a bit.
  *
- * drm_kms level can be used in the KMS code related with specific drm driver.
- * It is used to add the debug info related with KMS mode. For example:
- * the connector/crtc ,
- *     The macro definition of DRM_DEBUG_KMS can be used.
- *     DRM_DEBUG_KMS(fmt, args...)
- *     The debug info by using the DRM_DEBUG_KMS can be obtained by
- *     adding the boot option of "drm.debug=0x04"
+ * drm.debug=0x1 will enable CORE messages
+ * drm.debug=0x2 will enable DRIVER messages
+ * drm.debug=0x3 will enable CORE and DRIVER messages
+ * ...
+ * drm.debug=0xf will enable all messages
  *
- * If we add the boot option of "drm.debug=0x06", we can get the debug info by
- * using the DRM_DEBUG_KMS and DRM_DEBUG_DRIVER.
- * If we add the boot option of "drm.debug=0x05", we can get the debug info by
- * using the DRM_DEBUG_KMS and DRM_DEBUG.
+ * An interesting feature is that it's possible to enable verbose logging at
+ * run-time by echoing the debug value in its sysfs node:
+ *   # echo 0xf > /sys/module/drm/parameters/debug
  */
+#define DRM_UT_CORE            0x01
+#define DRM_UT_DRIVER          0x02
+#define DRM_UT_KMS             0x04
+#define DRM_UT_PRIME           0x08
 
-extern __printf(4, 5)
-void drm_ut_debug_printk(unsigned int request_level,
-                        const char *prefix,
-                        const char *function_name,
+extern __printf(2, 3)
+void drm_ut_debug_printk(const char *function_name,
                         const char *format, ...);
 extern __printf(2, 3)
 int drm_err(const char *func, const char *format, ...);
@@ -211,55 +207,30 @@ int drm_err(const char *func, const char *format, ...);
 #if DRM_DEBUG_CODE
 #define DRM_DEBUG(fmt, args...)                                                \
        do {                                                            \
-               drm_ut_debug_printk(DRM_UT_CORE, DRM_NAME,              \
-                                       __func__, fmt, ##args);         \
+               if (unlikely(drm_debug & DRM_UT_CORE))                  \
+                       drm_ut_debug_printk(__func__, fmt, ##args);     \
        } while (0)
 
 #define DRM_DEBUG_DRIVER(fmt, args...)                                 \
        do {                                                            \
-               drm_ut_debug_printk(DRM_UT_DRIVER, DRM_NAME,            \
-                                       __func__, fmt, ##args);         \
+               if (unlikely(drm_debug & DRM_UT_DRIVER))                \
+                       drm_ut_debug_printk(__func__, fmt, ##args);     \
        } while (0)
-#define DRM_DEBUG_KMS(fmt, args...)                            \
+#define DRM_DEBUG_KMS(fmt, args...)                                    \
        do {                                                            \
-               drm_ut_debug_printk(DRM_UT_KMS, DRM_NAME,               \
-                                        __func__, fmt, ##args);        \
+               if (unlikely(drm_debug & DRM_UT_KMS))                   \
+                       drm_ut_debug_printk(__func__, fmt, ##args);     \
        } while (0)
 #define DRM_DEBUG_PRIME(fmt, args...)                                  \
        do {                                                            \
-               drm_ut_debug_printk(DRM_UT_PRIME, DRM_NAME,             \
-                                       __func__, fmt, ##args);         \
-       } while (0)
-#define DRM_LOG(fmt, args...)                                          \
-       do {                                                            \
-               drm_ut_debug_printk(DRM_UT_CORE, NULL,                  \
-                                       NULL, fmt, ##args);             \
-       } while (0)
-#define DRM_LOG_KMS(fmt, args...)                                      \
-       do {                                                            \
-               drm_ut_debug_printk(DRM_UT_KMS, NULL,                   \
-                                       NULL, fmt, ##args);             \
-       } while (0)
-#define DRM_LOG_MODE(fmt, args...)                                     \
-       do {                                                            \
-               drm_ut_debug_printk(DRM_UT_MODE, NULL,                  \
-                                       NULL, fmt, ##args);             \
-       } while (0)
-#define DRM_LOG_DRIVER(fmt, args...)                                   \
-       do {                                                            \
-               drm_ut_debug_printk(DRM_UT_DRIVER, NULL,                \
-                                       NULL, fmt, ##args);             \
+               if (unlikely(drm_debug & DRM_UT_PRIME))                 \
+                       drm_ut_debug_printk(__func__, fmt, ##args);     \
        } while (0)
 #else
 #define DRM_DEBUG_DRIVER(fmt, args...) do { } while (0)
 #define DRM_DEBUG_KMS(fmt, args...)    do { } while (0)
 #define DRM_DEBUG_PRIME(fmt, args...)  do { } while (0)
 #define DRM_DEBUG(fmt, arg...)          do { } while (0)
-#define DRM_LOG(fmt, arg...)           do { } while (0)
-#define DRM_LOG_KMS(fmt, args...) do { } while (0)
-#define DRM_LOG_MODE(fmt, arg...) do { } while (0)
-#define DRM_LOG_DRIVER(fmt, arg...) do { } while (0)
-
 #endif
 
 /*@}*/
@@ -434,9 +405,15 @@ struct drm_prime_file_private {
 struct drm_file {
        unsigned always_authenticated :1;
        unsigned authenticated :1;
-       unsigned is_master :1; /* this file private is a master for a minor */
+       /* Whether we're master for a minor. Protected by master_mutex */
+       unsigned is_master :1;
        /* true when the client has asked us to expose stereo 3D mode flags */
        unsigned stereo_allowed :1;
+       /*
+        * true if client understands CRTC primary planes and cursor planes
+        * in the plane list
+        */
+       unsigned universal_planes:1;
 
        struct pid *pid;
        kuid_t uid;
@@ -713,29 +690,29 @@ struct drm_gem_object {
 
 #include <drm/drm_crtc.h>
 
-/* per-master structure */
+/**
+ * struct drm_master - drm master structure
+ *
+ * @refcount: Refcount for this master object.
+ * @minor: Link back to minor char device we are master for. Immutable.
+ * @unique: Unique identifier: e.g. busid. Protected by drm_global_mutex.
+ * @unique_len: Length of unique field. Protected by drm_global_mutex.
+ * @unique_size: Amount allocated. Protected by drm_global_mutex.
+ * @magiclist: Hash of used authentication tokens. Protected by struct_mutex.
+ * @magicfree: List of used authentication tokens. Protected by struct_mutex.
+ * @lock: DRI lock information.
+ * @driver_priv: Pointer to driver-private information.
+ */
 struct drm_master {
-
-       struct kref refcount; /* refcount for this master */
-
-       struct list_head head; /**< each minor contains a list of masters */
-       struct drm_minor *minor; /**< link back to minor we are a master for */
-
-       char *unique;                   /**< Unique identifier: e.g., busid */
-       int unique_len;                 /**< Length of unique field */
-       int unique_size;                /**< amount allocated */
-
-       int blocked;                    /**< Blocked due to VC switch? */
-
-       /** \name Authentication */
-       /*@{ */
+       struct kref refcount;
+       struct drm_minor *minor;
+       char *unique;
+       int unique_len;
+       int unique_size;
        struct drm_open_hash magiclist;
        struct list_head magicfree;
-       /*@} */
-
-       struct drm_lock_data lock;      /**< Information on hardware lock */
-
-       void *driver_priv; /**< Private structure for driver to use */
+       struct drm_lock_data lock;
+       void *driver_priv;
 };
 
 /* Size of ringbuffer for vblank timestamps. Just double-buffer
@@ -1008,10 +985,12 @@ struct drm_driver {
        struct list_head legacy_dev_list;
 };
 
-#define DRM_MINOR_UNASSIGNED 0
-#define DRM_MINOR_LEGACY 1
-#define DRM_MINOR_CONTROL 2
-#define DRM_MINOR_RENDER 3
+enum drm_minor_type {
+       DRM_MINOR_LEGACY,
+       DRM_MINOR_CONTROL,
+       DRM_MINOR_RENDER,
+       DRM_MINOR_CNT,
+};
 
 /**
  * Info file list entry. This structure represents a debugfs or proc file to
@@ -1040,7 +1019,6 @@ struct drm_info_node {
 struct drm_minor {
        int index;                      /**< Minor device number */
        int type;                       /**< Control or render */
-       dev_t device;                   /**< Device number for mknod */
        struct device *kdev;            /**< Linux device */
        struct drm_device *dev;
 
@@ -1049,26 +1027,11 @@ struct drm_minor {
        struct list_head debugfs_list;
        struct mutex debugfs_lock; /* Protects debugfs_list. */
 
-       struct drm_master *master; /* currently active master for this node */
-       struct list_head master_list;
+       /* currently active master for this node. Protected by master_mutex */
+       struct drm_master *master;
        struct drm_mode_group mode_group;
 };
 
-/* mode specified on the command line */
-struct drm_cmdline_mode {
-       bool specified;
-       bool refresh_specified;
-       bool bpp_specified;
-       int xres, yres;
-       int bpp;
-       int refresh;
-       bool rb;
-       bool interlace;
-       bool cvt;
-       bool margins;
-       enum drm_connector_force force;
-};
-
 
 struct drm_pending_vblank_event {
        struct drm_pending_event base;
@@ -1098,10 +1061,24 @@ struct drm_device {
        char *devname;                  /**< For /proc/interrupts */
        int if_version;                 /**< Highest interface version set */
 
+       /** \name Lifetime Management */
+       /*@{ */
+       struct kref ref;                /**< Object ref-count */
+       struct device *dev;             /**< Device structure of bus-device */
+       struct drm_driver *driver;      /**< DRM driver managing the device */
+       void *dev_private;              /**< DRM driver private data */
+       struct drm_minor *control;              /**< Control node */
+       struct drm_minor *primary;              /**< Primary node */
+       struct drm_minor *render;               /**< Render node */
+       atomic_t unplugged;                     /**< Flag whether dev is dead */
+       struct inode *anon_inode;               /**< inode for private address-space */
+       /*@} */
+
        /** \name Locks */
        /*@{ */
        spinlock_t count_lock;          /**< For inuse, drm_device::open_count, drm_device::buf_use */
        struct mutex struct_mutex;      /**< For others */
+       struct mutex master_mutex;      /**< For drm_minor::master and drm_file::is_master */
        /*@} */
 
        /** \name Usage Counters */
@@ -1171,7 +1148,6 @@ struct drm_device {
 
        struct drm_agp_head *agp;       /**< AGP data */
 
-       struct device *dev;             /**< Device structure */
        struct pci_dev *pdev;           /**< PCI device structure */
 #ifdef __alpha__
        struct pci_controller *hose;
@@ -1182,17 +1158,11 @@ struct drm_device {
 
        struct drm_sg_mem *sg;  /**< Scatter gather memory */
        unsigned int num_crtcs;                  /**< Number of CRTCs on this device */
-       void *dev_private;              /**< device private data */
-       struct address_space *dev_mapping;
        struct drm_sigdata sigdata;        /**< For block_all_signals */
        sigset_t sigmask;
 
-       struct drm_driver *driver;
        struct drm_local_map *agp_buffer_map;
        unsigned int agp_buffer_token;
-       struct drm_minor *control;              /**< Control node for card */
-       struct drm_minor *primary;              /**< render type primary screen head */
-       struct drm_minor *render;               /**< render node for card */
 
         struct drm_mode_config mode_config;    /**< Current mode config */
 
@@ -1203,8 +1173,6 @@ struct drm_device {
        struct drm_vma_offset_manager *vma_offset_manager;
        /*@} */
        int switch_power_state;
-
-       atomic_t unplugged; /* device has been unplugged or gone away */
 };
 
 #define DRM_SWITCH_POWER_ON 0
@@ -1241,11 +1209,21 @@ static inline bool drm_modeset_is_locked(struct drm_device *dev)
        return mutex_is_locked(&dev->mode_config.mutex);
 }
 
-static inline bool drm_is_render_client(struct drm_file *file_priv)
+static inline bool drm_is_render_client(const struct drm_file *file_priv)
 {
        return file_priv->minor->type == DRM_MINOR_RENDER;
 }
 
+static inline bool drm_is_control_client(const struct drm_file *file_priv)
+{
+       return file_priv->minor->type == DRM_MINOR_CONTROL;
+}
+
+static inline bool drm_is_primary_client(const struct drm_file *file_priv)
+{
+       return file_priv->minor->type == DRM_MINOR_LEGACY;
+}
+
 /******************************************************************/
 /** \name Internal function definitions */
 /*@{*/
@@ -1256,6 +1234,7 @@ extern long drm_ioctl(struct file *filp,
 extern long drm_compat_ioctl(struct file *filp,
                             unsigned int cmd, unsigned long arg);
 extern int drm_lastclose(struct drm_device *dev);
+extern bool drm_ioctl_flags(unsigned int nr, unsigned int *flags);
 
                                /* Device support (drm_fops.h) */
 extern struct mutex drm_global_mutex;
@@ -1411,20 +1390,6 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
 extern void drm_calc_timestamping_constants(struct drm_crtc *crtc,
                                            const struct drm_display_mode *mode);
 
-extern bool
-drm_mode_parse_command_line_for_connector(const char *mode_option,
-                                         struct drm_connector *connector,
-                                         struct drm_cmdline_mode *mode);
-
-extern struct drm_display_mode *
-drm_mode_create_from_cmdline_mode(struct drm_device *dev,
-                                 struct drm_cmdline_mode *cmd);
-
-extern int drm_display_mode_from_videomode(const struct videomode *vm,
-                                          struct drm_display_mode *dmode);
-extern int of_get_drm_display_mode(struct device_node *np,
-                                  struct drm_display_mode *dmode,
-                                  int index);
 
 /* Modesetting support */
 extern void drm_vblank_pre_modeset(struct drm_device *dev, int crtc);
@@ -1449,6 +1414,7 @@ extern void drm_put_dev(struct drm_device *dev);
 extern void drm_unplug_dev(struct drm_device *dev);
 extern unsigned int drm_debug;
 extern unsigned int drm_rnodes;
+extern unsigned int drm_universal_planes;
 
 extern unsigned int drm_vblank_offdelay;
 extern unsigned int drm_timestamp_precision;
@@ -1661,9 +1627,14 @@ static __inline__ void drm_core_dropmap(struct drm_local_map *map)
 
 struct drm_device *drm_dev_alloc(struct drm_driver *driver,
                                 struct device *parent);
-void drm_dev_free(struct drm_device *dev);
+void drm_dev_ref(struct drm_device *dev);
+void drm_dev_unref(struct drm_device *dev);
 int drm_dev_register(struct drm_device *dev, unsigned long flags);
 void drm_dev_unregister(struct drm_device *dev);
+
+struct drm_minor *drm_minor_acquire(unsigned int minor_id);
+void drm_minor_release(struct drm_minor *minor);
+
 /*@}*/
 
 /* PCI section */
index 8f3dee0..e55fccb 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/fb.h>
 #include <linux/hdmi.h>
 #include <drm/drm_mode.h>
-
 #include <drm/drm_fourcc.h>
 
 struct drm_device;
@@ -65,130 +64,14 @@ struct drm_object_properties {
        uint64_t values[DRM_OBJECT_MAX_PROPERTY];
 };
 
-/*
- * Note on terminology:  here, for brevity and convenience, we refer to connector
- * control chips as 'CRTCs'.  They can control any type of connector, VGA, LVDS,
- * DVI, etc.  And 'screen' refers to the whole of the visible display, which
- * may span multiple monitors (and therefore multiple CRTC and connector
- * structures).
- */
-
-enum drm_mode_status {
-    MODE_OK    = 0,    /* Mode OK */
-    MODE_HSYNC,                /* hsync out of range */
-    MODE_VSYNC,                /* vsync out of range */
-    MODE_H_ILLEGAL,    /* mode has illegal horizontal timings */
-    MODE_V_ILLEGAL,    /* mode has illegal horizontal timings */
-    MODE_BAD_WIDTH,    /* requires an unsupported linepitch */
-    MODE_NOMODE,       /* no mode with a matching name */
-    MODE_NO_INTERLACE, /* interlaced mode not supported */
-    MODE_NO_DBLESCAN,  /* doublescan mode not supported */
-    MODE_NO_VSCAN,     /* multiscan mode not supported */
-    MODE_MEM,          /* insufficient video memory */
-    MODE_VIRTUAL_X,    /* mode width too large for specified virtual size */
-    MODE_VIRTUAL_Y,    /* mode height too large for specified virtual size */
-    MODE_MEM_VIRT,     /* insufficient video memory given virtual size */
-    MODE_NOCLOCK,      /* no fixed clock available */
-    MODE_CLOCK_HIGH,   /* clock required is too high */
-    MODE_CLOCK_LOW,    /* clock required is too low */
-    MODE_CLOCK_RANGE,  /* clock/mode isn't in a ClockRange */
-    MODE_BAD_HVALUE,   /* horizontal timing was out of range */
-    MODE_BAD_VVALUE,   /* vertical timing was out of range */
-    MODE_BAD_VSCAN,    /* VScan value out of range */
-    MODE_HSYNC_NARROW, /* horizontal sync too narrow */
-    MODE_HSYNC_WIDE,   /* horizontal sync too wide */
-    MODE_HBLANK_NARROW,        /* horizontal blanking too narrow */
-    MODE_HBLANK_WIDE,  /* horizontal blanking too wide */
-    MODE_VSYNC_NARROW, /* vertical sync too narrow */
-    MODE_VSYNC_WIDE,   /* vertical sync too wide */
-    MODE_VBLANK_NARROW,        /* vertical blanking too narrow */
-    MODE_VBLANK_WIDE,  /* vertical blanking too wide */
-    MODE_PANEL,         /* exceeds panel dimensions */
-    MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */
-    MODE_ONE_WIDTH,     /* only one width is supported */
-    MODE_ONE_HEIGHT,    /* only one height is supported */
-    MODE_ONE_SIZE,      /* only one resolution is supported */
-    MODE_NO_REDUCED,    /* monitor doesn't accept reduced blanking */
-    MODE_NO_STEREO,    /* stereo modes not supported */
-    MODE_UNVERIFIED = -3, /* mode needs to reverified */
-    MODE_BAD = -2,     /* unspecified reason */
-    MODE_ERROR = -1    /* error condition */
-};
-
-#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \
-                                   DRM_MODE_TYPE_CRTC_C)
-
-#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \
-       .name = nm, .status = 0, .type = (t), .clock = (c), \
-       .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
-       .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \
-       .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
-       .vscan = (vs), .flags = (f), \
-       .base.type = DRM_MODE_OBJECT_MODE
-
-#define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */
-#define CRTC_STEREO_DOUBLE     (1 << 1) /* adjust timings for stereo modes */
-
-#define DRM_MODE_FLAG_3D_MAX   DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF
-
-struct drm_display_mode {
-       /* Header */
-       struct list_head head;
-       struct drm_mode_object base;
-
-       char name[DRM_DISPLAY_MODE_LEN];
-
-       enum drm_mode_status status;
-       unsigned int type;
-
-       /* Proposed mode values */
-       int clock;              /* in kHz */
-       int hdisplay;
-       int hsync_start;
-       int hsync_end;
-       int htotal;
-       int hskew;
-       int vdisplay;
-       int vsync_start;
-       int vsync_end;
-       int vtotal;
-       int vscan;
-       unsigned int flags;
-
-       /* Addressable image size (may be 0 for projectors, etc.) */
-       int width_mm;
-       int height_mm;
-
-       /* Actual mode we give to hw */
-       int crtc_clock;         /* in KHz */
-       int crtc_hdisplay;
-       int crtc_hblank_start;
-       int crtc_hblank_end;
-       int crtc_hsync_start;
-       int crtc_hsync_end;
-       int crtc_htotal;
-       int crtc_hskew;
-       int crtc_vdisplay;
-       int crtc_vblank_start;
-       int crtc_vblank_end;
-       int crtc_vsync_start;
-       int crtc_vsync_end;
-       int crtc_vtotal;
-
-       /* Driver private mode info */
-       int private_size;
-       int *private;
-       int private_flags;
-
-       int vrefresh;           /* in Hz */
-       int hsync;              /* in kHz */
-       enum hdmi_picture_aspect picture_aspect_ratio;
+enum drm_connector_force {
+       DRM_FORCE_UNSPECIFIED,
+       DRM_FORCE_OFF,
+       DRM_FORCE_ON,         /* force on analog part normally */
+       DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */
 };
 
-static inline bool drm_mode_is_stereo(const struct drm_display_mode *mode)
-{
-       return mode->flags & DRM_MODE_FLAG_3D_MASK;
-}
+#include <drm/drm_modes.h>
 
 enum drm_connector_status {
        connector_status_connected = 1,
@@ -387,6 +270,8 @@ struct drm_crtc_funcs {
  * @dev: parent DRM device
  * @head: list management
  * @base: base KMS object for ID tracking etc.
+ * @primary: primary plane for this CRTC
+ * @cursor: cursor plane for this CRTC
  * @enabled: is this CRTC enabled?
  * @mode: current mode timings
  * @hwmode: mode timings as programmed to hw regs
@@ -422,8 +307,9 @@ struct drm_crtc {
 
        struct drm_mode_object base;
 
-       /* framebuffer the connector is currently bound to */
-       struct drm_framebuffer *fb;
+       /* primary and cursor planes for CRTC */
+       struct drm_plane *primary;
+       struct drm_plane *cursor;
 
        /* Temporary tracking of the old fb while a modeset is ongoing. Used
         * by drm_mode_set_config_internal to implement correct refcounting. */
@@ -540,13 +426,6 @@ struct drm_encoder {
        void *helper_private;
 };
 
-enum drm_connector_force {
-       DRM_FORCE_UNSPECIFIED,
-       DRM_FORCE_OFF,
-       DRM_FORCE_ON,         /* force on analog part normally */
-       DRM_FORCE_ON_DIGITAL, /* for DVI-I use digital connector */
-};
-
 /* should we poll this connector for connects and disconnects */
 /* hot plug detectable */
 #define DRM_CONNECTOR_POLL_HPD (1 << 0)
@@ -665,6 +544,12 @@ struct drm_plane_funcs {
                            struct drm_property *property, uint64_t val);
 };
 
+enum drm_plane_type {
+       DRM_PLANE_TYPE_OVERLAY,
+       DRM_PLANE_TYPE_PRIMARY,
+       DRM_PLANE_TYPE_CURSOR,
+};
+
 /**
  * drm_plane - central DRM plane control structure
  * @dev: DRM device this plane belongs to
@@ -677,6 +562,7 @@ struct drm_plane_funcs {
  * @fb: currently bound fb
  * @funcs: helper functions
  * @properties: property tracking for this plane
+ * @type: type of plane (overlay, primary, cursor)
  */
 struct drm_plane {
        struct drm_device *dev;
@@ -694,6 +580,8 @@ struct drm_plane {
        const struct drm_plane_funcs *funcs;
 
        struct drm_object_properties properties;
+
+       enum drm_plane_type type;
 };
 
 /**
@@ -856,7 +744,15 @@ struct drm_mode_config {
        struct list_head bridge_list;
        int num_encoder;
        struct list_head encoder_list;
-       int num_plane;
+
+       /*
+        * Track # of overlay planes separately from # of total planes.  By
+        * default we only advertise overlay planes to userspace; if userspace
+        * sets the "universal plane" capability bit, we'll go ahead and
+        * expose all planes.
+        */
+       int num_overlay_plane;
+       int num_total_plane;
        struct list_head plane_list;
 
        int num_crtc;
@@ -878,6 +774,7 @@ struct drm_mode_config {
        struct list_head property_blob_list;
        struct drm_property *edid_property;
        struct drm_property *dpms_property;
+       struct drm_property *plane_type_property;
 
        /* DVI-I properties */
        struct drm_property *dvi_i_subconnector_property;
@@ -930,6 +827,11 @@ extern void drm_modeset_lock_all(struct drm_device *dev);
 extern void drm_modeset_unlock_all(struct drm_device *dev);
 extern void drm_warn_on_modeset_not_all_locked(struct drm_device *dev);
 
+extern int drm_crtc_init_with_planes(struct drm_device *dev,
+                                    struct drm_crtc *crtc,
+                                    struct drm_plane *primary,
+                                    void *cursor,
+                                    const struct drm_crtc_funcs *funcs);
 extern int drm_crtc_init(struct drm_device *dev,
                         struct drm_crtc *crtc,
                         const struct drm_crtc_funcs *funcs);
@@ -981,19 +883,31 @@ static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
        return !!(encoder->possible_crtcs & drm_crtc_mask(crtc));
 }
 
+extern int drm_universal_plane_init(struct drm_device *dev,
+                                   struct drm_plane *plane,
+                                   unsigned long possible_crtcs,
+                                   const struct drm_plane_funcs *funcs,
+                                   const uint32_t *formats,
+                                   uint32_t format_count,
+                                   enum drm_plane_type type);
 extern int drm_plane_init(struct drm_device *dev,
                          struct drm_plane *plane,
                          unsigned long possible_crtcs,
                          const struct drm_plane_funcs *funcs,
                          const uint32_t *formats, uint32_t format_count,
-                         bool priv);
+                         bool is_primary);
 extern void drm_plane_cleanup(struct drm_plane *plane);
 extern void drm_plane_force_disable(struct drm_plane *plane);
+extern int drm_crtc_check_viewport(const struct drm_crtc *crtc,
+                                  int x, int y,
+                                  const struct drm_display_mode *mode,
+                                  const struct drm_framebuffer *fb);
 
 extern void drm_encoder_cleanup(struct drm_encoder *encoder);
 
 extern const char *drm_get_connector_name(const struct drm_connector *connector);
 extern const char *drm_get_connector_status_name(enum drm_connector_status status);
+extern const char *drm_get_subpixel_order_name(enum subpixel_order order);
 extern const char *drm_get_dpms_name(int val);
 extern const char *drm_get_dvi_i_subconnector_name(int val);
 extern const char *drm_get_dvi_i_select_name(int val);
@@ -1006,34 +920,10 @@ extern struct edid *drm_get_edid(struct drm_connector *connector,
                                 struct i2c_adapter *adapter);
 extern struct edid *drm_edid_duplicate(const struct edid *edid);
 extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid);
-extern void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
-extern void drm_mode_copy(struct drm_display_mode *dst, const struct drm_display_mode *src);
-extern struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
-                                                  const struct drm_display_mode *mode);
-extern void drm_mode_debug_printmodeline(const struct drm_display_mode *mode);
 extern void drm_mode_config_init(struct drm_device *dev);
 extern void drm_mode_config_reset(struct drm_device *dev);
 extern void drm_mode_config_cleanup(struct drm_device *dev);
-extern void drm_mode_set_name(struct drm_display_mode *mode);
-extern bool drm_mode_equal(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2);
-extern bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1, const struct drm_display_mode *mode2);
-extern int drm_mode_width(const struct drm_display_mode *mode);
-extern int drm_mode_height(const struct drm_display_mode *mode);
-
-/* for us by fb module */
-extern struct drm_display_mode *drm_mode_create(struct drm_device *dev);
-extern void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
-extern void drm_mode_validate_size(struct drm_device *dev,
-                                  struct list_head *mode_list,
-                                  int maxX, int maxY, int maxPitch);
-extern void drm_mode_prune_invalid(struct drm_device *dev,
-                                  struct list_head *mode_list, bool verbose);
-extern void drm_mode_sort(struct list_head *mode_list);
-extern int drm_mode_hsync(const struct drm_display_mode *mode);
-extern int drm_mode_vrefresh(const struct drm_display_mode *mode);
-extern void drm_mode_set_crtcinfo(struct drm_display_mode *p,
-                                 int adjust_flags);
-extern void drm_mode_connector_list_update(struct drm_connector *connector);
+
 extern int drm_mode_connector_update_edid_property(struct drm_connector *connector,
                                                struct edid *edid);
 extern int drm_object_property_set_value(struct drm_mode_object *obj,
@@ -1081,8 +971,6 @@ extern const char *drm_get_encoder_name(const struct drm_encoder *encoder);
 
 extern int drm_mode_connector_attach_encoder(struct drm_connector *connector,
                                             struct drm_encoder *encoder);
-extern void drm_mode_connector_detach_encoder(struct drm_connector *connector,
-                                          struct drm_encoder *encoder);
 extern int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
                                         int gamma_size);
 extern struct drm_mode_object *drm_mode_object_find(struct drm_device *dev,
@@ -1137,16 +1025,6 @@ extern bool drm_detect_monitor_audio(struct edid *edid);
 extern bool drm_rgb_quant_range_selectable(struct edid *edid);
 extern int drm_mode_page_flip_ioctl(struct drm_device *dev,
                                    void *data, struct drm_file *file_priv);
-extern struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
-                               int hdisplay, int vdisplay, int vrefresh,
-                               bool reduced, bool interlaced, bool margins);
-extern struct drm_display_mode *drm_gtf_mode(struct drm_device *dev,
-                               int hdisplay, int vdisplay, int vrefresh,
-                               bool interlaced, int margins);
-extern struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev,
-                               int hdisplay, int vdisplay, int vrefresh,
-                               bool interlaced, int margins, int GTF_M,
-                               int GTF_2C, int GTF_K, int GTF_2J);
 extern int drm_add_modes_noedid(struct drm_connector *connector,
                                int hdisplay, int vdisplay);
 extern void drm_set_preferred_mode(struct drm_connector *connector,
@@ -1195,4 +1073,9 @@ static inline struct drm_encoder *drm_encoder_find(struct drm_device *dev,
        return mo ? obj_to_encoder(mo) : NULL;
 }
 
+/* Plane list iterator for legacy (overlay only) planes. */
+#define drm_for_each_legacy_plane(plane, planelist) \
+       list_for_each_entry(plane, planelist, head) \
+               if (plane->type == DRM_PLANE_TYPE_OVERLAY)
+
 #endif /* __DRM_CRTC_H__ */
index b1388b5..0bb34ca 100644 (file)
@@ -139,8 +139,8 @@ extern void drm_helper_connector_dpms(struct drm_connector *connector, int mode)
 
 extern void drm_helper_move_panel_connectors_to_head(struct drm_device *);
 
-extern int drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
-                                         struct drm_mode_fb_cmd2 *mode_cmd);
+extern void drm_helper_mode_fill_fb_struct(struct drm_framebuffer *fb,
+                                          struct drm_mode_fb_cmd2 *mode_cmd);
 
 static inline void drm_crtc_helper_add(struct drm_crtc *crtc,
                                       const struct drm_crtc_helper_funcs *funcs)
@@ -160,7 +160,7 @@ static inline void drm_connector_helper_add(struct drm_connector *connector,
        connector->helper_private = (void *)funcs;
 }
 
-extern int drm_helper_resume_force_mode(struct drm_device *dev);
+extern void drm_helper_resume_force_mode(struct drm_device *dev);
 extern void drm_kms_helper_poll_init(struct drm_device *dev);
 extern void drm_kms_helper_poll_fini(struct drm_device *dev);
 extern bool drm_helper_hpd_irq_event(struct drm_device *dev);
index 1d09050..b4f5891 100644 (file)
 
 #define DP_TEST_PATTERN                            0x221
 
+#define DP_TEST_CRC_R_CR                   0x240
+#define DP_TEST_CRC_G_Y                            0x242
+#define DP_TEST_CRC_B_CB                   0x244
+
+#define DP_TEST_SINK_MISC                  0x246
+#define DP_TEST_CRC_SUPPORTED              (1 << 5)
+
 #define DP_TEST_RESPONSE                   0x260
 # define DP_TEST_ACK                       (1 << 0)
 # define DP_TEST_NAK                       (1 << 1)
 # define DP_TEST_EDID_CHECKSUM_WRITE       (1 << 2)
 
+#define DP_TEST_SINK                       0x270
+#define DP_TEST_SINK_START         (1 << 0)
+
 #define DP_SOURCE_OUI                      0x300
 #define DP_SINK_OUI                        0x400
 #define DP_BRANCH_OUI                      0x500
 #define DP_SET_POWER                        0x600
 # define DP_SET_POWER_D0                    0x1
 # define DP_SET_POWER_D3                    0x2
+# define DP_SET_POWER_MASK                  0x3
 
 #define DP_PSR_ERROR_STATUS                 0x2006  /* XXX 1.2? */
 # define DP_PSR_LINK_CRC_ERROR              (1 << 0)
@@ -398,4 +409,118 @@ drm_dp_enhanced_frame_cap(const u8 dpcd[DP_RECEIVER_CAP_SIZE])
                (dpcd[DP_MAX_LANE_COUNT] & DP_ENHANCED_FRAME_CAP);
 }
 
+/*
+ * DisplayPort AUX channel
+ */
+
+/**
+ * struct drm_dp_aux_msg - DisplayPort AUX channel transaction
+ * @address: address of the (first) register to access
+ * @request: contains the type of transaction (see DP_AUX_* macros)
+ * @reply: upon completion, contains the reply type of the transaction
+ * @buffer: pointer to a transmission or reception buffer
+ * @size: size of @buffer
+ */
+struct drm_dp_aux_msg {
+       unsigned int address;
+       u8 request;
+       u8 reply;
+       void *buffer;
+       size_t size;
+};
+
+/**
+ * struct drm_dp_aux - DisplayPort AUX channel
+ * @ddc: I2C adapter that can be used for I2C-over-AUX communication
+ * @dev: pointer to struct device that is the parent for this AUX channel
+ * @transfer: transfers a message representing a single AUX transaction
+ *
+ * The .dev field should be set to a pointer to the device that implements
+ * the AUX channel.
+ *
+ * The .name field may be used to specify the name of the I2C adapter. If set to
+ * NULL, dev_name() of .dev will be used.
+ *
+ * Drivers provide a hardware-specific implementation of how transactions
+ * are executed via the .transfer() function. A pointer to a drm_dp_aux_msg
+ * structure describing the transaction is passed into this function. Upon
+ * success, the implementation should return the number of payload bytes
+ * that were transferred, or a negative error-code on failure. Helpers
+ * propagate errors from the .transfer() function, with the exception of
+ * the -EBUSY error, which causes a transaction to be retried. On a short,
+ * helpers will return -EPROTO to make it simpler to check for failure.
+ *
+ * An AUX channel can also be used to transport I2C messages to a sink. A
+ * typical application of that is to access an EDID that's present in the
+ * sink device. The .transfer() function can also be used to execute such
+ * transactions. The drm_dp_aux_register_i2c_bus() function registers an
+ * I2C adapter that can be passed to drm_probe_ddc(). Upon removal, drivers
+ * should call drm_dp_aux_unregister_i2c_bus() to remove the I2C adapter.
+ */
+struct drm_dp_aux {
+       const char *name;
+       struct i2c_adapter ddc;
+       struct device *dev;
+
+       ssize_t (*transfer)(struct drm_dp_aux *aux,
+                           struct drm_dp_aux_msg *msg);
+};
+
+ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
+                        void *buffer, size_t size);
+ssize_t drm_dp_dpcd_write(struct drm_dp_aux *aux, unsigned int offset,
+                         void *buffer, size_t size);
+
+/**
+ * drm_dp_dpcd_readb() - read a single byte from the DPCD
+ * @aux: DisplayPort AUX channel
+ * @offset: address of the register to read
+ * @valuep: location where the value of the register will be stored
+ *
+ * Returns the number of bytes transferred (1) on success, or a negative
+ * error code on failure.
+ */
+static inline ssize_t drm_dp_dpcd_readb(struct drm_dp_aux *aux,
+                                       unsigned int offset, u8 *valuep)
+{
+       return drm_dp_dpcd_read(aux, offset, valuep, 1);
+}
+
+/**
+ * drm_dp_dpcd_writeb() - write a single byte to the DPCD
+ * @aux: DisplayPort AUX channel
+ * @offset: address of the register to write
+ * @value: value to write to the register
+ *
+ * Returns the number of bytes transferred (1) on success, or a negative
+ * error code on failure.
+ */
+static inline ssize_t drm_dp_dpcd_writeb(struct drm_dp_aux *aux,
+                                        unsigned int offset, u8 value)
+{
+       return drm_dp_dpcd_write(aux, offset, &value, 1);
+}
+
+int drm_dp_dpcd_read_link_status(struct drm_dp_aux *aux,
+                                u8 status[DP_LINK_STATUS_SIZE]);
+
+/*
+ * DisplayPort link
+ */
+#define DP_LINK_CAP_ENHANCED_FRAMING (1 << 0)
+
+struct drm_dp_link {
+       unsigned char revision;
+       unsigned int rate;
+       unsigned int num_lanes;
+       unsigned long capabilities;
+};
+
+int drm_dp_link_probe(struct drm_dp_aux *aux, struct drm_dp_link *link);
+int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link);
+int drm_dp_link_configure(struct drm_dp_aux *aux, struct drm_dp_link *link);
+
+int drm_dp_aux_register_i2c_bus(struct drm_dp_aux *aux);
+void drm_dp_aux_unregister_i2c_bus(struct drm_dp_aux *aux);
+
 #endif /* _DRM_DP_HELPER_H_ */
index 0145b94..6e622f7 100644 (file)
@@ -121,5 +121,11 @@ bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel);
 int drm_fb_helper_single_add_all_connectors(struct drm_fb_helper *fb_helper);
 int drm_fb_helper_debug_enter(struct fb_info *info);
 int drm_fb_helper_debug_leave(struct fb_info *info);
+struct drm_display_mode *
+drm_has_preferred_mode(struct drm_fb_helper_connector *fb_connector,
+                       int width, int height);
+struct drm_display_mode *
+drm_pick_cmdline_mode(struct drm_fb_helper_connector *fb_helper_conn,
+                     int width, int height);
 
 #endif
index 89b4d7d..2a3cea9 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef __DRM_GEM_CMA_HELPER_H__
 #define __DRM_GEM_CMA_HELPER_H__
 
+#include <drm/drmP.h>
+
 struct drm_gem_cma_object {
        struct drm_gem_object base;
        dma_addr_t paddr;
index d32628a..7209df1 100644 (file)
 struct mipi_dsi_host;
 struct mipi_dsi_device;
 
+/* request ACK from peripheral */
+#define MIPI_DSI_MSG_REQ_ACK   BIT(0)
+/* use Low Power Mode to transmit message */
+#define MIPI_DSI_MSG_USE_LPM   BIT(1)
+
 /**
  * struct mipi_dsi_msg - read/write DSI buffer
  * @channel: virtual channel id
@@ -29,6 +34,7 @@ struct mipi_dsi_device;
 struct mipi_dsi_msg {
        u8 channel;
        u8 type;
+       u16 flags;
 
        size_t tx_len;
        const void *tx_buf;
index cba6786..a24addf 100644 (file)
 enum drm_mm_search_flags {
        DRM_MM_SEARCH_DEFAULT =         0,
        DRM_MM_SEARCH_BEST =            1 << 0,
+       DRM_MM_SEARCH_BELOW =           1 << 1,
 };
 
+enum drm_mm_allocator_flags {
+       DRM_MM_CREATE_DEFAULT =         0,
+       DRM_MM_CREATE_TOP =             1 << 0,
+};
+
+#define DRM_MM_BOTTOMUP DRM_MM_SEARCH_DEFAULT, DRM_MM_CREATE_DEFAULT
+#define DRM_MM_TOPDOWN DRM_MM_SEARCH_BELOW, DRM_MM_CREATE_TOP
+
 struct drm_mm_node {
        struct list_head node_list;
        struct list_head hole_stack;
@@ -85,11 +94,31 @@ struct drm_mm {
                             unsigned long *start, unsigned long *end);
 };
 
+/**
+ * drm_mm_node_allocated - checks whether a node is allocated
+ * @node: drm_mm_node to check
+ *
+ * Drivers should use this helpers for proper encapusulation of drm_mm
+ * internals.
+ *
+ * Returns:
+ * True if the @node is allocated.
+ */
 static inline bool drm_mm_node_allocated(struct drm_mm_node *node)
 {
        return node->allocated;
 }
 
+/**
+ * drm_mm_initialized - checks whether an allocator is initialized
+ * @mm: drm_mm to check
+ *
+ * Drivers should use this helpers for proper encapusulation of drm_mm
+ * internals.
+ *
+ * Returns:
+ * True if the @mm is initialized.
+ */
 static inline bool drm_mm_initialized(struct drm_mm *mm)
 {
        return mm->hole_stack.next;
@@ -100,6 +129,17 @@ static inline unsigned long __drm_mm_hole_node_start(struct drm_mm_node *hole_no
        return hole_node->start + hole_node->size;
 }
 
+/**
+ * drm_mm_hole_node_start - computes the start of the hole following @node
+ * @hole_node: drm_mm_node which implicitly tracks the following hole
+ *
+ * This is useful for driver-sepific debug dumpers. Otherwise drivers should not
+ * inspect holes themselves. Drivers must check first whether a hole indeed
+ * follows by looking at node->hole_follows.
+ *
+ * Returns:
+ * Start of the subsequent hole.
+ */
 static inline unsigned long drm_mm_hole_node_start(struct drm_mm_node *hole_node)
 {
        BUG_ON(!hole_node->hole_follows);
@@ -112,18 +152,52 @@ static inline unsigned long __drm_mm_hole_node_end(struct drm_mm_node *hole_node
                          struct drm_mm_node, node_list)->start;
 }
 
+/**
+ * drm_mm_hole_node_end - computes the end of the hole following @node
+ * @hole_node: drm_mm_node which implicitly tracks the following hole
+ *
+ * This is useful for driver-sepific debug dumpers. Otherwise drivers should not
+ * inspect holes themselves. Drivers must check first whether a hole indeed
+ * follows by looking at node->hole_follows.
+ *
+ * Returns:
+ * End of the subsequent hole.
+ */
 static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
 {
        return __drm_mm_hole_node_end(hole_node);
 }
 
+/**
+ * drm_mm_for_each_node - iterator to walk over all allocated nodes
+ * @entry: drm_mm_node structure to assign to in each iteration step
+ * @mm: drm_mm allocator to walk
+ *
+ * This iterator walks over all nodes in the range allocator. It is implemented
+ * with list_for_each, so not save against removal of elements.
+ */
 #define drm_mm_for_each_node(entry, mm) list_for_each_entry(entry, \
                                                &(mm)->head_node.node_list, \
                                                node_list)
 
-/* Note that we need to unroll list_for_each_entry in order to inline
- * setting hole_start and hole_end on each iteration and keep the
- * macro sane.
+/**
+ * drm_mm_for_each_hole - iterator to walk over all holes
+ * @entry: drm_mm_node used internally to track progress
+ * @mm: drm_mm allocator to walk
+ * @hole_start: ulong variable to assign the hole start to on each iteration
+ * @hole_end: ulong variable to assign the hole end to on each iteration
+ *
+ * This iterator walks over all holes in the range allocator. It is implemented
+ * with list_for_each, so not save against removal of elements. @entry is used
+ * internally and will not reflect a real drm_mm_node for the very first hole.
+ * Hence users of this iterator may not access it.
+ *
+ * Implementation Note:
+ * We need to inline list_for_each_entry in order to be able to set hole_start
+ * and hole_end on each iteration while keeping the macro sane.
+ *
+ * The __drm_mm_for_each_hole version is similar, but with added support for
+ * going backwards.
  */
 #define drm_mm_for_each_hole(entry, mm, hole_start, hole_end) \
        for (entry = list_entry((mm)->hole_stack.next, struct drm_mm_node, hole_stack); \
@@ -133,34 +207,79 @@ static inline unsigned long drm_mm_hole_node_end(struct drm_mm_node *hole_node)
             1 : 0; \
             entry = list_entry(entry->hole_stack.next, struct drm_mm_node, hole_stack))
 
+#define __drm_mm_for_each_hole(entry, mm, hole_start, hole_end, backwards) \
+       for (entry = list_entry((backwards) ? (mm)->hole_stack.prev : (mm)->hole_stack.next, struct drm_mm_node, hole_stack); \
+            &entry->hole_stack != &(mm)->hole_stack ? \
+            hole_start = drm_mm_hole_node_start(entry), \
+            hole_end = drm_mm_hole_node_end(entry), \
+            1 : 0; \
+            entry = list_entry((backwards) ? entry->hole_stack.prev : entry->hole_stack.next, struct drm_mm_node, hole_stack))
+
 /*
  * Basic range manager support (drm_mm.c)
  */
-extern int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node);
-
-extern int drm_mm_insert_node_generic(struct drm_mm *mm,
-                                     struct drm_mm_node *node,
-                                     unsigned long size,
-                                     unsigned alignment,
-                                     unsigned long color,
-                                     enum drm_mm_search_flags flags);
+int drm_mm_reserve_node(struct drm_mm *mm, struct drm_mm_node *node);
+
+int drm_mm_insert_node_generic(struct drm_mm *mm,
+                              struct drm_mm_node *node,
+                              unsigned long size,
+                              unsigned alignment,
+                              unsigned long color,
+                              enum drm_mm_search_flags sflags,
+                              enum drm_mm_allocator_flags aflags);
+/**
+ * drm_mm_insert_node - search for space and insert @node
+ * @mm: drm_mm to allocate from
+ * @node: preallocate node to insert
+ * @size: size of the allocation
+ * @alignment: alignment of the allocation
+ * @flags: flags to fine-tune the allocation
+ *
+ * This is a simplified version of drm_mm_insert_node_generic() with @color set
+ * to 0.
+ *
+ * The preallocated node must be cleared to 0.
+ *
+ * Returns:
+ * 0 on success, -ENOSPC if there's no suitable hole.
+ */
 static inline int drm_mm_insert_node(struct drm_mm *mm,
                                     struct drm_mm_node *node,
                                     unsigned long size,
                                     unsigned alignment,
                                     enum drm_mm_search_flags flags)
 {
-       return drm_mm_insert_node_generic(mm, node, size, alignment, 0, flags);
+       return drm_mm_insert_node_generic(mm, node, size, alignment, 0, flags,
+                                         DRM_MM_CREATE_DEFAULT);
 }
 
-extern int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
-                                      struct drm_mm_node *node,
-                                      unsigned long size,
-                                      unsigned alignment,
-                                      unsigned long color,
-                                      unsigned long start,
-                                      unsigned long end,
-                                      enum drm_mm_search_flags flags);
+int drm_mm_insert_node_in_range_generic(struct drm_mm *mm,
+                                       struct drm_mm_node *node,
+                                       unsigned long size,
+                                       unsigned alignment,
+                                       unsigned long color,
+                                       unsigned long start,
+                                       unsigned long end,
+                                       enum drm_mm_search_flags sflags,
+                                       enum drm_mm_allocator_flags aflags);
+/**
+ * drm_mm_insert_node_in_range - ranged search for space and insert @node
+ * @mm: drm_mm to allocate from
+ * @node: preallocate node to insert
+ * @size: size of the allocation
+ * @alignment: alignment of the allocation
+ * @start: start of the allowed range for this node
+ * @end: end of the allowed range for this node
+ * @flags: flags to fine-tune the allocation
+ *
+ * This is a simplified version of drm_mm_insert_node_in_range_generic() with
+ * @color set to 0.
+ *
+ * The preallocated node must be cleared to 0.
+ *
+ * Returns:
+ * 0 on success, -ENOSPC if there's no suitable hole.
+ */
 static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
                                              struct drm_mm_node *node,
                                              unsigned long size,
@@ -170,16 +289,17 @@ static inline int drm_mm_insert_node_in_range(struct drm_mm *mm,
                                              enum drm_mm_search_flags flags)
 {
        return drm_mm_insert_node_in_range_generic(mm, node, size, alignment,
-                                                  0, start, end, flags);
+                                                  0, start, end, flags,
+                                                  DRM_MM_CREATE_DEFAULT);
 }
 
-extern void drm_mm_remove_node(struct drm_mm_node *node);
-extern void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
-extern void drm_mm_init(struct drm_mm *mm,
-                       unsigned long start,
-                       unsigned long size);
-extern void drm_mm_takedown(struct drm_mm *mm);
-extern int drm_mm_clean(struct drm_mm *mm);
+void drm_mm_remove_node(struct drm_mm_node *node);
+void drm_mm_replace_node(struct drm_mm_node *old, struct drm_mm_node *new);
+void drm_mm_init(struct drm_mm *mm,
+                unsigned long start,
+                unsigned long size);
+void drm_mm_takedown(struct drm_mm *mm);
+bool drm_mm_clean(struct drm_mm *mm);
 
 void drm_mm_init_scan(struct drm_mm *mm,
                      unsigned long size,
@@ -191,10 +311,10 @@ void drm_mm_init_scan_with_range(struct drm_mm *mm,
                                 unsigned long color,
                                 unsigned long start,
                                 unsigned long end);
-int drm_mm_scan_add_block(struct drm_mm_node *node);
-int drm_mm_scan_remove_block(struct drm_mm_node *node);
+bool drm_mm_scan_add_block(struct drm_mm_node *node);
+bool drm_mm_scan_remove_block(struct drm_mm_node *node);
 
-extern void drm_mm_debug_table(struct drm_mm *mm, const char *prefix);
+void drm_mm_debug_table(struct drm_mm *mm, const char *prefix);
 #ifdef CONFIG_DEBUG_FS
 int drm_mm_dump_table(struct seq_file *m, struct drm_mm *mm);
 #endif
diff --git a/include/drm/drm_modes.h b/include/drm/drm_modes.h
new file mode 100644 (file)
index 0000000..2dbbf99
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ * Copyright © 2006 Keith Packard
+ * Copyright © 2007-2008 Dave Airlie
+ * Copyright © 2007-2008 Intel Corporation
+ *   Jesse Barnes <jesse.barnes@intel.com>
+ * Copyright © 2014 Intel Corporation
+ *   Daniel Vetter <daniel.vetter@ffwll.ch>
+ *
+ * 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.
+ */
+#ifndef __DRM_MODES_H__
+#define __DRM_MODES_H__
+
+/*
+ * Note on terminology:  here, for brevity and convenience, we refer to connector
+ * control chips as 'CRTCs'.  They can control any type of connector, VGA, LVDS,
+ * DVI, etc.  And 'screen' refers to the whole of the visible display, which
+ * may span multiple monitors (and therefore multiple CRTC and connector
+ * structures).
+ */
+
+enum drm_mode_status {
+    MODE_OK    = 0,    /* Mode OK */
+    MODE_HSYNC,                /* hsync out of range */
+    MODE_VSYNC,                /* vsync out of range */
+    MODE_H_ILLEGAL,    /* mode has illegal horizontal timings */
+    MODE_V_ILLEGAL,    /* mode has illegal horizontal timings */
+    MODE_BAD_WIDTH,    /* requires an unsupported linepitch */
+    MODE_NOMODE,       /* no mode with a matching name */
+    MODE_NO_INTERLACE, /* interlaced mode not supported */
+    MODE_NO_DBLESCAN,  /* doublescan mode not supported */
+    MODE_NO_VSCAN,     /* multiscan mode not supported */
+    MODE_MEM,          /* insufficient video memory */
+    MODE_VIRTUAL_X,    /* mode width too large for specified virtual size */
+    MODE_VIRTUAL_Y,    /* mode height too large for specified virtual size */
+    MODE_MEM_VIRT,     /* insufficient video memory given virtual size */
+    MODE_NOCLOCK,      /* no fixed clock available */
+    MODE_CLOCK_HIGH,   /* clock required is too high */
+    MODE_CLOCK_LOW,    /* clock required is too low */
+    MODE_CLOCK_RANGE,  /* clock/mode isn't in a ClockRange */
+    MODE_BAD_HVALUE,   /* horizontal timing was out of range */
+    MODE_BAD_VVALUE,   /* vertical timing was out of range */
+    MODE_BAD_VSCAN,    /* VScan value out of range */
+    MODE_HSYNC_NARROW, /* horizontal sync too narrow */
+    MODE_HSYNC_WIDE,   /* horizontal sync too wide */
+    MODE_HBLANK_NARROW,        /* horizontal blanking too narrow */
+    MODE_HBLANK_WIDE,  /* horizontal blanking too wide */
+    MODE_VSYNC_NARROW, /* vertical sync too narrow */
+    MODE_VSYNC_WIDE,   /* vertical sync too wide */
+    MODE_VBLANK_NARROW,        /* vertical blanking too narrow */
+    MODE_VBLANK_WIDE,  /* vertical blanking too wide */
+    MODE_PANEL,         /* exceeds panel dimensions */
+    MODE_INTERLACE_WIDTH, /* width too large for interlaced mode */
+    MODE_ONE_WIDTH,     /* only one width is supported */
+    MODE_ONE_HEIGHT,    /* only one height is supported */
+    MODE_ONE_SIZE,      /* only one resolution is supported */
+    MODE_NO_REDUCED,    /* monitor doesn't accept reduced blanking */
+    MODE_NO_STEREO,    /* stereo modes not supported */
+    MODE_UNVERIFIED = -3, /* mode needs to reverified */
+    MODE_BAD = -2,     /* unspecified reason */
+    MODE_ERROR = -1    /* error condition */
+};
+
+#define DRM_MODE_TYPE_CLOCK_CRTC_C (DRM_MODE_TYPE_CLOCK_C | \
+                                   DRM_MODE_TYPE_CRTC_C)
+
+#define DRM_MODE(nm, t, c, hd, hss, hse, ht, hsk, vd, vss, vse, vt, vs, f) \
+       .name = nm, .status = 0, .type = (t), .clock = (c), \
+       .hdisplay = (hd), .hsync_start = (hss), .hsync_end = (hse), \
+       .htotal = (ht), .hskew = (hsk), .vdisplay = (vd), \
+       .vsync_start = (vss), .vsync_end = (vse), .vtotal = (vt), \
+       .vscan = (vs), .flags = (f), \
+       .base.type = DRM_MODE_OBJECT_MODE
+
+#define CRTC_INTERLACE_HALVE_V (1 << 0) /* halve V values for interlacing */
+#define CRTC_STEREO_DOUBLE     (1 << 1) /* adjust timings for stereo modes */
+
+#define DRM_MODE_FLAG_3D_MAX   DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF
+
+struct drm_display_mode {
+       /* Header */
+       struct list_head head;
+       struct drm_mode_object base;
+
+       char name[DRM_DISPLAY_MODE_LEN];
+
+       enum drm_mode_status status;
+       unsigned int type;
+
+       /* Proposed mode values */
+       int clock;              /* in kHz */
+       int hdisplay;
+       int hsync_start;
+       int hsync_end;
+       int htotal;
+       int hskew;
+       int vdisplay;
+       int vsync_start;
+       int vsync_end;
+       int vtotal;
+       int vscan;
+       unsigned int flags;
+
+       /* Addressable image size (may be 0 for projectors, etc.) */
+       int width_mm;
+       int height_mm;
+
+       /* Actual mode we give to hw */
+       int crtc_clock;         /* in KHz */
+       int crtc_hdisplay;
+       int crtc_hblank_start;
+       int crtc_hblank_end;
+       int crtc_hsync_start;
+       int crtc_hsync_end;
+       int crtc_htotal;
+       int crtc_hskew;
+       int crtc_vdisplay;
+       int crtc_vblank_start;
+       int crtc_vblank_end;
+       int crtc_vsync_start;
+       int crtc_vsync_end;
+       int crtc_vtotal;
+
+       /* Driver private mode info */
+       int *private;
+       int private_flags;
+
+       int vrefresh;           /* in Hz */
+       int hsync;              /* in kHz */
+       enum hdmi_picture_aspect picture_aspect_ratio;
+};
+
+/* mode specified on the command line */
+struct drm_cmdline_mode {
+       bool specified;
+       bool refresh_specified;
+       bool bpp_specified;
+       int xres, yres;
+       int bpp;
+       int refresh;
+       bool rb;
+       bool interlace;
+       bool cvt;
+       bool margins;
+       enum drm_connector_force force;
+};
+
+/**
+ * drm_mode_is_stereo - check for stereo mode flags
+ * @mode: drm_display_mode to check
+ *
+ * Returns:
+ * True if the mode is one of the stereo modes (like side-by-side), false if
+ * not.
+ */
+static inline bool drm_mode_is_stereo(const struct drm_display_mode *mode)
+{
+       return mode->flags & DRM_MODE_FLAG_3D_MASK;
+}
+
+struct drm_connector;
+struct drm_cmdline_mode;
+
+struct drm_display_mode *drm_mode_create(struct drm_device *dev);
+void drm_mode_destroy(struct drm_device *dev, struct drm_display_mode *mode);
+void drm_mode_probed_add(struct drm_connector *connector, struct drm_display_mode *mode);
+void drm_mode_debug_printmodeline(const struct drm_display_mode *mode);
+
+struct drm_display_mode *drm_cvt_mode(struct drm_device *dev,
+                                     int hdisplay, int vdisplay, int vrefresh,
+                                     bool reduced, bool interlaced,
+                                     bool margins);
+struct drm_display_mode *drm_gtf_mode(struct drm_device *dev,
+                                     int hdisplay, int vdisplay, int vrefresh,
+                                     bool interlaced, int margins);
+struct drm_display_mode *drm_gtf_mode_complex(struct drm_device *dev,
+                                             int hdisplay, int vdisplay,
+                                             int vrefresh, bool interlaced,
+                                             int margins,
+                                             int GTF_M, int GTF_2C,
+                                             int GTF_K, int GTF_2J);
+void drm_display_mode_from_videomode(const struct videomode *vm,
+                                    struct drm_display_mode *dmode);
+int of_get_drm_display_mode(struct device_node *np,
+                           struct drm_display_mode *dmode,
+                           int index);
+
+void drm_mode_set_name(struct drm_display_mode *mode);
+int drm_mode_hsync(const struct drm_display_mode *mode);
+int drm_mode_vrefresh(const struct drm_display_mode *mode);
+
+void drm_mode_set_crtcinfo(struct drm_display_mode *p,
+                          int adjust_flags);
+void drm_mode_copy(struct drm_display_mode *dst,
+                  const struct drm_display_mode *src);
+struct drm_display_mode *drm_mode_duplicate(struct drm_device *dev,
+                                           const struct drm_display_mode *mode);
+bool drm_mode_equal(const struct drm_display_mode *mode1,
+                   const struct drm_display_mode *mode2);
+bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
+                                       const struct drm_display_mode *mode2);
+
+/* for use by the crtc helper probe functions */
+void drm_mode_validate_size(struct drm_device *dev,
+                           struct list_head *mode_list,
+                           int maxX, int maxY);
+void drm_mode_prune_invalid(struct drm_device *dev,
+                           struct list_head *mode_list, bool verbose);
+void drm_mode_sort(struct list_head *mode_list);
+void drm_mode_connector_list_update(struct drm_connector *connector);
+
+/* parsing cmdline modes */
+bool
+drm_mode_parse_command_line_for_connector(const char *mode_option,
+                                         struct drm_connector *connector,
+                                         struct drm_cmdline_mode *mode);
+struct drm_display_mode *
+drm_mode_create_from_cmdline_mode(struct drm_device *dev,
+                                 struct drm_cmdline_mode *cmd);
+
+#endif /* __DRM_MODES_H__ */
diff --git a/include/drm/drm_plane_helper.h b/include/drm/drm_plane_helper.h
new file mode 100644 (file)
index 0000000..09824be
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2011-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.
+ */
+
+#ifndef DRM_PLANE_HELPER_H
+#define DRM_PLANE_HELPER_H
+
+/**
+ * DOC: plane helpers
+ *
+ * Helper functions to assist with creation and handling of CRTC primary
+ * planes.
+ */
+
+extern int drm_primary_helper_update(struct drm_plane *plane,
+                                    struct drm_crtc *crtc,
+                                    struct drm_framebuffer *fb,
+                                    int crtc_x, int crtc_y,
+                                    unsigned int crtc_w, unsigned int crtc_h,
+                                    uint32_t src_x, uint32_t src_y,
+                                    uint32_t src_w, uint32_t src_h);
+extern int drm_primary_helper_disable(struct drm_plane *plane);
+extern void drm_primary_helper_destroy(struct drm_plane *plane);
+extern const struct drm_plane_funcs drm_primary_helper_funcs;
+extern struct drm_plane *drm_primary_helper_create_plane(struct drm_device *dev,
+                                                        uint32_t *formats,
+                                                        int num_formats);
+
+
+#endif
index c18a593..8cd402c 100644 (file)
@@ -221,8 +221,8 @@ static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *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.
+ * associated with the @file_mapping address-space. If no offset exists
+ * nothing is done.
  *
  * This call is unlocked. The caller must guarantee that drm_vma_offset_remove()
  * is not called on this node concurrently.
@@ -230,7 +230,7 @@ static inline __u64 drm_vma_node_offset_addr(struct drm_vma_offset_node *node)
 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))
+       if (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);
index 884613e..87ac5e6 100644 (file)
  *
  **************************************************************************/
 
-#ifndef _PSB_DRM_H_
-#define _PSB_DRM_H_
-
-/*
- *     Manage the LUT for an output
- */
-struct drm_psb_dpst_lut_arg {
-       uint8_t lut[256];
-       int output_id;
-};
-
-/*
- *     Validate modes
- */
-struct drm_psb_mode_operation_arg {
-       u32 obj_id;
-       u16 operation;
-       struct drm_mode_modeinfo mode;
-       u64 data;
-};
-
-/*
- *     Query the stolen memory for smarter management of
- *     memory by the server
- */
-struct drm_psb_stolen_memory_arg {
-       u32 base;
-       u32 size;
-};
-
-struct drm_psb_get_pipe_from_crtc_id_arg {
-       /** ID of CRTC being requested **/
-       u32 crtc_id;
-       /** pipe of requested CRTC **/
-       u32 pipe;
-};
-
-struct drm_psb_gem_create {
-       __u64 size;
-       __u32 handle;
-       __u32 flags;
-#define GMA_GEM_CREATE_STOLEN          1       /* Stolen memory can be used */
-};
-
-struct drm_psb_gem_mmap {
-       __u32 handle;
-       __u32 pad;
-       /**
-        * Fake offset to use for subsequent mmap call
-        *
-        * This is a fixed-size type for 32/64 compatibility.
-        */
-       __u64 offset;
-};
-
-/* Controlling the kernel modesetting buffers */
-
-#define DRM_GMA_GEM_CREATE     0x00            /* Create a GEM object */
-#define DRM_GMA_GEM_MMAP       0x01            /* Map GEM memory */
-#define DRM_GMA_STOLEN_MEMORY  0x02            /* Report stolen memory */
-#define DRM_GMA_2D_OP          0x03            /* Will be merged later */
-#define DRM_GMA_GAMMA          0x04            /* Set gamma table */
-#define DRM_GMA_ADB            0x05            /* Get backlight */
-#define DRM_GMA_DPST_BL                0x06            /* Set backlight */
-#define DRM_GMA_MODE_OPERATION 0x07            /* Mode validation/DC set */
-#define        PSB_MODE_OPERATION_MODE_VALID   0x01
-#define DRM_GMA_GET_PIPE_FROM_CRTC_ID  0x08    /* CRTC to physical pipe# */
-
+#ifndef _GMA_DRM_H_
+#define _GMA_DRM_H_
 
 #endif
index 32d34eb..a5183da 100644 (file)
@@ -747,6 +747,7 @@ extern int ttm_bo_device_release(struct ttm_bo_device *bdev);
  * @bdev: A pointer to a struct ttm_bo_device to initialize.
  * @glob: A pointer to an initialized struct ttm_bo_global.
  * @driver: A pointer to a struct ttm_bo_driver set up by the caller.
+ * @mapping: The address space to use for this bo.
  * @file_page_offset: Offset into the device address space that is available
  * for buffer data. This ensures compatibility with other users of the
  * address space.
@@ -758,6 +759,7 @@ extern int ttm_bo_device_release(struct ttm_bo_device *bdev);
 extern int ttm_bo_device_init(struct ttm_bo_device *bdev,
                              struct ttm_bo_global *glob,
                              struct ttm_bo_driver *driver,
+                             struct address_space *mapping,
                              uint64_t file_page_offset, bool need_dma32);
 
 /**
@@ -786,7 +788,7 @@ extern void ttm_bo_del_sub_from_lru(struct ttm_buffer_object *bo);
 extern void ttm_bo_add_to_lru(struct ttm_buffer_object *bo);
 
 /**
- * ttm_bo_reserve_nolru:
+ * __ttm_bo_reserve:
  *
  * @bo: A pointer to a struct ttm_buffer_object.
  * @interruptible: Sleep interruptible if waiting.
@@ -807,10 +809,10 @@ extern void ttm_bo_add_to_lru(struct ttm_buffer_object *bo);
  * -EALREADY: Bo already reserved using @ticket. This error code will only
  * be returned if @use_ticket is set to true.
  */
-static inline int ttm_bo_reserve_nolru(struct ttm_buffer_object *bo,
-                                      bool interruptible,
-                                      bool no_wait, bool use_ticket,
-                                      struct ww_acquire_ctx *ticket)
+static inline int __ttm_bo_reserve(struct ttm_buffer_object *bo,
+                                  bool interruptible,
+                                  bool no_wait, bool use_ticket,
+                                  struct ww_acquire_ctx *ticket)
 {
        int ret = 0;
 
@@ -886,8 +888,7 @@ static inline int ttm_bo_reserve(struct ttm_buffer_object *bo,
 
        WARN_ON(!atomic_read(&bo->kref.refcount));
 
-       ret = ttm_bo_reserve_nolru(bo, interruptible, no_wait, use_ticket,
-                                   ticket);
+       ret = __ttm_bo_reserve(bo, interruptible, no_wait, use_ticket, ticket);
        if (likely(ret == 0))
                ttm_bo_del_sub_from_lru(bo);
 
@@ -927,20 +928,14 @@ static inline int ttm_bo_reserve_slowpath(struct ttm_buffer_object *bo,
 }
 
 /**
- * ttm_bo_unreserve_ticket
+ * __ttm_bo_unreserve
  * @bo: A pointer to a struct ttm_buffer_object.
- * @ticket: ww_acquire_ctx used for reserving
  *
- * Unreserve a previous reservation of @bo made with @ticket.
+ * Unreserve a previous reservation of @bo where the buffer object is
+ * already on lru lists.
  */
-static inline void ttm_bo_unreserve_ticket(struct ttm_buffer_object *bo,
-                                          struct ww_acquire_ctx *t)
+static inline void __ttm_bo_unreserve(struct ttm_buffer_object *bo)
 {
-       if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) {
-               spin_lock(&bo->glob->lru_lock);
-               ttm_bo_add_to_lru(bo);
-               spin_unlock(&bo->glob->lru_lock);
-       }
        ww_mutex_unlock(&bo->resv->lock);
 }
 
@@ -953,7 +948,25 @@ static inline void ttm_bo_unreserve_ticket(struct ttm_buffer_object *bo,
  */
 static inline void ttm_bo_unreserve(struct ttm_buffer_object *bo)
 {
-       ttm_bo_unreserve_ticket(bo, NULL);
+       if (!(bo->mem.placement & TTM_PL_FLAG_NO_EVICT)) {
+               spin_lock(&bo->glob->lru_lock);
+               ttm_bo_add_to_lru(bo);
+               spin_unlock(&bo->glob->lru_lock);
+       }
+       __ttm_bo_unreserve(bo);
+}
+
+/**
+ * ttm_bo_unreserve_ticket
+ * @bo: A pointer to a struct ttm_buffer_object.
+ * @ticket: ww_acquire_ctx used for reserving
+ *
+ * Unreserve a previous reservation of @bo made with @ticket.
+ */
+static inline void ttm_bo_unreserve_ticket(struct ttm_buffer_object *bo,
+                                          struct ww_acquire_ctx *t)
+{
+       ttm_bo_unreserve(bo);
 }
 
 /*
index 0097cc0..ed953f9 100644 (file)
@@ -244,6 +244,10 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base);
 extern int ttm_ref_object_add(struct ttm_object_file *tfile,
                              struct ttm_base_object *base,
                              enum ttm_ref_type ref_type, bool *existed);
+
+extern bool ttm_ref_object_exists(struct ttm_object_file *tfile,
+                                 struct ttm_base_object *base);
+
 /**
  * ttm_ref_object_base_unref
  *
index c84ff15..8ed44f9 100644 (file)
@@ -65,6 +65,8 @@
  * reference the buffer.
  * TTM_PL_FLAG_NO_EVICT means that the buffer may never
  * be evicted to make room for other buffers.
+ * TTM_PL_FLAG_TOPDOWN requests to be placed from the
+ * top of the memory area, instead of the bottom.
  */
 
 #define TTM_PL_FLAG_CACHED      (1 << 16)
@@ -72,6 +74,7 @@
 #define TTM_PL_FLAG_WC          (1 << 18)
 #define TTM_PL_FLAG_SHARED      (1 << 20)
 #define TTM_PL_FLAG_NO_EVICT    (1 << 21)
+#define TTM_PL_FLAG_TOPDOWN     (1 << 22)
 
 #define TTM_PL_MASK_CACHING     (TTM_PL_FLAG_CACHED | \
                                 TTM_PL_FLAG_UNCACHED | \
index fb02980..329436d 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <linux/list.h>
 #include <linux/device.h>
+#include <linux/err.h>
 #include <linux/dmaengine.h>
 
 /**
@@ -103,12 +104,12 @@ static inline void devm_acpi_dma_controller_free(struct device *dev)
 static inline struct dma_chan *acpi_dma_request_slave_chan_by_index(
                struct device *dev, size_t index)
 {
-       return NULL;
+       return ERR_PTR(-ENODEV);
 }
 static inline struct dma_chan *acpi_dma_request_slave_chan_by_name(
                struct device *dev, const char *name)
 {
-       return NULL;
+       return ERR_PTR(-ENODEV);
 }
 
 #define acpi_dma_simple_xlate  NULL
index b4a745d..61f29e5 100644 (file)
@@ -44,7 +44,6 @@ struct linux_binprm {
        unsigned interp_flags;
        unsigned interp_data;
        unsigned long loader, exec;
-       char tcomm[TASK_COMM_LEN];
 };
 
 #define BINPRM_FLAGS_ENFORCE_NONDUMP_BIT 0
index 5a4d39b..5aa372a 100644 (file)
@@ -216,9 +216,9 @@ static inline void bvec_iter_advance(struct bio_vec *bv, struct bvec_iter *iter,
 }
 
 #define for_each_bvec(bvl, bio_vec, iter, start)                       \
-       for ((iter) = start;                                            \
-            (bvl) = bvec_iter_bvec((bio_vec), (iter)),                 \
-               (iter).bi_size;                                         \
+       for (iter = (start);                                            \
+            (iter).bi_size &&                                          \
+               ((bvl = bvec_iter_bvec((bio_vec), (iter))), 1); \
             bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len))
 
 
index bbc3a6c..aa0eaa2 100644 (file)
@@ -189,6 +189,7 @@ enum rq_flag_bits {
        __REQ_KERNEL,           /* direct IO to kernel pages */
        __REQ_PM,               /* runtime pm request */
        __REQ_END,              /* last of chain of requests */
+       __REQ_HASHED,           /* on IO scheduler merge hash */
        __REQ_NR_BITS,          /* stops here */
 };
 
@@ -241,5 +242,6 @@ enum rq_flag_bits {
 #define REQ_KERNEL             (1ULL << __REQ_KERNEL)
 #define REQ_PM                 (1ULL << __REQ_PM)
 #define REQ_END                        (1ULL << __REQ_END)
+#define REQ_HASHED             (1ULL << __REQ_HASHED)
 
 #endif /* __LINUX_BLK_TYPES_H */
index 1e1fa3f..99617cf 100644 (file)
@@ -118,7 +118,18 @@ struct request {
        struct bio *bio;
        struct bio *biotail;
 
-       struct hlist_node hash; /* merge hash */
+       /*
+        * The hash is used inside the scheduler, and killed once the
+        * request reaches the dispatch list. The ipi_list is only used
+        * to queue the request for softirq completion, which is long
+        * after the request has been unhashed (and even removed from
+        * the dispatch list).
+        */
+       union {
+               struct hlist_node hash; /* merge hash */
+               struct list_head ipi_list;
+       };
+
        /*
         * The rb_node is only used inside the io scheduler, requests
         * are pruned when moved to the dispatch queue. So let the
index 138448f..d12659c 100644 (file)
 #define CEPH_FEATURE_CRUSH_V2      (1ULL<<36)  /* new indep; SET_* steps */
 #define CEPH_FEATURE_EXPORT_PEER   (1ULL<<37)
 #define CEPH_FEATURE_OSD_ERASURE_CODES (1ULL<<38)
+#define CEPH_FEATURE_OSD_TMAP2OMAP (1ULL<<38)   /* overlap with EC */
+/* The process supports new-style OSDMap encoding. Monitors also use
+   this bit to determine if peers support NAK messages. */
+#define CEPH_FEATURE_OSDMAP_ENC    (1ULL<<39)
+#define CEPH_FEATURE_MDS_INLINE_DATA     (1ULL<<40)
+#define CEPH_FEATURE_CRUSH_TUNABLES3     (1ULL<<41)
+#define CEPH_FEATURE_OSD_PRIMARY_AFFINITY (1ULL<<41)  /* overlap w/ tunables3 */
 
 /*
  * The introduction of CEPH_FEATURE_OSD_SNAPMAPPER caused the feature
@@ -82,7 +89,10 @@ static inline u64 ceph_sanitize_features(u64 features)
         CEPH_FEATURE_OSDHASHPSPOOL |           \
         CEPH_FEATURE_OSD_CACHEPOOL |           \
         CEPH_FEATURE_CRUSH_V2 |                \
-        CEPH_FEATURE_EXPORT_PEER)
+        CEPH_FEATURE_EXPORT_PEER |             \
+        CEPH_FEATURE_OSDMAP_ENC |              \
+        CEPH_FEATURE_CRUSH_TUNABLES3 |         \
+        CEPH_FEATURE_OSD_PRIMARY_AFFINITY)
 
 #define CEPH_FEATURES_REQUIRED_DEFAULT   \
        (CEPH_FEATURE_NOSRCADDR |        \
index 25bfb0e..5f6db18 100644 (file)
@@ -332,6 +332,7 @@ enum {
        CEPH_MDS_OP_LOOKUPHASH = 0x00102,
        CEPH_MDS_OP_LOOKUPPARENT = 0x00103,
        CEPH_MDS_OP_LOOKUPINO  = 0x00104,
+       CEPH_MDS_OP_LOOKUPNAME = 0x00105,
 
        CEPH_MDS_OP_SETXATTR   = 0x01105,
        CEPH_MDS_OP_RMXATTR    = 0x01106,
@@ -420,8 +421,8 @@ union ceph_mds_request_args {
        struct {
                __u8 rule; /* currently fcntl or flock */
                __u8 type; /* shared, exclusive, remove*/
+               __le64 owner; /* owner of the lock */
                __le64 pid; /* process id requesting the lock */
-               __le64 pid_namespace;
                __le64 start; /* initial location to lock */
                __le64 length; /* num bytes to lock from start */
                __u8 wait; /* will caller wait for lock to become available? */
@@ -532,8 +533,8 @@ struct ceph_filelock {
        __le64 start;/* file offset to start lock at */
        __le64 length; /* num bytes to lock; 0 for all following start */
        __le64 client; /* which client holds the lock */
+       __le64 owner; /* owner the lock */
        __le64 pid; /* process id holding the lock on the client */
-       __le64 pid_namespace;
        __u8 type; /* shared lock, exclusive lock, or unlock */
 } __attribute__ ((packed));
 
index fd47e87..94ec696 100644 (file)
@@ -43,7 +43,7 @@ struct ceph_osd {
 };
 
 
-#define CEPH_OSD_MAX_OP        2
+#define CEPH_OSD_MAX_OP        3
 
 enum ceph_osd_data_type {
        CEPH_OSD_DATA_TYPE_NONE = 0,
@@ -76,6 +76,7 @@ struct ceph_osd_data {
 
 struct ceph_osd_req_op {
        u16 op;           /* CEPH_OSD_OP_* */
+       u32 flags;        /* CEPH_OSD_OP_FLAG_* */
        u32 payload_len;
        union {
                struct ceph_osd_data raw_data_in;
@@ -102,6 +103,10 @@ struct ceph_osd_req_op {
                        u32 timeout;
                        __u8 flag;
                } watch;
+               struct {
+                       u64 expected_object_size;
+                       u64 expected_write_size;
+               } alloc_hint;
        };
 };
 
@@ -293,6 +298,10 @@ extern void osd_req_op_cls_init(struct ceph_osd_request *osd_req,
 extern void osd_req_op_watch_init(struct ceph_osd_request *osd_req,
                                        unsigned int which, u16 opcode,
                                        u64 cookie, u64 version, int flag);
+extern void osd_req_op_alloc_hint_init(struct ceph_osd_request *osd_req,
+                                      unsigned int which,
+                                      u64 expected_object_size,
+                                      u64 expected_write_size);
 
 extern struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
                                               struct ceph_snap_context *snapc,
index 49ff69f..561ea89 100644 (file)
@@ -41,6 +41,18 @@ struct ceph_pg_pool_info {
        char *name;
 };
 
+static inline bool ceph_can_shift_osds(struct ceph_pg_pool_info *pool)
+{
+       switch (pool->type) {
+       case CEPH_POOL_TYPE_REP:
+               return true;
+       case CEPH_POOL_TYPE_EC:
+               return false;
+       default:
+               BUG_ON(1);
+       }
+}
+
 struct ceph_object_locator {
        s64 pool;
 };
@@ -60,8 +72,16 @@ struct ceph_object_id {
 struct ceph_pg_mapping {
        struct rb_node node;
        struct ceph_pg pgid;
-       int len;
-       int osds[];
+
+       union {
+               struct {
+                       int len;
+                       int osds[];
+               } pg_temp;
+               struct {
+                       int osd;
+               } primary_temp;
+       };
 };
 
 struct ceph_osdmap {
@@ -78,12 +98,19 @@ struct ceph_osdmap {
        struct ceph_entity_addr *osd_addr;
 
        struct rb_root pg_temp;
+       struct rb_root primary_temp;
+
+       u32 *osd_primary_affinity;
+
        struct rb_root pg_pools;
        u32 pool_max;
 
        /* the CRUSH map specifies the mapping of placement groups to
         * the list of osds that store+replicate them. */
        struct crush_map *crush;
+
+       struct mutex crush_scratch_mutex;
+       int crush_scratch_ary[CEPH_PG_MAX_SIZE * 3];
 };
 
 static inline void ceph_oid_set_name(struct ceph_object_id *oid,
@@ -110,9 +137,21 @@ static inline void ceph_oid_copy(struct ceph_object_id *dest,
        dest->name_len = src->name_len;
 }
 
+static inline int ceph_osd_exists(struct ceph_osdmap *map, int osd)
+{
+       return osd >= 0 && osd < map->max_osd &&
+              (map->osd_state[osd] & CEPH_OSD_EXISTS);
+}
+
 static inline int ceph_osd_is_up(struct ceph_osdmap *map, int osd)
 {
-       return (osd < map->max_osd) && (map->osd_state[osd] & CEPH_OSD_UP);
+       return ceph_osd_exists(map, osd) &&
+              (map->osd_state[osd] & CEPH_OSD_UP);
+}
+
+static inline int ceph_osd_is_down(struct ceph_osdmap *map, int osd)
+{
+       return !ceph_osd_is_up(map, osd);
 }
 
 static inline bool ceph_osdmap_flag(struct ceph_osdmap *map, int flag)
@@ -121,6 +160,7 @@ static inline bool ceph_osdmap_flag(struct ceph_osdmap *map, int flag)
 }
 
 extern char *ceph_osdmap_state_str(char *str, int len, int state);
+extern u32 ceph_get_primary_affinity(struct ceph_osdmap *map, int osd);
 
 static inline struct ceph_entity_addr *ceph_osd_addr(struct ceph_osdmap *map,
                                                     int osd)
@@ -153,7 +193,7 @@ static inline int ceph_decode_pgid(void **p, void *end, struct ceph_pg *pgid)
        return 0;
 }
 
-extern struct ceph_osdmap *osdmap_decode(void **p, void *end);
+extern struct ceph_osdmap *ceph_osdmap_decode(void **p, void *end);
 extern struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                                            struct ceph_osdmap *map,
                                            struct ceph_messenger *msgr);
@@ -172,7 +212,7 @@ extern int ceph_oloc_oid_to_pg(struct ceph_osdmap *osdmap,
 
 extern int ceph_calc_pg_acting(struct ceph_osdmap *osdmap,
                               struct ceph_pg pgid,
-                              int *acting);
+                              int *osds, int *primary);
 extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap,
                                struct ceph_pg pgid);
 
index 96292df..f20e0d8 100644 (file)
@@ -81,8 +81,9 @@ struct ceph_pg_v1 {
  */
 #define CEPH_NOPOOL  ((__u64) (-1))  /* pool id not defined */
 
-#define CEPH_PG_TYPE_REP     1
-#define CEPH_PG_TYPE_RAID4   2
+#define CEPH_POOL_TYPE_REP     1
+#define CEPH_POOL_TYPE_RAID4   2 /* never implemented */
+#define CEPH_POOL_TYPE_EC      3
 
 /*
  * stable_mod func is used to control number of placement groups.
@@ -133,6 +134,10 @@ extern const char *ceph_osd_state_name(int s);
 #define CEPH_OSD_IN  0x10000
 #define CEPH_OSD_OUT 0
 
+/* osd primary-affinity.  fixed point value: 0x10000 == baseline */
+#define CEPH_OSD_MAX_PRIMARY_AFFINITY 0x10000
+#define CEPH_OSD_DEFAULT_PRIMARY_AFFINITY 0x10000
+
 
 /*
  * osd map flag bits
@@ -227,6 +232,9 @@ enum {
        CEPH_OSD_OP_OMAPRMKEYS    = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 24,
        CEPH_OSD_OP_OMAP_CMP      = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_DATA | 25,
 
+       /* hints */
+       CEPH_OSD_OP_SETALLOCHINT = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_DATA | 35,
+
        /** multi **/
        CEPH_OSD_OP_CLONERANGE = CEPH_OSD_OP_MODE_WR | CEPH_OSD_OP_TYPE_MULTI | 1,
        CEPH_OSD_OP_ASSERT_SRC_VERSION = CEPH_OSD_OP_MODE_RD | CEPH_OSD_OP_TYPE_MULTI | 2,
@@ -382,7 +390,7 @@ enum {
  */
 struct ceph_osd_op {
        __le16 op;           /* CEPH_OSD_OP_* */
-       __le32 flags;        /* CEPH_OSD_FLAG_* */
+       __le32 flags;        /* CEPH_OSD_OP_FLAG_* */
        union {
                struct {
                        __le64 offset, length;
@@ -416,6 +424,10 @@ struct ceph_osd_op {
                        __le64 offset, length;
                        __le64 src_offset;
                } __attribute__ ((packed)) clonerange;
+               struct {
+                       __le64 expected_object_size;
+                       __le64 expected_write_size;
+               } __attribute__ ((packed)) alloc_hint;
        };
        __le32 payload_len;
 } __attribute__ ((packed));
index 03e962e..8188712 100644 (file)
@@ -115,26 +115,46 @@ enum {
                { .notifier_call = fn, .priority = pri };       \
        register_cpu_notifier(&fn##_nb);                        \
 }
+
+#define __cpu_notifier(fn, pri) {                              \
+       static struct notifier_block fn##_nb =                  \
+               { .notifier_call = fn, .priority = pri };       \
+       __register_cpu_notifier(&fn##_nb);                      \
+}
 #else /* #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
 #define cpu_notifier(fn, pri)  do { (void)(fn); } while (0)
+#define __cpu_notifier(fn, pri)        do { (void)(fn); } while (0)
 #endif /* #else #if defined(CONFIG_HOTPLUG_CPU) || !defined(MODULE) */
+
 #ifdef CONFIG_HOTPLUG_CPU
 extern int register_cpu_notifier(struct notifier_block *nb);
+extern int __register_cpu_notifier(struct notifier_block *nb);
 extern void unregister_cpu_notifier(struct notifier_block *nb);
+extern void __unregister_cpu_notifier(struct notifier_block *nb);
 #else
 
 #ifndef MODULE
 extern int register_cpu_notifier(struct notifier_block *nb);
+extern int __register_cpu_notifier(struct notifier_block *nb);
 #else
 static inline int register_cpu_notifier(struct notifier_block *nb)
 {
        return 0;
 }
+
+static inline int __register_cpu_notifier(struct notifier_block *nb)
+{
+       return 0;
+}
 #endif
 
 static inline void unregister_cpu_notifier(struct notifier_block *nb)
 {
 }
+
+static inline void __unregister_cpu_notifier(struct notifier_block *nb)
+{
+}
 #endif
 
 int cpu_up(unsigned int cpu);
@@ -142,19 +162,32 @@ void notify_cpu_starting(unsigned int cpu);
 extern void cpu_maps_update_begin(void);
 extern void cpu_maps_update_done(void);
 
+#define cpu_notifier_register_begin    cpu_maps_update_begin
+#define cpu_notifier_register_done     cpu_maps_update_done
+
 #else  /* CONFIG_SMP */
 
 #define cpu_notifier(fn, pri)  do { (void)(fn); } while (0)
+#define __cpu_notifier(fn, pri)        do { (void)(fn); } while (0)
 
 static inline int register_cpu_notifier(struct notifier_block *nb)
 {
        return 0;
 }
 
+static inline int __register_cpu_notifier(struct notifier_block *nb)
+{
+       return 0;
+}
+
 static inline void unregister_cpu_notifier(struct notifier_block *nb)
 {
 }
 
+static inline void __unregister_cpu_notifier(struct notifier_block *nb)
+{
+}
+
 static inline void cpu_maps_update_begin(void)
 {
 }
@@ -163,6 +196,14 @@ static inline void cpu_maps_update_done(void)
 {
 }
 
+static inline void cpu_notifier_register_begin(void)
+{
+}
+
+static inline void cpu_notifier_register_done(void)
+{
+}
+
 #endif /* CONFIG_SMP */
 extern struct bus_type cpu_subsys;
 
@@ -176,8 +217,11 @@ extern void put_online_cpus(void);
 extern void cpu_hotplug_disable(void);
 extern void cpu_hotplug_enable(void);
 #define hotcpu_notifier(fn, pri)       cpu_notifier(fn, pri)
+#define __hotcpu_notifier(fn, pri)     __cpu_notifier(fn, pri)
 #define register_hotcpu_notifier(nb)   register_cpu_notifier(nb)
+#define __register_hotcpu_notifier(nb) __register_cpu_notifier(nb)
 #define unregister_hotcpu_notifier(nb) unregister_cpu_notifier(nb)
+#define __unregister_hotcpu_notifier(nb)       __unregister_cpu_notifier(nb)
 void clear_tasks_mm_cpumask(int cpu);
 int cpu_down(unsigned int cpu);
 
@@ -190,9 +234,12 @@ static inline void cpu_hotplug_done(void) {}
 #define cpu_hotplug_disable()  do { } while (0)
 #define cpu_hotplug_enable()   do { } while (0)
 #define hotcpu_notifier(fn, pri)       do { (void)(fn); } while (0)
+#define __hotcpu_notifier(fn, pri)     do { (void)(fn); } while (0)
 /* These aren't inline functions due to a GCC bug. */
 #define register_hotcpu_notifier(nb)   ({ (void)(nb); 0; })
+#define __register_hotcpu_notifier(nb) ({ (void)(nb); 0; })
 #define unregister_hotcpu_notifier(nb) ({ (void)(nb); })
+#define __unregister_hotcpu_notifier(nb)       ({ (void)(nb); })
 #endif         /* CONFIG_HOTPLUG_CPU */
 
 #ifdef CONFIG_PM_SLEEP_SMP
index 7032518..72ab536 100644 (file)
@@ -25,6 +25,7 @@ extern int __weak remap_oldmem_pfn_range(struct vm_area_struct *vma,
 
 extern ssize_t copy_oldmem_page(unsigned long, char *, size_t,
                                                unsigned long, int);
+void vmcore_cleanup(void);
 
 /* Architecture code defines this if there are other possible ELF
  * machine types, e.g. on bi-arch capable hardware. */
index acaa561..4fad5f8 100644 (file)
@@ -51,6 +51,7 @@ enum {
        CRUSH_RULE_SET_CHOOSELEAF_TRIES = 9, /* override chooseleaf_descend_once */
        CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES = 10,
        CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES = 11,
+       CRUSH_RULE_SET_CHOOSELEAF_VARY_R = 12
 };
 
 /*
@@ -173,6 +174,12 @@ struct crush_map {
         * apply to a collision: in that case we will retry as we used
         * to. */
        __u32 chooseleaf_descend_once;
+
+       /* if non-zero, feed r into chooseleaf, bit-shifted right by (r-1)
+        * bits.  a value of 1 is best for new clusters.  for legacy clusters
+        * that want to limit reshuffling, a value of 3 or 4 will make the
+        * mappings line up a bit better with previous mappings. */
+       __u8 chooseleaf_vary_r;
 };
 
 
index c5c92d5..8300fb8 100644 (file)
@@ -341,15 +341,11 @@ enum dma_slave_buswidth {
  * and this struct will then be passed in as an argument to the
  * DMA engine device_control() function.
  *
- * The rationale for adding configuration information to this struct
- * is as follows: if it is likely that most DMA slave controllers in
- * the world will support the configuration option, then make it
- * generic. If not: if it is fixed so that it be sent in static from
- * the platform data, then prefer to do that. Else, if it is neither
- * fixed at runtime, nor generic enough (such as bus mastership on
- * some CPU family and whatnot) then create a custom slave config
- * struct and pass that, then make this config a member of that
- * struct, if applicable.
+ * The rationale for adding configuration information to this struct is as
+ * follows: if it is likely that more than one DMA slave controllers in
+ * the world will support the configuration option, then make it generic.
+ * If not: if it is fixed so that it be sent in static from the platform
+ * data, then prefer to do that.
  */
 struct dma_slave_config {
        enum dma_transfer_direction direction;
index 481ab23..68b4024 100644 (file)
@@ -1,6 +1,5 @@
 /*
- * Driver for the Synopsys DesignWare DMA Controller (aka DMACA on
- * AVR32 systems.)
+ * Driver for the Synopsys DesignWare DMA Controller
  *
  * Copyright (C) 2007 Atmel Corporation
  * Copyright (C) 2010-2011 ST Microelectronics
@@ -44,8 +43,6 @@ struct dw_dma_slave {
  * @nr_masters: Number of AHB masters supported by the controller
  * @data_width: Maximum data width supported by hardware per AHB master
  *             (0 - 8bits, 1 - 16bits, ..., 5 - 256bits)
- * @sd: slave specific data. Used for configuring channels
- * @sd_count: count of slave data structures passed.
  */
 struct dw_dma_platform_data {
        unsigned int    nr_channels;
index da74d87..df53e17 100644 (file)
@@ -183,7 +183,7 @@ struct f2fs_inode {
        __le32 i_pino;                  /* parent inode number */
        __le32 i_namelen;               /* file name length */
        __u8 i_name[F2FS_NAME_LEN];     /* file name for SPOR */
-       __u8 i_reserved2;               /* for backward compatibility */
+       __u8 i_dir_level;               /* dentry_level for large dir */
 
        struct f2fs_extent i_ext;       /* caching a largest extent */
 
index 9231be9..11c0182 100644 (file)
@@ -262,6 +262,18 @@ union hdmi_vendor_any_infoframe {
        struct hdmi_vendor_infoframe hdmi;
 };
 
+/**
+ * union hdmi_infoframe - overall union of all abstract infoframe representations
+ * @any: generic infoframe
+ * @avi: avi infoframe
+ * @spd: spd infoframe
+ * @vendor: union of all vendor infoframes
+ * @audio: audio infoframe
+ *
+ * This is used by the generic pack function. This works since all infoframes
+ * have the same header which also indicates which type of infoframe should be
+ * packed.
+ */
 union hdmi_infoframe {
        struct hdmi_any_infoframe any;
        struct hdmi_avi_infoframe avi;
index 3af8472..d2b5299 100644 (file)
@@ -136,6 +136,7 @@ u32 host1x_syncpt_id(struct host1x_syncpt *sp);
 u32 host1x_syncpt_read_min(struct host1x_syncpt *sp);
 u32 host1x_syncpt_read_max(struct host1x_syncpt *sp);
 int host1x_syncpt_incr(struct host1x_syncpt *sp);
+u32 host1x_syncpt_incr_max(struct host1x_syncpt *sp, u32 incrs);
 int host1x_syncpt_wait(struct host1x_syncpt *sp, u32 thresh, long timeout,
                       u32 *value);
 struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
index deddeb8..b556e0a 100644 (file)
@@ -487,6 +487,7 @@ void i2c_unlock_adapter(struct i2c_adapter *);
 #define I2C_CLASS_HWMON                (1<<0)  /* lm_sensors, ... */
 #define I2C_CLASS_DDC          (1<<3)  /* DDC bus on graphics adapters */
 #define I2C_CLASS_SPD          (1<<7)  /* Memory modules */
+#define I2C_CLASS_DEPRECATED   (1<<8)  /* Warn users that adapter will stop using classes */
 
 /* Internal numbers to terminate lists */
 #define I2C_CLIENT_END         0xfffeU
diff --git a/include/linux/i2c/bfin_twi.h b/include/linux/i2c/bfin_twi.h
new file mode 100644 (file)
index 0000000..135a4e0
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * i2c-bfin-twi.h - interface to ADI TWI controller
+ *
+ * Copyright 2005-2014 Analog Devices Inc.
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#ifndef __I2C_BFIN_TWI_H__
+#define __I2C_BFIN_TWI_H__
+
+#include <linux/types.h>
+#include <linux/i2c.h>
+
+/*
+ * ADI twi registers layout
+ */
+struct bfin_twi_regs {
+       u16 clkdiv;
+       u16 dummy1;
+       u16 control;
+       u16 dummy2;
+       u16 slave_ctl;
+       u16 dummy3;
+       u16 slave_stat;
+       u16 dummy4;
+       u16 slave_addr;
+       u16 dummy5;
+       u16 master_ctl;
+       u16 dummy6;
+       u16 master_stat;
+       u16 dummy7;
+       u16 master_addr;
+       u16 dummy8;
+       u16 int_stat;
+       u16 dummy9;
+       u16 int_mask;
+       u16 dummy10;
+       u16 fifo_ctl;
+       u16 dummy11;
+       u16 fifo_stat;
+       u16 dummy12;
+       u32 __pad[20];
+       u16 xmt_data8;
+       u16 dummy13;
+       u16 xmt_data16;
+       u16 dummy14;
+       u16 rcv_data8;
+       u16 dummy15;
+       u16 rcv_data16;
+       u16 dummy16;
+};
+
+struct bfin_twi_iface {
+       int                     irq;
+       spinlock_t              lock;
+       char                    read_write;
+       u8                      command;
+       u8                      *transPtr;
+       int                     readNum;
+       int                     writeNum;
+       int                     cur_mode;
+       int                     manual_stop;
+       int                     result;
+       struct i2c_adapter      adap;
+       struct completion       complete;
+       struct i2c_msg          *pmsg;
+       int                     msg_num;
+       int                     cur_msg;
+       u16                     saved_clkdiv;
+       u16                     saved_control;
+       struct bfin_twi_regs __iomem *regs_base;
+};
+
+/*  ********************  TWO-WIRE INTERFACE (TWI) MASKS  ********************/
+/* TWI_CLKDIV Macros (Use: *pTWI_CLKDIV = CLKLOW(x)|CLKHI(y);  ) */
+#define        CLKLOW(x)       ((x) & 0xFF)    /* Periods Clock Is Held Low */
+#define CLKHI(y)       (((y)&0xFF)<<0x8) /* Periods Before New Clock Low */
+
+/* TWI_PRESCALE Masks */
+#define        PRESCALE        0x007F  /* SCLKs Per Internal Time Reference (10MHz) */
+#define        TWI_ENA         0x0080  /* TWI Enable */
+#define        SCCB            0x0200  /* SCCB Compatibility Enable */
+
+/* TWI_SLAVE_CTL Masks */
+#define        SEN             0x0001  /* Slave Enable */
+#define        SADD_LEN        0x0002  /* Slave Address Length */
+#define        STDVAL          0x0004  /* Slave Transmit Data Valid */
+#define        NAK             0x0008  /* NAK Generated At Conclusion Of Transfer */
+#define        GEN             0x0010  /* General Call Address Matching Enabled */
+
+/* TWI_SLAVE_STAT Masks        */
+#define        SDIR            0x0001  /* Slave Transfer Direction (RX/TX*) */
+#define GCALL          0x0002  /* General Call Indicator */
+
+/* TWI_MASTER_CTL Masks        */
+#define        MEN             0x0001  /* Master Mode Enable          */
+#define        MADD_LEN        0x0002  /* Master Address Length       */
+#define        MDIR            0x0004  /* Master Transmit Direction (RX/TX*) */
+#define        FAST            0x0008  /* Use Fast Mode Timing Specs  */
+#define        STOP            0x0010  /* Issue Stop Condition        */
+#define        RSTART          0x0020  /* Repeat Start or Stop* At End Of Transfer */
+#define        DCNT            0x3FC0  /* Data Bytes To Transfer      */
+#define        SDAOVR          0x4000  /* Serial Data Override        */
+#define        SCLOVR          0x8000  /* Serial Clock Override       */
+
+/* TWI_MASTER_STAT Masks */
+#define        MPROG           0x0001  /* Master Transfer In Progress */
+#define        LOSTARB         0x0002  /* Lost Arbitration Indicator (Xfer Aborted) */
+#define        ANAK            0x0004  /* Address Not Acknowledged    */
+#define        DNAK            0x0008  /* Data Not Acknowledged       */
+#define        BUFRDERR        0x0010  /* Buffer Read Error           */
+#define        BUFWRERR        0x0020  /* Buffer Write Error          */
+#define        SDASEN          0x0040  /* Serial Data Sense           */
+#define        SCLSEN          0x0080  /* Serial Clock Sense          */
+#define        BUSBUSY         0x0100  /* Bus Busy Indicator          */
+
+/* TWI_INT_SRC and TWI_INT_ENABLE Masks        */
+#define        SINIT           0x0001  /* Slave Transfer Initiated    */
+#define        SCOMP           0x0002  /* Slave Transfer Complete     */
+#define        SERR            0x0004  /* Slave Transfer Error        */
+#define        SOVF            0x0008  /* Slave Overflow              */
+#define        MCOMP           0x0010  /* Master Transfer Complete    */
+#define        MERR            0x0020  /* Master Transfer Error       */
+#define        XMTSERV         0x0040  /* Transmit FIFO Service       */
+#define        RCVSERV         0x0080  /* Receive FIFO Service        */
+
+/* TWI_FIFO_CTRL Masks */
+#define        XMTFLUSH        0x0001  /* Transmit Buffer Flush                 */
+#define        RCVFLUSH        0x0002  /* Receive Buffer Flush                  */
+#define        XMTINTLEN       0x0004  /* Transmit Buffer Interrupt Length      */
+#define        RCVINTLEN       0x0008  /* Receive Buffer Interrupt Length       */
+
+/* TWI_FIFO_STAT Masks */
+#define        XMTSTAT         0x0003  /* Transmit FIFO Status                  */
+#define        XMT_EMPTY       0x0000  /* Transmit FIFO Empty                   */
+#define        XMT_HALF        0x0001  /* Transmit FIFO Has 1 Byte To Write     */
+#define        XMT_FULL        0x0003  /* Transmit FIFO Full (2 Bytes To Write) */
+
+#define        RCVSTAT         0x000C  /* Receive FIFO Status                   */
+#define        RCV_EMPTY       0x0000  /* Receive FIFO Empty                    */
+#define        RCV_HALF        0x0004  /* Receive FIFO Has 1 Byte To Read       */
+#define        RCV_FULL        0x000C  /* Receive FIFO Full (2 Bytes To Read)   */
+
+#endif
index ade1c06..d2b1670 100644 (file)
@@ -195,6 +195,18 @@ static inline int twl_i2c_read_u8(u8 mod_no, u8 *val, u8 reg) {
        return twl_i2c_read(mod_no, val, reg, 1);
 }
 
+static inline int twl_i2c_write_u16(u8 mod_no, u16 val, u8 reg) {
+       val = cpu_to_le16(val);
+       return twl_i2c_write(mod_no, (u8*) &val, reg, 2);
+}
+
+static inline int twl_i2c_read_u16(u8 mod_no, u16 *val, u8 reg) {
+       int ret;
+       ret = twl_i2c_read(mod_no, (u8*) val, reg, 2);
+       *val = le16_to_cpu(*val);
+       return ret;
+}
+
 int twl_get_type(void);
 int twl_get_version(void);
 int twl_get_hfclk_rate(void);
index 01f5951..1c0134d 100644 (file)
@@ -44,7 +44,7 @@ struct twl4030_madc_conversion_method {
 
 struct twl4030_madc_request {
        unsigned long channels;
-       u16 do_avg;
+       bool do_avg;
        u16 method;
        u16 type;
        bool active;
index f669585..6af3400 100644 (file)
@@ -132,69 +132,6 @@ static inline void *idr_find(struct idr *idr, int id)
 #define idr_for_each_entry(idp, entry, id)                     \
        for (id = 0; ((entry) = idr_get_next(idp, &(id))) != NULL; ++id)
 
-/*
- * Don't use the following functions.  These exist only to suppress
- * deprecated warnings on EXPORT_SYMBOL()s.
- */
-int __idr_pre_get(struct idr *idp, gfp_t gfp_mask);
-int __idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id);
-void __idr_remove_all(struct idr *idp);
-
-/**
- * idr_pre_get - reserve resources for idr allocation
- * @idp:       idr handle
- * @gfp_mask:  memory allocation flags
- *
- * Part of old alloc interface.  This is going away.  Use
- * idr_preload[_end]() and idr_alloc() instead.
- */
-static inline int __deprecated idr_pre_get(struct idr *idp, gfp_t gfp_mask)
-{
-       return __idr_pre_get(idp, gfp_mask);
-}
-
-/**
- * idr_get_new_above - allocate new idr entry above or equal to a start id
- * @idp: idr handle
- * @ptr: pointer you want associated with the id
- * @starting_id: id to start search at
- * @id: pointer to the allocated handle
- *
- * Part of old alloc interface.  This is going away.  Use
- * idr_preload[_end]() and idr_alloc() instead.
- */
-static inline int __deprecated idr_get_new_above(struct idr *idp, void *ptr,
-                                                int starting_id, int *id)
-{
-       return __idr_get_new_above(idp, ptr, starting_id, id);
-}
-
-/**
- * idr_get_new - allocate new idr entry
- * @idp: idr handle
- * @ptr: pointer you want associated with the id
- * @id: pointer to the allocated handle
- *
- * Part of old alloc interface.  This is going away.  Use
- * idr_preload[_end]() and idr_alloc() instead.
- */
-static inline int __deprecated idr_get_new(struct idr *idp, void *ptr, int *id)
-{
-       return __idr_get_new_above(idp, ptr, 0, id);
-}
-
-/**
- * idr_remove_all - remove all ids from the given idr tree
- * @idp: idr handle
- *
- * If you're trying to destroy @idp, calling idr_destroy() is enough.
- * This is going away.  Don't use.
- */
-static inline void __deprecated idr_remove_all(struct idr *idp)
-{
-       __idr_remove_all(idp);
-}
-
 /*
  * IDA - IDR based id allocator, use when translation from id to
  * pointer isn't necessary.
index 8a18e75..b76e6e5 100644 (file)
@@ -41,7 +41,7 @@ static inline int ioremap_page_range(unsigned long addr, unsigned long end,
 /*
  * Managed iomap interface
  */
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
 void __iomem * devm_ioport_map(struct device *dev, unsigned long port,
                               unsigned int nr);
 void devm_ioport_unmap(struct device *dev, void __iomem *addr);
index e2d28b0..3c77bf9 100644 (file)
 #define ISAPNP_DEVICE_ID(_va, _vb, _vc, _function) \
                { .vendor = ISAPNP_VENDOR(_va, _vb, _vc), .function = ISAPNP_FUNCTION(_function) }
 
-/* export used IDs outside module */
-#define ISAPNP_CARD_TABLE(name) \
-               MODULE_GENERIC_TABLE(isapnp_card, name)
-
 struct isapnp_card_id {
        unsigned long driver_data;      /* data private to the driver */
        unsigned short card_vendor, card_device;
index 08fb024..4c52907 100644 (file)
@@ -469,6 +469,7 @@ extern enum system_states {
 #define TAINT_CRAP                     10
 #define TAINT_FIRMWARE_WORKAROUND      11
 #define TAINT_OOT_MODULE               12
+#define TAINT_UNSIGNED_MODULE          13
 
 extern const char hex_asc[];
 #define hex_asc_lo(x)  hex_asc[((x) & 0x0f)]
@@ -841,4 +842,12 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
 # define REBUILD_DUE_TO_FTRACE_MCOUNT_RECORD
 #endif
 
+/* Permissions on a sysfs file: you didn't miss the 0 prefix did you? */
+#define VERIFY_OCTAL_PERMISSIONS(perms)                                        \
+       (BUILD_BUG_ON_ZERO((perms) < 0) +                               \
+        BUILD_BUG_ON_ZERO((perms) > 0777) +                            \
+        /* User perms >= group perms >= other perms */                 \
+        BUILD_BUG_ON_ZERO(((perms) >> 6) < (((perms) >> 3) & 7)) +     \
+        BUILD_BUG_ON_ZERO((((perms) >> 3) & 7) < ((perms) & 7)) +      \
+        (perms))
 #endif
index 96549ab..0081f00 100644 (file)
@@ -25,6 +25,8 @@
 #include <linux/cpu.h>
 #include <linux/notifier.h>
 
+#ifdef CONFIG_SMP
+
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
 #define LOCKDEP_INIT_MAP lockdep_init_map
 #else
@@ -57,4 +59,18 @@ void lg_local_unlock_cpu(struct lglock *lg, int cpu);
 void lg_global_lock(struct lglock *lg);
 void lg_global_unlock(struct lglock *lg);
 
+#else
+/* When !CONFIG_SMP, map lglock to spinlock */
+#define lglock spinlock
+#define DEFINE_LGLOCK(name) DEFINE_SPINLOCK(name)
+#define DEFINE_STATIC_LGLOCK(name) static DEFINE_SPINLOCK(name)
+#define lg_lock_init(lg, name) spin_lock_init(lg)
+#define lg_local_lock spin_lock
+#define lg_local_unlock spin_unlock
+#define lg_local_lock_cpu(lg, cpu) spin_lock(lg)
+#define lg_local_unlock_cpu(lg, cpu) spin_unlock(lg)
+#define lg_global_lock spin_lock
+#define lg_global_unlock spin_unlock
+#endif
+
 #endif
index eccfb4a..b569b8b 100644 (file)
@@ -65,7 +65,7 @@ struct mem_cgroup_reclaim_cookie {
  * (Of course, if memcg does memory allocation in future, GFP_KERNEL is sane.)
  */
 
-extern int mem_cgroup_newpage_charge(struct page *page, struct mm_struct *mm,
+extern int mem_cgroup_charge_anon(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask);
 /* for swap handling */
 extern int mem_cgroup_try_charge_swapin(struct mm_struct *mm,
@@ -74,7 +74,7 @@ extern void mem_cgroup_commit_charge_swapin(struct page *page,
                                        struct mem_cgroup *memcg);
 extern void mem_cgroup_cancel_charge_swapin(struct mem_cgroup *memcg);
 
-extern int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
+extern int mem_cgroup_charge_file(struct page *page, struct mm_struct *mm,
                                        gfp_t gfp_mask);
 
 struct lruvec *mem_cgroup_zone_lruvec(struct zone *, struct mem_cgroup *);
@@ -94,7 +94,6 @@ bool task_in_mem_cgroup(struct task_struct *task,
 
 extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
 extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
-extern struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm);
 
 extern struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg);
 extern struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css);
@@ -234,13 +233,13 @@ void mem_cgroup_print_bad_page(struct page *page);
 #else /* CONFIG_MEMCG */
 struct mem_cgroup;
 
-static inline int mem_cgroup_newpage_charge(struct page *page,
+static inline int mem_cgroup_charge_anon(struct page *page,
                                        struct mm_struct *mm, gfp_t gfp_mask)
 {
        return 0;
 }
 
-static inline int mem_cgroup_cache_charge(struct page *page,
+static inline int mem_cgroup_charge_file(struct page *page,
                                        struct mm_struct *mm, gfp_t gfp_mask)
 {
        return 0;
@@ -294,11 +293,6 @@ static inline struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
        return NULL;
 }
 
-static inline struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
-{
-       return NULL;
-}
-
 static inline bool mm_match_cgroup(struct mm_struct *mm,
                struct mem_cgroup *memcg)
 {
@@ -497,6 +491,9 @@ void __memcg_kmem_commit_charge(struct page *page,
 void __memcg_kmem_uncharge_pages(struct page *page, int order);
 
 int memcg_cache_id(struct mem_cgroup *memcg);
+
+char *memcg_create_cache_name(struct mem_cgroup *memcg,
+                             struct kmem_cache *root_cache);
 int memcg_alloc_cache_params(struct mem_cgroup *memcg, struct kmem_cache *s,
                             struct kmem_cache *root_cache);
 void memcg_free_cache_params(struct kmem_cache *s);
@@ -510,7 +507,7 @@ struct kmem_cache *
 __memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp);
 
 void mem_cgroup_destroy_cache(struct kmem_cache *cachep);
-void kmem_cache_destroy_memcg_children(struct kmem_cache *s);
+int __kmem_cache_destroy_memcg_children(struct kmem_cache *s);
 
 /**
  * memcg_kmem_newpage_charge: verify if a new kmem allocation is allowed.
@@ -664,10 +661,6 @@ memcg_kmem_get_cache(struct kmem_cache *cachep, gfp_t gfp)
 {
        return cachep;
 }
-
-static inline void kmem_cache_destroy_memcg_children(struct kmem_cache *s)
-{
-}
 #endif /* CONFIG_MEMCG_KMEM */
 #endif /* _LINUX_MEMCONTROL_H */
 
index 5f1ea75..3c1b968 100644 (file)
@@ -143,7 +143,6 @@ extern void numa_policy_init(void);
 extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
                                enum mpol_rebind_step step);
 extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
-extern void mpol_fix_fork_child_flag(struct task_struct *p);
 
 extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
                                unsigned long addr, gfp_t gfp_flags,
@@ -151,7 +150,7 @@ extern struct zonelist *huge_zonelist(struct vm_area_struct *vma,
 extern bool init_nodemask_of_mempolicy(nodemask_t *mask);
 extern bool mempolicy_nodemask_intersects(struct task_struct *tsk,
                                const nodemask_t *mask);
-extern unsigned slab_node(void);
+extern unsigned int mempolicy_slab_node(void);
 
 extern enum zone_type policy_zone;
 
index 3ddaa63..7b35c21 100644 (file)
 #define ARIZONA_DSP1_STATUS_1                    0x1104
 #define ARIZONA_DSP1_STATUS_2                    0x1105
 #define ARIZONA_DSP1_STATUS_3                    0x1106
+#define ARIZONA_DSP1_STATUS_4                    0x1107
+#define ARIZONA_DSP1_WDMA_BUFFER_1               0x1110
+#define ARIZONA_DSP1_WDMA_BUFFER_2               0x1111
+#define ARIZONA_DSP1_WDMA_BUFFER_3               0x1112
+#define ARIZONA_DSP1_WDMA_BUFFER_4               0x1113
+#define ARIZONA_DSP1_WDMA_BUFFER_5               0x1114
+#define ARIZONA_DSP1_WDMA_BUFFER_6               0x1115
+#define ARIZONA_DSP1_WDMA_BUFFER_7               0x1116
+#define ARIZONA_DSP1_WDMA_BUFFER_8               0x1117
+#define ARIZONA_DSP1_RDMA_BUFFER_1               0x1120
+#define ARIZONA_DSP1_RDMA_BUFFER_2               0x1121
+#define ARIZONA_DSP1_RDMA_BUFFER_3               0x1122
+#define ARIZONA_DSP1_RDMA_BUFFER_4               0x1123
+#define ARIZONA_DSP1_RDMA_BUFFER_5               0x1124
+#define ARIZONA_DSP1_RDMA_BUFFER_6               0x1125
+#define ARIZONA_DSP1_WDMA_CONFIG_1               0x1130
+#define ARIZONA_DSP1_WDMA_CONFIG_2               0x1131
+#define ARIZONA_DSP1_WDMA_OFFSET_1               0x1132
+#define ARIZONA_DSP1_RDMA_CONFIG_1               0x1134
+#define ARIZONA_DSP1_RDMA_OFFSET_1               0x1135
+#define ARIZONA_DSP1_EXTERNAL_START_SELECT_1     0x1138
 #define ARIZONA_DSP1_SCRATCH_0                   0x1140
 #define ARIZONA_DSP1_SCRATCH_1                   0x1141
 #define ARIZONA_DSP1_SCRATCH_2                   0x1142
 #define ARIZONA_DSP2_STATUS_1                    0x1204
 #define ARIZONA_DSP2_STATUS_2                    0x1205
 #define ARIZONA_DSP2_STATUS_3                    0x1206
+#define ARIZONA_DSP2_STATUS_4                    0x1207
+#define ARIZONA_DSP2_WDMA_BUFFER_1               0x1210
+#define ARIZONA_DSP2_WDMA_BUFFER_2               0x1211
+#define ARIZONA_DSP2_WDMA_BUFFER_3               0x1212
+#define ARIZONA_DSP2_WDMA_BUFFER_4               0x1213
+#define ARIZONA_DSP2_WDMA_BUFFER_5               0x1214
+#define ARIZONA_DSP2_WDMA_BUFFER_6               0x1215
+#define ARIZONA_DSP2_WDMA_BUFFER_7               0x1216
+#define ARIZONA_DSP2_WDMA_BUFFER_8               0x1217
+#define ARIZONA_DSP2_RDMA_BUFFER_1               0x1220
+#define ARIZONA_DSP2_RDMA_BUFFER_2               0x1221
+#define ARIZONA_DSP2_RDMA_BUFFER_3               0x1222
+#define ARIZONA_DSP2_RDMA_BUFFER_4               0x1223
+#define ARIZONA_DSP2_RDMA_BUFFER_5               0x1224
+#define ARIZONA_DSP2_RDMA_BUFFER_6               0x1225
+#define ARIZONA_DSP2_WDMA_CONFIG_1               0x1230
+#define ARIZONA_DSP2_WDMA_CONFIG_2               0x1231
+#define ARIZONA_DSP2_WDMA_OFFSET_1               0x1232
+#define ARIZONA_DSP2_RDMA_CONFIG_1               0x1234
+#define ARIZONA_DSP2_RDMA_OFFSET_1               0x1235
+#define ARIZONA_DSP2_EXTERNAL_START_SELECT_1     0x1238
 #define ARIZONA_DSP2_SCRATCH_0                   0x1240
 #define ARIZONA_DSP2_SCRATCH_1                   0x1241
 #define ARIZONA_DSP2_SCRATCH_2                   0x1242
 #define ARIZONA_DSP3_STATUS_1                    0x1304
 #define ARIZONA_DSP3_STATUS_2                    0x1305
 #define ARIZONA_DSP3_STATUS_3                    0x1306
+#define ARIZONA_DSP3_STATUS_4                    0x1307
+#define ARIZONA_DSP3_WDMA_BUFFER_1               0x1310
+#define ARIZONA_DSP3_WDMA_BUFFER_2               0x1311
+#define ARIZONA_DSP3_WDMA_BUFFER_3               0x1312
+#define ARIZONA_DSP3_WDMA_BUFFER_4               0x1313
+#define ARIZONA_DSP3_WDMA_BUFFER_5               0x1314
+#define ARIZONA_DSP3_WDMA_BUFFER_6               0x1315
+#define ARIZONA_DSP3_WDMA_BUFFER_7               0x1316
+#define ARIZONA_DSP3_WDMA_BUFFER_8               0x1317
+#define ARIZONA_DSP3_RDMA_BUFFER_1               0x1320
+#define ARIZONA_DSP3_RDMA_BUFFER_2               0x1321
+#define ARIZONA_DSP3_RDMA_BUFFER_3               0x1322
+#define ARIZONA_DSP3_RDMA_BUFFER_4               0x1323
+#define ARIZONA_DSP3_RDMA_BUFFER_5               0x1324
+#define ARIZONA_DSP3_RDMA_BUFFER_6               0x1325
+#define ARIZONA_DSP3_WDMA_CONFIG_1               0x1330
+#define ARIZONA_DSP3_WDMA_CONFIG_2               0x1331
+#define ARIZONA_DSP3_WDMA_OFFSET_1               0x1332
+#define ARIZONA_DSP3_RDMA_CONFIG_1               0x1334
+#define ARIZONA_DSP3_RDMA_OFFSET_1               0x1335
+#define ARIZONA_DSP3_EXTERNAL_START_SELECT_1     0x1338
 #define ARIZONA_DSP3_SCRATCH_0                   0x1340
 #define ARIZONA_DSP3_SCRATCH_1                   0x1341
 #define ARIZONA_DSP3_SCRATCH_2                   0x1342
 #define ARIZONA_DSP4_STATUS_1                    0x1404
 #define ARIZONA_DSP4_STATUS_2                    0x1405
 #define ARIZONA_DSP4_STATUS_3                    0x1406
+#define ARIZONA_DSP4_STATUS_4                    0x1407
+#define ARIZONA_DSP4_WDMA_BUFFER_1               0x1410
+#define ARIZONA_DSP4_WDMA_BUFFER_2               0x1411
+#define ARIZONA_DSP4_WDMA_BUFFER_3               0x1412
+#define ARIZONA_DSP4_WDMA_BUFFER_4               0x1413
+#define ARIZONA_DSP4_WDMA_BUFFER_5               0x1414
+#define ARIZONA_DSP4_WDMA_BUFFER_6               0x1415
+#define ARIZONA_DSP4_WDMA_BUFFER_7               0x1416
+#define ARIZONA_DSP4_WDMA_BUFFER_8               0x1417
+#define ARIZONA_DSP4_RDMA_BUFFER_1               0x1420
+#define ARIZONA_DSP4_RDMA_BUFFER_2               0x1421
+#define ARIZONA_DSP4_RDMA_BUFFER_3               0x1422
+#define ARIZONA_DSP4_RDMA_BUFFER_4               0x1423
+#define ARIZONA_DSP4_RDMA_BUFFER_5               0x1424
+#define ARIZONA_DSP4_RDMA_BUFFER_6               0x1425
+#define ARIZONA_DSP4_WDMA_CONFIG_1               0x1430
+#define ARIZONA_DSP4_WDMA_CONFIG_2               0x1431
+#define ARIZONA_DSP4_WDMA_OFFSET_1               0x1432
+#define ARIZONA_DSP4_RDMA_CONFIG_1               0x1434
+#define ARIZONA_DSP4_RDMA_OFFSET_1               0x1435
+#define ARIZONA_DSP4_EXTERNAL_START_SELECT_1     0x1438
 #define ARIZONA_DSP4_SCRATCH_0                   0x1440
 #define ARIZONA_DSP4_SCRATCH_1                   0x1441
 #define ARIZONA_DSP4_SCRATCH_2                   0x1442
diff --git a/include/linux/mfd/bcm590xx.h b/include/linux/mfd/bcm590xx.h
new file mode 100644 (file)
index 0000000..434df2d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Broadcom BCM590xx PMU
+ *
+ * Copyright 2014 Linaro Limited
+ * Author: Matt Porter <mporter@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under  the terms of the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __LINUX_MFD_BCM590XX_H
+#define __LINUX_MFD_BCM590XX_H
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+/* max register address */
+#define BCM590XX_MAX_REGISTER  0xe7
+
+struct bcm590xx {
+       struct device *dev;
+       struct i2c_client *i2c_client;
+       struct regmap *regmap;
+       unsigned int id;
+};
+
+#endif /*  __LINUX_MFD_BCM590XX_H */
index 21e21b8..bba65f5 100644 (file)
@@ -83,6 +83,7 @@ enum da9052_chip_id {
        DA9053_AA,
        DA9053_BA,
        DA9053_BB,
+       DA9053_BC,
 };
 
 struct da9052_pdata;
index 2d2a0af..00a9aac 100644 (file)
@@ -33,6 +33,10 @@ enum da9063_models {
        PMIC_DA9063 = 0x61,
 };
 
+enum da9063_variant_codes {
+       PMIC_DA9063_BB = 0x5
+};
+
 /* Interrupts */
 enum da9063_irqs {
        DA9063_IRQ_ONKEY = 0,
@@ -72,7 +76,7 @@ struct da9063 {
        /* Device */
        struct device   *dev;
        unsigned short  model;
-       unsigned short  revision;
+       unsigned char   variant_code;
        unsigned int    flags;
 
        /* Control interface */
index 5834813..09a85c6 100644 (file)
 #define        _DA9063_REG_H
 
 #define DA9063_I2C_PAGE_SEL_SHIFT      1
-
 #define        DA9063_EVENT_REG_NUM            4
-#define        DA9210_EVENT_REG_NUM            2
-#define        DA9063_EXT_EVENT_REG_NUM        (DA9063_EVENT_REG_NUM + \
-                                               DA9210_EVENT_REG_NUM)
 
 /* Page selection I2C or SPI always in the begining of any page. */
 /* Page 0 : I2C access 0x000 - 0x0FF   SPI access 0x000 - 0x07F */
@@ -61,9 +57,9 @@
 #define        DA9063_REG_GPIO_10_11           0x1A
 #define        DA9063_REG_GPIO_12_13           0x1B
 #define        DA9063_REG_GPIO_14_15           0x1C
-#define        DA9063_REG_GPIO_MODE_0_7        0x1D
-#define        DA9063_REG_GPIO_MODE_8_15       0x1E
-#define        DA9063_REG_GPIO_SWITCH_CONT     0x1F
+#define        DA9063_REG_GPIO_MODE0_7         0x1D
+#define        DA9063_REG_GPIO_MODE8_15        0x1E
+#define        DA9063_REG_SWITCH_CONT          0x1F
 
 /* Regulator Control Registers */
 #define        DA9063_REG_BCORE2_CONT          0x20
@@ -83,7 +79,7 @@
 #define        DA9063_REG_LDO9_CONT            0x2E
 #define        DA9063_REG_LDO10_CONT           0x2F
 #define        DA9063_REG_LDO11_CONT           0x30
-#define        DA9063_REG_VIB                  0x31
+#define        DA9063_REG_SUPPLIES             0x31
 #define        DA9063_REG_DVC_1                0x32
 #define        DA9063_REG_DVC_2                0x33
 
@@ -97,9 +93,9 @@
 #define        DA9063_REG_ADCIN1_RES           0x3A
 #define        DA9063_REG_ADCIN2_RES           0x3B
 #define        DA9063_REG_ADCIN3_RES           0x3C
-#define        DA9063_REG_MON1_RES             0x3D
-#define        DA9063_REG_MON2_RES             0x3E
-#define        DA9063_REG_MON3_RES             0x3F
+#define        DA9063_REG_MON_A8_RES           0x3D
+#define        DA9063_REG_MON_A9_RES           0x3E
+#define        DA9063_REG_MON_A10_RES          0x3F
 
 /* RTC Calendar and Alarm Registers */
 #define        DA9063_REG_COUNT_S              0x40
 #define        DA9063_REG_COUNT_D              0x43
 #define        DA9063_REG_COUNT_MO             0x44
 #define        DA9063_REG_COUNT_Y              0x45
-#define        DA9063_REG_ALARM_MI             0x46
-#define        DA9063_REG_ALARM_H              0x47
-#define        DA9063_REG_ALARM_D              0x48
-#define        DA9063_REG_ALARM_MO             0x49
-#define        DA9063_REG_ALARM_Y              0x4A
-#define        DA9063_REG_SECOND_A             0x4B
-#define        DA9063_REG_SECOND_B             0x4C
-#define        DA9063_REG_SECOND_C             0x4D
-#define        DA9063_REG_SECOND_D             0x4E
+#define        DA9063_REG_ALARM_S              0x46
+#define        DA9063_REG_ALARM_MI             0x47
+#define        DA9063_REG_ALARM_H              0x48
+#define        DA9063_REG_ALARM_D              0x49
+#define        DA9063_REG_ALARM_MO             0x4A
+#define        DA9063_REG_ALARM_Y              0x4B
+#define        DA9063_REG_SECOND_A             0x4C
+#define        DA9063_REG_SECOND_B             0x4D
+#define        DA9063_REG_SECOND_C             0x4E
+#define        DA9063_REG_SECOND_D             0x4F
 
 /* Sequencer Control Registers */
 #define        DA9063_REG_SEQ                  0x81
 #define        DA9063_REG_CONFIG_J             0x10F
 #define        DA9063_REG_CONFIG_K             0x110
 #define        DA9063_REG_CONFIG_L             0x111
-#define        DA9063_REG_MON_REG_1            0x112
-#define        DA9063_REG_MON_REG_2            0x113
-#define        DA9063_REG_MON_REG_3            0x114
-#define        DA9063_REG_MON_REG_4            0x115
-#define        DA9063_REG_MON_REG_5            0x116
-#define        DA9063_REG_MON_REG_6            0x117
-#define        DA9063_REG_TRIM_CLDR            0x118
-
+#define        DA9063_REG_CONFIG_M             0x112
+#define        DA9063_REG_CONFIG_N             0x113
+
+#define        DA9063_REG_MON_REG_1            0x114
+#define        DA9063_REG_MON_REG_2            0x115
+#define        DA9063_REG_MON_REG_3            0x116
+#define        DA9063_REG_MON_REG_4            0x117
+#define        DA9063_REG_MON_REG_5            0x11E
+#define        DA9063_REG_MON_REG_6            0x11F
+#define        DA9063_REG_TRIM_CLDR            0x120
 /* General Purpose Registers */
-#define        DA9063_REG_GP_ID_0              0x119
-#define        DA9063_REG_GP_ID_1              0x11A
-#define        DA9063_REG_GP_ID_2              0x11B
-#define        DA9063_REG_GP_ID_3              0x11C
-#define        DA9063_REG_GP_ID_4              0x11D
-#define        DA9063_REG_GP_ID_5              0x11E
-#define        DA9063_REG_GP_ID_6              0x11F
-#define        DA9063_REG_GP_ID_7              0x120
-#define        DA9063_REG_GP_ID_8              0x121
-#define        DA9063_REG_GP_ID_9              0x122
-#define        DA9063_REG_GP_ID_10             0x123
-#define        DA9063_REG_GP_ID_11             0x124
-#define        DA9063_REG_GP_ID_12             0x125
-#define        DA9063_REG_GP_ID_13             0x126
-#define        DA9063_REG_GP_ID_14             0x127
-#define        DA9063_REG_GP_ID_15             0x128
-#define        DA9063_REG_GP_ID_16             0x129
-#define        DA9063_REG_GP_ID_17             0x12A
-#define        DA9063_REG_GP_ID_18             0x12B
-#define        DA9063_REG_GP_ID_19             0x12C
+#define        DA9063_REG_GP_ID_0              0x121
+#define        DA9063_REG_GP_ID_1              0x122
+#define        DA9063_REG_GP_ID_2              0x123
+#define        DA9063_REG_GP_ID_3              0x124
+#define        DA9063_REG_GP_ID_4              0x125
+#define        DA9063_REG_GP_ID_5              0x126
+#define        DA9063_REG_GP_ID_6              0x127
+#define        DA9063_REG_GP_ID_7              0x128
+#define        DA9063_REG_GP_ID_8              0x129
+#define        DA9063_REG_GP_ID_9              0x12A
+#define        DA9063_REG_GP_ID_10             0x12B
+#define        DA9063_REG_GP_ID_11             0x12C
+#define        DA9063_REG_GP_ID_12             0x12D
+#define        DA9063_REG_GP_ID_13             0x12E
+#define        DA9063_REG_GP_ID_14             0x12F
+#define        DA9063_REG_GP_ID_15             0x130
+#define        DA9063_REG_GP_ID_16             0x131
+#define        DA9063_REG_GP_ID_17             0x132
+#define        DA9063_REG_GP_ID_18             0x133
+#define        DA9063_REG_GP_ID_19             0x134
 
 /* Chip ID and variant */
 #define        DA9063_REG_CHIP_ID              0x181
 /* DA9063_REG_CONTROL_B (addr=0x0F) */
 #define        DA9063_CHG_SEL                          0x01
 #define        DA9063_WATCHDOG_PD                      0x02
+#define        DA9063_RESET_BLINKING                   0x04
 #define        DA9063_NRES_MODE                        0x08
 #define        DA9063_NONKEY_LOCK                      0x10
+#define        DA9063_BUCK_SLOWSTART                   0x80
 
 /* DA9063_REG_CONTROL_C (addr=0x10) */
 #define        DA9063_DEBOUNCING_MASK                  0x07
 #define        DA9063_GPADC_PAUSE                      0x02
 #define        DA9063_PMIF_DIS                         0x04
 #define        DA9063_HS2WIRE_DIS                      0x08
+#define        DA9063_CLDR_PAUSE                       0x10
 #define        DA9063_BBAT_DIS                         0x20
 #define        DA9063_OUT_32K_PAUSE                    0x40
 #define        DA9063_PMCONT_DIS                       0x80
 #define                DA9063_GPIO15_TYPE_GPO          0x04
 #define        DA9063_GPIO15_NO_WAKEUP                 0x80
 
-/* DA9063_REG_GPIO_MODE_0_7 (addr=0x1D) */
+/* DA9063_REG_GPIO_MODE0_7 (addr=0x1D) */
 #define        DA9063_GPIO0_MODE                       0x01
 #define        DA9063_GPIO1_MODE                       0x02
 #define        DA9063_GPIO2_MODE                       0x04
 #define        DA9063_GPIO6_MODE                       0x40
 #define        DA9063_GPIO7_MODE                       0x80
 
-/* DA9063_REG_GPIO_MODE_8_15 (addr=0x1E) */
+/* DA9063_REG_GPIO_MODE8_15 (addr=0x1E) */
 #define        DA9063_GPIO8_MODE                       0x01
 #define        DA9063_GPIO9_MODE                       0x02
 #define        DA9063_GPIO10_MODE                      0x04
 #define                DA9063_SWITCH_SR_5MV            0x10
 #define                DA9063_SWITCH_SR_10MV           0x20
 #define                DA9063_SWITCH_SR_50MV           0x30
-#define        DA9063_SWITCH_SR_DIS                    0x40
+#define        DA9063_CORE_SW_INTERNAL                 0x40
 #define        DA9063_CP_EN_MODE                       0x80
 
 /* DA9063_REGL_Bxxxx_CONT common bits (addr=0x20-0x25) */
 #define        DA9063_BUCK_EN                          0x01
-#define DA9063_BUCK_GPI_MASK                   0x06
+#define        DA9063_BUCK_GPI_MASK                    0x06
 #define                DA9063_BUCK_GPI_OFF             0x00
 #define                DA9063_BUCK_GPI_GPIO1           0x02
 #define                DA9063_BUCK_GPI_GPIO2           0x04
 #define DA9063_COUNT_YEAR_MASK                 0x3F
 #define DA9063_MONITOR                         0x40
 
-/* DA9063_REG_ALARM_MI (addr=0x46) */
+/* DA9063_REG_ALARM_S (addr=0x46) */
+#define DA9063_ALARM_S_MASK                    0x3F
 #define DA9063_ALARM_STATUS_ALARM              0x80
 #define DA9063_ALARM_STATUS_TICK               0x40
+/* DA9063_REG_ALARM_MI (addr=0x47) */
 #define DA9063_ALARM_MIN_MASK                  0x3F
 
-/* DA9063_REG_ALARM_H (addr=0x47) */
+/* DA9063_REG_ALARM_H (addr=0x48) */
 #define DA9063_ALARM_HOUR_MASK                 0x1F
 
-/* DA9063_REG_ALARM_D (addr=0x48) */
+/* DA9063_REG_ALARM_D (addr=0x49) */
 #define DA9063_ALARM_DAY_MASK                  0x1F
 
-/* DA9063_REG_ALARM_MO (addr=0x49) */
+/* DA9063_REG_ALARM_MO (addr=0x4A) */
 #define DA9063_TICK_WAKE                       0x20
 #define DA9063_TICK_TYPE                       0x10
 #define                DA9063_TICK_TYPE_SEC            0x00
 #define                DA9063_TICK_TYPE_MIN            0x10
 #define DA9063_ALARM_MONTH_MASK                        0x0F
 
-/* DA9063_REG_ALARM_Y (addr=0x4A) */
+/* DA9063_REG_ALARM_Y (addr=0x4B) */
 #define DA9063_TICK_ON                         0x80
 #define DA9063_ALARM_ON                                0x40
 #define DA9063_ALARM_YEAR_MASK                 0x3F
 
 /* DA9063_REG_Bxxxx_CFG common bits (addr=0x9D-0xA2) */
 #define DA9063_BUCK_FB_MASK                    0x07
-#define DA9063_BUCK_PD_DIS_SHIFT               5
+#define DA9063_BUCK_PD_DIS_MASK                0x20
 #define DA9063_BUCK_MODE_MASK                  0xC0
 #define                DA9063_BUCK_MODE_MANUAL         0x00
 #define                DA9063_BUCK_MODE_SLEEP          0x40
index 3e1df64..8feac78 100644 (file)
 #define LPC_ICH_H
 
 /* Watchdog resources */
-#define ICH_RES_IO_TCO 0
-#define ICH_RES_IO_SMI 1
-#define ICH_RES_MEM_OFF        2
-#define ICH_RES_MEM_GCS        0
+#define ICH_RES_IO_TCO         0
+#define ICH_RES_IO_SMI         1
+#define ICH_RES_MEM_OFF                2
+#define ICH_RES_MEM_GCS_PMC    0
 
 /* GPIO resources */
 #define ICH_RES_GPIO   0
 #define ICH_RES_GPE0   1
 
 /* GPIO compatibility */
-#define ICH_I3100_GPIO         0x401
-#define ICH_V5_GPIO            0x501
-#define ICH_V6_GPIO            0x601
-#define ICH_V7_GPIO            0x701
-#define ICH_V9_GPIO            0x801
-#define ICH_V10CORP_GPIO       0xa01
-#define ICH_V10CONS_GPIO       0xa11
+enum {
+       ICH_I3100_GPIO,
+       ICH_V5_GPIO,
+       ICH_V6_GPIO,
+       ICH_V7_GPIO,
+       ICH_V9_GPIO,
+       ICH_V10CORP_GPIO,
+       ICH_V10CONS_GPIO,
+       AVOTON_GPIO,
+};
 
 struct lpc_ich_info {
        char name[32];
index a3d0185..c9b332f 100644 (file)
@@ -248,14 +248,6 @@ enum max14577_charger_reg {
 /* MAX14577 regulator SFOUT LDO voltage, fixed, uV */
 #define MAX14577_REGULATOR_SAFEOUT_VOLTAGE             4900000
 
-enum max14577_irq_source {
-       MAX14577_IRQ_INT1 = 0,
-       MAX14577_IRQ_INT2,
-       MAX14577_IRQ_INT3,
-
-       MAX14577_IRQ_REGS_NUM,
-};
-
 enum max14577_irq {
        /* INT1 */
        MAX14577_IRQ_INT1_ADC,
index 247b021..736d39c 100644 (file)
 #ifndef __MAX14577_H__
 #define __MAX14577_H__
 
-#include <linux/mfd/max14577-private.h>
 #include <linux/regulator/consumer.h>
 
-/*
- * MAX14577 Regulator
- */
-
 /* MAX14577 regulator IDs */
 enum max14577_regulators {
        MAX14577_SAFEOUT = 0,
index ac39d91..a326c85 100644 (file)
@@ -104,6 +104,9 @@ enum {
        MC13892_LED_R,
        MC13892_LED_G,
        MC13892_LED_B,
+       /* MC34708 LED IDs */
+       MC34708_LED_R,
+       MC34708_LED_G,
 };
 
 struct mc13xxx_led_platform_data {
@@ -163,6 +166,9 @@ struct mc13xxx_leds_platform_data {
 #define MC13892_LED_C2_CURRENT_G(x)    (((x) & 0x7) << 21)
 /* MC13892 LED Control 3 */
 #define MC13892_LED_C3_CURRENT_B(x)    (((x) & 0x7) << 9)
+/* MC34708 LED Control 0 */
+#define MC34708_LED_C0_CURRENT_R(x)    (((x) & 0x3) << 9)
+#define MC34708_LED_C0_CURRENT_G(x)    (((x) & 0x3) << 21)
        u32 led_control[MAX_LED_CONTROL_REGS];
 };
 
diff --git a/include/linux/mfd/pm8xxx/irq.h b/include/linux/mfd/pm8xxx/irq.h
deleted file mode 100644 (file)
index f83d6b4..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-/*
- * Qualcomm PMIC irq 8xxx driver header file
- *
- */
-
-#ifndef __MFD_PM8XXX_IRQ_H
-#define __MFD_PM8XXX_IRQ_H
-
-#include <linux/errno.h>
-#include <linux/err.h>
-
-struct pm8xxx_irq_core_data {
-       u32             rev;
-       int             nirqs;
-};
-
-struct pm8xxx_irq_platform_data {
-       int                             irq_base;
-       struct pm8xxx_irq_core_data     irq_cdata;
-       int                             devirq;
-       int                             irq_trigger_flag;
-};
-
-struct pm_irq_chip;
-
-#ifdef CONFIG_MFD_PM8XXX_IRQ
-int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq);
-struct pm_irq_chip *pm8xxx_irq_init(struct device *dev,
-                               const struct pm8xxx_irq_platform_data *pdata);
-int pm8xxx_irq_exit(struct pm_irq_chip *chip);
-#else
-static inline int pm8xxx_get_irq_stat(struct pm_irq_chip *chip, int irq)
-{
-       return -ENXIO;
-}
-static inline struct pm_irq_chip *pm8xxx_irq_init(
-                               const struct device *dev,
-                               const struct pm8xxx_irq_platform_data *pdata)
-{
-       return ERR_PTR(-ENXIO);
-}
-static inline int pm8xxx_irq_exit(struct pm_irq_chip *chip)
-{
-       return -ENXIO;
-}
-#endif /* CONFIG_MFD_PM8XXX_IRQ */
-#endif /* __MFD_PM8XXX_IRQ_H */
diff --git a/include/linux/mfd/pm8xxx/pm8921.h b/include/linux/mfd/pm8xxx/pm8921.h
deleted file mode 100644 (file)
index 00fa3de..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Copyright (c) 2011, Code Aurora Forum. 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 version 2 and
- * only 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.
- */
-/*
- * Qualcomm PMIC 8921 driver header file
- *
- */
-
-#ifndef __MFD_PM8921_H
-#define __MFD_PM8921_H
-
-#include <linux/mfd/pm8xxx/irq.h>
-
-#define PM8921_NR_IRQS         256
-
-struct pm8921_platform_data {
-       int                                     irq_base;
-       struct pm8xxx_irq_platform_data         *irq_pdata;
-};
-
-#endif
index 443176e..7c36cc5 100644 (file)
@@ -45,6 +45,7 @@ struct platform_device;
 struct rtsx_slot {
        struct platform_device  *p_dev;
        void                    (*card_event)(struct platform_device *p_dev);
+       void                    (*done_transfer)(struct platform_device *p_dev);
 };
 
 #endif
index 0ce7721..8d6bbd6 100644 (file)
 #define HOST_TO_DEVICE         0
 #define DEVICE_TO_HOST         1
 
-#define MAX_PHASE              31
+#define RTSX_PHASE_MAX         32
 #define RX_TUNING_CNT          3
 
 /* SG descriptor */
@@ -943,6 +943,12 @@ void rtsx_pci_send_cmd_no_wait(struct rtsx_pcr *pcr);
 int rtsx_pci_send_cmd(struct rtsx_pcr *pcr, int timeout);
 int rtsx_pci_transfer_data(struct rtsx_pcr *pcr, struct scatterlist *sglist,
                int num_sg, bool read, int timeout);
+int rtsx_pci_dma_map_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int num_sg, bool read);
+int rtsx_pci_dma_unmap_sg(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int num_sg, bool read);
+int rtsx_pci_dma_transfer(struct rtsx_pcr *pcr, struct scatterlist *sglist,
+               int sg_count, bool read);
 int rtsx_pci_read_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
 int rtsx_pci_write_ppbuf(struct rtsx_pcr *pcr, u8 *buf, int buf_len);
 int rtsx_pci_card_pull_ctl_enable(struct rtsx_pcr *pcr, int card);
diff --git a/include/linux/mfd/rtsx_usb.h b/include/linux/mfd/rtsx_usb.h
new file mode 100644 (file)
index 0000000..c446e4f
--- /dev/null
@@ -0,0 +1,628 @@
+/* Driver for Realtek RTS5139 USB card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. 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 version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ *   Roger Tseng <rogerable@realtek.com>
+ */
+
+#ifndef __RTSX_USB_H
+#define __RTSX_USB_H
+
+#include <linux/usb.h>
+
+/* related module names */
+#define RTSX_USB_SD_CARD       0
+#define RTSX_USB_MS_CARD       1
+
+/* endpoint numbers */
+#define EP_BULK_OUT            1
+#define EP_BULK_IN             2
+#define EP_INTR_IN             3
+
+/* USB vendor requests */
+#define RTSX_USB_REQ_REG_OP    0x00
+#define RTSX_USB_REQ_POLL      0x02
+
+/* miscellaneous parameters */
+#define MIN_DIV_N              60
+#define MAX_DIV_N              120
+
+#define MAX_PHASE              15
+#define RX_TUNING_CNT          3
+
+#define QFN24                  0
+#define LQFP48                 1
+#define CHECK_PKG(ucr, pkg)    ((ucr)->package == (pkg))
+
+/* data structures */
+struct rtsx_ucr {
+       u16                     vendor_id;
+       u16                     product_id;
+
+       int                     package;
+       u8                      ic_version;
+       bool                    is_rts5179;
+
+       unsigned int            cur_clk;
+
+       u8                      *cmd_buf;
+       unsigned int            cmd_idx;
+       u8                      *rsp_buf;
+
+       struct usb_device       *pusb_dev;
+       struct usb_interface    *pusb_intf;
+       struct usb_sg_request   current_sg;
+       unsigned char           *iobuf;
+       dma_addr_t              iobuf_dma;
+
+       struct timer_list       sg_timer;
+       struct mutex            dev_mutex;
+};
+
+/* buffer size */
+#define IOBUF_SIZE             1024
+
+/* prototypes of exported functions */
+extern int rtsx_usb_get_card_status(struct rtsx_ucr *ucr, u16 *status);
+
+extern int rtsx_usb_read_register(struct rtsx_ucr *ucr, u16 addr, u8 *data);
+extern int rtsx_usb_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask,
+               u8 data);
+
+extern int rtsx_usb_ep0_write_register(struct rtsx_ucr *ucr, u16 addr, u8 mask,
+               u8 data);
+extern int rtsx_usb_ep0_read_register(struct rtsx_ucr *ucr, u16 addr,
+               u8 *data);
+
+extern void rtsx_usb_add_cmd(struct rtsx_ucr *ucr, u8 cmd_type,
+               u16 reg_addr, u8 mask, u8 data);
+extern int rtsx_usb_send_cmd(struct rtsx_ucr *ucr, u8 flag, int timeout);
+extern int rtsx_usb_get_rsp(struct rtsx_ucr *ucr, int rsp_len, int timeout);
+extern int rtsx_usb_transfer_data(struct rtsx_ucr *ucr, unsigned int pipe,
+                             void *buf, unsigned int len, int use_sg,
+                             unsigned int *act_len, int timeout);
+
+extern int rtsx_usb_read_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len);
+extern int rtsx_usb_write_ppbuf(struct rtsx_ucr *ucr, u8 *buf, int buf_len);
+extern int rtsx_usb_switch_clock(struct rtsx_ucr *ucr, unsigned int card_clock,
+               u8 ssc_depth, bool initial_mode, bool double_clk, bool vpclk);
+extern int rtsx_usb_card_exclusive_check(struct rtsx_ucr *ucr, int card);
+
+/* card status */
+#define SD_CD          0x01
+#define MS_CD          0x02
+#define XD_CD          0x04
+#define CD_MASK                (SD_CD | MS_CD | XD_CD)
+#define SD_WP          0x08
+
+/* reader command field offset & parameters */
+#define READ_REG_CMD           0
+#define WRITE_REG_CMD          1
+#define CHECK_REG_CMD          2
+
+#define PACKET_TYPE            4
+#define CNT_H                  5
+#define CNT_L                  6
+#define STAGE_FLAG             7
+#define CMD_OFFSET             8
+#define SEQ_WRITE_DATA_OFFSET  12
+
+#define BATCH_CMD              0
+#define SEQ_READ               1
+#define SEQ_WRITE              2
+
+#define STAGE_R                        0x01
+#define STAGE_DI               0x02
+#define STAGE_DO               0x04
+#define STAGE_MS_STATUS                0x08
+#define STAGE_XD_STATUS                0x10
+#define MODE_C                 0x00
+#define MODE_CR                        (STAGE_R)
+#define MODE_CDIR              (STAGE_R | STAGE_DI)
+#define MODE_CDOR              (STAGE_R | STAGE_DO)
+
+#define EP0_OP_SHIFT           14
+#define EP0_READ_REG_CMD       2
+#define EP0_WRITE_REG_CMD      3
+
+#define rtsx_usb_cmd_hdr_tag(ucr)              \
+       do {                                    \
+               ucr->cmd_buf[0] = 'R';          \
+               ucr->cmd_buf[1] = 'T';          \
+               ucr->cmd_buf[2] = 'C';          \
+               ucr->cmd_buf[3] = 'R';          \
+       } while (0)
+
+static inline void rtsx_usb_init_cmd(struct rtsx_ucr *ucr)
+{
+       rtsx_usb_cmd_hdr_tag(ucr);
+       ucr->cmd_idx = 0;
+       ucr->cmd_buf[PACKET_TYPE] = BATCH_CMD;
+}
+
+/* internal register address */
+#define FPDCTL                         0xFC00
+#define SSC_DIV_N_0                    0xFC07
+#define SSC_CTL1                       0xFC09
+#define SSC_CTL2                       0xFC0A
+#define CFG_MODE                       0xFC0E
+#define CFG_MODE_1                     0xFC0F
+#define RCCTL                          0xFC14
+#define SOF_WDOG                       0xFC28
+#define SYS_DUMMY0                     0xFC30
+
+#define MS_BLKEND                      0xFD30
+#define MS_READ_START                  0xFD31
+#define MS_READ_COUNT                  0xFD32
+#define MS_WRITE_START                 0xFD33
+#define MS_WRITE_COUNT                 0xFD34
+#define MS_COMMAND                     0xFD35
+#define MS_OLD_BLOCK_0                 0xFD36
+#define MS_OLD_BLOCK_1                 0xFD37
+#define MS_NEW_BLOCK_0                 0xFD38
+#define MS_NEW_BLOCK_1                 0xFD39
+#define MS_LOG_BLOCK_0                 0xFD3A
+#define MS_LOG_BLOCK_1                 0xFD3B
+#define MS_BUS_WIDTH                   0xFD3C
+#define MS_PAGE_START                  0xFD3D
+#define MS_PAGE_LENGTH                 0xFD3E
+#define MS_CFG                         0xFD40
+#define MS_TPC                         0xFD41
+#define MS_TRANS_CFG                   0xFD42
+#define MS_TRANSFER                    0xFD43
+#define MS_INT_REG                     0xFD44
+#define MS_BYTE_CNT                    0xFD45
+#define MS_SECTOR_CNT_L                        0xFD46
+#define MS_SECTOR_CNT_H                        0xFD47
+#define MS_DBUS_H                      0xFD48
+
+#define CARD_DMA1_CTL                  0xFD5C
+#define CARD_PULL_CTL1                 0xFD60
+#define CARD_PULL_CTL2                 0xFD61
+#define CARD_PULL_CTL3                 0xFD62
+#define CARD_PULL_CTL4                 0xFD63
+#define CARD_PULL_CTL5                 0xFD64
+#define CARD_PULL_CTL6                 0xFD65
+#define CARD_EXIST                     0xFD6F
+#define CARD_INT_PEND                  0xFD71
+
+#define LDO_POWER_CFG                  0xFD7B
+
+#define SD_CFG1                                0xFDA0
+#define SD_CFG2                                0xFDA1
+#define SD_CFG3                                0xFDA2
+#define SD_STAT1                       0xFDA3
+#define SD_STAT2                       0xFDA4
+#define SD_BUS_STAT                    0xFDA5
+#define SD_PAD_CTL                     0xFDA6
+#define SD_SAMPLE_POINT_CTL            0xFDA7
+#define SD_PUSH_POINT_CTL              0xFDA8
+#define SD_CMD0                                0xFDA9
+#define SD_CMD1                                0xFDAA
+#define SD_CMD2                                0xFDAB
+#define SD_CMD3                                0xFDAC
+#define SD_CMD4                                0xFDAD
+#define SD_CMD5                                0xFDAE
+#define SD_BYTE_CNT_L                  0xFDAF
+#define SD_BYTE_CNT_H                  0xFDB0
+#define SD_BLOCK_CNT_L                 0xFDB1
+#define SD_BLOCK_CNT_H                 0xFDB2
+#define SD_TRANSFER                    0xFDB3
+#define SD_CMD_STATE                   0xFDB5
+#define SD_DATA_STATE                  0xFDB6
+#define SD_VPCLK0_CTL                  0xFC2A
+#define SD_VPCLK1_CTL                  0xFC2B
+#define SD_DCMPS0_CTL                  0xFC2C
+#define SD_DCMPS1_CTL                  0xFC2D
+
+#define CARD_DMA1_CTL                  0xFD5C
+
+#define HW_VERSION                     0xFC01
+
+#define SSC_CLK_FPGA_SEL               0xFC02
+#define CLK_DIV                                0xFC03
+#define SFSM_ED                                0xFC04
+
+#define CD_DEGLITCH_WIDTH              0xFC20
+#define CD_DEGLITCH_EN                 0xFC21
+#define AUTO_DELINK_EN                 0xFC23
+
+#define FPGA_PULL_CTL                  0xFC1D
+#define CARD_CLK_SOURCE                        0xFC2E
+
+#define CARD_SHARE_MODE                        0xFD51
+#define CARD_DRIVE_SEL                 0xFD52
+#define CARD_STOP                      0xFD53
+#define CARD_OE                                0xFD54
+#define CARD_AUTO_BLINK                        0xFD55
+#define CARD_GPIO                      0xFD56
+#define SD30_DRIVE_SEL                 0xFD57
+
+#define CARD_DATA_SOURCE               0xFD5D
+#define CARD_SELECT                    0xFD5E
+
+#define CARD_CLK_EN                    0xFD79
+#define CARD_PWR_CTL                   0xFD7A
+
+#define OCPCTL                         0xFD80
+#define OCPPARA1                       0xFD81
+#define OCPPARA2                       0xFD82
+#define OCPSTAT                                0xFD83
+
+#define HS_USB_STAT                    0xFE01
+#define HS_VCONTROL                    0xFE26
+#define HS_VSTAIN                      0xFE27
+#define HS_VLOADM                      0xFE28
+#define HS_VSTAOUT                     0xFE29
+
+#define MC_IRQ                         0xFF00
+#define MC_IRQEN                       0xFF01
+#define MC_FIFO_CTL                    0xFF02
+#define MC_FIFO_BC0                    0xFF03
+#define MC_FIFO_BC1                    0xFF04
+#define MC_FIFO_STAT                   0xFF05
+#define MC_FIFO_MODE                   0xFF06
+#define MC_FIFO_RD_PTR0                        0xFF07
+#define MC_FIFO_RD_PTR1                        0xFF08
+#define MC_DMA_CTL                     0xFF10
+#define MC_DMA_TC0                     0xFF11
+#define MC_DMA_TC1                     0xFF12
+#define MC_DMA_TC2                     0xFF13
+#define MC_DMA_TC3                     0xFF14
+#define MC_DMA_RST                     0xFF15
+
+#define RBUF_SIZE_MASK                 0xFBFF
+#define RBUF_BASE                      0xF000
+#define PPBUF_BASE1                    0xF800
+#define PPBUF_BASE2                    0xFA00
+
+/* internal register value macros */
+#define POWER_OFF                      0x03
+#define PARTIAL_POWER_ON               0x02
+#define POWER_ON                       0x00
+#define POWER_MASK                     0x03
+#define LDO3318_PWR_MASK               0x0C
+#define LDO_ON                         0x00
+#define LDO_SUSPEND                    0x08
+#define LDO_OFF                                0x0C
+#define DV3318_AUTO_PWR_OFF            0x10
+#define FORCE_LDO_POWERB               0x60
+
+/* LDO_POWER_CFG */
+#define TUNE_SD18_MASK                 0x1C
+#define TUNE_SD18_1V7                  0x00
+#define TUNE_SD18_1V8                  (0x01 << 2)
+#define TUNE_SD18_1V9                  (0x02 << 2)
+#define TUNE_SD18_2V0                  (0x03 << 2)
+#define TUNE_SD18_2V7                  (0x04 << 2)
+#define TUNE_SD18_2V8                  (0x05 << 2)
+#define TUNE_SD18_2V9                  (0x06 << 2)
+#define TUNE_SD18_3V3                  (0x07 << 2)
+
+/* CLK_DIV */
+#define CLK_CHANGE                     0x80
+#define CLK_DIV_1                      0x00
+#define CLK_DIV_2                      0x01
+#define CLK_DIV_4                      0x02
+#define CLK_DIV_8                      0x03
+
+#define SSC_POWER_MASK                 0x01
+#define SSC_POWER_DOWN                 0x01
+#define SSC_POWER_ON                   0x00
+
+#define FPGA_VER                       0x80
+#define HW_VER_MASK                    0x0F
+
+#define EXTEND_DMA1_ASYNC_SIGNAL       0x02
+
+/* CFG_MODE*/
+#define XTAL_FREE                      0x80
+#define CLK_MODE_MASK                  0x03
+#define CLK_MODE_12M_XTAL              0x00
+#define CLK_MODE_NON_XTAL              0x01
+#define CLK_MODE_24M_OSC               0x02
+#define CLK_MODE_48M_OSC               0x03
+
+/* CFG_MODE_1*/
+#define RTS5179                                0x02
+
+#define NYET_EN                                0x01
+#define NYET_MSAK                      0x01
+
+#define SD30_DRIVE_MASK                        0x07
+#define SD20_DRIVE_MASK                        0x03
+
+#define DISABLE_SD_CD                  0x08
+#define DISABLE_MS_CD                  0x10
+#define DISABLE_XD_CD                  0x20
+#define SD_CD_DEGLITCH_EN              0x01
+#define MS_CD_DEGLITCH_EN              0x02
+#define XD_CD_DEGLITCH_EN              0x04
+
+#define        CARD_SHARE_LQFP48               0x04
+#define        CARD_SHARE_QFN24                0x00
+#define CARD_SHARE_LQFP_SEL            0x04
+#define        CARD_SHARE_XD                   0x00
+#define        CARD_SHARE_SD                   0x01
+#define        CARD_SHARE_MS                   0x02
+#define CARD_SHARE_MASK                        0x03
+
+
+/* SD30_DRIVE_SEL */
+#define DRIVER_TYPE_A                  0x05
+#define DRIVER_TYPE_B                  0x03
+#define DRIVER_TYPE_C                  0x02
+#define DRIVER_TYPE_D                  0x01
+
+/* SD_BUS_STAT */
+#define        SD_CLK_TOGGLE_EN                0x80
+#define        SD_CLK_FORCE_STOP               0x40
+#define        SD_DAT3_STATUS                  0x10
+#define        SD_DAT2_STATUS                  0x08
+#define        SD_DAT1_STATUS                  0x04
+#define        SD_DAT0_STATUS                  0x02
+#define        SD_CMD_STATUS                   0x01
+
+/* SD_PAD_CTL */
+#define        SD_IO_USING_1V8                 0x80
+#define        SD_IO_USING_3V3                 0x7F
+#define        TYPE_A_DRIVING                  0x00
+#define        TYPE_B_DRIVING                  0x01
+#define        TYPE_C_DRIVING                  0x02
+#define        TYPE_D_DRIVING                  0x03
+
+/* CARD_CLK_EN */
+#define SD_CLK_EN                      0x04
+#define MS_CLK_EN                      0x08
+
+/* CARD_SELECT */
+#define SD_MOD_SEL                     2
+#define MS_MOD_SEL                     3
+
+/* CARD_SHARE_MODE */
+#define        CARD_SHARE_LQFP48               0x04
+#define        CARD_SHARE_QFN24                0x00
+#define CARD_SHARE_LQFP_SEL            0x04
+#define        CARD_SHARE_XD                   0x00
+#define        CARD_SHARE_SD                   0x01
+#define        CARD_SHARE_MS                   0x02
+#define CARD_SHARE_MASK                        0x03
+
+/* SSC_CTL1 */
+#define SSC_RSTB                       0x80
+#define SSC_8X_EN                      0x40
+#define SSC_FIX_FRAC                   0x20
+#define SSC_SEL_1M                     0x00
+#define SSC_SEL_2M                     0x08
+#define SSC_SEL_4M                     0x10
+#define SSC_SEL_8M                     0x18
+
+/* SSC_CTL2 */
+#define SSC_DEPTH_MASK                 0x03
+#define SSC_DEPTH_DISALBE              0x00
+#define SSC_DEPTH_2M                   0x01
+#define SSC_DEPTH_1M                   0x02
+#define SSC_DEPTH_512K                 0x03
+
+/* SD_VPCLK0_CTL */
+#define PHASE_CHANGE                   0x80
+#define PHASE_NOT_RESET                        0x40
+
+/* SD_TRANSFER */
+#define        SD_TRANSFER_START               0x80
+#define        SD_TRANSFER_END                 0x40
+#define SD_STAT_IDLE                   0x20
+#define        SD_TRANSFER_ERR                 0x10
+#define        SD_TM_NORMAL_WRITE              0x00
+#define        SD_TM_AUTO_WRITE_3              0x01
+#define        SD_TM_AUTO_WRITE_4              0x02
+#define        SD_TM_AUTO_READ_3               0x05
+#define        SD_TM_AUTO_READ_4               0x06
+#define        SD_TM_CMD_RSP                   0x08
+#define        SD_TM_AUTO_WRITE_1              0x09
+#define        SD_TM_AUTO_WRITE_2              0x0A
+#define        SD_TM_NORMAL_READ               0x0C
+#define        SD_TM_AUTO_READ_1               0x0D
+#define        SD_TM_AUTO_READ_2               0x0E
+#define        SD_TM_AUTO_TUNING               0x0F
+
+/* SD_CFG1 */
+#define SD_CLK_DIVIDE_0                        0x00
+#define        SD_CLK_DIVIDE_256               0xC0
+#define        SD_CLK_DIVIDE_128               0x80
+#define SD_CLK_DIVIDE_MASK             0xC0
+#define        SD_BUS_WIDTH_1BIT               0x00
+#define        SD_BUS_WIDTH_4BIT               0x01
+#define        SD_BUS_WIDTH_8BIT               0x02
+#define        SD_ASYNC_FIFO_RST               0x10
+#define        SD_20_MODE                      0x00
+#define        SD_DDR_MODE                     0x04
+#define        SD_30_MODE                      0x08
+
+/* SD_CFG2 */
+#define        SD_CALCULATE_CRC7               0x00
+#define        SD_NO_CALCULATE_CRC7            0x80
+#define        SD_CHECK_CRC16                  0x00
+#define        SD_NO_CHECK_CRC16               0x40
+#define SD_WAIT_CRC_TO_EN              0x20
+#define        SD_WAIT_BUSY_END                0x08
+#define        SD_NO_WAIT_BUSY_END             0x00
+#define        SD_CHECK_CRC7                   0x00
+#define        SD_NO_CHECK_CRC7                0x04
+#define        SD_RSP_LEN_0                    0x00
+#define        SD_RSP_LEN_6                    0x01
+#define        SD_RSP_LEN_17                   0x02
+#define        SD_RSP_TYPE_R0                  0x04
+#define        SD_RSP_TYPE_R1                  0x01
+#define        SD_RSP_TYPE_R1b                 0x09
+#define        SD_RSP_TYPE_R2                  0x02
+#define        SD_RSP_TYPE_R3                  0x05
+#define        SD_RSP_TYPE_R4                  0x05
+#define        SD_RSP_TYPE_R5                  0x01
+#define        SD_RSP_TYPE_R6                  0x01
+#define        SD_RSP_TYPE_R7                  0x01
+
+/* SD_STAT1 */
+#define        SD_CRC7_ERR                     0x80
+#define        SD_CRC16_ERR                    0x40
+#define        SD_CRC_WRITE_ERR                0x20
+#define        SD_CRC_WRITE_ERR_MASK           0x1C
+#define        GET_CRC_TIME_OUT                0x02
+#define        SD_TUNING_COMPARE_ERR           0x01
+
+/* SD_DATA_STATE */
+#define SD_DATA_IDLE                   0x80
+
+/* CARD_DATA_SOURCE */
+#define PINGPONG_BUFFER                        0x01
+#define RING_BUFFER                    0x00
+
+/* CARD_OE */
+#define SD_OUTPUT_EN                   0x04
+#define MS_OUTPUT_EN                   0x08
+
+/* CARD_STOP */
+#define SD_STOP                                0x04
+#define MS_STOP                                0x08
+#define SD_CLR_ERR                     0x40
+#define MS_CLR_ERR                     0x80
+
+/* CARD_CLK_SOURCE */
+#define CRC_FIX_CLK                    (0x00 << 0)
+#define CRC_VAR_CLK0                   (0x01 << 0)
+#define CRC_VAR_CLK1                   (0x02 << 0)
+#define SD30_FIX_CLK                   (0x00 << 2)
+#define SD30_VAR_CLK0                  (0x01 << 2)
+#define SD30_VAR_CLK1                  (0x02 << 2)
+#define SAMPLE_FIX_CLK                 (0x00 << 4)
+#define SAMPLE_VAR_CLK0                        (0x01 << 4)
+#define SAMPLE_VAR_CLK1                        (0x02 << 4)
+
+/* SD_SAMPLE_POINT_CTL */
+#define        DDR_FIX_RX_DAT                  0x00
+#define        DDR_VAR_RX_DAT                  0x80
+#define        DDR_FIX_RX_DAT_EDGE             0x00
+#define        DDR_FIX_RX_DAT_14_DELAY         0x40
+#define        DDR_FIX_RX_CMD                  0x00
+#define        DDR_VAR_RX_CMD                  0x20
+#define        DDR_FIX_RX_CMD_POS_EDGE         0x00
+#define        DDR_FIX_RX_CMD_14_DELAY         0x10
+#define        SD20_RX_POS_EDGE                0x00
+#define        SD20_RX_14_DELAY                0x08
+#define SD20_RX_SEL_MASK               0x08
+
+/* SD_PUSH_POINT_CTL */
+#define        DDR_FIX_TX_CMD_DAT              0x00
+#define        DDR_VAR_TX_CMD_DAT              0x80
+#define        DDR_FIX_TX_DAT_14_TSU           0x00
+#define        DDR_FIX_TX_DAT_12_TSU           0x40
+#define        DDR_FIX_TX_CMD_NEG_EDGE         0x00
+#define        DDR_FIX_TX_CMD_14_AHEAD         0x20
+#define        SD20_TX_NEG_EDGE                0x00
+#define        SD20_TX_14_AHEAD                0x10
+#define SD20_TX_SEL_MASK               0x10
+#define        DDR_VAR_SDCLK_POL_SWAP          0x01
+
+/* MS_CFG */
+#define        SAMPLE_TIME_RISING              0x00
+#define        SAMPLE_TIME_FALLING             0x80
+#define        PUSH_TIME_DEFAULT               0x00
+#define        PUSH_TIME_ODD                   0x40
+#define        NO_EXTEND_TOGGLE                0x00
+#define        EXTEND_TOGGLE_CHK               0x20
+#define        MS_BUS_WIDTH_1                  0x00
+#define        MS_BUS_WIDTH_4                  0x10
+#define        MS_BUS_WIDTH_8                  0x18
+#define        MS_2K_SECTOR_MODE               0x04
+#define        MS_512_SECTOR_MODE              0x00
+#define        MS_TOGGLE_TIMEOUT_EN            0x00
+#define        MS_TOGGLE_TIMEOUT_DISEN         0x01
+#define MS_NO_CHECK_INT                        0x02
+
+/* MS_TRANS_CFG */
+#define        WAIT_INT                        0x80
+#define        NO_WAIT_INT                     0x00
+#define        NO_AUTO_READ_INT_REG            0x00
+#define        AUTO_READ_INT_REG               0x40
+#define        MS_CRC16_ERR                    0x20
+#define        MS_RDY_TIMEOUT                  0x10
+#define        MS_INT_CMDNK                    0x08
+#define        MS_INT_BREQ                     0x04
+#define        MS_INT_ERR                      0x02
+#define        MS_INT_CED                      0x01
+
+/* MS_TRANSFER */
+#define        MS_TRANSFER_START               0x80
+#define        MS_TRANSFER_END                 0x40
+#define        MS_TRANSFER_ERR                 0x20
+#define        MS_BS_STATE                     0x10
+#define        MS_TM_READ_BYTES                0x00
+#define        MS_TM_NORMAL_READ               0x01
+#define        MS_TM_WRITE_BYTES               0x04
+#define        MS_TM_NORMAL_WRITE              0x05
+#define        MS_TM_AUTO_READ                 0x08
+#define        MS_TM_AUTO_WRITE                0x0C
+#define MS_TM_SET_CMD                  0x06
+#define MS_TM_COPY_PAGE                        0x07
+#define MS_TM_MULTI_READ               0x02
+#define MS_TM_MULTI_WRITE              0x03
+
+/* MC_FIFO_CTL */
+#define FIFO_FLUSH                     0x01
+
+/* MC_DMA_RST */
+#define DMA_RESET  0x01
+
+/* MC_DMA_CTL */
+#define DMA_TC_EQ_0                    0x80
+#define DMA_DIR_TO_CARD                        0x00
+#define DMA_DIR_FROM_CARD              0x02
+#define DMA_EN                         0x01
+#define DMA_128                                (0 << 2)
+#define DMA_256                                (1 << 2)
+#define DMA_512                                (2 << 2)
+#define DMA_1024                       (3 << 2)
+#define DMA_PACK_SIZE_MASK             0x0C
+
+/* CARD_INT_PEND */
+#define XD_INT                         0x10
+#define MS_INT                         0x08
+#define SD_INT                         0x04
+
+/* LED operations*/
+static inline int rtsx_usb_turn_on_led(struct rtsx_ucr *ucr)
+{
+       return  rtsx_usb_ep0_write_register(ucr, CARD_GPIO, 0x03, 0x02);
+}
+
+static inline int rtsx_usb_turn_off_led(struct rtsx_ucr *ucr)
+{
+       return rtsx_usb_ep0_write_register(ucr, CARD_GPIO, 0x03, 0x03);
+}
+
+/* HW error clearing */
+static inline void rtsx_usb_clear_fsm_err(struct rtsx_ucr *ucr)
+{
+       rtsx_usb_ep0_write_register(ucr, SFSM_ED, 0xf8, 0xf8);
+}
+
+static inline void rtsx_usb_clear_dma_err(struct rtsx_ucr *ucr)
+{
+       rtsx_usb_ep0_write_register(ucr, MC_FIFO_CTL,
+                       FIFO_FLUSH, FIFO_FLUSH);
+       rtsx_usb_ep0_write_register(ucr, MC_DMA_RST, DMA_RESET, DMA_RESET);
+}
+#endif /* __RTS51139_H */
diff --git a/include/linux/mfd/tps65218.h b/include/linux/mfd/tps65218.h
new file mode 100644 (file)
index 0000000..d2e357d
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * linux/mfd/tps65218.h
+ *
+ * Functions to access TPS65219 power management chip.
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether expressed or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License version 2 for more details.
+ */
+
+#ifndef __LINUX_MFD_TPS65218_H
+#define __LINUX_MFD_TPS65218_H
+
+#include <linux/i2c.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/bitops.h>
+
+/* TPS chip id list */
+#define TPS65218                       0xF0
+
+/* I2C ID for TPS65218 part */
+#define TPS65218_I2C_ID                        0x24
+
+/* All register addresses */
+#define TPS65218_REG_CHIPID            0x00
+#define TPS65218_REG_INT1              0x01
+#define TPS65218_REG_INT2              0x02
+#define TPS65218_REG_INT_MASK1         0x03
+#define TPS65218_REG_INT_MASK2         0x04
+#define TPS65218_REG_STATUS            0x05
+#define TPS65218_REG_CONTROL           0x06
+#define TPS65218_REG_FLAG              0x07
+
+#define TPS65218_REG_PASSWORD          0x10
+#define TPS65218_REG_ENABLE1           0x11
+#define TPS65218_REG_ENABLE2           0x12
+#define TPS65218_REG_CONFIG1           0x13
+#define TPS65218_REG_CONFIG2           0x14
+#define TPS65218_REG_CONFIG3           0x15
+#define TPS65218_REG_CONTROL_DCDC1     0x16
+#define TPS65218_REG_CONTROL_DCDC2     0x17
+#define TPS65218_REG_CONTROL_DCDC3     0x18
+#define TPS65218_REG_CONTROL_DCDC4     0x19
+#define TPS65218_REG_CONTRL_SLEW_RATE  0x1A
+#define TPS65218_REG_CONTROL_LDO1      0x1B
+#define TPS65218_REG_SEQ1              0x20
+#define TPS65218_REG_SEQ2              0x21
+#define TPS65218_REG_SEQ3              0x22
+#define TPS65218_REG_SEQ4              0x23
+#define TPS65218_REG_SEQ5              0x24
+#define TPS65218_REG_SEQ6              0x25
+#define TPS65218_REG_SEQ7              0x26
+
+/* Register field definitions */
+#define TPS65218_CHIPID_CHIP_MASK      0xF8
+#define TPS65218_CHIPID_REV_MASK       0x07
+
+#define TPS65218_INT1_VPRG             BIT(5)
+#define TPS65218_INT1_AC               BIT(4)
+#define TPS65218_INT1_PB               BIT(3)
+#define TPS65218_INT1_HOT              BIT(2)
+#define TPS65218_INT1_CC_AQC           BIT(1)
+#define TPS65218_INT1_PRGC             BIT(0)
+
+#define TPS65218_INT2_LS3_F            BIT(5)
+#define TPS65218_INT2_LS2_F            BIT(4)
+#define TPS65218_INT2_LS1_F            BIT(3)
+#define TPS65218_INT2_LS3_I            BIT(2)
+#define TPS65218_INT2_LS2_I            BIT(1)
+#define TPS65218_INT2_LS1_I            BIT(0)
+
+#define TPS65218_INT_MASK1_VPRG                BIT(5)
+#define TPS65218_INT_MASK1_AC          BIT(4)
+#define TPS65218_INT_MASK1_PB          BIT(3)
+#define TPS65218_INT_MASK1_HOT         BIT(2)
+#define TPS65218_INT_MASK1_CC_AQC      BIT(1)
+#define TPS65218_INT_MASK1_PRGC                BIT(0)
+
+#define TPS65218_INT_MASK2_LS3_F       BIT(5)
+#define TPS65218_INT_MASK2_LS2_F       BIT(4)
+#define TPS65218_INT_MASK2_LS1_F       BIT(3)
+#define TPS65218_INT_MASK2_LS3_I       BIT(2)
+#define TPS65218_INT_MASK2_LS2_I       BIT(1)
+#define TPS65218_INT_MASK2_LS1_I       BIT(0)
+
+#define TPS65218_STATUS_FSEAL          BIT(7)
+#define TPS65218_STATUS_EE             BIT(6)
+#define TPS65218_STATUS_AC_STATE       BIT(5)
+#define TPS65218_STATUS_PB_STATE       BIT(4)
+#define TPS65218_STATUS_STATE_MASK     0xC
+#define TPS65218_STATUS_CC_STAT                0x3
+
+#define TPS65218_CONTROL_OFFNPFO       BIT(1)
+#define TPS65218_CONTROL_CC_AQ BIT(0)
+
+#define TPS65218_FLAG_GPO3_FLG         BIT(7)
+#define TPS65218_FLAG_GPO2_FLG         BIT(6)
+#define TPS65218_FLAG_GPO1_FLG         BIT(5)
+#define TPS65218_FLAG_LDO1_FLG         BIT(4)
+#define TPS65218_FLAG_DC4_FLG          BIT(3)
+#define TPS65218_FLAG_DC3_FLG          BIT(2)
+#define TPS65218_FLAG_DC2_FLG          BIT(1)
+#define TPS65218_FLAG_DC1_FLG          BIT(0)
+
+#define TPS65218_ENABLE1_DC6_EN                BIT(5)
+#define TPS65218_ENABLE1_DC5_EN                BIT(4)
+#define TPS65218_ENABLE1_DC4_EN                BIT(3)
+#define TPS65218_ENABLE1_DC3_EN                BIT(2)
+#define TPS65218_ENABLE1_DC2_EN                BIT(1)
+#define TPS65218_ENABLE1_DC1_EN                BIT(0)
+
+#define TPS65218_ENABLE2_GPIO3         BIT(6)
+#define TPS65218_ENABLE2_GPIO2         BIT(5)
+#define TPS65218_ENABLE2_GPIO1         BIT(4)
+#define TPS65218_ENABLE2_LS3_EN                BIT(3)
+#define TPS65218_ENABLE2_LS2_EN                BIT(2)
+#define TPS65218_ENABLE2_LS1_EN                BIT(1)
+#define TPS65218_ENABLE2_LDO1_EN       BIT(0)
+
+
+#define TPS65218_CONFIG1_TRST          BIT(7)
+#define TPS65218_CONFIG1_GPO2_BUF      BIT(6)
+#define TPS65218_CONFIG1_IO1_SEL       BIT(5)
+#define TPS65218_CONFIG1_PGDLY_MASK    0x18
+#define TPS65218_CONFIG1_STRICT                BIT(2)
+#define TPS65218_CONFIG1_UVLO_MASK     0x3
+
+#define TPS65218_CONFIG2_DC12_RST      BIT(7)
+#define TPS65218_CONFIG2_UVLOHYS       BIT(6)
+#define TPS65218_CONFIG2_LS3ILIM_MASK  0xC
+#define TPS65218_CONFIG2_LS2ILIM_MASK  0x3
+
+#define TPS65218_CONFIG3_LS3NPFO       BIT(5)
+#define TPS65218_CONFIG3_LS2NPFO       BIT(4)
+#define TPS65218_CONFIG3_LS1NPFO       BIT(3)
+#define TPS65218_CONFIG3_LS3DCHRG      BIT(2)
+#define TPS65218_CONFIG3_LS2DCHRG      BIT(1)
+#define TPS65218_CONFIG3_LS1DCHRG      BIT(0)
+
+#define TPS65218_CONTROL_DCDC1_PFM     BIT(7)
+#define TPS65218_CONTROL_DCDC1_MASK    0x7F
+
+#define TPS65218_CONTROL_DCDC2_PFM     BIT(7)
+#define TPS65218_CONTROL_DCDC2_MASK    0x3F
+
+#define TPS65218_CONTROL_DCDC3_PFM     BIT(7)
+#define TPS65218_CONTROL_DCDC3_MASK    0x3F
+
+#define TPS65218_CONTROL_DCDC4_PFM     BIT(7)
+#define TPS65218_CONTROL_DCDC4_MASK    0x3F
+
+#define TPS65218_SLEW_RATE_GO          BIT(7)
+#define TPS65218_SLEW_RATE_GODSBL      BIT(6)
+#define TPS65218_SLEW_RATE_SLEW_MASK   0x7
+
+#define TPS65218_CONTROL_LDO1_MASK     0x3F
+
+#define TPS65218_SEQ1_DLY8             BIT(7)
+#define TPS65218_SEQ1_DLY7             BIT(6)
+#define TPS65218_SEQ1_DLY6             BIT(5)
+#define TPS65218_SEQ1_DLY5             BIT(4)
+#define TPS65218_SEQ1_DLY4             BIT(3)
+#define TPS65218_SEQ1_DLY3             BIT(2)
+#define TPS65218_SEQ1_DLY2             BIT(1)
+#define TPS65218_SEQ1_DLY1             BIT(0)
+
+#define TPS65218_SEQ2_DLYFCTR          BIT(7)
+#define TPS65218_SEQ2_DLY9             BIT(0)
+
+#define TPS65218_SEQ3_DC2_SEQ_MASK     0xF0
+#define TPS65218_SEQ3_DC1_SEQ_MASK     0xF
+
+#define TPS65218_SEQ4_DC4_SEQ_MASK     0xF0
+#define TPS65218_SEQ4_DC3_SEQ_MASK     0xF
+
+#define TPS65218_SEQ5_DC6_SEQ_MASK     0xF0
+#define TPS65218_SEQ5_DC5_SEQ_MASK     0xF
+
+#define TPS65218_SEQ6_LS1_SEQ_MASK     0xF0
+#define TPS65218_SEQ6_LDO1_SEQ_MASK    0xF
+
+#define TPS65218_SEQ7_GPO3_SEQ_MASK    0xF0
+#define TPS65218_SEQ7_GPO1_SEQ_MASK    0xF
+#define TPS65218_PROTECT_NONE          0
+#define TPS65218_PROTECT_L1            1
+
+enum tps65218_regulator_id {
+       /* DCDC's */
+       TPS65218_DCDC_1,
+       TPS65218_DCDC_2,
+       TPS65218_DCDC_3,
+       TPS65218_DCDC_4,
+       TPS65218_DCDC_5,
+       TPS65218_DCDC_6,
+       /* LDOs */
+       TPS65218_LDO_1,
+};
+
+#define TPS65218_MAX_REG_ID            TPS65218_LDO_1
+
+/* Number of step-down converters available */
+#define TPS65218_NUM_DCDC              6
+/* Number of LDO voltage regulators available */
+#define TPS65218_NUM_LDO               1
+/* Number of total regulators available */
+#define TPS65218_NUM_REGULATOR         (TPS65218_NUM_DCDC + TPS65218_NUM_LDO)
+
+/* Define the TPS65218 IRQ numbers */
+enum tps65218_irqs {
+       /* INT1 registers */
+       TPS65218_PRGC_IRQ,
+       TPS65218_CC_AQC_IRQ,
+       TPS65218_HOT_IRQ,
+       TPS65218_PB_IRQ,
+       TPS65218_AC_IRQ,
+       TPS65218_VPRG_IRQ,
+       TPS65218_INVALID1_IRQ,
+       TPS65218_INVALID2_IRQ,
+       /* INT2 registers */
+       TPS65218_LS1_I_IRQ,
+       TPS65218_LS2_I_IRQ,
+       TPS65218_LS3_I_IRQ,
+       TPS65218_LS1_F_IRQ,
+       TPS65218_LS2_F_IRQ,
+       TPS65218_LS3_F_IRQ,
+       TPS65218_INVALID3_IRQ,
+       TPS65218_INVALID4_IRQ,
+};
+
+/**
+ * struct tps_info - packages regulator constraints
+ * @id:                        Id of the regulator
+ * @name:              Voltage regulator name
+ * @min_uV:            minimum micro volts
+ * @max_uV:            minimum micro volts
+ *
+ * This data is used to check the regualtor voltage limits while setting.
+ */
+struct tps_info {
+       int id;
+       const char *name;
+       int min_uV;
+       int max_uV;
+};
+
+/**
+ * struct tps65218 - tps65218 sub-driver chip access routines
+ *
+ * Device data may be used to access the TPS65218 chip
+ */
+
+struct tps65218 {
+       struct device *dev;
+       unsigned int id;
+
+       struct mutex tps_lock;          /* lock guarding the data structure */
+       /* IRQ Data */
+       int irq;
+       u32 irq_mask;
+       struct regmap_irq_chip_data *irq_data;
+       struct regulator_desc desc[TPS65218_NUM_REGULATOR];
+       struct regulator_dev *rdev[TPS65218_NUM_REGULATOR];
+       struct tps_info *info[TPS65218_NUM_REGULATOR];
+       struct regmap *regmap;
+};
+
+int tps65218_reg_read(struct tps65218 *tps, unsigned int reg,
+                                       unsigned int *val);
+int tps65218_reg_write(struct tps65218 *tps, unsigned int reg,
+                       unsigned int val, unsigned int level);
+int tps65218_set_bits(struct tps65218 *tps, unsigned int reg,
+               unsigned int mask, unsigned int val, unsigned int level);
+int tps65218_clear_bits(struct tps65218 *tps, unsigned int reg,
+               unsigned int mask, unsigned int level);
+
+#endif /*  __LINUX_MFD_TPS65218_H */
index 35300f3..abc8484 100644 (file)
@@ -177,6 +177,9 @@ extern unsigned int kobjsize(const void *objp);
  */
 #define VM_SPECIAL (VM_IO | VM_DONTEXPAND | VM_PFNMAP | VM_MIXEDMAP)
 
+/* This mask defines which mm->def_flags a process can inherit its parent */
+#define VM_INIT_DEF_MASK       VM_NOHUGEPAGE
+
 /*
  * mapping from the currently active vm_flags protection bits (the
  * low four bits) to a page protection mask..
@@ -210,6 +213,10 @@ struct vm_fault {
                                         * is set (which is also implied by
                                         * VM_FAULT_ERROR).
                                         */
+       /* for ->map_pages() only */
+       pgoff_t max_pgoff;              /* map pages for offset from pgoff till
+                                        * max_pgoff inclusive */
+       pte_t *pte;                     /* pte entry associated with ->pgoff */
 };
 
 /*
@@ -221,6 +228,7 @@ struct vm_operations_struct {
        void (*open)(struct vm_area_struct * area);
        void (*close)(struct vm_area_struct * area);
        int (*fault)(struct vm_area_struct *vma, struct vm_fault *vmf);
+       void (*map_pages)(struct vm_area_struct *vma, struct vm_fault *vmf);
 
        /* notification that a previously read-only page is about to become
         * writable, if an error is returned it will cause a SIGBUS */
@@ -581,6 +589,9 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
                pte = pte_mkwrite(pte);
        return pte;
 }
+
+void do_set_pte(struct vm_area_struct *vma, unsigned long address,
+               struct page *page, pte_t *pte, bool write, bool anon);
 #endif
 
 /*
@@ -684,7 +695,7 @@ static inline pte_t maybe_mkwrite(pte_t pte, struct vm_area_struct *vma)
 #define ZONES_MASK             ((1UL << ZONES_WIDTH) - 1)
 #define NODES_MASK             ((1UL << NODES_WIDTH) - 1)
 #define SECTIONS_MASK          ((1UL << SECTIONS_WIDTH) - 1)
-#define LAST_CPUPID_MASK       ((1UL << LAST_CPUPID_WIDTH) - 1)
+#define LAST_CPUPID_MASK       ((1UL << LAST_CPUPID_SHIFT) - 1)
 #define ZONEID_MASK            ((1UL << ZONEID_SHIFT) - 1)
 
 static inline enum zone_type page_zonenum(const struct page *page)
@@ -1836,6 +1847,7 @@ extern void truncate_inode_pages_final(struct address_space *);
 
 /* generic vm_area_ops exported for stackable file systems */
 extern int filemap_fault(struct vm_area_struct *, struct vm_fault *);
+extern void filemap_map_pages(struct vm_area_struct *vma, struct vm_fault *vmf);
 extern int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf);
 
 /* mm/page-writeback.c */
@@ -1863,9 +1875,6 @@ void page_cache_async_readahead(struct address_space *mapping,
                                unsigned long size);
 
 unsigned long max_sane_readahead(unsigned long nr);
-unsigned long ra_submit(struct file_ra_state *ra,
-                       struct address_space *mapping,
-                       struct file *filp);
 
 /* Generic expand stack which grows the stack according to GROWS{UP,DOWN} */
 extern int expand_stack(struct vm_area_struct *vma, unsigned long address);
index 290901a..2b58d19 100644 (file)
@@ -342,9 +342,9 @@ struct mm_rss_stat {
 
 struct kioctx_table;
 struct mm_struct {
-       struct vm_area_struct * mmap;           /* list of VMAs */
+       struct vm_area_struct *mmap;            /* list of VMAs */
        struct rb_root mm_rb;
-       struct vm_area_struct * mmap_cache;     /* last find_vma result */
+       u32 vmacache_seqnum;                   /* per-thread vmacache */
 #ifdef CONFIG_MMU
        unsigned long (*get_unmapped_area) (struct file *filp,
                                unsigned long addr, unsigned long len,
index 87079fc..f206e29 100644 (file)
@@ -95,7 +95,7 @@ struct mmc_command {
  *              actively failing requests
  */
 
-       unsigned int            cmd_timeout_ms; /* in milliseconds */
+       unsigned int            busy_timeout;   /* busy detect timeout in ms */
        /* Set this flag only for blocking sanitize request */
        bool                    sanitize_busy;
 
@@ -152,7 +152,7 @@ extern int mmc_wait_for_app_cmd(struct mmc_host *, struct mmc_card *,
        struct mmc_command *, int);
 extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
 extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
-                       bool);
+                       bool, bool);
 extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
 extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
 
index 99f5709..cb61ea4 100644 (file)
@@ -264,15 +264,12 @@ struct mmc_host {
        u32                     caps2;          /* More host capabilities */
 
 #define MMC_CAP2_BOOTPART_NOACC        (1 << 0)        /* Boot partition no access */
-#define MMC_CAP2_CACHE_CTRL    (1 << 1)        /* Allow cache control */
 #define MMC_CAP2_FULL_PWR_CYCLE        (1 << 2)        /* Can do full power cycle */
 #define MMC_CAP2_NO_MULTI_READ (1 << 3)        /* Multiblock reads don't work */
-#define MMC_CAP2_NO_SLEEP_CMD  (1 << 4)        /* Don't allow sleep command */
 #define MMC_CAP2_HS200_1_8V_SDR        (1 << 5)        /* can support */
 #define MMC_CAP2_HS200_1_2V_SDR        (1 << 6)        /* can support */
 #define MMC_CAP2_HS200         (MMC_CAP2_HS200_1_8V_SDR | \
                                 MMC_CAP2_HS200_1_2V_SDR)
-#define MMC_CAP2_BROKEN_VOLTAGE        (1 << 7)        /* Use the broken voltage */
 #define MMC_CAP2_HC_ERASE_SZ   (1 << 9)        /* High-capacity erase size */
 #define MMC_CAP2_CD_ACTIVE_HIGH        (1 << 10)       /* Card-detect signal active high */
 #define MMC_CAP2_RO_ACTIVE_HIGH        (1 << 11)       /* Write-protect signal active high */
@@ -281,7 +278,6 @@ struct mmc_host {
 #define MMC_CAP2_PACKED_CMD    (MMC_CAP2_PACKED_RD | \
                                 MMC_CAP2_PACKED_WR)
 #define MMC_CAP2_NO_PRESCAN_POWERUP (1 << 14)  /* Don't power up before scan */
-#define MMC_CAP2_SANITIZE      (1 << 15)               /* Support Sanitize */
 
        mmc_pm_flag_t           pm_caps;        /* supported pm features */
 
@@ -304,7 +300,7 @@ struct mmc_host {
        unsigned int            max_req_size;   /* maximum number of bytes in one req */
        unsigned int            max_blk_size;   /* maximum size of one mmc block */
        unsigned int            max_blk_count;  /* maximum number of blocks in one req */
-       unsigned int            max_discard_to; /* max. discard timeout in ms */
+       unsigned int            max_busy_timeout; /* max busy timeout in ms */
 
        /* private data */
        spinlock_t              lock;           /* lock for claim and bus ops */
@@ -388,8 +384,6 @@ int mmc_power_restore_host(struct mmc_host *host);
 void mmc_detect_change(struct mmc_host *, unsigned long delay);
 void mmc_request_done(struct mmc_host *, struct mmc_request *);
 
-int mmc_cache_ctrl(struct mmc_host *, u8);
-
 static inline void mmc_signal_sdio_irq(struct mmc_host *host)
 {
        host->ops->enable_sdio_irq(host, 0);
@@ -424,12 +418,9 @@ static inline int mmc_regulator_get_supply(struct mmc_host *mmc)
 
 int mmc_pm_notify(struct notifier_block *notify_block, unsigned long, void *);
 
-/* Module parameter */
-extern bool mmc_assume_removable;
-
 static inline int mmc_card_is_removable(struct mmc_host *host)
 {
-       return !(host->caps & MMC_CAP_NONREMOVABLE) && mmc_assume_removable;
+       return !(host->caps & MMC_CAP_NONREMOVABLE);
 }
 
 static inline int mmc_card_keep_power(struct mmc_host *host)
index e78c0e2..8cc095a 100644 (file)
 /*
  * struct sdhci_plat_data: spear sdhci platform data structure
  *
- * @card_power_gpio: gpio pin for enabling/disabling power to sdhci socket
- * @power_active_high: if set, enable power to sdhci socket by setting
- *                     card_power_gpio
- * @power_always_enb: If set, then enable power on probe, otherwise enable only
- *                     on card insertion and disable on card removal.
  * card_int_gpio: gpio pin used for card detection
  */
 struct sdhci_plat_data {
-       int card_power_gpio;
-       int power_active_high;
-       int power_always_enb;
        int card_int_gpio;
 };
 
index 362927c..7be12b8 100644 (file)
@@ -100,6 +100,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK2_BROKEN_HOST_CONTROL               (1<<5)
 /* Controller does not support HS200 */
 #define SDHCI_QUIRK2_BROKEN_HS200                      (1<<6)
+/* Controller does not support DDR50 */
+#define SDHCI_QUIRK2_BROKEN_DDR50                      (1<<7)
 
        int irq;                /* Device IRQ */
        void __iomem *ioaddr;   /* Mapped address */
index b0c73e4..d243338 100644 (file)
@@ -22,4 +22,10 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
                        unsigned int debounce);
 void mmc_gpio_free_cd(struct mmc_host *host);
 
+int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
+                        unsigned int idx, bool override_active_level,
+                        unsigned int debounce);
+void mmc_gpiod_free_cd(struct mmc_host *host);
+void mmc_gpiod_request_cd_irq(struct mmc_host *host);
+
 #endif
index 5042c03..2d57efa 100644 (file)
@@ -3,8 +3,8 @@
 
 struct page;
 
-extern void dump_page(struct page *page, char *reason);
-extern void dump_page_badflags(struct page *page, char *reason,
+extern void dump_page(struct page *page, const char *reason);
+extern void dump_page_badflags(struct page *page, const char *reason,
                               unsigned long badflags);
 
 #ifdef CONFIG_DEBUG_VM
index 5a50539..f520a76 100644 (file)
@@ -82,15 +82,6 @@ void sort_extable(struct exception_table_entry *start,
 void sort_main_extable(void);
 void trim_init_extable(struct module *m);
 
-#ifdef MODULE
-#define MODULE_GENERIC_TABLE(gtype, name)                      \
-extern const struct gtype##_id __mod_##gtype##_table           \
-  __attribute__ ((unused, alias(__stringify(name))))
-
-#else  /* !MODULE */
-#define MODULE_GENERIC_TABLE(gtype, name)
-#endif
-
 /* Generic info of form tag = "info" */
 #define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
 
@@ -141,8 +132,14 @@ extern const struct gtype##_id __mod_##gtype##_table               \
 /* What your module does. */
 #define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
 
-#define MODULE_DEVICE_TABLE(type, name)                \
-  MODULE_GENERIC_TABLE(type##_device, name)
+#ifdef MODULE
+/* Creates an alias so file2alias.c can find device table. */
+#define MODULE_DEVICE_TABLE(type, name)                                        \
+  extern const struct type##_device_id __mod_##type##__##name##_device_table \
+  __attribute__ ((unused, alias(__stringify(name))))
+#else  /* !MODULE */
+#define MODULE_DEVICE_TABLE(type, name)
+#endif
 
 /* Version of form [<epoch>:]<version>[-<extra-version>].
  * Or for CVS/RCS ID version, everything but the number is stripped.
index c3eb102..204a677 100644 (file)
@@ -186,14 +186,12 @@ struct kparam_array
    parameters. */
 #define __module_param_call(prefix, name, ops, arg, perm, level)       \
        /* Default value instead of permissions? */                     \
-       static int __param_perm_check_##name __attribute__((unused)) =  \
-       BUILD_BUG_ON_ZERO((perm) < 0 || (perm) > 0777 || ((perm) & 2))  \
-       + BUILD_BUG_ON_ZERO(sizeof(""prefix) > MAX_PARAM_PREFIX_LEN);   \
-       static const char __param_str_##name[] = prefix #name;          \
+       static const char __param_str_##name[] = prefix #name; \
        static struct kernel_param __moduleparam_const __param_##name   \
        __used                                                          \
     __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
-       = { __param_str_##name, ops, perm, level, { arg } }
+       = { __param_str_##name, ops, VERIFY_OCTAL_PERMISSIONS(perm),    \
+           level, { arg } }
 
 /* Obsolete - use module_param_cb() */
 #define module_param_call(name, set, get, arg, perm)                   \
@@ -346,7 +344,7 @@ static inline void destroy_params(const struct kernel_param *params,
 /* The macros to do compile-time type checking stolen from Jakub
    Jelinek, who IIRC came up with this idea for the 2.4 module init code. */
 #define __param_check(name, p, type) \
-       static inline type *__check_##name(void) { return(p); }
+       static inline type __always_unused *__check_##name(void) { return(p); }
 
 extern struct kernel_param_ops param_ops_byte;
 extern int param_set_byte(const char *val, const struct kernel_param *kp);
index 8cc0e2f..a1b0b4c 100644 (file)
@@ -204,12 +204,12 @@ struct mtd_info {
                          struct mtd_oob_ops *ops);
        int (*_write_oob) (struct mtd_info *mtd, loff_t to,
                           struct mtd_oob_ops *ops);
-       int (*_get_fact_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
-                                   size_t len);
+       int (*_get_fact_prot_info) (struct mtd_info *mtd, size_t len,
+                                   size_t *retlen, struct otp_info *buf);
        int (*_read_fact_prot_reg) (struct mtd_info *mtd, loff_t from,
                                    size_t len, size_t *retlen, u_char *buf);
-       int (*_get_user_prot_info) (struct mtd_info *mtd, struct otp_info *buf,
-                                   size_t len);
+       int (*_get_user_prot_info) (struct mtd_info *mtd, size_t len,
+                                   size_t *retlen, struct otp_info *buf);
        int (*_read_user_prot_reg) (struct mtd_info *mtd, loff_t from,
                                    size_t len, size_t *retlen, u_char *buf);
        int (*_write_user_prot_reg) (struct mtd_info *mtd, loff_t to,
@@ -278,12 +278,12 @@ static inline int mtd_write_oob(struct mtd_info *mtd, loff_t to,
        return mtd->_write_oob(mtd, to, ops);
 }
 
-int mtd_get_fact_prot_info(struct mtd_info *mtd, struct otp_info *buf,
-                          size_t len);
+int mtd_get_fact_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
+                          struct otp_info *buf);
 int mtd_read_fact_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
                           size_t *retlen, u_char *buf);
-int mtd_get_user_prot_info(struct mtd_info *mtd, struct otp_info *buf,
-                          size_t len);
+int mtd_get_user_prot_info(struct mtd_info *mtd, size_t len, size_t *retlen,
+                          struct otp_info *buf);
 int mtd_read_user_prot_reg(struct mtd_info *mtd, loff_t from, size_t len,
                           size_t *retlen, u_char *buf);
 int mtd_write_user_prot_reg(struct mtd_info *mtd, loff_t to, size_t len,
index 32f8612..450d61e 100644 (file)
@@ -51,14 +51,6 @@ extern int nand_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len);
 /* The maximum number of NAND chips in an array */
 #define NAND_MAX_CHIPS         8
 
-/*
- * This constant declares the max. oobsize / page, which
- * is supported now. If you add a chip with bigger oobsize/page
- * adjust this accordingly.
- */
-#define NAND_MAX_OOBSIZE       744
-#define NAND_MAX_PAGESIZE      8192
-
 /*
  * Constants for hardware specific CLE/ALE/NCE function
  *
@@ -350,6 +342,84 @@ struct nand_onfi_vendor_micron {
        u8 param_revision;
 } __packed;
 
+struct jedec_ecc_info {
+       u8 ecc_bits;
+       u8 codeword_size;
+       __le16 bb_per_lun;
+       __le16 block_endurance;
+       u8 reserved[2];
+} __packed;
+
+/* JEDEC features */
+#define JEDEC_FEATURE_16_BIT_BUS       (1 << 0)
+
+struct nand_jedec_params {
+       /* rev info and features block */
+       /* 'J' 'E' 'S' 'D'  */
+       u8 sig[4];
+       __le16 revision;
+       __le16 features;
+       u8 opt_cmd[3];
+       __le16 sec_cmd;
+       u8 num_of_param_pages;
+       u8 reserved0[18];
+
+       /* manufacturer information block */
+       char manufacturer[12];
+       char model[20];
+       u8 jedec_id[6];
+       u8 reserved1[10];
+
+       /* memory organization block */
+       __le32 byte_per_page;
+       __le16 spare_bytes_per_page;
+       u8 reserved2[6];
+       __le32 pages_per_block;
+       __le32 blocks_per_lun;
+       u8 lun_count;
+       u8 addr_cycles;
+       u8 bits_per_cell;
+       u8 programs_per_page;
+       u8 multi_plane_addr;
+       u8 multi_plane_op_attr;
+       u8 reserved3[38];
+
+       /* electrical parameter block */
+       __le16 async_sdr_speed_grade;
+       __le16 toggle_ddr_speed_grade;
+       __le16 sync_ddr_speed_grade;
+       u8 async_sdr_features;
+       u8 toggle_ddr_features;
+       u8 sync_ddr_features;
+       __le16 t_prog;
+       __le16 t_bers;
+       __le16 t_r;
+       __le16 t_r_multi_plane;
+       __le16 t_ccs;
+       __le16 io_pin_capacitance_typ;
+       __le16 input_pin_capacitance_typ;
+       __le16 clk_pin_capacitance_typ;
+       u8 driver_strength_support;
+       __le16 t_ald;
+       u8 reserved4[36];
+
+       /* ECC and endurance block */
+       u8 guaranteed_good_blocks;
+       __le16 guaranteed_block_endurance;
+       struct jedec_ecc_info ecc_info[4];
+       u8 reserved5[29];
+
+       /* reserved */
+       u8 reserved6[148];
+
+       /* vendor */
+       __le16 vendor_rev_num;
+       u8 reserved7[88];
+
+       /* CRC for Parameter Page */
+       __le16 crc;
+} __packed;
+
 /**
  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
  * @lock:               protection lock
@@ -418,7 +488,7 @@ struct nand_ecc_ctrl {
        int (*read_page)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint8_t *buf, int oob_required, int page);
        int (*read_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint32_t offs, uint32_t len, uint8_t *buf);
+                       uint32_t offs, uint32_t len, uint8_t *buf, int page);
        int (*write_subpage)(struct mtd_info *mtd, struct nand_chip *chip,
                        uint32_t offset, uint32_t data_len,
                        const uint8_t *data_buf, int oob_required);
@@ -435,17 +505,17 @@ struct nand_ecc_ctrl {
 
 /**
  * struct nand_buffers - buffer structure for read/write
- * @ecccalc:   buffer for calculated ECC
- * @ecccode:   buffer for ECC read from flash
- * @databuf:   buffer for data - dynamically sized
+ * @ecccalc:   buffer pointer for calculated ECC, size is oobsize.
+ * @ecccode:   buffer pointer for ECC read from flash, size is oobsize.
+ * @databuf:   buffer pointer for data, size is (page size + oobsize).
  *
  * Do not change the order of buffers. databuf and oobrbuf must be in
  * consecutive order.
  */
 struct nand_buffers {
-       uint8_t ecccalc[NAND_MAX_OOBSIZE];
-       uint8_t ecccode[NAND_MAX_OOBSIZE];
-       uint8_t databuf[NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE];
+       uint8_t *ecccalc;
+       uint8_t *ecccode;
+       uint8_t *databuf;
 };
 
 /**
@@ -523,8 +593,12 @@ struct nand_buffers {
  * @subpagesize:       [INTERN] holds the subpagesize
  * @onfi_version:      [INTERN] holds the chip ONFI version (BCD encoded),
  *                     non 0 if ONFI supported.
+ * @jedec_version:     [INTERN] holds the chip JEDEC version (BCD encoded),
+ *                     non 0 if JEDEC supported.
  * @onfi_params:       [INTERN] holds the ONFI page parameter when ONFI is
  *                     supported, 0 otherwise.
+ * @jedec_params:      [INTERN] holds the JEDEC parameter page when JEDEC is
+ *                     supported, 0 otherwise.
  * @read_retries:      [INTERN] the number of read retry modes supported
  * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
  * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
@@ -597,7 +671,11 @@ struct nand_chip {
        int badblockbits;
 
        int onfi_version;
-       struct nand_onfi_params onfi_params;
+       int jedec_version;
+       union {
+               struct nand_onfi_params onfi_params;
+               struct nand_jedec_params jedec_params;
+       };
 
        int read_retries;
 
@@ -840,4 +918,29 @@ static inline bool nand_is_slc(struct nand_chip *chip)
 {
        return chip->bits_per_cell == 1;
 }
+
+/**
+ * Check if the opcode's address should be sent only on the lower 8 bits
+ * @command: opcode to check
+ */
+static inline int nand_opcode_8bits(unsigned int command)
+{
+       switch (command) {
+       case NAND_CMD_READID:
+       case NAND_CMD_PARAM:
+       case NAND_CMD_GET_FEATURES:
+       case NAND_CMD_SET_FEATURES:
+               return 1;
+       default:
+               break;
+       }
+       return 0;
+}
+
+/* return the supported JEDEC features. */
+static inline int jedec_feature(struct nand_chip *chip)
+{
+       return chip->jedec_version ? le16_to_cpu(chip->jedec_params.features)
+               : 0;
+}
 #endif /* __LINUX_MTD_NAND_H */
index 5a09a48..c26d0ec 100644 (file)
@@ -63,6 +63,7 @@ enum {
        NETIF_F_HW_VLAN_STAG_RX_BIT,    /* Receive VLAN STAG HW acceleration */
        NETIF_F_HW_VLAN_STAG_FILTER_BIT,/* Receive filtering on VLAN STAGs */
        NETIF_F_HW_L2FW_DOFFLOAD_BIT,   /* Allow L2 Forwarding in Hardware */
+       NETIF_F_BUSY_POLL_BIT,          /* Busy poll */
 
        /*
         * Add your fresh new feature above and remember to update
@@ -118,6 +119,7 @@ enum {
 #define NETIF_F_HW_VLAN_STAG_RX        __NETIF_F(HW_VLAN_STAG_RX)
 #define NETIF_F_HW_VLAN_STAG_TX        __NETIF_F(HW_VLAN_STAG_TX)
 #define NETIF_F_HW_L2FW_DOFFLOAD       __NETIF_F(HW_L2FW_DOFFLOAD)
+#define NETIF_F_BUSY_POLL      __NETIF_F(BUSY_POLL)
 
 /* Features valid for ethtool to change */
 /* = all defined minus driver/device-class-related */
index 775cc95..7ed3a3a 100644 (file)
@@ -519,11 +519,18 @@ enum netdev_queue_state_t {
        __QUEUE_STATE_DRV_XOFF,
        __QUEUE_STATE_STACK_XOFF,
        __QUEUE_STATE_FROZEN,
-#define QUEUE_STATE_ANY_XOFF ((1 << __QUEUE_STATE_DRV_XOFF)            | \
-                             (1 << __QUEUE_STATE_STACK_XOFF))
-#define QUEUE_STATE_ANY_XOFF_OR_FROZEN (QUEUE_STATE_ANY_XOFF           | \
-                                       (1 << __QUEUE_STATE_FROZEN))
 };
+
+#define QUEUE_STATE_DRV_XOFF   (1 << __QUEUE_STATE_DRV_XOFF)
+#define QUEUE_STATE_STACK_XOFF (1 << __QUEUE_STATE_STACK_XOFF)
+#define QUEUE_STATE_FROZEN     (1 << __QUEUE_STATE_FROZEN)
+
+#define QUEUE_STATE_ANY_XOFF   (QUEUE_STATE_DRV_XOFF | QUEUE_STATE_STACK_XOFF)
+#define QUEUE_STATE_ANY_XOFF_OR_FROZEN (QUEUE_STATE_ANY_XOFF | \
+                                       QUEUE_STATE_FROZEN)
+#define QUEUE_STATE_DRV_XOFF_OR_FROZEN (QUEUE_STATE_DRV_XOFF | \
+                                       QUEUE_STATE_FROZEN)
+
 /*
  * __QUEUE_STATE_DRV_XOFF is used by drivers to stop the transmit queue.  The
  * netif_tx_* functions below are used to manipulate this flag.  The
@@ -2252,11 +2259,18 @@ static inline bool netif_xmit_stopped(const struct netdev_queue *dev_queue)
        return dev_queue->state & QUEUE_STATE_ANY_XOFF;
 }
 
-static inline bool netif_xmit_frozen_or_stopped(const struct netdev_queue *dev_queue)
+static inline bool
+netif_xmit_frozen_or_stopped(const struct netdev_queue *dev_queue)
 {
        return dev_queue->state & QUEUE_STATE_ANY_XOFF_OR_FROZEN;
 }
 
+static inline bool
+netif_xmit_frozen_or_drv_stopped(const struct netdev_queue *dev_queue)
+{
+       return dev_queue->state & QUEUE_STATE_DRV_XOFF_OR_FROZEN;
+}
+
 static inline void netdev_tx_sent_queue(struct netdev_queue *dev_queue,
                                        unsigned int bytes)
 {
index 0ae5807..fa6918b 100644 (file)
@@ -92,6 +92,7 @@ struct nfs_open_context {
 };
 
 struct nfs_open_dir_context {
+       struct list_head list;
        struct rpc_cred *cred;
        unsigned long attr_gencount;
        __u64 dir_cookie;
@@ -510,7 +511,6 @@ extern void nfs_complete_unlink(struct dentry *dentry, struct inode *);
 extern void nfs_wait_on_sillyrename(struct dentry *dentry);
 extern void nfs_block_sillyrename(struct dentry *dentry);
 extern void nfs_unblock_sillyrename(struct dentry *dentry);
-extern int  nfs_sillyrename(struct inode *dir, struct dentry *dentry);
 
 /*
  * linux/fs/nfs/write.c
index 5624e4e..6fb5b23 100644 (file)
@@ -1402,6 +1402,7 @@ struct nfs_renamedata {
        struct inode            *new_dir;
        struct dentry           *new_dentry;
        struct nfs_fattr        new_fattr;
+       void (*complete)(struct rpc_task *, struct nfs_renamedata *);
 };
 
 struct nfs_access_entry;
@@ -1444,8 +1445,6 @@ struct nfs_rpc_ops {
        void    (*unlink_setup)  (struct rpc_message *, struct inode *dir);
        void    (*unlink_rpc_prepare) (struct rpc_task *, struct nfs_unlinkdata *);
        int     (*unlink_done) (struct rpc_task *, struct inode *);
-       int     (*rename)  (struct inode *, struct qstr *,
-                           struct inode *, struct qstr *);
        void    (*rename_setup)  (struct rpc_message *msg, struct inode *dir);
        void    (*rename_rpc_prepare)(struct rpc_task *task, struct nfs_renamedata *);
        int     (*rename_done) (struct rpc_task *task, struct inode *old_dir, struct inode *new_dir);
index cb32d9c..e266caa 100644 (file)
@@ -13,6 +13,8 @@
 
 #include <linux/of.h>
 int of_get_nand_ecc_mode(struct device_node *np);
+int of_get_nand_ecc_step_size(struct device_node *np);
+int of_get_nand_ecc_strength(struct device_node *np);
 int of_get_nand_bus_width(struct device_node *np);
 bool of_get_nand_on_flash_bbt(struct device_node *np);
 
@@ -23,6 +25,16 @@ static inline int of_get_nand_ecc_mode(struct device_node *np)
        return -ENOSYS;
 }
 
+static inline int of_get_nand_ecc_step_size(struct device_node *np)
+{
+       return -ENOSYS;
+}
+
+static inline int of_get_nand_ecc_strength(struct device_node *np)
+{
+       return -ENOSYS;
+}
+
 static inline int of_get_nand_bus_width(struct device_node *np)
 {
        return -ENOSYS;
index e3817d2..e7a0b95 100644 (file)
@@ -173,6 +173,12 @@ extern phys_addr_t per_cpu_ptr_to_phys(void *addr);
 
 extern void __bad_size_call_parameter(void);
 
+#ifdef CONFIG_DEBUG_PREEMPT
+extern void __this_cpu_preempt_check(const char *op);
+#else
+static inline void __this_cpu_preempt_check(const char *op) { }
+#endif
+
 #define __pcpu_size_call_return(stem, variable)                                \
 ({     typeof(variable) pscr_ret__;                                    \
        __verify_pcpu_ptr(&(variable));                                 \
@@ -243,6 +249,8 @@ do {                                                                        \
 } while (0)
 
 /*
+ * this_cpu operations (C) 2008-2013 Christoph Lameter <cl@linux.com>
+ *
  * Optimized manipulation for memory allocated through the per cpu
  * allocator or for addresses of per cpu variables.
  *
@@ -296,7 +304,7 @@ do {                                                                        \
 do {                                                                   \
        unsigned long flags;                                            \
        raw_local_irq_save(flags);                                      \
-       *__this_cpu_ptr(&(pcp)) op val;                                 \
+       *raw_cpu_ptr(&(pcp)) op val;                                    \
        raw_local_irq_restore(flags);                                   \
 } while (0)
 
@@ -381,8 +389,8 @@ do {                                                                        \
        typeof(pcp) ret__;                                              \
        unsigned long flags;                                            \
        raw_local_irq_save(flags);                                      \
-       __this_cpu_add(pcp, val);                                       \
-       ret__ = __this_cpu_read(pcp);                                   \
+       raw_cpu_add(pcp, val);                                  \
+       ret__ = raw_cpu_read(pcp);                                      \
        raw_local_irq_restore(flags);                                   \
        ret__;                                                          \
 })
@@ -411,8 +419,8 @@ do {                                                                        \
 ({     typeof(pcp) ret__;                                              \
        unsigned long flags;                                            \
        raw_local_irq_save(flags);                                      \
-       ret__ = __this_cpu_read(pcp);                                   \
-       __this_cpu_write(pcp, nval);                                    \
+       ret__ = raw_cpu_read(pcp);                                      \
+       raw_cpu_write(pcp, nval);                                       \
        raw_local_irq_restore(flags);                                   \
        ret__;                                                          \
 })
@@ -439,9 +447,9 @@ do {                                                                        \
        typeof(pcp) ret__;                                              \
        unsigned long flags;                                            \
        raw_local_irq_save(flags);                                      \
-       ret__ = __this_cpu_read(pcp);                                   \
+       ret__ = raw_cpu_read(pcp);                                      \
        if (ret__ == (oval))                                            \
-               __this_cpu_write(pcp, nval);                            \
+               raw_cpu_write(pcp, nval);                               \
        raw_local_irq_restore(flags);                                   \
        ret__;                                                          \
 })
@@ -476,7 +484,7 @@ do {                                                                        \
        int ret__;                                                      \
        unsigned long flags;                                            \
        raw_local_irq_save(flags);                                      \
-       ret__ = __this_cpu_generic_cmpxchg_double(pcp1, pcp2,           \
+       ret__ = raw_cpu_generic_cmpxchg_double(pcp1, pcp2,              \
                        oval1, oval2, nval1, nval2);                    \
        raw_local_irq_restore(flags);                                   \
        ret__;                                                          \
@@ -504,12 +512,8 @@ do {                                                                       \
 #endif
 
 /*
- * Generic percpu operations for context that are safe from preemption/interrupts.
- * Either we do not care about races or the caller has the
- * responsibility of handling preemption/interrupt issues. Arch code can still
- * override these instructions since the arch per cpu code may be more
- * efficient and may actually get race freeness for free (that is the
- * case for x86 for example).
+ * Generic percpu operations for contexts where we do not want to do
+ * any checks for preemptiosn.
  *
  * If there is no other protection through preempt disable and/or
  * disabling interupts then one of these RMW operations can show unexpected
@@ -517,211 +521,285 @@ do {                                                                    \
  * or an interrupt occurred and the same percpu variable was modified from
  * the interrupt context.
  */
-#ifndef __this_cpu_read
-# ifndef __this_cpu_read_1
-#  define __this_cpu_read_1(pcp)       (*__this_cpu_ptr(&(pcp)))
+#ifndef raw_cpu_read
+# ifndef raw_cpu_read_1
+#  define raw_cpu_read_1(pcp)  (*raw_cpu_ptr(&(pcp)))
 # endif
-# ifndef __this_cpu_read_2
-#  define __this_cpu_read_2(pcp)       (*__this_cpu_ptr(&(pcp)))
+# ifndef raw_cpu_read_2
+#  define raw_cpu_read_2(pcp)  (*raw_cpu_ptr(&(pcp)))
 # endif
-# ifndef __this_cpu_read_4
-#  define __this_cpu_read_4(pcp)       (*__this_cpu_ptr(&(pcp)))
+# ifndef raw_cpu_read_4
+#  define raw_cpu_read_4(pcp)  (*raw_cpu_ptr(&(pcp)))
 # endif
-# ifndef __this_cpu_read_8
-#  define __this_cpu_read_8(pcp)       (*__this_cpu_ptr(&(pcp)))
+# ifndef raw_cpu_read_8
+#  define raw_cpu_read_8(pcp)  (*raw_cpu_ptr(&(pcp)))
 # endif
-# define __this_cpu_read(pcp)  __pcpu_size_call_return(__this_cpu_read_, (pcp))
+# define raw_cpu_read(pcp)     __pcpu_size_call_return(raw_cpu_read_, (pcp))
 #endif
 
-#define __this_cpu_generic_to_op(pcp, val, op)                         \
+#define raw_cpu_generic_to_op(pcp, val, op)                            \
 do {                                                                   \
-       *__this_cpu_ptr(&(pcp)) op val;                                 \
+       *raw_cpu_ptr(&(pcp)) op val;                                    \
 } while (0)
 
-#ifndef __this_cpu_write
-# ifndef __this_cpu_write_1
-#  define __this_cpu_write_1(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+
+#ifndef raw_cpu_write
+# ifndef raw_cpu_write_1
+#  define raw_cpu_write_1(pcp, val)    raw_cpu_generic_to_op((pcp), (val), =)
 # endif
-# ifndef __this_cpu_write_2
-#  define __this_cpu_write_2(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# ifndef raw_cpu_write_2
+#  define raw_cpu_write_2(pcp, val)    raw_cpu_generic_to_op((pcp), (val), =)
 # endif
-# ifndef __this_cpu_write_4
-#  define __this_cpu_write_4(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# ifndef raw_cpu_write_4
+#  define raw_cpu_write_4(pcp, val)    raw_cpu_generic_to_op((pcp), (val), =)
 # endif
-# ifndef __this_cpu_write_8
-#  define __this_cpu_write_8(pcp, val) __this_cpu_generic_to_op((pcp), (val), =)
+# ifndef raw_cpu_write_8
+#  define raw_cpu_write_8(pcp, val)    raw_cpu_generic_to_op((pcp), (val), =)
 # endif
-# define __this_cpu_write(pcp, val)    __pcpu_size_call(__this_cpu_write_, (pcp), (val))
+# define raw_cpu_write(pcp, val)       __pcpu_size_call(raw_cpu_write_, (pcp), (val))
 #endif
 
-#ifndef __this_cpu_add
-# ifndef __this_cpu_add_1
-#  define __this_cpu_add_1(pcp, val)   __this_cpu_generic_to_op((pcp), (val), +=)
+#ifndef raw_cpu_add
+# ifndef raw_cpu_add_1
+#  define raw_cpu_add_1(pcp, val)      raw_cpu_generic_to_op((pcp), (val), +=)
 # endif
-# ifndef __this_cpu_add_2
-#  define __this_cpu_add_2(pcp, val)   __this_cpu_generic_to_op((pcp), (val), +=)
+# ifndef raw_cpu_add_2
+#  define raw_cpu_add_2(pcp, val)      raw_cpu_generic_to_op((pcp), (val), +=)
 # endif
-# ifndef __this_cpu_add_4
-#  define __this_cpu_add_4(pcp, val)   __this_cpu_generic_to_op((pcp), (val), +=)
+# ifndef raw_cpu_add_4
+#  define raw_cpu_add_4(pcp, val)      raw_cpu_generic_to_op((pcp), (val), +=)
 # endif
-# ifndef __this_cpu_add_8
-#  define __this_cpu_add_8(pcp, val)   __this_cpu_generic_to_op((pcp), (val), +=)
+# ifndef raw_cpu_add_8
+#  define raw_cpu_add_8(pcp, val)      raw_cpu_generic_to_op((pcp), (val), +=)
 # endif
-# define __this_cpu_add(pcp, val)      __pcpu_size_call(__this_cpu_add_, (pcp), (val))
+# define raw_cpu_add(pcp, val) __pcpu_size_call(raw_cpu_add_, (pcp), (val))
 #endif
 
-#ifndef __this_cpu_sub
-# define __this_cpu_sub(pcp, val)      __this_cpu_add((pcp), -(typeof(pcp))(val))
+#ifndef raw_cpu_sub
+# define raw_cpu_sub(pcp, val) raw_cpu_add((pcp), -(val))
 #endif
 
-#ifndef __this_cpu_inc
-# define __this_cpu_inc(pcp)           __this_cpu_add((pcp), 1)
+#ifndef raw_cpu_inc
+# define raw_cpu_inc(pcp)              raw_cpu_add((pcp), 1)
 #endif
 
-#ifndef __this_cpu_dec
-# define __this_cpu_dec(pcp)           __this_cpu_sub((pcp), 1)
+#ifndef raw_cpu_dec
+# define raw_cpu_dec(pcp)              raw_cpu_sub((pcp), 1)
 #endif
 
-#ifndef __this_cpu_and
-# ifndef __this_cpu_and_1
-#  define __this_cpu_and_1(pcp, val)   __this_cpu_generic_to_op((pcp), (val), &=)
+#ifndef raw_cpu_and
+# ifndef raw_cpu_and_1
+#  define raw_cpu_and_1(pcp, val)      raw_cpu_generic_to_op((pcp), (val), &=)
 # endif
-# ifndef __this_cpu_and_2
-#  define __this_cpu_and_2(pcp, val)   __this_cpu_generic_to_op((pcp), (val), &=)
+# ifndef raw_cpu_and_2
+#  define raw_cpu_and_2(pcp, val)      raw_cpu_generic_to_op((pcp), (val), &=)
 # endif
-# ifndef __this_cpu_and_4
-#  define __this_cpu_and_4(pcp, val)   __this_cpu_generic_to_op((pcp), (val), &=)
+# ifndef raw_cpu_and_4
+#  define raw_cpu_and_4(pcp, val)      raw_cpu_generic_to_op((pcp), (val), &=)
 # endif
-# ifndef __this_cpu_and_8
-#  define __this_cpu_and_8(pcp, val)   __this_cpu_generic_to_op((pcp), (val), &=)
+# ifndef raw_cpu_and_8
+#  define raw_cpu_and_8(pcp, val)      raw_cpu_generic_to_op((pcp), (val), &=)
 # endif
-# define __this_cpu_and(pcp, val)      __pcpu_size_call(__this_cpu_and_, (pcp), (val))
+# define raw_cpu_and(pcp, val) __pcpu_size_call(raw_cpu_and_, (pcp), (val))
 #endif
 
-#ifndef __this_cpu_or
-# ifndef __this_cpu_or_1
-#  define __this_cpu_or_1(pcp, val)    __this_cpu_generic_to_op((pcp), (val), |=)
+#ifndef raw_cpu_or
+# ifndef raw_cpu_or_1
+#  define raw_cpu_or_1(pcp, val)       raw_cpu_generic_to_op((pcp), (val), |=)
 # endif
-# ifndef __this_cpu_or_2
-#  define __this_cpu_or_2(pcp, val)    __this_cpu_generic_to_op((pcp), (val), |=)
+# ifndef raw_cpu_or_2
+#  define raw_cpu_or_2(pcp, val)       raw_cpu_generic_to_op((pcp), (val), |=)
 # endif
-# ifndef __this_cpu_or_4
-#  define __this_cpu_or_4(pcp, val)    __this_cpu_generic_to_op((pcp), (val), |=)
+# ifndef raw_cpu_or_4
+#  define raw_cpu_or_4(pcp, val)       raw_cpu_generic_to_op((pcp), (val), |=)
 # endif
-# ifndef __this_cpu_or_8
-#  define __this_cpu_or_8(pcp, val)    __this_cpu_generic_to_op((pcp), (val), |=)
+# ifndef raw_cpu_or_8
+#  define raw_cpu_or_8(pcp, val)       raw_cpu_generic_to_op((pcp), (val), |=)
 # endif
-# define __this_cpu_or(pcp, val)       __pcpu_size_call(__this_cpu_or_, (pcp), (val))
+# define raw_cpu_or(pcp, val)  __pcpu_size_call(raw_cpu_or_, (pcp), (val))
 #endif
 
-#define __this_cpu_generic_add_return(pcp, val)                                \
+#define raw_cpu_generic_add_return(pcp, val)                           \
 ({                                                                     \
-       __this_cpu_add(pcp, val);                                       \
-       __this_cpu_read(pcp);                                           \
+       raw_cpu_add(pcp, val);                                          \
+       raw_cpu_read(pcp);                                              \
 })
 
-#ifndef __this_cpu_add_return
-# ifndef __this_cpu_add_return_1
-#  define __this_cpu_add_return_1(pcp, val)    __this_cpu_generic_add_return(pcp, val)
+#ifndef raw_cpu_add_return
+# ifndef raw_cpu_add_return_1
+#  define raw_cpu_add_return_1(pcp, val)       raw_cpu_generic_add_return(pcp, val)
 # endif
-# ifndef __this_cpu_add_return_2
-#  define __this_cpu_add_return_2(pcp, val)    __this_cpu_generic_add_return(pcp, val)
+# ifndef raw_cpu_add_return_2
+#  define raw_cpu_add_return_2(pcp, val)       raw_cpu_generic_add_return(pcp, val)
 # endif
-# ifndef __this_cpu_add_return_4
-#  define __this_cpu_add_return_4(pcp, val)    __this_cpu_generic_add_return(pcp, val)
+# ifndef raw_cpu_add_return_4
+#  define raw_cpu_add_return_4(pcp, val)       raw_cpu_generic_add_return(pcp, val)
 # endif
-# ifndef __this_cpu_add_return_8
-#  define __this_cpu_add_return_8(pcp, val)    __this_cpu_generic_add_return(pcp, val)
+# ifndef raw_cpu_add_return_8
+#  define raw_cpu_add_return_8(pcp, val)       raw_cpu_generic_add_return(pcp, val)
 # endif
-# define __this_cpu_add_return(pcp, val)       \
-       __pcpu_size_call_return2(__this_cpu_add_return_, pcp, val)
+# define raw_cpu_add_return(pcp, val)  \
+       __pcpu_size_call_return2(raw_add_return_, pcp, val)
 #endif
 
-#define __this_cpu_sub_return(pcp, val)        __this_cpu_add_return(pcp, -(typeof(pcp))(val))
-#define __this_cpu_inc_return(pcp)     __this_cpu_add_return(pcp, 1)
-#define __this_cpu_dec_return(pcp)     __this_cpu_add_return(pcp, -1)
+#define raw_cpu_sub_return(pcp, val)   raw_cpu_add_return(pcp, -(typeof(pcp))(val))
+#define raw_cpu_inc_return(pcp)        raw_cpu_add_return(pcp, 1)
+#define raw_cpu_dec_return(pcp)        raw_cpu_add_return(pcp, -1)
 
-#define __this_cpu_generic_xchg(pcp, nval)                             \
+#define raw_cpu_generic_xchg(pcp, nval)                                        \
 ({     typeof(pcp) ret__;                                              \
-       ret__ = __this_cpu_read(pcp);                                   \
-       __this_cpu_write(pcp, nval);                                    \
+       ret__ = raw_cpu_read(pcp);                                      \
+       raw_cpu_write(pcp, nval);                                       \
        ret__;                                                          \
 })
 
-#ifndef __this_cpu_xchg
-# ifndef __this_cpu_xchg_1
-#  define __this_cpu_xchg_1(pcp, nval) __this_cpu_generic_xchg(pcp, nval)
+#ifndef raw_cpu_xchg
+# ifndef raw_cpu_xchg_1
+#  define raw_cpu_xchg_1(pcp, nval)    raw_cpu_generic_xchg(pcp, nval)
 # endif
-# ifndef __this_cpu_xchg_2
-#  define __this_cpu_xchg_2(pcp, nval) __this_cpu_generic_xchg(pcp, nval)
+# ifndef raw_cpu_xchg_2
+#  define raw_cpu_xchg_2(pcp, nval)    raw_cpu_generic_xchg(pcp, nval)
 # endif
-# ifndef __this_cpu_xchg_4
-#  define __this_cpu_xchg_4(pcp, nval) __this_cpu_generic_xchg(pcp, nval)
+# ifndef raw_cpu_xchg_4
+#  define raw_cpu_xchg_4(pcp, nval)    raw_cpu_generic_xchg(pcp, nval)
 # endif
-# ifndef __this_cpu_xchg_8
-#  define __this_cpu_xchg_8(pcp, nval) __this_cpu_generic_xchg(pcp, nval)
+# ifndef raw_cpu_xchg_8
+#  define raw_cpu_xchg_8(pcp, nval)    raw_cpu_generic_xchg(pcp, nval)
 # endif
-# define __this_cpu_xchg(pcp, nval)    \
-       __pcpu_size_call_return2(__this_cpu_xchg_, (pcp), nval)
+# define raw_cpu_xchg(pcp, nval)       \
+       __pcpu_size_call_return2(raw_cpu_xchg_, (pcp), nval)
 #endif
 
-#define __this_cpu_generic_cmpxchg(pcp, oval, nval)                    \
+#define raw_cpu_generic_cmpxchg(pcp, oval, nval)                       \
 ({                                                                     \
        typeof(pcp) ret__;                                              \
-       ret__ = __this_cpu_read(pcp);                                   \
+       ret__ = raw_cpu_read(pcp);                                      \
        if (ret__ == (oval))                                            \
-               __this_cpu_write(pcp, nval);                            \
+               raw_cpu_write(pcp, nval);                               \
        ret__;                                                          \
 })
 
-#ifndef __this_cpu_cmpxchg
-# ifndef __this_cpu_cmpxchg_1
-#  define __this_cpu_cmpxchg_1(pcp, oval, nval)        __this_cpu_generic_cmpxchg(pcp, oval, nval)
+#ifndef raw_cpu_cmpxchg
+# ifndef raw_cpu_cmpxchg_1
+#  define raw_cpu_cmpxchg_1(pcp, oval, nval)   raw_cpu_generic_cmpxchg(pcp, oval, nval)
 # endif
-# ifndef __this_cpu_cmpxchg_2
-#  define __this_cpu_cmpxchg_2(pcp, oval, nval)        __this_cpu_generic_cmpxchg(pcp, oval, nval)
+# ifndef raw_cpu_cmpxchg_2
+#  define raw_cpu_cmpxchg_2(pcp, oval, nval)   raw_cpu_generic_cmpxchg(pcp, oval, nval)
 # endif
-# ifndef __this_cpu_cmpxchg_4
-#  define __this_cpu_cmpxchg_4(pcp, oval, nval)        __this_cpu_generic_cmpxchg(pcp, oval, nval)
+# ifndef raw_cpu_cmpxchg_4
+#  define raw_cpu_cmpxchg_4(pcp, oval, nval)   raw_cpu_generic_cmpxchg(pcp, oval, nval)
 # endif
-# ifndef __this_cpu_cmpxchg_8
-#  define __this_cpu_cmpxchg_8(pcp, oval, nval)        __this_cpu_generic_cmpxchg(pcp, oval, nval)
+# ifndef raw_cpu_cmpxchg_8
+#  define raw_cpu_cmpxchg_8(pcp, oval, nval)   raw_cpu_generic_cmpxchg(pcp, oval, nval)
 # endif
-# define __this_cpu_cmpxchg(pcp, oval, nval)   \
-       __pcpu_size_call_return2(__this_cpu_cmpxchg_, pcp, oval, nval)
+# define raw_cpu_cmpxchg(pcp, oval, nval)      \
+       __pcpu_size_call_return2(raw_cpu_cmpxchg_, pcp, oval, nval)
 #endif
 
-#define __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)      \
+#define raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) \
 ({                                                                     \
        int __ret = 0;                                                  \
-       if (__this_cpu_read(pcp1) == (oval1) &&                         \
-                        __this_cpu_read(pcp2)  == (oval2)) {           \
-               __this_cpu_write(pcp1, (nval1));                        \
-               __this_cpu_write(pcp2, (nval2));                        \
+       if (raw_cpu_read(pcp1) == (oval1) &&                            \
+                        raw_cpu_read(pcp2)  == (oval2)) {              \
+               raw_cpu_write(pcp1, (nval1));                           \
+               raw_cpu_write(pcp2, (nval2));                           \
                __ret = 1;                                              \
        }                                                               \
        (__ret);                                                        \
 })
 
-#ifndef __this_cpu_cmpxchg_double
-# ifndef __this_cpu_cmpxchg_double_1
-#  define __this_cpu_cmpxchg_double_1(pcp1, pcp2, oval1, oval2, nval1, nval2)  \
-       __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+#ifndef raw_cpu_cmpxchg_double
+# ifndef raw_cpu_cmpxchg_double_1
+#  define raw_cpu_cmpxchg_double_1(pcp1, pcp2, oval1, oval2, nval1, nval2)     \
+       raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
 # endif
-# ifndef __this_cpu_cmpxchg_double_2
-#  define __this_cpu_cmpxchg_double_2(pcp1, pcp2, oval1, oval2, nval1, nval2)  \
-       __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+# ifndef raw_cpu_cmpxchg_double_2
+#  define raw_cpu_cmpxchg_double_2(pcp1, pcp2, oval1, oval2, nval1, nval2)     \
+       raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
 # endif
-# ifndef __this_cpu_cmpxchg_double_4
-#  define __this_cpu_cmpxchg_double_4(pcp1, pcp2, oval1, oval2, nval1, nval2)  \
-       __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+# ifndef raw_cpu_cmpxchg_double_4
+#  define raw_cpu_cmpxchg_double_4(pcp1, pcp2, oval1, oval2, nval1, nval2)     \
+       raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
 # endif
-# ifndef __this_cpu_cmpxchg_double_8
-#  define __this_cpu_cmpxchg_double_8(pcp1, pcp2, oval1, oval2, nval1, nval2)  \
-       __this_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
+# ifndef raw_cpu_cmpxchg_double_8
+#  define raw_cpu_cmpxchg_double_8(pcp1, pcp2, oval1, oval2, nval1, nval2)     \
+       raw_cpu_generic_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)
 # endif
+# define raw_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)        \
+       __pcpu_double_call_return_bool(raw_cpu_cmpxchg_double_, (pcp1), (pcp2), (oval1), (oval2), (nval1), (nval2))
+#endif
+
+/*
+ * Generic percpu operations for context that are safe from preemption/interrupts.
+ */
+#ifndef __this_cpu_read
+# define __this_cpu_read(pcp) \
+       (__this_cpu_preempt_check("read"),__pcpu_size_call_return(raw_cpu_read_, (pcp)))
+#endif
+
+#ifndef __this_cpu_write
+# define __this_cpu_write(pcp, val)                                    \
+do { __this_cpu_preempt_check("write");                                        \
+     __pcpu_size_call(raw_cpu_write_, (pcp), (val));                   \
+} while (0)
+#endif
+
+#ifndef __this_cpu_add
+# define __this_cpu_add(pcp, val)                                       \
+do { __this_cpu_preempt_check("add");                                  \
+       __pcpu_size_call(raw_cpu_add_, (pcp), (val));                   \
+} while (0)
+#endif
+
+#ifndef __this_cpu_sub
+# define __this_cpu_sub(pcp, val)      __this_cpu_add((pcp), -(typeof(pcp))(val))
+#endif
+
+#ifndef __this_cpu_inc
+# define __this_cpu_inc(pcp)           __this_cpu_add((pcp), 1)
+#endif
+
+#ifndef __this_cpu_dec
+# define __this_cpu_dec(pcp)           __this_cpu_sub((pcp), 1)
+#endif
+
+#ifndef __this_cpu_and
+# define __this_cpu_and(pcp, val)                                      \
+do { __this_cpu_preempt_check("and");                                  \
+       __pcpu_size_call(raw_cpu_and_, (pcp), (val));                   \
+} while (0)
+
+#endif
+
+#ifndef __this_cpu_or
+# define __this_cpu_or(pcp, val)                                       \
+do { __this_cpu_preempt_check("or");                                   \
+       __pcpu_size_call(raw_cpu_or_, (pcp), (val));                    \
+} while (0)
+#endif
+
+#ifndef __this_cpu_add_return
+# define __this_cpu_add_return(pcp, val)       \
+       (__this_cpu_preempt_check("add_return"),__pcpu_size_call_return2(raw_cpu_add_return_, pcp, val))
+#endif
+
+#define __this_cpu_sub_return(pcp, val)        __this_cpu_add_return(pcp, -(typeof(pcp))(val))
+#define __this_cpu_inc_return(pcp)     __this_cpu_add_return(pcp, 1)
+#define __this_cpu_dec_return(pcp)     __this_cpu_add_return(pcp, -1)
+
+#ifndef __this_cpu_xchg
+# define __this_cpu_xchg(pcp, nval)    \
+       (__this_cpu_preempt_check("xchg"),__pcpu_size_call_return2(raw_cpu_xchg_, (pcp), nval))
+#endif
+
+#ifndef __this_cpu_cmpxchg
+# define __this_cpu_cmpxchg(pcp, oval, nval)   \
+       (__this_cpu_preempt_check("cmpxchg"),__pcpu_size_call_return2(raw_cpu_cmpxchg_, pcp, oval, nval))
+#endif
+
+#ifndef __this_cpu_cmpxchg_double
 # define __this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2)     \
-       __pcpu_double_call_return_bool(__this_cpu_cmpxchg_double_, (pcp1), (pcp2), (oval1), (oval2), (nval1), (nval2))
+       (__this_cpu_preempt_check("cmpxchg_double"),__pcpu_double_call_return_bool(raw_cpu_cmpxchg_double_, (pcp1), (pcp2), (oval1), (oval2), (nval1), (nval2)))
 #endif
 
 #endif /* __LINUX_PERCPU_H */
index e56b07f..3356abc 100644 (file)
@@ -835,6 +835,8 @@ do {                                                                        \
                { .notifier_call = fn, .priority = CPU_PRI_PERF };      \
        unsigned long cpu = smp_processor_id();                         \
        unsigned long flags;                                            \
+                                                                       \
+       cpu_notifier_register_begin();                                  \
        fn(&fn##_nb, (unsigned long)CPU_UP_PREPARE,                     \
                (void *)(unsigned long)cpu);                            \
        local_irq_save(flags);                                          \
@@ -843,9 +845,21 @@ do {                                                                       \
        local_irq_restore(flags);                                       \
        fn(&fn##_nb, (unsigned long)CPU_ONLINE,                         \
                (void *)(unsigned long)cpu);                            \
-       register_cpu_notifier(&fn##_nb);                                \
+       __register_cpu_notifier(&fn##_nb);                              \
+       cpu_notifier_register_done();                                   \
 } while (0)
 
+/*
+ * Bare-bones version of perf_cpu_notifier(), which doesn't invoke the
+ * callback for already online CPUs.
+ */
+#define __perf_cpu_notifier(fn)                                                \
+do {                                                                   \
+       static struct notifier_block fn##_nb =                          \
+               { .notifier_call = fn, .priority = CPU_PRI_PERF };      \
+                                                                       \
+       __register_cpu_notifier(&fn##_nb);                              \
+} while (0)
 
 struct perf_pmu_events_attr {
        struct device_attribute attr;
diff --git a/include/linux/platform_data/dma-rcar-audmapp.h b/include/linux/platform_data/dma-rcar-audmapp.h
new file mode 100644 (file)
index 0000000..471fffe
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * This is for Renesas R-Car Audio-DMAC-peri-peri.
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ * Copyright (C) 2014 Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
+ *
+ * This file is based on the include/linux/sh_dma.h
+ *
+ * Header for the new SH dmaengine driver
+ *
+ * Copyright (C) 2010 Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * 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 SH_AUDMAPP_H
+#define SH_AUDMAPP_H
+
+#include <linux/dmaengine.h>
+
+struct audmapp_slave_config {
+       int             slave_id;
+       dma_addr_t      src;
+       dma_addr_t      dst;
+       u32             chcr;
+};
+
+struct audmapp_pdata {
+       struct audmapp_slave_config *slave;
+       int slave_num;
+};
+
+#endif /* SH_AUDMAPP_H */
index bf0a83b..4edb406 100644 (file)
@@ -26,13 +26,6 @@ enum bch_ecc {
 /* ELM support 8 error syndrome process */
 #define ERROR_VECTOR_MAX               8
 
-#define BCH8_ECC_OOB_BYTES             13
-#define BCH4_ECC_OOB_BYTES             7
-/* RBL requires 14 byte even though BCH8 uses only 13 byte */
-#define BCH8_SIZE                      (BCH8_ECC_OOB_BYTES + 1)
-/* Uses 1 extra byte to handle erased pages */
-#define BCH4_SIZE                      (BCH4_ECC_OOB_BYTES + 1)
-
 /**
  * struct elm_errorvec - error vector for elm
  * @error_reported:            set true for vectors error is reported
@@ -50,5 +43,6 @@ struct elm_errorvec {
 
 void elm_decode_bch_error_page(struct device *dev, u8 *ecc_calc,
                struct elm_errorvec *err_vec);
-int elm_config(struct device *dev, enum bch_ecc bch_type);
+int elm_config(struct device *dev, enum bch_ecc bch_type,
+       int ecc_steps, int ecc_step_size, int ecc_syndrome_size);
 #endif /* __ELM_H */
index 2a50048..05af66b 100644 (file)
@@ -1,5 +1,4 @@
-/* arch/arm/plat-s3c/include/plat/iic.h
- *
+/*
  * Copyright 2004-2009 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
@@ -10,8 +9,8 @@
  * published by the Free Software Foundation.
 */
 
-#ifndef __ASM_ARCH_IIC_H
-#define __ASM_ARCH_IIC_H __FILE__
+#ifndef __I2C_S3C2410_H
+#define __I2C_S3C2410_H __FILE__
 
 #define S3C_IICFLG_FILTER      (1<<0)  /* enable s3c2440 filter */
 
@@ -76,4 +75,4 @@ extern void s3c_i2c7_cfg_gpio(struct platform_device *dev);
 
 extern struct s3c2410_platform_i2c default_i2c_data;
 
-#endif /* __ASM_ARCH_IIC_H */
+#endif /* __I2C_S3C2410_H */
index d8a7672..441a6f2 100644 (file)
@@ -1,5 +1,4 @@
-/* arch/arm/mach-s3c2410/include/mach/leds-gpio.h
- *
+/*
  * Copyright (c) 2006 Simtec Electronics
  *     http://armlinux.simtec.co.uk/
  *     Ben Dooks <ben@simtec.co.uk>
@@ -11,8 +10,8 @@
  * published by the Free Software Foundation.
 */
 
-#ifndef __ASM_ARCH_LEDSGPIO_H
-#define __ASM_ARCH_LEDSGPIO_H "leds-gpio.h"
+#ifndef __LEDS_S3C24XX_H
+#define __LEDS_S3C24XX_H
 
 #define S3C24XX_LEDF_ACTLOW    (1<<0)          /* LED is on when GPIO low */
 #define S3C24XX_LEDF_TRISTATE  (1<<1)          /* tristate to turn off */
@@ -25,4 +24,4 @@ struct s3c24xx_led_platdata {
        char                    *def_trigger;
 };
 
-#endif /* __ASM_ARCH_LEDSGPIO_H */
+#endif /* __LEDS_S3C24XX_H */
index ffcd9e3..55aa873 100644 (file)
@@ -1,8 +1,5 @@
-/*
- *  arch/arm/include/asm/mach/mmc.h
- */
-#ifndef ASMARM_MACH_MMC_H
-#define ASMARM_MACH_MMC_H
+#ifndef __MMC_MSM_SDCC_H
+#define __MMC_MSM_SDCC_H
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/card.h>
index 1190efe..d02704c 100644 (file)
@@ -1,13 +1,11 @@
 /*
- * arch/arm/plat-orion/include/plat/mvsdio.h
- *
  * 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.
  */
 
-#ifndef __MACH_MVSDIO_H
-#define __MACH_MVSDIO_H
+#ifndef __MMC_MVSDIO_H
+#define __MMC_MVSDIO_H
 
 #include <linux/mbus.h>
 
index b64115f..36bb921 100644 (file)
@@ -1,5 +1,4 @@
-/* arch/arm/mach-s3c2410/include/mach/nand.h
- *
+/*
  * Copyright (c) 2004 Simtec Electronics
  *     Ben Dooks <ben@simtec.co.uk>
  *
@@ -10,6 +9,9 @@
  * published by the Free Software Foundation.
 */
 
+#ifndef __MTD_NAND_S3C2410_H
+#define __MTD_NAND_S3C2410_H
+
 /**
  * struct s3c2410_nand_set - define a set of one or more nand chips
  * @disable_ecc:       Entirely disable ECC - Dangerous
@@ -65,3 +67,5 @@ struct s3c2410_platform_nand {
  * it with the s3c_device_nand. This allows @nand to be __initdata.
 */
 extern void s3c_nand_set_platdata(struct s3c2410_platform_nand *nand);
+
+#endif /*__MTD_NAND_S3C2410_H */
index 201a697..56b7bc3 100644 (file)
@@ -104,15 +104,13 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent);
  *       units, e.g. numbers, bytes, Kbytes, etc
  *
  * returns 0 on success and <0 if the counter->usage will exceed the
- * counter->limit _locked call expects the counter->lock to be taken
+ * counter->limit
  *
  * charge_nofail works the same, except that it charges the resource
  * counter unconditionally, and returns < 0 if the after the current
  * charge we are over limit.
  */
 
-int __must_check res_counter_charge_locked(struct res_counter *counter,
-                                          unsigned long val, bool force);
 int __must_check res_counter_charge(struct res_counter *counter,
                unsigned long val, struct res_counter **limit_fail_at);
 int res_counter_charge_nofail(struct res_counter *counter,
@@ -125,12 +123,10 @@ int res_counter_charge_nofail(struct res_counter *counter,
  * @val: the amount of the resource
  *
  * these calls check for usage underflow and show a warning on the console
- * _locked call expects the counter->lock to be taken
  *
  * returns the total charges still present in @counter.
  */
 
-u64 res_counter_uncharge_locked(struct res_counter *counter, unsigned long val);
 u64 res_counter_uncharge(struct res_counter *counter, unsigned long val);
 
 u64 res_counter_uncharge_until(struct res_counter *counter,
index b71d573..6bda06f 100644 (file)
@@ -83,7 +83,7 @@
 #define RIO_CTAG_UDEVID        0x0001ffff /* Unique device identifier */
 
 extern struct bus_type rio_bus_type;
-extern struct device rio_bus;
+extern struct class rio_mport_class;
 
 struct rio_mport;
 struct rio_dev;
@@ -201,6 +201,7 @@ struct rio_dev {
 #define rio_dev_f(n) list_entry(n, struct rio_dev, net_list)
 #define        to_rio_dev(n) container_of(n, struct rio_dev, dev)
 #define sw_to_rio_dev(n) container_of(n, struct rio_dev, rswitch[0])
+#define        to_rio_mport(n) container_of(n, struct rio_mport, dev)
 
 /**
  * struct rio_msg - RIO message event
@@ -248,6 +249,7 @@ enum rio_phy_type {
  * @phy_type: RapidIO phy type
  * @phys_efptr: RIO port extended features pointer
  * @name: Port name string
+ * @dev: device structure associated with an mport
  * @priv: Master port private data
  * @dma: DMA device associated with mport
  * @nscan: RapidIO network enumeration/discovery operations
@@ -272,6 +274,7 @@ struct rio_mport {
        enum rio_phy_type phy_type;     /* RapidIO phy type */
        u32 phys_efptr;
        unsigned char name[RIO_MAX_MPORT_NAME];
+       struct device dev;
        void *priv;             /* Master port private data */
 #ifdef CONFIG_RAPIDIO_DMA_ENGINE
        struct dma_device       dma;
index 7cb07fd..075b305 100644 (file)
@@ -132,6 +132,10 @@ struct perf_event_context;
 struct blk_plug;
 struct filename;
 
+#define VMACACHE_BITS 2
+#define VMACACHE_SIZE (1U << VMACACHE_BITS)
+#define VMACACHE_MASK (VMACACHE_SIZE - 1)
+
 /*
  * List of flags we want to share for kernel threads,
  * if only because they are not used by them anyway.
@@ -206,8 +210,9 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq);
 #define __TASK_STOPPED         4
 #define __TASK_TRACED          8
 /* in tsk->exit_state */
-#define EXIT_ZOMBIE            16
-#define EXIT_DEAD              32
+#define EXIT_DEAD              16
+#define EXIT_ZOMBIE            32
+#define EXIT_TRACE             (EXIT_ZOMBIE | EXIT_DEAD)
 /* in tsk->state again */
 #define TASK_DEAD              64
 #define TASK_WAKEKILL          128
@@ -1235,6 +1240,9 @@ struct task_struct {
 #ifdef CONFIG_COMPAT_BRK
        unsigned brk_randomized:1;
 #endif
+       /* per-thread vma caching */
+       u32 vmacache_seqnum;
+       struct vm_area_struct *vmacache[VMACACHE_SIZE];
 #if defined(SPLIT_RSS_COUNTING)
        struct task_rss_stat    rss_stat;
 #endif
@@ -1844,7 +1852,6 @@ extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut,
 #define PF_SPREAD_SLAB 0x02000000      /* Spread some slab caches over cpuset */
 #define PF_NO_SETAFFINITY 0x04000000   /* Userland is not allowed to meddle with cpus_allowed */
 #define PF_MCE_EARLY    0x08000000      /* Early kill for mce process policy */
-#define PF_MEMPOLICY   0x10000000      /* Non-default NUMA mempolicy */
 #define PF_MUTEX_TESTER        0x20000000      /* Thread belongs to the rt mutex tester */
 #define PF_FREEZER_SKIP        0x40000000      /* Freezer should not count it as freezable */
 #define PF_SUSPEND_TASK 0x80000000      /* this thread called freeze_processes and should not be frozen */
@@ -2351,7 +2358,7 @@ extern long do_fork(unsigned long, unsigned long, unsigned long, int __user *, i
 struct task_struct *fork_idle(int);
 extern pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
-extern void set_task_comm(struct task_struct *tsk, char *from);
+extern void set_task_comm(struct task_struct *tsk, const char *from);
 extern char *get_task_comm(char *to, struct task_struct *tsk);
 
 #ifdef CONFIG_SMP
index b5b2df6..3dd389a 100644 (file)
@@ -115,9 +115,9 @@ int slab_is_available(void);
 struct kmem_cache *kmem_cache_create(const char *, size_t, size_t,
                        unsigned long,
                        void (*)(void *));
-struct kmem_cache *
-kmem_cache_create_memcg(struct mem_cgroup *, const char *, size_t, size_t,
-                       unsigned long, void (*)(void *), struct kmem_cache *);
+#ifdef CONFIG_MEMCG_KMEM
+void kmem_cache_create_memcg(struct mem_cgroup *, struct kmem_cache *);
+#endif
 void kmem_cache_destroy(struct kmem_cache *);
 int kmem_cache_shrink(struct kmem_cache *);
 void kmem_cache_free(struct kmem_cache *, void *);
index f56bfa9..f2f7398 100644 (file)
@@ -87,6 +87,9 @@ struct kmem_cache {
 #ifdef CONFIG_MEMCG_KMEM
        struct memcg_cache_params *memcg_params;
        int max_attr_size; /* for propagation, maximum size of a stored attr */
+#ifdef CONFIG_SYSFS
+       struct kset *memcg_kset;
+#endif
 #endif
 
 #ifdef CONFIG_NUMA
index bcbb642..087b08a 100644 (file)
 int ssbi_write(struct device *dev, u16 addr, const u8 *buf, int len);
 int ssbi_read(struct device *dev, u16 addr, u8 *buf, int len);
 
+static inline int
+ssbi_reg_read(void *context, unsigned int reg, unsigned int *val)
+{
+       int ret;
+       u8 v;
+
+       ret = ssbi_read(context, reg, &v, 1);
+       if (!ret)
+               *val = v;
+
+       return ret;
+}
+
+static inline int
+ssbi_reg_write(void *context, unsigned int reg, unsigned int val)
+{
+       u8 v = val;
+       return ssbi_write(context, reg, &v, 1);
+}
+
 #endif
index 969c0a6..2ca67b5 100644 (file)
@@ -32,7 +32,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <linux/sunrpc/sched.h>
 
 #ifdef CONFIG_SUNRPC_BACKCHANNEL
-struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt);
+struct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid);
+void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied);
 void xprt_free_bc_request(struct rpc_rqst *req);
 int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs);
 void xprt_destroy_backchannel(struct rpc_xprt *, unsigned int max_reqs);
index 8af2804..70736b9 100644 (file)
@@ -130,6 +130,8 @@ struct rpc_create_args {
 #define RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT     (1UL << 9)
 
 struct rpc_clnt *rpc_create(struct rpc_create_args *args);
+struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
+                                       struct rpc_xprt *xprt);
 struct rpc_clnt        *rpc_bind_new_program(struct rpc_clnt *,
                                const struct rpc_program *, u32);
 void rpc_task_reset_client(struct rpc_task *task, struct rpc_clnt *clnt);
index 62fd1b7..947009e 100644 (file)
@@ -56,6 +56,7 @@ int           svc_recv(struct svc_rqst *, long);
 int            svc_send(struct svc_rqst *);
 void           svc_drop(struct svc_rqst *);
 void           svc_sock_update_bufs(struct svc_serv *serv);
+bool           svc_alien_sock(struct net *net, int fd);
 int            svc_addsock(struct svc_serv *serv, const int fd,
                                        char *name_return, const size_t len);
 void           svc_init_xprt_sock(void);
index 8097b9d..3e5efb2 100644 (file)
@@ -295,13 +295,24 @@ int                       xprt_adjust_timeout(struct rpc_rqst *req);
 void                   xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task);
 void                   xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task);
 void                   xprt_release(struct rpc_task *task);
-struct rpc_xprt *      xprt_get(struct rpc_xprt *xprt);
 void                   xprt_put(struct rpc_xprt *xprt);
 struct rpc_xprt *      xprt_alloc(struct net *net, size_t size,
                                unsigned int num_prealloc,
                                unsigned int max_req);
 void                   xprt_free(struct rpc_xprt *);
 
+/**
+ * xprt_get - return a reference to an RPC transport.
+ * @xprt: pointer to the transport
+ *
+ */
+static inline struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
+{
+       if (atomic_inc_not_zero(&xprt->count))
+               return xprt;
+       return NULL;
+}
+
 static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p)
 {
        return p + xprt->tsh_size;
index 2aa8b74..697ceb7 100644 (file)
@@ -748,6 +748,9 @@ asmlinkage long sys_linkat(int olddfd, const char __user *oldname,
                           int newdfd, const char __user *newname, int flags);
 asmlinkage long sys_renameat(int olddfd, const char __user * oldname,
                             int newdfd, const char __user * newname);
+asmlinkage long sys_renameat2(int olddfd, const char __user *oldname,
+                             int newdfd, const char __user *newname,
+                             unsigned int flags);
 asmlinkage long sys_futimesat(int dfd, const char __user *filename,
                              struct timeval __user *utimes);
 asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode);
index e0bf210..084354b 100644 (file)
@@ -71,7 +71,8 @@ struct attribute_group {
  */
 
 #define __ATTR(_name, _mode, _show, _store) {                          \
-       .attr = {.name = __stringify(_name), .mode = _mode },           \
+       .attr = {.name = __stringify(_name),                            \
+                .mode = VERIFY_OCTAL_PERMISSIONS(_mode) },             \
        .show   = _show,                                                \
        .store  = _store,                                               \
 }
index 12ae6ce..7062330 100644 (file)
@@ -188,7 +188,7 @@ DECLARE_PER_CPU(int, numa_node);
 /* Returns the number of the current Node. */
 static inline int numa_node_id(void)
 {
-       return __this_cpu_read(numa_node);
+       return raw_cpu_read(numa_node);
 }
 #endif
 
@@ -245,7 +245,7 @@ static inline void set_numa_mem(int node)
 /* Returns the number of the nearest Node with memory */
 static inline int numa_mem_id(void)
 {
-       return __this_cpu_read(_numa_mem_);
+       return raw_cpu_read(_numa_mem_);
 }
 #endif
 
diff --git a/include/linux/vmacache.h b/include/linux/vmacache.h
new file mode 100644 (file)
index 0000000..c3fa0fd
--- /dev/null
@@ -0,0 +1,38 @@
+#ifndef __LINUX_VMACACHE_H
+#define __LINUX_VMACACHE_H
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+/*
+ * Hash based on the page number. Provides a good hit rate for
+ * workloads with good locality and those with random accesses as well.
+ */
+#define VMACACHE_HASH(addr) ((addr >> PAGE_SHIFT) & VMACACHE_MASK)
+
+static inline void vmacache_flush(struct task_struct *tsk)
+{
+       memset(tsk->vmacache, 0, sizeof(tsk->vmacache));
+}
+
+extern void vmacache_flush_all(struct mm_struct *mm);
+extern void vmacache_update(unsigned long addr, struct vm_area_struct *newvma);
+extern struct vm_area_struct *vmacache_find(struct mm_struct *mm,
+                                                   unsigned long addr);
+
+#ifndef CONFIG_MMU
+extern struct vm_area_struct *vmacache_find_exact(struct mm_struct *mm,
+                                                 unsigned long start,
+                                                 unsigned long end);
+#endif
+
+static inline void vmacache_invalidate(struct mm_struct *mm)
+{
+       mm->vmacache_seqnum++;
+
+       /* deal with overflows */
+       if (unlikely(mm->vmacache_seqnum == 0))
+               vmacache_flush_all(mm);
+}
+
+#endif /* __LINUX_VMACACHE_H */
index ea44761..45c9cd1 100644 (file)
@@ -27,9 +27,13 @@ struct vm_event_state {
 
 DECLARE_PER_CPU(struct vm_event_state, vm_event_states);
 
+/*
+ * vm counters are allowed to be racy. Use raw_cpu_ops to avoid the
+ * local_irq_disable overhead.
+ */
 static inline void __count_vm_event(enum vm_event_item item)
 {
-       __this_cpu_inc(vm_event_states.event[item]);
+       raw_cpu_inc(vm_event_states.event[item]);
 }
 
 static inline void count_vm_event(enum vm_event_item item)
@@ -39,7 +43,7 @@ static inline void count_vm_event(enum vm_event_item item)
 
 static inline void __count_vm_events(enum vm_event_item item, long delta)
 {
-       __this_cpu_add(vm_event_states.event[item], delta);
+       raw_cpu_add(vm_event_states.event[item], delta);
 }
 
 static inline void count_vm_events(enum vm_event_item item, long delta)
index 559044c..e7d9d9e 100644 (file)
@@ -803,17 +803,6 @@ do {                                                                       \
        __ret;                                                          \
 })
 
-
-/*
- * These are the old interfaces to sleep waiting for an event.
- * They are racy.  DO NOT use them, use the wait_event* interfaces above.
- * We plan to remove these interfaces.
- */
-extern void sleep_on(wait_queue_head_t *q);
-extern long sleep_on_timeout(wait_queue_head_t *q, signed long timeout);
-extern void interruptible_sleep_on(wait_queue_head_t *q);
-extern long interruptible_sleep_on_timeout(wait_queue_head_t *q, signed long timeout);
-
 /*
  * Waitqueues which are removed from the waitqueue_head at wakeup time
  */
index 021b8a3..5777c13 100644 (file)
@@ -178,7 +178,7 @@ int write_cache_pages(struct address_space *mapping,
                      struct writeback_control *wbc, writepage_t writepage,
                      void *data);
 int do_writepages(struct address_space *mapping, struct writeback_control *wbc);
-void set_page_dirty_balance(struct page *page, int page_mkwrite);
+void set_page_dirty_balance(struct page *page);
 void writeback_set_ratelimit(void);
 void tag_pages_for_writeback(struct address_space *mapping,
                             pgoff_t start, pgoff_t end);
index 956b175..55d1504 100644 (file)
@@ -47,8 +47,8 @@ enum nf_ct_ext_id {
 /* Extensions: optional stuff which isn't permanently in struct. */
 struct nf_ct_ext {
        struct rcu_head rcu;
-       u8 offset[NF_CT_EXT_NUM];
-       u8 len;
+       u16 offset[NF_CT_EXT_NUM];
+       u16 len;
        char data[0];
 };
 
index 4e845b8..5853c91 100644 (file)
@@ -423,11 +423,11 @@ extern int scsi_is_target_device(const struct device *);
 extern int scsi_execute(struct scsi_device *sdev, const unsigned char *cmd,
                        int data_direction, void *buffer, unsigned bufflen,
                        unsigned char *sense, int timeout, int retries,
-                       int flag, int *resid);
+                       u64 flags, int *resid);
 extern int scsi_execute_req_flags(struct scsi_device *sdev,
        const unsigned char *cmd, int data_direction, void *buffer,
        unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout,
-       int retries, int *resid, int flags);
+       int retries, int *resid, u64 flags);
 static inline int scsi_execute_req(struct scsi_device *sdev,
        const unsigned char *cmd, int data_direction, void *buffer,
        unsigned bufflen, struct scsi_sense_hdr *sshdr, int timeout,
index f862cff..0b6a187 100644 (file)
 
 struct snd_pcm_substream;
 
+int snd_cs8427_init(struct snd_i2c_bus *bus, struct snd_i2c_device *device);
 int snd_cs8427_create(struct snd_i2c_bus *bus, unsigned char addr,
                      unsigned int reset_timeout, struct snd_i2c_device **r_cs8427);
 int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg,
diff --git a/include/trace/events/i2c.h b/include/trace/events/i2c.h
new file mode 100644 (file)
index 0000000..fe17187
--- /dev/null
@@ -0,0 +1,372 @@
+/* I2C and SMBUS message transfer tracepoints
+ *
+ * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM i2c
+
+#if !defined(_TRACE_I2C_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_I2C_H
+
+#include <linux/i2c.h>
+#include <linux/tracepoint.h>
+
+/*
+ * drivers/i2c/i2c-core.c
+ */
+extern void i2c_transfer_trace_reg(void);
+extern void i2c_transfer_trace_unreg(void);
+
+/*
+ * __i2c_transfer() write request
+ */
+TRACE_EVENT_FN(i2c_write,
+              TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg,
+                       int num),
+              TP_ARGS(adap, msg, num),
+              TP_STRUCT__entry(
+                      __field(int,     adapter_nr              )
+                      __field(__u16,   msg_nr                  )
+                      __field(__u16,   addr                    )
+                      __field(__u16,   flags                   )
+                      __field(__u16,   len                     )
+                      __dynamic_array(__u8, buf, msg->len)     ),
+              TP_fast_assign(
+                      __entry->adapter_nr = adap->nr;
+                      __entry->msg_nr = num;
+                      __entry->addr = msg->addr;
+                      __entry->flags = msg->flags;
+                      __entry->len = msg->len;
+                      memcpy(__get_dynamic_array(buf), msg->buf, msg->len);
+                             ),
+              TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]",
+                        __entry->adapter_nr,
+                        __entry->msg_nr,
+                        __entry->addr,
+                        __entry->flags,
+                        __entry->len,
+                        __entry->len, __get_dynamic_array(buf)
+                        ),
+              i2c_transfer_trace_reg,
+              i2c_transfer_trace_unreg);
+
+/*
+ * __i2c_transfer() read request
+ */
+TRACE_EVENT_FN(i2c_read,
+              TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg,
+                       int num),
+              TP_ARGS(adap, msg, num),
+              TP_STRUCT__entry(
+                      __field(int,     adapter_nr              )
+                      __field(__u16,   msg_nr                  )
+                      __field(__u16,   addr                    )
+                      __field(__u16,   flags                   )
+                      __field(__u16,   len                     )
+                               ),
+              TP_fast_assign(
+                      __entry->adapter_nr = adap->nr;
+                      __entry->msg_nr = num;
+                      __entry->addr = msg->addr;
+                      __entry->flags = msg->flags;
+                      __entry->len = msg->len;
+                             ),
+              TP_printk("i2c-%d #%u a=%03x f=%04x l=%u",
+                        __entry->adapter_nr,
+                        __entry->msg_nr,
+                        __entry->addr,
+                        __entry->flags,
+                        __entry->len
+                        ),
+              i2c_transfer_trace_reg,
+                      i2c_transfer_trace_unreg);
+
+/*
+ * __i2c_transfer() read reply
+ */
+TRACE_EVENT_FN(i2c_reply,
+              TP_PROTO(const struct i2c_adapter *adap, const struct i2c_msg *msg,
+                       int num),
+              TP_ARGS(adap, msg, num),
+              TP_STRUCT__entry(
+                      __field(int,     adapter_nr              )
+                      __field(__u16,   msg_nr                  )
+                      __field(__u16,   addr                    )
+                      __field(__u16,   flags                   )
+                      __field(__u16,   len                     )
+                      __dynamic_array(__u8, buf, msg->len)     ),
+              TP_fast_assign(
+                      __entry->adapter_nr = adap->nr;
+                      __entry->msg_nr = num;
+                      __entry->addr = msg->addr;
+                      __entry->flags = msg->flags;
+                      __entry->len = msg->len;
+                      memcpy(__get_dynamic_array(buf), msg->buf, msg->len);
+                             ),
+              TP_printk("i2c-%d #%u a=%03x f=%04x l=%u [%*phD]",
+                        __entry->adapter_nr,
+                        __entry->msg_nr,
+                        __entry->addr,
+                        __entry->flags,
+                        __entry->len,
+                        __entry->len, __get_dynamic_array(buf)
+                        ),
+              i2c_transfer_trace_reg,
+              i2c_transfer_trace_unreg);
+
+/*
+ * __i2c_transfer() result
+ */
+TRACE_EVENT_FN(i2c_result,
+              TP_PROTO(const struct i2c_adapter *adap, int num, int ret),
+              TP_ARGS(adap, num, ret),
+              TP_STRUCT__entry(
+                      __field(int,     adapter_nr              )
+                      __field(__u16,   nr_msgs                 )
+                      __field(__s16,   ret                     )
+                               ),
+              TP_fast_assign(
+                      __entry->adapter_nr = adap->nr;
+                      __entry->nr_msgs = num;
+                      __entry->ret = ret;
+                             ),
+              TP_printk("i2c-%d n=%u ret=%d",
+                        __entry->adapter_nr,
+                        __entry->nr_msgs,
+                        __entry->ret
+                        ),
+              i2c_transfer_trace_reg,
+              i2c_transfer_trace_unreg);
+
+/*
+ * i2c_smbus_xfer() write data or procedure call request
+ */
+TRACE_EVENT_CONDITION(smbus_write,
+       TP_PROTO(const struct i2c_adapter *adap,
+                u16 addr, unsigned short flags,
+                char read_write, u8 command, int protocol,
+                const union i2c_smbus_data *data),
+       TP_ARGS(adap, addr, flags, read_write, command, protocol, data),
+       TP_CONDITION(read_write == I2C_SMBUS_WRITE ||
+                    protocol == I2C_SMBUS_PROC_CALL ||
+                    protocol == I2C_SMBUS_BLOCK_PROC_CALL),
+       TP_STRUCT__entry(
+               __field(int,    adapter_nr              )
+               __field(__u16,  addr                    )
+               __field(__u16,  flags                   )
+               __field(__u8,   command                 )
+               __field(__u8,   len                     )
+               __field(__u32,  protocol                )
+               __array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2)     ),
+       TP_fast_assign(
+               __entry->adapter_nr = adap->nr;
+               __entry->addr = addr;
+               __entry->flags = flags;
+               __entry->command = command;
+               __entry->protocol = protocol;
+
+               switch (protocol) {
+               case I2C_SMBUS_BYTE_DATA:
+                       __entry->len = 1;
+                       goto copy;
+               case I2C_SMBUS_WORD_DATA:
+               case I2C_SMBUS_PROC_CALL:
+                       __entry->len = 2;
+                       goto copy;
+               case I2C_SMBUS_BLOCK_DATA:
+               case I2C_SMBUS_BLOCK_PROC_CALL:
+               case I2C_SMBUS_I2C_BLOCK_DATA:
+                       __entry->len = data->block[0] + 1;
+               copy:
+                       memcpy(__entry->buf, data->block, __entry->len);
+                       break;
+               case I2C_SMBUS_QUICK:
+               case I2C_SMBUS_BYTE:
+               case I2C_SMBUS_I2C_BLOCK_BROKEN:
+               default:
+                       __entry->len = 0;
+               }
+                      ),
+       TP_printk("i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]",
+                 __entry->adapter_nr,
+                 __entry->addr,
+                 __entry->flags,
+                 __entry->command,
+                 __print_symbolic(__entry->protocol,
+                                  { I2C_SMBUS_QUICK,           "QUICK" },
+                                  { I2C_SMBUS_BYTE,            "BYTE"  },
+                                  { I2C_SMBUS_BYTE_DATA,               "BYTE_DATA" },
+                                  { I2C_SMBUS_WORD_DATA,               "WORD_DATA" },
+                                  { I2C_SMBUS_PROC_CALL,               "PROC_CALL" },
+                                  { I2C_SMBUS_BLOCK_DATA,              "BLOCK_DATA" },
+                                  { I2C_SMBUS_I2C_BLOCK_BROKEN,        "I2C_BLOCK_BROKEN" },
+                                  { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" },
+                                  { I2C_SMBUS_I2C_BLOCK_DATA,  "I2C_BLOCK_DATA" }),
+                 __entry->len,
+                 __entry->len, __entry->buf
+                 ));
+
+/*
+ * i2c_smbus_xfer() read data request
+ */
+TRACE_EVENT_CONDITION(smbus_read,
+       TP_PROTO(const struct i2c_adapter *adap,
+                u16 addr, unsigned short flags,
+                char read_write, u8 command, int protocol),
+       TP_ARGS(adap, addr, flags, read_write, command, protocol),
+       TP_CONDITION(!(read_write == I2C_SMBUS_WRITE ||
+                      protocol == I2C_SMBUS_PROC_CALL ||
+                      protocol == I2C_SMBUS_BLOCK_PROC_CALL)),
+       TP_STRUCT__entry(
+               __field(int,    adapter_nr              )
+               __field(__u16,  flags                   )
+               __field(__u16,  addr                    )
+               __field(__u8,   command                 )
+               __field(__u32,  protocol                )
+               __array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2)     ),
+       TP_fast_assign(
+               __entry->adapter_nr = adap->nr;
+               __entry->addr = addr;
+               __entry->flags = flags;
+               __entry->command = command;
+               __entry->protocol = protocol;
+                      ),
+       TP_printk("i2c-%d a=%03x f=%04x c=%x %s",
+                 __entry->adapter_nr,
+                 __entry->addr,
+                 __entry->flags,
+                 __entry->command,
+                 __print_symbolic(__entry->protocol,
+                                  { I2C_SMBUS_QUICK,           "QUICK" },
+                                  { I2C_SMBUS_BYTE,            "BYTE"  },
+                                  { I2C_SMBUS_BYTE_DATA,               "BYTE_DATA" },
+                                  { I2C_SMBUS_WORD_DATA,               "WORD_DATA" },
+                                  { I2C_SMBUS_PROC_CALL,               "PROC_CALL" },
+                                  { I2C_SMBUS_BLOCK_DATA,              "BLOCK_DATA" },
+                                  { I2C_SMBUS_I2C_BLOCK_BROKEN,        "I2C_BLOCK_BROKEN" },
+                                  { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" },
+                                  { I2C_SMBUS_I2C_BLOCK_DATA,  "I2C_BLOCK_DATA" })
+                 ));
+
+/*
+ * i2c_smbus_xfer() read data or procedure call reply
+ */
+TRACE_EVENT_CONDITION(smbus_reply,
+       TP_PROTO(const struct i2c_adapter *adap,
+                u16 addr, unsigned short flags,
+                char read_write, u8 command, int protocol,
+                const union i2c_smbus_data *data),
+       TP_ARGS(adap, addr, flags, read_write, command, protocol, data),
+       TP_CONDITION(read_write == I2C_SMBUS_READ),
+       TP_STRUCT__entry(
+               __field(int,    adapter_nr              )
+               __field(__u16,  addr                    )
+               __field(__u16,  flags                   )
+               __field(__u8,   command                 )
+               __field(__u8,   len                     )
+               __field(__u32,  protocol                )
+               __array(__u8, buf, I2C_SMBUS_BLOCK_MAX + 2)     ),
+       TP_fast_assign(
+               __entry->adapter_nr = adap->nr;
+               __entry->addr = addr;
+               __entry->flags = flags;
+               __entry->command = command;
+               __entry->protocol = protocol;
+
+               switch (protocol) {
+               case I2C_SMBUS_BYTE:
+               case I2C_SMBUS_BYTE_DATA:
+                       __entry->len = 1;
+                       goto copy;
+               case I2C_SMBUS_WORD_DATA:
+               case I2C_SMBUS_PROC_CALL:
+                       __entry->len = 2;
+                       goto copy;
+               case I2C_SMBUS_BLOCK_DATA:
+               case I2C_SMBUS_BLOCK_PROC_CALL:
+               case I2C_SMBUS_I2C_BLOCK_DATA:
+                       __entry->len = data->block[0] + 1;
+               copy:
+                       memcpy(__entry->buf, data->block, __entry->len);
+                       break;
+               case I2C_SMBUS_QUICK:
+               case I2C_SMBUS_I2C_BLOCK_BROKEN:
+               default:
+                       __entry->len = 0;
+               }
+                      ),
+       TP_printk("i2c-%d a=%03x f=%04x c=%x %s l=%u [%*phD]",
+                 __entry->adapter_nr,
+                 __entry->addr,
+                 __entry->flags,
+                 __entry->command,
+                 __print_symbolic(__entry->protocol,
+                                  { I2C_SMBUS_QUICK,           "QUICK" },
+                                  { I2C_SMBUS_BYTE,            "BYTE"  },
+                                  { I2C_SMBUS_BYTE_DATA,               "BYTE_DATA" },
+                                  { I2C_SMBUS_WORD_DATA,               "WORD_DATA" },
+                                  { I2C_SMBUS_PROC_CALL,               "PROC_CALL" },
+                                  { I2C_SMBUS_BLOCK_DATA,              "BLOCK_DATA" },
+                                  { I2C_SMBUS_I2C_BLOCK_BROKEN,        "I2C_BLOCK_BROKEN" },
+                                  { I2C_SMBUS_BLOCK_PROC_CALL, "BLOCK_PROC_CALL" },
+                                  { I2C_SMBUS_I2C_BLOCK_DATA,  "I2C_BLOCK_DATA" }),
+                 __entry->len,
+                 __entry->len, __entry->buf
+                 ));
+
+/*
+ * i2c_smbus_xfer() result
+ */
+TRACE_EVENT(smbus_result,
+           TP_PROTO(const struct i2c_adapter *adap,
+                    u16 addr, unsigned short flags,
+                    char read_write, u8 command, int protocol,
+                    int res),
+           TP_ARGS(adap, addr, flags, read_write, command, protocol, res),
+           TP_STRUCT__entry(
+                   __field(int,        adapter_nr              )
+                   __field(__u16,      addr                    )
+                   __field(__u16,      flags                   )
+                   __field(__u8,       read_write              )
+                   __field(__u8,       command                 )
+                   __field(__s16,      res                     )
+                   __field(__u32,      protocol                )
+                            ),
+           TP_fast_assign(
+                   __entry->adapter_nr = adap->nr;
+                   __entry->addr = addr;
+                   __entry->flags = flags;
+                   __entry->read_write = read_write;
+                   __entry->command = command;
+                   __entry->protocol = protocol;
+                   __entry->res = res;
+                          ),
+           TP_printk("i2c-%d a=%03x f=%04x c=%x %s %s res=%d",
+                     __entry->adapter_nr,
+                     __entry->addr,
+                     __entry->flags,
+                     __entry->command,
+                     __print_symbolic(__entry->protocol,
+                                      { I2C_SMBUS_QUICK,               "QUICK" },
+                                      { I2C_SMBUS_BYTE,                "BYTE"  },
+                                      { I2C_SMBUS_BYTE_DATA,           "BYTE_DATA" },
+                                      { I2C_SMBUS_WORD_DATA,           "WORD_DATA" },
+                                      { I2C_SMBUS_PROC_CALL,           "PROC_CALL" },
+                                      { I2C_SMBUS_BLOCK_DATA,          "BLOCK_DATA" },
+                                      { I2C_SMBUS_I2C_BLOCK_BROKEN,    "I2C_BLOCK_BROKEN" },
+                                      { I2C_SMBUS_BLOCK_PROC_CALL,     "BLOCK_PROC_CALL" },
+                                      { I2C_SMBUS_I2C_BLOCK_DATA,      "I2C_BLOCK_DATA" }),
+                     __entry->read_write == I2C_SMBUS_WRITE ? "wr" : "rd",
+                     __entry->res
+                     ));
+
+#endif /* _TRACE_I2C_H */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 1619327..11fd51b 100644 (file)
@@ -22,8 +22,10 @@ struct module;
 
 #define show_module_flags(flags) __print_flags(flags, "",      \
        { (1UL << TAINT_PROPRIETARY_MODULE),    "P" },          \
+       { (1UL << TAINT_OOT_MODULE),            "O" },          \
        { (1UL << TAINT_FORCED_MODULE),         "F" },          \
-       { (1UL << TAINT_CRAP),                  "C" })
+       { (1UL << TAINT_CRAP),                  "C" },          \
+       { (1UL << TAINT_UNSIGNED_MODULE),       "X" })
 
 TRACE_EVENT(module_load,
 
index 102a646..dee3bb1 100644 (file)
@@ -32,7 +32,7 @@ TRACE_EVENT(task_newtask,
 
 TRACE_EVENT(task_rename,
 
-       TP_PROTO(struct task_struct *task, char *comm),
+       TP_PROTO(struct task_struct *task, const char *comm),
 
        TP_ARGS(task, comm),
 
index 4164529..ddc3b36 100644 (file)
@@ -50,7 +50,7 @@
 
 #define MADV_DONTDUMP   16             /* Explicity exclude from the core dump,
                                           overrides the coredump filter bits */
-#define MADV_DODUMP    17              /* Clear the MADV_NODUMP flag */
+#define MADV_DODUMP    17              /* Clear the MADV_DONTDUMP flag */
 
 /* compatibility flags */
 #define MAP_FILE       0
index b06c8ed..9abbeb9 100644 (file)
@@ -619,6 +619,15 @@ struct drm_gem_open {
 #define  DRM_PRIME_CAP_EXPORT          0x2
 #define DRM_CAP_TIMESTAMP_MONOTONIC    0x6
 #define DRM_CAP_ASYNC_PAGE_FLIP                0x7
+/*
+ * The CURSOR_WIDTH and CURSOR_HEIGHT capabilities return a valid widthxheight
+ * combination for the hardware cursor. The intention is that a hardware
+ * agnostic userspace can query a cursor plane size to use.
+ *
+ * Note that the cross-driver contract is to merely return a valid size;
+ * drivers are free to attach another meaning on top, eg. i915 returns the
+ * maximum plane size.
+ */
 #define DRM_CAP_CURSOR_WIDTH           0x8
 #define DRM_CAP_CURSOR_HEIGHT          0x9
 
@@ -637,6 +646,14 @@ struct drm_get_cap {
  */
 #define DRM_CLIENT_CAP_STEREO_3D       1
 
+/**
+ * DRM_CLIENT_CAP_UNIVERSAL_PLANES
+ *
+ * If set to 1, the DRM core will expose all planes (overlay, primary, and
+ * cursor) to userspace.
+ */
+#define DRM_CLIENT_CAP_UNIVERSAL_PLANES  2
+
 /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */
 struct drm_set_client_cap {
        __u64 capability;
index d3c6207..0664c31 100644 (file)
@@ -50,6 +50,7 @@ struct drm_msm_timespec {
 
 #define MSM_PARAM_GPU_ID     0x01
 #define MSM_PARAM_GMEM_SIZE  0x02
+#define MSM_PARAM_CHIP_ID    0x03
 
 struct drm_msm_param {
        uint32_t pipe;           /* in, MSM_PIPE_x */
@@ -69,6 +70,12 @@ struct drm_msm_param {
 #define MSM_BO_WC            0x00020000
 #define MSM_BO_UNCACHED      0x00040000
 
+#define MSM_BO_FLAGS         (MSM_BO_SCANOUT | \
+                              MSM_BO_GPU_READONLY | \
+                              MSM_BO_CACHED | \
+                              MSM_BO_WC | \
+                              MSM_BO_UNCACHED)
+
 struct drm_msm_gem_new {
        uint64_t size;           /* in */
        uint32_t flags;          /* in, mask of MSM_BO_x */
@@ -85,6 +92,8 @@ struct drm_msm_gem_info {
 #define MSM_PREP_WRITE       0x02
 #define MSM_PREP_NOSYNC      0x04
 
+#define MSM_PREP_FLAGS       (MSM_PREP_READ | MSM_PREP_WRITE | MSM_PREP_NOSYNC)
+
 struct drm_msm_gem_cpu_prep {
        uint32_t handle;         /* in */
        uint32_t op;             /* in, mask of MSM_PREP_x */
@@ -152,6 +161,9 @@ struct drm_msm_gem_submit_cmd {
  */
 #define MSM_SUBMIT_BO_READ             0x0001
 #define MSM_SUBMIT_BO_WRITE            0x0002
+
+#define MSM_SUBMIT_BO_FLAGS            (MSM_SUBMIT_BO_READ | MSM_SUBMIT_BO_WRITE)
+
 struct drm_msm_gem_submit_bo {
        uint32_t flags;          /* in, mask of MSM_SUBMIT_BO_x */
        uint32_t handle;         /* in, GEM handle */
index d9ea3a7..aefa2f6 100644 (file)
@@ -510,6 +510,7 @@ typedef struct {
 #define DRM_RADEON_GEM_GET_TILING      0x29
 #define DRM_RADEON_GEM_BUSY            0x2a
 #define DRM_RADEON_GEM_VA              0x2b
+#define DRM_RADEON_GEM_OP              0x2c
 
 #define DRM_IOCTL_RADEON_CP_INIT    DRM_IOW( DRM_COMMAND_BASE + DRM_RADEON_CP_INIT, drm_radeon_init_t)
 #define DRM_IOCTL_RADEON_CP_START   DRM_IO(  DRM_COMMAND_BASE + DRM_RADEON_CP_START)
@@ -552,6 +553,7 @@ typedef struct {
 #define DRM_IOCTL_RADEON_GEM_GET_TILING        DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_GET_TILING, struct drm_radeon_gem_get_tiling)
 #define DRM_IOCTL_RADEON_GEM_BUSY      DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_BUSY, struct drm_radeon_gem_busy)
 #define DRM_IOCTL_RADEON_GEM_VA                DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_VA, struct drm_radeon_gem_va)
+#define DRM_IOCTL_RADEON_GEM_OP                DRM_IOWR(DRM_COMMAND_BASE + DRM_RADEON_GEM_OP, struct drm_radeon_gem_op)
 
 typedef struct drm_radeon_init {
        enum {
@@ -884,6 +886,16 @@ struct drm_radeon_gem_pwrite {
        uint64_t data_ptr;
 };
 
+/* Sets or returns a value associated with a buffer. */
+struct drm_radeon_gem_op {
+       uint32_t        handle; /* buffer */
+       uint32_t        op;     /* RADEON_GEM_OP_* */
+       uint64_t        value;  /* input or return value */
+};
+
+#define RADEON_GEM_OP_GET_INITIAL_DOMAIN       0
+#define RADEON_GEM_OP_SET_INITIAL_DOMAIN       1
+
 #define RADEON_VA_MAP                  1
 #define RADEON_VA_UNMAP                        2
 
@@ -919,6 +931,7 @@ struct drm_radeon_gem_va {
 #define RADEON_CS_RING_COMPUTE      1
 #define RADEON_CS_RING_DMA          2
 #define RADEON_CS_RING_UVD          3
+#define RADEON_CS_RING_VCE          4
 /* The third dword of RADEON_CHUNK_ID_FLAGS is a sint32 that sets the priority */
 /* 0 = normal, + = higher priority, - = lower priority */
 
@@ -987,6 +1000,13 @@ struct drm_radeon_cs {
 #define RADEON_INFO_SI_BACKEND_ENABLED_MASK    0x19
 /* max engine clock - needed for OpenCL */
 #define RADEON_INFO_MAX_SCLK           0x1a
+/* version of VCE firmware */
+#define RADEON_INFO_VCE_FW_VERSION     0x1b
+/* version of VCE feedback */
+#define RADEON_INFO_VCE_FB_VERSION     0x1c
+#define RADEON_INFO_NUM_BYTES_MOVED    0x1d
+#define RADEON_INFO_VRAM_USAGE         0x1e
+#define RADEON_INFO_GTT_USAGE          0x1f
 
 
 struct drm_radeon_info {
index 5e1ab55..b042b48 100644 (file)
@@ -1,17 +1,23 @@
 /*
  * Copyright (c) 2012-2013, NVIDIA CORPORATION.  All rights reserved.
  *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
+ * 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:
  *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
  *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ * 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.
  */
 
 #ifndef _UAPI_TEGRA_DRM_H_
index 87792a5..4fc66f6 100644 (file)
 #define DRM_VMW_PARAM_MAX_MOB_MEMORY   9
 #define DRM_VMW_PARAM_MAX_MOB_SIZE     10
 
+/**
+ * enum drm_vmw_handle_type - handle type for ref ioctls
+ *
+ */
+enum drm_vmw_handle_type {
+       DRM_VMW_HANDLE_LEGACY = 0,
+       DRM_VMW_HANDLE_PRIME = 1
+};
+
 /**
  * struct drm_vmw_getparam_arg
  *
@@ -177,6 +186,7 @@ struct drm_vmw_surface_create_req {
  * struct drm_wmv_surface_arg
  *
  * @sid: Surface id of created surface or surface to destroy or reference.
+ * @handle_type: Handle type for DRM_VMW_REF_SURFACE Ioctl.
  *
  * Output data from the DRM_VMW_CREATE_SURFACE Ioctl.
  * Input argument to the DRM_VMW_UNREF_SURFACE Ioctl.
@@ -185,7 +195,7 @@ struct drm_vmw_surface_create_req {
 
 struct drm_vmw_surface_arg {
        int32_t sid;
-       uint32_t pad64;
+       enum drm_vmw_handle_type handle_type;
 };
 
 /**
index 289760f..58afc04 100644 (file)
 
 #define PR_GET_TID_ADDRESS     40
 
+#define PR_SET_THP_DISABLE     41
+#define PR_GET_THP_DISABLE     42
+
 #endif /* _LINUX_PRCTL_H */
index 24f3a57..6adb445 100644 (file)
@@ -1018,4 +1018,18 @@ static inline bool omapdss_device_is_enabled(struct omap_dss_device *dssdev)
        return dssdev->state == OMAP_DSS_DISPLAY_ACTIVE;
 }
 
+struct device_node *
+omapdss_of_get_next_port(const struct device_node *parent,
+                        struct device_node *prev);
+
+struct device_node *
+omapdss_of_get_next_endpoint(const struct device_node *parent,
+                            struct device_node *prev);
+
+struct device_node *
+omapdss_of_get_first_endpoint(const struct device_node *parent);
+
+struct omap_dss_device *
+omapdss_of_find_source_for_first_ep(struct device_node *node);
+
 #endif
index 8851c64..427ba60 100644 (file)
@@ -1483,6 +1483,7 @@ config PCI_QUIRKS
 
 config EMBEDDED
        bool "Embedded system"
+       option allnoconfig_y
        select EXPERT
        help
          This option should be enabled if compiling the kernel for
index 93b6139..a8497fa 100644 (file)
@@ -455,6 +455,7 @@ static char * __init unpack_to_rootfs(char *buf, unsigned len)
                }
                this_header = 0;
                decompress = decompress_method(buf, len, &compress_name);
+               pr_debug("Detected %s compressed data\n", compress_name);
                if (decompress) {
                        res = decompress(buf, len, NULL, flush_buffer, NULL,
                                   &my_inptr, error);
index a4695ad..45d035d 100644 (file)
@@ -113,9 +113,6 @@ struct compat_shm_info {
        compat_ulong_t swap_attempts, swap_successes;
 };
 
-extern int sem_ctls[];
-#define sc_semopm      (sem_ctls[2])
-
 static inline int compat_ipc_parse_version(int *cmd)
 {
 #ifdef CONFIG_ARCH_WANT_COMPAT_IPC_PARSE_VERSION
index 1702864..998d31b 100644 (file)
@@ -281,4 +281,4 @@ static int __init ipc_sysctl_init(void)
        return 0;
 }
 
-__initcall(ipc_sysctl_init);
+device_initcall(ipc_sysctl_init);
index c3b3117..4fcf39a 100644 (file)
@@ -1459,4 +1459,4 @@ out_sysctl:
        return error;
 }
 
-__initcall(init_mqueue_fs);
+device_initcall(init_mqueue_fs);
index e1b4c6d..2eb0d1e 100644 (file)
@@ -128,7 +128,7 @@ static int __init ipc_init(void)
        register_ipcns_notifier(&init_ipc_ns);
        return 0;
 }
-__initcall(ipc_init);
+device_initcall(ipc_init);
 
 /**
  * ipc_init_ids        - initialise ipc identifiers
index fede3d3..9fcdaa7 100644 (file)
@@ -1487,6 +1487,7 @@ static struct dentry *cgroup_mount(struct file_system_type *fs_type,
        struct cgroup_sb_opts opts;
        struct dentry *dentry;
        int ret;
+       bool new_sb;
 
        /*
         * The first time anyone tries to mount a cgroup, enable the list
@@ -1603,8 +1604,8 @@ out_unlock:
        if (ret)
                return ERR_PTR(ret);
 
-       dentry = kernfs_mount(fs_type, flags, root->kf_root, NULL);
-       if (IS_ERR(dentry))
+       dentry = kernfs_mount(fs_type, flags, root->kf_root, &new_sb);
+       if (IS_ERR(dentry) || !new_sb)
                cgroup_put(&root->cgrp);
        return dentry;
 }
@@ -2345,11 +2346,26 @@ static int cgroup_rename(struct kernfs_node *kn, struct kernfs_node *new_parent,
        return ret;
 }
 
+/* set uid and gid of cgroup dirs and files to that of the creator */
+static int cgroup_kn_set_ugid(struct kernfs_node *kn)
+{
+       struct iattr iattr = { .ia_valid = ATTR_UID | ATTR_GID,
+                              .ia_uid = current_fsuid(),
+                              .ia_gid = current_fsgid(), };
+
+       if (uid_eq(iattr.ia_uid, GLOBAL_ROOT_UID) &&
+           gid_eq(iattr.ia_gid, GLOBAL_ROOT_GID))
+               return 0;
+
+       return kernfs_setattr(kn, &iattr);
+}
+
 static int cgroup_add_file(struct cgroup *cgrp, struct cftype *cft)
 {
        char name[CGROUP_FILE_NAME_MAX];
        struct kernfs_node *kn;
        struct lock_class_key *key = NULL;
+       int ret;
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
        key = &cft->lockdep_key;
@@ -2357,7 +2373,13 @@ static int cgroup_add_file(struct cgroup *cgrp, struct cftype *cft)
        kn = __kernfs_create_file(cgrp->kn, cgroup_file_name(cgrp, cft, name),
                                  cgroup_file_mode(cft), 0, cft->kf_ops, cft,
                                  NULL, false, key);
-       return PTR_ERR_OR_ZERO(kn);
+       if (IS_ERR(kn))
+               return PTR_ERR(kn);
+
+       ret = cgroup_kn_set_ugid(kn);
+       if (ret)
+               kernfs_remove(kn);
+       return ret;
 }
 
 /**
@@ -3752,6 +3774,10 @@ static long cgroup_create(struct cgroup *parent, const char *name,
         */
        idr_replace(&root->cgroup_idr, cgrp, cgrp->id);
 
+       err = cgroup_kn_set_ugid(kn);
+       if (err)
+               goto err_destroy;
+
        err = cgroup_addrm_files(cgrp, cgroup_base_files, true);
        if (err)
                goto err_destroy;
index deff2e6..a9e710e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mutex.h>
 #include <linux/gfp.h>
 #include <linux/suspend.h>
+#include <linux/lockdep.h>
 
 #include "smpboot.h"
 
 static DEFINE_MUTEX(cpu_add_remove_lock);
 
 /*
- * The following two API's must be used when attempting
- * to serialize the updates to cpu_online_mask, cpu_present_mask.
+ * The following two APIs (cpu_maps_update_begin/done) must be used when
+ * attempting to serialize the updates to cpu_online_mask & cpu_present_mask.
+ * The APIs cpu_notifier_register_begin/done() must be used to protect CPU
+ * hotplug callback (un)registration performed using __register_cpu_notifier()
+ * or __unregister_cpu_notifier().
  */
 void cpu_maps_update_begin(void)
 {
        mutex_lock(&cpu_add_remove_lock);
 }
+EXPORT_SYMBOL(cpu_notifier_register_begin);
 
 void cpu_maps_update_done(void)
 {
        mutex_unlock(&cpu_add_remove_lock);
 }
+EXPORT_SYMBOL(cpu_notifier_register_done);
 
 static RAW_NOTIFIER_HEAD(cpu_chain);
 
@@ -57,17 +63,30 @@ static struct {
         * an ongoing cpu hotplug operation.
         */
        int refcount;
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       struct lockdep_map dep_map;
+#endif
 } cpu_hotplug = {
        .active_writer = NULL,
        .lock = __MUTEX_INITIALIZER(cpu_hotplug.lock),
        .refcount = 0,
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       .dep_map = {.name = "cpu_hotplug.lock" },
+#endif
 };
 
+/* Lockdep annotations for get/put_online_cpus() and cpu_hotplug_begin/end() */
+#define cpuhp_lock_acquire_read() lock_map_acquire_read(&cpu_hotplug.dep_map)
+#define cpuhp_lock_acquire()      lock_map_acquire(&cpu_hotplug.dep_map)
+#define cpuhp_lock_release()      lock_map_release(&cpu_hotplug.dep_map)
+
 void get_online_cpus(void)
 {
        might_sleep();
        if (cpu_hotplug.active_writer == current)
                return;
+       cpuhp_lock_acquire_read();
        mutex_lock(&cpu_hotplug.lock);
        cpu_hotplug.refcount++;
        mutex_unlock(&cpu_hotplug.lock);
@@ -87,6 +106,7 @@ void put_online_cpus(void)
        if (!--cpu_hotplug.refcount && unlikely(cpu_hotplug.active_writer))
                wake_up_process(cpu_hotplug.active_writer);
        mutex_unlock(&cpu_hotplug.lock);
+       cpuhp_lock_release();
 
 }
 EXPORT_SYMBOL_GPL(put_online_cpus);
@@ -117,6 +137,7 @@ void cpu_hotplug_begin(void)
 {
        cpu_hotplug.active_writer = current;
 
+       cpuhp_lock_acquire();
        for (;;) {
                mutex_lock(&cpu_hotplug.lock);
                if (likely(!cpu_hotplug.refcount))
@@ -131,6 +152,7 @@ void cpu_hotplug_done(void)
 {
        cpu_hotplug.active_writer = NULL;
        mutex_unlock(&cpu_hotplug.lock);
+       cpuhp_lock_release();
 }
 
 /*
@@ -166,6 +188,11 @@ int __ref register_cpu_notifier(struct notifier_block *nb)
        return ret;
 }
 
+int __ref __register_cpu_notifier(struct notifier_block *nb)
+{
+       return raw_notifier_chain_register(&cpu_chain, nb);
+}
+
 static int __cpu_notify(unsigned long val, void *v, int nr_to_call,
                        int *nr_calls)
 {
@@ -189,6 +216,7 @@ static void cpu_notify_nofail(unsigned long val, void *v)
        BUG_ON(cpu_notify(val, v));
 }
 EXPORT_SYMBOL(register_cpu_notifier);
+EXPORT_SYMBOL(__register_cpu_notifier);
 
 void __ref unregister_cpu_notifier(struct notifier_block *nb)
 {
@@ -198,6 +226,12 @@ void __ref unregister_cpu_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL(unregister_cpu_notifier);
 
+void __ref __unregister_cpu_notifier(struct notifier_block *nb)
+{
+       raw_notifier_chain_unregister(&cpu_chain, nb);
+}
+EXPORT_SYMBOL(__unregister_cpu_notifier);
+
 /**
  * clear_tasks_mm_cpumask - Safely clear tasks' mm_cpumask for a CPU
  * @cpu: a CPU id
index 99982a7..2956c8d 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/pid.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
+#include <linux/vmacache.h>
 #include <linux/rcupdate.h>
 
 #include <asm/cacheflush.h>
@@ -224,10 +225,17 @@ static void kgdb_flush_swbreak_addr(unsigned long addr)
        if (!CACHE_FLUSH_IS_SAFE)
                return;
 
-       if (current->mm && current->mm->mmap_cache) {
-               flush_cache_range(current->mm->mmap_cache,
-                                 addr, addr + BREAK_INSTR_SIZE);
+       if (current->mm) {
+               int i;
+
+               for (i = 0; i < VMACACHE_SIZE; i++) {
+                       if (!current->vmacache[i])
+                               continue;
+                       flush_cache_range(current->vmacache[i],
+                                         addr, addr + BREAK_INSTR_SIZE);
+               }
        }
+
        /* Force flush instruction cache if it was outside the mm */
        flush_icache_range(addr, addr + BREAK_INSTR_SIZE);
 }
index 6480d1c..6ed6a1d 100644 (file)
@@ -570,7 +570,7 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
        if (same_thread_group(p->real_parent, father))
                return;
 
-       /* We don't want people slaying init.  */
+       /* We don't want people slaying init. */
        p->exit_signal = SIGCHLD;
 
        /* If it has exited notify the new parent about this child's death. */
@@ -784,9 +784,10 @@ void do_exit(long code)
        exit_shm(tsk);
        exit_files(tsk);
        exit_fs(tsk);
+       if (group_dead)
+               disassociate_ctty(1);
        exit_task_namespaces(tsk);
        exit_task_work(tsk);
-       check_stack_usage();
        exit_thread();
 
        /*
@@ -799,19 +800,15 @@ void do_exit(long code)
 
        cgroup_exit(tsk);
 
-       if (group_dead)
-               disassociate_ctty(1);
-
        module_put(task_thread_info(tsk)->exec_domain->module);
 
-       proc_exit_connector(tsk);
-
        /*
         * FIXME: do that only when needed, using sched_exit tracepoint
         */
        flush_ptrace_hw_breakpoint(tsk);
 
        exit_notify(tsk, group_dead);
+       proc_exit_connector(tsk);
 #ifdef CONFIG_NUMA
        task_lock(tsk);
        mpol_put(tsk->mempolicy);
@@ -844,6 +841,7 @@ void do_exit(long code)
 
        validate_creds_for_do_exit(tsk);
 
+       check_stack_usage();
        preempt_disable();
        if (tsk->nr_dirtied)
                __this_cpu_add(dirty_throttle_leaks, tsk->nr_dirtied);
@@ -1038,17 +1036,13 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
                return wait_noreap_copyout(wo, p, pid, uid, why, status);
        }
 
+       traced = ptrace_reparented(p);
        /*
-        * Try to move the task's state to DEAD
-        * only one thread is allowed to do this:
+        * Move the task's state to DEAD/TRACE, only one thread can do this.
         */
-       state = xchg(&p->exit_state, EXIT_DEAD);
-       if (state != EXIT_ZOMBIE) {
-               BUG_ON(state != EXIT_DEAD);
+       state = traced && thread_group_leader(p) ? EXIT_TRACE : EXIT_DEAD;
+       if (cmpxchg(&p->exit_state, EXIT_ZOMBIE, state) != EXIT_ZOMBIE)
                return 0;
-       }
-
-       traced = ptrace_reparented(p);
        /*
         * It can be ptraced but not reparented, check
         * thread_group_leader() to filter out sub-threads.
@@ -1109,7 +1103,7 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
 
        /*
         * Now we are sure this task is interesting, and no other
-        * thread can reap it because we set its state to EXIT_DEAD.
+        * thread can reap it because we its state == DEAD/TRACE.
         */
        read_unlock(&tasklist_lock);
 
@@ -1146,22 +1140,19 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
        if (!retval)
                retval = pid;
 
-       if (traced) {
+       if (state == EXIT_TRACE) {
                write_lock_irq(&tasklist_lock);
                /* We dropped tasklist, ptracer could die and untrace */
                ptrace_unlink(p);
-               /*
-                * If this is not a sub-thread, notify the parent.
-                * If parent wants a zombie, don't release it now.
-                */
-               if (thread_group_leader(p) &&
-                   !do_notify_parent(p, p->exit_signal)) {
-                       p->exit_state = EXIT_ZOMBIE;
-                       p = NULL;
-               }
+
+               /* If parent wants a zombie, don't release it now */
+               state = EXIT_ZOMBIE;
+               if (do_notify_parent(p, p->exit_signal))
+                       state = EXIT_DEAD;
+               p->exit_state = state;
                write_unlock_irq(&tasklist_lock);
        }
-       if (p != NULL)
+       if (state == EXIT_DEAD)
                release_task(p);
 
        return retval;
@@ -1338,7 +1329,12 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
 static int wait_consider_task(struct wait_opts *wo, int ptrace,
                                struct task_struct *p)
 {
-       int ret = eligible_child(wo, p);
+       int ret;
+
+       if (unlikely(p->exit_state == EXIT_DEAD))
+               return 0;
+
+       ret = eligible_child(wo, p);
        if (!ret)
                return ret;
 
@@ -1356,33 +1352,44 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
                return 0;
        }
 
-       /* dead body doesn't have much to contribute */
-       if (unlikely(p->exit_state == EXIT_DEAD)) {
+       if (unlikely(p->exit_state == EXIT_TRACE)) {
                /*
-                * But do not ignore this task until the tracer does
-                * wait_task_zombie()->do_notify_parent().
+                * ptrace == 0 means we are the natural parent. In this case
+                * we should clear notask_error, debugger will notify us.
                 */
-               if (likely(!ptrace) && unlikely(ptrace_reparented(p)))
+               if (likely(!ptrace))
                        wo->notask_error = 0;
                return 0;
        }
 
-       /* slay zombie? */
-       if (p->exit_state == EXIT_ZOMBIE) {
+       if (likely(!ptrace) && unlikely(p->ptrace)) {
                /*
-                * A zombie ptracee is only visible to its ptracer.
-                * Notification and reaping will be cascaded to the real
-                * parent when the ptracer detaches.
+                * If it is traced by its real parent's group, just pretend
+                * the caller is ptrace_do_wait() and reap this child if it
+                * is zombie.
+                *
+                * This also hides group stop state from real parent; otherwise
+                * a single stop can be reported twice as group and ptrace stop.
+                * If a ptracer wants to distinguish these two events for its
+                * own children it should create a separate process which takes
+                * the role of real parent.
                 */
-               if (likely(!ptrace) && unlikely(p->ptrace)) {
-                       /* it will become visible, clear notask_error */
-                       wo->notask_error = 0;
-                       return 0;
-               }
+               if (!ptrace_reparented(p))
+                       ptrace = 1;
+       }
 
+       /* slay zombie? */
+       if (p->exit_state == EXIT_ZOMBIE) {
                /* we don't reap group leaders with subthreads */
-               if (!delay_group_leader(p))
-                       return wait_task_zombie(wo, p);
+               if (!delay_group_leader(p)) {
+                       /*
+                        * A zombie ptracee is only visible to its ptracer.
+                        * Notification and reaping will be cascaded to the
+                        * real parent when the ptracer detaches.
+                        */
+                       if (unlikely(ptrace) || likely(!p->ptrace))
+                               return wait_task_zombie(wo, p);
+               }
 
                /*
                 * Allow access to stopped/continued state via zombie by
@@ -1407,19 +1414,6 @@ static int wait_consider_task(struct wait_opts *wo, int ptrace,
                if (likely(!ptrace) || (wo->wo_flags & (WCONTINUED | WEXITED)))
                        wo->notask_error = 0;
        } else {
-               /*
-                * If @p is ptraced by a task in its real parent's group,
-                * hide group stop/continued state when looking at @p as
-                * the real parent; otherwise, a single stop can be
-                * reported twice as group and ptrace stops.
-                *
-                * If a ptracer wants to distinguish the two events for its
-                * own children, it should create a separate process which
-                * takes the role of real parent.
-                */
-               if (likely(!ptrace) && p->ptrace && !ptrace_reparented(p))
-                       return 0;
-
                /*
                 * @p is alive and it's gonna stop, continue or exit, so
                 * there always is something to wait for.
index abc4589..54a8d26 100644 (file)
@@ -28,6 +28,8 @@
 #include <linux/mman.h>
 #include <linux/mmu_notifier.h>
 #include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/vmacache.h>
 #include <linux/nsproxy.h>
 #include <linux/capability.h>
 #include <linux/cpu.h>
@@ -71,6 +73,7 @@
 #include <linux/signalfd.h>
 #include <linux/uprobes.h>
 #include <linux/aio.h>
+#include <linux/compiler.h>
 
 #include <asm/pgtable.h>
 #include <asm/pgalloc.h>
@@ -284,7 +287,7 @@ void __init fork_init(unsigned long mempages)
                init_task.signal->rlim[RLIMIT_NPROC];
 }
 
-int __attribute__((weak)) arch_dup_task_struct(struct task_struct *dst,
+int __weak arch_dup_task_struct(struct task_struct *dst,
                                               struct task_struct *src)
 {
        *dst = *src;
@@ -364,7 +367,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
 
        mm->locked_vm = 0;
        mm->mmap = NULL;
-       mm->mmap_cache = NULL;
+       mm->vmacache_seqnum = 0;
        mm->map_count = 0;
        cpumask_clear(mm_cpumask(mm));
        mm->mm_rb = RB_ROOT;
@@ -530,8 +533,6 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p)
        atomic_set(&mm->mm_count, 1);
        init_rwsem(&mm->mmap_sem);
        INIT_LIST_HEAD(&mm->mmlist);
-       mm->flags = (current->mm) ?
-               (current->mm->flags & MMF_INIT_MASK) : default_dump_filter;
        mm->core_state = NULL;
        atomic_long_set(&mm->nr_ptes, 0);
        memset(&mm->rss_stat, 0, sizeof(mm->rss_stat));
@@ -540,8 +541,15 @@ static struct mm_struct *mm_init(struct mm_struct *mm, struct task_struct *p)
        mm_init_owner(mm, p);
        clear_tlb_flush_pending(mm);
 
-       if (likely(!mm_alloc_pgd(mm))) {
+       if (current->mm) {
+               mm->flags = current->mm->flags & MMF_INIT_MASK;
+               mm->def_flags = current->mm->def_flags & VM_INIT_DEF_MASK;
+       } else {
+               mm->flags = default_dump_filter;
                mm->def_flags = 0;
+       }
+
+       if (likely(!mm_alloc_pgd(mm))) {
                mmu_notifier_mm_init(mm);
                return mm;
        }
@@ -877,6 +885,9 @@ static int copy_mm(unsigned long clone_flags, struct task_struct *tsk)
        if (!oldmm)
                return 0;
 
+       /* initialize the new vmacache entries */
+       vmacache_flush(tsk);
+
        if (clone_flags & CLONE_VM) {
                atomic_inc(&oldmm->mm_users);
                mm = oldmm;
@@ -1070,15 +1081,6 @@ static int copy_signal(unsigned long clone_flags, struct task_struct *tsk)
        return 0;
 }
 
-static void copy_flags(unsigned long clone_flags, struct task_struct *p)
-{
-       unsigned long new_flags = p->flags;
-
-       new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
-       new_flags |= PF_FORKNOEXEC;
-       p->flags = new_flags;
-}
-
 SYSCALL_DEFINE1(set_tid_address, int __user *, tidptr)
 {
        current->clear_child_tid = tidptr;
@@ -1228,7 +1230,8 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                goto bad_fork_cleanup_count;
 
        delayacct_tsk_init(p);  /* Must remain after dup_task_struct() */
-       copy_flags(clone_flags, p);
+       p->flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
+       p->flags |= PF_FORKNOEXEC;
        INIT_LIST_HEAD(&p->children);
        INIT_LIST_HEAD(&p->sibling);
        rcu_copy_process(p);
@@ -1274,7 +1277,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
                p->mempolicy = NULL;
                goto bad_fork_cleanup_threadgroup_lock;
        }
-       mpol_fix_fork_child_flag(p);
 #endif
 #ifdef CONFIG_CPUSETS
        p->cpuset_mem_spread_rotor = NUMA_NO_NODE;
index 67dacaf..6801b37 100644 (file)
@@ -1452,6 +1452,7 @@ retry:
        hb2 = hash_futex(&key2);
 
 retry_private:
+       hb_waiters_inc(hb2);
        double_lock_hb(hb1, hb2);
 
        if (likely(cmpval != NULL)) {
@@ -1461,6 +1462,7 @@ retry_private:
 
                if (unlikely(ret)) {
                        double_unlock_hb(hb1, hb2);
+                       hb_waiters_dec(hb2);
 
                        ret = get_user(curval, uaddr1);
                        if (ret)
@@ -1510,6 +1512,7 @@ retry_private:
                        break;
                case -EFAULT:
                        double_unlock_hb(hb1, hb2);
+                       hb_waiters_dec(hb2);
                        put_futex_key(&key2);
                        put_futex_key(&key1);
                        ret = fault_in_user_writeable(uaddr2);
@@ -1519,6 +1522,7 @@ retry_private:
                case -EAGAIN:
                        /* The owner was exiting, try again. */
                        double_unlock_hb(hb1, hb2);
+                       hb_waiters_dec(hb2);
                        put_futex_key(&key2);
                        put_futex_key(&key1);
                        cond_resched();
@@ -1594,6 +1598,7 @@ retry_private:
 
 out_unlock:
        double_unlock_hb(hb1, hb2);
+       hb_waiters_dec(hb2);
 
        /*
         * drop_futex_key_refs() must be called outside the spinlocks. During
index 3127ad5..cb0cf37 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/ctype.h>
 #include <linux/slab.h>
+#include <linux/compiler.h>
 
 #include <asm/sections.h>
 
@@ -36,8 +37,8 @@
  * These will be re-linked against their real values
  * during the second link stage.
  */
-extern const unsigned long kallsyms_addresses[] __attribute__((weak));
-extern const u8 kallsyms_names[] __attribute__((weak));
+extern const unsigned long kallsyms_addresses[] __weak;
+extern const u8 kallsyms_names[] __weak;
 
 /*
  * Tell the compiler that the count isn't in the small data section if the arch
@@ -46,10 +47,10 @@ extern const u8 kallsyms_names[] __attribute__((weak));
 extern const unsigned long kallsyms_num_syms
 __attribute__((weak, section(".rodata")));
 
-extern const u8 kallsyms_token_table[] __attribute__((weak));
-extern const u16 kallsyms_token_index[] __attribute__((weak));
+extern const u8 kallsyms_token_table[] __weak;
+extern const u16 kallsyms_token_index[] __weak;
 
-extern const unsigned long kallsyms_markers[] __attribute__((weak));
+extern const unsigned long kallsyms_markers[] __weak;
 
 static inline int is_kernel_inittext(unsigned long addr)
 {
index c0d261c..c8380ad 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/vmalloc.h>
 #include <linux/swap.h>
 #include <linux/syscore_ops.h>
+#include <linux/compiler.h>
 
 #include <asm/page.h>
 #include <asm/uaccess.h>
@@ -1551,10 +1552,10 @@ void vmcoreinfo_append_str(const char *fmt, ...)
  * provide an empty default implementation here -- architecture
  * code may override this
  */
-void __attribute__ ((weak)) arch_crash_save_vmcoreinfo(void)
+void __weak arch_crash_save_vmcoreinfo(void)
 {}
 
-unsigned long __attribute__ ((weak)) paddr_vmcoreinfo_note(void)
+unsigned long __weak paddr_vmcoreinfo_note(void)
 {
        return __pa((unsigned long)(char *)&vmcoreinfo_note);
 }
index e660964..2495a9b 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/stat.h>
 #include <linux/sched.h>
 #include <linux/capability.h>
+#include <linux/compiler.h>
 
 #include <linux/rcupdate.h>    /* rcu_expedited */
 
@@ -162,8 +163,8 @@ KERNEL_ATTR_RW(rcu_expedited);
 /*
  * Make /sys/kernel/notes give the raw contents of our kernel .notes section.
  */
-extern const void __start_notes __attribute__((weak));
-extern const void __stop_notes __attribute__((weak));
+extern const void __start_notes __weak;
+extern const void __stop_notes __weak;
 #define        notes_size (&__stop_notes - &__start_notes)
 
 static ssize_t notes_read(struct file *filp, struct kobject *kobj,
index 306a76b..b8bdcd4 100644 (file)
@@ -1,5 +1,5 @@
 
-obj-y += mutex.o semaphore.o rwsem.o lglock.o mcs_spinlock.o
+obj-y += mutex.o semaphore.o rwsem.o mcs_spinlock.o
 
 ifdef CONFIG_FUNCTION_TRACER
 CFLAGS_REMOVE_lockdep.o = -pg
@@ -14,6 +14,7 @@ ifeq ($(CONFIG_PROC_FS),y)
 obj-$(CONFIG_LOCKDEP) += lockdep_proc.o
 endif
 obj-$(CONFIG_SMP) += spinlock.o
+obj-$(CONFIG_SMP) += lglock.o
 obj-$(CONFIG_PROVE_LOCKING) += spinlock.o
 obj-$(CONFIG_RT_MUTEXES) += rtmutex.o
 obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o
index 8dc7f5e..1186940 100644 (file)
@@ -640,7 +640,7 @@ static int module_unload_init(struct module *mod)
        INIT_LIST_HEAD(&mod->target_list);
 
        /* Hold reference count during initialization. */
-       __this_cpu_write(mod->refptr->incs, 1);
+       raw_cpu_write(mod->refptr->incs, 1);
 
        return 0;
 }
@@ -1013,6 +1013,8 @@ static size_t module_flags_taint(struct module *mod, char *buf)
                buf[l++] = 'F';
        if (mod->taints & (1 << TAINT_CRAP))
                buf[l++] = 'C';
+       if (mod->taints & (1 << TAINT_UNSIGNED_MODULE))
+               buf[l++] = 'E';
        /*
         * TAINT_FORCED_RMMOD: could be added.
         * TAINT_CPU_OUT_OF_SPEC, TAINT_MACHINE_CHECK, TAINT_BAD_PAGE don't
@@ -3218,7 +3220,7 @@ static int load_module(struct load_info *info, const char __user *uargs,
                pr_notice_once("%s: module verification failed: signature "
                               "and/or  required key missing - tainting "
                               "kernel\n", mod->name);
-               add_taint_module(mod, TAINT_FORCED_MODULE, LOCKDEP_STILL_OK);
+               add_taint_module(mod, TAINT_UNSIGNED_MODULE, LOCKDEP_STILL_OK);
        }
 #endif
 
@@ -3813,12 +3815,12 @@ void print_modules(void)
        list_for_each_entry_rcu(mod, &modules, list) {
                if (mod->state == MODULE_STATE_UNFORMED)
                        continue;
-               printk(" %s%s", mod->name, module_flags(mod, buf));
+               pr_cont(" %s%s", mod->name, module_flags(mod, buf));
        }
        preempt_enable();
        if (last_unloaded_module[0])
-               printk(" [last unloaded: %s]", last_unloaded_module);
-       printk("\n");
+               pr_cont(" [last unloaded: %s]", last_unloaded_module);
+       pr_cont("\n");
 }
 
 #ifdef CONFIG_MODVERSIONS
index cca8a91..d02fa9f 100644 (file)
@@ -100,7 +100,7 @@ void panic(const char *fmt, ...)
        va_start(args, fmt);
        vsnprintf(buf, sizeof(buf), fmt, args);
        va_end(args);
-       printk(KERN_EMERG "Kernel panic - not syncing: %s\n",buf);
+       pr_emerg("Kernel panic - not syncing: %s\n", buf);
 #ifdef CONFIG_DEBUG_BUGVERBOSE
        /*
         * Avoid nested stack-dumping if a panic occurs during oops processing
@@ -141,7 +141,7 @@ void panic(const char *fmt, ...)
                 * Delay timeout seconds before rebooting the machine.
                 * We can't use the "normal" timers since we just panicked.
                 */
-               printk(KERN_EMERG "Rebooting in %d seconds..", panic_timeout);
+               pr_emerg("Rebooting in %d seconds..", panic_timeout);
 
                for (i = 0; i < panic_timeout * 1000; i += PANIC_TIMER_STEP) {
                        touch_nmi_watchdog();
@@ -165,7 +165,7 @@ void panic(const char *fmt, ...)
                extern int stop_a_enabled;
                /* Make sure the user can actually press Stop-A (L1-A) */
                stop_a_enabled = 1;
-               printk(KERN_EMERG "Press Stop-A (L1-A) to return to the boot prom\n");
+               pr_emerg("Press Stop-A (L1-A) to return to the boot prom\n");
        }
 #endif
 #if defined(CONFIG_S390)
@@ -176,6 +176,7 @@ void panic(const char *fmt, ...)
                disabled_wait(caller);
        }
 #endif
+       pr_emerg("---[ end Kernel panic - not syncing: %s\n", buf);
        local_irq_enable();
        for (i = 0; ; i += PANIC_TIMER_STEP) {
                touch_softlockup_watchdog();
@@ -210,6 +211,7 @@ static const struct tnt tnts[] = {
        { TAINT_CRAP,                   'C', ' ' },
        { TAINT_FIRMWARE_WORKAROUND,    'I', ' ' },
        { TAINT_OOT_MODULE,             'O', ' ' },
+       { TAINT_UNSIGNED_MODULE,        'E', ' ' },
 };
 
 /**
@@ -228,6 +230,7 @@ static const struct tnt tnts[] = {
  *  'C' - modules from drivers/staging are loaded.
  *  'I' - Working around severe firmware bug.
  *  'O' - Out-of-tree module has been loaded.
+ *  'E' - Unsigned module has been loaded.
  *
  *     The string is overwritten by the next call to print_tainted().
  */
@@ -274,8 +277,7 @@ unsigned long get_taint(void)
 void add_taint(unsigned flag, enum lockdep_ok lockdep_ok)
 {
        if (lockdep_ok == LOCKDEP_NOW_UNRELIABLE && __debug_locks_off())
-               printk(KERN_WARNING
-                      "Disabling lock debugging due to kernel taint\n");
+               pr_warn("Disabling lock debugging due to kernel taint\n");
 
        set_bit(flag, &tainted_mask);
 }
@@ -380,8 +382,7 @@ late_initcall(init_oops_id);
 void print_oops_end_marker(void)
 {
        init_oops_id();
-       printk(KERN_WARNING "---[ end trace %016llx ]---\n",
-               (unsigned long long)oops_id);
+       pr_warn("---[ end trace %016llx ]---\n", (unsigned long long)oops_id);
 }
 
 /*
index 1ca7531..15f37ea 100644 (file)
@@ -2,6 +2,7 @@
 #include <linux/suspend_ioctls.h>
 #include <linux/utsname.h>
 #include <linux/freezer.h>
+#include <linux/compiler.h>
 
 struct swsusp_info {
        struct new_utsname      uts;
@@ -11,7 +12,7 @@ struct swsusp_info {
        unsigned long           image_pages;
        unsigned long           pages;
        unsigned long           size;
-} __attribute__((aligned(PAGE_SIZE)));
+} __aligned(PAGE_SIZE);
 
 #ifdef CONFIG_HIBERNATION
 /* kernel/power/snapshot.c */
index 149e745..18fb7a2 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/highmem.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/compiler.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -155,7 +156,7 @@ static inline void free_image_page(void *addr, int clear_nosave_free)
 struct linked_page {
        struct linked_page *next;
        char data[LINKED_PAGE_DATA_SIZE];
-} __attribute__((packed));
+} __packed;
 
 static inline void
 free_list_of_pages(struct linked_page *list, int clear_page_nosave)
index 90b3d93..c3ad9ca 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/syscore_ops.h>
 #include <linux/ftrace.h>
 #include <trace/events/power.h>
+#include <linux/compiler.h>
 
 #include "power.h"
 
@@ -156,13 +157,13 @@ static int suspend_prepare(suspend_state_t state)
 }
 
 /* default implementation */
-void __attribute__ ((weak)) arch_suspend_disable_irqs(void)
+void __weak arch_suspend_disable_irqs(void)
 {
        local_irq_disable();
 }
 
 /* default implementation */
-void __attribute__ ((weak)) arch_suspend_enable_irqs(void)
+void __weak arch_suspend_enable_irqs(void)
 {
        local_irq_enable();
 }
index 7c33ed2..8c9a481 100644 (file)
@@ -101,7 +101,7 @@ struct swsusp_header {
        unsigned int flags;     /* Flags to pass to the "boot" kernel */
        char    orig_sig[10];
        char    sig[10];
-} __attribute__((packed));
+} __packed;
 
 static struct swsusp_header *swsusp_header;
 
index 1b266db..cb980f0 100644 (file)
@@ -591,18 +591,28 @@ out_cleanup:
 int __ref create_proc_profile(void) /* false positive from hotcpu_notifier */
 {
        struct proc_dir_entry *entry;
+       int err = 0;
 
        if (!prof_on)
                return 0;
-       if (create_hash_tables())
-               return -ENOMEM;
+
+       cpu_notifier_register_begin();
+
+       if (create_hash_tables()) {
+               err = -ENOMEM;
+               goto out;
+       }
+
        entry = proc_create("profile", S_IWUSR | S_IRUGO,
                            NULL, &proc_profile_operations);
        if (!entry)
-               return 0;
+               goto out;
        proc_set_size(entry, (1 + prof_len) * sizeof(atomic_t));
-       hotcpu_notifier(profile_cpu_callback, 0);
-       return 0;
+       __hotcpu_notifier(profile_cpu_callback, 0);
+
+out:
+       cpu_notifier_register_done();
+       return err;
 }
 subsys_initcall(create_proc_profile);
 #endif /* CONFIG_PROC_FS */
index 4aa8a30..51dbac6 100644 (file)
@@ -22,8 +22,18 @@ void res_counter_init(struct res_counter *counter, struct res_counter *parent)
        counter->parent = parent;
 }
 
-int res_counter_charge_locked(struct res_counter *counter, unsigned long val,
-                             bool force)
+static u64 res_counter_uncharge_locked(struct res_counter *counter,
+                                      unsigned long val)
+{
+       if (WARN_ON(counter->usage < val))
+               val = counter->usage;
+
+       counter->usage -= val;
+       return counter->usage;
+}
+
+static int res_counter_charge_locked(struct res_counter *counter,
+                                    unsigned long val, bool force)
 {
        int ret = 0;
 
@@ -86,15 +96,6 @@ int res_counter_charge_nofail(struct res_counter *counter, unsigned long val,
        return __res_counter_charge(counter, val, limit_fail_at, true);
 }
 
-u64 res_counter_uncharge_locked(struct res_counter *counter, unsigned long val)
-{
-       if (WARN_ON(counter->usage < val))
-               val = counter->usage;
-
-       counter->usage -= val;
-       return counter->usage;
-}
-
 u64 res_counter_uncharge_until(struct res_counter *counter,
                               struct res_counter *top,
                               unsigned long val)
index b30a292..3ef6451 100644 (file)
 #include <linux/sched.h>
 #include <linux/static_key.h>
 #include <linux/workqueue.h>
+#include <linux/compiler.h>
 
 /*
  * Scheduler clock - returns current time in nanosec units.
  * This is default implementation.
  * Architectures and sub-architectures can override this.
  */
-unsigned long long __attribute__((weak)) sched_clock(void)
+unsigned long long __weak sched_clock(void)
 {
        return (unsigned long long)(jiffies - INITIAL_JIFFIES)
                                        * (NSEC_PER_SEC / HZ);
index 1d1b87b..268a45e 100644 (file)
@@ -73,6 +73,7 @@
 #include <linux/init_task.h>
 #include <linux/binfmts.h>
 #include <linux/context_tracking.h>
+#include <linux/compiler.h>
 
 #include <asm/switch_to.h>
 #include <asm/tlb.h>
@@ -2845,52 +2846,6 @@ int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
 }
 EXPORT_SYMBOL(default_wake_function);
 
-static long __sched
-sleep_on_common(wait_queue_head_t *q, int state, long timeout)
-{
-       unsigned long flags;
-       wait_queue_t wait;
-
-       init_waitqueue_entry(&wait, current);
-
-       __set_current_state(state);
-
-       spin_lock_irqsave(&q->lock, flags);
-       __add_wait_queue(q, &wait);
-       spin_unlock(&q->lock);
-       timeout = schedule_timeout(timeout);
-       spin_lock_irq(&q->lock);
-       __remove_wait_queue(q, &wait);
-       spin_unlock_irqrestore(&q->lock, flags);
-
-       return timeout;
-}
-
-void __sched interruptible_sleep_on(wait_queue_head_t *q)
-{
-       sleep_on_common(q, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
-}
-EXPORT_SYMBOL(interruptible_sleep_on);
-
-long __sched
-interruptible_sleep_on_timeout(wait_queue_head_t *q, long timeout)
-{
-       return sleep_on_common(q, TASK_INTERRUPTIBLE, timeout);
-}
-EXPORT_SYMBOL(interruptible_sleep_on_timeout);
-
-void __sched sleep_on(wait_queue_head_t *q)
-{
-       sleep_on_common(q, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
-}
-EXPORT_SYMBOL(sleep_on);
-
-long __sched sleep_on_timeout(wait_queue_head_t *q, long timeout)
-{
-       return sleep_on_common(q, TASK_UNINTERRUPTIBLE, timeout);
-}
-EXPORT_SYMBOL(sleep_on_timeout);
-
 #ifdef CONFIG_RT_MUTEXES
 
 /*
@@ -6498,7 +6453,7 @@ static cpumask_var_t fallback_doms;
  * cpu core maps. It is supposed to return 1 if the topology changed
  * or 0 if it stayed the same.
  */
-int __attribute__((weak)) arch_update_cpu_topology(void)
+int __weak arch_update_cpu_topology(void)
 {
        return 0;
 }
index 5d4b05a..6ea13c0 100644 (file)
@@ -33,6 +33,8 @@
 #include <linux/uprobes.h>
 #include <linux/compat.h>
 #include <linux/cn_proc.h>
+#include <linux/compiler.h>
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/signal.h>
 
@@ -3618,7 +3620,7 @@ SYSCALL_DEFINE3(sigsuspend, int, unused1, int, unused2, old_sigset_t, mask)
 }
 #endif
 
-__attribute__((weak)) const char *arch_vma_name(struct vm_area_struct *vma)
+__weak const char *arch_vma_name(struct vm_area_struct *vma)
 {
        return NULL;
 }
index adaeab6..fba0f29 100644 (file)
@@ -1996,6 +1996,21 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
                if (arg2 || arg3 || arg4 || arg5)
                        return -EINVAL;
                return current->no_new_privs ? 1 : 0;
+       case PR_GET_THP_DISABLE:
+               if (arg2 || arg3 || arg4 || arg5)
+                       return -EINVAL;
+               error = !!(me->mm->def_flags & VM_NOHUGEPAGE);
+               break;
+       case PR_SET_THP_DISABLE:
+               if (arg3 || arg4 || arg5)
+                       return -EINVAL;
+               down_write(&me->mm->mmap_sem);
+               if (arg2)
+                       me->mm->def_flags |= VM_NOHUGEPAGE;
+               else
+                       me->mm->def_flags &= ~VM_NOHUGEPAGE;
+               up_write(&me->mm->mmap_sem);
+               break;
        default:
                error = -EINVAL;
                break;
index 5c14b54..74f5b58 100644 (file)
@@ -141,6 +141,11 @@ static int min_percpu_pagelist_fract = 8;
 static int ngroups_max = NGROUPS_MAX;
 static const int cap_last_cap = CAP_LAST_CAP;
 
+/*this is needed for proc_doulongvec_minmax of sysctl_hung_task_timeout_secs */
+#ifdef CONFIG_DETECT_HUNG_TASK
+static unsigned long hung_task_timeout_max = (LONG_MAX/HZ);
+#endif
+
 #ifdef CONFIG_INOTIFY_USER
 #include <linux/inotify.h>
 #endif
@@ -985,6 +990,7 @@ static struct ctl_table kern_table[] = {
                .maxlen         = sizeof(unsigned long),
                .mode           = 0644,
                .proc_handler   = proc_dohung_task_timeout_secs,
+               .extra2         = &hung_task_timeout_max,
        },
        {
                .procname       = "hung_task_warnings",
index 5b40279..f7df8ea 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/tick.h>
 #include <linux/stop_machine.h>
 #include <linux/pvclock_gtod.h>
+#include <linux/compiler.h>
 
 #include "tick-internal.h"
 #include "ntp_internal.h"
@@ -760,7 +761,7 @@ u64 timekeeping_max_deferment(void)
  *
  *  XXX - Do be sure to remove it once all arches implement it.
  */
-void __attribute__((weak)) read_persistent_clock(struct timespec *ts)
+void __weak read_persistent_clock(struct timespec *ts)
 {
        ts->tv_sec = 0;
        ts->tv_nsec = 0;
@@ -775,7 +776,7 @@ void __attribute__((weak)) read_persistent_clock(struct timespec *ts)
  *
  *  XXX - Do be sure to remove it once all arches implement it.
  */
-void __attribute__((weak)) read_boot_clock(struct timespec *ts)
+void __weak read_boot_clock(struct timespec *ts)
 {
        ts->tv_sec = 0;
        ts->tv_nsec = 0;
index fc4da2d..c634868 100644 (file)
@@ -1301,7 +1301,7 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
         * In that off case, we need to allocate for all possible cpus.
         */
 #ifdef CONFIG_HOTPLUG_CPU
-       get_online_cpus();
+       cpu_notifier_register_begin();
        cpumask_copy(buffer->cpumask, cpu_online_mask);
 #else
        cpumask_copy(buffer->cpumask, cpu_possible_mask);
@@ -1324,10 +1324,10 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
 #ifdef CONFIG_HOTPLUG_CPU
        buffer->cpu_notify.notifier_call = rb_cpu_notify;
        buffer->cpu_notify.priority = 0;
-       register_cpu_notifier(&buffer->cpu_notify);
+       __register_cpu_notifier(&buffer->cpu_notify);
+       cpu_notifier_register_done();
 #endif
 
-       put_online_cpus();
        mutex_init(&buffer->mutex);
 
        return buffer;
@@ -1341,7 +1341,9 @@ struct ring_buffer *__ring_buffer_alloc(unsigned long size, unsigned flags,
 
  fail_free_cpumask:
        free_cpumask_var(buffer->cpumask);
-       put_online_cpus();
+#ifdef CONFIG_HOTPLUG_CPU
+       cpu_notifier_register_done();
+#endif
 
  fail_free_buffer:
        kfree(buffer);
@@ -1358,16 +1360,17 @@ ring_buffer_free(struct ring_buffer *buffer)
 {
        int cpu;
 
-       get_online_cpus();
-
 #ifdef CONFIG_HOTPLUG_CPU
-       unregister_cpu_notifier(&buffer->cpu_notify);
+       cpu_notifier_register_begin();
+       __unregister_cpu_notifier(&buffer->cpu_notify);
 #endif
 
        for_each_buffer_cpu(buffer, cpu)
                rb_free_cpu_buffer(buffer->buffers[cpu]);
 
-       put_online_cpus();
+#ifdef CONFIG_HOTPLUG_CPU
+       cpu_notifier_register_done();
+#endif
 
        kfree(buffer->buffers);
        free_cpumask_var(buffer->cpumask);
index ffc314b..2e29d7b 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/hw_breakpoint.h>
 #include <linux/trace_seq.h>
 #include <linux/ftrace_event.h>
+#include <linux/compiler.h>
 
 #ifdef CONFIG_FTRACE_SYSCALLS
 #include <asm/unistd.h>                /* For NR_SYSCALLS           */
@@ -1279,7 +1280,7 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled);
 #undef FTRACE_ENTRY
 #define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter)    \
        extern struct ftrace_event_call                                 \
-       __attribute__((__aligned__(4))) event_##call;
+       __aligned(4) event_##call;
 #undef FTRACE_ENTRY_DUP
 #define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print, filter)        \
        FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \
index 50f8329..fb0a38a 100644 (file)
@@ -460,7 +460,8 @@ EXPORT_SYMBOL_GPL(tracepoint_probe_unregister);
 #ifdef CONFIG_MODULES
 bool trace_module_has_bad_taint(struct module *mod)
 {
-       return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP));
+       return mod->taints & ~((1 << TAINT_OOT_MODULE) | (1 << TAINT_CRAP) |
+                              (1 << TAINT_UNSIGNED_MODULE));
 }
 
 static int tracepoint_module_coming(struct module *mod)
@@ -474,7 +475,7 @@ static int tracepoint_module_coming(struct module *mod)
        /*
         * We skip modules that taint the kernel, especially those with different
         * module headers (for forced load), to make sure we don't cause a crash.
-        * Staging and out-of-tree GPL modules are fine.
+        * Staging, out-of-tree, and unsigned GPL modules are fine.
         */
        if (trace_module_has_bad_taint(mod))
                return 0;
index 991c98b..5d4984c 100644 (file)
@@ -342,9 +342,9 @@ config HAS_IOMEM
        select GENERIC_IO
        default y
 
-config HAS_IOPORT
+config HAS_IOPORT_MAP
        boolean
-       depends on HAS_IOMEM && !NO_IOPORT
+       depends on HAS_IOMEM && !NO_IOPORT_MAP
        default y
 
 config HAS_DMA
index 4d1cd03..86069d7 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/types.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/printk.h>
 
 #ifndef CONFIG_DECOMPRESS_GZIP
 # define gunzip NULL
@@ -61,6 +62,8 @@ decompress_fn __init decompress_method(const unsigned char *inbuf, int len,
        if (len < 2)
                return NULL;    /* Need at least this much... */
 
+       pr_debug("Compressed data magic: %#.2x %#.2x\n", inbuf[0], inbuf[1]);
+
        for (cf = compressed_formats; cf->name; cf++) {
                if (!memcmp(inbuf, cf->magic, 2))
                        break;
index 48cb3c7..2f16c13 100644 (file)
@@ -170,7 +170,7 @@ void __iomem *devm_request_and_ioremap(struct device *device,
 }
 EXPORT_SYMBOL(devm_request_and_ioremap);
 
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
 /*
  * Generic iomap devres
  */
@@ -229,7 +229,7 @@ void devm_ioport_unmap(struct device *dev, void __iomem *addr)
                               devm_ioport_map_match, (__force void *)addr));
 }
 EXPORT_SYMBOL(devm_ioport_unmap);
-#endif /* CONFIG_HAS_IOPORT */
+#endif /* CONFIG_HAS_IOPORT_MAP */
 
 #ifdef CONFIG_PCI
 /*
index 1ba4956..2642fa8 100644 (file)
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -196,7 +196,7 @@ static void idr_mark_full(struct idr_layer **pa, int id)
        }
 }
 
-int __idr_pre_get(struct idr *idp, gfp_t gfp_mask)
+static int __idr_pre_get(struct idr *idp, gfp_t gfp_mask)
 {
        while (idp->id_free_cnt < MAX_IDR_FREE) {
                struct idr_layer *new;
@@ -207,7 +207,6 @@ int __idr_pre_get(struct idr *idp, gfp_t gfp_mask)
        }
        return 1;
 }
-EXPORT_SYMBOL(__idr_pre_get);
 
 /**
  * sub_alloc - try to allocate an id without growing the tree depth
@@ -374,20 +373,6 @@ static void idr_fill_slot(struct idr *idr, void *ptr, int id,
        idr_mark_full(pa, id);
 }
 
-int __idr_get_new_above(struct idr *idp, void *ptr, int starting_id, int *id)
-{
-       struct idr_layer *pa[MAX_IDR_LEVEL + 1];
-       int rv;
-
-       rv = idr_get_empty_slot(idp, starting_id, pa, 0, idp);
-       if (rv < 0)
-               return rv == -ENOMEM ? -EAGAIN : rv;
-
-       idr_fill_slot(idp, ptr, rv, pa);
-       *id = rv;
-       return 0;
-}
-EXPORT_SYMBOL(__idr_get_new_above);
 
 /**
  * idr_preload - preload for idr_alloc()
@@ -548,7 +533,7 @@ static void sub_remove(struct idr *idp, int shift, int id)
        n = id & IDR_MASK;
        if (likely(p != NULL && test_bit(n, p->bitmap))) {
                __clear_bit(n, p->bitmap);
-               rcu_assign_pointer(p->ary[n], NULL);
+               RCU_INIT_POINTER(p->ary[n], NULL);
                to_free = NULL;
                while(*paa && ! --((**paa)->count)){
                        if (to_free)
@@ -607,7 +592,7 @@ void idr_remove(struct idr *idp, int id)
 }
 EXPORT_SYMBOL(idr_remove);
 
-void __idr_remove_all(struct idr *idp)
+static void __idr_remove_all(struct idr *idp)
 {
        int n, id, max;
        int bt_mask;
@@ -617,7 +602,7 @@ void __idr_remove_all(struct idr *idp)
 
        n = idp->layers * IDR_BITS;
        p = idp->top;
-       rcu_assign_pointer(idp->top, NULL);
+       RCU_INIT_POINTER(idp->top, NULL);
        max = idr_max(idp->layers);
 
        id = 0;
@@ -640,7 +625,6 @@ void __idr_remove_all(struct idr *idp)
        }
        idp->layers = 0;
 }
-EXPORT_SYMBOL(__idr_remove_all);
 
 /**
  * idr_destroy - release all cached layers within an idr tree
index 2c08f36..fc3dcb4 100644 (file)
@@ -224,7 +224,7 @@ EXPORT_SYMBOL(iowrite8_rep);
 EXPORT_SYMBOL(iowrite16_rep);
 EXPORT_SYMBOL(iowrite32_rep);
 
-#ifdef CONFIG_HAS_IOPORT
+#ifdef CONFIG_HAS_IOPORT_MAP
 /* Create a virtual mapping cookie for an IO port range */
 void __iomem *ioport_map(unsigned long port, unsigned int nr)
 {
@@ -239,7 +239,7 @@ void ioport_unmap(void __iomem *addr)
 }
 EXPORT_SYMBOL(ioport_map);
 EXPORT_SYMBOL(ioport_unmap);
-#endif /* CONFIG_HAS_IOPORT */
+#endif /* CONFIG_HAS_IOPORT_MAP */
 
 #ifdef CONFIG_PCI
 /* Hide the details if this is a MMIO or PIO address space and just do what
index 8280a5d..7dd3357 100644 (file)
@@ -169,7 +169,7 @@ static int percpu_counter_hotcpu_callback(struct notifier_block *nb,
        struct percpu_counter *fbc;
 
        compute_batch_value();
-       if (action != CPU_DEAD)
+       if (action != CPU_DEAD && action != CPU_DEAD_FROZEN)
                return NOTIFY_OK;
 
        cpu = (unsigned long)hcpu;
index 04abe53..1afec32 100644 (file)
@@ -7,7 +7,8 @@
 #include <linux/kallsyms.h>
 #include <linux/sched.h>
 
-notrace unsigned int debug_smp_processor_id(void)
+notrace static unsigned int check_preemption_disabled(const char *what1,
+                                                       const char *what2)
 {
        int this_cpu = raw_smp_processor_id();
 
@@ -38,9 +39,9 @@ notrace unsigned int debug_smp_processor_id(void)
        if (!printk_ratelimit())
                goto out_enable;
 
-       printk(KERN_ERR "BUG: using smp_processor_id() in preemptible [%08x] "
-                       "code: %s/%d\n",
-                       preempt_count() - 1, current->comm, current->pid);
+       printk(KERN_ERR "BUG: using %s%s() in preemptible [%08x] code: %s/%d\n",
+               what1, what2, preempt_count() - 1, current->comm, current->pid);
+
        print_symbol("caller is %s\n", (long)__builtin_return_address(0));
        dump_stack();
 
@@ -50,5 +51,14 @@ out:
        return this_cpu;
 }
 
+notrace unsigned int debug_smp_processor_id(void)
+{
+       return check_preemption_disabled("smp_processor_id", "");
+}
 EXPORT_SYMBOL(debug_smp_processor_id);
 
+notrace void __this_cpu_preempt_check(const char *op)
+{
+       check_preemption_disabled("__this_cpu_", op);
+}
+EXPORT_SYMBOL(__this_cpu_preempt_check);
index 2888024..ebe5880 100644 (file)
@@ -216,6 +216,7 @@ config PAGEFLAGS_EXTENDED
 #
 config SPLIT_PTLOCK_CPUS
        int
+       default "999999" if !MMU
        default "999999" if ARM && !CPU_CACHE_VIPT
        default "999999" if PARISC && !PA20
        default "4"
@@ -577,3 +578,6 @@ config PGTABLE_MAPPING
 
          You can check speed with zsmalloc benchmark:
          https://github.com/spartacus06/zsmapbench
+
+config GENERIC_EARLY_IOREMAP
+       bool
index cdd7415..9e5aaf9 100644 (file)
@@ -16,7 +16,7 @@ obj-y                 := filemap.o mempool.o oom_kill.o fadvise.o \
                           readahead.o swap.o truncate.o vmscan.o shmem.o \
                           util.o mmzone.o vmstat.o backing-dev.o \
                           mm_init.o mmu_context.o percpu.o slab_common.o \
-                          compaction.o balloon_compaction.o \
+                          compaction.o balloon_compaction.o vmacache.o \
                           interval_tree.o list_lru.o workingset.o $(mmu-y)
 
 obj-y += init-mm.o
@@ -61,3 +61,4 @@ obj-$(CONFIG_CLEANCACHE) += cleancache.o
 obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
 obj-$(CONFIG_ZBUD)     += zbud.o
 obj-$(CONFIG_ZSMALLOC) += zsmalloc.o
+obj-$(CONFIG_GENERIC_EARLY_IOREMAP) += early_ioremap.o
index b6ab771..37f9762 100644 (file)
@@ -217,21 +217,12 @@ static inline bool compact_trylock_irqsave(spinlock_t *lock,
 /* Returns true if the page is within a block suitable for migration to */
 static bool suitable_migration_target(struct page *page)
 {
-       int migratetype = get_pageblock_migratetype(page);
-
-       /* Don't interfere with memory hot-remove or the min_free_kbytes blocks */
-       if (migratetype == MIGRATE_RESERVE)
-               return false;
-
-       if (is_migrate_isolate(migratetype))
-               return false;
-
-       /* If the page is a large free page, then allow migration */
+       /* If the page is a large free page, then disallow migration */
        if (PageBuddy(page) && page_order(page) >= pageblock_order)
-               return true;
+               return false;
 
        /* If the block is MIGRATE_MOVABLE or MIGRATE_CMA, allow migration */
-       if (migrate_async_suitable(migratetype))
+       if (migrate_async_suitable(get_pageblock_migratetype(page)))
                return true;
 
        /* Otherwise skip the block */
@@ -253,6 +244,7 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
        struct page *cursor, *valid_page = NULL;
        unsigned long flags;
        bool locked = false;
+       bool checked_pageblock = false;
 
        cursor = pfn_to_page(blockpfn);
 
@@ -284,8 +276,16 @@ static unsigned long isolate_freepages_block(struct compact_control *cc,
                        break;
 
                /* Recheck this is a suitable migration target under lock */
-               if (!strict && !suitable_migration_target(page))
-                       break;
+               if (!strict && !checked_pageblock) {
+                       /*
+                        * We need to check suitability of pageblock only once
+                        * and this isolate_freepages_block() is called with
+                        * pageblock range, so just check once is sufficient.
+                        */
+                       checked_pageblock = true;
+                       if (!suitable_migration_target(page))
+                               break;
+               }
 
                /* Recheck this is a buddy page under lock */
                if (!PageBuddy(page))
@@ -460,12 +460,13 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
        unsigned long last_pageblock_nr = 0, pageblock_nr;
        unsigned long nr_scanned = 0, nr_isolated = 0;
        struct list_head *migratelist = &cc->migratepages;
-       isolate_mode_t mode = 0;
        struct lruvec *lruvec;
        unsigned long flags;
        bool locked = false;
        struct page *page = NULL, *valid_page = NULL;
        bool skipped_async_unsuitable = false;
+       const isolate_mode_t mode = (!cc->sync ? ISOLATE_ASYNC_MIGRATE : 0) |
+                                   (unevictable ? ISOLATE_UNEVICTABLE : 0);
 
        /*
         * Ensure that there are not too many pages isolated from the LRU
@@ -487,7 +488,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
        cond_resched();
        for (; low_pfn < end_pfn; low_pfn++) {
                /* give a chance to irqs before checking need_resched() */
-               if (locked && !((low_pfn+1) % SWAP_CLUSTER_MAX)) {
+               if (locked && !(low_pfn % SWAP_CLUSTER_MAX)) {
                        if (should_release_lock(&zone->lru_lock)) {
                                spin_unlock_irqrestore(&zone->lru_lock, flags);
                                locked = false;
@@ -526,8 +527,25 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
 
                /* If isolation recently failed, do not retry */
                pageblock_nr = low_pfn >> pageblock_order;
-               if (!isolation_suitable(cc, page))
-                       goto next_pageblock;
+               if (last_pageblock_nr != pageblock_nr) {
+                       int mt;
+
+                       last_pageblock_nr = pageblock_nr;
+                       if (!isolation_suitable(cc, page))
+                               goto next_pageblock;
+
+                       /*
+                        * For async migration, also only scan in MOVABLE
+                        * blocks. Async migration is optimistic to see if
+                        * the minimum amount of work satisfies the allocation
+                        */
+                       mt = get_pageblock_migratetype(page);
+                       if (!cc->sync && !migrate_async_suitable(mt)) {
+                               cc->finished_update_migrate = true;
+                               skipped_async_unsuitable = true;
+                               goto next_pageblock;
+                       }
+               }
 
                /*
                 * Skip if free. page_order cannot be used without zone->lock
@@ -536,18 +554,6 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                if (PageBuddy(page))
                        continue;
 
-               /*
-                * For async migration, also only scan in MOVABLE blocks. Async
-                * migration is optimistic to see if the minimum amount of work
-                * satisfies the allocation
-                */
-               if (!cc->sync && last_pageblock_nr != pageblock_nr &&
-                   !migrate_async_suitable(get_pageblock_migratetype(page))) {
-                       cc->finished_update_migrate = true;
-                       skipped_async_unsuitable = true;
-                       goto next_pageblock;
-               }
-
                /*
                 * Check may be lockless but that's ok as we recheck later.
                 * It's possible to migrate LRU pages and balloon pages
@@ -557,11 +563,7 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                        if (unlikely(balloon_page_movable(page))) {
                                if (locked && balloon_page_isolate(page)) {
                                        /* Successfully isolated */
-                                       cc->finished_update_migrate = true;
-                                       list_add(&page->lru, migratelist);
-                                       cc->nr_migratepages++;
-                                       nr_isolated++;
-                                       goto check_compact_cluster;
+                                       goto isolate_success;
                                }
                        }
                        continue;
@@ -607,12 +609,6 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                        continue;
                }
 
-               if (!cc->sync)
-                       mode |= ISOLATE_ASYNC_MIGRATE;
-
-               if (unevictable)
-                       mode |= ISOLATE_UNEVICTABLE;
-
                lruvec = mem_cgroup_page_lruvec(page, zone);
 
                /* Try isolate the page */
@@ -622,13 +618,14 @@ isolate_migratepages_range(struct zone *zone, struct compact_control *cc,
                VM_BUG_ON_PAGE(PageTransCompound(page), page);
 
                /* Successfully isolated */
-               cc->finished_update_migrate = true;
                del_page_from_lru_list(page, lruvec, page_lru(page));
+
+isolate_success:
+               cc->finished_update_migrate = true;
                list_add(&page->lru, migratelist);
                cc->nr_migratepages++;
                nr_isolated++;
 
-check_compact_cluster:
                /* Avoid isolating too much */
                if (cc->nr_migratepages == COMPACT_CLUSTER_MAX) {
                        ++low_pfn;
@@ -639,7 +636,6 @@ check_compact_cluster:
 
 next_pageblock:
                low_pfn = ALIGN(low_pfn + 1, pageblock_nr_pages) - 1;
-               last_pageblock_nr = pageblock_nr;
        }
 
        acct_isolated(zone, locked, cc);
diff --git a/mm/early_ioremap.c b/mm/early_ioremap.c
new file mode 100644 (file)
index 0000000..e10ccd2
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ * Provide common bits of early_ioremap() support for architectures needing
+ * temporary mappings during boot before ioremap() is available.
+ *
+ * This is mostly a direct copy of the x86 early_ioremap implementation.
+ *
+ * (C) Copyright 1995 1996, 2014 Linus Torvalds
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <asm/fixmap.h>
+
+#ifdef CONFIG_MMU
+static int early_ioremap_debug __initdata;
+
+static int __init early_ioremap_debug_setup(char *str)
+{
+       early_ioremap_debug = 1;
+
+       return 0;
+}
+early_param("early_ioremap_debug", early_ioremap_debug_setup);
+
+static int after_paging_init __initdata;
+
+void __init __weak early_ioremap_shutdown(void)
+{
+}
+
+void __init early_ioremap_reset(void)
+{
+       early_ioremap_shutdown();
+       after_paging_init = 1;
+}
+
+/*
+ * Generally, ioremap() is available after paging_init() has been called.
+ * Architectures wanting to allow early_ioremap after paging_init() can
+ * define __late_set_fixmap and __late_clear_fixmap to do the right thing.
+ */
+#ifndef __late_set_fixmap
+static inline void __init __late_set_fixmap(enum fixed_addresses idx,
+                                           phys_addr_t phys, pgprot_t prot)
+{
+       BUG();
+}
+#endif
+
+#ifndef __late_clear_fixmap
+static inline void __init __late_clear_fixmap(enum fixed_addresses idx)
+{
+       BUG();
+}
+#endif
+
+static void __iomem *prev_map[FIX_BTMAPS_SLOTS] __initdata;
+static unsigned long prev_size[FIX_BTMAPS_SLOTS] __initdata;
+static unsigned long slot_virt[FIX_BTMAPS_SLOTS] __initdata;
+
+void __init early_ioremap_setup(void)
+{
+       int i;
+
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
+               if (WARN_ON(prev_map[i]))
+                       break;
+
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
+               slot_virt[i] = __fix_to_virt(FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*i);
+}
+
+static int __init check_early_ioremap_leak(void)
+{
+       int count = 0;
+       int i;
+
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++)
+               if (prev_map[i])
+                       count++;
+
+       if (WARN(count, KERN_WARNING
+                "Debug warning: early ioremap leak of %d areas detected.\n"
+                "please boot with early_ioremap_debug and report the dmesg.\n",
+                count))
+               return 1;
+       return 0;
+}
+late_initcall(check_early_ioremap_leak);
+
+static void __init __iomem *
+__early_ioremap(resource_size_t phys_addr, unsigned long size, pgprot_t prot)
+{
+       unsigned long offset;
+       resource_size_t last_addr;
+       unsigned int nrpages;
+       enum fixed_addresses idx;
+       int i, slot;
+
+       WARN_ON(system_state != SYSTEM_BOOTING);
+
+       slot = -1;
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+               if (!prev_map[i]) {
+                       slot = i;
+                       break;
+               }
+       }
+
+       if (WARN(slot < 0, "%s(%08llx, %08lx) not found slot\n",
+                __func__, (u64)phys_addr, size))
+               return NULL;
+
+       /* Don't allow wraparound or zero size */
+       last_addr = phys_addr + size - 1;
+       if (WARN_ON(!size || last_addr < phys_addr))
+               return NULL;
+
+       prev_size[slot] = size;
+       /*
+        * Mappings have to be page-aligned
+        */
+       offset = phys_addr & ~PAGE_MASK;
+       phys_addr &= PAGE_MASK;
+       size = PAGE_ALIGN(last_addr + 1) - phys_addr;
+
+       /*
+        * Mappings have to fit in the FIX_BTMAP area.
+        */
+       nrpages = size >> PAGE_SHIFT;
+       if (WARN_ON(nrpages > NR_FIX_BTMAPS))
+               return NULL;
+
+       /*
+        * Ok, go for it..
+        */
+       idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
+       while (nrpages > 0) {
+               if (after_paging_init)
+                       __late_set_fixmap(idx, phys_addr, prot);
+               else
+                       __early_set_fixmap(idx, phys_addr, prot);
+               phys_addr += PAGE_SIZE;
+               --idx;
+               --nrpages;
+       }
+       WARN(early_ioremap_debug, "%s(%08llx, %08lx) [%d] => %08lx + %08lx\n",
+            __func__, (u64)phys_addr, size, slot, offset, slot_virt[slot]);
+
+       prev_map[slot] = (void __iomem *)(offset + slot_virt[slot]);
+       return prev_map[slot];
+}
+
+void __init early_iounmap(void __iomem *addr, unsigned long size)
+{
+       unsigned long virt_addr;
+       unsigned long offset;
+       unsigned int nrpages;
+       enum fixed_addresses idx;
+       int i, slot;
+
+       slot = -1;
+       for (i = 0; i < FIX_BTMAPS_SLOTS; i++) {
+               if (prev_map[i] == addr) {
+                       slot = i;
+                       break;
+               }
+       }
+
+       if (WARN(slot < 0, "early_iounmap(%p, %08lx) not found slot\n",
+                addr, size))
+               return;
+
+       if (WARN(prev_size[slot] != size,
+                "early_iounmap(%p, %08lx) [%d] size not consistent %08lx\n",
+                addr, size, slot, prev_size[slot]))
+               return;
+
+       WARN(early_ioremap_debug, "early_iounmap(%p, %08lx) [%d]\n",
+            addr, size, slot);
+
+       virt_addr = (unsigned long)addr;
+       if (WARN_ON(virt_addr < fix_to_virt(FIX_BTMAP_BEGIN)))
+               return;
+
+       offset = virt_addr & ~PAGE_MASK;
+       nrpages = PAGE_ALIGN(offset + size) >> PAGE_SHIFT;
+
+       idx = FIX_BTMAP_BEGIN - NR_FIX_BTMAPS*slot;
+       while (nrpages > 0) {
+               if (after_paging_init)
+                       __late_clear_fixmap(idx);
+               else
+                       __early_set_fixmap(idx, 0, FIXMAP_PAGE_CLEAR);
+               --idx;
+               --nrpages;
+       }
+       prev_map[slot] = NULL;
+}
+
+/* Remap an IO device */
+void __init __iomem *
+early_ioremap(resource_size_t phys_addr, unsigned long size)
+{
+       return __early_ioremap(phys_addr, size, FIXMAP_PAGE_IO);
+}
+
+/* Remap memory */
+void __init *
+early_memremap(resource_size_t phys_addr, unsigned long size)
+{
+       return (__force void *)__early_ioremap(phys_addr, size,
+                                              FIXMAP_PAGE_NORMAL);
+}
+#else /* CONFIG_MMU */
+
+void __init __iomem *
+early_ioremap(resource_size_t phys_addr, unsigned long size)
+{
+       return (__force void __iomem *)phys_addr;
+}
+
+/* Remap memory */
+void __init *
+early_memremap(resource_size_t phys_addr, unsigned long size)
+{
+       return (void *)phys_addr;
+}
+
+void __init early_iounmap(void __iomem *addr, unsigned long size)
+{
+}
+
+#endif /* CONFIG_MMU */
+
+
+void __init early_memunmap(void *addr, unsigned long size)
+{
+       early_iounmap((__force void __iomem *)addr, size);
+}
index 21781f1..27ebc0c 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/hardirq.h> /* for BUG_ON(!in_atomic()) only */
 #include <linux/memcontrol.h>
 #include <linux/cleancache.h>
+#include <linux/rmap.h>
 #include "internal.h"
 
 #define CREATE_TRACE_POINTS
@@ -562,7 +563,7 @@ static int __add_to_page_cache_locked(struct page *page,
        VM_BUG_ON_PAGE(!PageLocked(page), page);
        VM_BUG_ON_PAGE(PageSwapBacked(page), page);
 
-       error = mem_cgroup_cache_charge(page, current->mm,
+       error = mem_cgroup_charge_file(page, current->mm,
                                        gfp_mask & GFP_RECLAIM_MASK);
        if (error)
                return error;
@@ -1952,11 +1953,11 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        struct inode *inode = mapping->host;
        pgoff_t offset = vmf->pgoff;
        struct page *page;
-       pgoff_t size;
+       loff_t size;
        int ret = 0;
 
-       size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (offset >= size)
+       size = round_up(i_size_read(inode), PAGE_CACHE_SIZE);
+       if (offset >= size >> PAGE_CACHE_SHIFT)
                return VM_FAULT_SIGBUS;
 
        /*
@@ -2005,8 +2006,8 @@ retry_find:
         * Found the page and have a reference on it.
         * We must recheck i_size under page lock.
         */
-       size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-       if (unlikely(offset >= size)) {
+       size = round_up(i_size_read(inode), PAGE_CACHE_SIZE);
+       if (unlikely(offset >= size >> PAGE_CACHE_SHIFT)) {
                unlock_page(page);
                page_cache_release(page);
                return VM_FAULT_SIGBUS;
@@ -2064,6 +2065,78 @@ page_not_uptodate:
 }
 EXPORT_SYMBOL(filemap_fault);
 
+void filemap_map_pages(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct radix_tree_iter iter;
+       void **slot;
+       struct file *file = vma->vm_file;
+       struct address_space *mapping = file->f_mapping;
+       loff_t size;
+       struct page *page;
+       unsigned long address = (unsigned long) vmf->virtual_address;
+       unsigned long addr;
+       pte_t *pte;
+
+       rcu_read_lock();
+       radix_tree_for_each_slot(slot, &mapping->page_tree, &iter, vmf->pgoff) {
+               if (iter.index > vmf->max_pgoff)
+                       break;
+repeat:
+               page = radix_tree_deref_slot(slot);
+               if (unlikely(!page))
+                       goto next;
+               if (radix_tree_exception(page)) {
+                       if (radix_tree_deref_retry(page))
+                               break;
+                       else
+                               goto next;
+               }
+
+               if (!page_cache_get_speculative(page))
+                       goto repeat;
+
+               /* Has the page moved? */
+               if (unlikely(page != *slot)) {
+                       page_cache_release(page);
+                       goto repeat;
+               }
+
+               if (!PageUptodate(page) ||
+                               PageReadahead(page) ||
+                               PageHWPoison(page))
+                       goto skip;
+               if (!trylock_page(page))
+                       goto skip;
+
+               if (page->mapping != mapping || !PageUptodate(page))
+                       goto unlock;
+
+               size = round_up(i_size_read(mapping->host), PAGE_CACHE_SIZE);
+               if (page->index >= size >> PAGE_CACHE_SHIFT)
+                       goto unlock;
+
+               pte = vmf->pte + page->index - vmf->pgoff;
+               if (!pte_none(*pte))
+                       goto unlock;
+
+               if (file->f_ra.mmap_miss > 0)
+                       file->f_ra.mmap_miss--;
+               addr = address + (page->index - vmf->pgoff) * PAGE_SIZE;
+               do_set_pte(vma, addr, page, pte, false, false);
+               unlock_page(page);
+               goto next;
+unlock:
+               unlock_page(page);
+skip:
+               page_cache_release(page);
+next:
+               if (iter.index == vmf->max_pgoff)
+                       break;
+       }
+       rcu_read_unlock();
+}
+EXPORT_SYMBOL(filemap_map_pages);
+
 int filemap_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct page *page = vmf->page;
@@ -2093,6 +2166,7 @@ EXPORT_SYMBOL(filemap_page_mkwrite);
 
 const struct vm_operations_struct generic_file_vm_ops = {
        .fault          = filemap_fault,
+       .map_pages      = filemap_map_pages,
        .page_mkwrite   = filemap_page_mkwrite,
        .remap_pages    = generic_file_remap_pages,
 };
index 6ac89e9..64635f5 100644 (file)
@@ -827,7 +827,7 @@ int do_huge_pmd_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
                count_vm_event(THP_FAULT_FALLBACK);
                return VM_FAULT_FALLBACK;
        }
-       if (unlikely(mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))) {
+       if (unlikely(mem_cgroup_charge_anon(page, mm, GFP_KERNEL))) {
                put_page(page);
                count_vm_event(THP_FAULT_FALLBACK);
                return VM_FAULT_FALLBACK;
@@ -968,7 +968,7 @@ static int do_huge_pmd_wp_page_fallback(struct mm_struct *mm,
                                               __GFP_OTHER_NODE,
                                               vma, address, page_to_nid(page));
                if (unlikely(!pages[i] ||
-                            mem_cgroup_newpage_charge(pages[i], mm,
+                            mem_cgroup_charge_anon(pages[i], mm,
                                                       GFP_KERNEL))) {
                        if (pages[i])
                                put_page(pages[i]);
@@ -1101,7 +1101,7 @@ alloc:
                goto out;
        }
 
-       if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))) {
+       if (unlikely(mem_cgroup_charge_anon(new_page, mm, GFP_KERNEL))) {
                put_page(new_page);
                if (page) {
                        split_huge_page(page);
@@ -1891,17 +1891,22 @@ out:
 int hugepage_madvise(struct vm_area_struct *vma,
                     unsigned long *vm_flags, int advice)
 {
-       struct mm_struct *mm = vma->vm_mm;
-
        switch (advice) {
        case MADV_HUGEPAGE:
+#ifdef CONFIG_S390
+               /*
+                * qemu blindly sets MADV_HUGEPAGE on all allocations, but s390
+                * can't handle this properly after s390_enable_sie, so we simply
+                * ignore the madvise to prevent qemu from causing a SIGSEGV.
+                */
+               if (mm_has_pgste(vma->vm_mm))
+                       return 0;
+#endif
                /*
                 * Be somewhat over-protective like KSM for now!
                 */
                if (*vm_flags & (VM_HUGEPAGE | VM_NO_THP))
                        return -EINVAL;
-               if (mm->def_flags & VM_NOHUGEPAGE)
-                       return -EINVAL;
                *vm_flags &= ~VM_NOHUGEPAGE;
                *vm_flags |= VM_HUGEPAGE;
                /*
@@ -2354,7 +2359,7 @@ static void collapse_huge_page(struct mm_struct *mm,
        if (!new_page)
                return;
 
-       if (unlikely(mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL)))
+       if (unlikely(mem_cgroup_charge_anon(new_page, mm, GFP_KERNEL)))
                return;
 
        /*
index 7c02b9d..dd30f22 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/nodemask.h>
 #include <linux/pagemap.h>
 #include <linux/mempolicy.h>
+#include <linux/compiler.h>
 #include <linux/cpuset.h>
 #include <linux/mutex.h>
 #include <linux/bootmem.h>
@@ -1535,6 +1536,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
        while (min_count < persistent_huge_pages(h)) {
                if (!free_pool_huge_page(h, nodes_allowed, 0))
                        break;
+               cond_resched_lock(&hugetlb_lock);
        }
        while (count < persistent_huge_pages(h)) {
                if (!adjust_pool_surplus(h, nodes_allowed, 1))
@@ -2690,7 +2692,8 @@ retry_avoidcopy:
                                BUG_ON(huge_pte_none(pte));
                                spin_lock(ptl);
                                ptep = huge_pte_offset(mm, address & huge_page_mask(h));
-                               if (likely(pte_same(huge_ptep_get(ptep), pte)))
+                               if (likely(ptep &&
+                                          pte_same(huge_ptep_get(ptep), pte)))
                                        goto retry_avoidcopy;
                                /*
                                 * race occurs while re-acquiring page table
@@ -2734,7 +2737,7 @@ retry_avoidcopy:
         */
        spin_lock(ptl);
        ptep = huge_pte_offset(mm, address & huge_page_mask(h));
-       if (likely(pte_same(huge_ptep_get(ptep), pte))) {
+       if (likely(ptep && pte_same(huge_ptep_get(ptep), pte))) {
                ClearPagePrivate(new_page);
 
                /* Break COW */
@@ -2896,8 +2899,7 @@ retry:
        if (anon_rmap) {
                ClearPagePrivate(page);
                hugepage_add_new_anon_rmap(page, vma, address);
-       }
-       else
+       } else
                page_dup_rmap(page);
        new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE)
                                && (vma->vm_flags & VM_SHARED)));
@@ -3185,6 +3187,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
        BUG_ON(address >= end);
        flush_cache_range(vma, address, end);
 
+       mmu_notifier_invalidate_range_start(mm, start, end);
        mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex);
        for (; address < end; address += huge_page_size(h)) {
                spinlock_t *ptl;
@@ -3214,6 +3217,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
         */
        flush_tlb_range(vma, start, end);
        mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
+       mmu_notifier_invalidate_range_end(mm, start, end);
 
        return pages << h->order;
 }
@@ -3518,7 +3522,7 @@ follow_huge_pud(struct mm_struct *mm, unsigned long address,
 #else /* !CONFIG_ARCH_WANT_GENERAL_HUGETLB */
 
 /* Can be overriden by architectures */
-__attribute__((weak)) struct page *
+struct page * __weak
 follow_huge_pud(struct mm_struct *mm, unsigned long address,
               pud_t *pud, int write)
 {
index 29e1e76..07b6736 100644 (file)
@@ -11,6 +11,7 @@
 #ifndef __MM_INTERNAL_H
 #define __MM_INTERNAL_H
 
+#include <linux/fs.h>
 #include <linux/mm.h>
 
 void free_pgtables(struct mmu_gather *tlb, struct vm_area_struct *start_vma,
@@ -21,6 +22,20 @@ static inline void set_page_count(struct page *page, int v)
        atomic_set(&page->_count, v);
 }
 
+extern int __do_page_cache_readahead(struct address_space *mapping,
+               struct file *filp, pgoff_t offset, unsigned long nr_to_read,
+               unsigned long lookahead_size);
+
+/*
+ * Submit IO for the read-ahead request in file_ra_state.
+ */
+static inline unsigned long ra_submit(struct file_ra_state *ra,
+               struct address_space *mapping, struct file *filp)
+{
+       return __do_page_cache_readahead(mapping, filp,
+                                       ra->start, ra->size, ra->async_size);
+}
+
 /*
  * Turn a non-refcounted page (->_count == 0) into refcounted with
  * a count of one.
@@ -370,5 +385,6 @@ unsigned long reclaim_clean_pages_from_list(struct zone *zone,
 #define ALLOC_HIGH             0x20 /* __GFP_HIGH set */
 #define ALLOC_CPUSET           0x40 /* check for correct cpuset */
 #define ALLOC_CMA              0x80 /* allow allocations from CMA areas */
+#define ALLOC_FAIR             0x100 /* fair zone allocation */
 
 #endif /* __MM_INTERNAL_H */
index 7fe5354..e9d6ca9 100644 (file)
@@ -1253,7 +1253,7 @@ phys_addr_t __init memblock_mem_size(unsigned long limit_pfn)
                pages += end_pfn - start_pfn;
        }
 
-       return (phys_addr_t)pages << PAGE_SHIFT;
+       return PFN_PHYS(pages);
 }
 
 /* lowest address */
@@ -1271,16 +1271,14 @@ phys_addr_t __init_memblock memblock_end_of_DRAM(void)
 
 void __init memblock_enforce_memory_limit(phys_addr_t limit)
 {
-       unsigned long i;
        phys_addr_t max_addr = (phys_addr_t)ULLONG_MAX;
+       struct memblock_region *r;
 
        if (!limit)
                return;
 
        /* find out max address */
-       for (i = 0; i < memblock.memory.cnt; i++) {
-               struct memblock_region *r = &memblock.memory.regions[i];
-
+       for_each_memblock(memory, r) {
                if (limit <= r->size) {
                        max_addr = r->base + limit;
                        break;
@@ -1326,7 +1324,7 @@ int __init_memblock memblock_search_pfn_nid(unsigned long pfn,
                         unsigned long *start_pfn, unsigned long *end_pfn)
 {
        struct memblock_type *type = &memblock.memory;
-       int mid = memblock_search(type, (phys_addr_t)pfn << PAGE_SHIFT);
+       int mid = memblock_search(type, PFN_PHYS(pfn));
 
        if (mid == -1)
                return -1;
@@ -1379,13 +1377,12 @@ int __init_memblock memblock_is_region_reserved(phys_addr_t base, phys_addr_t si
 
 void __init_memblock memblock_trim_memory(phys_addr_t align)
 {
-       int i;
        phys_addr_t start, end, orig_start, orig_end;
-       struct memblock_type *mem = &memblock.memory;
+       struct memblock_region *r;
 
-       for (i = 0; i < mem->cnt; i++) {
-               orig_start = mem->regions[i].base;
-               orig_end = mem->regions[i].base + mem->regions[i].size;
+       for_each_memblock(memory, r) {
+               orig_start = r->base;
+               orig_end = r->base + r->size;
                start = round_up(orig_start, align);
                end = round_down(orig_end, align);
 
@@ -1393,11 +1390,12 @@ void __init_memblock memblock_trim_memory(phys_addr_t align)
                        continue;
 
                if (start < end) {
-                       mem->regions[i].base = start;
-                       mem->regions[i].size = end - start;
+                       r->base = start;
+                       r->size = end - start;
                } else {
-                       memblock_remove_region(mem, i);
-                       i--;
+                       memblock_remove_region(&memblock.memory,
+                                              r - memblock.memory.regions);
+                       r--;
                }
        }
 }
index dcc8153..29501f0 100644 (file)
@@ -921,8 +921,6 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
                                         struct page *page,
                                         bool anon, int nr_pages)
 {
-       preempt_disable();
-
        /*
         * Here, RSS means 'mapped anon' and anon's SwapCache. Shmem/tmpfs is
         * counted as CACHE even if it's on ANON LRU.
@@ -947,8 +945,6 @@ static void mem_cgroup_charge_statistics(struct mem_cgroup *memcg,
        }
 
        __this_cpu_add(memcg->stat->nr_page_events, nr_pages);
-
-       preempt_enable();
 }
 
 unsigned long
@@ -1075,22 +1071,15 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
        return mem_cgroup_from_css(task_css(p, memory_cgrp_id));
 }
 
-struct mem_cgroup *try_get_mem_cgroup_from_mm(struct mm_struct *mm)
+static struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
 {
        struct mem_cgroup *memcg = NULL;
 
-       if (!mm)
-               return NULL;
-       /*
-        * Because we have no locks, mm->owner's may be being moved to other
-        * cgroup. We use css_tryget() here even if this looks
-        * pessimistic (rather than adding locks here).
-        */
        rcu_read_lock();
        do {
                memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
                if (unlikely(!memcg))
-                       break;
+                       memcg = root_mem_cgroup;
        } while (!css_tryget(&memcg->css));
        rcu_read_unlock();
        return memcg;
@@ -1486,7 +1475,7 @@ bool task_in_mem_cgroup(struct task_struct *task,
 
        p = find_lock_task_mm(task);
        if (p) {
-               curr = try_get_mem_cgroup_from_mm(p->mm);
+               curr = get_mem_cgroup_from_mm(p->mm);
                task_unlock(p);
        } else {
                /*
@@ -1500,8 +1489,6 @@ bool task_in_mem_cgroup(struct task_struct *task,
                        css_get(&curr->css);
                rcu_read_unlock();
        }
-       if (!curr)
-               return false;
        /*
         * We should check use_hierarchy of "memcg" not "curr". Because checking
         * use_hierarchy of "curr" here make this function true if hierarchy is
@@ -2588,7 +2575,7 @@ static int memcg_cpu_hotplug_callback(struct notifier_block *nb,
 }
 
 
-/* See __mem_cgroup_try_charge() for details */
+/* See mem_cgroup_try_charge() for details */
 enum {
        CHARGE_OK,              /* success */
        CHARGE_RETRY,           /* need to retry but retry is not bad */
@@ -2661,45 +2648,34 @@ static int mem_cgroup_do_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
        return CHARGE_NOMEM;
 }
 
-/*
- * __mem_cgroup_try_charge() does
- * 1. detect memcg to be charged against from passed *mm and *ptr,
- * 2. update res_counter
- * 3. call memory reclaim if necessary.
- *
- * In some special case, if the task is fatal, fatal_signal_pending() or
- * has TIF_MEMDIE, this function returns -EINTR while writing root_mem_cgroup
- * to *ptr. There are two reasons for this. 1: fatal threads should quit as soon
- * as possible without any hazards. 2: all pages should have a valid
- * pc->mem_cgroup. If mm is NULL and the caller doesn't pass a valid memcg
- * pointer, that is treated as a charge to root_mem_cgroup.
- *
- * So __mem_cgroup_try_charge() will return
- *  0       ...  on success, filling *ptr with a valid memcg pointer.
- *  -ENOMEM ...  charge failure because of resource limits.
- *  -EINTR  ...  if thread is fatal. *ptr is filled with root_mem_cgroup.
+/**
+ * mem_cgroup_try_charge - try charging a memcg
+ * @memcg: memcg to charge
+ * @nr_pages: number of pages to charge
+ * @oom: trigger OOM if reclaim fails
  *
- * Unlike the exported interface, an "oom" parameter is added. if oom==true,
- * the oom-killer can be invoked.
+ * Returns 0 if @memcg was charged successfully, -EINTR if the charge
+ * was bypassed to root_mem_cgroup, and -ENOMEM if the charge failed.
  */
-static int __mem_cgroup_try_charge(struct mm_struct *mm,
-                                  gfp_t gfp_mask,
-                                  unsigned int nr_pages,
-                                  struct mem_cgroup **ptr,
-                                  bool oom)
+static int mem_cgroup_try_charge(struct mem_cgroup *memcg,
+                                gfp_t gfp_mask,
+                                unsigned int nr_pages,
+                                bool oom)
 {
        unsigned int batch = max(CHARGE_BATCH, nr_pages);
        int nr_oom_retries = MEM_CGROUP_RECLAIM_RETRIES;
-       struct mem_cgroup *memcg = NULL;
        int ret;
 
+       if (mem_cgroup_is_root(memcg))
+               goto done;
        /*
-        * Unlike gloval-vm's OOM-kill, we're not in memory shortage
-        * in system level. So, allow to go ahead dying process in addition to
-        * MEMDIE process.
+        * Unlike in global OOM situations, memcg is not in a physical
+        * memory shortage.  Allow dying and OOM-killed tasks to
+        * bypass the last charges so that they can exit quickly and
+        * free their memory.
         */
-       if (unlikely(test_thread_flag(TIF_MEMDIE)
-                    || fatal_signal_pending(current)))
+       if (unlikely(test_thread_flag(TIF_MEMDIE) ||
+                    fatal_signal_pending(current)))
                goto bypass;
 
        if (unlikely(task_in_memcg_oom(current)))
@@ -2707,73 +2683,16 @@ static int __mem_cgroup_try_charge(struct mm_struct *mm,
 
        if (gfp_mask & __GFP_NOFAIL)
                oom = false;
-
-       /*
-        * We always charge the cgroup the mm_struct belongs to.
-        * The mm_struct's mem_cgroup changes on task migration if the
-        * thread group leader migrates. It's possible that mm is not
-        * set, if so charge the root memcg (happens for pagecache usage).
-        */
-       if (!*ptr && !mm)
-               *ptr = root_mem_cgroup;
 again:
-       if (*ptr) { /* css should be a valid one */
-               memcg = *ptr;
-               if (mem_cgroup_is_root(memcg))
-                       goto done;
-               if (consume_stock(memcg, nr_pages))
-                       goto done;
-               css_get(&memcg->css);
-       } else {
-               struct task_struct *p;
-
-               rcu_read_lock();
-               p = rcu_dereference(mm->owner);
-               /*
-                * Because we don't have task_lock(), "p" can exit.
-                * In that case, "memcg" can point to root or p can be NULL with
-                * race with swapoff. Then, we have small risk of mis-accouning.
-                * But such kind of mis-account by race always happens because
-                * we don't have cgroup_mutex(). It's overkill and we allo that
-                * small race, here.
-                * (*) swapoff at el will charge against mm-struct not against
-                * task-struct. So, mm->owner can be NULL.
-                */
-               memcg = mem_cgroup_from_task(p);
-               if (!memcg)
-                       memcg = root_mem_cgroup;
-               if (mem_cgroup_is_root(memcg)) {
-                       rcu_read_unlock();
-                       goto done;
-               }
-               if (consume_stock(memcg, nr_pages)) {
-                       /*
-                        * It seems dagerous to access memcg without css_get().
-                        * But considering how consume_stok works, it's not
-                        * necessary. If consume_stock success, some charges
-                        * from this memcg are cached on this cpu. So, we
-                        * don't need to call css_get()/css_tryget() before
-                        * calling consume_stock().
-                        */
-                       rcu_read_unlock();
-                       goto done;
-               }
-               /* after here, we may be blocked. we need to get refcnt */
-               if (!css_tryget(&memcg->css)) {
-                       rcu_read_unlock();
-                       goto again;
-               }
-               rcu_read_unlock();
-       }
+       if (consume_stock(memcg, nr_pages))
+               goto done;
 
        do {
                bool invoke_oom = oom && !nr_oom_retries;
 
                /* If killed, bypass charge */
-               if (fatal_signal_pending(current)) {
-                       css_put(&memcg->css);
+               if (fatal_signal_pending(current))
                        goto bypass;
-               }
 
                ret = mem_cgroup_do_charge(memcg, gfp_mask, batch,
                                           nr_pages, invoke_oom);
@@ -2782,17 +2701,12 @@ again:
                        break;
                case CHARGE_RETRY: /* not in OOM situation but retry */
                        batch = nr_pages;
-                       css_put(&memcg->css);
-                       memcg = NULL;
                        goto again;
                case CHARGE_WOULDBLOCK: /* !__GFP_WAIT */
-                       css_put(&memcg->css);
                        goto nomem;
                case CHARGE_NOMEM: /* OOM routine works */
-                       if (!oom || invoke_oom) {
-                               css_put(&memcg->css);
+                       if (!oom || invoke_oom)
                                goto nomem;
-                       }
                        nr_oom_retries--;
                        break;
                }
@@ -2800,20 +2714,44 @@ again:
 
        if (batch > nr_pages)
                refill_stock(memcg, batch - nr_pages);
-       css_put(&memcg->css);
 done:
-       *ptr = memcg;
        return 0;
 nomem:
-       if (!(gfp_mask & __GFP_NOFAIL)) {
-               *ptr = NULL;
+       if (!(gfp_mask & __GFP_NOFAIL))
                return -ENOMEM;
-       }
 bypass:
-       *ptr = root_mem_cgroup;
        return -EINTR;
 }
 
+/**
+ * mem_cgroup_try_charge_mm - try charging a mm
+ * @mm: mm_struct to charge
+ * @nr_pages: number of pages to charge
+ * @oom: trigger OOM if reclaim fails
+ *
+ * Returns the charged mem_cgroup associated with the given mm_struct or
+ * NULL the charge failed.
+ */
+static struct mem_cgroup *mem_cgroup_try_charge_mm(struct mm_struct *mm,
+                                gfp_t gfp_mask,
+                                unsigned int nr_pages,
+                                bool oom)
+
+{
+       struct mem_cgroup *memcg;
+       int ret;
+
+       memcg = get_mem_cgroup_from_mm(mm);
+       ret = mem_cgroup_try_charge(memcg, gfp_mask, nr_pages, oom);
+       css_put(&memcg->css);
+       if (ret == -EINTR)
+               memcg = root_mem_cgroup;
+       else if (ret)
+               memcg = NULL;
+
+       return memcg;
+}
+
 /*
  * Somemtimes we have to undo a charge we got by try_charge().
  * This function is for that and do uncharge, put css's refcnt.
@@ -3009,20 +2947,17 @@ static int mem_cgroup_slabinfo_read(struct seq_file *m, void *v)
 static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size)
 {
        struct res_counter *fail_res;
-       struct mem_cgroup *_memcg;
        int ret = 0;
 
        ret = res_counter_charge(&memcg->kmem, size, &fail_res);
        if (ret)
                return ret;
 
-       _memcg = memcg;
-       ret = __mem_cgroup_try_charge(NULL, gfp, size >> PAGE_SHIFT,
-                                     &_memcg, oom_gfp_allowed(gfp));
-
+       ret = mem_cgroup_try_charge(memcg, gfp, size >> PAGE_SHIFT,
+                                   oom_gfp_allowed(gfp));
        if (ret == -EINTR)  {
                /*
-                * __mem_cgroup_try_charge() chosed to bypass to root due to
+                * mem_cgroup_try_charge() chosed to bypass to root due to
                 * OOM kill or fatal signal.  Since our only options are to
                 * either fail the allocation or charge it to this cgroup, do
                 * it as a temporary condition. But we can't fail. From a
@@ -3032,7 +2967,7 @@ static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size)
                 *
                 * This condition will only trigger if the task entered
                 * memcg_charge_kmem in a sane state, but was OOM-killed during
-                * __mem_cgroup_try_charge() above. Tasks that were already
+                * mem_cgroup_try_charge() above. Tasks that were already
                 * dying when the allocation triggers should have been already
                 * directed to the root cgroup in memcontrol.h
                 */
@@ -3159,6 +3094,29 @@ int memcg_update_cache_size(struct kmem_cache *s, int num_groups)
        return 0;
 }
 
+char *memcg_create_cache_name(struct mem_cgroup *memcg,
+                             struct kmem_cache *root_cache)
+{
+       static char *buf = NULL;
+
+       /*
+        * We need a mutex here to protect the shared buffer. Since this is
+        * expected to be called only on cache creation, we can employ the
+        * slab_mutex for that purpose.
+        */
+       lockdep_assert_held(&slab_mutex);
+
+       if (!buf) {
+               buf = kmalloc(NAME_MAX + 1, GFP_KERNEL);
+               if (!buf)
+                       return NULL;
+       }
+
+       cgroup_name(memcg->css.cgroup, buf, NAME_MAX + 1);
+       return kasprintf(GFP_KERNEL, "%s(%d:%s)", root_cache->name,
+                        memcg_cache_id(memcg), buf);
+}
+
 int memcg_alloc_cache_params(struct mem_cgroup *memcg, struct kmem_cache *s,
                             struct kmem_cache *root_cache)
 {
@@ -3182,6 +3140,7 @@ int memcg_alloc_cache_params(struct mem_cgroup *memcg, struct kmem_cache *s,
                s->memcg_params->root_cache = root_cache;
                INIT_WORK(&s->memcg_params->destroy,
                                kmem_cache_destroy_work_func);
+               css_get(&memcg->css);
        } else
                s->memcg_params->is_root_cache = true;
 
@@ -3190,6 +3149,10 @@ int memcg_alloc_cache_params(struct mem_cgroup *memcg, struct kmem_cache *s,
 
 void memcg_free_cache_params(struct kmem_cache *s)
 {
+       if (!s->memcg_params)
+               return;
+       if (!s->memcg_params->is_root_cache)
+               css_put(&s->memcg_params->memcg->css);
        kfree(s->memcg_params);
 }
 
@@ -3212,9 +3175,6 @@ void memcg_register_cache(struct kmem_cache *s)
        memcg = s->memcg_params->memcg;
        id = memcg_cache_id(memcg);
 
-       css_get(&memcg->css);
-
-
        /*
         * Since readers won't lock (see cache_from_memcg_idx()), we need a
         * barrier here to ensure nobody will see the kmem_cache partially
@@ -3263,10 +3223,8 @@ void memcg_unregister_cache(struct kmem_cache *s)
         * after removing it from the memcg_slab_caches list, otherwise we can
         * fail to convert memcg_params_to_cache() while traversing the list.
         */
-       VM_BUG_ON(!root->memcg_params->memcg_caches[id]);
+       VM_BUG_ON(root->memcg_params->memcg_caches[id] != s);
        root->memcg_params->memcg_caches[id] = NULL;
-
-       css_put(&memcg->css);
 }
 
 /*
@@ -3363,55 +3321,10 @@ void mem_cgroup_destroy_cache(struct kmem_cache *cachep)
        schedule_work(&cachep->memcg_params->destroy);
 }
 
-static struct kmem_cache *memcg_create_kmem_cache(struct mem_cgroup *memcg,
-                                                 struct kmem_cache *s)
-{
-       struct kmem_cache *new = NULL;
-       static char *tmp_path = NULL, *tmp_name = NULL;
-       static DEFINE_MUTEX(mutex);     /* protects tmp_name */
-
-       BUG_ON(!memcg_can_account_kmem(memcg));
-
-       mutex_lock(&mutex);
-       /*
-        * kmem_cache_create_memcg duplicates the given name and
-        * cgroup_name for this name requires RCU context.
-        * This static temporary buffer is used to prevent from
-        * pointless shortliving allocation.
-        */
-       if (!tmp_path || !tmp_name) {
-               if (!tmp_path)
-                       tmp_path = kmalloc(PATH_MAX, GFP_KERNEL);
-               if (!tmp_name)
-                       tmp_name = kmalloc(NAME_MAX + 1, GFP_KERNEL);
-               if (!tmp_path || !tmp_name)
-                       goto out;
-       }
-
-       cgroup_name(memcg->css.cgroup, tmp_name, NAME_MAX + 1);
-       snprintf(tmp_path, PATH_MAX, "%s(%d:%s)", s->name,
-                memcg_cache_id(memcg), tmp_name);
-
-       new = kmem_cache_create_memcg(memcg, tmp_path, s->object_size, s->align,
-                                     (s->flags & ~SLAB_PANIC), s->ctor, s);
-       if (new)
-               new->allocflags |= __GFP_KMEMCG;
-       else
-               new = s;
-out:
-       mutex_unlock(&mutex);
-       return new;
-}
-
-void kmem_cache_destroy_memcg_children(struct kmem_cache *s)
+int __kmem_cache_destroy_memcg_children(struct kmem_cache *s)
 {
        struct kmem_cache *c;
-       int i;
-
-       if (!s->memcg_params)
-               return;
-       if (!s->memcg_params->is_root_cache)
-               return;
+       int i, failed = 0;
 
        /*
         * If the cache is being destroyed, we trust that there is no one else
@@ -3445,16 +3358,14 @@ void kmem_cache_destroy_memcg_children(struct kmem_cache *s)
                c->memcg_params->dead = false;
                cancel_work_sync(&c->memcg_params->destroy);
                kmem_cache_destroy(c);
+
+               if (cache_from_memcg_idx(s, i))
+                       failed++;
        }
        mutex_unlock(&activate_kmem_mutex);
+       return failed;
 }
 
-struct create_work {
-       struct mem_cgroup *memcg;
-       struct kmem_cache *cachep;
-       struct work_struct work;
-};
-
 static void mem_cgroup_destroy_all_caches(struct mem_cgroup *memcg)
 {
        struct kmem_cache *cachep;
@@ -3472,13 +3383,20 @@ static void mem_cgroup_destroy_all_caches(struct mem_cgroup *memcg)
        mutex_unlock(&memcg->slab_caches_mutex);
 }
 
+struct create_work {
+       struct mem_cgroup *memcg;
+       struct kmem_cache *cachep;
+       struct work_struct work;
+};
+
 static void memcg_create_cache_work_func(struct work_struct *w)
 {
-       struct create_work *cw;
+       struct create_work *cw = container_of(w, struct create_work, work);
+       struct mem_cgroup *memcg = cw->memcg;
+       struct kmem_cache *cachep = cw->cachep;
 
-       cw = container_of(w, struct create_work, work);
-       memcg_create_kmem_cache(cw->memcg, cw->cachep);
-       css_put(&cw->memcg->css);
+       kmem_cache_create_memcg(memcg, cachep);
+       css_put(&memcg->css);
        kfree(cw);
 }
 
@@ -3637,15 +3555,7 @@ __memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **_memcg, int order)
        if (!current->mm || current->memcg_kmem_skip_account)
                return true;
 
-       memcg = try_get_mem_cgroup_from_mm(current->mm);
-
-       /*
-        * very rare case described in mem_cgroup_from_task. Unfortunately there
-        * isn't much we can do without complicating this too much, and it would
-        * be gfp-dependent anyway. Just let it go
-        */
-       if (unlikely(!memcg))
-               return true;
+       memcg = get_mem_cgroup_from_mm(current->mm);
 
        if (!memcg_can_account_kmem(memcg)) {
                css_put(&memcg->css);
@@ -3748,19 +3658,6 @@ void mem_cgroup_split_huge_fixup(struct page *head)
 }
 #endif /* CONFIG_TRANSPARENT_HUGEPAGE */
 
-static inline
-void mem_cgroup_move_account_page_stat(struct mem_cgroup *from,
-                                       struct mem_cgroup *to,
-                                       unsigned int nr_pages,
-                                       enum mem_cgroup_stat_index idx)
-{
-       /* Update stat data for mem_cgroup */
-       preempt_disable();
-       __this_cpu_sub(from->stat->count[idx], nr_pages);
-       __this_cpu_add(to->stat->count[idx], nr_pages);
-       preempt_enable();
-}
-
 /**
  * mem_cgroup_move_account - move account of the page
  * @page: the page
@@ -3806,13 +3703,19 @@ static int mem_cgroup_move_account(struct page *page,
 
        move_lock_mem_cgroup(from, &flags);
 
-       if (!anon && page_mapped(page))
-               mem_cgroup_move_account_page_stat(from, to, nr_pages,
-                       MEM_CGROUP_STAT_FILE_MAPPED);
+       if (!anon && page_mapped(page)) {
+               __this_cpu_sub(from->stat->count[MEM_CGROUP_STAT_FILE_MAPPED],
+                              nr_pages);
+               __this_cpu_add(to->stat->count[MEM_CGROUP_STAT_FILE_MAPPED],
+                              nr_pages);
+       }
 
-       if (PageWriteback(page))
-               mem_cgroup_move_account_page_stat(from, to, nr_pages,
-                       MEM_CGROUP_STAT_WRITEBACK);
+       if (PageWriteback(page)) {
+               __this_cpu_sub(from->stat->count[MEM_CGROUP_STAT_WRITEBACK],
+                              nr_pages);
+               __this_cpu_add(to->stat->count[MEM_CGROUP_STAT_WRITEBACK],
+                              nr_pages);
+       }
 
        mem_cgroup_charge_statistics(from, page, anon, -nr_pages);
 
@@ -3898,19 +3801,19 @@ out:
        return ret;
 }
 
-/*
- * Charge the memory controller for page usage.
- * Return
- * 0 if the charge was successful
- * < 0 if the cgroup is over its limit
- */
-static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
-                               gfp_t gfp_mask, enum charge_type ctype)
+int mem_cgroup_charge_anon(struct page *page,
+                             struct mm_struct *mm, gfp_t gfp_mask)
 {
-       struct mem_cgroup *memcg = NULL;
        unsigned int nr_pages = 1;
+       struct mem_cgroup *memcg;
        bool oom = true;
-       int ret;
+
+       if (mem_cgroup_disabled())
+               return 0;
+
+       VM_BUG_ON_PAGE(page_mapped(page), page);
+       VM_BUG_ON_PAGE(page->mapping && !PageAnon(page), page);
+       VM_BUG_ON(!mm);
 
        if (PageTransHuge(page)) {
                nr_pages <<= compound_order(page);
@@ -3922,25 +3825,14 @@ static int mem_cgroup_charge_common(struct page *page, struct mm_struct *mm,
                oom = false;
        }
 
-       ret = __mem_cgroup_try_charge(mm, gfp_mask, nr_pages, &memcg, oom);
-       if (ret == -ENOMEM)
-               return ret;
-       __mem_cgroup_commit_charge(memcg, page, nr_pages, ctype, false);
+       memcg = mem_cgroup_try_charge_mm(mm, gfp_mask, nr_pages, oom);
+       if (!memcg)
+               return -ENOMEM;
+       __mem_cgroup_commit_charge(memcg, page, nr_pages,
+                                  MEM_CGROUP_CHARGE_TYPE_ANON, false);
        return 0;
 }
 
-int mem_cgroup_newpage_charge(struct page *page,
-                             struct mm_struct *mm, gfp_t gfp_mask)
-{
-       if (mem_cgroup_disabled())
-               return 0;
-       VM_BUG_ON_PAGE(page_mapped(page), page);
-       VM_BUG_ON_PAGE(page->mapping && !PageAnon(page), page);
-       VM_BUG_ON(!mm);
-       return mem_cgroup_charge_common(page, mm, gfp_mask,
-                                       MEM_CGROUP_CHARGE_TYPE_ANON);
-}
-
 /*
  * While swap-in, try_charge -> commit or cancel, the page is locked.
  * And when try_charge() successfully returns, one refcnt to memcg without
@@ -3952,7 +3844,7 @@ static int __mem_cgroup_try_charge_swapin(struct mm_struct *mm,
                                          gfp_t mask,
                                          struct mem_cgroup **memcgp)
 {
-       struct mem_cgroup *memcg;
+       struct mem_cgroup *memcg = NULL;
        struct page_cgroup *pc;
        int ret;
 
@@ -3965,31 +3857,29 @@ static int __mem_cgroup_try_charge_swapin(struct mm_struct *mm,
         * in turn serializes uncharging.
         */
        if (PageCgroupUsed(pc))
-               return 0;
-       if (!do_swap_account)
-               goto charge_cur_mm;
-       memcg = try_get_mem_cgroup_from_page(page);
+               goto out;
+       if (do_swap_account)
+               memcg = try_get_mem_cgroup_from_page(page);
        if (!memcg)
-               goto charge_cur_mm;
-       *memcgp = memcg;
-       ret = __mem_cgroup_try_charge(NULL, mask, 1, memcgp, true);
+               memcg = get_mem_cgroup_from_mm(mm);
+       ret = mem_cgroup_try_charge(memcg, mask, 1, true);
        css_put(&memcg->css);
        if (ret == -EINTR)
-               ret = 0;
-       return ret;
-charge_cur_mm:
-       ret = __mem_cgroup_try_charge(mm, mask, 1, memcgp, true);
-       if (ret == -EINTR)
-               ret = 0;
-       return ret;
+               memcg = root_mem_cgroup;
+       else if (ret)
+               return ret;
+out:
+       *memcgp = memcg;
+       return 0;
 }
 
 int mem_cgroup_try_charge_swapin(struct mm_struct *mm, struct page *page,
                                 gfp_t gfp_mask, struct mem_cgroup **memcgp)
 {
-       *memcgp = NULL;
-       if (mem_cgroup_disabled())
+       if (mem_cgroup_disabled()) {
+               *memcgp = NULL;
                return 0;
+       }
        /*
         * A racing thread's fault, or swapoff, may have already
         * updated the pte, and even removed page from swap cache: in
@@ -3997,12 +3887,13 @@ int mem_cgroup_try_charge_swapin(struct mm_struct *mm, struct page *page,
         * there's also a KSM case which does need to charge the page.
         */
        if (!PageSwapCache(page)) {
-               int ret;
+               struct mem_cgroup *memcg;
 
-               ret = __mem_cgroup_try_charge(mm, gfp_mask, 1, memcgp, true);
-               if (ret == -EINTR)
-                       ret = 0;
-               return ret;
+               memcg = mem_cgroup_try_charge_mm(mm, gfp_mask, 1, true);
+               if (!memcg)
+                       return -ENOMEM;
+               *memcgp = memcg;
+               return 0;
        }
        return __mem_cgroup_try_charge_swapin(mm, page, gfp_mask, memcgp);
 }
@@ -4046,11 +3937,11 @@ void mem_cgroup_commit_charge_swapin(struct page *page,
                                          MEM_CGROUP_CHARGE_TYPE_ANON);
 }
 
-int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
+int mem_cgroup_charge_file(struct page *page, struct mm_struct *mm,
                                gfp_t gfp_mask)
 {
-       struct mem_cgroup *memcg = NULL;
        enum charge_type type = MEM_CGROUP_CHARGE_TYPE_CACHE;
+       struct mem_cgroup *memcg;
        int ret;
 
        if (mem_cgroup_disabled())
@@ -4058,15 +3949,28 @@ int mem_cgroup_cache_charge(struct page *page, struct mm_struct *mm,
        if (PageCompound(page))
                return 0;
 
-       if (!PageSwapCache(page))
-               ret = mem_cgroup_charge_common(page, mm, gfp_mask, type);
-       else { /* page is swapcache/shmem */
+       if (PageSwapCache(page)) { /* shmem */
                ret = __mem_cgroup_try_charge_swapin(mm, page,
                                                     gfp_mask, &memcg);
-               if (!ret)
-                       __mem_cgroup_commit_charge_swapin(page, memcg, type);
+               if (ret)
+                       return ret;
+               __mem_cgroup_commit_charge_swapin(page, memcg, type);
+               return 0;
        }
-       return ret;
+
+       /*
+        * Page cache insertions can happen without an actual mm
+        * context, e.g. during disk probing on boot.
+        */
+       if (unlikely(!mm))
+               memcg = root_mem_cgroup;
+       else {
+               memcg = mem_cgroup_try_charge_mm(mm, gfp_mask, 1, true);
+               if (!memcg)
+                       return -ENOMEM;
+       }
+       __mem_cgroup_commit_charge(memcg, page, 1, type, false);
+       return 0;
 }
 
 static void mem_cgroup_do_uncharge(struct mem_cgroup *memcg,
@@ -6678,8 +6582,7 @@ one_by_one:
                        batch_count = PRECHARGE_COUNT_AT_ONCE;
                        cond_resched();
                }
-               ret = __mem_cgroup_try_charge(NULL,
-                                       GFP_KERNEL, 1, &memcg, false);
+               ret = mem_cgroup_try_charge(memcg, GFP_KERNEL, 1, false);
                if (ret)
                        /* mem_cgroup_clear_mc() will do uncharge later */
                        return ret;
index 82c1e4c..d0f0bef 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/migrate.h>
 #include <linux/string.h>
 #include <linux/dma-debug.h>
+#include <linux/debugfs.h>
 
 #include <asm/io.h>
 #include <asm/pgalloc.h>
@@ -1320,9 +1321,9 @@ static void unmap_single_vma(struct mmu_gather *tlb,
                         * It is undesirable to test vma->vm_file as it
                         * should be non-null for valid hugetlb area.
                         * However, vm_file will be NULL in the error
-                        * cleanup path of do_mmap_pgoff. When
+                        * cleanup path of mmap_region. When
                         * hugetlbfs ->mmap method fails,
-                        * do_mmap_pgoff() nullifies vma->vm_file
+                        * mmap_region() nullifies vma->vm_file
                         * before calling this function to clean up.
                         * Since no pte has actually been setup, it is
                         * safe to do nothing in this case.
@@ -2781,7 +2782,7 @@ reuse:
                 */
                if (!page_mkwrite) {
                        wait_on_page_locked(dirty_page);
-                       set_page_dirty_balance(dirty_page, page_mkwrite);
+                       set_page_dirty_balance(dirty_page);
                        /* file_update_time outside page_lock */
                        if (vma->vm_file)
                                file_update_time(vma->vm_file);
@@ -2827,7 +2828,7 @@ gotten:
        }
        __SetPageUptodate(new_page);
 
-       if (mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL))
+       if (mem_cgroup_charge_anon(new_page, mm, GFP_KERNEL))
                goto oom_free_new;
 
        mmun_start  = address & PAGE_MASK;
@@ -3280,7 +3281,7 @@ static int do_anonymous_page(struct mm_struct *mm, struct vm_area_struct *vma,
         */
        __SetPageUptodate(page);
 
-       if (mem_cgroup_newpage_charge(page, mm, GFP_KERNEL))
+       if (mem_cgroup_charge_anon(page, mm, GFP_KERNEL))
                goto oom_free_page;
 
        entry = mk_pte(page, vma->vm_page_prot);
@@ -3342,7 +3343,22 @@ static int __do_fault(struct vm_area_struct *vma, unsigned long address,
        return ret;
 }
 
-static void do_set_pte(struct vm_area_struct *vma, unsigned long address,
+/**
+ * do_set_pte - setup new PTE entry for given page and add reverse page mapping.
+ *
+ * @vma: virtual memory area
+ * @address: user virtual address
+ * @page: page to map
+ * @pte: pointer to target page table entry
+ * @write: true, if new entry is writable
+ * @anon: true, if it's anonymous page
+ *
+ * Caller must hold page table lock relevant for @pte.
+ *
+ * Target users are page handler itself and implementations of
+ * vm_ops->map_pages.
+ */
+void do_set_pte(struct vm_area_struct *vma, unsigned long address,
                struct page *page, pte_t *pte, bool write, bool anon)
 {
        pte_t entry;
@@ -3366,6 +3382,105 @@ static void do_set_pte(struct vm_area_struct *vma, unsigned long address,
        update_mmu_cache(vma, address, pte);
 }
 
+#define FAULT_AROUND_ORDER 4
+
+#ifdef CONFIG_DEBUG_FS
+static unsigned int fault_around_order = FAULT_AROUND_ORDER;
+
+static int fault_around_order_get(void *data, u64 *val)
+{
+       *val = fault_around_order;
+       return 0;
+}
+
+static int fault_around_order_set(void *data, u64 val)
+{
+       BUILD_BUG_ON((1UL << FAULT_AROUND_ORDER) > PTRS_PER_PTE);
+       if (1UL << val > PTRS_PER_PTE)
+               return -EINVAL;
+       fault_around_order = val;
+       return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fault_around_order_fops,
+               fault_around_order_get, fault_around_order_set, "%llu\n");
+
+static int __init fault_around_debugfs(void)
+{
+       void *ret;
+
+       ret = debugfs_create_file("fault_around_order", 0644, NULL, NULL,
+                       &fault_around_order_fops);
+       if (!ret)
+               pr_warn("Failed to create fault_around_order in debugfs");
+       return 0;
+}
+late_initcall(fault_around_debugfs);
+
+static inline unsigned long fault_around_pages(void)
+{
+       return 1UL << fault_around_order;
+}
+
+static inline unsigned long fault_around_mask(void)
+{
+       return ~((1UL << (PAGE_SHIFT + fault_around_order)) - 1);
+}
+#else
+static inline unsigned long fault_around_pages(void)
+{
+       unsigned long nr_pages;
+
+       nr_pages = 1UL << FAULT_AROUND_ORDER;
+       BUILD_BUG_ON(nr_pages > PTRS_PER_PTE);
+       return nr_pages;
+}
+
+static inline unsigned long fault_around_mask(void)
+{
+       return ~((1UL << (PAGE_SHIFT + FAULT_AROUND_ORDER)) - 1);
+}
+#endif
+
+static void do_fault_around(struct vm_area_struct *vma, unsigned long address,
+               pte_t *pte, pgoff_t pgoff, unsigned int flags)
+{
+       unsigned long start_addr;
+       pgoff_t max_pgoff;
+       struct vm_fault vmf;
+       int off;
+
+       start_addr = max(address & fault_around_mask(), vma->vm_start);
+       off = ((address - start_addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1);
+       pte -= off;
+       pgoff -= off;
+
+       /*
+        *  max_pgoff is either end of page table or end of vma
+        *  or fault_around_pages() from pgoff, depending what is neast.
+        */
+       max_pgoff = pgoff - ((start_addr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) +
+               PTRS_PER_PTE - 1;
+       max_pgoff = min3(max_pgoff, vma_pages(vma) + vma->vm_pgoff - 1,
+                       pgoff + fault_around_pages() - 1);
+
+       /* Check if it makes any sense to call ->map_pages */
+       while (!pte_none(*pte)) {
+               if (++pgoff > max_pgoff)
+                       return;
+               start_addr += PAGE_SIZE;
+               if (start_addr >= vma->vm_end)
+                       return;
+               pte++;
+       }
+
+       vmf.virtual_address = (void __user *) start_addr;
+       vmf.pte = pte;
+       vmf.pgoff = pgoff;
+       vmf.max_pgoff = max_pgoff;
+       vmf.flags = flags;
+       vma->vm_ops->map_pages(vma, &vmf);
+}
+
 static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                unsigned long address, pmd_t *pmd,
                pgoff_t pgoff, unsigned int flags, pte_t orig_pte)
@@ -3373,7 +3488,20 @@ static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        struct page *fault_page;
        spinlock_t *ptl;
        pte_t *pte;
-       int ret;
+       int ret = 0;
+
+       /*
+        * Let's call ->map_pages() first and use ->fault() as fallback
+        * if page by the offset is not ready to be mapped (cold cache or
+        * something).
+        */
+       if (vma->vm_ops->map_pages) {
+               pte = pte_offset_map_lock(mm, pmd, address, &ptl);
+               do_fault_around(vma, address, pte, pgoff, flags);
+               if (!pte_same(*pte, orig_pte))
+                       goto unlock_out;
+               pte_unmap_unlock(pte, ptl);
+       }
 
        ret = __do_fault(vma, address, pgoff, flags, &fault_page);
        if (unlikely(ret & (VM_FAULT_ERROR | VM_FAULT_NOPAGE | VM_FAULT_RETRY)))
@@ -3387,8 +3515,9 @@ static int do_read_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                return ret;
        }
        do_set_pte(vma, address, fault_page, pte, false, false);
-       pte_unmap_unlock(pte, ptl);
        unlock_page(fault_page);
+unlock_out:
+       pte_unmap_unlock(pte, ptl);
        return ret;
 }
 
@@ -3408,7 +3537,7 @@ static int do_cow_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        if (!new_page)
                return VM_FAULT_OOM;
 
-       if (mem_cgroup_newpage_charge(new_page, mm, GFP_KERNEL)) {
+       if (mem_cgroup_charge_anon(new_page, mm, GFP_KERNEL)) {
                page_cache_release(new_page);
                return VM_FAULT_OOM;
        }
index e3ab028..78e1472 100644 (file)
@@ -795,36 +795,6 @@ static int mbind_range(struct mm_struct *mm, unsigned long start,
        return err;
 }
 
-/*
- * Update task->flags PF_MEMPOLICY bit: set iff non-default
- * mempolicy.  Allows more rapid checking of this (combined perhaps
- * with other PF_* flag bits) on memory allocation hot code paths.
- *
- * If called from outside this file, the task 'p' should -only- be
- * a newly forked child not yet visible on the task list, because
- * manipulating the task flags of a visible task is not safe.
- *
- * The above limitation is why this routine has the funny name
- * mpol_fix_fork_child_flag().
- *
- * It is also safe to call this with a task pointer of current,
- * which the static wrapper mpol_set_task_struct_flag() does,
- * for use within this file.
- */
-
-void mpol_fix_fork_child_flag(struct task_struct *p)
-{
-       if (p->mempolicy)
-               p->flags |= PF_MEMPOLICY;
-       else
-               p->flags &= ~PF_MEMPOLICY;
-}
-
-static void mpol_set_task_struct_flag(void)
-{
-       mpol_fix_fork_child_flag(current);
-}
-
 /* Set the process memory policy */
 static long do_set_mempolicy(unsigned short mode, unsigned short flags,
                             nodemask_t *nodes)
@@ -861,7 +831,6 @@ static long do_set_mempolicy(unsigned short mode, unsigned short flags,
        }
        old = current->mempolicy;
        current->mempolicy = new;
-       mpol_set_task_struct_flag();
        if (new && new->mode == MPOL_INTERLEAVE &&
            nodes_weight(new->v.nodes))
                current->il_next = first_node(new->v.nodes);
@@ -1782,21 +1751,18 @@ static unsigned interleave_nodes(struct mempolicy *policy)
 /*
  * Depending on the memory policy provide a node from which to allocate the
  * next slab entry.
- * @policy must be protected by freeing by the caller.  If @policy is
- * the current task's mempolicy, this protection is implicit, as only the
- * task can change it's policy.  The system default policy requires no
- * such protection.
  */
-unsigned slab_node(void)
+unsigned int mempolicy_slab_node(void)
 {
        struct mempolicy *policy;
+       int node = numa_mem_id();
 
        if (in_interrupt())
-               return numa_node_id();
+               return node;
 
        policy = current->mempolicy;
        if (!policy || policy->flags & MPOL_F_LOCAL)
-               return numa_node_id();
+               return node;
 
        switch (policy->mode) {
        case MPOL_PREFERRED:
@@ -1816,11 +1782,11 @@ unsigned slab_node(void)
                struct zonelist *zonelist;
                struct zone *zone;
                enum zone_type highest_zoneidx = gfp_zone(GFP_KERNEL);
-               zonelist = &NODE_DATA(numa_node_id())->node_zonelists[0];
+               zonelist = &NODE_DATA(node)->node_zonelists[0];
                (void)first_zones_zonelist(zonelist, highest_zoneidx,
                                                        &policy->v.nodes,
                                                        &zone);
-               return zone ? zone->node : numa_node_id();
+               return zone ? zone->node : node;
        }
 
        default:
index 659aa42..905434f 100644 (file)
@@ -304,9 +304,9 @@ void mempool_free(void *element, mempool_t *pool)
         * ensures that there will be frees which return elements to the
         * pool waking up the waiters.
         */
-       if (pool->curr_nr < pool->min_nr) {
+       if (unlikely(pool->curr_nr < pool->min_nr)) {
                spin_lock_irqsave(&pool->lock, flags);
-               if (pool->curr_nr < pool->min_nr) {
+               if (likely(pool->curr_nr < pool->min_nr)) {
                        add_element(pool, element);
                        spin_unlock_irqrestore(&pool->lock, flags);
                        wake_up(&pool->wait);
index 4e1a681..b1eb536 100644 (file)
@@ -79,6 +79,7 @@ void clear_page_mlock(struct page *page)
  */
 void mlock_vma_page(struct page *page)
 {
+       /* Serialize with page migration */
        BUG_ON(!PageLocked(page));
 
        if (!TestSetPageMlocked(page)) {
@@ -174,6 +175,7 @@ unsigned int munlock_vma_page(struct page *page)
        unsigned int nr_pages;
        struct zone *zone = page_zone(page);
 
+       /* For try_to_munlock() and to serialize with page migration */
        BUG_ON(!PageLocked(page));
 
        /*
index 46433e1..b1202cf 100644 (file)
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -10,6 +10,7 @@
 #include <linux/slab.h>
 #include <linux/backing-dev.h>
 #include <linux/mm.h>
+#include <linux/vmacache.h>
 #include <linux/shm.h>
 #include <linux/mman.h>
 #include <linux/pagemap.h>
@@ -681,8 +682,9 @@ __vma_unlink(struct mm_struct *mm, struct vm_area_struct *vma,
        prev->vm_next = next = vma->vm_next;
        if (next)
                next->vm_prev = prev;
-       if (mm->mmap_cache == vma)
-               mm->mmap_cache = prev;
+
+       /* Kill the cache */
+       vmacache_invalidate(mm);
 }
 
 /*
@@ -1989,34 +1991,33 @@ EXPORT_SYMBOL(get_unmapped_area);
 /* Look up the first VMA which satisfies  addr < vm_end,  NULL if none. */
 struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
 {
-       struct vm_area_struct *vma = NULL;
+       struct rb_node *rb_node;
+       struct vm_area_struct *vma;
 
        /* Check the cache first. */
-       /* (Cache hit rate is typically around 35%.) */
-       vma = ACCESS_ONCE(mm->mmap_cache);
-       if (!(vma && vma->vm_end > addr && vma->vm_start <= addr)) {
-               struct rb_node *rb_node;
+       vma = vmacache_find(mm, addr);
+       if (likely(vma))
+               return vma;
 
-               rb_node = mm->mm_rb.rb_node;
-               vma = NULL;
+       rb_node = mm->mm_rb.rb_node;
+       vma = NULL;
 
-               while (rb_node) {
-                       struct vm_area_struct *vma_tmp;
-
-                       vma_tmp = rb_entry(rb_node,
-                                          struct vm_area_struct, vm_rb);
-
-                       if (vma_tmp->vm_end > addr) {
-                               vma = vma_tmp;
-                               if (vma_tmp->vm_start <= addr)
-                                       break;
-                               rb_node = rb_node->rb_left;
-                       } else
-                               rb_node = rb_node->rb_right;
-               }
-               if (vma)
-                       mm->mmap_cache = vma;
+       while (rb_node) {
+               struct vm_area_struct *tmp;
+
+               tmp = rb_entry(rb_node, struct vm_area_struct, vm_rb);
+
+               if (tmp->vm_end > addr) {
+                       vma = tmp;
+                       if (tmp->vm_start <= addr)
+                               break;
+                       rb_node = rb_node->rb_left;
+               } else
+                       rb_node = rb_node->rb_right;
        }
+
+       if (vma)
+               vmacache_update(addr, vma);
        return vma;
 }
 
@@ -2388,7 +2389,9 @@ detach_vmas_to_be_unmapped(struct mm_struct *mm, struct vm_area_struct *vma,
        } else
                mm->highest_vm_end = prev ? prev->vm_end : 0;
        tail_vma->vm_next = NULL;
-       mm->mmap_cache = NULL;          /* Kill the cache. */
+
+       /* Kill the cache */
+       vmacache_invalidate(mm);
 }
 
 /*
index 769a67a..c43d557 100644 (file)
@@ -36,6 +36,34 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
 }
 #endif
 
+/*
+ * For a prot_numa update we only hold mmap_sem for read so there is a
+ * potential race with faulting where a pmd was temporarily none. This
+ * function checks for a transhuge pmd under the appropriate lock. It
+ * returns a pte if it was successfully locked or NULL if it raced with
+ * a transhuge insertion.
+ */
+static pte_t *lock_pte_protection(struct vm_area_struct *vma, pmd_t *pmd,
+                       unsigned long addr, int prot_numa, spinlock_t **ptl)
+{
+       pte_t *pte;
+       spinlock_t *pmdl;
+
+       /* !prot_numa is protected by mmap_sem held for write */
+       if (!prot_numa)
+               return pte_offset_map_lock(vma->vm_mm, pmd, addr, ptl);
+
+       pmdl = pmd_lock(vma->vm_mm, pmd);
+       if (unlikely(pmd_trans_huge(*pmd) || pmd_none(*pmd))) {
+               spin_unlock(pmdl);
+               return NULL;
+       }
+
+       pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, ptl);
+       spin_unlock(pmdl);
+       return pte;
+}
+
 static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
                unsigned long addr, unsigned long end, pgprot_t newprot,
                int dirty_accountable, int prot_numa)
@@ -45,7 +73,10 @@ static unsigned long change_pte_range(struct vm_area_struct *vma, pmd_t *pmd,
        spinlock_t *ptl;
        unsigned long pages = 0;
 
-       pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
+       pte = lock_pte_protection(vma, pmd, addr, prot_numa, &ptl);
+       if (!pte)
+               return 0;
+
        arch_enter_lazy_mmu_mode();
        do {
                oldpte = *pte;
@@ -109,15 +140,26 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
                pgprot_t newprot, int dirty_accountable, int prot_numa)
 {
        pmd_t *pmd;
+       struct mm_struct *mm = vma->vm_mm;
        unsigned long next;
        unsigned long pages = 0;
        unsigned long nr_huge_updates = 0;
+       unsigned long mni_start = 0;
 
        pmd = pmd_offset(pud, addr);
        do {
                unsigned long this_pages;
 
                next = pmd_addr_end(addr, end);
+               if (!pmd_trans_huge(*pmd) && pmd_none_or_clear_bad(pmd))
+                       continue;
+
+               /* invoke the mmu notifier if the pmd is populated */
+               if (!mni_start) {
+                       mni_start = addr;
+                       mmu_notifier_invalidate_range_start(mm, mni_start, end);
+               }
+
                if (pmd_trans_huge(*pmd)) {
                        if (next - addr != HPAGE_PMD_SIZE)
                                split_huge_page_pmd(vma, addr, pmd);
@@ -130,18 +172,21 @@ static inline unsigned long change_pmd_range(struct vm_area_struct *vma,
                                                pages += HPAGE_PMD_NR;
                                                nr_huge_updates++;
                                        }
+
+                                       /* huge pmd was handled */
                                        continue;
                                }
                        }
-                       /* fall through */
+                       /* fall through, the trans huge pmd just split */
                }
-               if (pmd_none_or_clear_bad(pmd))
-                       continue;
                this_pages = change_pte_range(vma, pmd, addr, next, newprot,
                                 dirty_accountable, prot_numa);
                pages += this_pages;
        } while (pmd++, addr = next, addr != end);
 
+       if (mni_start)
+               mmu_notifier_invalidate_range_end(mm, mni_start, end);
+
        if (nr_huge_updates)
                count_vm_numa_events(NUMA_HUGE_PTE_UPDATES, nr_huge_updates);
        return pages;
@@ -201,15 +246,12 @@ unsigned long change_protection(struct vm_area_struct *vma, unsigned long start,
                       unsigned long end, pgprot_t newprot,
                       int dirty_accountable, int prot_numa)
 {
-       struct mm_struct *mm = vma->vm_mm;
        unsigned long pages;
 
-       mmu_notifier_invalidate_range_start(mm, start, end);
        if (is_vm_hugetlb_page(vma))
                pages = hugetlb_change_protection(vma, start, end, newprot);
        else
                pages = change_protection_range(vma, start, end, newprot, dirty_accountable, prot_numa);
-       mmu_notifier_invalidate_range_end(mm, start, end);
 
        return pages;
 }
index a554e5a..85f8d66 100644 (file)
@@ -15,6 +15,7 @@
 
 #include <linux/export.h>
 #include <linux/mm.h>
+#include <linux/vmacache.h>
 #include <linux/mman.h>
 #include <linux/swap.h>
 #include <linux/file.h>
@@ -24,6 +25,7 @@
 #include <linux/vmalloc.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
+#include <linux/compiler.h>
 #include <linux/mount.h>
 #include <linux/personality.h>
 #include <linux/security.h>
@@ -296,7 +298,7 @@ long vwrite(char *buf, char *addr, unsigned long count)
                count = -(unsigned long) addr;
 
        memcpy(addr, buf, count);
-       return(count);
+       return count;
 }
 
 /*
@@ -459,7 +461,7 @@ EXPORT_SYMBOL_GPL(vm_unmap_aliases);
  * Implement a stub for vmalloc_sync_all() if the architecture chose not to
  * have one.
  */
-void  __attribute__((weak)) vmalloc_sync_all(void)
+void __weak vmalloc_sync_all(void)
 {
 }
 
@@ -768,16 +770,23 @@ static void add_vma_to_mm(struct mm_struct *mm, struct vm_area_struct *vma)
  */
 static void delete_vma_from_mm(struct vm_area_struct *vma)
 {
+       int i;
        struct address_space *mapping;
        struct mm_struct *mm = vma->vm_mm;
+       struct task_struct *curr = current;
 
        kenter("%p", vma);
 
        protect_vma(vma, 0);
 
        mm->map_count--;
-       if (mm->mmap_cache == vma)
-               mm->mmap_cache = NULL;
+       for (i = 0; i < VMACACHE_SIZE; i++) {
+               /* if the vma is cached, invalidate the entire cache */
+               if (curr->vmacache[i] == vma) {
+                       vmacache_invalidate(curr->mm);
+                       break;
+               }
+       }
 
        /* remove the VMA from the mapping */
        if (vma->vm_file) {
@@ -825,8 +834,8 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
        struct vm_area_struct *vma;
 
        /* check the cache first */
-       vma = ACCESS_ONCE(mm->mmap_cache);
-       if (vma && vma->vm_start <= addr && vma->vm_end > addr)
+       vma = vmacache_find(mm, addr);
+       if (likely(vma))
                return vma;
 
        /* trawl the list (there may be multiple mappings in which addr
@@ -835,7 +844,7 @@ struct vm_area_struct *find_vma(struct mm_struct *mm, unsigned long addr)
                if (vma->vm_start > addr)
                        return NULL;
                if (vma->vm_end > addr) {
-                       mm->mmap_cache = vma;
+                       vmacache_update(addr, vma);
                        return vma;
                }
        }
@@ -874,8 +883,8 @@ static struct vm_area_struct *find_vma_exact(struct mm_struct *mm,
        unsigned long end = addr + len;
 
        /* check the cache first */
-       vma = mm->mmap_cache;
-       if (vma && vma->vm_start == addr && vma->vm_end == end)
+       vma = vmacache_find_exact(mm, addr, end);
+       if (vma)
                return vma;
 
        /* trawl the list (there may be multiple mappings in which addr
@@ -886,7 +895,7 @@ static struct vm_area_struct *find_vma_exact(struct mm_struct *mm,
                if (vma->vm_start > addr)
                        return NULL;
                if (vma->vm_end == end) {
-                       mm->mmap_cache = vma;
+                       vmacache_update(addr, vma);
                        return vma;
                }
        }
@@ -1003,8 +1012,7 @@ static int validate_mmap_request(struct file *file,
 
                        /* we mustn't privatise shared mappings */
                        capabilities &= ~BDI_CAP_MAP_COPY;
-               }
-               else {
+               } else {
                        /* we're going to read the file into private memory we
                         * allocate */
                        if (!(capabilities & BDI_CAP_MAP_COPY))
@@ -1035,23 +1043,20 @@ static int validate_mmap_request(struct file *file,
                if (file->f_path.mnt->mnt_flags & MNT_NOEXEC) {
                        if (prot & PROT_EXEC)
                                return -EPERM;
-               }
-               else if ((prot & PROT_READ) && !(prot & PROT_EXEC)) {
+               } else if ((prot & PROT_READ) && !(prot & PROT_EXEC)) {
                        /* handle implication of PROT_EXEC by PROT_READ */
                        if (current->personality & READ_IMPLIES_EXEC) {
                                if (capabilities & BDI_CAP_EXEC_MAP)
                                        prot |= PROT_EXEC;
                        }
-               }
-               else if ((prot & PROT_READ) &&
+               } else if ((prot & PROT_READ) &&
                         (prot & PROT_EXEC) &&
                         !(capabilities & BDI_CAP_EXEC_MAP)
                         ) {
                        /* backing file is not executable, try to copy */
                        capabilities &= ~BDI_CAP_MAP_DIRECT;
                }
-       }
-       else {
+       } else {
                /* anonymous mappings are always memory backed and can be
                 * privately mapped
                 */
@@ -1659,7 +1664,7 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
        /* find the first potentially overlapping VMA */
        vma = find_vma(mm, start);
        if (!vma) {
-               static int limit = 0;
+               static int limit;
                if (limit < 5) {
                        printk(KERN_WARNING
                               "munmap of memory not mmapped by process %d"
@@ -1985,6 +1990,12 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 }
 EXPORT_SYMBOL(filemap_fault);
 
+void filemap_map_pages(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       BUG();
+}
+EXPORT_SYMBOL(filemap_map_pages);
+
 int generic_file_remap_pages(struct vm_area_struct *vma, unsigned long addr,
                             unsigned long size, pgoff_t pgoff)
 {
index 7106cb1..ef41349 100644 (file)
@@ -1562,9 +1562,9 @@ pause:
                bdi_start_background_writeback(bdi);
 }
 
-void set_page_dirty_balance(struct page *page, int page_mkwrite)
+void set_page_dirty_balance(struct page *page)
 {
-       if (set_page_dirty(page) || page_mkwrite) {
+       if (set_page_dirty(page)) {
                struct address_space *mapping = page_mapping(page);
 
                if (mapping)
index 979378d..5dba293 100644 (file)
@@ -295,7 +295,8 @@ static inline int bad_range(struct zone *zone, struct page *page)
 }
 #endif
 
-static void bad_page(struct page *page, char *reason, unsigned long bad_flags)
+static void bad_page(struct page *page, const char *reason,
+               unsigned long bad_flags)
 {
        static unsigned long resume;
        static unsigned long nr_shown;
@@ -623,7 +624,7 @@ out:
 
 static inline int free_pages_check(struct page *page)
 {
-       char *bad_reason = NULL;
+       const char *bad_reason = NULL;
        unsigned long bad_flags = 0;
 
        if (unlikely(page_mapcount(page)))
@@ -859,7 +860,7 @@ static inline void expand(struct zone *zone, struct page *page,
  */
 static inline int check_new_page(struct page *page)
 {
-       char *bad_reason = NULL;
+       const char *bad_reason = NULL;
        unsigned long bad_flags = 0;
 
        if (unlikely(page_mapcount(page)))
@@ -1238,15 +1239,6 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
        }
        local_irq_restore(flags);
 }
-static bool gfp_thisnode_allocation(gfp_t gfp_mask)
-{
-       return (gfp_mask & GFP_THISNODE) == GFP_THISNODE;
-}
-#else
-static bool gfp_thisnode_allocation(gfp_t gfp_mask)
-{
-       return false;
-}
 #endif
 
 /*
@@ -1583,12 +1575,7 @@ again:
                                          get_pageblock_migratetype(page));
        }
 
-       /*
-        * NOTE: GFP_THISNODE allocations do not partake in the kswapd
-        * aging protocol, so they can't be fair.
-        */
-       if (!gfp_thisnode_allocation(gfp_flags))
-               __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
+       __mod_zone_page_state(zone, NR_ALLOC_BATCH, -(1 << order));
 
        __count_zone_vm_events(PGALLOC, zone, 1 << order);
        zone_statistics(preferred_zone, zone, gfp_flags);
@@ -1870,7 +1857,7 @@ static void __paginginit init_zone_allows_reclaim(int nid)
 {
        int i;
 
-       for_each_online_node(i)
+       for_each_node_state(i, N_MEMORY)
                if (node_distance(nid, i) <= RECLAIM_DISTANCE)
                        node_set(i, NODE_DATA(nid)->reclaim_nodes);
                else
@@ -1954,23 +1941,12 @@ zonelist_scan:
                 * zone size to ensure fair page aging.  The zone a
                 * page was allocated in should have no effect on the
                 * time the page has in memory before being reclaimed.
-                *
-                * Try to stay in local zones in the fastpath.  If
-                * that fails, the slowpath is entered, which will do
-                * another pass starting with the local zones, but
-                * ultimately fall back to remote zones that do not
-                * partake in the fairness round-robin cycle of this
-                * zonelist.
-                *
-                * NOTE: GFP_THISNODE allocations do not partake in
-                * the kswapd aging protocol, so they can't be fair.
                 */
-               if ((alloc_flags & ALLOC_WMARK_LOW) &&
-                   !gfp_thisnode_allocation(gfp_mask)) {
-                       if (zone_page_state(zone, NR_ALLOC_BATCH) <= 0)
-                               continue;
+               if (alloc_flags & ALLOC_FAIR) {
                        if (!zone_local(preferred_zone, zone))
                                continue;
+                       if (zone_page_state(zone, NR_ALLOC_BATCH) <= 0)
+                               continue;
                }
                /*
                 * When allocating a page cache page for writing, we
@@ -2408,32 +2384,40 @@ __alloc_pages_high_priority(gfp_t gfp_mask, unsigned int order,
        return page;
 }
 
-static void prepare_slowpath(gfp_t gfp_mask, unsigned int order,
-                            struct zonelist *zonelist,
-                            enum zone_type high_zoneidx,
-                            struct zone *preferred_zone)
+static void reset_alloc_batches(struct zonelist *zonelist,
+                               enum zone_type high_zoneidx,
+                               struct zone *preferred_zone)
 {
        struct zoneref *z;
        struct zone *zone;
 
        for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
-               if (!(gfp_mask & __GFP_NO_KSWAPD))
-                       wakeup_kswapd(zone, order, zone_idx(preferred_zone));
                /*
                 * Only reset the batches of zones that were actually
-                * considered in the fast path, we don't want to
-                * thrash fairness information for zones that are not
+                * considered in the fairness pass, we don't want to
+                * trash fairness information for zones that are not
                 * actually part of this zonelist's round-robin cycle.
                 */
                if (!zone_local(preferred_zone, zone))
                        continue;
                mod_zone_page_state(zone, NR_ALLOC_BATCH,
-                                   high_wmark_pages(zone) -
-                                   low_wmark_pages(zone) -
-                                   zone_page_state(zone, NR_ALLOC_BATCH));
+                       high_wmark_pages(zone) - low_wmark_pages(zone) -
+                       atomic_long_read(&zone->vm_stat[NR_ALLOC_BATCH]));
        }
 }
 
+static void wake_all_kswapds(unsigned int order,
+                            struct zonelist *zonelist,
+                            enum zone_type high_zoneidx,
+                            struct zone *preferred_zone)
+{
+       struct zoneref *z;
+       struct zone *zone;
+
+       for_each_zone_zonelist(zone, z, zonelist, high_zoneidx)
+               wakeup_kswapd(zone, order, zone_idx(preferred_zone));
+}
+
 static inline int
 gfp_to_alloc_flags(gfp_t gfp_mask)
 {
@@ -2522,12 +2506,13 @@ __alloc_pages_slowpath(gfp_t gfp_mask, unsigned int order,
         * allowed per node queues are empty and that nodes are
         * over allocated.
         */
-       if (gfp_thisnode_allocation(gfp_mask))
+       if (IS_ENABLED(CONFIG_NUMA) &&
+           (gfp_mask & GFP_THISNODE) == GFP_THISNODE)
                goto nopage;
 
 restart:
-       prepare_slowpath(gfp_mask, order, zonelist,
-                        high_zoneidx, preferred_zone);
+       if (!(gfp_mask & __GFP_NO_KSWAPD))
+               wake_all_kswapds(order, zonelist, high_zoneidx, preferred_zone);
 
        /*
         * OK, we're below the kswapd watermark and have kicked background
@@ -2711,7 +2696,7 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
        struct page *page = NULL;
        int migratetype = allocflags_to_migratetype(gfp_mask);
        unsigned int cpuset_mems_cookie;
-       int alloc_flags = ALLOC_WMARK_LOW|ALLOC_CPUSET;
+       int alloc_flags = ALLOC_WMARK_LOW|ALLOC_CPUSET|ALLOC_FAIR;
        struct mem_cgroup *memcg = NULL;
 
        gfp_mask &= gfp_allowed_mask;
@@ -2752,11 +2737,28 @@ retry_cpuset:
        if (allocflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
                alloc_flags |= ALLOC_CMA;
 #endif
+retry:
        /* First allocation attempt */
        page = get_page_from_freelist(gfp_mask|__GFP_HARDWALL, nodemask, order,
                        zonelist, high_zoneidx, alloc_flags,
                        preferred_zone, migratetype);
        if (unlikely(!page)) {
+               /*
+                * The first pass makes sure allocations are spread
+                * fairly within the local node.  However, the local
+                * node might have free pages left after the fairness
+                * batches are exhausted, and remote zones haven't
+                * even been considered yet.  Try once more without
+                * fairness, and include remote zones now, before
+                * entering the slowpath and waking kswapd: prefer
+                * spilling to a remote zone over swapping locally.
+                */
+               if (alloc_flags & ALLOC_FAIR) {
+                       reset_alloc_batches(zonelist, high_zoneidx,
+                                           preferred_zone);
+                       alloc_flags &= ~ALLOC_FAIR;
+                       goto retry;
+               }
                /*
                 * Runtime PM, block IO and its error handling path
                 * can deadlock because I/O on the device might not
@@ -4919,7 +4921,8 @@ void __paginginit free_area_init_node(int nid, unsigned long *zones_size,
 
        pgdat->node_id = nid;
        pgdat->node_start_pfn = node_start_pfn;
-       init_zone_allows_reclaim(nid);
+       if (node_state(nid, N_MEMORY))
+               init_zone_allows_reclaim(nid);
 #ifdef CONFIG_HAVE_MEMBLOCK_NODE_MAP
        get_pfn_range_for_nid(nid, &start_pfn, &end_pfn);
 #endif
@@ -5070,7 +5073,7 @@ static void __init find_zone_movable_pfns_for_nodes(void)
        nodemask_t saved_node_state = node_states[N_MEMORY];
        unsigned long totalpages = early_calculate_totalpages();
        int usable_nodes = nodes_weight(node_states[N_MEMORY]);
-       struct memblock_type *type = &memblock.memory;
+       struct memblock_region *r;
 
        /* Need to find movable_zone earlier when movable_node is specified. */
        find_usable_zone_for_movable();
@@ -5080,13 +5083,13 @@ static void __init find_zone_movable_pfns_for_nodes(void)
         * options.
         */
        if (movable_node_is_enabled()) {
-               for (i = 0; i < type->cnt; i++) {
-                       if (!memblock_is_hotpluggable(&type->regions[i]))
+               for_each_memblock(memory, r) {
+                       if (!memblock_is_hotpluggable(r))
                                continue;
 
-                       nid = type->regions[i].nid;
+                       nid = r->nid;
 
-                       usable_startpfn = PFN_DOWN(type->regions[i].base);
+                       usable_startpfn = PFN_DOWN(r->base);
                        zone_movable_pfn[nid] = zone_movable_pfn[nid] ?
                                min(usable_startpfn, zone_movable_pfn[nid]) :
                                usable_startpfn;
@@ -6544,7 +6547,8 @@ static void dump_page_flags(unsigned long flags)
        printk(")\n");
 }
 
-void dump_page_badflags(struct page *page, char *reason, unsigned long badflags)
+void dump_page_badflags(struct page *page, const char *reason,
+               unsigned long badflags)
 {
        printk(KERN_ALERT
               "page:%p count:%d mapcount:%d mapping:%p index:%#lx\n",
@@ -6560,8 +6564,8 @@ void dump_page_badflags(struct page *page, char *reason, unsigned long badflags)
        mem_cgroup_print_bad_page(page);
 }
 
-void dump_page(struct page *page, char *reason)
+void dump_page(struct page *page, const char *reason)
 {
        dump_page_badflags(page, reason, 0);
 }
-EXPORT_SYMBOL_GPL(dump_page);
+EXPORT_SYMBOL(dump_page);
index 29c5e1a..0ca36a7 100644 (file)
@@ -8,9 +8,7 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/fs.h>
 #include <linux/gfp.h>
-#include <linux/mm.h>
 #include <linux/export.h>
 #include <linux/blkdev.h>
 #include <linux/backing-dev.h>
@@ -20,6 +18,8 @@
 #include <linux/syscalls.h>
 #include <linux/file.h>
 
+#include "internal.h"
+
 /*
  * Initialise a struct file's readahead state.  Assumes that the caller has
  * memset *ra to zero.
@@ -149,8 +149,7 @@ out:
  *
  * Returns the number of pages requested, or the maximum amount of I/O allowed.
  */
-static int
-__do_page_cache_readahead(struct address_space *mapping, struct file *filp,
+int __do_page_cache_readahead(struct address_space *mapping, struct file *filp,
                        pgoff_t offset, unsigned long nr_to_read,
                        unsigned long lookahead_size)
 {
@@ -243,20 +242,6 @@ unsigned long max_sane_readahead(unsigned long nr)
        return min(nr, MAX_READAHEAD);
 }
 
-/*
- * Submit IO for the read-ahead request in file_ra_state.
- */
-unsigned long ra_submit(struct file_ra_state *ra,
-                      struct address_space *mapping, struct file *filp)
-{
-       int actual;
-
-       actual = __do_page_cache_readahead(mapping, filp,
-                                       ra->start, ra->size, ra->async_size);
-
-       return actual;
-}
-
 /*
  * Set the initial window size, round to next power of 2 and square
  * for small size, x 4 for medium, and x 2 for large
index 11cf322..9c3e773 100644 (file)
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1332,9 +1332,19 @@ static int try_to_unmap_cluster(unsigned long cursor, unsigned int *mapcount,
                BUG_ON(!page || PageAnon(page));
 
                if (locked_vma) {
-                       mlock_vma_page(page);   /* no-op if already mlocked */
-                       if (page == check_page)
+                       if (page == check_page) {
+                               /* we know we have check_page locked */
+                               mlock_vma_page(page);
                                ret = SWAP_MLOCK;
+                       } else if (trylock_page(page)) {
+                               /*
+                                * If we can lock the page, perform mlock.
+                                * Otherwise leave the page alone, it will be
+                                * eventually encountered again later.
+                                */
+                               mlock_vma_page(page);
+                               unlock_page(page);
+                       }
                        continue;       /* don't unmap */
                }
 
index a3ba988..70273f8 100644 (file)
@@ -683,7 +683,7 @@ int shmem_unuse(swp_entry_t swap, struct page *page)
         * the shmem_swaplist_mutex which might hold up shmem_writepage().
         * Charged back to the user (not to caller) when swap account is used.
         */
-       error = mem_cgroup_cache_charge(page, current->mm, GFP_KERNEL);
+       error = mem_cgroup_charge_file(page, current->mm, GFP_KERNEL);
        if (error)
                goto out;
        /* No radix_tree_preload: swap entry keeps a place for page in tree */
@@ -1080,7 +1080,7 @@ repeat:
                                goto failed;
                }
 
-               error = mem_cgroup_cache_charge(page, current->mm,
+               error = mem_cgroup_charge_file(page, current->mm,
                                                gfp & GFP_RECLAIM_MASK);
                if (!error) {
                        error = shmem_add_to_page_cache(page, mapping, index,
@@ -1134,7 +1134,7 @@ repeat:
 
                SetPageSwapBacked(page);
                __set_page_locked(page);
-               error = mem_cgroup_cache_charge(page, current->mm,
+               error = mem_cgroup_charge_file(page, current->mm,
                                                gfp & GFP_RECLAIM_MASK);
                if (error)
                        goto decused;
@@ -2723,6 +2723,7 @@ static const struct super_operations shmem_ops = {
 
 static const struct vm_operations_struct shmem_vm_ops = {
        .fault          = shmem_fault,
+       .map_pages      = filemap_map_pages,
 #ifdef CONFIG_NUMA
        .set_policy     = shmem_set_policy,
        .get_policy     = shmem_get_policy,
index 9153c80..3db4cb0 100644 (file)
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -3027,7 +3027,7 @@ out:
 
 #ifdef CONFIG_NUMA
 /*
- * Try allocating on another node if PF_SPREAD_SLAB|PF_MEMPOLICY.
+ * Try allocating on another node if PF_SPREAD_SLAB is a mempolicy is set.
  *
  * If we are in_interrupt, then process context, including cpusets and
  * mempolicy, may not apply and should not be used for allocation policy.
@@ -3042,7 +3042,7 @@ static void *alternate_node_alloc(struct kmem_cache *cachep, gfp_t flags)
        if (cpuset_do_slab_mem_spread() && (cachep->flags & SLAB_MEM_SPREAD))
                nid_alloc = cpuset_slab_spread_node();
        else if (current->mempolicy)
-               nid_alloc = slab_node();
+               nid_alloc = mempolicy_slab_node();
        if (nid_alloc != nid_here)
                return ____cache_alloc_node(cachep, flags, nid_alloc);
        return NULL;
@@ -3074,7 +3074,7 @@ static void *fallback_alloc(struct kmem_cache *cache, gfp_t flags)
 
 retry_cpuset:
        cpuset_mems_cookie = read_mems_allowed_begin();
-       zonelist = node_zonelist(slab_node(), flags);
+       zonelist = node_zonelist(mempolicy_slab_node(), flags);
 
 retry:
        /*
@@ -3259,7 +3259,7 @@ __do_cache_alloc(struct kmem_cache *cache, gfp_t flags)
 {
        void *objp;
 
-       if (unlikely(current->flags & (PF_SPREAD_SLAB | PF_MEMPOLICY))) {
+       if (current->mempolicy || unlikely(current->flags & PF_SPREAD_SLAB)) {
                objp = alternate_node_alloc(cache, flags);
                if (objp)
                        goto out;
index 8184a7c..3045316 100644 (file)
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -55,12 +55,12 @@ extern void create_boot_cache(struct kmem_cache *, const char *name,
 struct mem_cgroup;
 #ifdef CONFIG_SLUB
 struct kmem_cache *
-__kmem_cache_alias(struct mem_cgroup *memcg, const char *name, size_t size,
-                  size_t align, unsigned long flags, void (*ctor)(void *));
+__kmem_cache_alias(const char *name, size_t size, size_t align,
+                  unsigned long flags, void (*ctor)(void *));
 #else
 static inline struct kmem_cache *
-__kmem_cache_alias(struct mem_cgroup *memcg, const char *name, size_t size,
-                  size_t align, unsigned long flags, void (*ctor)(void *))
+__kmem_cache_alias(const char *name, size_t size, size_t align,
+                  unsigned long flags, void (*ctor)(void *))
 { return NULL; }
 #endif
 
@@ -119,13 +119,6 @@ static inline bool is_root_cache(struct kmem_cache *s)
        return !s->memcg_params || s->memcg_params->is_root_cache;
 }
 
-static inline bool cache_match_memcg(struct kmem_cache *cachep,
-                                    struct mem_cgroup *memcg)
-{
-       return (is_root_cache(cachep) && !memcg) ||
-                               (cachep->memcg_params->memcg == memcg);
-}
-
 static inline void memcg_bind_pages(struct kmem_cache *s, int order)
 {
        if (!is_root_cache(s))
@@ -204,12 +197,6 @@ static inline bool is_root_cache(struct kmem_cache *s)
        return true;
 }
 
-static inline bool cache_match_memcg(struct kmem_cache *cachep,
-                                    struct mem_cgroup *memcg)
-{
-       return true;
-}
-
 static inline void memcg_bind_pages(struct kmem_cache *s, int order)
 {
 }
index 1ec3c61..f3cfccf 100644 (file)
@@ -29,8 +29,7 @@ DEFINE_MUTEX(slab_mutex);
 struct kmem_cache *kmem_cache;
 
 #ifdef CONFIG_DEBUG_VM
-static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name,
-                                  size_t size)
+static int kmem_cache_sanity_check(const char *name, size_t size)
 {
        struct kmem_cache *s = NULL;
 
@@ -57,13 +56,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name,
                }
 
 #if !defined(CONFIG_SLUB) || !defined(CONFIG_SLUB_DEBUG_ON)
-               /*
-                * For simplicity, we won't check this in the list of memcg
-                * caches. We have control over memcg naming, and if there
-                * aren't duplicates in the global list, there won't be any
-                * duplicates in the memcg lists as well.
-                */
-               if (!memcg && !strcmp(s->name, name)) {
+               if (!strcmp(s->name, name)) {
                        pr_err("%s (%s): Cache name already exists.\n",
                               __func__, name);
                        dump_stack();
@@ -77,8 +70,7 @@ static int kmem_cache_sanity_check(struct mem_cgroup *memcg, const char *name,
        return 0;
 }
 #else
-static inline int kmem_cache_sanity_check(struct mem_cgroup *memcg,
-                                         const char *name, size_t size)
+static inline int kmem_cache_sanity_check(const char *name, size_t size)
 {
        return 0;
 }
@@ -139,6 +131,46 @@ unsigned long calculate_alignment(unsigned long flags,
        return ALIGN(align, sizeof(void *));
 }
 
+static struct kmem_cache *
+do_kmem_cache_create(char *name, size_t object_size, size_t size, size_t align,
+                    unsigned long flags, void (*ctor)(void *),
+                    struct mem_cgroup *memcg, struct kmem_cache *root_cache)
+{
+       struct kmem_cache *s;
+       int err;
+
+       err = -ENOMEM;
+       s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
+       if (!s)
+               goto out;
+
+       s->name = name;
+       s->object_size = object_size;
+       s->size = size;
+       s->align = align;
+       s->ctor = ctor;
+
+       err = memcg_alloc_cache_params(memcg, s, root_cache);
+       if (err)
+               goto out_free_cache;
+
+       err = __kmem_cache_create(s, flags);
+       if (err)
+               goto out_free_cache;
+
+       s->refcount = 1;
+       list_add(&s->list, &slab_caches);
+       memcg_register_cache(s);
+out:
+       if (err)
+               return ERR_PTR(err);
+       return s;
+
+out_free_cache:
+       memcg_free_cache_params(s);
+       kfree(s);
+       goto out;
+}
 
 /*
  * kmem_cache_create - Create a cache.
@@ -164,34 +196,21 @@ unsigned long calculate_alignment(unsigned long flags,
  * cacheline.  This can be beneficial if you're counting cycles as closely
  * as davem.
  */
-
 struct kmem_cache *
-kmem_cache_create_memcg(struct mem_cgroup *memcg, const char *name, size_t size,
-                       size_t align, unsigned long flags, void (*ctor)(void *),
-                       struct kmem_cache *parent_cache)
+kmem_cache_create(const char *name, size_t size, size_t align,
+                 unsigned long flags, void (*ctor)(void *))
 {
-       struct kmem_cache *s = NULL;
+       struct kmem_cache *s;
+       char *cache_name;
        int err;
 
        get_online_cpus();
        mutex_lock(&slab_mutex);
 
-       err = kmem_cache_sanity_check(memcg, name, size);
+       err = kmem_cache_sanity_check(name, size);
        if (err)
                goto out_unlock;
 
-       if (memcg) {
-               /*
-                * Since per-memcg caches are created asynchronously on first
-                * allocation (see memcg_kmem_get_cache()), several threads can
-                * try to create the same cache, but only one of them may
-                * succeed. Therefore if we get here and see the cache has
-                * already been created, we silently return NULL.
-                */
-               if (cache_from_memcg_idx(parent_cache, memcg_cache_id(memcg)))
-                       goto out_unlock;
-       }
-
        /*
         * Some allocators will constraint the set of valid flags to a subset
         * of all flags. We expect them to define CACHE_CREATE_MASK in this
@@ -200,50 +219,29 @@ kmem_cache_create_memcg(struct mem_cgroup *memcg, const char *name, size_t size,
         */
        flags &= CACHE_CREATE_MASK;
 
-       s = __kmem_cache_alias(memcg, name, size, align, flags, ctor);
+       s = __kmem_cache_alias(name, size, align, flags, ctor);
        if (s)
                goto out_unlock;
 
-       err = -ENOMEM;
-       s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
-       if (!s)
+       cache_name = kstrdup(name, GFP_KERNEL);
+       if (!cache_name) {
+               err = -ENOMEM;
                goto out_unlock;
+       }
 
-       s->object_size = s->size = size;
-       s->align = calculate_alignment(flags, align, size);
-       s->ctor = ctor;
-
-       s->name = kstrdup(name, GFP_KERNEL);
-       if (!s->name)
-               goto out_free_cache;
-
-       err = memcg_alloc_cache_params(memcg, s, parent_cache);
-       if (err)
-               goto out_free_cache;
-
-       err = __kmem_cache_create(s, flags);
-       if (err)
-               goto out_free_cache;
-
-       s->refcount = 1;
-       list_add(&s->list, &slab_caches);
-       memcg_register_cache(s);
+       s = do_kmem_cache_create(cache_name, size, size,
+                                calculate_alignment(flags, align, size),
+                                flags, ctor, NULL, NULL);
+       if (IS_ERR(s)) {
+               err = PTR_ERR(s);
+               kfree(cache_name);
+       }
 
 out_unlock:
        mutex_unlock(&slab_mutex);
        put_online_cpus();
 
        if (err) {
-               /*
-                * There is no point in flooding logs with warnings or
-                * especially crashing the system if we fail to create a cache
-                * for a memcg. In this case we will be accounting the memcg
-                * allocation to the root cgroup until we succeed to create its
-                * own cache, but it isn't that critical.
-                */
-               if (!memcg)
-                       return NULL;
-
                if (flags & SLAB_PANIC)
                        panic("kmem_cache_create: Failed to create slab '%s'. Error %d\n",
                                name, err);
@@ -255,52 +253,112 @@ out_unlock:
                return NULL;
        }
        return s;
+}
+EXPORT_SYMBOL(kmem_cache_create);
 
-out_free_cache:
-       memcg_free_cache_params(s);
-       kfree(s->name);
-       kmem_cache_free(kmem_cache, s);
-       goto out_unlock;
+#ifdef CONFIG_MEMCG_KMEM
+/*
+ * kmem_cache_create_memcg - Create a cache for a memory cgroup.
+ * @memcg: The memory cgroup the new cache is for.
+ * @root_cache: The parent of the new cache.
+ *
+ * This function attempts to create a kmem cache that will serve allocation
+ * requests going from @memcg to @root_cache. The new cache inherits properties
+ * from its parent.
+ */
+void kmem_cache_create_memcg(struct mem_cgroup *memcg, struct kmem_cache *root_cache)
+{
+       struct kmem_cache *s;
+       char *cache_name;
+
+       get_online_cpus();
+       mutex_lock(&slab_mutex);
+
+       /*
+        * Since per-memcg caches are created asynchronously on first
+        * allocation (see memcg_kmem_get_cache()), several threads can try to
+        * create the same cache, but only one of them may succeed.
+        */
+       if (cache_from_memcg_idx(root_cache, memcg_cache_id(memcg)))
+               goto out_unlock;
+
+       cache_name = memcg_create_cache_name(memcg, root_cache);
+       if (!cache_name)
+               goto out_unlock;
+
+       s = do_kmem_cache_create(cache_name, root_cache->object_size,
+                                root_cache->size, root_cache->align,
+                                root_cache->flags, root_cache->ctor,
+                                memcg, root_cache);
+       if (IS_ERR(s)) {
+               kfree(cache_name);
+               goto out_unlock;
+       }
+
+       s->allocflags |= __GFP_KMEMCG;
+
+out_unlock:
+       mutex_unlock(&slab_mutex);
+       put_online_cpus();
 }
 
-struct kmem_cache *
-kmem_cache_create(const char *name, size_t size, size_t align,
-                 unsigned long flags, void (*ctor)(void *))
+static int kmem_cache_destroy_memcg_children(struct kmem_cache *s)
 {
-       return kmem_cache_create_memcg(NULL, name, size, align, flags, ctor, NULL);
+       int rc;
+
+       if (!s->memcg_params ||
+           !s->memcg_params->is_root_cache)
+               return 0;
+
+       mutex_unlock(&slab_mutex);
+       rc = __kmem_cache_destroy_memcg_children(s);
+       mutex_lock(&slab_mutex);
+
+       return rc;
 }
-EXPORT_SYMBOL(kmem_cache_create);
+#else
+static int kmem_cache_destroy_memcg_children(struct kmem_cache *s)
+{
+       return 0;
+}
+#endif /* CONFIG_MEMCG_KMEM */
 
 void kmem_cache_destroy(struct kmem_cache *s)
 {
-       /* Destroy all the children caches if we aren't a memcg cache */
-       kmem_cache_destroy_memcg_children(s);
-
        get_online_cpus();
        mutex_lock(&slab_mutex);
+
        s->refcount--;
-       if (!s->refcount) {
-               list_del(&s->list);
-
-               if (!__kmem_cache_shutdown(s)) {
-                       memcg_unregister_cache(s);
-                       mutex_unlock(&slab_mutex);
-                       if (s->flags & SLAB_DESTROY_BY_RCU)
-                               rcu_barrier();
-
-                       memcg_free_cache_params(s);
-                       kfree(s->name);
-                       kmem_cache_free(kmem_cache, s);
-               } else {
-                       list_add(&s->list, &slab_caches);
-                       mutex_unlock(&slab_mutex);
-                       printk(KERN_ERR "kmem_cache_destroy %s: Slab cache still has objects\n",
-                               s->name);
-                       dump_stack();
-               }
-       } else {
-               mutex_unlock(&slab_mutex);
+       if (s->refcount)
+               goto out_unlock;
+
+       if (kmem_cache_destroy_memcg_children(s) != 0)
+               goto out_unlock;
+
+       list_del(&s->list);
+       memcg_unregister_cache(s);
+
+       if (__kmem_cache_shutdown(s) != 0) {
+               list_add(&s->list, &slab_caches);
+               memcg_register_cache(s);
+               printk(KERN_ERR "kmem_cache_destroy %s: "
+                      "Slab cache still has objects\n", s->name);
+               dump_stack();
+               goto out_unlock;
        }
+
+       mutex_unlock(&slab_mutex);
+       if (s->flags & SLAB_DESTROY_BY_RCU)
+               rcu_barrier();
+
+       memcg_free_cache_params(s);
+       kfree(s->name);
+       kmem_cache_free(kmem_cache, s);
+       goto out_put_cpus;
+
+out_unlock:
+       mutex_unlock(&slab_mutex);
+out_put_cpus:
        put_online_cpus();
 }
 EXPORT_SYMBOL(kmem_cache_destroy);
index fe6d7be..f620bbf 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -224,7 +224,11 @@ static inline void memcg_propagate_slab_attrs(struct kmem_cache *s) { }
 static inline void stat(const struct kmem_cache *s, enum stat_item si)
 {
 #ifdef CONFIG_SLUB_STATS
-       __this_cpu_inc(s->cpu_slab->stat[si]);
+       /*
+        * The rmw is racy on a preemptible kernel but this is acceptable, so
+        * avoid this_cpu_add()'s irq-disable overhead.
+        */
+       raw_cpu_inc(s->cpu_slab->stat[si]);
 #endif
 }
 
@@ -1685,7 +1689,7 @@ static void *get_any_partial(struct kmem_cache *s, gfp_t flags,
 
        do {
                cpuset_mems_cookie = read_mems_allowed_begin();
-               zonelist = node_zonelist(slab_node(), flags);
+               zonelist = node_zonelist(mempolicy_slab_node(), flags);
                for_each_zone_zonelist(zone, z, zonelist, high_zoneidx) {
                        struct kmem_cache_node *n;
 
@@ -3685,6 +3689,9 @@ static int slab_unmergeable(struct kmem_cache *s)
        if (slub_nomerge || (s->flags & SLUB_NEVER_MERGE))
                return 1;
 
+       if (!is_root_cache(s))
+               return 1;
+
        if (s->ctor)
                return 1;
 
@@ -3697,9 +3704,8 @@ static int slab_unmergeable(struct kmem_cache *s)
        return 0;
 }
 
-static struct kmem_cache *find_mergeable(struct mem_cgroup *memcg, size_t size,
-               size_t align, unsigned long flags, const char *name,
-               void (*ctor)(void *))
+static struct kmem_cache *find_mergeable(size_t size, size_t align,
+               unsigned long flags, const char *name, void (*ctor)(void *))
 {
        struct kmem_cache *s;
 
@@ -3722,7 +3728,7 @@ static struct kmem_cache *find_mergeable(struct mem_cgroup *memcg, size_t size,
                        continue;
 
                if ((flags & SLUB_MERGE_SAME) != (s->flags & SLUB_MERGE_SAME))
-                               continue;
+                       continue;
                /*
                 * Check if alignment is compatible.
                 * Courtesy of Adrian Drzewiecki
@@ -3733,23 +3739,24 @@ static struct kmem_cache *find_mergeable(struct mem_cgroup *memcg, size_t size,
                if (s->size - size >= sizeof(void *))
                        continue;
 
-               if (!cache_match_memcg(s, memcg))
-                       continue;
-
                return s;
        }
        return NULL;
 }
 
 struct kmem_cache *
-__kmem_cache_alias(struct mem_cgroup *memcg, const char *name, size_t size,
-                  size_t align, unsigned long flags, void (*ctor)(void *))
+__kmem_cache_alias(const char *name, size_t size, size_t align,
+                  unsigned long flags, void (*ctor)(void *))
 {
        struct kmem_cache *s;
 
-       s = find_mergeable(memcg, size, align, flags, name, ctor);
+       s = find_mergeable(size, align, flags, name, ctor);
        if (s) {
+               int i;
+               struct kmem_cache *c;
+
                s->refcount++;
+
                /*
                 * Adjust the object sizes so that we clear
                 * the complete object on kzalloc.
@@ -3757,6 +3764,15 @@ __kmem_cache_alias(struct mem_cgroup *memcg, const char *name, size_t size,
                s->object_size = max(s->object_size, (int)size);
                s->inuse = max_t(int, s->inuse, ALIGN(size, sizeof(void *)));
 
+               for_each_memcg_cache_index(i) {
+                       c = cache_from_memcg_idx(s, i);
+                       if (!c)
+                               continue;
+                       c->object_size = s->object_size;
+                       c->inuse = max_t(int, c->inuse,
+                                        ALIGN(size, sizeof(void *)));
+               }
+
                if (sysfs_slab_alias(s, name)) {
                        s->refcount--;
                        s = NULL;
@@ -5126,6 +5142,15 @@ static const struct kset_uevent_ops slab_uevent_ops = {
 
 static struct kset *slab_kset;
 
+static inline struct kset *cache_kset(struct kmem_cache *s)
+{
+#ifdef CONFIG_MEMCG_KMEM
+       if (!is_root_cache(s))
+               return s->memcg_params->root_cache->memcg_kset;
+#endif
+       return slab_kset;
+}
+
 #define ID_STR_LENGTH 64
 
 /* Create a unique string id for a slab cache:
@@ -5191,26 +5216,39 @@ static int sysfs_slab_add(struct kmem_cache *s)
                name = create_unique_id(s);
        }
 
-       s->kobj.kset = slab_kset;
+       s->kobj.kset = cache_kset(s);
        err = kobject_init_and_add(&s->kobj, &slab_ktype, NULL, "%s", name);
-       if (err) {
-               kobject_put(&s->kobj);
-               return err;
-       }
+       if (err)
+               goto out_put_kobj;
 
        err = sysfs_create_group(&s->kobj, &slab_attr_group);
-       if (err) {
-               kobject_del(&s->kobj);
-               kobject_put(&s->kobj);
-               return err;
+       if (err)
+               goto out_del_kobj;
+
+#ifdef CONFIG_MEMCG_KMEM
+       if (is_root_cache(s)) {
+               s->memcg_kset = kset_create_and_add("cgroup", NULL, &s->kobj);
+               if (!s->memcg_kset) {
+                       err = -ENOMEM;
+                       goto out_del_kobj;
+               }
        }
+#endif
+
        kobject_uevent(&s->kobj, KOBJ_ADD);
        if (!unmergeable) {
                /* Setup first alias */
                sysfs_slab_alias(s, s->name);
-               kfree(name);
        }
-       return 0;
+out:
+       if (!unmergeable)
+               kfree(name);
+       return err;
+out_del_kobj:
+       kobject_del(&s->kobj);
+out_put_kobj:
+       kobject_put(&s->kobj);
+       goto out;
 }
 
 static void sysfs_slab_remove(struct kmem_cache *s)
@@ -5222,6 +5260,9 @@ static void sysfs_slab_remove(struct kmem_cache *s)
                 */
                return;
 
+#ifdef CONFIG_MEMCG_KMEM
+       kset_unregister(s->memcg_kset);
+#endif
        kobject_uevent(&s->kobj, KOBJ_REMOVE);
        kobject_del(&s->kobj);
        kobject_put(&s->kobj);
index 38cad8f..d1b48b6 100644 (file)
@@ -5,10 +5,12 @@
 #include <linux/slab.h>
 #include <linux/mmzone.h>
 #include <linux/bootmem.h>
+#include <linux/compiler.h>
 #include <linux/highmem.h>
 #include <linux/export.h>
 #include <linux/spinlock.h>
 #include <linux/vmalloc.h>
+
 #include "internal.h"
 #include <asm/dma.h>
 #include <asm/pgalloc.h>
@@ -461,7 +463,7 @@ static struct page __init *sparse_early_mem_map_alloc(unsigned long pnum)
 }
 #endif
 
-void __attribute__((weak)) __meminit vmemmap_populate_print_last(void)
+void __weak __meminit vmemmap_populate_print_last(void)
 {
 }
 
index a24aa22..d7813e6 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -1,6 +1,7 @@
 #include <linux/mm.h>
 #include <linux/slab.h>
 #include <linux/string.h>
+#include <linux/compiler.h>
 #include <linux/export.h>
 #include <linux/err.h>
 #include <linux/sched.h>
@@ -307,7 +308,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
  * If the architecture not support this function, simply return with no
  * page pinned
  */
-int __attribute__((weak)) __get_user_pages_fast(unsigned long start,
+int __weak __get_user_pages_fast(unsigned long start,
                                 int nr_pages, int write, struct page **pages)
 {
        return 0;
@@ -338,7 +339,7 @@ EXPORT_SYMBOL_GPL(__get_user_pages_fast);
  * callers need to carefully consider what to use. On many architectures,
  * get_user_pages_fast simply falls back to get_user_pages.
  */
-int __attribute__((weak)) get_user_pages_fast(unsigned long start,
+int __weak get_user_pages_fast(unsigned long start,
                                int nr_pages, int write, struct page **pages)
 {
        struct mm_struct *mm = current->mm;
diff --git a/mm/vmacache.c b/mm/vmacache.c
new file mode 100644 (file)
index 0000000..d4224b3
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 Davidlohr Bueso.
+ */
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/vmacache.h>
+
+/*
+ * Flush vma caches for threads that share a given mm.
+ *
+ * The operation is safe because the caller holds the mmap_sem
+ * exclusively and other threads accessing the vma cache will
+ * have mmap_sem held at least for read, so no extra locking
+ * is required to maintain the vma cache.
+ */
+void vmacache_flush_all(struct mm_struct *mm)
+{
+       struct task_struct *g, *p;
+
+       rcu_read_lock();
+       for_each_process_thread(g, p) {
+               /*
+                * Only flush the vmacache pointers as the
+                * mm seqnum is already set and curr's will
+                * be set upon invalidation when the next
+                * lookup is done.
+                */
+               if (mm == p->mm)
+                       vmacache_flush(p);
+       }
+       rcu_read_unlock();
+}
+
+/*
+ * This task may be accessing a foreign mm via (for example)
+ * get_user_pages()->find_vma().  The vmacache is task-local and this
+ * task's vmacache pertains to a different mm (ie, its own).  There is
+ * nothing we can do here.
+ *
+ * Also handle the case where a kernel thread has adopted this mm via use_mm().
+ * That kernel thread's vmacache is not applicable to this mm.
+ */
+static bool vmacache_valid_mm(struct mm_struct *mm)
+{
+       return current->mm == mm && !(current->flags & PF_KTHREAD);
+}
+
+void vmacache_update(unsigned long addr, struct vm_area_struct *newvma)
+{
+       if (vmacache_valid_mm(newvma->vm_mm))
+               current->vmacache[VMACACHE_HASH(addr)] = newvma;
+}
+
+static bool vmacache_valid(struct mm_struct *mm)
+{
+       struct task_struct *curr;
+
+       if (!vmacache_valid_mm(mm))
+               return false;
+
+       curr = current;
+       if (mm->vmacache_seqnum != curr->vmacache_seqnum) {
+               /*
+                * First attempt will always be invalid, initialize
+                * the new cache for this task here.
+                */
+               curr->vmacache_seqnum = mm->vmacache_seqnum;
+               vmacache_flush(curr);
+               return false;
+       }
+       return true;
+}
+
+struct vm_area_struct *vmacache_find(struct mm_struct *mm, unsigned long addr)
+{
+       int i;
+
+       if (!vmacache_valid(mm))
+               return NULL;
+
+       for (i = 0; i < VMACACHE_SIZE; i++) {
+               struct vm_area_struct *vma = current->vmacache[i];
+
+               if (vma && vma->vm_start <= addr && vma->vm_end > addr) {
+                       BUG_ON(vma->vm_mm != mm);
+                       return vma;
+               }
+       }
+
+       return NULL;
+}
+
+#ifndef CONFIG_MMU
+struct vm_area_struct *vmacache_find_exact(struct mm_struct *mm,
+                                          unsigned long start,
+                                          unsigned long end)
+{
+       int i;
+
+       if (!vmacache_valid(mm))
+               return NULL;
+
+       for (i = 0; i < VMACACHE_SIZE; i++) {
+               struct vm_area_struct *vma = current->vmacache[i];
+
+               if (vma && vma->vm_start == start && vma->vm_end == end)
+                       return vma;
+       }
+
+       return NULL;
+}
+#endif
index 0fdf968..bf233b2 100644 (file)
@@ -27,7 +27,9 @@
 #include <linux/pfn.h>
 #include <linux/kmemleak.h>
 #include <linux/atomic.h>
+#include <linux/compiler.h>
 #include <linux/llist.h>
+
 #include <asm/uaccess.h>
 #include <asm/tlbflush.h>
 #include <asm/shmparam.h>
@@ -1083,6 +1085,12 @@ EXPORT_SYMBOL(vm_unmap_ram);
  * @node: prefer to allocate data structures on this node
  * @prot: memory protection to use. PAGE_KERNEL for regular RAM
  *
+ * If you use this function for less than VMAP_MAX_ALLOC pages, it could be
+ * faster than vmap so it's good.  But if you mix long-life and short-life
+ * objects with vm_map_ram(), it could consume lots of address space through
+ * fragmentation (especially on a 32bit machine).  You could see failures in
+ * the end.  Please use this function for short-lived objects.
+ *
  * Returns: a pointer to the address that has been mapped, or %NULL on failure
  */
 void *vm_map_ram(struct page **pages, unsigned int count, int node, pgprot_t prot)
@@ -2181,7 +2189,7 @@ EXPORT_SYMBOL(remap_vmalloc_range);
  * Implement a stub for vmalloc_sync_all() if the architecture chose not to
  * have one.
  */
-void  __attribute__((weak)) vmalloc_sync_all(void)
+void __weak vmalloc_sync_all(void)
 {
 }
 
index 1f56a80..9b6497e 100644 (file)
@@ -1862,7 +1862,7 @@ static void get_scan_count(struct lruvec *lruvec, struct scan_control *sc,
        struct zone *zone = lruvec_zone(lruvec);
        unsigned long anon_prio, file_prio;
        enum scan_balance scan_balance;
-       unsigned long anon, file, free;
+       unsigned long anon, file;
        bool force_scan = false;
        unsigned long ap, fp;
        enum lru_list lru;
@@ -1915,20 +1915,6 @@ static void get_scan_count(struct lruvec *lruvec, struct scan_control *sc,
        file  = get_lru_size(lruvec, LRU_ACTIVE_FILE) +
                get_lru_size(lruvec, LRU_INACTIVE_FILE);
 
-       /*
-        * If it's foreseeable that reclaiming the file cache won't be
-        * enough to get the zone back into a desirable shape, we have
-        * to swap.  Better start now and leave the - probably heavily
-        * thrashing - remaining file pages alone.
-        */
-       if (global_reclaim(sc)) {
-               free = zone_page_state(zone, NR_FREE_PAGES);
-               if (unlikely(file + free <= high_wmark_pages(zone))) {
-                       scan_balance = SCAN_ANON;
-                       goto out;
-               }
-       }
-
        /*
         * There is enough inactive page cache, do not reclaim
         * anything from the anonymous working set right now.
@@ -2314,15 +2300,18 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
        unsigned long lru_pages = 0;
        bool aborted_reclaim = false;
        struct reclaim_state *reclaim_state = current->reclaim_state;
+       gfp_t orig_mask;
        struct shrink_control shrink = {
                .gfp_mask = sc->gfp_mask,
        };
+       enum zone_type requested_highidx = gfp_zone(sc->gfp_mask);
 
        /*
         * If the number of buffer_heads in the machine exceeds the maximum
         * allowed level, force direct reclaim to scan the highmem zone as
         * highmem pages could be pinning lowmem pages storing buffer_heads
         */
+       orig_mask = sc->gfp_mask;
        if (buffer_heads_over_limit)
                sc->gfp_mask |= __GFP_HIGHMEM;
 
@@ -2356,7 +2345,8 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                                 * noticeable problem, like transparent huge
                                 * page allocations.
                                 */
-                               if (compaction_ready(zone, sc)) {
+                               if ((zonelist_zone_idx(z) <= requested_highidx)
+                                   && compaction_ready(zone, sc)) {
                                        aborted_reclaim = true;
                                        continue;
                                }
@@ -2393,6 +2383,12 @@ static bool shrink_zones(struct zonelist *zonelist, struct scan_control *sc)
                }
        }
 
+       /*
+        * Restore to original mask to avoid the impact on the caller if we
+        * promoted it to __GFP_HIGHMEM.
+        */
+       sc->gfp_mask = orig_mask;
+
        return aborted_reclaim;
 }
 
index 197b4c4..302dd07 100644 (file)
@@ -1298,14 +1298,14 @@ static int __init setup_vmstat(void)
 #ifdef CONFIG_SMP
        int cpu;
 
-       register_cpu_notifier(&vmstat_notifier);
+       cpu_notifier_register_begin();
+       __register_cpu_notifier(&vmstat_notifier);
 
-       get_online_cpus();
        for_each_online_cpu(cpu) {
                start_cpu_timer(cpu);
                node_set_state(cpu_to_node(cpu), N_CPU);
        }
-       put_online_cpus();
+       cpu_notifier_register_done();
 #endif
 #ifdef CONFIG_PROC_FS
        proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
index c03ca5e..36b4591 100644 (file)
@@ -814,21 +814,32 @@ static void zs_exit(void)
 {
        int cpu;
 
+       cpu_notifier_register_begin();
+
        for_each_online_cpu(cpu)
                zs_cpu_notifier(NULL, CPU_DEAD, (void *)(long)cpu);
-       unregister_cpu_notifier(&zs_cpu_nb);
+       __unregister_cpu_notifier(&zs_cpu_nb);
+
+       cpu_notifier_register_done();
 }
 
 static int zs_init(void)
 {
        int cpu, ret;
 
-       register_cpu_notifier(&zs_cpu_nb);
+       cpu_notifier_register_begin();
+
+       __register_cpu_notifier(&zs_cpu_nb);
        for_each_online_cpu(cpu) {
                ret = zs_cpu_notifier(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
-               if (notifier_to_errno(ret))
+               if (notifier_to_errno(ret)) {
+                       cpu_notifier_register_done();
                        goto fail;
+               }
        }
+
+       cpu_notifier_register_done();
+
        return 0;
 fail:
        zs_exit();
index e55bab9..aeaef0f 100644 (file)
@@ -89,6 +89,9 @@ static unsigned int zswap_max_pool_percent = 20;
 module_param_named(max_pool_percent,
                        zswap_max_pool_percent, uint, 0644);
 
+/* zbud_pool is shared by all of zswap backend  */
+static struct zbud_pool *zswap_pool;
+
 /*********************************
 * compression functions
 **********************************/
@@ -160,14 +163,14 @@ static void zswap_comp_exit(void)
  * rbnode - links the entry into red-black tree for the appropriate swap type
  * refcount - the number of outstanding reference to the entry. This is needed
  *            to protect against premature freeing of the entry by code
- *            concurent calls to load, invalidate, and writeback.  The lock
+ *            concurrent calls to load, invalidate, and writeback.  The lock
  *            for the zswap_tree structure that contains the entry must
  *            be held while changing the refcount.  Since the lock must
  *            be held, there is no reason to also make refcount atomic.
  * offset - the swap offset for the entry.  Index into the red-black tree.
- * handle - zsmalloc allocation handle that stores the compressed page data
+ * handle - zbud allocation handle that stores the compressed page data
  * length - the length in bytes of the compressed page data.  Needed during
- *           decompression
+ *          decompression
  */
 struct zswap_entry {
        struct rb_node rbnode;
@@ -189,7 +192,6 @@ struct zswap_header {
 struct zswap_tree {
        struct rb_root rbroot;
        spinlock_t lock;
-       struct zbud_pool *pool;
 };
 
 static struct zswap_tree *zswap_trees[MAX_SWAPFILES];
@@ -202,7 +204,7 @@ static struct kmem_cache *zswap_entry_cache;
 static int zswap_entry_cache_create(void)
 {
        zswap_entry_cache = KMEM_CACHE(zswap_entry, 0);
-       return (zswap_entry_cache == NULL);
+       return zswap_entry_cache == NULL;
 }
 
 static void zswap_entry_cache_destory(void)
@@ -282,16 +284,15 @@ static void zswap_rb_erase(struct rb_root *root, struct zswap_entry *entry)
 }
 
 /*
- * Carries out the common pattern of freeing and entry's zsmalloc allocation,
+ * Carries out the common pattern of freeing and entry's zbud allocation,
  * freeing the entry itself, and decrementing the number of stored pages.
  */
-static void zswap_free_entry(struct zswap_tree *tree,
-                       struct zswap_entry *entry)
+static void zswap_free_entry(struct zswap_entry *entry)
 {
-       zbud_free(tree->pool, entry->handle);
+       zbud_free(zswap_pool, entry->handle);
        zswap_entry_cache_free(entry);
        atomic_dec(&zswap_stored_pages);
-       zswap_pool_pages = zbud_get_pool_size(tree->pool);
+       zswap_pool_pages = zbud_get_pool_size(zswap_pool);
 }
 
 /* caller must hold the tree lock */
@@ -311,7 +312,7 @@ static void zswap_entry_put(struct zswap_tree *tree,
        BUG_ON(refcount < 0);
        if (refcount == 0) {
                zswap_rb_erase(&tree->rbroot, entry);
-               zswap_free_entry(tree, entry);
+               zswap_free_entry(entry);
        }
 }
 
@@ -387,18 +388,18 @@ static int zswap_cpu_init(void)
 {
        unsigned long cpu;
 
-       get_online_cpus();
+       cpu_notifier_register_begin();
        for_each_online_cpu(cpu)
                if (__zswap_cpu_notifier(CPU_UP_PREPARE, cpu) != NOTIFY_OK)
                        goto cleanup;
-       register_cpu_notifier(&zswap_cpu_notifier_block);
-       put_online_cpus();
+       __register_cpu_notifier(&zswap_cpu_notifier_block);
+       cpu_notifier_register_done();
        return 0;
 
 cleanup:
        for_each_online_cpu(cpu)
                __zswap_cpu_notifier(CPU_UP_CANCELED, cpu);
-       put_online_cpus();
+       cpu_notifier_register_done();
        return -ENOMEM;
 }
 
@@ -407,8 +408,8 @@ cleanup:
 **********************************/
 static bool zswap_is_full(void)
 {
-       return (totalram_pages * zswap_max_pool_percent / 100 <
-               zswap_pool_pages);
+       return totalram_pages * zswap_max_pool_percent / 100 <
+               zswap_pool_pages;
 }
 
 /*********************************
@@ -545,7 +546,6 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle)
        zbud_unmap(pool, handle);
        tree = zswap_trees[swp_type(swpentry)];
        offset = swp_offset(swpentry);
-       BUG_ON(pool != tree->pool);
 
        /* find and ref zswap entry */
        spin_lock(&tree->lock);
@@ -573,13 +573,13 @@ static int zswap_writeback_entry(struct zbud_pool *pool, unsigned long handle)
        case ZSWAP_SWAPCACHE_NEW: /* page is locked */
                /* decompress */
                dlen = PAGE_SIZE;
-               src = (u8 *)zbud_map(tree->pool, entry->handle) +
+               src = (u8 *)zbud_map(zswap_pool, entry->handle) +
                        sizeof(struct zswap_header);
                dst = kmap_atomic(page);
                ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src,
                                entry->length, dst, &dlen);
                kunmap_atomic(dst);
-               zbud_unmap(tree->pool, entry->handle);
+               zbud_unmap(zswap_pool, entry->handle);
                BUG_ON(ret);
                BUG_ON(dlen != PAGE_SIZE);
 
@@ -652,7 +652,7 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
        /* reclaim space if needed */
        if (zswap_is_full()) {
                zswap_pool_limit_hit++;
-               if (zbud_reclaim_page(tree->pool, 8)) {
+               if (zbud_reclaim_page(zswap_pool, 8)) {
                        zswap_reject_reclaim_fail++;
                        ret = -ENOMEM;
                        goto reject;
@@ -679,7 +679,7 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
 
        /* store */
        len = dlen + sizeof(struct zswap_header);
-       ret = zbud_alloc(tree->pool, len, __GFP_NORETRY | __GFP_NOWARN,
+       ret = zbud_alloc(zswap_pool, len, __GFP_NORETRY | __GFP_NOWARN,
                &handle);
        if (ret == -ENOSPC) {
                zswap_reject_compress_poor++;
@@ -689,11 +689,11 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
                zswap_reject_alloc_fail++;
                goto freepage;
        }
-       zhdr = zbud_map(tree->pool, handle);
+       zhdr = zbud_map(zswap_pool, handle);
        zhdr->swpentry = swp_entry(type, offset);
        buf = (u8 *)(zhdr + 1);
        memcpy(buf, dst, dlen);
-       zbud_unmap(tree->pool, handle);
+       zbud_unmap(zswap_pool, handle);
        put_cpu_var(zswap_dstmem);
 
        /* populate entry */
@@ -716,7 +716,7 @@ static int zswap_frontswap_store(unsigned type, pgoff_t offset,
 
        /* update stats */
        atomic_inc(&zswap_stored_pages);
-       zswap_pool_pages = zbud_get_pool_size(tree->pool);
+       zswap_pool_pages = zbud_get_pool_size(zswap_pool);
 
        return 0;
 
@@ -752,13 +752,13 @@ static int zswap_frontswap_load(unsigned type, pgoff_t offset,
 
        /* decompress */
        dlen = PAGE_SIZE;
-       src = (u8 *)zbud_map(tree->pool, entry->handle) +
+       src = (u8 *)zbud_map(zswap_pool, entry->handle) +
                        sizeof(struct zswap_header);
        dst = kmap_atomic(page);
        ret = zswap_comp_op(ZSWAP_COMPOP_DECOMPRESS, src, entry->length,
                dst, &dlen);
        kunmap_atomic(dst);
-       zbud_unmap(tree->pool, entry->handle);
+       zbud_unmap(zswap_pool, entry->handle);
        BUG_ON(ret);
 
        spin_lock(&tree->lock);
@@ -804,11 +804,9 @@ static void zswap_frontswap_invalidate_area(unsigned type)
        /* walk the tree and free everything */
        spin_lock(&tree->lock);
        rbtree_postorder_for_each_entry_safe(entry, n, &tree->rbroot, rbnode)
-               zswap_free_entry(tree, entry);
+               zswap_free_entry(entry);
        tree->rbroot = RB_ROOT;
        spin_unlock(&tree->lock);
-
-       zbud_destroy_pool(tree->pool);
        kfree(tree);
        zswap_trees[type] = NULL;
 }
@@ -822,20 +820,14 @@ static void zswap_frontswap_init(unsigned type)
        struct zswap_tree *tree;
 
        tree = kzalloc(sizeof(struct zswap_tree), GFP_KERNEL);
-       if (!tree)
-               goto err;
-       tree->pool = zbud_create_pool(GFP_KERNEL, &zswap_zbud_ops);
-       if (!tree->pool)
-               goto freetree;
+       if (!tree) {
+               pr_err("alloc failed, zswap disabled for swap type %d\n", type);
+               return;
+       }
+
        tree->rbroot = RB_ROOT;
        spin_lock_init(&tree->lock);
        zswap_trees[type] = tree;
-       return;
-
-freetree:
-       kfree(tree);
-err:
-       pr_err("alloc failed, zswap disabled for swap type %d\n", type);
 }
 
 static struct frontswap_ops zswap_frontswap_ops = {
@@ -907,9 +899,16 @@ static int __init init_zswap(void)
                return 0;
 
        pr_info("loading zswap\n");
+
+       zswap_pool = zbud_create_pool(GFP_KERNEL, &zswap_zbud_ops);
+       if (!zswap_pool) {
+               pr_err("zbud pool creation failed\n");
+               goto error;
+       }
+
        if (zswap_entry_cache_create()) {
                pr_err("entry cache creation failed\n");
-               goto error;
+               goto cachefail;
        }
        if (zswap_comp_init()) {
                pr_err("compressor initialization failed\n");
@@ -919,6 +918,7 @@ static int __init init_zswap(void)
                pr_err("per-cpu initialization failed\n");
                goto pcpufail;
        }
+
        frontswap_register_ops(&zswap_frontswap_ops);
        if (zswap_debugfs_init())
                pr_warn("debugfs initialization failed\n");
@@ -927,6 +927,8 @@ pcpufail:
        zswap_comp_exit();
 compfail:
        zswap_entry_cache_destory();
+cachefail:
+       zbud_destroy_pool(zswap_pool);
 error:
        return -ENOMEM;
 }
index 0e474b1..1059ed3 100644 (file)
@@ -1044,10 +1044,9 @@ static int do_replace_finish(struct net *net, struct ebt_replace *repl,
        if (repl->num_counters &&
           copy_to_user(repl->counters, counterstmp,
           repl->num_counters * sizeof(struct ebt_counter))) {
-               ret = -EFAULT;
+               /* Silent error, can't fail, new table is already in place */
+               net_warn_ratelimited("ebtables: counters copy to user failed while replacing table\n");
        }
-       else
-               ret = 0;
 
        /* decrease module count and free resources */
        EBT_ENTRY_ITERATE(table->entries, table->entries_size,
index b703790..a1ef53c 100644 (file)
@@ -292,10 +292,12 @@ static int is_out(const struct crush_map *map,
  * @outpos: our position in that vector
  * @tries: number of attempts to make
  * @recurse_tries: number of attempts to have recursive chooseleaf make
- * @local_tries: localized retries
- * @local_fallback_tries: localized fallback retries
+ * @local_retries: localized retries
+ * @local_fallback_retries: localized fallback retries
  * @recurse_to_leaf: true if we want one device under each item of given type (chooseleaf instead of choose)
+ * @vary_r: pass r to recursive calls
  * @out2: second output vector for leaf items (if @recurse_to_leaf)
+ * @parent_r: r value passed from the parent
  */
 static int crush_choose_firstn(const struct crush_map *map,
                               struct crush_bucket *bucket,
@@ -304,10 +306,12 @@ static int crush_choose_firstn(const struct crush_map *map,
                               int *out, int outpos,
                               unsigned int tries,
                               unsigned int recurse_tries,
-                              unsigned int local_tries,
-                              unsigned int local_fallback_tries,
+                              unsigned int local_retries,
+                              unsigned int local_fallback_retries,
                               int recurse_to_leaf,
-                              int *out2)
+                              unsigned int vary_r,
+                              int *out2,
+                              int parent_r)
 {
        int rep;
        unsigned int ftotal, flocal;
@@ -319,8 +323,11 @@ static int crush_choose_firstn(const struct crush_map *map,
        int itemtype;
        int collide, reject;
 
-       dprintk("CHOOSE%s bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "",
-               bucket->id, x, outpos, numrep);
+       dprintk("CHOOSE%s bucket %d x %d outpos %d numrep %d tries %d recurse_tries %d local_retries %d local_fallback_retries %d parent_r %d\n",
+               recurse_to_leaf ? "_LEAF" : "",
+               bucket->id, x, outpos, numrep,
+               tries, recurse_tries, local_retries, local_fallback_retries,
+               parent_r);
 
        for (rep = outpos; rep < numrep; rep++) {
                /* keep trying until we get a non-out, non-colliding item */
@@ -335,7 +342,7 @@ static int crush_choose_firstn(const struct crush_map *map,
                        do {
                                collide = 0;
                                retry_bucket = 0;
-                               r = rep;
+                               r = rep + parent_r;
                                /* r' = r + f_total */
                                r += ftotal;
 
@@ -344,9 +351,9 @@ static int crush_choose_firstn(const struct crush_map *map,
                                        reject = 1;
                                        goto reject;
                                }
-                               if (local_fallback_tries > 0 &&
+                               if (local_fallback_retries > 0 &&
                                    flocal >= (in->size>>1) &&
-                                   flocal > local_fallback_tries)
+                                   flocal > local_fallback_retries)
                                        item = bucket_perm_choose(in, x, r);
                                else
                                        item = crush_bucket_choose(in, x, r);
@@ -387,16 +394,23 @@ static int crush_choose_firstn(const struct crush_map *map,
                                reject = 0;
                                if (!collide && recurse_to_leaf) {
                                        if (item < 0) {
+                                               int sub_r;
+                                               if (vary_r)
+                                                       sub_r = r >> (vary_r-1);
+                                               else
+                                                       sub_r = 0;
                                                if (crush_choose_firstn(map,
                                                         map->buckets[-1-item],
                                                         weight, weight_max,
                                                         x, outpos+1, 0,
                                                         out2, outpos,
                                                         recurse_tries, 0,
-                                                        local_tries,
-                                                        local_fallback_tries,
+                                                        local_retries,
+                                                        local_fallback_retries,
                                                         0,
-                                                        NULL) <= outpos)
+                                                        vary_r,
+                                                        NULL,
+                                                        sub_r) <= outpos)
                                                        /* didn't get leaf */
                                                        reject = 1;
                                        } else {
@@ -420,14 +434,14 @@ reject:
                                        ftotal++;
                                        flocal++;
 
-                                       if (collide && flocal <= local_tries)
+                                       if (collide && flocal <= local_retries)
                                                /* retry locally a few times */
                                                retry_bucket = 1;
-                                       else if (local_fallback_tries > 0 &&
-                                                flocal <= in->size + local_fallback_tries)
+                                       else if (local_fallback_retries > 0 &&
+                                                flocal <= in->size + local_fallback_retries)
                                                /* exhaustive bucket search */
                                                retry_bucket = 1;
-                                       else if (ftotal <= tries)
+                                       else if (ftotal < tries)
                                                /* then retry descent */
                                                retry_descent = 1;
                                        else
@@ -640,10 +654,20 @@ int crush_do_rule(const struct crush_map *map,
        __u32 step;
        int i, j;
        int numrep;
-       int choose_tries = map->choose_total_tries;
-       int choose_local_tries = map->choose_local_tries;
-       int choose_local_fallback_tries = map->choose_local_fallback_tries;
+       /*
+        * the original choose_total_tries value was off by one (it
+        * counted "retries" and not "tries").  add one.
+        */
+       int choose_tries = map->choose_total_tries + 1;
        int choose_leaf_tries = 0;
+       /*
+        * the local tries values were counted as "retries", though,
+        * and need no adjustment
+        */
+       int choose_local_retries = map->choose_local_tries;
+       int choose_local_fallback_retries = map->choose_local_fallback_tries;
+
+       int vary_r = map->chooseleaf_vary_r;
 
        if ((__u32)ruleno >= map->max_rules) {
                dprintk(" bad ruleno %d\n", ruleno);
@@ -676,13 +700,18 @@ int crush_do_rule(const struct crush_map *map,
                        break;
 
                case CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES:
-                       if (curstep->arg1 > 0)
-                               choose_local_tries = curstep->arg1;
+                       if (curstep->arg1 >= 0)
+                               choose_local_retries = curstep->arg1;
                        break;
 
                case CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES:
-                       if (curstep->arg1 > 0)
-                               choose_local_fallback_tries = curstep->arg1;
+                       if (curstep->arg1 >= 0)
+                               choose_local_fallback_retries = curstep->arg1;
+                       break;
+
+               case CRUSH_RULE_SET_CHOOSELEAF_VARY_R:
+                       if (curstep->arg1 >= 0)
+                               vary_r = curstep->arg1;
                        break;
 
                case CRUSH_RULE_CHOOSELEAF_FIRSTN:
@@ -734,10 +763,12 @@ int crush_do_rule(const struct crush_map *map,
                                                o+osize, j,
                                                choose_tries,
                                                recurse_tries,
-                                               choose_local_tries,
-                                               choose_local_fallback_tries,
+                                               choose_local_retries,
+                                               choose_local_fallback_retries,
                                                recurse_to_leaf,
-                                               c+osize);
+                                               vary_r,
+                                               c+osize,
+                                               0);
                                } else {
                                        crush_choose_indep(
                                                map,
index 258a382..10421a4 100644 (file)
@@ -53,34 +53,55 @@ static int osdmap_show(struct seq_file *s, void *p)
 {
        int i;
        struct ceph_client *client = s->private;
+       struct ceph_osdmap *map = client->osdc.osdmap;
        struct rb_node *n;
 
-       if (client->osdc.osdmap == NULL)
+       if (map == NULL)
                return 0;
-       seq_printf(s, "epoch %d\n", client->osdc.osdmap->epoch);
+
+       seq_printf(s, "epoch %d\n", map->epoch);
        seq_printf(s, "flags%s%s\n",
-                  (client->osdc.osdmap->flags & CEPH_OSDMAP_NEARFULL) ?
-                  " NEARFULL" : "",
-                  (client->osdc.osdmap->flags & CEPH_OSDMAP_FULL) ?
-                  " FULL" : "");
-       for (n = rb_first(&client->osdc.osdmap->pg_pools); n; n = rb_next(n)) {
+                  (map->flags & CEPH_OSDMAP_NEARFULL) ?  " NEARFULL" : "",
+                  (map->flags & CEPH_OSDMAP_FULL) ?  " FULL" : "");
+
+       for (n = rb_first(&map->pg_pools); n; n = rb_next(n)) {
                struct ceph_pg_pool_info *pool =
                        rb_entry(n, struct ceph_pg_pool_info, node);
-               seq_printf(s, "pg_pool %llu pg_num %d / %d\n",
-                          (unsigned long long)pool->id, pool->pg_num,
-                          pool->pg_num_mask);
+
+               seq_printf(s, "pool %lld pg_num %u (%d) read_tier %lld write_tier %lld\n",
+                          pool->id, pool->pg_num, pool->pg_num_mask,
+                          pool->read_tier, pool->write_tier);
        }
-       for (i = 0; i < client->osdc.osdmap->max_osd; i++) {
-               struct ceph_entity_addr *addr =
-                       &client->osdc.osdmap->osd_addr[i];
-               int state = client->osdc.osdmap->osd_state[i];
+       for (i = 0; i < map->max_osd; i++) {
+               struct ceph_entity_addr *addr = &map->osd_addr[i];
+               int state = map->osd_state[i];
                char sb[64];
 
-               seq_printf(s, "\tosd%d\t%s\t%3d%%\t(%s)\n",
+               seq_printf(s, "osd%d\t%s\t%3d%%\t(%s)\t%3d%%\n",
                           i, ceph_pr_addr(&addr->in_addr),
-                          ((client->osdc.osdmap->osd_weight[i]*100) >> 16),
-                          ceph_osdmap_state_str(sb, sizeof(sb), state));
+                          ((map->osd_weight[i]*100) >> 16),
+                          ceph_osdmap_state_str(sb, sizeof(sb), state),
+                          ((ceph_get_primary_affinity(map, i)*100) >> 16));
+       }
+       for (n = rb_first(&map->pg_temp); n; n = rb_next(n)) {
+               struct ceph_pg_mapping *pg =
+                       rb_entry(n, struct ceph_pg_mapping, node);
+
+               seq_printf(s, "pg_temp %llu.%x [", pg->pgid.pool,
+                          pg->pgid.seed);
+               for (i = 0; i < pg->pg_temp.len; i++)
+                       seq_printf(s, "%s%d", (i == 0 ? "" : ","),
+                                  pg->pg_temp.osds[i]);
+               seq_printf(s, "]\n");
        }
+       for (n = rb_first(&map->primary_temp); n; n = rb_next(n)) {
+               struct ceph_pg_mapping *pg =
+                       rb_entry(n, struct ceph_pg_mapping, node);
+
+               seq_printf(s, "primary_temp %llu.%x %d\n", pg->pgid.pool,
+                          pg->pgid.seed, pg->primary_temp.osd);
+       }
+
        return 0;
 }
 
index 30efc5c..4f55f9c 100644 (file)
@@ -919,6 +919,9 @@ static bool ceph_msg_data_pages_advance(struct ceph_msg_data_cursor *cursor,
        if (!bytes || cursor->page_offset)
                return false;   /* more bytes to process in the current page */
 
+       if (!cursor->resid)
+               return false;   /* no more data */
+
        /* Move on to the next page; offset is already at 0 */
 
        BUG_ON(cursor->page_index >= cursor->page_count);
@@ -1004,6 +1007,9 @@ static bool ceph_msg_data_pagelist_advance(struct ceph_msg_data_cursor *cursor,
        if (!bytes || cursor->offset & ~PAGE_MASK)
                return false;   /* more bytes to process in the current page */
 
+       if (!cursor->resid)
+               return false;   /* no more data */
+
        /* Move on to the next page */
 
        BUG_ON(list_is_last(&cursor->page->lru, &pagelist->head));
index 82750f9..b0dfce7 100644 (file)
@@ -436,6 +436,7 @@ static bool osd_req_opcode_valid(u16 opcode)
        case CEPH_OSD_OP_OMAPCLEAR:
        case CEPH_OSD_OP_OMAPRMKEYS:
        case CEPH_OSD_OP_OMAP_CMP:
+       case CEPH_OSD_OP_SETALLOCHINT:
        case CEPH_OSD_OP_CLONERANGE:
        case CEPH_OSD_OP_ASSERT_SRC_VERSION:
        case CEPH_OSD_OP_SRC_CMPXATTR:
@@ -591,6 +592,26 @@ void osd_req_op_watch_init(struct ceph_osd_request *osd_req,
 }
 EXPORT_SYMBOL(osd_req_op_watch_init);
 
+void osd_req_op_alloc_hint_init(struct ceph_osd_request *osd_req,
+                               unsigned int which,
+                               u64 expected_object_size,
+                               u64 expected_write_size)
+{
+       struct ceph_osd_req_op *op = _osd_req_op_init(osd_req, which,
+                                                     CEPH_OSD_OP_SETALLOCHINT);
+
+       op->alloc_hint.expected_object_size = expected_object_size;
+       op->alloc_hint.expected_write_size = expected_write_size;
+
+       /*
+        * CEPH_OSD_OP_SETALLOCHINT op is advisory and therefore deemed
+        * not worth a feature bit.  Set FAILOK per-op flag to make
+        * sure older osds don't trip over an unsupported opcode.
+        */
+       op->flags |= CEPH_OSD_OP_FLAG_FAILOK;
+}
+EXPORT_SYMBOL(osd_req_op_alloc_hint_init);
+
 static void ceph_osdc_msg_data_add(struct ceph_msg *msg,
                                struct ceph_osd_data *osd_data)
 {
@@ -681,6 +702,12 @@ static u64 osd_req_encode_op(struct ceph_osd_request *req,
                dst->watch.ver = cpu_to_le64(src->watch.ver);
                dst->watch.flag = src->watch.flag;
                break;
+       case CEPH_OSD_OP_SETALLOCHINT:
+               dst->alloc_hint.expected_object_size =
+                   cpu_to_le64(src->alloc_hint.expected_object_size);
+               dst->alloc_hint.expected_write_size =
+                   cpu_to_le64(src->alloc_hint.expected_write_size);
+               break;
        default:
                pr_err("unsupported osd opcode %s\n",
                        ceph_osd_op_name(src->op));
@@ -688,7 +715,9 @@ static u64 osd_req_encode_op(struct ceph_osd_request *req,
 
                return 0;
        }
+
        dst->op = cpu_to_le16(src->op);
+       dst->flags = cpu_to_le32(src->flags);
        dst->payload_len = cpu_to_le32(src->payload_len);
 
        return request_data_len;
@@ -1304,7 +1333,7 @@ static int __map_request(struct ceph_osd_client *osdc,
 {
        struct ceph_pg pgid;
        int acting[CEPH_PG_MAX_SIZE];
-       int o = -1, num = 0;
+       int num, o;
        int err;
        bool was_paused;
 
@@ -1317,11 +1346,9 @@ static int __map_request(struct ceph_osd_client *osdc,
        }
        req->r_pgid = pgid;
 
-       err = ceph_calc_pg_acting(osdc->osdmap, pgid, acting);
-       if (err > 0) {
-               o = acting[0];
-               num = err;
-       }
+       num = ceph_calc_pg_acting(osdc->osdmap, pgid, acting, &o);
+       if (num < 0)
+               num = 0;
 
        was_paused = req->r_paused;
        req->r_paused = __req_should_be_paused(osdc, req);
@@ -2033,7 +2060,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                        int skipped_map = 0;
 
                        dout("taking full map %u len %d\n", epoch, maplen);
-                       newmap = osdmap_decode(&p, p+maplen);
+                       newmap = ceph_osdmap_decode(&p, p+maplen);
                        if (IS_ERR(newmap)) {
                                err = PTR_ERR(newmap);
                                goto bad;
index aade4a5..e632b5a 100644 (file)
@@ -343,7 +343,7 @@ bad:
 
 /*
  * rbtree of pg_mapping for handling pg_temp (explicit mapping of pgid
- * to a set of osds)
+ * to a set of osds) and primary_temp (explicit primary setting)
  */
 static int pgid_cmp(struct ceph_pg l, struct ceph_pg r)
 {
@@ -506,7 +506,7 @@ static void __remove_pg_pool(struct rb_root *root, struct ceph_pg_pool_info *pi)
        kfree(pi);
 }
 
-static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi)
+static int decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi)
 {
        u8 ev, cv;
        unsigned len, num;
@@ -587,7 +587,7 @@ bad:
        return -EINVAL;
 }
 
-static int __decode_pool_names(void **p, void *end, struct ceph_osdmap *map)
+static int decode_pool_names(void **p, void *end, struct ceph_osdmap *map)
 {
        struct ceph_pg_pool_info *pi;
        u32 num, len;
@@ -633,6 +633,13 @@ void ceph_osdmap_destroy(struct ceph_osdmap *map)
                rb_erase(&pg->node, &map->pg_temp);
                kfree(pg);
        }
+       while (!RB_EMPTY_ROOT(&map->primary_temp)) {
+               struct ceph_pg_mapping *pg =
+                       rb_entry(rb_first(&map->primary_temp),
+                                struct ceph_pg_mapping, node);
+               rb_erase(&pg->node, &map->primary_temp);
+               kfree(pg);
+       }
        while (!RB_EMPTY_ROOT(&map->pg_pools)) {
                struct ceph_pg_pool_info *pi =
                        rb_entry(rb_first(&map->pg_pools),
@@ -642,186 +649,516 @@ void ceph_osdmap_destroy(struct ceph_osdmap *map)
        kfree(map->osd_state);
        kfree(map->osd_weight);
        kfree(map->osd_addr);
+       kfree(map->osd_primary_affinity);
        kfree(map);
 }
 
 /*
- * adjust max osd value.  reallocate arrays.
+ * Adjust max_osd value, (re)allocate arrays.
+ *
+ * The new elements are properly initialized.
  */
 static int osdmap_set_max_osd(struct ceph_osdmap *map, int max)
 {
        u8 *state;
-       struct ceph_entity_addr *addr;
        u32 *weight;
+       struct ceph_entity_addr *addr;
+       int i;
 
-       state = kcalloc(max, sizeof(*state), GFP_NOFS);
-       addr = kcalloc(max, sizeof(*addr), GFP_NOFS);
-       weight = kcalloc(max, sizeof(*weight), GFP_NOFS);
-       if (state == NULL || addr == NULL || weight == NULL) {
+       state = krealloc(map->osd_state, max*sizeof(*state), GFP_NOFS);
+       weight = krealloc(map->osd_weight, max*sizeof(*weight), GFP_NOFS);
+       addr = krealloc(map->osd_addr, max*sizeof(*addr), GFP_NOFS);
+       if (!state || !weight || !addr) {
                kfree(state);
-               kfree(addr);
                kfree(weight);
+               kfree(addr);
+
                return -ENOMEM;
        }
 
-       /* copy old? */
-       if (map->osd_state) {
-               memcpy(state, map->osd_state, map->max_osd*sizeof(*state));
-               memcpy(addr, map->osd_addr, map->max_osd*sizeof(*addr));
-               memcpy(weight, map->osd_weight, map->max_osd*sizeof(*weight));
-               kfree(map->osd_state);
-               kfree(map->osd_addr);
-               kfree(map->osd_weight);
+       for (i = map->max_osd; i < max; i++) {
+               state[i] = 0;
+               weight[i] = CEPH_OSD_OUT;
+               memset(addr + i, 0, sizeof(*addr));
        }
 
        map->osd_state = state;
        map->osd_weight = weight;
        map->osd_addr = addr;
+
+       if (map->osd_primary_affinity) {
+               u32 *affinity;
+
+               affinity = krealloc(map->osd_primary_affinity,
+                                   max*sizeof(*affinity), GFP_NOFS);
+               if (!affinity)
+                       return -ENOMEM;
+
+               for (i = map->max_osd; i < max; i++)
+                       affinity[i] = CEPH_OSD_DEFAULT_PRIMARY_AFFINITY;
+
+               map->osd_primary_affinity = affinity;
+       }
+
        map->max_osd = max;
+
        return 0;
 }
 
+#define OSDMAP_WRAPPER_COMPAT_VER      7
+#define OSDMAP_CLIENT_DATA_COMPAT_VER  1
+
 /*
- * decode a full map.
+ * Return 0 or error.  On success, *v is set to 0 for old (v6) osdmaps,
+ * to struct_v of the client_data section for new (v7 and above)
+ * osdmaps.
  */
-struct ceph_osdmap *osdmap_decode(void **p, void *end)
+static int get_osdmap_client_data_v(void **p, void *end,
+                                   const char *prefix, u8 *v)
 {
-       struct ceph_osdmap *map;
-       u16 version;
-       u32 len, max, i;
-       int err = -EINVAL;
-       void *start = *p;
-       struct ceph_pg_pool_info *pi;
+       u8 struct_v;
+
+       ceph_decode_8_safe(p, end, struct_v, e_inval);
+       if (struct_v >= 7) {
+               u8 struct_compat;
+
+               ceph_decode_8_safe(p, end, struct_compat, e_inval);
+               if (struct_compat > OSDMAP_WRAPPER_COMPAT_VER) {
+                       pr_warning("got v %d cv %d > %d of %s ceph_osdmap\n",
+                                  struct_v, struct_compat,
+                                  OSDMAP_WRAPPER_COMPAT_VER, prefix);
+                       return -EINVAL;
+               }
+               *p += 4; /* ignore wrapper struct_len */
+
+               ceph_decode_8_safe(p, end, struct_v, e_inval);
+               ceph_decode_8_safe(p, end, struct_compat, e_inval);
+               if (struct_compat > OSDMAP_CLIENT_DATA_COMPAT_VER) {
+                       pr_warning("got v %d cv %d > %d of %s ceph_osdmap client data\n",
+                                  struct_v, struct_compat,
+                                  OSDMAP_CLIENT_DATA_COMPAT_VER, prefix);
+                       return -EINVAL;
+               }
+               *p += 4; /* ignore client data struct_len */
+       } else {
+               u16 version;
+
+               *p -= 1;
+               ceph_decode_16_safe(p, end, version, e_inval);
+               if (version < 6) {
+                       pr_warning("got v %d < 6 of %s ceph_osdmap\n", version,
+                                  prefix);
+                       return -EINVAL;
+               }
 
-       dout("osdmap_decode %p to %p len %d\n", *p, end, (int)(end - *p));
+               /* old osdmap enconding */
+               struct_v = 0;
+       }
 
-       map = kzalloc(sizeof(*map), GFP_NOFS);
-       if (map == NULL)
-               return ERR_PTR(-ENOMEM);
-       map->pg_temp = RB_ROOT;
+       *v = struct_v;
+       return 0;
 
-       ceph_decode_16_safe(p, end, version, bad);
-       if (version > 6) {
-               pr_warning("got unknown v %d > 6 of osdmap\n", version);
-               goto bad;
+e_inval:
+       return -EINVAL;
+}
+
+static int __decode_pools(void **p, void *end, struct ceph_osdmap *map,
+                         bool incremental)
+{
+       u32 n;
+
+       ceph_decode_32_safe(p, end, n, e_inval);
+       while (n--) {
+               struct ceph_pg_pool_info *pi;
+               u64 pool;
+               int ret;
+
+               ceph_decode_64_safe(p, end, pool, e_inval);
+
+               pi = __lookup_pg_pool(&map->pg_pools, pool);
+               if (!incremental || !pi) {
+                       pi = kzalloc(sizeof(*pi), GFP_NOFS);
+                       if (!pi)
+                               return -ENOMEM;
+
+                       pi->id = pool;
+
+                       ret = __insert_pg_pool(&map->pg_pools, pi);
+                       if (ret) {
+                               kfree(pi);
+                               return ret;
+                       }
+               }
+
+               ret = decode_pool(p, end, pi);
+               if (ret)
+                       return ret;
        }
-       if (version < 6) {
-               pr_warning("got old v %d < 6 of osdmap\n", version);
-               goto bad;
+
+       return 0;
+
+e_inval:
+       return -EINVAL;
+}
+
+static int decode_pools(void **p, void *end, struct ceph_osdmap *map)
+{
+       return __decode_pools(p, end, map, false);
+}
+
+static int decode_new_pools(void **p, void *end, struct ceph_osdmap *map)
+{
+       return __decode_pools(p, end, map, true);
+}
+
+static int __decode_pg_temp(void **p, void *end, struct ceph_osdmap *map,
+                           bool incremental)
+{
+       u32 n;
+
+       ceph_decode_32_safe(p, end, n, e_inval);
+       while (n--) {
+               struct ceph_pg pgid;
+               u32 len, i;
+               int ret;
+
+               ret = ceph_decode_pgid(p, end, &pgid);
+               if (ret)
+                       return ret;
+
+               ceph_decode_32_safe(p, end, len, e_inval);
+
+               ret = __remove_pg_mapping(&map->pg_temp, pgid);
+               BUG_ON(!incremental && ret != -ENOENT);
+
+               if (!incremental || len > 0) {
+                       struct ceph_pg_mapping *pg;
+
+                       ceph_decode_need(p, end, len*sizeof(u32), e_inval);
+
+                       if (len > (UINT_MAX - sizeof(*pg)) / sizeof(u32))
+                               return -EINVAL;
+
+                       pg = kzalloc(sizeof(*pg) + len*sizeof(u32), GFP_NOFS);
+                       if (!pg)
+                               return -ENOMEM;
+
+                       pg->pgid = pgid;
+                       pg->pg_temp.len = len;
+                       for (i = 0; i < len; i++)
+                               pg->pg_temp.osds[i] = ceph_decode_32(p);
+
+                       ret = __insert_pg_mapping(pg, &map->pg_temp);
+                       if (ret) {
+                               kfree(pg);
+                               return ret;
+                       }
+               }
        }
 
-       ceph_decode_need(p, end, 2*sizeof(u64)+6*sizeof(u32), bad);
+       return 0;
+
+e_inval:
+       return -EINVAL;
+}
+
+static int decode_pg_temp(void **p, void *end, struct ceph_osdmap *map)
+{
+       return __decode_pg_temp(p, end, map, false);
+}
+
+static int decode_new_pg_temp(void **p, void *end, struct ceph_osdmap *map)
+{
+       return __decode_pg_temp(p, end, map, true);
+}
+
+static int __decode_primary_temp(void **p, void *end, struct ceph_osdmap *map,
+                                bool incremental)
+{
+       u32 n;
+
+       ceph_decode_32_safe(p, end, n, e_inval);
+       while (n--) {
+               struct ceph_pg pgid;
+               u32 osd;
+               int ret;
+
+               ret = ceph_decode_pgid(p, end, &pgid);
+               if (ret)
+                       return ret;
+
+               ceph_decode_32_safe(p, end, osd, e_inval);
+
+               ret = __remove_pg_mapping(&map->primary_temp, pgid);
+               BUG_ON(!incremental && ret != -ENOENT);
+
+               if (!incremental || osd != (u32)-1) {
+                       struct ceph_pg_mapping *pg;
+
+                       pg = kzalloc(sizeof(*pg), GFP_NOFS);
+                       if (!pg)
+                               return -ENOMEM;
+
+                       pg->pgid = pgid;
+                       pg->primary_temp.osd = osd;
+
+                       ret = __insert_pg_mapping(pg, &map->primary_temp);
+                       if (ret) {
+                               kfree(pg);
+                               return ret;
+                       }
+               }
+       }
+
+       return 0;
+
+e_inval:
+       return -EINVAL;
+}
+
+static int decode_primary_temp(void **p, void *end, struct ceph_osdmap *map)
+{
+       return __decode_primary_temp(p, end, map, false);
+}
+
+static int decode_new_primary_temp(void **p, void *end,
+                                  struct ceph_osdmap *map)
+{
+       return __decode_primary_temp(p, end, map, true);
+}
+
+u32 ceph_get_primary_affinity(struct ceph_osdmap *map, int osd)
+{
+       BUG_ON(osd >= map->max_osd);
+
+       if (!map->osd_primary_affinity)
+               return CEPH_OSD_DEFAULT_PRIMARY_AFFINITY;
+
+       return map->osd_primary_affinity[osd];
+}
+
+static int set_primary_affinity(struct ceph_osdmap *map, int osd, u32 aff)
+{
+       BUG_ON(osd >= map->max_osd);
+
+       if (!map->osd_primary_affinity) {
+               int i;
+
+               map->osd_primary_affinity = kmalloc(map->max_osd*sizeof(u32),
+                                                   GFP_NOFS);
+               if (!map->osd_primary_affinity)
+                       return -ENOMEM;
+
+               for (i = 0; i < map->max_osd; i++)
+                       map->osd_primary_affinity[i] =
+                           CEPH_OSD_DEFAULT_PRIMARY_AFFINITY;
+       }
+
+       map->osd_primary_affinity[osd] = aff;
+
+       return 0;
+}
+
+static int decode_primary_affinity(void **p, void *end,
+                                  struct ceph_osdmap *map)
+{
+       u32 len, i;
+
+       ceph_decode_32_safe(p, end, len, e_inval);
+       if (len == 0) {
+               kfree(map->osd_primary_affinity);
+               map->osd_primary_affinity = NULL;
+               return 0;
+       }
+       if (len != map->max_osd)
+               goto e_inval;
+
+       ceph_decode_need(p, end, map->max_osd*sizeof(u32), e_inval);
+
+       for (i = 0; i < map->max_osd; i++) {
+               int ret;
+
+               ret = set_primary_affinity(map, i, ceph_decode_32(p));
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+
+e_inval:
+       return -EINVAL;
+}
+
+static int decode_new_primary_affinity(void **p, void *end,
+                                      struct ceph_osdmap *map)
+{
+       u32 n;
+
+       ceph_decode_32_safe(p, end, n, e_inval);
+       while (n--) {
+               u32 osd, aff;
+               int ret;
+
+               ceph_decode_32_safe(p, end, osd, e_inval);
+               ceph_decode_32_safe(p, end, aff, e_inval);
+
+               ret = set_primary_affinity(map, osd, aff);
+               if (ret)
+                       return ret;
+
+               pr_info("osd%d primary-affinity 0x%x\n", osd, aff);
+       }
+
+       return 0;
+
+e_inval:
+       return -EINVAL;
+}
+
+/*
+ * decode a full map.
+ */
+static int osdmap_decode(void **p, void *end, struct ceph_osdmap *map)
+{
+       u8 struct_v;
+       u32 epoch = 0;
+       void *start = *p;
+       u32 max;
+       u32 len, i;
+       int err;
+
+       dout("%s %p to %p len %d\n", __func__, *p, end, (int)(end - *p));
+
+       err = get_osdmap_client_data_v(p, end, "full", &struct_v);
+       if (err)
+               goto bad;
+
+       /* fsid, epoch, created, modified */
+       ceph_decode_need(p, end, sizeof(map->fsid) + sizeof(u32) +
+                        sizeof(map->created) + sizeof(map->modified), e_inval);
        ceph_decode_copy(p, &map->fsid, sizeof(map->fsid));
-       map->epoch = ceph_decode_32(p);
+       epoch = map->epoch = ceph_decode_32(p);
        ceph_decode_copy(p, &map->created, sizeof(map->created));
        ceph_decode_copy(p, &map->modified, sizeof(map->modified));
 
-       ceph_decode_32_safe(p, end, max, bad);
-       while (max--) {
-               ceph_decode_need(p, end, 8 + 2, bad);
-               err = -ENOMEM;
-               pi = kzalloc(sizeof(*pi), GFP_NOFS);
-               if (!pi)
-                       goto bad;
-               pi->id = ceph_decode_64(p);
-               err = __decode_pool(p, end, pi);
-               if (err < 0) {
-                       kfree(pi);
-                       goto bad;
-               }
-               __insert_pg_pool(&map->pg_pools, pi);
-       }
+       /* pools */
+       err = decode_pools(p, end, map);
+       if (err)
+               goto bad;
 
-       err = __decode_pool_names(p, end, map);
-       if (err < 0) {
-               dout("fail to decode pool names");
+       /* pool_name */
+       err = decode_pool_names(p, end, map);
+       if (err)
                goto bad;
-       }
 
-       ceph_decode_32_safe(p, end, map->pool_max, bad);
+       ceph_decode_32_safe(p, end, map->pool_max, e_inval);
 
-       ceph_decode_32_safe(p, end, map->flags, bad);
+       ceph_decode_32_safe(p, end, map->flags, e_inval);
 
-       max = ceph_decode_32(p);
+       /* max_osd */
+       ceph_decode_32_safe(p, end, max, e_inval);
 
        /* (re)alloc osd arrays */
        err = osdmap_set_max_osd(map, max);
-       if (err < 0)
+       if (err)
                goto bad;
-       dout("osdmap_decode max_osd = %d\n", map->max_osd);
 
-       /* osds */
-       err = -EINVAL;
+       /* osd_state, osd_weight, osd_addrs->client_addr */
        ceph_decode_need(p, end, 3*sizeof(u32) +
                         map->max_osd*(1 + sizeof(*map->osd_weight) +
-                                      sizeof(*map->osd_addr)), bad);
-       *p += 4; /* skip length field (should match max) */
+                                      sizeof(*map->osd_addr)), e_inval);
+
+       if (ceph_decode_32(p) != map->max_osd)
+               goto e_inval;
+
        ceph_decode_copy(p, map->osd_state, map->max_osd);
 
-       *p += 4; /* skip length field (should match max) */
+       if (ceph_decode_32(p) != map->max_osd)
+               goto e_inval;
+
        for (i = 0; i < map->max_osd; i++)
                map->osd_weight[i] = ceph_decode_32(p);
 
-       *p += 4; /* skip length field (should match max) */
+       if (ceph_decode_32(p) != map->max_osd)
+               goto e_inval;
+
        ceph_decode_copy(p, map->osd_addr, map->max_osd*sizeof(*map->osd_addr));
        for (i = 0; i < map->max_osd; i++)
                ceph_decode_addr(&map->osd_addr[i]);
 
        /* pg_temp */
-       ceph_decode_32_safe(p, end, len, bad);
-       for (i = 0; i < len; i++) {
-               int n, j;
-               struct ceph_pg pgid;
-               struct ceph_pg_mapping *pg;
+       err = decode_pg_temp(p, end, map);
+       if (err)
+               goto bad;
 
-               err = ceph_decode_pgid(p, end, &pgid);
+       /* primary_temp */
+       if (struct_v >= 1) {
+               err = decode_primary_temp(p, end, map);
                if (err)
                        goto bad;
-               ceph_decode_need(p, end, sizeof(u32), bad);
-               n = ceph_decode_32(p);
-               err = -EINVAL;
-               if (n > (UINT_MAX - sizeof(*pg)) / sizeof(u32))
-                       goto bad;
-               ceph_decode_need(p, end, n * sizeof(u32), bad);
-               err = -ENOMEM;
-               pg = kmalloc(sizeof(*pg) + n*sizeof(u32), GFP_NOFS);
-               if (!pg)
-                       goto bad;
-               pg->pgid = pgid;
-               pg->len = n;
-               for (j = 0; j < n; j++)
-                       pg->osds[j] = ceph_decode_32(p);
+       }
 
-               err = __insert_pg_mapping(pg, &map->pg_temp);
+       /* primary_affinity */
+       if (struct_v >= 2) {
+               err = decode_primary_affinity(p, end, map);
                if (err)
                        goto bad;
-               dout(" added pg_temp %lld.%x len %d\n", pgid.pool, pgid.seed,
-                    len);
+       } else {
+               /* XXX can this happen? */
+               kfree(map->osd_primary_affinity);
+               map->osd_primary_affinity = NULL;
        }
 
        /* crush */
-       ceph_decode_32_safe(p, end, len, bad);
-       dout("osdmap_decode crush len %d from off 0x%x\n", len,
-            (int)(*p - start));
-       ceph_decode_need(p, end, len, bad);
-       map->crush = crush_decode(*p, end);
-       *p += len;
+       ceph_decode_32_safe(p, end, len, e_inval);
+       map->crush = crush_decode(*p, min(*p + len, end));
        if (IS_ERR(map->crush)) {
                err = PTR_ERR(map->crush);
                map->crush = NULL;
                goto bad;
        }
+       *p += len;
 
-       /* ignore the rest of the map */
+       /* ignore the rest */
        *p = end;
 
-       dout("osdmap_decode done %p %p\n", *p, end);
-       return map;
+       dout("full osdmap epoch %d max_osd %d\n", map->epoch, map->max_osd);
+       return 0;
 
+e_inval:
+       err = -EINVAL;
 bad:
-       dout("osdmap_decode fail err %d\n", err);
-       ceph_osdmap_destroy(map);
-       return ERR_PTR(err);
+       pr_err("corrupt full osdmap (%d) epoch %d off %d (%p of %p-%p)\n",
+              err, epoch, (int)(*p - start), *p, start, end);
+       print_hex_dump(KERN_DEBUG, "osdmap: ",
+                      DUMP_PREFIX_OFFSET, 16, 1,
+                      start, end - start, true);
+       return err;
+}
+
+/*
+ * Allocate and decode a full map.
+ */
+struct ceph_osdmap *ceph_osdmap_decode(void **p, void *end)
+{
+       struct ceph_osdmap *map;
+       int ret;
+
+       map = kzalloc(sizeof(*map), GFP_NOFS);
+       if (!map)
+               return ERR_PTR(-ENOMEM);
+
+       map->pg_temp = RB_ROOT;
+       map->primary_temp = RB_ROOT;
+       mutex_init(&map->crush_scratch_mutex);
+
+       ret = osdmap_decode(p, end, map);
+       if (ret) {
+               ceph_osdmap_destroy(map);
+               return ERR_PTR(ret);
+       }
+
+       return map;
 }
 
 /*
@@ -840,17 +1177,18 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
        __s64 new_pool_max;
        __s32 new_flags, max;
        void *start = *p;
-       int err = -EINVAL;
-       u16 version;
+       int err;
+       u8 struct_v;
+
+       dout("%s %p to %p len %d\n", __func__, *p, end, (int)(end - *p));
 
-       ceph_decode_16_safe(p, end, version, bad);
-       if (version != 6) {
-               pr_warning("got unknown v %d != 6 of inc osdmap\n", version);
+       err = get_osdmap_client_data_v(p, end, "inc", &struct_v);
+       if (err)
                goto bad;
-       }
 
-       ceph_decode_need(p, end, sizeof(fsid)+sizeof(modified)+2*sizeof(u32),
-                        bad);
+       /* fsid, epoch, modified, new_pool_max, new_flags */
+       ceph_decode_need(p, end, sizeof(fsid) + sizeof(u32) + sizeof(modified) +
+                        sizeof(u64) + sizeof(u32), e_inval);
        ceph_decode_copy(p, &fsid, sizeof(fsid));
        epoch = ceph_decode_32(p);
        BUG_ON(epoch != map->epoch+1);
@@ -859,21 +1197,22 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
        new_flags = ceph_decode_32(p);
 
        /* full map? */
-       ceph_decode_32_safe(p, end, len, bad);
+       ceph_decode_32_safe(p, end, len, e_inval);
        if (len > 0) {
                dout("apply_incremental full map len %d, %p to %p\n",
                     len, *p, end);
-               return osdmap_decode(p, min(*p+len, end));
+               return ceph_osdmap_decode(p, min(*p+len, end));
        }
 
        /* new crush? */
-       ceph_decode_32_safe(p, end, len, bad);
+       ceph_decode_32_safe(p, end, len, e_inval);
        if (len > 0) {
-               dout("apply_incremental new crush map len %d, %p to %p\n",
-                    len, *p, end);
                newcrush = crush_decode(*p, min(*p+len, end));
-               if (IS_ERR(newcrush))
-                       return ERR_CAST(newcrush);
+               if (IS_ERR(newcrush)) {
+                       err = PTR_ERR(newcrush);
+                       newcrush = NULL;
+                       goto bad;
+               }
                *p += len;
        }
 
@@ -883,13 +1222,11 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
        if (new_pool_max >= 0)
                map->pool_max = new_pool_max;
 
-       ceph_decode_need(p, end, 5*sizeof(u32), bad);
-
        /* new max? */
-       max = ceph_decode_32(p);
+       ceph_decode_32_safe(p, end, max, e_inval);
        if (max >= 0) {
                err = osdmap_set_max_osd(map, max);
-               if (err < 0)
+               if (err)
                        goto bad;
        }
 
@@ -902,51 +1239,34 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
                newcrush = NULL;
        }
 
-       /* new_pool */
-       ceph_decode_32_safe(p, end, len, bad);
-       while (len--) {
-               struct ceph_pg_pool_info *pi;
+       /* new_pools */
+       err = decode_new_pools(p, end, map);
+       if (err)
+               goto bad;
 
-               ceph_decode_64_safe(p, end, pool, bad);
-               pi = __lookup_pg_pool(&map->pg_pools, pool);
-               if (!pi) {
-                       pi = kzalloc(sizeof(*pi), GFP_NOFS);
-                       if (!pi) {
-                               err = -ENOMEM;
-                               goto bad;
-                       }
-                       pi->id = pool;
-                       __insert_pg_pool(&map->pg_pools, pi);
-               }
-               err = __decode_pool(p, end, pi);
-               if (err < 0)
-                       goto bad;
-       }
-       if (version >= 5) {
-               err = __decode_pool_names(p, end, map);
-               if (err < 0)
-                       goto bad;
-       }
+       /* new_pool_names */
+       err = decode_pool_names(p, end, map);
+       if (err)
+               goto bad;
 
        /* old_pool */
-       ceph_decode_32_safe(p, end, len, bad);
+       ceph_decode_32_safe(p, end, len, e_inval);
        while (len--) {
                struct ceph_pg_pool_info *pi;
 
-               ceph_decode_64_safe(p, end, pool, bad);
+               ceph_decode_64_safe(p, end, pool, e_inval);
                pi = __lookup_pg_pool(&map->pg_pools, pool);
                if (pi)
                        __remove_pg_pool(&map->pg_pools, pi);
        }
 
        /* new_up */
-       err = -EINVAL;
-       ceph_decode_32_safe(p, end, len, bad);
+       ceph_decode_32_safe(p, end, len, e_inval);
        while (len--) {
                u32 osd;
                struct ceph_entity_addr addr;
-               ceph_decode_32_safe(p, end, osd, bad);
-               ceph_decode_copy_safe(p, end, &addr, sizeof(addr), bad);
+               ceph_decode_32_safe(p, end, osd, e_inval);
+               ceph_decode_copy_safe(p, end, &addr, sizeof(addr), e_inval);
                ceph_decode_addr(&addr);
                pr_info("osd%d up\n", osd);
                BUG_ON(osd >= map->max_osd);
@@ -955,11 +1275,11 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
        }
 
        /* new_state */
-       ceph_decode_32_safe(p, end, len, bad);
+       ceph_decode_32_safe(p, end, len, e_inval);
        while (len--) {
                u32 osd;
                u8 xorstate;
-               ceph_decode_32_safe(p, end, osd, bad);
+               ceph_decode_32_safe(p, end, osd, e_inval);
                xorstate = **(u8 **)p;
                (*p)++;  /* clean flag */
                if (xorstate == 0)
@@ -971,10 +1291,10 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
        }
 
        /* new_weight */
-       ceph_decode_32_safe(p, end, len, bad);
+       ceph_decode_32_safe(p, end, len, e_inval);
        while (len--) {
                u32 osd, off;
-               ceph_decode_need(p, end, sizeof(u32)*2, bad);
+               ceph_decode_need(p, end, sizeof(u32)*2, e_inval);
                osd = ceph_decode_32(p);
                off = ceph_decode_32(p);
                pr_info("osd%d weight 0x%x %s\n", osd, off,
@@ -985,56 +1305,35 @@ struct ceph_osdmap *osdmap_apply_incremental(void **p, void *end,
        }
 
        /* new_pg_temp */
-       ceph_decode_32_safe(p, end, len, bad);
-       while (len--) {
-               struct ceph_pg_mapping *pg;
-               int j;
-               struct ceph_pg pgid;
-               u32 pglen;
+       err = decode_new_pg_temp(p, end, map);
+       if (err)
+               goto bad;
 
-               err = ceph_decode_pgid(p, end, &pgid);
+       /* new_primary_temp */
+       if (struct_v >= 1) {
+               err = decode_new_primary_temp(p, end, map);
                if (err)
                        goto bad;
-               ceph_decode_need(p, end, sizeof(u32), bad);
-               pglen = ceph_decode_32(p);
-               if (pglen) {
-                       ceph_decode_need(p, end, pglen*sizeof(u32), bad);
-
-                       /* removing existing (if any) */
-                       (void) __remove_pg_mapping(&map->pg_temp, pgid);
+       }
 
-                       /* insert */
-                       err = -EINVAL;
-                       if (pglen > (UINT_MAX - sizeof(*pg)) / sizeof(u32))
-                               goto bad;
-                       err = -ENOMEM;
-                       pg = kmalloc(sizeof(*pg) + sizeof(u32)*pglen, GFP_NOFS);
-                       if (!pg)
-                               goto bad;
-                       pg->pgid = pgid;
-                       pg->len = pglen;
-                       for (j = 0; j < pglen; j++)
-                               pg->osds[j] = ceph_decode_32(p);
-                       err = __insert_pg_mapping(pg, &map->pg_temp);
-                       if (err) {
-                               kfree(pg);
-                               goto bad;
-                       }
-                       dout(" added pg_temp %lld.%x len %d\n", pgid.pool,
-                            pgid.seed, pglen);
-               } else {
-                       /* remove */
-                       __remove_pg_mapping(&map->pg_temp, pgid);
-               }
+       /* new_primary_affinity */
+       if (struct_v >= 2) {
+               err = decode_new_primary_affinity(p, end, map);
+               if (err)
+                       goto bad;
        }
 
        /* ignore the rest */
        *p = end;
+
+       dout("inc osdmap epoch %d max_osd %d\n", map->epoch, map->max_osd);
        return map;
 
+e_inval:
+       err = -EINVAL;
 bad:
-       pr_err("corrupt inc osdmap epoch %d off %d (%p of %p-%p)\n",
-              epoch, (int)(*p - start), *p, start, end);
+       pr_err("corrupt inc osdmap (%d) epoch %d off %d (%p of %p-%p)\n",
+              err, epoch, (int)(*p - start), *p, start, end);
        print_hex_dump(KERN_DEBUG, "osdmap: ",
                       DUMP_PREFIX_OFFSET, 16, 1,
                       start, end - start, true);
@@ -1142,61 +1441,249 @@ int ceph_oloc_oid_to_pg(struct ceph_osdmap *osdmap,
 }
 EXPORT_SYMBOL(ceph_oloc_oid_to_pg);
 
-static int crush_do_rule_ary(const struct crush_map *map, int ruleno, int x,
-                            int *result, int result_max,
-                            const __u32 *weight, int weight_max)
+static int do_crush(struct ceph_osdmap *map, int ruleno, int x,
+                   int *result, int result_max,
+                   const __u32 *weight, int weight_max)
 {
-       int scratch[result_max * 3];
+       int r;
 
-       return crush_do_rule(map, ruleno, x, result, result_max,
-                            weight, weight_max, scratch);
+       BUG_ON(result_max > CEPH_PG_MAX_SIZE);
+
+       mutex_lock(&map->crush_scratch_mutex);
+       r = crush_do_rule(map->crush, ruleno, x, result, result_max,
+                         weight, weight_max, map->crush_scratch_ary);
+       mutex_unlock(&map->crush_scratch_mutex);
+
+       return r;
 }
 
 /*
- * Calculate raw osd vector for the given pgid.  Return pointer to osd
- * array, or NULL on failure.
+ * Calculate raw (crush) set for given pgid.
+ *
+ * Return raw set length, or error.
  */
-static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
-                       int *osds, int *num)
+static int pg_to_raw_osds(struct ceph_osdmap *osdmap,
+                         struct ceph_pg_pool_info *pool,
+                         struct ceph_pg pgid, u32 pps, int *osds)
 {
-       struct ceph_pg_mapping *pg;
-       struct ceph_pg_pool_info *pool;
        int ruleno;
-       int r;
-       u32 pps;
+       int len;
 
-       pool = __lookup_pg_pool(&osdmap->pg_pools, pgid.pool);
-       if (!pool)
-               return NULL;
+       /* crush */
+       ruleno = crush_find_rule(osdmap->crush, pool->crush_ruleset,
+                                pool->type, pool->size);
+       if (ruleno < 0) {
+               pr_err("no crush rule: pool %lld ruleset %d type %d size %d\n",
+                      pgid.pool, pool->crush_ruleset, pool->type,
+                      pool->size);
+               return -ENOENT;
+       }
 
-       /* pg_temp? */
+       len = do_crush(osdmap, ruleno, pps, osds,
+                      min_t(int, pool->size, CEPH_PG_MAX_SIZE),
+                      osdmap->osd_weight, osdmap->max_osd);
+       if (len < 0) {
+               pr_err("error %d from crush rule %d: pool %lld ruleset %d type %d size %d\n",
+                      len, ruleno, pgid.pool, pool->crush_ruleset,
+                      pool->type, pool->size);
+               return len;
+       }
+
+       return len;
+}
+
+/*
+ * Given raw set, calculate up set and up primary.
+ *
+ * Return up set length.  *primary is set to up primary osd id, or -1
+ * if up set is empty.
+ */
+static int raw_to_up_osds(struct ceph_osdmap *osdmap,
+                         struct ceph_pg_pool_info *pool,
+                         int *osds, int len, int *primary)
+{
+       int up_primary = -1;
+       int i;
+
+       if (ceph_can_shift_osds(pool)) {
+               int removed = 0;
+
+               for (i = 0; i < len; i++) {
+                       if (ceph_osd_is_down(osdmap, osds[i])) {
+                               removed++;
+                               continue;
+                       }
+                       if (removed)
+                               osds[i - removed] = osds[i];
+               }
+
+               len -= removed;
+               if (len > 0)
+                       up_primary = osds[0];
+       } else {
+               for (i = len - 1; i >= 0; i--) {
+                       if (ceph_osd_is_down(osdmap, osds[i]))
+                               osds[i] = CRUSH_ITEM_NONE;
+                       else
+                               up_primary = osds[i];
+               }
+       }
+
+       *primary = up_primary;
+       return len;
+}
+
+static void apply_primary_affinity(struct ceph_osdmap *osdmap, u32 pps,
+                                  struct ceph_pg_pool_info *pool,
+                                  int *osds, int len, int *primary)
+{
+       int i;
+       int pos = -1;
+
+       /*
+        * Do we have any non-default primary_affinity values for these
+        * osds?
+        */
+       if (!osdmap->osd_primary_affinity)
+               return;
+
+       for (i = 0; i < len; i++) {
+               if (osds[i] != CRUSH_ITEM_NONE &&
+                   osdmap->osd_primary_affinity[i] !=
+                                       CEPH_OSD_DEFAULT_PRIMARY_AFFINITY) {
+                       break;
+               }
+       }
+       if (i == len)
+               return;
+
+       /*
+        * Pick the primary.  Feed both the seed (for the pg) and the
+        * osd into the hash/rng so that a proportional fraction of an
+        * osd's pgs get rejected as primary.
+        */
+       for (i = 0; i < len; i++) {
+               int osd;
+               u32 aff;
+
+               osd = osds[i];
+               if (osd == CRUSH_ITEM_NONE)
+                       continue;
+
+               aff = osdmap->osd_primary_affinity[osd];
+               if (aff < CEPH_OSD_MAX_PRIMARY_AFFINITY &&
+                   (crush_hash32_2(CRUSH_HASH_RJENKINS1,
+                                   pps, osd) >> 16) >= aff) {
+                       /*
+                        * We chose not to use this primary.  Note it
+                        * anyway as a fallback in case we don't pick
+                        * anyone else, but keep looking.
+                        */
+                       if (pos < 0)
+                               pos = i;
+               } else {
+                       pos = i;
+                       break;
+               }
+       }
+       if (pos < 0)
+               return;
+
+       *primary = osds[pos];
+
+       if (ceph_can_shift_osds(pool) && pos > 0) {
+               /* move the new primary to the front */
+               for (i = pos; i > 0; i--)
+                       osds[i] = osds[i - 1];
+               osds[0] = *primary;
+       }
+}
+
+/*
+ * Given up set, apply pg_temp and primary_temp mappings.
+ *
+ * Return acting set length.  *primary is set to acting primary osd id,
+ * or -1 if acting set is empty.
+ */
+static int apply_temps(struct ceph_osdmap *osdmap,
+                      struct ceph_pg_pool_info *pool, struct ceph_pg pgid,
+                      int *osds, int len, int *primary)
+{
+       struct ceph_pg_mapping *pg;
+       int temp_len;
+       int temp_primary;
+       int i;
+
+       /* raw_pg -> pg */
        pgid.seed = ceph_stable_mod(pgid.seed, pool->pg_num,
                                    pool->pg_num_mask);
+
+       /* pg_temp? */
        pg = __lookup_pg_mapping(&osdmap->pg_temp, pgid);
        if (pg) {
-               *num = pg->len;
-               return pg->osds;
+               temp_len = 0;
+               temp_primary = -1;
+
+               for (i = 0; i < pg->pg_temp.len; i++) {
+                       if (ceph_osd_is_down(osdmap, pg->pg_temp.osds[i])) {
+                               if (ceph_can_shift_osds(pool))
+                                       continue;
+                               else
+                                       osds[temp_len++] = CRUSH_ITEM_NONE;
+                       } else {
+                               osds[temp_len++] = pg->pg_temp.osds[i];
+                       }
+               }
+
+               /* apply pg_temp's primary */
+               for (i = 0; i < temp_len; i++) {
+                       if (osds[i] != CRUSH_ITEM_NONE) {
+                               temp_primary = osds[i];
+                               break;
+                       }
+               }
+       } else {
+               temp_len = len;
+               temp_primary = *primary;
        }
 
-       /* crush */
-       ruleno = crush_find_rule(osdmap->crush, pool->crush_ruleset,
-                                pool->type, pool->size);
-       if (ruleno < 0) {
-               pr_err("no crush rule pool %lld ruleset %d type %d size %d\n",
-                      pgid.pool, pool->crush_ruleset, pool->type,
-                      pool->size);
-               return NULL;
+       /* primary_temp? */
+       pg = __lookup_pg_mapping(&osdmap->primary_temp, pgid);
+       if (pg)
+               temp_primary = pg->primary_temp.osd;
+
+       *primary = temp_primary;
+       return temp_len;
+}
+
+/*
+ * Calculate acting set for given pgid.
+ *
+ * Return acting set length, or error.  *primary is set to acting
+ * primary osd id, or -1 if acting set is empty or on error.
+ */
+int ceph_calc_pg_acting(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
+                       int *osds, int *primary)
+{
+       struct ceph_pg_pool_info *pool;
+       u32 pps;
+       int len;
+
+       pool = __lookup_pg_pool(&osdmap->pg_pools, pgid.pool);
+       if (!pool) {
+               *primary = -1;
+               return -ENOENT;
        }
 
        if (pool->flags & CEPH_POOL_FLAG_HASHPSPOOL) {
-               /* hash pool id and seed sothat pool PGs do not overlap */
+               /* hash pool id and seed so that pool PGs do not overlap */
                pps = crush_hash32_2(CRUSH_HASH_RJENKINS1,
                                     ceph_stable_mod(pgid.seed, pool->pgp_num,
                                                     pool->pgp_num_mask),
                                     pgid.pool);
        } else {
                /*
-                * legacy ehavior: add ps and pool together.  this is
+                * legacy behavior: add ps and pool together.  this is
                 * not a great approach because the PGs from each pool
                 * will overlap on top of each other: 0.5 == 1.4 ==
                 * 2.3 == ...
@@ -1205,38 +1692,20 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
                                      pool->pgp_num_mask) +
                        (unsigned)pgid.pool;
        }
-       r = crush_do_rule_ary(osdmap->crush, ruleno, pps,
-                             osds, min_t(int, pool->size, *num),
-                             osdmap->osd_weight, osdmap->max_osd);
-       if (r < 0) {
-               pr_err("error %d from crush rule: pool %lld ruleset %d type %d"
-                      " size %d\n", r, pgid.pool, pool->crush_ruleset,
-                      pool->type, pool->size);
-               return NULL;
+
+       len = pg_to_raw_osds(osdmap, pool, pgid, pps, osds);
+       if (len < 0) {
+               *primary = -1;
+               return len;
        }
-       *num = r;
-       return osds;
-}
 
-/*
- * Return acting set for given pgid.
- */
-int ceph_calc_pg_acting(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
-                       int *acting)
-{
-       int rawosds[CEPH_PG_MAX_SIZE], *osds;
-       int i, o, num = CEPH_PG_MAX_SIZE;
+       len = raw_to_up_osds(osdmap, pool, osds, len, primary);
 
-       osds = calc_pg_raw(osdmap, pgid, rawosds, &num);
-       if (!osds)
-               return -1;
+       apply_primary_affinity(osdmap, pps, pool, osds, len, primary);
 
-       /* primary is first up osd */
-       o = 0;
-       for (i = 0; i < num; i++)
-               if (ceph_osd_is_up(osdmap, osds[i]))
-                       acting[o++] = osds[i];
-       return o;
+       len = apply_temps(osdmap, pool, pgid, osds, len, primary);
+
+       return len;
 }
 
 /*
@@ -1244,17 +1713,11 @@ int ceph_calc_pg_acting(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
  */
 int ceph_calc_pg_primary(struct ceph_osdmap *osdmap, struct ceph_pg pgid)
 {
-       int rawosds[CEPH_PG_MAX_SIZE], *osds;
-       int i, num = CEPH_PG_MAX_SIZE;
+       int osds[CEPH_PG_MAX_SIZE];
+       int primary;
 
-       osds = calc_pg_raw(osdmap, pgid, rawosds, &num);
-       if (!osds)
-               return -1;
+       ceph_calc_pg_acting(osdmap, pgid, osds, &primary);
 
-       /* primary is first up osd */
-       for (i = 0; i < num; i++)
-               if (ceph_osd_is_up(osdmap, osds[i]))
-                       return osds[i];
-       return -1;
+       return primary;
 }
 EXPORT_SYMBOL(ceph_calc_pg_primary);
index 7570634..14dac06 100644 (file)
@@ -4043,6 +4043,7 @@ static void napi_reuse_skb(struct napi_struct *napi, struct sk_buff *skb)
        skb->vlan_tci = 0;
        skb->dev = napi->dev;
        skb->skb_iif = 0;
+       skb->truesize = SKB_TRUESIZE(skb_end_offset(skb));
 
        napi->skb = skb;
 }
@@ -4588,8 +4589,7 @@ void *netdev_lower_get_next_private(struct net_device *dev,
        if (&lower->list == &dev->adj_list.lower)
                return NULL;
 
-       if (iter)
-               *iter = lower->list.next;
+       *iter = lower->list.next;
 
        return lower->private;
 }
@@ -4617,8 +4617,7 @@ void *netdev_lower_get_next_private_rcu(struct net_device *dev,
        if (&lower->list == &dev->adj_list.lower)
                return NULL;
 
-       if (iter)
-               *iter = &lower->list;
+       *iter = &lower->list;
 
        return lower->private;
 }
@@ -5696,6 +5695,13 @@ static netdev_features_t netdev_fix_features(struct net_device *dev,
                }
        }
 
+#ifdef CONFIG_NET_RX_BUSY_POLL
+       if (dev->netdev_ops->ndo_busy_poll)
+               features |= NETIF_F_BUSY_POLL;
+       else
+#endif
+               features &= ~NETIF_F_BUSY_POLL;
+
        return features;
 }
 
index 30071de..640ba0e 100644 (file)
@@ -97,6 +97,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
        [NETIF_F_RXFCS_BIT] =            "rx-fcs",
        [NETIF_F_RXALL_BIT] =            "rx-all",
        [NETIF_F_HW_L2FW_DOFFLOAD_BIT] = "l2-fwd-offload",
+       [NETIF_F_BUSY_POLL_BIT] =        "busy-poll",
 };
 
 static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
index 765556b..e08b382 100644 (file)
@@ -295,43 +295,43 @@ select_insn:
                (*(s64 *) &A) >>= K;
                CONT;
        BPF_ALU64_BPF_MOD_BPF_X:
+               if (unlikely(X == 0))
+                       return 0;
                tmp = A;
-               if (X)
-                       A = do_div(tmp, X);
+               A = do_div(tmp, X);
                CONT;
        BPF_ALU_BPF_MOD_BPF_X:
+               if (unlikely(X == 0))
+                       return 0;
                tmp = (u32) A;
-               if (X)
-                       A = do_div(tmp, (u32) X);
+               A = do_div(tmp, (u32) X);
                CONT;
        BPF_ALU64_BPF_MOD_BPF_K:
                tmp = A;
-               if (K)
-                       A = do_div(tmp, K);
+               A = do_div(tmp, K);
                CONT;
        BPF_ALU_BPF_MOD_BPF_K:
                tmp = (u32) A;
-               if (K)
-                       A = do_div(tmp, (u32) K);
+               A = do_div(tmp, (u32) K);
                CONT;
        BPF_ALU64_BPF_DIV_BPF_X:
-               if (X)
-                       do_div(A, X);
+               if (unlikely(X == 0))
+                       return 0;
+               do_div(A, X);
                CONT;
        BPF_ALU_BPF_DIV_BPF_X:
+               if (unlikely(X == 0))
+                       return 0;
                tmp = (u32) A;
-               if (X)
-                       do_div(tmp, (u32) X);
+               do_div(tmp, (u32) X);
                A = (u32) tmp;
                CONT;
        BPF_ALU64_BPF_DIV_BPF_K:
-               if (K)
-                       do_div(A, K);
+               do_div(A, K);
                CONT;
        BPF_ALU_BPF_DIV_BPF_K:
                tmp = (u32) A;
-               if (K)
-                       do_div(tmp, (u32) K);
+               do_div(tmp, (u32) K);
                A = (u32) tmp;
                CONT;
        BPF_ALU_BPF_END_BPF_TO_BE:
index 31cfb36..a0348fd 100644 (file)
@@ -455,6 +455,8 @@ int flow_cache_init(struct net *net)
        if (!fc->percpu)
                return -ENOMEM;
 
+       cpu_notifier_register_begin();
+
        for_each_online_cpu(i) {
                if (flow_cache_cpu_prepare(fc, i))
                        goto err;
@@ -462,7 +464,9 @@ int flow_cache_init(struct net *net)
        fc->hotcpu_notifier = (struct notifier_block){
                .notifier_call = flow_cache_cpu,
        };
-       register_hotcpu_notifier(&fc->hotcpu_notifier);
+       __register_hotcpu_notifier(&fc->hotcpu_notifier);
+
+       cpu_notifier_register_done();
 
        setup_timer(&fc->rnd_timer, flow_cache_new_hashrnd,
                    (unsigned long) fc);
@@ -478,6 +482,8 @@ err:
                fcp->hash_table = NULL;
        }
 
+       cpu_notifier_register_done();
+
        free_percpu(fc->percpu);
        fc->percpu = NULL;
 
index d0dac57..d068ec2 100644 (file)
@@ -3340,7 +3340,7 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
        __netif_tx_lock_bh(txq);
 
-       if (unlikely(netif_xmit_frozen_or_stopped(txq))) {
+       if (unlikely(netif_xmit_frozen_or_drv_stopped(txq))) {
                ret = NETDEV_TX_BUSY;
                pkt_dev->last_ok = 0;
                goto unlock;
index 59da7cd..f95b6f9 100644 (file)
@@ -1044,8 +1044,10 @@ static int __do_replace(struct net *net, const char *name,
 
        xt_free_table_info(oldinfo);
        if (copy_to_user(counters_ptr, counters,
-                        sizeof(struct xt_counters) * num_counters) != 0)
-               ret = -EFAULT;
+                        sizeof(struct xt_counters) * num_counters) != 0) {
+               /* Silent error, can't fail, new table is already in place */
+               net_warn_ratelimited("arptables: counters copy to user failed while replacing table\n");
+       }
        vfree(counters);
        xt_table_unlock(t);
        return ret;
index 718dfbd..99e810f 100644 (file)
@@ -1231,8 +1231,10 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
 
        xt_free_table_info(oldinfo);
        if (copy_to_user(counters_ptr, counters,
-                        sizeof(struct xt_counters) * num_counters) != 0)
-               ret = -EFAULT;
+                        sizeof(struct xt_counters) * num_counters) != 0) {
+               /* Silent error, can't fail, new table is already in place */
+               net_warn_ratelimited("iptables: counters copy to user failed while replacing table\n");
+       }
        vfree(counters);
        xt_table_unlock(t);
        return ret;
index 1be9e99..34d094c 100644 (file)
@@ -188,7 +188,7 @@ const __u8 ip_tos2prio[16] = {
 EXPORT_SYMBOL(ip_tos2prio);
 
 static DEFINE_PER_CPU(struct rt_cache_stat, rt_cache_stat);
-#define RT_CACHE_STAT_INC(field) __this_cpu_inc(rt_cache_stat.field)
+#define RT_CACHE_STAT_INC(field) raw_cpu_inc(rt_cache_stat.field)
 
 #ifdef CONFIG_PROC_FS
 static void *rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
index 710238f..e080fbb 100644 (file)
@@ -1241,8 +1241,10 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
 
        xt_free_table_info(oldinfo);
        if (copy_to_user(counters_ptr, counters,
-                        sizeof(struct xt_counters) * num_counters) != 0)
-               ret = -EFAULT;
+                        sizeof(struct xt_counters) * num_counters) != 0) {
+               /* Silent error, can't fail, new table is already in place */
+               net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n");
+       }
        vfree(counters);
        xt_table_unlock(t);
        return ret;
index cd5b8ec..da78793 100644 (file)
@@ -621,6 +621,42 @@ static void iucv_disable(void)
        put_online_cpus();
 }
 
+static void free_iucv_data(int cpu)
+{
+       kfree(iucv_param_irq[cpu]);
+       iucv_param_irq[cpu] = NULL;
+       kfree(iucv_param[cpu]);
+       iucv_param[cpu] = NULL;
+       kfree(iucv_irq_data[cpu]);
+       iucv_irq_data[cpu] = NULL;
+}
+
+static int alloc_iucv_data(int cpu)
+{
+       /* Note: GFP_DMA used to get memory below 2G */
+       iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
+                            GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
+       if (!iucv_irq_data[cpu])
+               goto out_free;
+
+       /* Allocate parameter blocks. */
+       iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
+                         GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
+       if (!iucv_param[cpu])
+               goto out_free;
+
+       iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param),
+                         GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
+       if (!iucv_param_irq[cpu])
+               goto out_free;
+
+       return 0;
+
+out_free:
+       free_iucv_data(cpu);
+       return -ENOMEM;
+}
+
 static int iucv_cpu_notify(struct notifier_block *self,
                                     unsigned long action, void *hcpu)
 {
@@ -630,38 +666,14 @@ static int iucv_cpu_notify(struct notifier_block *self,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
-                                       GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
-               if (!iucv_irq_data[cpu])
-                       return notifier_from_errno(-ENOMEM);
-
-               iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
-                                    GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
-               if (!iucv_param[cpu]) {
-                       kfree(iucv_irq_data[cpu]);
-                       iucv_irq_data[cpu] = NULL;
+               if (alloc_iucv_data(cpu))
                        return notifier_from_errno(-ENOMEM);
-               }
-               iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param),
-                                       GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
-               if (!iucv_param_irq[cpu]) {
-                       kfree(iucv_param[cpu]);
-                       iucv_param[cpu] = NULL;
-                       kfree(iucv_irq_data[cpu]);
-                       iucv_irq_data[cpu] = NULL;
-                       return notifier_from_errno(-ENOMEM);
-               }
                break;
        case CPU_UP_CANCELED:
        case CPU_UP_CANCELED_FROZEN:
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
-               kfree(iucv_param_irq[cpu]);
-               iucv_param_irq[cpu] = NULL;
-               kfree(iucv_param[cpu]);
-               iucv_param[cpu] = NULL;
-               kfree(iucv_irq_data[cpu]);
-               iucv_irq_data[cpu] = NULL;
+               free_iucv_data(cpu);
                break;
        case CPU_ONLINE:
        case CPU_ONLINE_FROZEN:
@@ -2016,7 +2028,7 @@ static int __init iucv_init(void)
        rc = iucv_query_maxconn();
        if (rc)
                goto out_ctl;
-       rc = register_external_interrupt(0x4000, iucv_external_interrupt);
+       rc = register_external_irq(EXT_IRQ_IUCV, iucv_external_interrupt);
        if (rc)
                goto out_ctl;
        iucv_root = root_device_register("iucv");
@@ -2025,33 +2037,20 @@ static int __init iucv_init(void)
                goto out_int;
        }
 
-       for_each_online_cpu(cpu) {
-               /* Note: GFP_DMA used to get memory below 2G */
-               iucv_irq_data[cpu] = kmalloc_node(sizeof(struct iucv_irq_data),
-                                    GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
-               if (!iucv_irq_data[cpu]) {
-                       rc = -ENOMEM;
-                       goto out_free;
-               }
+       cpu_notifier_register_begin();
 
-               /* Allocate parameter blocks. */
-               iucv_param[cpu] = kmalloc_node(sizeof(union iucv_param),
-                                 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
-               if (!iucv_param[cpu]) {
-                       rc = -ENOMEM;
-                       goto out_free;
-               }
-               iucv_param_irq[cpu] = kmalloc_node(sizeof(union iucv_param),
-                                 GFP_KERNEL|GFP_DMA, cpu_to_node(cpu));
-               if (!iucv_param_irq[cpu]) {
+       for_each_online_cpu(cpu) {
+               if (alloc_iucv_data(cpu)) {
                        rc = -ENOMEM;
                        goto out_free;
                }
-
        }
-       rc = register_hotcpu_notifier(&iucv_cpu_notifier);
+       rc = __register_hotcpu_notifier(&iucv_cpu_notifier);
        if (rc)
                goto out_free;
+
+       cpu_notifier_register_done();
+
        rc = register_reboot_notifier(&iucv_reboot_notifier);
        if (rc)
                goto out_cpu;
@@ -2069,19 +2068,17 @@ static int __init iucv_init(void)
 out_reboot:
        unregister_reboot_notifier(&iucv_reboot_notifier);
 out_cpu:
-       unregister_hotcpu_notifier(&iucv_cpu_notifier);
+       cpu_notifier_register_begin();
+       __unregister_hotcpu_notifier(&iucv_cpu_notifier);
 out_free:
-       for_each_possible_cpu(cpu) {
-               kfree(iucv_param_irq[cpu]);
-               iucv_param_irq[cpu] = NULL;
-               kfree(iucv_param[cpu]);
-               iucv_param[cpu] = NULL;
-               kfree(iucv_irq_data[cpu]);
-               iucv_irq_data[cpu] = NULL;
-       }
+       for_each_possible_cpu(cpu)
+               free_iucv_data(cpu);
+
+       cpu_notifier_register_done();
+
        root_device_unregister(iucv_root);
 out_int:
-       unregister_external_interrupt(0x4000, iucv_external_interrupt);
+       unregister_external_irq(EXT_IRQ_IUCV, iucv_external_interrupt);
 out_ctl:
        ctl_clear_bit(0, 1);
 out:
@@ -2105,18 +2102,14 @@ static void __exit iucv_exit(void)
                kfree(p);
        spin_unlock_irq(&iucv_queue_lock);
        unregister_reboot_notifier(&iucv_reboot_notifier);
-       unregister_hotcpu_notifier(&iucv_cpu_notifier);
-       for_each_possible_cpu(cpu) {
-               kfree(iucv_param_irq[cpu]);
-               iucv_param_irq[cpu] = NULL;
-               kfree(iucv_param[cpu]);
-               iucv_param[cpu] = NULL;
-               kfree(iucv_irq_data[cpu]);
-               iucv_irq_data[cpu] = NULL;
-       }
+       cpu_notifier_register_begin();
+       __unregister_hotcpu_notifier(&iucv_cpu_notifier);
+       for_each_possible_cpu(cpu)
+               free_iucv_data(cpu);
+       cpu_notifier_register_done();
        root_device_unregister(iucv_root);
        bus_unregister(&iucv_bus);
-       unregister_external_interrupt(0x4000, iucv_external_interrupt);
+       unregister_external_irq(EXT_IRQ_IUCV, iucv_external_interrupt);
 }
 
 subsys_initcall(iucv_init);
index 153bd1d..f0991f2 100644 (file)
@@ -26,7 +26,6 @@
 #include <net/mac802154.h>
 #include <net/ieee802154_netdev.h>
 #include <net/wpan-phy.h>
-#include <net/ieee802154_netdev.h>
 
 #include "mac802154.h"
 
index 33045a5..3fd159d 100644 (file)
@@ -152,8 +152,8 @@ nf_tables_chain_type_lookup(const struct nft_af_info *afi,
 #ifdef CONFIG_MODULES
        if (autoload) {
                nfnl_unlock(NFNL_SUBSYS_NFTABLES);
-               request_module("nft-chain-%u-%*.s", afi->family,
-                              nla_len(nla)-1, (const char *)nla_data(nla));
+               request_module("nft-chain-%u-%.*s", afi->family,
+                              nla_len(nla), (const char *)nla_data(nla));
                nfnl_lock(NFNL_SUBSYS_NFTABLES);
                type = __nf_tables_chain_type_lookup(afi->family, nla);
                if (type != NULL)
@@ -1946,7 +1946,8 @@ static const struct nft_set_ops *nft_select_set_ops(const struct nlattr * const
 
 static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
        [NFTA_SET_TABLE]                = { .type = NLA_STRING },
-       [NFTA_SET_NAME]                 = { .type = NLA_STRING },
+       [NFTA_SET_NAME]                 = { .type = NLA_STRING,
+                                           .len = IFNAMSIZ - 1 },
        [NFTA_SET_FLAGS]                = { .type = NLA_U32 },
        [NFTA_SET_KEY_TYPE]             = { .type = NLA_U32 },
        [NFTA_SET_KEY_LEN]              = { .type = NLA_U32 },
index 9a8e77e..f4e8330 100644 (file)
@@ -54,7 +54,8 @@ static struct xt_match cgroup_mt_reg __read_mostly = {
        .matchsize  = sizeof(struct xt_cgroup_info),
        .me         = THIS_MODULE,
        .hooks      = (1 << NF_INET_LOCAL_OUT) |
-                     (1 << NF_INET_POST_ROUTING),
+                     (1 << NF_INET_POST_ROUTING) |
+                     (1 << NF_INET_LOCAL_IN),
 };
 
 static int __init cgroup_mt_init(void)
index 458464e..fbc66bb 100644 (file)
 #include <net/netfilter/nf_conntrack_tuple.h>
 #include <net/netfilter/nf_conntrack_zones.h>
 
-#define CONNLIMIT_SLOTS                32
-#define CONNLIMIT_LOCK_SLOTS   32
+#define CONNLIMIT_SLOTS                256U
+
+#ifdef CONFIG_LOCKDEP
+#define CONNLIMIT_LOCK_SLOTS   8U
+#else
+#define CONNLIMIT_LOCK_SLOTS   256U
+#endif
+
 #define CONNLIMIT_GC_MAX_NODES 8
 
 /* we will save the tuples of all connections we care about */
@@ -49,10 +55,11 @@ struct xt_connlimit_rb {
        union nf_inet_addr addr; /* search key */
 };
 
+static spinlock_t xt_connlimit_locks[CONNLIMIT_LOCK_SLOTS] __cacheline_aligned_in_smp;
+
 struct xt_connlimit_data {
        struct rb_root climit_root4[CONNLIMIT_SLOTS];
        struct rb_root climit_root6[CONNLIMIT_SLOTS];
-       spinlock_t              locks[CONNLIMIT_LOCK_SLOTS];
 };
 
 static u_int32_t connlimit_rnd __read_mostly;
@@ -297,11 +304,11 @@ static int count_them(struct net *net,
                root = &data->climit_root4[hash];
        }
 
-       spin_lock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]);
+       spin_lock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]);
 
        count = count_tree(net, root, tuple, addr, mask, family);
 
-       spin_unlock_bh(&data->locks[hash % CONNLIMIT_LOCK_SLOTS]);
+       spin_unlock_bh(&xt_connlimit_locks[hash % CONNLIMIT_LOCK_SLOTS]);
 
        return count;
 }
@@ -377,9 +384,6 @@ static int connlimit_mt_check(const struct xt_mtchk_param *par)
                return -ENOMEM;
        }
 
-       for (i = 0; i < ARRAY_SIZE(info->data->locks); ++i)
-               spin_lock_init(&info->data->locks[i]);
-
        for (i = 0; i < ARRAY_SIZE(info->data->climit_root4); ++i)
                info->data->climit_root4[i] = RB_ROOT;
        for (i = 0; i < ARRAY_SIZE(info->data->climit_root6); ++i)
@@ -435,11 +439,14 @@ static struct xt_match connlimit_mt_reg __read_mostly = {
 
 static int __init connlimit_mt_init(void)
 {
-       int ret;
+       int ret, i;
 
        BUILD_BUG_ON(CONNLIMIT_LOCK_SLOTS > CONNLIMIT_SLOTS);
        BUILD_BUG_ON((CONNLIMIT_SLOTS % CONNLIMIT_LOCK_SLOTS) != 0);
 
+       for (i = 0; i < CONNLIMIT_LOCK_SLOTS; ++i)
+               spin_lock_init(&xt_connlimit_locks[i]);
+
        connlimit_conn_cachep = kmem_cache_create("xt_connlimit_conn",
                                           sizeof(struct xt_connlimit_conn),
                                           0, 0, NULL);
index 7174611..c529161 100644 (file)
@@ -422,4 +422,6 @@ module_exit(xt_osf_fini);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Evgeniy Polyakov <zbr@ioremap.net>");
 MODULE_DESCRIPTION("Passive OS fingerprint matching.");
+MODULE_ALIAS("ipt_osf");
+MODULE_ALIAS("ip6t_osf");
 MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_OSF);
index 01039d2..72e0c71 100644 (file)
@@ -261,7 +261,7 @@ static int packet_direct_xmit(struct sk_buff *skb)
        local_bh_disable();
 
        HARD_TX_LOCK(dev, txq, smp_processor_id());
-       if (!netif_xmit_frozen_or_stopped(txq)) {
+       if (!netif_xmit_frozen_or_drv_stopped(txq)) {
                ret = ops->ndo_start_xmit(skb, dev);
                if (ret == NETDEV_TX_OK)
                        txq_trans_update(txq);
@@ -275,6 +275,7 @@ static int packet_direct_xmit(struct sk_buff *skb)
 
        return ret;
 drop:
+       atomic_long_inc(&dev->tx_dropped);
        kfree_skb(skb);
        return NET_XMIT_DROP;
 }
index 981aaf8..5f83a6a 100644 (file)
@@ -6593,6 +6593,40 @@ static void __sctp_write_space(struct sctp_association *asoc)
        }
 }
 
+static void sctp_wake_up_waiters(struct sock *sk,
+                                struct sctp_association *asoc)
+{
+       struct sctp_association *tmp = asoc;
+
+       /* We do accounting for the sndbuf space per association,
+        * so we only need to wake our own association.
+        */
+       if (asoc->ep->sndbuf_policy)
+               return __sctp_write_space(asoc);
+
+       /* Accounting for the sndbuf space is per socket, so we
+        * need to wake up others, try to be fair and in case of
+        * other associations, let them have a go first instead
+        * of just doing a sctp_write_space() call.
+        *
+        * Note that we reach sctp_wake_up_waiters() only when
+        * associations free up queued chunks, thus we are under
+        * lock and the list of associations on a socket is
+        * guaranteed not to change.
+        */
+       for (tmp = list_next_entry(tmp, asocs); 1;
+            tmp = list_next_entry(tmp, asocs)) {
+               /* Manually skip the head element. */
+               if (&tmp->asocs == &((sctp_sk(sk))->ep->asocs))
+                       continue;
+               /* Wake up association. */
+               __sctp_write_space(tmp);
+               /* We've reached the end. */
+               if (tmp == asoc)
+                       break;
+       }
+}
+
 /* Do accounting for the sndbuf space.
  * Decrement the used sndbuf space of the corresponding association by the
  * data size which was just transmitted(freed).
@@ -6620,7 +6654,7 @@ static void sctp_wfree(struct sk_buff *skb)
        sk_mem_uncharge(sk, skb->truesize);
 
        sock_wfree(skb);
-       __sctp_write_space(asoc);
+       sctp_wake_up_waiters(sk, asoc);
 
        sctp_association_put(asoc);
 }
index 241b54f..0754d0f 100644 (file)
@@ -9,19 +9,6 @@ config SUNRPC_BACKCHANNEL
        bool
        depends on SUNRPC
 
-config SUNRPC_XPRT_RDMA
-       tristate
-       depends on SUNRPC && INFINIBAND && INFINIBAND_ADDR_TRANS
-       default SUNRPC && INFINIBAND
-       help
-         This option allows the NFS client and server to support
-         an RDMA-enabled transport.
-
-         To compile RPC client RDMA transport support as a module,
-         choose M here: the module will be called xprtrdma.
-
-         If unsure, say N.
-
 config SUNRPC_SWAP
        bool
        depends on SUNRPC
@@ -57,3 +44,29 @@ config SUNRPC_DEBUG
          but makes troubleshooting NFS issues significantly harder.
 
          If unsure, say Y.
+
+config SUNRPC_XPRT_RDMA_CLIENT
+       tristate "RPC over RDMA Client Support"
+       depends on SUNRPC && INFINIBAND && INFINIBAND_ADDR_TRANS
+       default SUNRPC && INFINIBAND
+       help
+         This option allows the NFS client to support an RDMA-enabled
+         transport.
+
+         To compile RPC client RDMA transport support as a module,
+         choose M here: the module will be called xprtrdma.
+
+         If unsure, say N.
+
+config SUNRPC_XPRT_RDMA_SERVER
+       tristate "RPC over RDMA Server Support"
+       depends on SUNRPC && INFINIBAND && INFINIBAND_ADDR_TRANS
+       default SUNRPC && INFINIBAND
+       help
+         This option allows the NFS server to support an RDMA-enabled
+         transport.
+
+         To compile RPC server RDMA transport support as a module,
+         choose M here: the module will be called svcrdma.
+
+         If unsure, say N.
index 8209a04..e5a7a1c 100644 (file)
@@ -5,7 +5,8 @@
 
 obj-$(CONFIG_SUNRPC) += sunrpc.o
 obj-$(CONFIG_SUNRPC_GSS) += auth_gss/
-obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma/
+
+obj-y += xprtrdma/
 
 sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
            auth.o auth_null.o auth_unix.o auth_generic.o \
index e860d4f..3513d55 100644 (file)
@@ -212,39 +212,23 @@ out:
 }
 EXPORT_SYMBOL_GPL(xprt_destroy_backchannel);
 
-/*
- * One or more rpc_rqst structure have been preallocated during the
- * backchannel setup.  Buffer space for the send and private XDR buffers
- * has been preallocated as well.  Use xprt_alloc_bc_request to allocate
- * to this request.  Use xprt_free_bc_request to return it.
- *
- * We know that we're called in soft interrupt context, grab the spin_lock
- * since there is no need to grab the bottom half spin_lock.
- *
- * Return an available rpc_rqst, otherwise NULL if non are available.
- */
-struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt)
+static struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt, __be32 xid)
 {
-       struct rpc_rqst *req;
+       struct rpc_rqst *req = NULL;
 
        dprintk("RPC:       allocate a backchannel request\n");
-       spin_lock(&xprt->bc_pa_lock);
-       if (!list_empty(&xprt->bc_pa_list)) {
-               req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
-                               rq_bc_pa_list);
-               list_del(&req->rq_bc_pa_list);
-       } else {
-               req = NULL;
-       }
-       spin_unlock(&xprt->bc_pa_lock);
+       if (list_empty(&xprt->bc_pa_list))
+               goto not_found;
 
-       if (req != NULL) {
-               set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
-               req->rq_reply_bytes_recvd = 0;
-               req->rq_bytes_sent = 0;
-               memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
+       req = list_first_entry(&xprt->bc_pa_list, struct rpc_rqst,
+                               rq_bc_pa_list);
+       req->rq_reply_bytes_recvd = 0;
+       req->rq_bytes_sent = 0;
+       memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
                        sizeof(req->rq_private_buf));
-       }
+       req->rq_xid = xid;
+       req->rq_connect_cookie = xprt->connect_cookie;
+not_found:
        dprintk("RPC:       backchannel req=%p\n", req);
        return req;
 }
@@ -259,6 +243,7 @@ void xprt_free_bc_request(struct rpc_rqst *req)
 
        dprintk("RPC:       free backchannel req=%p\n", req);
 
+       req->rq_connect_cookie = xprt->connect_cookie - 1;
        smp_mb__before_clear_bit();
        WARN_ON_ONCE(!test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state));
        clear_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
@@ -281,7 +266,57 @@ void xprt_free_bc_request(struct rpc_rqst *req)
         * may be reused by a new callback request.
         */
        spin_lock_bh(&xprt->bc_pa_lock);
-       list_add(&req->rq_bc_pa_list, &xprt->bc_pa_list);
+       list_add_tail(&req->rq_bc_pa_list, &xprt->bc_pa_list);
        spin_unlock_bh(&xprt->bc_pa_lock);
 }
 
+/*
+ * One or more rpc_rqst structure have been preallocated during the
+ * backchannel setup.  Buffer space for the send and private XDR buffers
+ * has been preallocated as well.  Use xprt_alloc_bc_request to allocate
+ * to this request.  Use xprt_free_bc_request to return it.
+ *
+ * We know that we're called in soft interrupt context, grab the spin_lock
+ * since there is no need to grab the bottom half spin_lock.
+ *
+ * Return an available rpc_rqst, otherwise NULL if non are available.
+ */
+struct rpc_rqst *xprt_lookup_bc_request(struct rpc_xprt *xprt, __be32 xid)
+{
+       struct rpc_rqst *req;
+
+       spin_lock(&xprt->bc_pa_lock);
+       list_for_each_entry(req, &xprt->bc_pa_list, rq_bc_pa_list) {
+               if (req->rq_connect_cookie != xprt->connect_cookie)
+                       continue;
+               if (req->rq_xid == xid)
+                       goto found;
+       }
+       req = xprt_alloc_bc_request(xprt, xid);
+found:
+       spin_unlock(&xprt->bc_pa_lock);
+       return req;
+}
+
+/*
+ * Add callback request to callback list.  The callback
+ * service sleeps on the sv_cb_waitq waiting for new
+ * requests.  Wake it up after adding enqueing the
+ * request.
+ */
+void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
+{
+       struct rpc_xprt *xprt = req->rq_xprt;
+       struct svc_serv *bc_serv = xprt->bc_serv;
+
+       req->rq_private_buf.len = copied;
+       set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);
+
+       dprintk("RPC:       add callback request to list\n");
+       spin_lock(&bc_serv->sv_cb_lock);
+       list_del(&req->rq_bc_pa_list);
+       list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
+       wake_up(&bc_serv->sv_cb_waitq);
+       spin_unlock(&bc_serv->sv_cb_lock);
+}
+
index 0edada9..2e6ab10 100644 (file)
@@ -438,6 +438,38 @@ out_no_rpciod:
        return ERR_PTR(err);
 }
 
+struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
+                                       struct rpc_xprt *xprt)
+{
+       struct rpc_clnt *clnt = NULL;
+
+       clnt = rpc_new_client(args, xprt, NULL);
+       if (IS_ERR(clnt))
+               return clnt;
+
+       if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
+               int err = rpc_ping(clnt);
+               if (err != 0) {
+                       rpc_shutdown_client(clnt);
+                       return ERR_PTR(err);
+               }
+       }
+
+       clnt->cl_softrtry = 1;
+       if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
+               clnt->cl_softrtry = 0;
+
+       if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
+               clnt->cl_autobind = 1;
+       if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
+               clnt->cl_discrtry = 1;
+       if (!(args->flags & RPC_CLNT_CREATE_QUIET))
+               clnt->cl_chatty = 1;
+
+       return clnt;
+}
+EXPORT_SYMBOL_GPL(rpc_create_xprt);
+
 /**
  * rpc_create - create an RPC client and transport with one call
  * @args: rpc_clnt create argument structure
@@ -451,7 +483,6 @@ out_no_rpciod:
 struct rpc_clnt *rpc_create(struct rpc_create_args *args)
 {
        struct rpc_xprt *xprt;
-       struct rpc_clnt *clnt;
        struct xprt_create xprtargs = {
                .net = args->net,
                .ident = args->protocol,
@@ -515,30 +546,7 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args)
        if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT)
                xprt->resvport = 0;
 
-       clnt = rpc_new_client(args, xprt, NULL);
-       if (IS_ERR(clnt))
-               return clnt;
-
-       if (!(args->flags & RPC_CLNT_CREATE_NOPING)) {
-               int err = rpc_ping(clnt);
-               if (err != 0) {
-                       rpc_shutdown_client(clnt);
-                       return ERR_PTR(err);
-               }
-       }
-
-       clnt->cl_softrtry = 1;
-       if (args->flags & RPC_CLNT_CREATE_HARDRTRY)
-               clnt->cl_softrtry = 0;
-
-       if (args->flags & RPC_CLNT_CREATE_AUTOBIND)
-               clnt->cl_autobind = 1;
-       if (args->flags & RPC_CLNT_CREATE_DISCRTRY)
-               clnt->cl_discrtry = 1;
-       if (!(args->flags & RPC_CLNT_CREATE_QUIET))
-               clnt->cl_chatty = 1;
-
-       return clnt;
+       return rpc_create_xprt(args, xprt);
 }
 EXPORT_SYMBOL_GPL(rpc_create);
 
@@ -1363,6 +1371,7 @@ rpc_restart_call_prepare(struct rpc_task *task)
        if (RPC_ASSASSINATED(task))
                return 0;
        task->tk_action = call_start;
+       task->tk_status = 0;
        if (task->tk_ops->rpc_call_prepare != NULL)
                task->tk_action = rpc_prepare_task;
        return 1;
@@ -1379,6 +1388,7 @@ rpc_restart_call(struct rpc_task *task)
        if (RPC_ASSASSINATED(task))
                return 0;
        task->tk_action = call_start;
+       task->tk_status = 0;
        return 1;
 }
 EXPORT_SYMBOL_GPL(rpc_restart_call);
@@ -1728,9 +1738,7 @@ call_bind_status(struct rpc_task *task)
        case -EPROTONOSUPPORT:
                dprintk("RPC: %5u remote rpcbind version unavailable, retrying\n",
                                task->tk_pid);
-               task->tk_status = 0;
-               task->tk_action = call_bind;
-               return;
+               goto retry_timeout;
        case -ECONNREFUSED:             /* connection problems */
        case -ECONNRESET:
        case -ECONNABORTED:
@@ -1756,6 +1764,7 @@ call_bind_status(struct rpc_task *task)
        return;
 
 retry_timeout:
+       task->tk_status = 0;
        task->tk_action = call_timeout;
 }
 
@@ -1798,21 +1807,19 @@ call_connect_status(struct rpc_task *task)
        trace_rpc_connect_status(task, status);
        task->tk_status = 0;
        switch (status) {
-               /* if soft mounted, test if we've timed out */
-       case -ETIMEDOUT:
-               task->tk_action = call_timeout;
-               return;
        case -ECONNREFUSED:
        case -ECONNRESET:
        case -ECONNABORTED:
        case -ENETUNREACH:
        case -EHOSTUNREACH:
-               /* retry with existing socket, after a delay */
-               rpc_delay(task, 3*HZ);
                if (RPC_IS_SOFTCONN(task))
                        break;
+               /* retry with existing socket, after a delay */
+               rpc_delay(task, 3*HZ);
        case -EAGAIN:
-               task->tk_action = call_bind;
+               /* Check for timeouts before looping back to call_bind */
+       case -ETIMEDOUT:
+               task->tk_action = call_timeout;
                return;
        case 0:
                clnt->cl_stats->netreconn++;
@@ -2007,6 +2014,10 @@ call_status(struct rpc_task *task)
        case -EHOSTDOWN:
        case -EHOSTUNREACH:
        case -ENETUNREACH:
+               if (RPC_IS_SOFTCONN(task)) {
+                       rpc_exit(task, status);
+                       break;
+               }
                /*
                 * Delay any retries for 3 seconds, then handle as if it
                 * were a timeout.
index ff3cc4b..25578af 100644 (file)
@@ -637,7 +637,8 @@ static void __rpc_queue_timer_fn(unsigned long ptr)
 
 static void __rpc_atrun(struct rpc_task *task)
 {
-       task->tk_status = 0;
+       if (task->tk_status == -ETIMEDOUT)
+               task->tk_status = 0;
 }
 
 /*
index b6e59f0..d06cb87 100644 (file)
@@ -1397,6 +1397,22 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
        return svsk;
 }
 
+bool svc_alien_sock(struct net *net, int fd)
+{
+       int err;
+       struct socket *sock = sockfd_lookup(fd, &err);
+       bool ret = false;
+
+       if (!sock)
+               goto out;
+       if (sock_net(sock->sk) != net)
+               ret = true;
+       sockfd_put(sock);
+out:
+       return ret;
+}
+EXPORT_SYMBOL_GPL(svc_alien_sock);
+
 /**
  * svc_addsock - add a listener socket to an RPC service
  * @serv: pointer to RPC service to which to add a new listener
index 1504bb1..dd97ba3 100644 (file)
@@ -833,8 +833,20 @@ xdr_buf_from_iov(struct kvec *iov, struct xdr_buf *buf)
 }
 EXPORT_SYMBOL_GPL(xdr_buf_from_iov);
 
-/* Sets subbuf to the portion of buf of length len beginning base bytes
- * from the start of buf. Returns -1 if base of length are out of bounds. */
+/**
+ * xdr_buf_subsegment - set subbuf to a portion of buf
+ * @buf: an xdr buffer
+ * @subbuf: the result buffer
+ * @base: beginning of range in bytes
+ * @len: length of range in bytes
+ *
+ * sets @subbuf to an xdr buffer representing the portion of @buf of
+ * length @len starting at offset @base.
+ *
+ * @buf and @subbuf may be pointers to the same struct xdr_buf.
+ *
+ * Returns -1 if base of length are out of bounds.
+ */
 int
 xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
                        unsigned int base, unsigned int len)
@@ -847,9 +859,8 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
                len -= subbuf->head[0].iov_len;
                base = 0;
        } else {
-               subbuf->head[0].iov_base = NULL;
-               subbuf->head[0].iov_len = 0;
                base -= buf->head[0].iov_len;
+               subbuf->head[0].iov_len = 0;
        }
 
        if (base < buf->page_len) {
@@ -871,9 +882,8 @@ xdr_buf_subsegment(struct xdr_buf *buf, struct xdr_buf *subbuf,
                len -= subbuf->tail[0].iov_len;
                base = 0;
        } else {
-               subbuf->tail[0].iov_base = NULL;
-               subbuf->tail[0].iov_len = 0;
                base -= buf->tail[0].iov_len;
+               subbuf->tail[0].iov_len = 0;
        }
 
        if (base || len)
index 7d4df99..d173f79 100644 (file)
@@ -1383,15 +1383,3 @@ void xprt_put(struct rpc_xprt *xprt)
        if (atomic_dec_and_test(&xprt->count))
                xprt_destroy(xprt);
 }
-
-/**
- * xprt_get - return a reference to an RPC transport.
- * @xprt: pointer to the transport
- *
- */
-struct rpc_xprt *xprt_get(struct rpc_xprt *xprt)
-{
-       if (atomic_inc_not_zero(&xprt->count))
-               return xprt;
-       return NULL;
-}
index 5a8f268..da5136f 100644 (file)
@@ -1,8 +1,8 @@
-obj-$(CONFIG_SUNRPC_XPRT_RDMA) += xprtrdma.o
+obj-$(CONFIG_SUNRPC_XPRT_RDMA_CLIENT) += xprtrdma.o
 
 xprtrdma-y := transport.o rpc_rdma.o verbs.o
 
-obj-$(CONFIG_SUNRPC_XPRT_RDMA) += svcrdma.o
+obj-$(CONFIG_SUNRPC_XPRT_RDMA_SERVER) += svcrdma.o
 
 svcrdma-y := svc_rdma.o svc_rdma_transport.o \
        svc_rdma_marshal.o svc_rdma_sendto.o svc_rdma_recvfrom.o
index e03725b..96ead52 100644 (file)
@@ -649,9 +649,7 @@ rpcrdma_inline_fixup(struct rpc_rqst *rqst, char *srcp, int copy_len, int pad)
                                break;
                        page_base = 0;
                }
-               rqst->rq_rcv_buf.page_len = olen - copy_len;
-       } else
-               rqst->rq_rcv_buf.page_len = 0;
+       }
 
        if (copy_len && rqst->rq_rcv_buf.tail[0].iov_len) {
                curlen = copy_len;
index 0ce7552..8d904e4 100644 (file)
@@ -90,6 +90,7 @@ static void rdma_build_arg_xdr(struct svc_rqst *rqstp,
                sge_no++;
        }
        rqstp->rq_respages = &rqstp->rq_pages[sge_no];
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
 
        /* We should never run out of SGE because the limit is defined to
         * support the max allowed RPC data length
@@ -169,6 +170,7 @@ static int map_read_chunks(struct svcxprt_rdma *xprt,
                 */
                head->arg.pages[page_no] = rqstp->rq_arg.pages[page_no];
                rqstp->rq_respages = &rqstp->rq_arg.pages[page_no+1];
+               rqstp->rq_next_page = rqstp->rq_respages + 1;
 
                byte_count -= sge_bytes;
                ch_bytes -= sge_bytes;
@@ -276,6 +278,7 @@ static int fast_reg_read_chunks(struct svcxprt_rdma *xprt,
 
        /* rq_respages points one past arg pages */
        rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
 
        /* Create the reply and chunk maps */
        offset = 0;
@@ -520,13 +523,6 @@ next_sge:
        for (ch_no = 0; &rqstp->rq_pages[ch_no] < rqstp->rq_respages; ch_no++)
                rqstp->rq_pages[ch_no] = NULL;
 
-       /*
-        * Detach res pages. If svc_release sees any it will attempt to
-        * put them.
-        */
-       while (rqstp->rq_next_page != rqstp->rq_respages)
-               *(--rqstp->rq_next_page) = NULL;
-
        return err;
 }
 
@@ -550,7 +546,7 @@ static int rdma_read_complete(struct svc_rqst *rqstp,
 
        /* rq_respages starts after the last arg page */
        rqstp->rq_respages = &rqstp->rq_arg.pages[page_no];
-       rqstp->rq_next_page = &rqstp->rq_arg.pages[page_no];
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
 
        /* Rebuild rq_arg head and tail. */
        rqstp->rq_arg.head[0] = head->arg.head[0];
index c1d124d..7e024a5 100644 (file)
@@ -265,6 +265,7 @@ static dma_addr_t dma_map_xdr(struct svcxprt_rdma *xprt,
                xdr_off -= xdr->head[0].iov_len;
                if (xdr_off < xdr->page_len) {
                        /* This offset is in the page list */
+                       xdr_off += xdr->page_base;
                        page = xdr->pages[xdr_off >> PAGE_SHIFT];
                        xdr_off &= ~PAGE_MASK;
                } else {
@@ -625,6 +626,7 @@ static int send_reply(struct svcxprt_rdma *rdma,
                if (page_no+1 >= sge_no)
                        ctxt->sge[page_no+1].length = 0;
        }
+       rqstp->rq_next_page = rqstp->rq_respages + 1;
        BUG_ON(sge_no > rdma->sc_max_sge);
        memset(&send_wr, 0, sizeof send_wr);
        ctxt->wr_op = IB_WR_SEND;
index 62e4f9b..25688fa 100644 (file)
@@ -477,8 +477,7 @@ struct page *svc_rdma_get_page(void)
 
        while ((page = alloc_page(GFP_KERNEL)) == NULL) {
                /* If we can't get memory, wait a bit and try again */
-               printk(KERN_INFO "svcrdma: out of memory...retrying in 1000 "
-                      "jiffies.\n");
+               printk(KERN_INFO "svcrdma: out of memory...retrying in 1s\n");
                schedule_timeout_uninterruptible(msecs_to_jiffies(1000));
        }
        return page;
index 285dc08..1eb9c46 100644 (file)
@@ -733,7 +733,7 @@ static void __exit xprt_rdma_cleanup(void)
 {
        int rc;
 
-       dprintk(KERN_INFO "RPCRDMA Module Removed, deregister RPC RDMA transport\n");
+       dprintk("RPCRDMA Module Removed, deregister RPC RDMA transport\n");
 #ifdef RPC_DEBUG
        if (sunrpc_table_header) {
                unregister_sysctl_table(sunrpc_table_header);
@@ -755,14 +755,14 @@ static int __init xprt_rdma_init(void)
        if (rc)
                return rc;
 
-       dprintk(KERN_INFO "RPCRDMA Module Init, register RPC RDMA transport\n");
+       dprintk("RPCRDMA Module Init, register RPC RDMA transport\n");
 
-       dprintk(KERN_INFO "Defaults:\n");
-       dprintk(KERN_INFO "\tSlots %d\n"
+       dprintk("Defaults:\n");
+       dprintk("\tSlots %d\n"
                "\tMaxInlineRead %d\n\tMaxInlineWrite %d\n",
                xprt_rdma_slot_table_entries,
                xprt_rdma_max_inline_read, xprt_rdma_max_inline_write);
-       dprintk(KERN_INFO "\tPadding %d\n\tMemreg %d\n",
+       dprintk("\tPadding %d\n\tMemreg %d\n",
                xprt_rdma_inline_write_padding, xprt_rdma_memreg_strategy);
 
 #ifdef RPC_DEBUG
index 0addefc..6735e1d 100644 (file)
@@ -909,6 +909,12 @@ static void xs_tcp_close(struct rpc_xprt *xprt)
                xs_tcp_shutdown(xprt);
 }
 
+static void xs_xprt_free(struct rpc_xprt *xprt)
+{
+       xs_free_peer_addresses(xprt);
+       xprt_free(xprt);
+}
+
 /**
  * xs_destroy - prepare to shutdown a transport
  * @xprt: doomed transport
@@ -919,8 +925,7 @@ static void xs_destroy(struct rpc_xprt *xprt)
        dprintk("RPC:       xs_destroy xprt %p\n", xprt);
 
        xs_close(xprt);
-       xs_free_peer_addresses(xprt);
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        module_put(THIS_MODULE);
 }
 
@@ -1306,41 +1311,29 @@ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt,
  * If we're unable to obtain the rpc_rqst we schedule the closing of the
  * connection and return -1.
  */
-static inline int xs_tcp_read_callback(struct rpc_xprt *xprt,
+static int xs_tcp_read_callback(struct rpc_xprt *xprt,
                                       struct xdr_skb_reader *desc)
 {
        struct sock_xprt *transport =
                                container_of(xprt, struct sock_xprt, xprt);
        struct rpc_rqst *req;
 
-       req = xprt_alloc_bc_request(xprt);
+       /* Look up and lock the request corresponding to the given XID */
+       spin_lock(&xprt->transport_lock);
+       req = xprt_lookup_bc_request(xprt, transport->tcp_xid);
        if (req == NULL) {
+               spin_unlock(&xprt->transport_lock);
                printk(KERN_WARNING "Callback slot table overflowed\n");
                xprt_force_disconnect(xprt);
                return -1;
        }
 
-       req->rq_xid = transport->tcp_xid;
        dprintk("RPC:       read callback  XID %08x\n", ntohl(req->rq_xid));
        xs_tcp_read_common(xprt, desc, req);
 
-       if (!(transport->tcp_flags & TCP_RCV_COPY_DATA)) {
-               struct svc_serv *bc_serv = xprt->bc_serv;
-
-               /*
-                * Add callback request to callback list.  The callback
-                * service sleeps on the sv_cb_waitq waiting for new
-                * requests.  Wake it up after adding enqueing the
-                * request.
-                */
-               dprintk("RPC:       add callback request to list\n");
-               spin_lock(&bc_serv->sv_cb_lock);
-               list_add(&req->rq_bc_list, &bc_serv->sv_cb_list);
-               spin_unlock(&bc_serv->sv_cb_lock);
-               wake_up(&bc_serv->sv_cb_waitq);
-       }
-
-       req->rq_private_buf.len = transport->tcp_copied;
+       if (!(transport->tcp_flags & TCP_RCV_COPY_DATA))
+               xprt_complete_bc_request(req, transport->tcp_copied);
+       spin_unlock(&xprt->transport_lock);
 
        return 0;
 }
@@ -2544,6 +2537,10 @@ static void bc_close(struct rpc_xprt *xprt)
 
 static void bc_destroy(struct rpc_xprt *xprt)
 {
+       dprintk("RPC:       bc_destroy xprt %p\n", xprt);
+
+       xs_xprt_free(xprt);
+       module_put(THIS_MODULE);
 }
 
 static struct rpc_xprt_ops xs_local_ops = {
@@ -2744,7 +2741,7 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args)
                return xprt;
        ret = ERR_PTR(-EINVAL);
 out_err:
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        return ret;
 }
 
@@ -2822,7 +2819,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args)
                return xprt;
        ret = ERR_PTR(-EINVAL);
 out_err:
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        return ret;
 }
 
@@ -2897,12 +2894,11 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args)
                                xprt->address_strings[RPC_DISPLAY_ADDR],
                                xprt->address_strings[RPC_DISPLAY_PROTO]);
 
-
        if (try_module_get(THIS_MODULE))
                return xprt;
        ret = ERR_PTR(-EINVAL);
 out_err:
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        return ret;
 }
 
@@ -2919,15 +2915,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
        struct svc_sock *bc_sock;
        struct rpc_xprt *ret;
 
-       if (args->bc_xprt->xpt_bc_xprt) {
-               /*
-                * This server connection already has a backchannel
-                * transport; we can't create a new one, as we wouldn't
-                * be able to match replies based on xid any more.  So,
-                * reuse the already-existing one:
-                */
-                return args->bc_xprt->xpt_bc_xprt;
-       }
        xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries,
                        xprt_tcp_slot_table_entries);
        if (IS_ERR(xprt))
@@ -2985,13 +2972,14 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
         */
        xprt_set_connected(xprt);
 
-
        if (try_module_get(THIS_MODULE))
                return xprt;
+
+       args->bc_xprt->xpt_bc_xprt = NULL;
        xprt_put(xprt);
        ret = ERR_PTR(-EINVAL);
 out_err:
-       xprt_free(xprt);
+       xs_xprt_free(xprt);
        return ret;
 }
 
index 0374a81..4c564eb 100644 (file)
@@ -182,6 +182,8 @@ void tipc_net_start(u32 addr)
        tipc_bclink_init();
        write_unlock_bh(&tipc_net_lock);
 
+       tipc_nametbl_publish(TIPC_CFG_SRV, tipc_own_addr, tipc_own_addr,
+                            TIPC_ZONE_SCOPE, 0, tipc_own_addr);
        pr_info("Started in network mode\n");
        pr_info("Own node address %s, network identity %u\n",
                tipc_addr_string_fill(addr_string, tipc_own_addr), tipc_net_id);
@@ -192,6 +194,7 @@ void tipc_net_stop(void)
        if (!tipc_own_addr)
                return;
 
+       tipc_nametbl_withdraw(TIPC_CFG_SRV, tipc_own_addr, 0, tipc_own_addr);
        write_lock_bh(&tipc_net_lock);
        tipc_bearer_stop();
        tipc_bclink_stop();
index 29b7f26..adc12e2 100644 (file)
@@ -301,7 +301,6 @@ static int tipc_release(struct socket *sock)
        struct tipc_sock *tsk;
        struct tipc_port *port;
        struct sk_buff *buf;
-       int res;
 
        /*
         * Exit if socket isn't fully initialized (occurs when a failed accept()
@@ -349,7 +348,7 @@ static int tipc_release(struct socket *sock)
        sock_put(sk);
        sock->sk = NULL;
 
-       return res;
+       return 0;
 }
 
 /**
index 93a0da2..122f95c 100644 (file)
@@ -3,6 +3,7 @@
 
 # Convenient variables
 comma   := ,
+quote   := "
 squote  := '
 empty   :=
 space   := $(empty) $(empty)
index 01e7adb..1d07860 100644 (file)
@@ -27,10 +27,10 @@ always              := $(hostprogs-y) $(hostprogs-m)
 hostprogs-y += unifdef docproc
 
 # These targets are used internally to avoid "is up to date" messages
-PHONY += build_unifdef
-build_unifdef: scripts/unifdef FORCE
+PHONY += build_unifdef build_docproc
+build_unifdef: $(obj)/unifdef
        @:
-build_docproc: scripts/docproc FORCE
+build_docproc: $(obj)/docproc
        @:
 
 subdir-$(CONFIG_MODVERSIONS) += genksyms
index 72105d1..6a5b0de 100644 (file)
@@ -380,7 +380,3 @@ quiet_cmd_xzmisc = XZMISC  $@
 cmd_xzmisc = (cat $(filter-out FORCE,$^) | \
        xz --check=crc32 --lzma2=dict=1MiB) > $@ || \
        (rm -f $@ ; false)
-
-# misc stuff
-# ---------------------------------------------------------------------------
-quote:="
index 10085de..1237dd7 100644 (file)
@@ -36,13 +36,13 @@ struct sym_entry {
        unsigned char *sym;
 };
 
-struct text_range {
-       const char *stext, *etext;
+struct addr_range {
+       const char *start_sym, *end_sym;
        unsigned long long start, end;
 };
 
 static unsigned long long _text;
-static struct text_range text_ranges[] = {
+static struct addr_range text_ranges[] = {
        { "_stext",     "_etext"     },
        { "_sinittext", "_einittext" },
        { "_stext_l1",  "_etext_l1"  }, /* Blackfin on-chip L1 inst SRAM */
@@ -51,9 +51,14 @@ static struct text_range text_ranges[] = {
 #define text_range_text     (&text_ranges[0])
 #define text_range_inittext (&text_ranges[1])
 
+static struct addr_range percpu_range = {
+       "__per_cpu_start", "__per_cpu_end", -1ULL, 0
+};
+
 static struct sym_entry *table;
 static unsigned int table_size, table_cnt;
 static int all_symbols = 0;
+static int absolute_percpu = 0;
 static char symbol_prefix_char = '\0';
 static unsigned long long kernel_start_addr = 0;
 
@@ -83,19 +88,20 @@ static inline int is_arm_mapping_symbol(const char *str)
               && (str[2] == '\0' || str[2] == '.');
 }
 
-static int read_symbol_tr(const char *sym, unsigned long long addr)
+static int check_symbol_range(const char *sym, unsigned long long addr,
+                             struct addr_range *ranges, int entries)
 {
        size_t i;
-       struct text_range *tr;
+       struct addr_range *ar;
 
-       for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) {
-               tr = &text_ranges[i];
+       for (i = 0; i < entries; ++i) {
+               ar = &ranges[i];
 
-               if (strcmp(sym, tr->stext) == 0) {
-                       tr->start = addr;
+               if (strcmp(sym, ar->start_sym) == 0) {
+                       ar->start = addr;
                        return 0;
-               } else if (strcmp(sym, tr->etext) == 0) {
-                       tr->end = addr;
+               } else if (strcmp(sym, ar->end_sym) == 0) {
+                       ar->end = addr;
                        return 0;
                }
        }
@@ -130,7 +136,8 @@ static int read_symbol(FILE *in, struct sym_entry *s)
        /* Ignore most absolute/undefined (?) symbols. */
        if (strcmp(sym, "_text") == 0)
                _text = s->addr;
-       else if (read_symbol_tr(sym, s->addr) == 0)
+       else if (check_symbol_range(sym, s->addr, text_ranges,
+                                   ARRAY_SIZE(text_ranges)) == 0)
                /* nothing to do */;
        else if (toupper(stype) == 'A')
        {
@@ -164,18 +171,22 @@ static int read_symbol(FILE *in, struct sym_entry *s)
        strcpy((char *)s->sym + 1, str);
        s->sym[0] = stype;
 
+       /* Record if we've found __per_cpu_start/end. */
+       check_symbol_range(sym, s->addr, &percpu_range, 1);
+
        return 0;
 }
 
-static int symbol_valid_tr(struct sym_entry *s)
+static int symbol_in_range(struct sym_entry *s, struct addr_range *ranges,
+                          int entries)
 {
        size_t i;
-       struct text_range *tr;
+       struct addr_range *ar;
 
-       for (i = 0; i < ARRAY_SIZE(text_ranges); ++i) {
-               tr = &text_ranges[i];
+       for (i = 0; i < entries; ++i) {
+               ar = &ranges[i];
 
-               if (s->addr >= tr->start && s->addr <= tr->end)
+               if (s->addr >= ar->start && s->addr <= ar->end)
                        return 1;
        }
 
@@ -214,7 +225,8 @@ static int symbol_valid(struct sym_entry *s)
        /* if --all-symbols is not specified, then symbols outside the text
         * and inittext sections are discarded */
        if (!all_symbols) {
-               if (symbol_valid_tr(s) == 0)
+               if (symbol_in_range(s, text_ranges,
+                                   ARRAY_SIZE(text_ranges)) == 0)
                        return 0;
                /* Corner case.  Discard any symbols with the same value as
                 * _etext _einittext; they can move between pass 1 and 2 when
@@ -223,9 +235,11 @@ static int symbol_valid(struct sym_entry *s)
                 * rules.
                 */
                if ((s->addr == text_range_text->end &&
-                               strcmp((char *)s->sym + offset, text_range_text->etext)) ||
+                               strcmp((char *)s->sym + offset,
+                                      text_range_text->end_sym)) ||
                    (s->addr == text_range_inittext->end &&
-                               strcmp((char *)s->sym + offset, text_range_inittext->etext)))
+                               strcmp((char *)s->sym + offset,
+                                      text_range_inittext->end_sym)))
                        return 0;
        }
 
@@ -298,6 +312,11 @@ static int expand_symbol(unsigned char *data, int len, char *result)
        return total;
 }
 
+static int symbol_absolute(struct sym_entry *s)
+{
+       return toupper(s->sym[0]) == 'A';
+}
+
 static void write_src(void)
 {
        unsigned int i, k, off;
@@ -325,7 +344,7 @@ static void write_src(void)
         */
        output_label("kallsyms_addresses");
        for (i = 0; i < table_cnt; i++) {
-               if (toupper(table[i].sym[0]) != 'A') {
+               if (!symbol_absolute(&table[i])) {
                        if (_text <= table[i].addr)
                                printf("\tPTR\t_text + %#llx\n",
                                        table[i].addr - _text);
@@ -646,6 +665,15 @@ static void sort_symbols(void)
        qsort(table, table_cnt, sizeof(struct sym_entry), compare_symbols);
 }
 
+static void make_percpus_absolute(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < table_cnt; i++)
+               if (symbol_in_range(&table[i], &percpu_range, 1))
+                       table[i].sym[0] = 'A';
+}
+
 int main(int argc, char **argv)
 {
        if (argc >= 2) {
@@ -653,6 +681,8 @@ int main(int argc, char **argv)
                for (i = 1; i < argc; i++) {
                        if(strcmp(argv[i], "--all-symbols") == 0)
                                all_symbols = 1;
+                       else if (strcmp(argv[i], "--absolute-percpu") == 0)
+                               absolute_percpu = 1;
                        else if (strncmp(argv[i], "--symbol-prefix=", 16) == 0) {
                                char *p = &argv[i][16];
                                /* skip quote */
@@ -669,6 +699,8 @@ int main(int argc, char **argv)
                usage();
 
        read_map(stdin);
+       if (absolute_percpu)
+               make_percpus_absolute();
        sort_symbols();
        optimize_token_table();
        write_src();
index 87f7238..f88d90f 100644 (file)
@@ -1178,7 +1178,10 @@ bool conf_set_all_new_symbols(enum conf_def_mode mode)
                                sym->def[S_DEF_USER].tri = mod;
                                break;
                        case def_no:
-                               sym->def[S_DEF_USER].tri = no;
+                               if (sym->flags & SYMBOL_ALLNOCONFIG_Y)
+                                       sym->def[S_DEF_USER].tri = yes;
+                               else
+                                       sym->def[S_DEF_USER].tri = no;
                                break;
                        case def_random:
                                sym->def[S_DEF_USER].tri = no;
index ba663e1..412ea8a 100644 (file)
@@ -109,6 +109,9 @@ struct symbol {
 /* choice values need to be set before calculating this symbol value */
 #define SYMBOL_NEED_SET_CHOICE_VALUES  0x100000
 
+/* Set symbol to y if allnoconfig; used for symbols that hide others */
+#define SYMBOL_ALLNOCONFIG_Y 0x200000
+
 #define SYMBOL_MAXLENGTH       256
 #define SYMBOL_HASHSIZE                9973
 
index 09f4edf..d5daa7a 100644 (file)
@@ -61,6 +61,7 @@ enum conf_def_mode {
 #define T_OPT_MODULES          1
 #define T_OPT_DEFCONFIG_LIST   2
 #define T_OPT_ENV              3
+#define T_OPT_ALLNOCONFIG_Y    4
 
 struct kconf_id {
        int name;
index db1512a..3ac2c9c 100644 (file)
@@ -217,6 +217,9 @@ void menu_add_option(int token, char *arg)
        case T_OPT_ENV:
                prop_add_env(arg);
                break;
+       case T_OPT_ALLNOCONFIG_Y:
+               current_entry->sym->flags |= SYMBOL_ALLNOCONFIG_Y;
+               break;
        }
 }
 
index f14ab41..b6ac02d 100644 (file)
@@ -44,4 +44,5 @@ on,           T_ON,           TF_PARAM
 modules,       T_OPT_MODULES,  TF_OPTION
 defconfig_list,        T_OPT_DEFCONFIG_LIST,TF_OPTION
 env,           T_OPT_ENV,      TF_OPTION
+allnoconfig_y, T_OPT_ALLNOCONFIG_Y,TF_OPTION
 %%
index 40df000..c77a8ef 100644 (file)
@@ -55,10 +55,10 @@ kconf_id_hash (register const char *str, register unsigned int len)
       73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
       73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
       73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
-      73, 73, 73, 73, 73, 73, 73, 73, 25, 25,
+      73, 73, 73, 73, 73, 73, 73,  5, 25, 25,
        0,  0,  0,  5,  0,  0, 73, 73,  5,  0,
       10,  5, 45, 73, 20, 20,  0, 15, 15, 73,
-      20, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+      20,  5, 73, 73, 73, 73, 73, 73, 73, 73,
       73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
       73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
       73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
@@ -106,6 +106,7 @@ struct kconf_id_strings_t
     char kconf_id_strings_str23[sizeof("mainmenu")];
     char kconf_id_strings_str25[sizeof("menuconfig")];
     char kconf_id_strings_str27[sizeof("modules")];
+    char kconf_id_strings_str28[sizeof("allnoconfig_y")];
     char kconf_id_strings_str29[sizeof("menu")];
     char kconf_id_strings_str31[sizeof("select")];
     char kconf_id_strings_str32[sizeof("comment")];
@@ -141,6 +142,7 @@ static const struct kconf_id_strings_t kconf_id_strings_contents =
     "mainmenu",
     "menuconfig",
     "modules",
+    "allnoconfig_y",
     "menu",
     "select",
     "comment",
@@ -170,7 +172,7 @@ kconf_id_lookup (register const char *str, register unsigned int len)
 {
   enum
     {
-      TOTAL_KEYWORDS = 32,
+      TOTAL_KEYWORDS = 33,
       MIN_WORD_LENGTH = 2,
       MAX_WORD_LENGTH = 14,
       MIN_HASH_VALUE = 2,
@@ -219,7 +221,8 @@ kconf_id_lookup (register const char *str, register unsigned int len)
       {-1},
 #line 44 "scripts/kconfig/zconf.gperf"
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str27,   T_OPT_MODULES,  TF_OPTION},
-      {-1},
+#line 47 "scripts/kconfig/zconf.gperf"
+      {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str28,   T_OPT_ALLNOCONFIG_Y,TF_OPTION},
 #line 16 "scripts/kconfig/zconf.gperf"
       {(int)(long)&((struct kconf_id_strings_t *)0)->kconf_id_strings_str29,           T_MENU,         TF_COMMAND},
       {-1},
@@ -282,5 +285,5 @@ kconf_id_lookup (register const char *str, register unsigned int len)
     }
   return 0;
 }
-#line 47 "scripts/kconfig/zconf.gperf"
+#line 48 "scripts/kconfig/zconf.gperf"
 
index 2dcb377..86a4fe7 100644 (file)
@@ -86,6 +86,10 @@ kallsyms()
                kallsymopt="${kallsymopt} --page-offset=$CONFIG_PAGE_OFFSET"
        fi
 
+       if [ -n "${CONFIG_X86_64}" ]; then
+               kallsymopt="${kallsymopt} --absolute-percpu"
+       fi
+
        local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL}               \
                      ${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
 
index 25f6f59..1924990 100644 (file)
@@ -42,7 +42,7 @@ typedef unsigned char __u8;
 
 /* This array collects all instances that use the generic do_table */
 struct devtable {
-       const char *device_id; /* name of table, __mod_<name>_device_table. */
+       const char *device_id; /* name of table, __mod_<name>__*_device_table. */
        unsigned long id_size;
        void *function;
 };
@@ -146,7 +146,8 @@ static void device_id_check(const char *modname, const char *device_id,
 
        if (size % id_size || size < id_size) {
                fatal("%s: sizeof(struct %s_device_id)=%lu is not a modulo "
-                     "of the size of section __mod_%s_device_table=%lu.\n"
+                     "of the size of "
+                     "section __mod_%s__<identifier>_device_table=%lu.\n"
                      "Fix definition of struct %s_device_id "
                      "in mod_devicetable.h\n",
                      modname, device_id, id_size, device_id, size, device_id);
@@ -1216,7 +1217,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
 {
        void *symval;
        char *zeros = NULL;
-       const char *name;
+       const char *name, *identifier;
        unsigned int namelen;
 
        /* We're looking for a section relative symbol */
@@ -1227,7 +1228,7 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
        if (ELF_ST_TYPE(sym->st_info) != STT_OBJECT)
                return;
 
-       /* All our symbols are of form <prefix>__mod_XXX_device_table. */
+       /* All our symbols are of form <prefix>__mod_<name>__<identifier>_device_table. */
        name = strstr(symname, "__mod_");
        if (!name)
                return;
@@ -1237,7 +1238,10 @@ void handle_moddevtable(struct module *mod, struct elf_info *info,
                return;
        if (strcmp(name + namelen - strlen("_device_table"), "_device_table"))
                return;
-       namelen -= strlen("_device_table");
+       identifier = strstr(name, "__");
+       if (!identifier)
+               return;
+       namelen = identifier - name;
 
        /* Handle all-NULL symbols allocated into .bss */
        if (info->sechdrs[get_secindex(info, sym)].sh_type & SHT_NOBITS) {
index 6c2dc38..7e21621 100644 (file)
@@ -150,10 +150,8 @@ static void snd_cs8427_free(struct snd_i2c_device *device)
        kfree(device->private_data);
 }
 
-int snd_cs8427_create(struct snd_i2c_bus *bus,
-                     unsigned char addr,
-                     unsigned int reset_timeout,
-                     struct snd_i2c_device **r_cs8427)
+int snd_cs8427_init(struct snd_i2c_bus *bus,
+                   struct snd_i2c_device *device)
 {
        static unsigned char initvals1[] = {
          CS8427_REG_CONTROL1 | CS8427_REG_AUTOINC,
@@ -200,22 +198,10 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
             Inhibit E->F transfers. */
          CS8427_UD | CS8427_EFTUI | CS8427_DETUI,
        };
+       struct cs8427 *chip = device->private_data;
        int err;
-       struct cs8427 *chip;
-       struct snd_i2c_device *device;
        unsigned char buf[24];
 
-       if ((err = snd_i2c_device_create(bus, "CS8427",
-                                        CS8427_ADDR | (addr & 7),
-                                        &device)) < 0)
-               return err;
-       chip = device->private_data = kzalloc(sizeof(*chip), GFP_KERNEL);
-       if (chip == NULL) {
-               snd_i2c_device_free(device);
-               return -ENOMEM;
-       }
-       device->private_free = snd_cs8427_free;
-       
        snd_i2c_lock(bus);
        err = snd_cs8427_reg_read(device, CS8427_REG_ID_AND_VER);
        if (err != CS8427_VER8427A) {
@@ -264,10 +250,44 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
        snd_i2c_unlock(bus);
 
        /* turn on run bit and rock'n'roll */
+       snd_cs8427_reset(device);
+
+       return 0;
+
+__fail:
+       snd_i2c_unlock(bus);
+
+       return err;
+}
+EXPORT_SYMBOL(snd_cs8427_init);
+
+int snd_cs8427_create(struct snd_i2c_bus *bus,
+                     unsigned char addr,
+                     unsigned int reset_timeout,
+                     struct snd_i2c_device **r_cs8427)
+{
+       int err;
+       struct cs8427 *chip;
+       struct snd_i2c_device *device;
+
+       err = snd_i2c_device_create(bus, "CS8427", CS8427_ADDR | (addr & 7),
+                                   &device);
+       if (err < 0)
+               return err;
+       chip = device->private_data = kzalloc(sizeof(*chip), GFP_KERNEL);
+       if (chip == NULL) {
+               snd_i2c_device_free(device);
+               return -ENOMEM;
+       }
+       device->private_free = snd_cs8427_free;
+
        if (reset_timeout < 1)
                reset_timeout = 1;
        chip->reset_timeout = reset_timeout;
-       snd_cs8427_reset(device);
+
+       err = snd_cs8427_init(bus, device);
+       if (err)
+               goto __fail;
 
 #if 0  // it's nice for read tests
        {
@@ -286,7 +306,6 @@ int snd_cs8427_create(struct snd_i2c_bus *bus,
        return 0;
 
       __fail:
-       snd_i2c_unlock(bus);
        snd_i2c_device_free(device);
        return err < 0 ? err : -EIO;
 }
index affa134..0216475 100644 (file)
@@ -191,7 +191,7 @@ config SND_ES18XX
 
 config SND_SC6000
        tristate "Gallant SC-6000/6600/7000 and Audio Excel DSP 16"
-       depends on HAS_IOPORT
+       depends on HAS_IOPORT_MAP
        select SND_WSS_LIB
        select SND_OPL3_LIB
        select SND_MPU401_UART
index a7cc49e..d10ef76 100644 (file)
@@ -725,15 +725,4 @@ struct platform_driver au1000_ac97c_driver = {
        .remove         = au1000_ac97_remove,
 };
 
-static int __init au1000_ac97_load(void)
-{
-       return platform_driver_register(&au1000_ac97c_driver);
-}
-
-static void __exit au1000_ac97_unload(void)
-{
-       platform_driver_unregister(&au1000_ac97c_driver);
-}
-
-module_init(au1000_ac97_load);
-module_exit(au1000_ac97_unload);
+module_platform_driver(au1000_ac97c_driver);
index 4918b71..ec1ee07 100644 (file)
@@ -50,8 +50,6 @@
 #include <linux/pnp.h>
 #include <linux/spinlock.h>
 
-#define DEB(x)
-#define DEB1(x)
 #include "sound_config.h"
 
 #include "ad1848.h"
@@ -1016,8 +1014,6 @@ static void ad1848_close(int dev)
        ad1848_info    *devc = (ad1848_info *) audio_devs[dev]->devc;
        ad1848_port_info *portc = (ad1848_port_info *) audio_devs[dev]->portc;
 
-       DEB(printk("ad1848_close(void)\n"));
-
        devc->intr_active = 0;
        ad1848_halt(dev);
 
index 87910e9..c2d45a5 100644 (file)
@@ -733,19 +733,7 @@ static struct platform_driver amiga_audio_driver = {
        },
 };
 
-static int __init amiga_audio_init(void)
-{
-       return platform_driver_probe(&amiga_audio_driver, amiga_audio_probe);
-}
-
-module_init(amiga_audio_init);
-
-static void __exit amiga_audio_exit(void)
-{
-       platform_driver_unregister(&amiga_audio_driver);
-}
-
-module_exit(amiga_audio_exit);
+module_platform_driver_probe(amiga_audio_driver, amiga_audio_probe);
 
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:amiga-audio");
index c5c2440..4709e59 100644 (file)
@@ -275,7 +275,6 @@ static int opl3_kill_note  (int devno, int voice, int note, int velocity)
         devc->v_alloc->map[voice] = 0;
 
         map = &pv_map[devc->lv_map[voice]];
-        DEB(printk("Kill note %d\n", voice));
 
         if (map->voice_mode == 0)
                 return 0;
@@ -873,8 +872,6 @@ static void opl3_aftertouch(int dev, int voice, int pressure)
 
        map = &pv_map[devc->lv_map[voice]];
 
-       DEB(printk("Aftertouch %d\n", voice));
-
        if (map->voice_mode == 0)
                return;
 
index a0bcb85..50b5bd5 100644 (file)
 
 #include "pas2.h"
 
-#ifndef DEB
-#define DEB(what)              /* (what) */
-#endif
-
 extern int      pas_translate_code;
 extern char     pas_model;
 extern int     *pas_osp;
@@ -120,8 +116,6 @@ pas_mixer_set(int whichDev, unsigned int level)
 {
        int             left, right, devmask, changed, i, mixer = 0;
 
-       DEB(printk("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level));
-
        left = level & 0x7f;
        right = (level & 0x7f00) >> 8;
 
@@ -207,8 +201,6 @@ pas_mixer_reset(void)
 {
        int             foo;
 
-       DEB(printk("pas2_mixer.c: void pas_mixer_reset(void)\n"));
-
        for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++)
                pas_mixer_set(foo, levels[foo]);
 
@@ -220,7 +212,6 @@ static int pas_mixer_ioctl(int dev, unsigned int cmd, void __user *arg)
        int level,v ;
        int __user *p = (int __user *)arg;
 
-       DEB(printk("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
        if (cmd == SOUND_MIXER_PRIVATE1) { /* Set loudness bit */
                if (get_user(level, p))
                        return -EFAULT;
index 6f13ab4..474803b 100644 (file)
 
 #include "pas2.h"
 
-#ifndef DEB
-#define DEB(WHAT)
-#endif
-
 #define PAS_PCM_INTRBITS (0x08)
 /*
  * Sample buffer timer interrupt enable
@@ -156,8 +152,6 @@ static int pas_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
        int val, ret;
        int __user *p = arg;
 
-       DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
-
        switch (cmd) 
        {
        case SOUND_PCM_WRITE_RATE:
@@ -204,8 +198,6 @@ static int pas_audio_ioctl(int dev, unsigned int cmd, void __user *arg)
 
 static void pas_audio_reset(int dev)
 {
-       DEB(printk("pas2_pcm.c: static void pas_audio_reset(void)\n"));
-
        pas_write(pas_read(0xF8A) & ~0x40, 0xF8A);      /* Disable PCM */
 }
 
@@ -214,8 +206,6 @@ static int pas_audio_open(int dev, int mode)
        int             err;
        unsigned long   flags;
 
-       DEB(printk("pas2_pcm.c: static int pas_audio_open(int mode = %X)\n", mode));
-
        spin_lock_irqsave(&pas_lock, flags);
        if (pcm_busy)
        {
@@ -239,8 +229,6 @@ static void pas_audio_close(int dev)
 {
        unsigned long   flags;
 
-       DEB(printk("pas2_pcm.c: static void pas_audio_close(void)\n"));
-
        spin_lock_irqsave(&pas_lock, flags);
 
        pas_audio_reset(dev);
@@ -256,8 +244,6 @@ static void pas_audio_output_block(int dev, unsigned long buf, int count,
 {
        unsigned long   flags, cnt;
 
-       DEB(printk("pas2_pcm.c: static void pas_audio_output_block(char *buf = %P, int count = %X)\n", buf, count));
-
        cnt = count;
        if (audio_devs[dev]->dmap_out->dma > 3)
                cnt >>= 1;
@@ -303,8 +289,6 @@ static void pas_audio_start_input(int dev, unsigned long buf, int count,
        unsigned long   flags;
        int             cnt;
 
-       DEB(printk("pas2_pcm.c: static void pas_audio_start_input(char *buf = %P, int count = %X)\n", buf, count));
-
        cnt = count;
        if (audio_devs[dev]->dmap_out->dma > 3)
                cnt >>= 1;
@@ -388,8 +372,6 @@ static struct audio_driver pas_audio_driver =
 
 void __init pas_pcm_init(struct address_info *hw_config)
 {
-       DEB(printk("pas2_pcm.c: long pas_pcm_init()\n"));
-
        pcm_bitsok = 8;
        if (pas_read(0xEF8B) & 0x08)
                pcm_bitsok |= 16;
index 851a1da..3d50fb4 100644 (file)
@@ -226,8 +226,6 @@ int sb_dsp_reset(sb_devc * devc)
 {
        int loopc;
 
-       DEB(printk("Entered sb_dsp_reset()\n"));
-
        if (devc->model == MDL_ESS) return ess_dsp_reset (devc);
 
        /* This is only for non-ESS chips */
@@ -246,8 +244,6 @@ int sb_dsp_reset(sb_devc * devc)
                return 0;       /* Sorry */
        }
 
-       DEB(printk("sb_dsp_reset() OK\n"));
-
        return 1;
 }
 
index 0e7254b..b47a690 100644 (file)
@@ -865,8 +865,6 @@ printk(KERN_INFO "FKS: ess_dsp_reset 1\n");
 ess_show_mixerregs (devc);
 #endif
 
-       DEB(printk("Entered ess_dsp_reset()\n"));
-
        outb(3, DSP_RESET); /* Reset FIFO too */
 
        udelay(10);
@@ -881,8 +879,6 @@ ess_show_mixerregs (devc);
        }
        ess_extended (devc);
 
-       DEB(printk("sb_dsp_reset() OK\n"));
-
 #ifdef FKS_LOGGING
 printk(KERN_INFO "FKS: dsp_reset 2\n");
 ess_show_mixerregs (devc);
index 9b9f7d3..c0eea1d 100644 (file)
@@ -216,8 +216,6 @@ int sequencer_write(int dev, struct file *file, const char __user *buf, int coun
 
        dev = dev >> 4;
 
-       DEB(printk("sequencer_write(dev=%d, count=%d)\n", dev, count));
-
        if (mode == OPEN_READ)
                return -EIO;
 
@@ -959,8 +957,6 @@ int sequencer_open(int dev, struct file *file)
        dev = dev >> 4;
        mode = translate_mode(file);
 
-       DEB(printk("sequencer_open(dev=%d)\n", dev));
-
        if (!sequencer_ok)
        {
 /*             printk("Sound card: sequencer not initialized\n");*/
@@ -1133,8 +1129,6 @@ void sequencer_release(int dev, struct file *file)
 
        dev = dev >> 4;
 
-       DEB(printk("sequencer_release(dev=%d)\n", dev));
-
        /*
         * Wait until the queue is empty (if we don't have nonblock)
         */
index 9d35c4c..f2554ab 100644 (file)
@@ -123,10 +123,6 @@ static inline int translate_mode(struct file *file)
 #include "sound_calls.h"
 #include "dev_table.h"
 
-#ifndef DEB
-#define DEB(x)
-#endif
-
 #ifndef DDB
 #define DDB(x) do {} while (0)
 #endif
index e778034..b70c7c8 100644 (file)
@@ -154,7 +154,6 @@ static ssize_t sound_read(struct file *file, char __user *buf, size_t count, lof
         
        mutex_lock(&soundcard_mutex);
        
-       DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
        switch (dev & 0x0f) {
        case SND_DEV_DSP:
        case SND_DEV_DSP16:
@@ -180,7 +179,6 @@ static ssize_t sound_write(struct file *file, const char __user *buf, size_t cou
        int ret = -EINVAL;
        
        mutex_lock(&soundcard_mutex);
-       DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
        switch (dev & 0x0f) {
        case SND_DEV_SEQ:
        case SND_DEV_SEQ2:
@@ -206,7 +204,6 @@ static int sound_open(struct inode *inode, struct file *file)
        int dev = iminor(inode);
        int retval;
 
-       DEB(printk("sound_open(dev=%d)\n", dev));
        if ((dev >= SND_NDEVS) || (dev < 0)) {
                printk(KERN_ERR "Invalid minor device %d\n", dev);
                return -ENXIO;
@@ -257,7 +254,6 @@ static int sound_release(struct inode *inode, struct file *file)
        int dev = iminor(inode);
 
        mutex_lock(&soundcard_mutex);
-       DEB(printk("sound_release(dev=%d)\n", dev));
        switch (dev & 0x0f) {
        case SND_DEV_CTL:
                module_put(mixer_devs[dev >> 4]->owner);
@@ -351,7 +347,6 @@ static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                        if (!access_ok(VERIFY_WRITE, p, len))
                                return -EFAULT;
        }
-       DEB(printk("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
        if (cmd == OSS_GETVERSION)
                return __put_user(SOUND_VERSION, (int __user *)p);
        
@@ -409,7 +404,6 @@ static unsigned int sound_poll(struct file *file, poll_table * wait)
        struct inode *inode = file_inode(file);
        int dev = iminor(inode);
 
-       DEB(printk("sound_poll(dev=%d)\n", dev));
        switch (dev & 0x0f) {
        case SND_DEV_SEQ:
        case SND_DEV_SEQ2:
index 5433c6f..62b8869 100644 (file)
@@ -274,19 +274,12 @@ static int reset_uart401(uart401_devc * devc)
                }
        }
 
-
+       /* Flush input before enabling interrupts */
        if (ok)
-       {
-               DEB(printk("Reset UART401 OK\n"));
-       }
+               uart401_input_loop(devc);
        else
                DDB(printk("Reset UART401 failed - No hardware detected.\n"));
 
-       if (ok)
-               uart401_input_loop(devc);       /*
-                                                * Flush input before enabling interrupts
-                                                */
-
        return ok;
 }
 
index 0b0c0cf..3a3a3a7 100644 (file)
@@ -688,7 +688,7 @@ config SND_LOLA
 
 config SND_LX6464ES
        tristate "Digigram LX6464ES"
-       depends on HAS_IOPORT
+       depends on HAS_IOPORT_MAP
        select SND_PCM
        help
          Say Y here to include support for Digigram LX6464ES boards.
index 97993e1..248b90a 100644 (file)
@@ -187,13 +187,14 @@ azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream)
                struct azx_dev *azx_dev = &chip->azx_dev[dev];
                dsp_lock(azx_dev);
                if (!azx_dev->opened && !dsp_is_locked(azx_dev)) {
-                       res = azx_dev;
-                       if (res->assigned_key == key) {
-                               res->opened = 1;
-                               res->assigned_key = key;
+                       if (azx_dev->assigned_key == key) {
+                               azx_dev->opened = 1;
+                               azx_dev->assigned_key = key;
                                dsp_unlock(azx_dev);
                                return azx_dev;
                        }
+                       if (!res)
+                               res = azx_dev;
                }
                dsp_unlock(azx_dev);
        }
@@ -1604,7 +1605,7 @@ static void azx_exit_link_reset(struct azx *chip)
 }
 
 /* reset codec link */
-static int azx_reset(struct azx *chip, int full_reset)
+static int azx_reset(struct azx *chip, bool full_reset)
 {
        if (!full_reset)
                goto __skip;
@@ -1701,7 +1702,7 @@ static void azx_int_clear(struct azx *chip)
 /*
  * reset and start the controller registers
  */
-void azx_init_chip(struct azx *chip, int full_reset)
+void azx_init_chip(struct azx *chip, bool full_reset)
 {
        if (chip->initialized)
                return;
@@ -1758,7 +1759,7 @@ irqreturn_t azx_interrupt(int irq, void *dev_id)
 
 #ifdef CONFIG_PM_RUNTIME
        if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME)
-               if (chip->card->dev->power.runtime_status != RPM_ACTIVE)
+               if (!pm_runtime_active(chip->card->dev))
                        return IRQ_NONE;
 #endif
 
@@ -1841,7 +1842,7 @@ static void azx_bus_reset(struct hda_bus *bus)
 
        bus->in_reset = 1;
        azx_stop_chip(chip);
-       azx_init_chip(chip, 1);
+       azx_init_chip(chip, true);
 #ifdef CONFIG_PM
        if (chip->initialized) {
                struct azx_pcm *p;
@@ -1948,7 +1949,7 @@ int azx_codec_create(struct azx *chip, const char *model,
                                 * get back to the sanity state.
                                 */
                                azx_stop_chip(chip);
-                               azx_init_chip(chip, 1);
+                               azx_init_chip(chip, true);
                        }
                }
        }
index 1d2e3be..baf0e77 100644 (file)
@@ -37,7 +37,7 @@ int azx_alloc_stream_pages(struct azx *chip);
 void azx_free_stream_pages(struct azx *chip);
 
 /* Low level azx interface */
-void azx_init_chip(struct azx *chip, int full_reset);
+void azx_init_chip(struct azx *chip, bool full_reset);
 void azx_stop_chip(struct azx *chip);
 void azx_enter_link_reset(struct azx *chip);
 irqreturn_t azx_interrupt(int irq, void *dev_id);
index 77ca894..d6bca62 100644 (file)
@@ -636,7 +636,7 @@ static int azx_resume(struct device *dev)
                return -EIO;
        azx_init_pci(chip);
 
-       azx_init_chip(chip, 1);
+       azx_init_chip(chip, true);
 
        snd_hda_resume(chip->bus);
        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
@@ -689,7 +689,7 @@ static int azx_runtime_resume(struct device *dev)
        status = azx_readw(chip, STATESTS);
 
        azx_init_pci(chip);
-       azx_init_chip(chip, 1);
+       azx_init_chip(chip, true);
 
        bus = chip->bus;
        if (status && bus) {
index ea2351d..14ae979 100644 (file)
@@ -3026,6 +3026,11 @@ static void alc283_init(struct hda_codec *codec)
        bool hp_pin_sense;
        int val;
 
+       if (!spec->gen.autocfg.hp_outs) {
+               if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
+                       hp_pin = spec->gen.autocfg.line_out_pins[0];
+       }
+
        alc283_restore_default_value(codec);
 
        if (!hp_pin)
@@ -3062,6 +3067,11 @@ static void alc283_shutup(struct hda_codec *codec)
        bool hp_pin_sense;
        int val;
 
+       if (!spec->gen.autocfg.hp_outs) {
+               if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT)
+                       hp_pin = spec->gen.autocfg.line_out_pins[0];
+       }
+
        if (!hp_pin) {
                alc269_shutup(codec);
                return;
@@ -3085,6 +3095,7 @@ static void alc283_shutup(struct hda_codec *codec)
 
        if (hp_pin_sense)
                msleep(100);
+       alc_auto_setup_eapd(codec, false);
        snd_hda_shutup_pins(codec);
        alc_write_coef_idx(codec, 0x43, 0x9614);
 }
@@ -3361,8 +3372,9 @@ static void alc269_fixup_mic_mute_hook(void *private_data, int enabled)
 
        if (spec->mute_led_polarity)
                enabled = !enabled;
-       pinval = AC_PINCTL_IN_EN |
-               (enabled ? AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_80);
+       pinval = snd_hda_codec_get_pin_target(codec, spec->mute_led_nid);
+       pinval &= ~AC_PINCTL_VREFEN;
+       pinval |= enabled ? AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_80;
        if (spec->mute_led_nid)
                snd_hda_set_pin_ctl_cache(codec, spec->mute_led_nid, pinval);
 }
@@ -3994,6 +4006,10 @@ static void alc283_fixup_chromebook(struct hda_codec *codec,
                spec->gen.mixer_nid = 0;
                break;
        case HDA_FIXUP_ACT_INIT:
+               /* MIC2-VREF control */
+               /* Set to manual mode */
+               val = alc_read_coef_idx(codec, 0x06);
+               alc_write_coef_idx(codec, 0x06, val & ~0x000c);
                /* Enable Line1 input control by verb */
                val = alc_read_coef_idx(codec, 0x1a);
                alc_write_coef_idx(codec, 0x1a, val | (1 << 4));
@@ -4602,6 +4618,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x0658, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x065f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0662, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x0667, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE),
@@ -4768,7 +4785,7 @@ static const struct hda_model_fixup alc269_fixup_models[] = {
        {.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"},
        {.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"},
        {.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"},
-       {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-chrome"},
+       {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"},
        {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"},
        {}
 };
index ed2144e..496dbd0 100644 (file)
@@ -579,12 +579,37 @@ static struct snd_ak4xxx_private akm_vx442_priv = {
 #ifdef CONFIG_PM_SLEEP
 static int snd_ice1712_delta_resume(struct snd_ice1712 *ice)
 {
-       unsigned char akm_backup[AK4XXX_IMAGE_SIZE];
+       unsigned char akm_img_bak[AK4XXX_IMAGE_SIZE];
+       unsigned char akm_vol_bak[AK4XXX_IMAGE_SIZE];
+
+       /* init spdif */
+       switch (ice->eeprom.subvendor) {
+       case ICE1712_SUBDEVICE_AUDIOPHILE:
+       case ICE1712_SUBDEVICE_DELTA410:
+       case ICE1712_SUBDEVICE_DELTA1010E:
+       case ICE1712_SUBDEVICE_DELTA1010LT:
+       case ICE1712_SUBDEVICE_VX442:
+       case ICE1712_SUBDEVICE_DELTA66E:
+               snd_cs8427_init(ice->i2c, ice->cs8427);
+               break;
+       case ICE1712_SUBDEVICE_DELTA1010:
+       case ICE1712_SUBDEVICE_MEDIASTATION:
+               /* nothing */
+               break;
+       case ICE1712_SUBDEVICE_DELTADIO2496:
+       case ICE1712_SUBDEVICE_DELTA66:
+               /* Set spdif defaults */
+               snd_ice1712_delta_cs8403_spdif_write(ice, ice->spdif.cs8403_bits);
+               break;
+       }
+
        /* init codec and restore registers */
        if (ice->akm_codecs) {
-               memcpy(akm_backup, ice->akm->images, sizeof(akm_backup));
+               memcpy(akm_img_bak, ice->akm->images, sizeof(akm_img_bak));
+               memcpy(akm_vol_bak, ice->akm->volumes, sizeof(akm_vol_bak));
                snd_akm4xxx_init(ice->akm);
-               memcpy(ice->akm->images, akm_backup, sizeof(akm_backup));
+               memcpy(ice->akm->images, akm_img_bak, sizeof(akm_img_bak));
+               memcpy(ice->akm->volumes, akm_vol_bak, sizeof(akm_vol_bak));
                snd_akm4xxx_reset(ice->akm, 0);
        }
 
index 291672f..d9b9e45 100644 (file)
@@ -685,9 +685,10 @@ static snd_pcm_uframes_t snd_ice1712_playback_pointer(struct snd_pcm_substream *
        if (!(snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL) & 1))
                return 0;
        ptr = runtime->buffer_size - inw(ice->ddma_port + 4);
+       ptr = bytes_to_frames(substream->runtime, ptr);
        if (ptr == runtime->buffer_size)
                ptr = 0;
-       return bytes_to_frames(substream->runtime, ptr);
+       return ptr;
 }
 
 static snd_pcm_uframes_t snd_ice1712_playback_ds_pointer(struct snd_pcm_substream *substream)
@@ -704,9 +705,10 @@ static snd_pcm_uframes_t snd_ice1712_playback_ds_pointer(struct snd_pcm_substrea
                addr = ICE1712_DSC_ADDR0;
        ptr = snd_ice1712_ds_read(ice, substream->number * 2, addr) -
                ice->playback_con_virt_addr[substream->number];
+       ptr = bytes_to_frames(substream->runtime, ptr);
        if (ptr == substream->runtime->buffer_size)
                ptr = 0;
-       return bytes_to_frames(substream->runtime, ptr);
+       return ptr;
 }
 
 static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *substream)
@@ -717,9 +719,10 @@ static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *s
        if (!(snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL) & 1))
                return 0;
        ptr = inl(ICEREG(ice, CONCAP_ADDR)) - ice->capture_con_virt_addr;
+       ptr = bytes_to_frames(substream->runtime, ptr);
        if (ptr == substream->runtime->buffer_size)
                ptr = 0;
-       return bytes_to_frames(substream->runtime, ptr);
+       return ptr;
 }
 
 static const struct snd_pcm_hardware snd_ice1712_playback = {
@@ -1048,6 +1051,8 @@ __out:
        old = inb(ICEMT(ice, RATE));
        if (!force && old == val)
                goto __out;
+
+       ice->cur_rate = rate;
        outb(val, ICEMT(ice, RATE));
        spin_unlock_irqrestore(&ice->reg_lock, flags);
 
@@ -1114,9 +1119,10 @@ static snd_pcm_uframes_t snd_ice1712_playback_pro_pointer(struct snd_pcm_substre
        if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_PLAYBACK_START))
                return 0;
        ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2);
+       ptr = bytes_to_frames(substream->runtime, ptr);
        if (ptr == substream->runtime->buffer_size)
                ptr = 0;
-       return bytes_to_frames(substream->runtime, ptr);
+       return ptr;
 }
 
 static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substream *substream)
@@ -1127,9 +1133,10 @@ static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substrea
        if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_CAPTURE_START_SHADOW))
                return 0;
        ptr = ice->capture_pro_size - (inw(ICEMT(ice, CAPTURE_SIZE)) << 2);
+       ptr = bytes_to_frames(substream->runtime, ptr);
        if (ptr == substream->runtime->buffer_size)
                ptr = 0;
-       return bytes_to_frames(substream->runtime, ptr);
+       return ptr;
 }
 
 static const struct snd_pcm_hardware snd_ice1712_playback_pro = {
@@ -2832,6 +2839,12 @@ static int snd_ice1712_suspend(struct device *dev)
        snd_pcm_suspend_all(ice->pcm_ds);
        snd_ac97_suspend(ice->ac97);
 
+       spin_lock_irq(&ice->reg_lock);
+       ice->pm_saved_is_spdif_master = is_spdif_master(ice);
+       ice->pm_saved_spdif_ctrl = inw(ICEMT(ice, ROUTE_SPDOUT));
+       ice->pm_saved_route = inw(ICEMT(ice, ROUTE_PSDOUT03));
+       spin_unlock_irq(&ice->reg_lock);
+
        if (ice->pm_suspend)
                ice->pm_suspend(ice);
 
@@ -2846,6 +2859,7 @@ static int snd_ice1712_resume(struct device *dev)
        struct pci_dev *pci = to_pci_dev(dev);
        struct snd_card *card = dev_get_drvdata(dev);
        struct snd_ice1712 *ice = card->private_data;
+       int rate;
 
        if (!ice->pm_suspend_enabled)
                return 0;
@@ -2860,14 +2874,37 @@ static int snd_ice1712_resume(struct device *dev)
 
        pci_set_master(pci);
 
+       if (ice->cur_rate)
+               rate = ice->cur_rate;
+       else
+               rate = PRO_RATE_DEFAULT;
+
        if (snd_ice1712_chip_init(ice) < 0) {
                snd_card_disconnect(card);
                return -EIO;
        }
 
+       ice->cur_rate = rate;
+
        if (ice->pm_resume)
                ice->pm_resume(ice);
 
+       if (ice->pm_saved_is_spdif_master) {
+               /* switching to external clock via SPDIF */
+               spin_lock_irq(&ice->reg_lock);
+               outb(inb(ICEMT(ice, RATE)) | ICE1712_SPDIF_MASTER,
+                       ICEMT(ice, RATE));
+               spin_unlock_irq(&ice->reg_lock);
+               snd_ice1712_set_input_clock_source(ice, 1);
+       } else {
+               /* internal on-card clock */
+               snd_ice1712_set_pro_rate(ice, rate, 1);
+               snd_ice1712_set_input_clock_source(ice, 0);
+       }
+
+       outw(ice->pm_saved_spdif_ctrl, ICEMT(ice, ROUTE_SPDOUT));
+       outw(ice->pm_saved_route, ICEMT(ice, ROUTE_PSDOUT03));
+
        if (ice->ac97)
                snd_ac97_resume(ice->ac97);
 
index 09f7e77..f500905 100644 (file)
@@ -902,7 +902,6 @@ static int alc5623_probe(struct snd_soc_codec *codec)
 {
        struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
        struct snd_soc_dapm_context *dapm = &codec->dapm;
-       int ret;
 
        alc5623_reset(codec);
 
@@ -961,7 +960,7 @@ static int alc5623_probe(struct snd_soc_codec *codec)
                return -EINVAL;
        }
 
-       return ret;
+       return 0;
 }
 
 /* power down chip */
index ec071a6..85942ca 100644 (file)
@@ -1061,7 +1061,6 @@ static int alc5632_resume(struct snd_soc_codec *codec)
 static int alc5632_probe(struct snd_soc_codec *codec)
 {
        struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
-       int ret;
 
        /* power on device  */
        alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1075,7 +1074,7 @@ static int alc5632_probe(struct snd_soc_codec *codec)
                return -EINVAL;
        }
 
-       return ret;
+       return 0;
 }
 
 /* power down chip */
@@ -1191,11 +1190,18 @@ static const struct i2c_device_id alc5632_i2c_table[] = {
 };
 MODULE_DEVICE_TABLE(i2c, alc5632_i2c_table);
 
+static const struct of_device_id alc5632_of_match[] = {
+       { .compatible = "realtek,alc5632", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, alc5632_of_match);
+
 /* i2c codec control layer */
 static struct i2c_driver alc5632_i2c_driver = {
        .driver = {
                .name = "alc5632",
                .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(alc5632_of_match),
        },
        .probe = alc5632_i2c_probe,
        .remove =  alc5632_i2c_remove,
index f0ca6be..460d355 100644 (file)
@@ -1259,7 +1259,7 @@ static int cs42l52_i2c_probe(struct i2c_client *i2c_client,
        }
 
        dev_info(&i2c_client->dev, "Cirrus Logic CS42L52, Revision: %02X\n",
-                       reg & 0xFF);
+                reg & CS42L52_CHIP_REV_MASK);
 
        /* Set Platform Data */
        if (cs42l52->pdata.mica_diff_cfg)
index 6fb8f00..ac44599 100644 (file)
@@ -37,7 +37,7 @@
 #define CS42L52_CHIP_REV_A0                    0x00
 #define CS42L52_CHIP_REV_A1                    0x01
 #define CS42L52_CHIP_REV_B0                    0x02
-#define CS42L52_CHIP_REV_MASK                  0x03
+#define CS42L52_CHIP_REV_MASK                  0x07
 
 #define CS42L52_PWRCTL1                                0x02
 #define CS42L52_PWRCTL1_PDN_ALL                        0x9F
index 082299a..8502032 100644 (file)
@@ -495,17 +495,16 @@ int cs42xx8_probe(struct device *dev, struct regmap *regmap)
        regcache_cache_bypass(cs42xx8->regmap, true);
 
        /* Validate the chip ID */
-       regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
-       if (val < 0) {
-               dev_err(dev, "failed to get device ID: %x", val);
-               ret = -EINVAL;
+       ret = regmap_read(cs42xx8->regmap, CS42XX8_CHIPID, &val);
+       if (ret < 0) {
+               dev_err(dev, "failed to get device ID, ret = %d", ret);
                goto err_enable;
        }
 
        /* The top four bits of the chip ID should be 0000 */
-       if ((val & CS42XX8_CHIPID_CHIP_ID_MASK) != 0x00) {
+       if (((val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4) != 0x00) {
                dev_err(dev, "unmatched chip ID: %d\n",
-                               val & CS42XX8_CHIPID_CHIP_ID_MASK);
+                       (val & CS42XX8_CHIPID_CHIP_ID_MASK) >> 4);
                ret = -EINVAL;
                goto err_enable;
        }
index 7d168ec..48f3fef 100644 (file)
@@ -1571,7 +1571,8 @@ static int da732x_i2c_probe(struct i2c_client *i2c,
        }
 
        dev_info(&i2c->dev, "Revision: %d.%d\n",
-                (reg & DA732X_ID_MAJOR_MASK), (reg & DA732X_ID_MINOR_MASK));
+                (reg & DA732X_ID_MAJOR_MASK) >> 4,
+                (reg & DA732X_ID_MINOR_MASK));
 
        ret = snd_soc_register_codec(&i2c->dev, &soc_codec_dev_da732x,
                                     da732x_dai, ARRAY_SIZE(da732x_dai));
index 98c6e10..f7b0b37 100644 (file)
@@ -2399,11 +2399,18 @@ static const struct i2c_device_id max98090_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, max98090_i2c_id);
 
+static const struct of_device_id max98090_of_match[] = {
+       { .compatible = "maxim,max98090", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, max98090_of_match);
+
 static struct i2c_driver max98090_i2c_driver = {
        .driver = {
                .name = "max98090",
                .owner = THIS_MODULE,
                .pm = &max98090_pm,
+               .of_match_table = of_match_ptr(max98090_of_match),
        },
        .probe  = max98090_i2c_probe,
        .remove = max98090_i2c_remove,
index 0061ae6..68b4dd6 100644 (file)
@@ -2074,6 +2074,14 @@ static const struct i2c_device_id rt5640_i2c_id[] = {
 };
 MODULE_DEVICE_TABLE(i2c, rt5640_i2c_id);
 
+#if defined(CONFIG_OF)
+static const struct of_device_id rt5640_of_match[] = {
+       { .compatible = "realtek,rt5640", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, rt5640_of_match);
+#endif
+
 #ifdef CONFIG_ACPI
 static struct acpi_device_id rt5640_acpi_match[] = {
        { "INT33CA", 0 },
@@ -2203,6 +2211,7 @@ static struct i2c_driver rt5640_i2c_driver = {
                .name = "rt5640",
                .owner = THIS_MODULE,
                .acpi_match_table = ACPI_PTR(rt5640_acpi_match),
+               .of_match_table = of_match_ptr(rt5640_of_match),
        },
        .probe = rt5640_i2c_probe,
        .remove   = rt5640_i2c_remove,
index 20fc460..b73c94e 100644 (file)
@@ -43,9 +43,16 @@ static const struct i2c_device_id tlv320aic23_id[] = {
 
 MODULE_DEVICE_TABLE(i2c, tlv320aic23_id);
 
+static const struct of_device_id tlv320aic23_of_match[] = {
+       { .compatible = "ti,tlv320aic23", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, tlv320aic23_of_match);
+
 static struct i2c_driver tlv320aic23_i2c_driver = {
        .driver = {
                   .name = "tlv320aic23-codec",
+                  .of_match_table = of_match_ptr(tlv320aic23_of_match),
                   },
        .probe = tlv320aic23_i2c_probe,
        .remove = __exit_p(tlv320aic23_i2c_remove),
index a01ae97..4f75cac 100644 (file)
@@ -336,7 +336,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
@@ -344,7 +344,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
@@ -352,7 +352,7 @@ static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
                mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKXCTL_REG, ACLKXPOL);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG, FSXPOL);
 
-               mcasp_set_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
+               mcasp_clr_bits(mcasp, DAVINCI_MCASP_ACLKRCTL_REG, ACLKRPOL);
                mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG, FSRPOL);
                break;
 
index c4a4231..56da8c8 100644 (file)
 
 #include "fsl_sai.h"
 
+#define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\
+                      FSL_SAI_CSR_FEIE)
+
+static irqreturn_t fsl_sai_isr(int irq, void *devid)
+{
+       struct fsl_sai *sai = (struct fsl_sai *)devid;
+       struct device *dev = &sai->pdev->dev;
+       u32 xcsr, mask;
+
+       /* Only handle those what we enabled */
+       mask = (FSL_SAI_FLAGS >> FSL_SAI_CSR_xIE_SHIFT) << FSL_SAI_CSR_xF_SHIFT;
+
+       /* Tx IRQ */
+       regmap_read(sai->regmap, FSL_SAI_TCSR, &xcsr);
+       xcsr &= mask;
+
+       if (xcsr & FSL_SAI_CSR_WSF)
+               dev_dbg(dev, "isr: Start of Tx word detected\n");
+
+       if (xcsr & FSL_SAI_CSR_SEF)
+               dev_warn(dev, "isr: Tx Frame sync error detected\n");
+
+       if (xcsr & FSL_SAI_CSR_FEF) {
+               dev_warn(dev, "isr: Transmit underrun detected\n");
+               /* FIFO reset for safety */
+               xcsr |= FSL_SAI_CSR_FR;
+       }
+
+       if (xcsr & FSL_SAI_CSR_FWF)
+               dev_dbg(dev, "isr: Enabled transmit FIFO is empty\n");
+
+       if (xcsr & FSL_SAI_CSR_FRF)
+               dev_dbg(dev, "isr: Transmit FIFO watermark has been reached\n");
+
+       regmap_update_bits(sai->regmap, FSL_SAI_TCSR,
+                          FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+
+       /* Rx IRQ */
+       regmap_read(sai->regmap, FSL_SAI_RCSR, &xcsr);
+       xcsr &= mask;
+
+       if (xcsr & FSL_SAI_CSR_WSF)
+               dev_dbg(dev, "isr: Start of Rx word detected\n");
+
+       if (xcsr & FSL_SAI_CSR_SEF)
+               dev_warn(dev, "isr: Rx Frame sync error detected\n");
+
+       if (xcsr & FSL_SAI_CSR_FEF) {
+               dev_warn(dev, "isr: Receive overflow detected\n");
+               /* FIFO reset for safety */
+               xcsr |= FSL_SAI_CSR_FR;
+       }
+
+       if (xcsr & FSL_SAI_CSR_FWF)
+               dev_dbg(dev, "isr: Enabled receive FIFO is full\n");
+
+       if (xcsr & FSL_SAI_CSR_FRF)
+               dev_dbg(dev, "isr: Receive FIFO watermark has been reached\n");
+
+       regmap_update_bits(sai->regmap, FSL_SAI_RCSR,
+                          FSL_SAI_CSR_xF_W_MASK | FSL_SAI_CSR_FR, xcsr);
+
+       return IRQ_HANDLED;
+}
+
 static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai,
                int clk_id, unsigned int freq, int fsl_dir)
 {
@@ -114,7 +179,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                 * that is, together with the last bit of the previous
                 * data word.
                 */
-               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               val_cr2 |= FSL_SAI_CR2_BCP;
                val_cr4 |= FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP;
                break;
        case SND_SOC_DAIFMT_LEFT_J:
@@ -122,7 +187,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                 * Frame high, one word length for frame sync,
                 * frame sync asserts with the first bit of the frame.
                 */
-               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               val_cr2 |= FSL_SAI_CR2_BCP;
                val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
                break;
        case SND_SOC_DAIFMT_DSP_A:
@@ -132,7 +197,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                 * that is, together with the last bit of the previous
                 * data word.
                 */
-               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               val_cr2 |= FSL_SAI_CR2_BCP;
                val_cr4 &= ~FSL_SAI_CR4_FSP;
                val_cr4 |= FSL_SAI_CR4_FSE;
                sai->is_dsp_mode = true;
@@ -142,7 +207,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai,
                 * Frame high, one bit for frame sync,
                 * frame sync asserts with the first bit of the frame.
                 */
-               val_cr2 &= ~FSL_SAI_CR2_BCP;
+               val_cr2 |= FSL_SAI_CR2_BCP;
                val_cr4 &= ~(FSL_SAI_CR4_FSE | FSL_SAI_CR4_FSP);
                sai->is_dsp_mode = true;
                break;
@@ -373,8 +438,8 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai)
 {
        struct fsl_sai *sai = dev_get_drvdata(cpu_dai->dev);
 
-       regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, 0x0);
-       regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, 0x0);
+       regmap_update_bits(sai->regmap, FSL_SAI_TCSR, 0xffffffff, FSL_SAI_FLAGS);
+       regmap_update_bits(sai->regmap, FSL_SAI_RCSR, 0xffffffff, FSL_SAI_FLAGS);
        regmap_update_bits(sai->regmap, FSL_SAI_TCR1, FSL_SAI_CR1_RFW_MASK,
                           FSL_SAI_MAXBURST_TX * 2);
        regmap_update_bits(sai->regmap, FSL_SAI_RCR1, FSL_SAI_CR1_RFW_MASK,
@@ -490,12 +555,14 @@ static int fsl_sai_probe(struct platform_device *pdev)
        struct fsl_sai *sai;
        struct resource *res;
        void __iomem *base;
-       int ret;
+       int irq, ret;
 
        sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL);
        if (!sai)
                return -ENOMEM;
 
+       sai->pdev = pdev;
+
        sai->big_endian_regs = of_property_read_bool(np, "big-endian-regs");
        if (sai->big_endian_regs)
                fsl_sai_regmap_config.val_format_endian = REGMAP_ENDIAN_BIG;
@@ -514,6 +581,18 @@ static int fsl_sai_probe(struct platform_device *pdev)
                return PTR_ERR(sai->regmap);
        }
 
+       irq = platform_get_irq(pdev, 0);
+       if (irq < 0) {
+               dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
+               return irq;
+       }
+
+       ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, 0, np->name, sai);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to claim irq %u\n", irq);
+               return ret;
+       }
+
        sai->dma_params_rx.addr = res->start + FSL_SAI_RDR;
        sai->dma_params_tx.addr = res->start + FSL_SAI_TDR;
        sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX;
index e432260..a264185 100644 (file)
 
 /* SAI Transmit/Recieve Control Register */
 #define FSL_SAI_CSR_TERE       BIT(31)
+#define FSL_SAI_CSR_FR         BIT(25)
+#define FSL_SAI_CSR_xF_SHIFT   16
+#define FSL_SAI_CSR_xF_W_SHIFT 18
+#define FSL_SAI_CSR_xF_MASK    (0x1f << FSL_SAI_CSR_xF_SHIFT)
+#define FSL_SAI_CSR_xF_W_MASK  (0x7 << FSL_SAI_CSR_xF_W_SHIFT)
+#define FSL_SAI_CSR_WSF                BIT(20)
+#define FSL_SAI_CSR_SEF                BIT(19)
+#define FSL_SAI_CSR_FEF                BIT(18)
 #define FSL_SAI_CSR_FWF                BIT(17)
+#define FSL_SAI_CSR_FRF                BIT(16)
+#define FSL_SAI_CSR_xIE_SHIFT  8
+#define FSL_SAI_CSR_WSIE       BIT(12)
+#define FSL_SAI_CSR_SEIE       BIT(11)
+#define FSL_SAI_CSR_FEIE       BIT(10)
+#define FSL_SAI_CSR_FWIE       BIT(9)
 #define FSL_SAI_CSR_FRIE       BIT(8)
 #define FSL_SAI_CSR_FRDE       BIT(0)
 
 #define FSL_SAI_MAXBURST_RX 6
 
 struct fsl_sai {
+       struct platform_device *pdev;
        struct regmap *regmap;
 
        bool big_endian_regs;
index 4a88e36..76b072b 100644 (file)
@@ -39,15 +39,15 @@ struct s3c_ac97_info {
 };
 static struct s3c_ac97_info s3c_ac97;
 
-static struct s3c2410_dma_client s3c_dma_client_out = {
+static struct s3c_dma_client s3c_dma_client_out = {
        .name = "AC97 PCMOut"
 };
 
-static struct s3c2410_dma_client s3c_dma_client_in = {
+static struct s3c_dma_client s3c_dma_client_in = {
        .name = "AC97 PCMIn"
 };
 
-static struct s3c2410_dma_client s3c_dma_client_micin = {
+static struct s3c_dma_client s3c_dma_client_micin = {
        .name = "AC97 MicIn"
 };
 
index 225e537..ad7c0f0 100644 (file)
 
 #include <sound/dmaengine_pcm.h>
 
+struct s3c_dma_client {
+       char *name;
+};
+
 struct s3c_dma_params {
-       struct s3c2410_dma_client *client;      /* stream identifier */
+       struct s3c_dma_client *client;  /* stream identifier */
        int channel;                            /* Channel ID */
        dma_addr_t dma_addr;
        int dma_size;                   /* Size of the DMA transfer */
index 0a9b44c..048ead9 100644 (file)
@@ -1211,10 +1211,10 @@ static int samsung_i2s_probe(struct platform_device *pdev)
        pri_dai->dma_playback.dma_addr = regs_base + I2STXD;
        pri_dai->dma_capture.dma_addr = regs_base + I2SRXD;
        pri_dai->dma_playback.client =
-               (struct s3c2410_dma_client *)&pri_dai->dma_playback;
+               (struct s3c_dma_client *)&pri_dai->dma_playback;
        pri_dai->dma_playback.ch_name = "tx";
        pri_dai->dma_capture.client =
-               (struct s3c2410_dma_client *)&pri_dai->dma_capture;
+               (struct s3c_dma_client *)&pri_dai->dma_capture;
        pri_dai->dma_capture.ch_name = "rx";
        pri_dai->dma_playback.dma_size = 4;
        pri_dai->dma_capture.dma_size = 4;
@@ -1233,7 +1233,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
                }
                sec_dai->dma_playback.dma_addr = regs_base + I2STXDS;
                sec_dai->dma_playback.client =
-                       (struct s3c2410_dma_client *)&sec_dai->dma_playback;
+                       (struct s3c_dma_client *)&sec_dai->dma_playback;
                sec_dai->dma_playback.ch_name = "tx-sec";
 
                if (!np) {
index 6a5e4bf..ab54e29 100644 (file)
@@ -20,7 +20,6 @@
 #include <sound/pcm_params.h>
 
 #include <linux/platform_data/asoc-s3c.h>
-#include <mach/dma.h>
 
 #include "dma.h"
 #include "pcm.h"
@@ -132,11 +131,11 @@ struct s3c_pcm_info {
        struct s3c_dma_params   *dma_capture;
 };
 
-static struct s3c2410_dma_client s3c_pcm_dma_client_out = {
+static struct s3c_dma_client s3c_pcm_dma_client_out = {
        .name           = "PCM Stereo out"
 };
 
-static struct s3c2410_dma_client s3c_pcm_dma_client_in = {
+static struct s3c_dma_client s3c_pcm_dma_client_in = {
        .name           = "PCM Stereo in"
 };
 
index d079445..e9bb5d7 100644 (file)
 #include "regs-i2s-v2.h"
 #include "s3c2412-i2s.h"
 
-static struct s3c2410_dma_client s3c2412_dma_client_out = {
+static struct s3c_dma_client s3c2412_dma_client_out = {
        .name           = "I2S PCM Stereo out"
 };
 
-static struct s3c2410_dma_client s3c2412_dma_client_in = {
+static struct s3c_dma_client s3c2412_dma_client_in = {
        .name           = "I2S PCM Stereo in"
 };
 
index f31e916..d7b8457 100644 (file)
 #include "dma.h"
 #include "s3c24xx-i2s.h"
 
-static struct s3c2410_dma_client s3c24xx_dma_client_out = {
+static struct s3c_dma_client s3c24xx_dma_client_out = {
        .name = "I2S PCM Stereo out"
 };
 
-static struct s3c2410_dma_client s3c24xx_dma_client_in = {
+static struct s3c_dma_client s3c24xx_dma_client_in = {
        .name = "I2S PCM Stereo in"
 };
 
index 28487dc..cfe63b7 100644 (file)
@@ -18,7 +18,6 @@
 #include <sound/pcm_params.h>
 
 #include <linux/platform_data/asoc-s3c.h>
-#include <mach/dma.h>
 
 #include "dma.h"
 #include "spdif.h"
@@ -94,7 +93,7 @@ struct samsung_spdif_info {
        struct s3c_dma_params   *dma_playback;
 };
 
-static struct s3c2410_dma_client spdif_dma_client_out = {
+static struct s3c_dma_client spdif_dma_client_out = {
        .name           = "S/PDIF Stereo out",
 };
 
index 49de5c1..131336d 100644 (file)
@@ -1501,7 +1501,8 @@ static void retire_playback_urb(struct snd_usb_substream *subs,
         * The error should be lower than 2ms since the estimate relies
         * on two reads of a counter updated every ms.
         */
-       if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
+       if (printk_ratelimit() &&
+           abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2)
                dev_dbg(&subs->dev->dev,
                        "delay: estimated %d, actual %d\n",
                        est_delay, subs->last_delay);
index f9be24d..05654f5 100644 (file)
@@ -19,7 +19,8 @@
  * Authors: Wu Fengguang <fengguang.wu@intel.com>
  */
 
-#define _LARGEFILE64_SOURCE
+#define _FILE_OFFSET_BITS 64
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <getopt.h>
 #include <limits.h>
 #include <assert.h>
+#include <ftw.h>
+#include <time.h>
 #include <sys/types.h>
 #include <sys/errno.h>
 #include <sys/fcntl.h>
 #include <sys/mount.h>
 #include <sys/statfs.h>
+#include <sys/mman.h>
 #include "../../include/uapi/linux/magic.h"
 #include "../../include/uapi/linux/kernel-page-flags.h"
 #include <api/fs/debugfs.h>
@@ -158,6 +162,7 @@ static int          opt_raw;        /* for kernel developers */
 static int             opt_list;       /* list pages (in ranges) */
 static int             opt_no_summary; /* don't show summary */
 static pid_t           opt_pid;        /* process to walk */
+const char *           opt_file;
 
 #define MAX_ADDR_RANGES        1024
 static int             nr_addr_ranges;
@@ -253,12 +258,7 @@ static unsigned long do_u64_read(int fd, char *name,
        if (index > ULONG_MAX / 8)
                fatal("index overflow: %lu\n", index);
 
-       if (lseek(fd, index * 8, SEEK_SET) < 0) {
-               perror(name);
-               exit(EXIT_FAILURE);
-       }
-
-       bytes = read(fd, buf, count * 8);
+       bytes = pread(fd, buf, count * 8, (off_t)index * 8);
        if (bytes < 0) {
                perror(name);
                exit(EXIT_FAILURE);
@@ -343,8 +343,8 @@ static char *page_flag_longname(uint64_t flags)
  * page list and summary
  */
 
-static void show_page_range(unsigned long voffset,
-                           unsigned long offset, uint64_t flags)
+static void show_page_range(unsigned long voffset, unsigned long offset,
+                           unsigned long size, uint64_t flags)
 {
        static uint64_t      flags0;
        static unsigned long voff;
@@ -352,14 +352,16 @@ static void show_page_range(unsigned long voffset,
        static unsigned long count;
 
        if (flags == flags0 && offset == index + count &&
-           (!opt_pid || voffset == voff + count)) {
-               count++;
+           size && voffset == voff + count) {
+               count += size;
                return;
        }
 
        if (count) {
                if (opt_pid)
                        printf("%lx\t", voff);
+               if (opt_file)
+                       printf("%lu\t", voff);
                printf("%lx\t%lx\t%s\n",
                                index, count, page_flag_name(flags0));
        }
@@ -367,7 +369,12 @@ static void show_page_range(unsigned long voffset,
        flags0 = flags;
        index  = offset;
        voff   = voffset;
-       count  = 1;
+       count  = size;
+}
+
+static void flush_page_range(void)
+{
+       show_page_range(0, 0, 0, 0);
 }
 
 static void show_page(unsigned long voffset,
@@ -375,6 +382,8 @@ static void show_page(unsigned long voffset,
 {
        if (opt_pid)
                printf("%lx\t", voffset);
+       if (opt_file)
+               printf("%lu\t", voffset);
        printf("%lx\t%s\n", offset, page_flag_name(flags));
 }
 
@@ -565,7 +574,7 @@ static void add_page(unsigned long voffset,
                unpoison_page(offset);
 
        if (opt_list == 1)
-               show_page_range(voffset, offset, flags);
+               show_page_range(voffset, offset, 1, flags);
        else if (opt_list == 2)
                show_page(voffset, offset, flags);
 
@@ -667,7 +676,7 @@ static void walk_addr_ranges(void)
 
        for (i = 0; i < nr_addr_ranges; i++)
                if (!opt_pid)
-                       walk_pfn(0, opt_offset[i], opt_size[i], 0);
+                       walk_pfn(opt_offset[i], opt_offset[i], opt_size[i], 0);
                else
                        walk_task(opt_offset[i], opt_size[i]);
 
@@ -699,9 +708,7 @@ static void usage(void)
 "            -a|--addr    addr-spec     Walk a range of pages\n"
 "            -b|--bits    bits-spec     Walk pages with specified bits\n"
 "            -p|--pid     pid           Walk process address space\n"
-#if 0 /* planned features */
 "            -f|--file    filename      Walk file address space\n"
-#endif
 "            -l|--list                  Show page details in ranges\n"
 "            -L|--list-each             Show page details one by one\n"
 "            -N|--no-summary            Don't show summary info\n"
@@ -799,8 +806,130 @@ static void parse_pid(const char *str)
        fclose(file);
 }
 
+static void show_file(const char *name, const struct stat *st)
+{
+       unsigned long long size = st->st_size;
+       char atime[64], mtime[64];
+       long now = time(NULL);
+
+       printf("%s\tInode: %u\tSize: %llu (%llu pages)\n",
+                       name, (unsigned)st->st_ino,
+                       size, (size + page_size - 1) / page_size);
+
+       strftime(atime, sizeof(atime), "%c", localtime(&st->st_atime));
+       strftime(mtime, sizeof(mtime), "%c", localtime(&st->st_mtime));
+
+       printf("Modify: %s (%ld seconds ago)\nAccess: %s (%ld seconds ago)\n",
+                       mtime, now - st->st_mtime,
+                       atime, now - st->st_atime);
+}
+
+static void walk_file(const char *name, const struct stat *st)
+{
+       uint8_t vec[PAGEMAP_BATCH];
+       uint64_t buf[PAGEMAP_BATCH], flags;
+       unsigned long nr_pages, pfn, i;
+       int fd;
+       off_t off;
+       ssize_t len;
+       void *ptr;
+       int first = 1;
+
+       fd = checked_open(name, O_RDONLY|O_NOATIME|O_NOFOLLOW);
+
+       for (off = 0; off < st->st_size; off += len) {
+               nr_pages = (st->st_size - off + page_size - 1) / page_size;
+               if (nr_pages > PAGEMAP_BATCH)
+                       nr_pages = PAGEMAP_BATCH;
+               len = nr_pages * page_size;
+
+               ptr = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, off);
+               if (ptr == MAP_FAILED)
+                       fatal("mmap failed: %s", name);
+
+               /* determine cached pages */
+               if (mincore(ptr, len, vec))
+                       fatal("mincore failed: %s", name);
+
+               /* turn off readahead */
+               if (madvise(ptr, len, MADV_RANDOM))
+                       fatal("madvice failed: %s", name);
+
+               /* populate ptes */
+               for (i = 0; i < nr_pages ; i++) {
+                       if (vec[i] & 1)
+                               (void)*(volatile int *)(ptr + i * page_size);
+               }
+
+               /* turn off harvesting reference bits */
+               if (madvise(ptr, len, MADV_SEQUENTIAL))
+                       fatal("madvice failed: %s", name);
+
+               if (pagemap_read(buf, (unsigned long)ptr / page_size,
+                                       nr_pages) != nr_pages)
+                       fatal("cannot read pagemap");
+
+               munmap(ptr, len);
+
+               for (i = 0; i < nr_pages; i++) {
+                       pfn = pagemap_pfn(buf[i]);
+                       if (!pfn)
+                               continue;
+                       if (!kpageflags_read(&flags, pfn, 1))
+                               continue;
+                       if (first && opt_list) {
+                               first = 0;
+                               flush_page_range();
+                               show_file(name, st);
+                       }
+                       add_page(off / page_size + i, pfn, flags, buf[i]);
+               }
+       }
+
+       close(fd);
+}
+
+int walk_tree(const char *name, const struct stat *st, int type, struct FTW *f)
+{
+       (void)f;
+       switch (type) {
+       case FTW_F:
+               if (S_ISREG(st->st_mode))
+                       walk_file(name, st);
+               break;
+       case FTW_DNR:
+               fprintf(stderr, "cannot read dir: %s\n", name);
+               break;
+       }
+       return 0;
+}
+
+static void walk_page_cache(void)
+{
+       struct stat st;
+
+       kpageflags_fd = checked_open(PROC_KPAGEFLAGS, O_RDONLY);
+       pagemap_fd = checked_open("/proc/self/pagemap", O_RDONLY);
+
+       if (stat(opt_file, &st))
+               fatal("stat failed: %s\n", opt_file);
+
+       if (S_ISREG(st.st_mode)) {
+               walk_file(opt_file, &st);
+       } else if (S_ISDIR(st.st_mode)) {
+               /* do not follow symlinks and mountpoints */
+               if (nftw(opt_file, walk_tree, 64, FTW_MOUNT | FTW_PHYS) < 0)
+                       fatal("nftw failed: %s\n", opt_file);
+       } else
+               fatal("unhandled file type: %s\n", opt_file);
+
+       close(kpageflags_fd);
+       close(pagemap_fd);
+}
+
 static void parse_file(const char *name)
 {
+       opt_file = name;
 }
 
 static void parse_addr_range(const char *optarg)
@@ -991,15 +1120,20 @@ int main(int argc, char *argv[])
 
        if (opt_list && opt_pid)
                printf("voffset\t");
+       if (opt_list && opt_file)
+               printf("foffset\t");
        if (opt_list == 1)
                printf("offset\tlen\tflags\n");
        if (opt_list == 2)
                printf("offset\tflags\n");
 
-       walk_addr_ranges();
+       if (opt_file)
+               walk_page_cache();
+       else
+               walk_addr_ranges();
 
        if (opt_list == 1)
-               show_page_range(0, 0, 0);  /* drain the buffer */
+               flush_page_range();
 
        if (opt_no_summary)
                return 0;